• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &regionList = 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 &regionList = 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 &regionRoots = 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 &regionRoots = 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 &regionRoots = 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 &regionRoots = 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