1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/compiler/state_split_linearizer.h"
17 #include "ecmascript/compiler/scheduler.h"
18
19 namespace panda::ecmascript::kungfu {
Run()20 void StateSplitLinearizer::Run()
21 {
22 graphLinearizer_.SetScheduleJSOpcode();
23 graphLinearizer_.LinearizeGraph();
24 LinearizeStateSplit();
25 if (IsLogEnabled()) {
26 LOG_COMPILER(INFO) << "";
27 LOG_COMPILER(INFO) << "\033[34m"
28 << "===================="
29 << " After state split linearizer "
30 << "[" << GetMethodName() << "]"
31 << "===================="
32 << "\033[0m";
33 circuit_->PrintAllGatesWithBytecode();
34 LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
35 }
36 #ifndef NDEBUG
37 graphLinearizer_.Reset();
38 graphLinearizer_.EnableScheduleUpperBound();
39 graphLinearizer_.SetScheduleJSOpcode();
40 graphLinearizer_.LinearizeGraph();
41 if (IsLogEnabled()) {
42 LOG_COMPILER(INFO) << "";
43 LOG_COMPILER(INFO) << "\033[34m"
44 << "===================="
45 << " verify split linearizer "
46 << "[" << GetMethodName() << "]"
47 << "===================="
48 << "\033[0m";
49 graphLinearizer_.PrintGraph("Build Basic Block");
50 LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
51 }
52 #endif
53 }
54
55 struct RegionEdge {
56 GateRef stateOut {Circuit::NullGate()};
57 GateRef dependOut {Circuit::NullGate()};
58 GateRef frameStateOut {Circuit::NullGate()};
59 };
60
61 struct PendingGateRegionEdge {
PendingGateRegionEdgepanda::ecmascript::kungfu::PendingGateRegionEdge62 explicit PendingGateRegionEdge(GateRegion* from, GateRegion* to,
63 GateRef dependStart, size_t index) : from(from), to(to),
64 dependStart(dependStart), index(index) {}
65
66 GateRegion* from;
67 GateRegion* to;
68 GateRef dependStart;
69 size_t index;
70 };
71
72 class RegionStateDependMap {
73 public:
RegionStateDependMap(Chunk * chunk)74 explicit RegionStateDependMap(Chunk* chunk) : regionMap_(chunk) {}
GetEdge(GateRegion * from,GateRegion * to)75 RegionEdge& GetEdge(GateRegion* from, GateRegion* to)
76 {
77 return regionMap_[std::make_pair(from->GetId(), to->GetId())];
78 }
79 private:
80 ChunkMap<std::pair<size_t, size_t>, RegionEdge> regionMap_;
81 };
82
83 class StateDependBuilder {
84 public:
StateDependBuilder(StateSplitLinearizer * linearizer,Chunk * chunk)85 explicit StateDependBuilder(StateSplitLinearizer* linearizer, Chunk* chunk)
86 : linearizer_(linearizer), pendingList_(chunk),
87 acc_(linearizer->circuit_), map_(chunk), pendingEdges_(chunk) {}
88
Run(ChunkVector<GateRegion * > & regionList)89 void Run(ChunkVector<GateRegion*>& regionList)
90 {
91 replacement_.SetDepend(acc_.GetDependRoot());
92 dependStart_ = replacement_.Depend();
93 auto entry = regionList.front();
94 linearizer_->circuit_->AdvanceTime();
95 entry->SetVisited(acc_);
96 ASSERT(pendingList_.empty());
97 pendingList_.emplace_back(entry);
98 while (!pendingList_.empty()) {
99 auto curRegion = pendingList_.back();
100 pendingList_.pop_back();
101 VisitRegion(curRegion);
102 for (auto succ : curRegion->succs_) {
103 if (!succ->IsVisited(acc_)) {
104 succ->SetVisited(acc_);
105 pendingList_.emplace_back(succ);
106 }
107 }
108 }
109 ConnectPendingRegionEdges();
110 }
111
VisitFixedGate(GateRef curGate)112 void VisitFixedGate(GateRef curGate)
113 {
114 auto op = acc_.GetOpCode(curGate);
115 if (op == OpCode::DEPEND_SELECTOR || op == OpCode::DEPEND_RELAY) {
116 replacement_.SetDepend(curGate);
117 dependStart_ = curGate;
118 } else {
119 VisitGate(curGate);
120 }
121 }
122
VisitRegion(GateRegion * curRegion)123 void VisitRegion(GateRegion* curRegion)
124 {
125 replacement_.SetState(curRegion->GetState());
126 currentIndex_ = static_cast<int32_t>(curRegion->gateList_.size() - 1); // 1: -1 for size
127 TryLoadDependStart(curRegion);
128 // 0: is state
129 for (; currentIndex_ > 0; currentIndex_--) {
130 auto curGate = curRegion->gateList_[currentIndex_];
131 VisitFixedGate(curGate);
132 if (dependStart_ != Circuit::NullGate()) {
133 currentIndex_--;
134 break;
135 }
136 }
137 ConnectStateDepend(curRegion);
138 for (; currentIndex_ > 0; currentIndex_--) {
139 auto curGate = curRegion->gateList_[currentIndex_];
140 VisitGate(curGate);
141 }
142 StoreStateDepend(curRegion);
143 }
144
ProcessStateDepend(GateRef currentGate)145 void ProcessStateDepend(GateRef currentGate)
146 {
147 auto currentState = replacement_.State();
148 auto currentDepend = replacement_.Depend();
149 if (acc_.GetStateCount(currentGate) > 0) {
150 ASSERT(acc_.GetStateCount(currentGate) == 1);
151 auto stateInput = acc_.GetState(currentGate);
152 if (currentState != stateInput) {
153 acc_.ReplaceStateIn(currentGate, currentState);
154 }
155 if (!acc_.IsVirtualState(currentGate) && !acc_.IsFixed(currentGate)) {
156 replacement_.SetState(currentGate);
157 }
158 }
159 if (acc_.GetDependCount(currentGate) > 0) {
160 ASSERT(acc_.GetDependCount(currentGate) == 1);
161 auto dependInput = acc_.GetDep(currentGate);
162 if (currentDepend != dependInput) {
163 acc_.ReplaceDependIn(currentGate, currentDepend);
164 }
165 replacement_.SetDepend(currentGate);
166 }
167 }
168
VisitGate(GateRef gate)169 void VisitGate(GateRef gate)
170 {
171 auto& lowering = linearizer_->lcrLowering_;
172 auto op = acc_.GetOpCode(gate);
173 switch (op) {
174 case OpCode::FRAME_STATE:
175 frameState_ = gate;
176 break;
177 case OpCode::STATE_SPLIT:
178 return;
179 case OpCode::CONVERT:
180 ASSERT(replacement_.State() != Circuit::NullGate());
181 replacement_ = lowering.LowerConvert(replacement_, gate);
182 break;
183 default:
184 break;
185 }
186 ProcessStateDepend(gate);
187 }
188
TryLoadDependStart(GateRegion * curRegion)189 void TryLoadDependStart(GateRegion* curRegion)
190 {
191 auto currentState = curRegion->GetState();
192 if (dependStart_ == Circuit::NullGate()) {
193 if (acc_.GetOpCode(currentState) == OpCode::IF_EXCEPTION) {
194 dependStart_ = currentState;
195 replacement_.SetDepend(dependStart_);
196 } else if (curRegion->preds_.size() == 1) {
197 auto &edge = map_.GetEdge(curRegion->preds_[0], curRegion);
198 ASSERT(edge.dependOut != Circuit::NullGate());
199 replacement_.SetDepend(edge.dependOut);
200 frameState_ = edge.frameStateOut;
201 }
202 }
203 }
204
ConnectStateDepend(GateRegion * curRegion)205 void ConnectStateDepend(GateRegion* curRegion)
206 {
207 auto currentState = curRegion->GetState();
208 ASSERT(dependStart_ == Circuit::NullGate() ||
209 curRegion->preds_.size() == acc_.GetDependCount(dependStart_));
210 ASSERT(curRegion->preds_.size() == acc_.GetStateCount(currentState));
211 for (size_t i = 0; i < curRegion->preds_.size(); i++) {
212 auto pred = curRegion->preds_[i];
213 auto &edge = map_.GetEdge(pred, curRegion);
214 auto stateInput = acc_.GetState(currentState, i);
215 if (edge.stateOut == Circuit::NullGate()) {
216 ASSERT(edge.dependOut == Circuit::NullGate());
217 pendingEdges_.emplace_back(PendingGateRegionEdge(pred, curRegion, dependStart_, i));
218 } else {
219 ConnectEdge(edge, currentState, stateInput, i);
220 }
221 }
222 }
223
ConnectEdge(RegionEdge & edge,GateRef currentState,GateRef stateInput,size_t i)224 void ConnectEdge(RegionEdge& edge, GateRef currentState, GateRef stateInput, size_t i)
225 {
226 if (edge.stateOut != stateInput) {
227 acc_.ReplaceStateIn(currentState, edge.stateOut, i);
228 }
229 if (frameState_ == Circuit::NullGate()) {
230 frameState_ = edge.frameStateOut;
231 }
232 if (dependStart_ != Circuit::NullGate()) {
233 auto dependInput = acc_.GetDep(dependStart_, i);
234 if (edge.dependOut != dependInput) {
235 acc_.ReplaceDependIn(dependStart_, edge.dependOut, i);
236 }
237 }
238 }
239
ConnectPendingRegionEdges()240 void ConnectPendingRegionEdges()
241 {
242 for (auto regionEdge : pendingEdges_) {
243 auto currentState = regionEdge.to->GetState();
244 auto stateInput = acc_.GetState(currentState, regionEdge.index);
245 auto &edge = map_.GetEdge(regionEdge.from, regionEdge.to);
246 if (edge.stateOut != stateInput) {
247 acc_.ReplaceStateIn(currentState, edge.stateOut, regionEdge.index);
248 }
249 auto dependInput = acc_.GetDep(regionEdge.dependStart, regionEdge.index);
250 if (edge.dependOut != dependInput) {
251 acc_.ReplaceDependIn(regionEdge.dependStart, edge.dependOut, regionEdge.index);
252 }
253 }
254 }
255
StoreStateDepend(GateRegion * curRegion)256 void StoreStateDepend(GateRegion* curRegion)
257 {
258 for (auto succ : curRegion->succs_) {
259 auto &edge = map_.GetEdge(curRegion, succ);
260 if (edge.stateOut == Circuit::NullGate()) {
261 edge.stateOut = replacement_.State();
262 }
263 if (edge.dependOut == Circuit::NullGate()) {
264 edge.dependOut = replacement_.Depend();
265 }
266 if (edge.frameStateOut == Circuit::NullGate()) {
267 edge.frameStateOut = frameState_;
268 }
269 }
270 replacement_.Reset();
271 frameState_ = Circuit::NullGate();
272 dependStart_ = Circuit::NullGate();
273 currentIndex_ = -1;
274 }
275
276 private:
277 GateRef dependStart_ {Circuit::NullGate()};
278 GateRef frameState_ {Circuit::NullGate()};
279 StateDepend replacement_;
280 int32_t currentIndex_ {-1};
281 StateSplitLinearizer* linearizer_ {nullptr};
282 ChunkDeque<GateRegion*> pendingList_;
283 GateAccessor acc_;
284 RegionStateDependMap map_;
285 ChunkVector<PendingGateRegionEdge> pendingEdges_;
286 };
287
LinearizeStateSplit()288 void StateSplitLinearizer::LinearizeStateSplit()
289 {
290 StateDependBuilder builder(this, graphLinearizer_.chunk_);
291 builder.Run(graphLinearizer_.regionList_);
292 }
293
294 } // namespace panda::ecmascript::kungfu
295