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 ®ionList = 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 ®ionList = 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 ®ionRoots = 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 ®ionRoots = 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 ®ionRoots = 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 ®ionRoots = 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