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/graph_linearizer.h"
17 #include "ecmascript/compiler/gate.h"
18 #include "ecmascript/compiler/scheduler.h"
19
20 namespace panda::ecmascript::kungfu {
Run(ControlFlowGraph & result)21 void GraphLinearizer::Run(ControlFlowGraph &result)
22 {
23 LinearizeGraph();
24 LinearizeRegions(result);
25
26 if (IsLogEnabled()) {
27 LOG_COMPILER(INFO) << "";
28 LOG_COMPILER(INFO) << "\033[34m"
29 << "===================="
30 << " After graph linearizer "
31 << "[" << GetMethodName() << "]"
32 << "===================="
33 << "\033[0m";
34 PrintGraph("Build Basic Block");
35 LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
36 }
37 }
38
39 class CFGBuilder {
40 public:
CFGBuilder(GraphLinearizer * linearizer)41 explicit CFGBuilder(GraphLinearizer *linearizer)
42 : linearizer_(linearizer), pendingList_(linearizer->chunk_),
43 endStateList_(linearizer->chunk_),
44 acc_(linearizer->circuit_), scheduleLIR_(linearizer->IsSchedueLIR()) {}
45
Run()46 void Run()
47 {
48 VisitStateGates();
49 // connect region
50 for (auto rootGate : linearizer_->regionRootList_) {
51 auto toRegion = linearizer_->GateToRegion(rootGate);
52 auto numStateIn = acc_.GetStateCount(rootGate);
53 for (size_t i = 0; i < numStateIn; i++) {
54 auto input = acc_.GetState(rootGate, i);
55 ASSERT(acc_.IsState(input) || acc_.GetOpCode(input) == OpCode::STATE_ENTRY);
56 auto fromRegion = linearizer_->FindPredRegion(input);
57 fromRegion->AddSucc(toRegion);
58 }
59 }
60 for (auto fixedGate : endStateList_) {
61 auto state = acc_.GetState(fixedGate);
62 auto region = linearizer_->FindPredRegion(state);
63 linearizer_->AddFixedGateToRegion(fixedGate, region);
64 linearizer_->BindGate(fixedGate, region);
65 }
66 }
67
VisitStateGates()68 void VisitStateGates()
69 {
70 ASSERT(pendingList_.empty());
71 linearizer_->circuit_->AdvanceTime();
72 auto startGate = acc_.GetStateRoot();
73 acc_.SetMark(startGate, MarkCode::VISITED);
74 pendingList_.emplace_back(startGate);
75 bool litecg = linearizer_->enableLiteCG();
76 while (!pendingList_.empty()) {
77 auto curGate = pendingList_.back();
78 pendingList_.pop_back();
79 VisitStateGate(curGate);
80 if (acc_.GetOpCode(curGate) != OpCode::LOOP_BACK) {
81 auto uses = acc_.Uses(curGate);
82 // The LiteCG backend is unable to perform branch prediction scheduling, thus requiring advance
83 // preparation
84 if (litecg && acc_.GetOpCode(curGate) == OpCode::IF_BRANCH && acc_.HasBranchWeight(curGate)) {
85 std::vector<GateRef> outs;
86 acc_.GetOutStates(curGate, outs);
87 GateRef bTrue = (acc_.GetOpCode(outs[0]) == OpCode::IF_TRUE) ? outs[0] : outs[1];
88 GateRef bFalse = (acc_.GetOpCode(outs[0]) == OpCode::IF_FALSE) ? outs[0] : outs[1];
89 if (acc_.GetTrueWeight(curGate) >= acc_.GetFalseWeight(curGate)) {
90 std::swap(bTrue, bFalse);
91 }
92 if (acc_.GetMark(bTrue) == MarkCode::NO_MARK) {
93 acc_.SetMark(bTrue, MarkCode::VISITED);
94 pendingList_.emplace_back(bTrue);
95 }
96 if (acc_.GetMark(bFalse) == MarkCode::NO_MARK) {
97 acc_.SetMark(bFalse, MarkCode::VISITED);
98 pendingList_.emplace_back(bFalse);
99 }
100 continue;
101 }
102 for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
103 if (acc_.IsStateIn(useIt) && acc_.IsState(*useIt) && acc_.GetMark(*useIt) == MarkCode::NO_MARK) {
104 acc_.SetMark(*useIt, MarkCode::VISITED);
105 pendingList_.emplace_back(*useIt);
106 }
107 }
108 }
109 }
110 }
111
VisitStateGate(GateRef gate)112 void VisitStateGate(GateRef gate)
113 {
114 if (scheduleLIR_) {
115 linearizer_->CreateGateRegion(gate);
116 } else {
117 auto op = acc_.GetOpCode(gate);
118 switch (op) {
119 case OpCode::LOOP_BEGIN:
120 case OpCode::MERGE:
121 case OpCode::IF_TRUE:
122 case OpCode::IF_FALSE:
123 case OpCode::SWITCH_CASE:
124 case OpCode::STATE_ENTRY:
125 case OpCode::IF_EXCEPTION:
126 case OpCode::IF_SUCCESS: {
127 linearizer_->CreateGateRegion(gate);
128 if (linearizer_->onlyBB_) {
129 currentRegion_ = linearizer_->GateToRegion(gate);
130 }
131 break;
132 }
133 case OpCode::LOOP_BACK:
134 case OpCode::IF_BRANCH:
135 case OpCode::SWITCH_BRANCH:
136 case OpCode::RETURN:
137 case OpCode::RETURN_VOID:
138 case OpCode::TYPED_CONDITION_JUMP:
139 endStateList_.emplace_back(gate);
140 break;
141 case OpCode::JS_BYTECODE:
142 if (IsStateSplit(gate)) {
143 endStateList_.emplace_back(gate);
144 }
145 break;
146 default: {
147 if (linearizer_->onlyBB_) {
148 auto &info = linearizer_->GetGateInfo(gate);
149 info.region = currentRegion_;
150 linearizer_->BindGate(gate, currentRegion_);
151 }
152 break;
153 }
154 }
155 }
156 }
157
IsStateSplit(GateRef gate)158 bool IsStateSplit(GateRef gate)
159 {
160 size_t stateOut = 0;
161 auto uses = acc_.Uses(gate);
162 for (auto it = uses.begin(); it != uses.end(); it++) {
163 if (acc_.IsStateIn(it)) {
164 auto op = acc_.GetOpCode(*it);
165 switch (op) {
166 case OpCode::IF_TRUE:
167 case OpCode::IF_FALSE:
168 case OpCode::IF_EXCEPTION:
169 case OpCode::IF_SUCCESS:
170 stateOut++;
171 break;
172 default:
173 break;
174 }
175 }
176 }
177 return stateOut > 1; // 1: depend out
178 }
179
180 private:
181 GraphLinearizer* linearizer_;
182 ChunkDeque<GateRef> pendingList_;
183 ChunkVector<GateRef> endStateList_;
184 GateAccessor acc_;
185 GateRegion* currentRegion_;
186 bool scheduleLIR_;
187 };
188
189 class ImmediateDominatorsGenerator {
190 public:
ImmediateDominatorsGenerator(GraphLinearizer * linearizer,Chunk * chunk,size_t size)191 explicit ImmediateDominatorsGenerator(GraphLinearizer *linearizer, Chunk* chunk, size_t size)
192 : linearizer_(linearizer), pendingList_(chunk),
193 dfsList_(chunk), dfsTimestamp_(size, chunk), dfsFatherIdx_(size, chunk),
194 bbDfsTimestampToIdx_(size, chunk), semiDom_(size, chunk), immDom_(size, chunk),
195 minIdx_(size, chunk), parentIdx_(size, chunk), semiDomTree_(chunk) {}
196
Run()197 void Run()
198 {
199 BuildDfsFather();
200 BuildDomTree();
201 BuildImmediateDominator();
202 BuildImmediateDominatorDepth();
203 }
204
BuildDfsFather()205 void BuildDfsFather()
206 {
207 size_t timestamp = 0;
208 auto entry = linearizer_->regionList_.front();
209 linearizer_->circuit_->AdvanceTime();
210 entry->SetVisited(linearizer_->acc_);
211 ASSERT(pendingList_.empty());
212 pendingList_.emplace_back(entry);
213 while (!pendingList_.empty()) {
214 auto curRegion = pendingList_.back();
215 pendingList_.pop_back();
216 dfsList_.emplace_back(curRegion->id_);
217 dfsTimestamp_[curRegion->id_] = timestamp++;
218 for (auto succ : curRegion->succs_) {
219 if (!succ->IsVisited(linearizer_->acc_)) {
220 succ->SetVisited(linearizer_->acc_);
221 pendingList_.emplace_back(succ);
222 dfsFatherIdx_[succ->id_] = dfsTimestamp_[curRegion->id_];
223 }
224 }
225 }
226 for (size_t idx = 0; idx < dfsList_.size(); idx++) {
227 bbDfsTimestampToIdx_[dfsList_[idx]] = idx;
228 }
229 ASSERT(timestamp == linearizer_->regionList_.size());
230 }
231
UnionFind(size_t idx)232 size_t UnionFind(size_t idx)
233 {
234 size_t pIdx = parentIdx_[idx];
235 if (pIdx == idx) {
236 return idx;
237 }
238 size_t unionFindSetRoot = UnionFind(pIdx);
239 if (semiDom_[minIdx_[idx]] > semiDom_[minIdx_[pIdx]]) {
240 minIdx_[idx] = minIdx_[pIdx];
241 }
242 return parentIdx_[idx] = unionFindSetRoot;
243 }
244
Merge(size_t fatherIdx,size_t sonIdx)245 void Merge(size_t fatherIdx, size_t sonIdx)
246 {
247 size_t parentFatherIdx = UnionFind(fatherIdx);
248 size_t parentSonIdx = UnionFind(sonIdx);
249 parentIdx_[parentSonIdx] = parentFatherIdx;
250 }
251
BuildDomTree()252 void BuildDomTree()
253 {
254 auto ®ionList = linearizer_->regionList_;
255 for (size_t i = 0; i < dfsList_.size(); i++) {
256 ChunkDeque<size_t> sonList(linearizer_->chunk_);
257 semiDomTree_.emplace_back(std::move(sonList));
258 }
259 std::iota(parentIdx_.begin(), parentIdx_.end(), 0);
260 std::iota(semiDom_.begin(), semiDom_.end(), 0);
261 semiDom_[0] = semiDom_.size();
262
263 for (size_t idx = dfsList_.size() - 1; idx >= 1; idx--) {
264 for (const auto &preRegion : regionList[dfsList_[idx]]->preds_) {
265 size_t preRegionIdx = bbDfsTimestampToIdx_[preRegion->id_];
266 if (bbDfsTimestampToIdx_[preRegion->id_] < idx) {
267 semiDom_[idx] = std::min(semiDom_[idx], preRegionIdx);
268 } else {
269 UnionFind(preRegionIdx);
270 semiDom_[idx] = std::min(semiDom_[idx], semiDom_[minIdx_[preRegionIdx]]);
271 }
272 }
273 for (const auto &succDomIdx : semiDomTree_[idx]) {
274 UnionFind(succDomIdx);
275 if (idx == semiDom_[minIdx_[succDomIdx]]) {
276 immDom_[succDomIdx] = idx;
277 } else {
278 immDom_[succDomIdx] = minIdx_[succDomIdx];
279 }
280 }
281 minIdx_[idx] = idx;
282 Merge(dfsFatherIdx_[dfsList_[idx]], idx);
283 semiDomTree_[semiDom_[idx]].emplace_back(idx);
284 }
285 }
286
BuildImmediateDominator()287 void BuildImmediateDominator()
288 {
289 for (size_t idx = 1; idx < dfsList_.size(); idx++) {
290 if (immDom_[idx] != semiDom_[idx]) {
291 immDom_[idx] = immDom_[immDom_[idx]];
292 }
293 }
294 auto entry = linearizer_->regionList_.front();
295 entry->iDominator_ = entry;
296 entry->depth_ = 0;
297 auto ®ionList = linearizer_->regionList_;
298 for (size_t i = 1; i < immDom_.size(); i++) {
299 auto index = dfsList_[i];
300 auto dominatedRegion = regionList[index];
301 auto domIndex = dfsList_[immDom_[i]];
302 auto immDomRegion = regionList[domIndex];
303 immDomRegion->depth_ = static_cast<int32_t>(immDom_[i]);
304 dominatedRegion->iDominator_ = immDomRegion;
305 immDomRegion->dominatedRegions_.emplace_back(dominatedRegion);
306 }
307 }
308
BuildImmediateDominatorDepth()309 void BuildImmediateDominatorDepth()
310 {
311 auto entry = linearizer_->regionList_.front();
312 entry->depth_ = 0;
313
314 ASSERT(pendingList_.empty());
315 pendingList_.emplace_back(entry);
316 while (!pendingList_.empty()) {
317 auto curRegion = pendingList_.back();
318 pendingList_.pop_back();
319
320 for (auto succ : curRegion->dominatedRegions_) {
321 ASSERT(succ->iDominator_->depth_ != GateRegion::INVALID_DEPTH);
322 succ->depth_ = succ->iDominator_->depth_ + 1;
323 pendingList_.emplace_back(succ);
324 }
325 }
326 }
327
328 private:
329 GraphLinearizer* linearizer_;
330 ChunkDeque<GateRegion*> pendingList_;
331 ChunkVector<size_t> dfsList_;
332 ChunkVector<size_t> dfsTimestamp_;
333 ChunkVector<size_t> dfsFatherIdx_;
334 ChunkVector<size_t> bbDfsTimestampToIdx_;
335 ChunkVector<size_t> semiDom_;
336 ChunkVector<size_t> immDom_;
337 ChunkVector<size_t> minIdx_;
338 ChunkVector<size_t> parentIdx_;
339 ChunkVector<ChunkDeque<size_t>> semiDomTree_;
340 };
341
342 class LoopInfoBuilder {
343 public:
LoopInfoBuilder(GraphLinearizer * linearizer,Chunk * chunk)344 explicit LoopInfoBuilder(GraphLinearizer *linearizer, Chunk* chunk)
345 : linearizer_(linearizer), pendingList_(chunk),
346 loopbacks_(chunk), chunk_(chunk),
347 dfsStack_(chunk), acc_(linearizer->circuit_) {}
348
Run()349 void Run()
350 {
351 ComputeLoopNumber();
352 ComputeLoopInfo();
353 ComputeLoopTree();
354 if (linearizer_->IsLogEnabled()) {
355 for (size_t i = 0; i < numLoops_; i++) {
356 auto& loopInfo = linearizer_->loops_[i];
357 PrintLoop(loopInfo);
358 }
359 }
360 }
361
PrintLoop(GraphLinearizer::LoopInfo & loopInfo)362 void PrintLoop(GraphLinearizer::LoopInfo& loopInfo)
363 {
364 auto size = linearizer_->regionList_.size();
365 LOG_COMPILER(INFO) << "--------------------------------- LoopInfo Start ---------------------------------";
366 LOG_COMPILER(INFO) << "Head: " << acc_.GetId(loopInfo.loopHead->state_);
367 LOG_COMPILER(INFO) << "loopNumber: " << loopInfo.loopHead->loopNumber_;
368 LOG_COMPILER(INFO) << "Body: [";
369 for (size_t i = 0; i < size; i++) {
370 if (loopInfo.loopBodys->TestBit(i)) {
371 auto current = linearizer_->regionList_.at(i)->state_;
372 LOG_COMPILER(INFO) << acc_.GetId(current) << ", ";
373 }
374 }
375 LOG_COMPILER(INFO) << "]";
376 LOG_COMPILER(INFO) << "Exit: [";
377 if (loopInfo.loopExits != nullptr) {
378 for (auto region : *loopInfo.loopExits) {
379 auto current = region->state_;
380 LOG_COMPILER(INFO) << acc_.GetId(current) << ", ";
381 }
382 }
383 LOG_COMPILER(INFO) << "]";
384 LOG_COMPILER(INFO) << "--------------------------------- LoopInfo End ---------------------------------";
385 }
386
ComputeLoopInfo()387 void ComputeLoopInfo()
388 {
389 linearizer_->loops_.clear();
390 auto size = linearizer_->regionList_.size();
391 linearizer_->loops_.resize(numLoops_, GraphLinearizer::LoopInfo());
392
393 for (auto curState : loopbacks_) {
394 GateRegion* curRegion = curState.region;
395 GateRegion* loopHead = curRegion->succs_[curState.index];
396 auto loopNumber = loopHead->GetLoopNumber();
397 auto& loopInfo = linearizer_->loops_[loopNumber];
398
399 if (loopInfo.loopHead == nullptr) {
400 loopInfo.loopHead = loopHead;
401 loopInfo.loopBodys = chunk_->New<BitSet>(chunk_, size);
402 loopInfo.loopIndex = loopNumber;
403 loopInfo.loopHead->loopIndex_ = loopInfo.loopIndex;
404 }
405 if (curRegion != loopHead) {
406 loopInfo.loopBodys->SetBit(curRegion->GetId());
407 pendingList_.emplace_back(curRegion);
408 }
409 PropagateLoopBody(loopInfo);
410 }
411 }
412
PropagateLoopBody(GraphLinearizer::LoopInfo & loopInfo)413 void PropagateLoopBody(GraphLinearizer::LoopInfo& loopInfo)
414 {
415 while (!pendingList_.empty()) {
416 auto curRegion = pendingList_.back();
417 pendingList_.pop_back();
418 for (auto pred : curRegion->preds_) {
419 if (pred != loopInfo.loopHead) {
420 if (!loopInfo.loopBodys->TestBit(pred->GetId())) {
421 loopInfo.loopBodys->SetBit(pred->GetId());
422 pendingList_.emplace_back(pred);
423 }
424 }
425 }
426 }
427 }
428
ComputeLoopNumber()429 void ComputeLoopNumber()
430 {
431 auto size = linearizer_->regionList_.size();
432 dfsStack_.resize(size, DFSState(nullptr, 0));
433 linearizer_->circuit_->AdvanceTime();
434
435 auto entry = linearizer_->regionList_.front();
436 auto currentDepth = Push(entry, 0);
437 while (currentDepth > 0) {
438 auto& curState = dfsStack_[currentDepth - 1]; // -1: for current
439 auto curRegion = curState.region;
440 auto index = curState.index;
441
442 if (index == curRegion->succs_.size()) {
443 currentDepth--;
444 curRegion->SetFinished(acc_);
445 } else {
446 GateRegion* succ = curRegion->succs_[index];
447 curState.index = ++index;
448 if (succ->IsFinished(acc_)) {
449 continue;
450 }
451 if (succ->IsUnvisited(acc_)) {
452 currentDepth = Push(succ, currentDepth);
453 } else {
454 ASSERT(succ->IsVisited(acc_));
455 loopbacks_.emplace_back(DFSState(curRegion, index - 1)); // -1: for prev
456 if (!succ->HasLoopNumber()) {
457 succ->SetLoopNumber(numLoops_++);
458 }
459 }
460 }
461 }
462 }
463
ComputeLoopTree()464 void ComputeLoopTree()
465 {
466 linearizer_->circuit_->AdvanceTime();
467 auto entry = linearizer_->regionList_.front();
468 GraphLinearizer::LoopInfo *loopInfo = nullptr;
469 auto currentDepth = Push(entry, 0);
470 while (currentDepth > 0) {
471 auto &curState = dfsStack_[currentDepth - 1]; // -1: for current
472 auto curRegion = curState.region;
473 auto index = curState.index;
474 GateRegion* succ = nullptr;
475 if (index >= curRegion->succs_.size()) {
476 if (curRegion->HasLoopNumber()) {
477 if (curRegion->IsVisited(acc_)) {
478 ASSERT(loopInfo != nullptr && loopInfo->loopHead == curRegion);
479 loopInfo = loopInfo->outer;
480 curRegion->SetFinished(acc_);
481 }
482 auto loopExitIndex = index - curRegion->succs_.size();
483 auto& currentInfo = linearizer_->loops_[curRegion->GetLoopNumber()];
484 if (currentInfo.loopExits != nullptr && loopExitIndex < currentInfo.loopExits->size()) {
485 succ = currentInfo.loopExits->at(loopExitIndex);
486 curState.index++;
487 }
488 }
489 } else {
490 succ = curRegion->succs_[curState.index++]; // goto next
491 }
492 if (succ != nullptr) {
493 if (!succ->IsUnvisited(acc_)) {
494 continue;
495 }
496 if (loopInfo != nullptr && !loopInfo->loopBodys->TestBit(succ->GetId())) {
497 AddLoopExit(succ, loopInfo);
498 } else if (succ->IsUnvisited(acc_)) {
499 currentDepth = Push(succ, currentDepth);
500 loopInfo = EnterInnerLoop(succ, loopInfo);
501 }
502 } else {
503 if (!curRegion->HasLoopNumber()) {
504 curRegion->SetFinished(acc_);
505 }
506 currentDepth--;
507 }
508 }
509 }
510
AddLoopExit(GateRegion * succ,GraphLinearizer::LoopInfo * loopInfo)511 void AddLoopExit(GateRegion* succ, GraphLinearizer::LoopInfo *loopInfo)
512 {
513 if (loopInfo->loopExits == nullptr) {
514 loopInfo->loopExits = chunk_->New<ChunkVector<GateRegion*>>(chunk_);
515 }
516 loopInfo->loopExits->emplace_back(succ);
517 }
518
EnterInnerLoop(GateRegion * succ,GraphLinearizer::LoopInfo * loopInfo)519 GraphLinearizer::LoopInfo *EnterInnerLoop(GateRegion* succ, GraphLinearizer::LoopInfo *loopInfo)
520 {
521 // enter inner loop
522 if (succ->HasLoopNumber()) {
523 ASSERT_PRINT(succ->loopIndex_ != GateRegion::INVALID_INDEX, "GateRegion's index should be assigned");
524 auto& innerLoop = linearizer_->loops_[succ->GetLoopNumber()];
525 innerLoop.outer = loopInfo;
526 if (loopInfo != nullptr) {
527 innerLoop.loopDepth = loopInfo->loopDepth + 1;
528 } else {
529 innerLoop.loopDepth = 1;
530 }
531 succ->loopDepth_ = innerLoop.loopDepth;
532 loopInfo = &innerLoop;
533 } else if (loopInfo != nullptr) {
534 succ->loopIndex_ = static_cast<int32_t>(loopInfo->loopIndex);
535 succ->loopDepth_ = static_cast<int32_t>(loopInfo->loopDepth);
536 }
537 return loopInfo;
538 }
539
Push(GateRegion * region,size_t depth)540 size_t Push(GateRegion *region, size_t depth)
541 {
542 if (region->IsUnvisited(acc_)) {
543 dfsStack_[depth].region = region;
544 dfsStack_[depth].index = 0;
545 region->SetVisited(acc_);
546 return depth + 1;
547 }
548 return depth;
549 }
550
551 private:
552 struct DFSState {
DFSStatepanda::ecmascript::kungfu::LoopInfoBuilder::DFSState553 DFSState(GateRegion *region, size_t index)
554 : region(region), index(index) {}
555
556 GateRegion *region;
557 size_t index;
558 };
559 GraphLinearizer* linearizer_ {nullptr};
560 ChunkDeque<GateRegion*> pendingList_;
561 ChunkVector<DFSState> loopbacks_;
562 Chunk* chunk_ {nullptr};
563 ChunkVector<DFSState> dfsStack_;
564 GateAccessor acc_;
565 size_t numLoops_{0};
566 };
567
568 class GateScheduler {
569 public:
GateScheduler(GraphLinearizer * linearizer)570 explicit GateScheduler(GraphLinearizer *linearizer)
571 : linearizer_(linearizer), fixedGateList_(linearizer->chunk_),
572 pendingList_(linearizer->chunk_), acc_(linearizer->circuit_),
573 scheduleUpperBound_(linearizer_->scheduleUpperBound_) {}
574
InitializeFixedGate()575 void InitializeFixedGate()
576 {
577 auto ®ionRoots = linearizer_->regionRootList_;
578 auto size = regionRoots.size();
579 for (size_t i = 0; i < size; i++) {
580 auto fixedGate = regionRoots[i];
581 auto region = linearizer_->GateToRegion(fixedGate);
582 // fixed Gate's output
583 auto uses = acc_.Uses(fixedGate);
584 for (auto it = uses.begin(); it != uses.end(); it++) {
585 GateRef succGate = *it;
586 if (acc_.IsStateIn(it) && acc_.IsSelector(succGate)) {
587 linearizer_->AddFixedGateToRegion(succGate, region);
588 fixedGateList_.emplace_back(succGate);
589 }
590 }
591 }
592 }
593
Prepare()594 void Prepare()
595 {
596 InitializeFixedGate();
597 auto ®ionRoots = linearizer_->regionRootList_;
598 ASSERT(pendingList_.empty());
599 for (const auto rootGate : regionRoots) {
600 pendingList_.emplace_back(rootGate);
601 }
602 while (!pendingList_.empty()) {
603 auto curGate = pendingList_.back();
604 pendingList_.pop_back();
605 auto numIns = acc_.GetNumIns(curGate);
606 for (size_t i = 0; i < numIns; i++) {
607 VisitPreparedGate(Edge(curGate, i));
608 }
609 }
610 }
611
ScheduleUpperBound()612 void ScheduleUpperBound()
613 {
614 if (!scheduleUpperBound_) {
615 return;
616 }
617 auto ®ionRoots = linearizer_->regionRootList_;
618 ASSERT(pendingList_.empty());
619 for (const auto rootGate : regionRoots) {
620 pendingList_.emplace_back(rootGate);
621 }
622 while (!pendingList_.empty()) {
623 auto curGate = pendingList_.back();
624 pendingList_.pop_back();
625 auto uses = acc_.Uses(curGate);
626 for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
627 VisitUpperBoundGate(useIt.GetEdge());
628 }
629 }
630 }
631
VisitUpperBoundGate(Edge edge)632 void VisitUpperBoundGate(Edge edge)
633 {
634 GateRef succGate = edge.GetGate();
635 auto& succInfo = linearizer_->GetGateInfo(succGate);
636 if (!succInfo.IsSchedulable()) {
637 return;
638 }
639 ASSERT(succInfo.upperBound != nullptr);
640 auto curGate = acc_.GetIn(succGate, edge.GetIndex());
641 auto curUpperBound = linearizer_->GateToUpperBound(curGate);
642 ASSERT(IsInSameDominatorChain(curUpperBound, succInfo.upperBound));
643 if (curUpperBound->depth_ > succInfo.upperBound->depth_) {
644 succInfo.upperBound = curUpperBound;
645 pendingList_.emplace_back(succGate);
646 }
647 }
648
ScheduleFloatingGate()649 void ScheduleFloatingGate()
650 {
651 auto ®ionRoots = linearizer_->regionRootList_;
652 for (const auto rootGate : regionRoots) {
653 auto ins = acc_.Ins(rootGate);
654 for (auto it = ins.begin(); it != ins.end(); it++) {
655 pendingList_.emplace_back(*it);
656 while (!pendingList_.empty()) {
657 auto curGate = pendingList_.back();
658 pendingList_.pop_back();
659 ComputeLowerBoundAndScheduleGate(curGate);
660 }
661 }
662 }
663 }
664
VisitPreparedGate(Edge edge)665 void VisitPreparedGate(Edge edge)
666 {
667 auto curGate = edge.GetGate();
668 auto prevGate = acc_.GetIn(curGate, edge.GetIndex());
669 if (acc_.IsProlog(prevGate) || acc_.IsRoot(prevGate)) {
670 return;
671 }
672 auto& prevInfo = linearizer_->GetGateInfo(prevGate);
673 if (prevInfo.IsNone()) {
674 if (scheduleUpperBound_) {
675 prevInfo.upperBound = linearizer_->GetEntryRegion();
676 }
677 ASSERT(prevInfo.schedulableUseCount == 0);
678 prevInfo.state_ = GraphLinearizer::ScheduleState::SCHEDELABLE;
679 pendingList_.emplace_back(prevGate);
680 }
681 auto& curInfo = linearizer_->GetGateInfo(curGate);
682 if (prevInfo.IsSchedulable() && curInfo.IsSchedulable()) {
683 prevInfo.schedulableUseCount++;
684 }
685 }
686
ComputeLowerBoundAndScheduleGate(GateRef curGate)687 void ComputeLowerBoundAndScheduleGate(GateRef curGate)
688 {
689 auto& curInfo = linearizer_->GetGateInfo(curGate);
690 if (!curInfo.IsSchedulable() ||
691 (curInfo.schedulableUseCount != 0) || (curInfo.region != nullptr)) {
692 return;
693 }
694 auto region = GetCommonDominatorOfAllUses(curGate);
695 if (scheduleUpperBound_) {
696 ASSERT(curInfo.upperBound != nullptr);
697 ASSERT(linearizer_->GetCommonDominator(region, curInfo.upperBound) == curInfo.upperBound);
698 auto uppermost = curInfo.upperBound->depth_;
699 auto upperRegion = GetUpperBoundRegion(region);
700 while (upperRegion != nullptr && upperRegion->depth_ >= uppermost) {
701 region = upperRegion;
702 upperRegion = GetUpperBoundRegion(region);
703 }
704 }
705 ScheduleGate(curGate, region);
706 }
707
GetUpperBoundRegion(GateRegion * region)708 GateRegion* GetUpperBoundRegion(GateRegion* region)
709 {
710 if (region->IsLoopHead()) {
711 return region->iDominator_;
712 }
713 auto loopInfo = linearizer_->GetLoopInfo(region);
714 if (loopInfo != nullptr) {
715 if (!CheckRegionDomLoopExist(region, loopInfo)) {
716 return nullptr;
717 }
718 return loopInfo->loopHead->iDominator_;
719 }
720 return nullptr;
721 }
722
CheckRegionDomLoopExist(GateRegion * region,GraphLinearizer::LoopInfo * loopInfo)723 bool CheckRegionDomLoopExist(GateRegion* region, GraphLinearizer::LoopInfo* loopInfo)
724 {
725 if (loopInfo->loopExits == nullptr) {
726 return true;
727 }
728 for (auto exitRegion : *loopInfo->loopExits) {
729 if (linearizer_->GetCommonDominator(region, exitRegion) != region) {
730 return false;
731 }
732 }
733 return true;
734 }
735
ScheduleGate(GateRef gate,GateRegion * region)736 void ScheduleGate(GateRef gate, GateRegion* region)
737 {
738 auto ins = acc_.Ins(gate);
739 for (auto it = ins.begin(); it != ins.end(); it++) {
740 auto inputGate = *it;
741 auto& inputInfo = linearizer_->GetGateInfo(inputGate);
742 if (!inputInfo.IsSchedulable()) {
743 continue;
744 }
745 inputInfo.schedulableUseCount--;
746 if (inputInfo.schedulableUseCount == 0) {
747 pendingList_.emplace_back(inputGate);
748 }
749 }
750 ASSERT(!linearizer_->IsScheduled(gate));
751 linearizer_->BindGate(gate, region);
752 }
753
GetCommonDominatorOfAllUses(GateRef curGate)754 GateRegion* GetCommonDominatorOfAllUses(GateRef curGate)
755 {
756 GateRegion* region = nullptr;
757 auto uses = acc_.Uses(curGate);
758 for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
759 GateRef useGate = *useIt;
760 auto& useInfo = linearizer_->GetGateInfo(useGate);
761 if (useInfo.IsNone()) {
762 continue;
763 }
764 GateRegion* useRegion = useInfo.region;
765 if (useInfo.IsSelector()) {
766 GateRef state = acc_.GetState(useGate);
767 ASSERT(acc_.IsCFGMerge(state));
768 useGate = acc_.GetIn(state, useIt.GetIndex() - 1); // -1: for state
769 useRegion = linearizer_->FindPredRegion(useGate);
770 } else if (acc_.IsCFGMerge(useGate)) {
771 useGate = acc_.GetIn(useGate, useIt.GetIndex());
772 useRegion = linearizer_->FindPredRegion(useGate);
773 }
774
775 if (region == nullptr) {
776 region = useRegion;
777 } else {
778 ASSERT(useRegion != nullptr);
779 region = linearizer_->GetCommonDominator(region, useRegion);
780 }
781 }
782 return region;
783 }
784
IsInSameDominatorChain(GateRegion * left,GateRegion * right) const785 bool IsInSameDominatorChain(GateRegion* left, GateRegion* right) const
786 {
787 auto dom = linearizer_->GetCommonDominator(left, right);
788 return left == dom || right == dom;
789 }
790
ScheduleFixedGate()791 void ScheduleFixedGate()
792 {
793 for (auto gate : fixedGateList_) {
794 GateRegion* region = linearizer_->GateToRegion(gate);
795 linearizer_->BindGate(gate, region);
796 }
797 #ifndef NDEBUG
798 Verify();
799 #endif
800 }
801
Verify()802 void Verify()
803 {
804 std::vector<GateRef> gateList;
805 linearizer_->circuit_->GetAllGates(gateList);
806 for (const auto &gate : gateList) {
807 auto& gateInfo = linearizer_->GetGateInfo(gate);
808 if (gateInfo.IsSchedulable()) {
809 ASSERT(linearizer_->IsScheduled(gate));
810 }
811 ASSERT(gateInfo.schedulableUseCount == 0);
812 }
813 }
814
815 private:
816 GraphLinearizer* linearizer_ {nullptr};
817 ChunkVector<GateRef> fixedGateList_;
818 ChunkDeque<GateRef> pendingList_;
819 GateAccessor acc_;
820 bool scheduleUpperBound_{false};
821 };
822
LinearizeGraph()823 void GraphLinearizer::LinearizeGraph()
824 {
825 gateIdToGateInfo_.resize(circuit_->GetMaxGateId() + 1, GateInfo{nullptr}); // 1: max + 1 = size
826 CFGBuilder builder(this);
827 builder.Run();
828 ImmediateDominatorsGenerator generator(this, chunk_, regionList_.size());
829 generator.Run();
830 if (IsEnableLoopInvariantCodeMotion() && loopNumber_ > 0) {
831 scheduleUpperBound_ = true;
832 LoopInfoBuilder loopInfoBuilder(this, chunk_);
833 loopInfoBuilder.Run();
834 }
835 if (!onlyBB_) {
836 GateScheduler scheduler(this);
837 scheduler.Prepare();
838 scheduler.ScheduleUpperBound();
839 scheduler.ScheduleFloatingGate();
840 scheduler.ScheduleFixedGate();
841 }
842 }
843
CreateGateRegion(GateRef gate)844 void GraphLinearizer::CreateGateRegion(GateRef gate)
845 {
846 ASSERT(GateToRegion(gate) == nullptr);
847 auto region = new (chunk_) GateRegion(chunk_);
848 region->id_ = regionList_.size();
849 regionList_.emplace_back(region);
850 if (acc_.GetOpCode(gate) == OpCode::LOOP_BEGIN) {
851 loopNumber_++;
852 region->stateKind_ = GateRegion::StateKind::LOOP_HEAD;
853 }
854 AddRootGateToRegion(gate, region);
855 }
856
LinearizeRegions(ControlFlowGraph & result)857 void GraphLinearizer::LinearizeRegions(ControlFlowGraph &result)
858 {
859 size_t liveNum = OptimizeCFG();
860
861 ASSERT(result.size() == 0);
862 result.resize(liveNum);
863 auto uses = acc_.Uses(acc_.GetArgRoot());
864 for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
865 regionList_.front()->gateList_.emplace_back(*useIt);
866 }
867
868 size_t i = 0;
869 for (size_t id = 0; id < regionList_.size(); id++) {
870 GateRegion* r = regionList_[id];
871 if (r->IsDead()) {
872 continue;
873 }
874 auto& gates = r->GetGates();
875 auto& bb = result[i];
876 bb.insert(bb.end(), gates.begin(), gates.end());
877 i++;
878 }
879 }
880
IsSimple(GateAccessor * acc) const881 bool GateRegion::IsSimple(GateAccessor *acc) const
882 {
883 for (auto g : gateList_) {
884 bool isSimple = acc->IsSimpleState(g);
885 bool complexOut = HasComplexOuts();
886 if (!isSimple || complexOut) {
887 return false;
888 }
889 }
890 return true;
891 }
892
OptimizeControls(GateRegion * region)893 size_t GraphLinearizer::OptimizeControls(GateRegion *region)
894 {
895 size_t deads = 0;
896 GateRegion* target = region;
897 do {
898 GateRegion* succ = target->GetSimpleSuccRegion();
899 if (succ == nullptr) {
900 break;
901 }
902 MoveAndClear(target, succ);
903 target = succ;
904 deads++;
905 } while (target->IsSimple(&acc_));
906 return deads;
907 }
908
MoveAndClear(GateRegion * from,GateRegion * to)909 void GraphLinearizer::MoveAndClear(GateRegion* from, GateRegion* to)
910 {
911 ASSERT(from != to);
912 ASSERT(to->GetPreds().size() == 1);
913 for (GateRef g: from->GetGates()) {
914 ASSERT(acc_.IsSimpleState(g));
915 OpCode op = acc_.GetOpCode(g);
916 switch (op) {
917 case OpCode::IF_TRUE:
918 case OpCode::IF_FALSE:
919 case OpCode::SWITCH_CASE:
920 case OpCode::DEFAULT_CASE:
921 case OpCode::LOOP_BACK:
922 case OpCode::ORDINARY_BLOCK:
923 case OpCode::MERGE:
924 case OpCode::VALUE_SELECTOR:
925 to->AddGate(g);
926 break;
927 default:
928 break;
929 }
930 }
931 for (auto p : from->GetPreds()) {
932 p->ReplaceSucc(from, to);
933 }
934 to->RemovePred(from);
935 from->SetDead();
936 #ifndef NDEBUG
937 from->Clear();
938 #endif
939 }
940
OptimizeCFG()941 size_t GraphLinearizer::OptimizeCFG()
942 {
943 size_t liveNum = regionList_.size();
944 for (size_t i = 0; i < regionList_.size(); i++) {
945 GateRegion* src = regionList_[i];
946 if (!src->IsDead() && src->IsSimple(&acc_)) {
947 size_t dead = OptimizeControls(src);
948 liveNum -= dead;
949 }
950 }
951 return liveNum;
952 }
953
FindPredRegion(GateRef input)954 GateRegion* GraphLinearizer::FindPredRegion(GateRef input)
955 {
956 GateRegion* predRegion = GateToRegion(input);
957 while (predRegion == nullptr) {
958 ASSERT(acc_.GetStateCount(input) == 1); // 1: fall through block
959 input = acc_.GetState(input);
960 predRegion = GateToRegion(input);
961 }
962 ASSERT(predRegion != nullptr);
963 return predRegion;
964 }
965
GetCommonDominator(GateRegion * left,GateRegion * right) const966 GateRegion* GraphLinearizer::GetCommonDominator(GateRegion* left, GateRegion* right) const
967 {
968 while (left != right) {
969 if (left->depth_ < right->depth_) {
970 right = right->iDominator_;
971 } else {
972 left = left->iDominator_;
973 }
974 }
975 return left;
976 }
977
PrintGraph(const char * title)978 void GraphLinearizer::PrintGraph(const char* title)
979 {
980 LOG_COMPILER(INFO) << "======================== " << title << " ========================";
981 int bbIdx = 0;
982 for (size_t i = 0; i < regionList_.size(); i++) {
983 auto bb = regionList_[i];
984 if (bb->IsDead()) {
985 continue;
986 }
987 auto front = bb->gateList_.front();
988 auto opcode = acc_.GetOpCode(front);
989 size_t loopHeadId = 0;
990 auto loopInfo = GetLoopInfo(bb);
991 if (loopInfo != nullptr) {
992 loopHeadId = loopInfo->loopHead->id_;
993 }
994 LOG_COMPILER(INFO) << "B" << bb->id_ << "_LB" << bbIdx << ": " << "depth: [" << bb->depth_ << "] "
995 << opcode << "(" << acc_.GetId(front) << ") "
996 << "IDom B" << bb->iDominator_->id_ << " loop Header: " << loopHeadId;
997 std::string log("\tPreds: ");
998 for (size_t k = 0; k < bb->preds_.size(); ++k) {
999 log += std::to_string(bb->preds_[k]->id_) + ", ";
1000 }
1001 LOG_COMPILER(INFO) << log;
1002 std::string log1("\tSucces: ");
1003 for (size_t j = 0; j < bb->succs_.size(); j++) {
1004 log1 += std::to_string(bb->succs_[j]->id_) + ", ";
1005 }
1006 LOG_COMPILER(INFO) << log1;
1007 for (auto it = bb->gateList_.crbegin(); it != bb->gateList_.crend(); it++) {
1008 acc_.Print(*it);
1009 }
1010 LOG_COMPILER(INFO) << "";
1011 bbIdx++;
1012 }
1013 }
1014 } // namespace panda::ecmascript::kungfu
1015