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