• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 "basicblock.h"
17 #include "graph.h"
18 #include "inst.h"
19 #include "optimizer/analysis/loop_analyzer.h"
20 #include "optimizer/analysis/dominators_tree.h"
21 
22 namespace ark::compiler {
23 class Inst;
BasicBlock(Graph * graph,uint32_t guestPc)24 BasicBlock::BasicBlock(Graph *graph, uint32_t guestPc)
25     : graph_(graph),
26       preds_(graph_->GetAllocator()->Adapter()),
27       succs_(graph_->GetAllocator()),
28       domBlocks_(graph_->GetAllocator()->Adapter()),
29       guestPc_(guestPc)
30 {
31 }
32 
SetId(uint32_t id)33 void BasicBlock::SetId(uint32_t id)
34 {
35     bbId_ = id;
36 }
GetId() const37 uint32_t BasicBlock::GetId() const
38 {
39     return bbId_;
40 }
41 
GetPredsBlocks()42 ArenaVector<BasicBlock *> &BasicBlock::GetPredsBlocks()
43 {
44     return preds_;
45 }
GetPredsBlocks() const46 const ArenaVector<BasicBlock *> &BasicBlock::GetPredsBlocks() const
47 {
48     return preds_;
49 }
50 
GetSuccsBlocks()51 BasicBlock::SuccsVector &BasicBlock::GetSuccsBlocks()
52 {
53     return succs_;
54 }
GetSuccsBlocks() const55 const BasicBlock::SuccsVector &BasicBlock::GetSuccsBlocks() const
56 {
57     return succs_;
58 }
59 
GetSuccessor(size_t index) const60 BasicBlock *BasicBlock::GetSuccessor(size_t index) const
61 {
62     ASSERT(index < succs_.size());
63     return succs_[index];
64 }
65 
GetPredecessor(size_t index) const66 BasicBlock *BasicBlock::GetPredecessor(size_t index) const
67 {
68     ASSERT(index < preds_.size());
69     return preds_[index];
70 }
71 
IsInverted() const72 bool BasicBlock::IsInverted() const
73 {
74     return inverted_;
75 }
76 
SetHotness(int64_t hotness)77 void BasicBlock::SetHotness(int64_t hotness)
78 {
79     hotness_ = hotness;
80 }
81 
GetHotness() const82 int64_t BasicBlock::GetHotness() const
83 {
84     return hotness_;
85 }
86 
GetTrueSuccessor() const87 BasicBlock *BasicBlock::GetTrueSuccessor() const
88 {
89     ASSERT(!succs_.empty());
90     return succs_[TRUE_SUCC_IDX];
91 }
92 
GetFalseSuccessor() const93 BasicBlock *BasicBlock::GetFalseSuccessor() const
94 {
95     ASSERT(succs_.size() > 1);
96     return succs_[FALSE_SUCC_IDX];
97 }
98 
GetPredBlockIndex(const BasicBlock * block) const99 size_t BasicBlock::GetPredBlockIndex(const BasicBlock *block) const
100 {
101     auto it = std::find(preds_.begin(), preds_.end(), block);
102     ASSERT(it != preds_.end());
103     ASSERT(std::find(it + 1, preds_.end(), block) == preds_.end());
104     return std::distance(preds_.begin(), it);
105 }
106 
GetSuccBlockIndex(const BasicBlock * block) const107 size_t BasicBlock::GetSuccBlockIndex(const BasicBlock *block) const
108 {
109     auto it = std::find(succs_.begin(), succs_.end(), block);
110     ASSERT(it != succs_.end());
111     ASSERT(std::find(it + 1, succs_.end(), block) == succs_.end());
112     return std::distance(succs_.begin(), it);
113 }
114 
GetPredBlockByIndex(size_t index) const115 BasicBlock *BasicBlock::GetPredBlockByIndex(size_t index) const
116 {
117     ASSERT(index < preds_.size());
118     return preds_[index];
119 }
120 
GetGraph()121 Graph *BasicBlock::GetGraph()
122 {
123     return graph_;
124 }
125 
GetGraph() const126 const Graph *BasicBlock::GetGraph() const
127 {
128     return graph_;
129 }
130 
SetGraph(Graph * graph)131 void BasicBlock::SetGraph(Graph *graph)
132 {
133     graph_ = graph;
134 }
135 
SetGuestPc(uint32_t guestPc)136 void BasicBlock::SetGuestPc(uint32_t guestPc)
137 {
138     guestPc_ = guestPc;
139 }
140 
GetGuestPc() const141 uint32_t BasicBlock::GetGuestPc() const
142 {
143     return guestPc_;
144 }
145 
HasSucc(BasicBlock * succ)146 bool BasicBlock::HasSucc(BasicBlock *succ)
147 {
148     return std::find(succs_.begin(), succs_.end(), succ) != succs_.end();
149 }
150 
ReplacePred(BasicBlock * prevPred,BasicBlock * newPred)151 void BasicBlock::ReplacePred(BasicBlock *prevPred, BasicBlock *newPred)
152 {
153     preds_[GetPredBlockIndex(prevPred)] = newPred;
154     newPred->succs_.push_back(this);
155 }
156 
ReplaceTrueSuccessor(BasicBlock * newSucc)157 void BasicBlock::ReplaceTrueSuccessor(BasicBlock *newSucc)
158 {
159     ASSERT(!succs_.empty());
160     succs_[TRUE_SUCC_IDX] = newSucc;
161     newSucc->preds_.push_back(this);
162 }
163 
ReplaceFalseSuccessor(BasicBlock * newSucc)164 void BasicBlock::ReplaceFalseSuccessor(BasicBlock *newSucc)
165 {
166     ASSERT(succs_.size() > 1);
167     succs_[FALSE_SUCC_IDX] = newSucc;
168     newSucc->preds_.push_back(this);
169 }
170 
PrependInst(Inst * inst)171 void BasicBlock::PrependInst(Inst *inst)
172 {
173     AddInst<false>(inst);
174 }
175 // Insert new instruction(NOT PHI) in BasicBlock at the end of instructions
AppendInst(Inst * inst)176 void BasicBlock::AppendInst(Inst *inst)
177 {
178     AddInst<true>(inst);
179 }
AppendInsts(std::initializer_list<Inst * > && insts)180 void BasicBlock::AppendInsts(std::initializer_list<Inst *> &&insts)
181 {
182     for (auto inst : insts) {
183         AddInst<true>(inst);
184     }
185 }
186 
GetLastInst() const187 Inst *BasicBlock::GetLastInst() const
188 {
189     return lastInst_;
190 }
191 
IsEndWithThrowOrDeoptimize() const192 bool BasicBlock::IsEndWithThrowOrDeoptimize() const
193 {
194     if (lastInst_ == nullptr) {
195         return false;
196     }
197     return lastInst_->IsControlFlow() && lastInst_->CanThrow() && lastInst_->IsTerminator();
198 }
199 
IsEndWithThrow() const200 bool BasicBlock::IsEndWithThrow() const
201 {
202     if (lastInst_ == nullptr) {
203         return false;
204     }
205     return lastInst_->GetOpcode() == Opcode::Throw;
206 }
207 
GetFirstInst() const208 Inst *BasicBlock::GetFirstInst() const
209 {
210     return firstInst_;
211 }
212 
GetFirstPhi() const213 Inst *BasicBlock::GetFirstPhi() const
214 {
215     return firstPhi_;
216 }
217 
IsEmpty() const218 bool BasicBlock::IsEmpty() const
219 {
220     return firstInst_ == nullptr;
221 }
222 
HasPhi() const223 bool BasicBlock::HasPhi() const
224 {
225     return firstPhi_ != nullptr;
226 }
227 
SetDominator(BasicBlock * dominator)228 void BasicBlock::SetDominator(BasicBlock *dominator)
229 {
230     dominator_ = dominator;
231 }
ClearDominator()232 void BasicBlock::ClearDominator()
233 {
234     dominator_ = nullptr;
235 }
236 
AddDominatedBlock(BasicBlock * block)237 void BasicBlock::AddDominatedBlock(BasicBlock *block)
238 {
239     domBlocks_.push_back(block);
240 }
241 
RemoveDominatedBlock(BasicBlock * block)242 void BasicBlock::RemoveDominatedBlock(BasicBlock *block)
243 {
244     domBlocks_.erase(std::find(domBlocks_.begin(), domBlocks_.end(), block));
245 }
246 
ClearDominatedBlocks()247 void BasicBlock::ClearDominatedBlocks()
248 {
249     domBlocks_.clear();
250 }
251 
RemovePred(const BasicBlock * pred)252 void BasicBlock::RemovePred(const BasicBlock *pred)
253 {
254     ASSERT(GetPredBlockIndex(pred) < preds_.size());
255     preds_[GetPredBlockIndex(pred)] = preds_.back();
256     preds_.pop_back();
257 }
258 
RemovePred(size_t index)259 void BasicBlock::RemovePred(size_t index)
260 {
261     ASSERT(index < preds_.size());
262     preds_[index] = preds_.back();
263     preds_.pop_back();
264 }
265 
RemoveSucc(BasicBlock * succ)266 void BasicBlock::RemoveSucc(BasicBlock *succ)
267 {
268     auto it = std::find(succs_.begin(), succs_.end(), succ);
269     ASSERT(it != succs_.end());
270     succs_.erase(it);
271 }
272 
GetLoop() const273 Loop *BasicBlock::GetLoop() const
274 {
275     return loop_;
276 }
SetLoop(Loop * loop)277 void BasicBlock::SetLoop(Loop *loop)
278 {
279     loop_ = loop;
280 }
IsLoopValid() const281 bool BasicBlock::IsLoopValid() const
282 {
283     return GetLoop() != nullptr;
284 }
285 
SetNextLoop(Loop * loop)286 void BasicBlock::SetNextLoop(Loop *loop)
287 {
288     nextLoop_ = loop;
289 }
290 
GetNextLoop()291 Loop *BasicBlock::GetNextLoop()
292 {
293     return nextLoop_;
294 }
295 
IsLoopPreHeader() const296 bool BasicBlock::IsLoopPreHeader() const
297 {
298     return (nextLoop_ != nullptr);
299 }
300 
SetAllFields(uint32_t bitFields)301 void BasicBlock::SetAllFields(uint32_t bitFields)
302 {
303     bitFields_ = bitFields;
304 }
305 
GetAllFields() const306 uint32_t BasicBlock::GetAllFields() const
307 {
308     return bitFields_;
309 }
310 
SetMonitorEntryBlock(bool v)311 void BasicBlock::SetMonitorEntryBlock(bool v)
312 {
313     SetField<MonitorEntryBlock>(v);
314 }
315 
GetMonitorEntryBlock()316 bool BasicBlock::GetMonitorEntryBlock()
317 {
318     return GetField<MonitorEntryBlock>();
319 }
320 
SetMonitorExitBlock(bool v)321 void BasicBlock::SetMonitorExitBlock(bool v)
322 {
323     SetField<MonitorExitBlock>(v);
324 }
325 
GetMonitorExitBlock() const326 bool BasicBlock::GetMonitorExitBlock() const
327 {
328     return GetField<MonitorExitBlock>();
329 }
330 
SetMonitorBlock(bool v)331 void BasicBlock::SetMonitorBlock(bool v)
332 {
333     SetField<MonitorBlock>(v);
334 }
335 
GetMonitorBlock() const336 bool BasicBlock::GetMonitorBlock() const
337 {
338     return GetField<MonitorBlock>();
339 }
340 
SetCatch(bool v)341 void BasicBlock::SetCatch(bool v)
342 {
343     SetField<CatchBlock>(v);
344 }
345 
IsCatch() const346 bool BasicBlock::IsCatch() const
347 {
348     return GetField<CatchBlock>();
349 }
350 
SetCatchBegin(bool v)351 void BasicBlock::SetCatchBegin(bool v)
352 {
353     SetField<CatchBeginBlock>(v);
354 }
355 
IsCatchBegin() const356 bool BasicBlock::IsCatchBegin() const
357 {
358     return GetField<CatchBeginBlock>();
359 }
360 
SetTry(bool v)361 void BasicBlock::SetTry(bool v)
362 {
363     SetField<TryBlock>(v);
364 }
365 
IsTry() const366 bool BasicBlock::IsTry() const
367 {
368     return GetField<TryBlock>();
369 }
370 
SetTryBegin(bool v)371 void BasicBlock::SetTryBegin(bool v)
372 {
373     SetField<TryBeginBlock>(v);
374 }
375 
IsTryBegin() const376 bool BasicBlock::IsTryBegin() const
377 {
378     return GetField<TryBeginBlock>();
379 }
380 
SetTryEnd(bool v)381 void BasicBlock::SetTryEnd(bool v)
382 {
383     SetField<TryEndBlock>(v);
384 }
385 
IsTryEnd() const386 bool BasicBlock::IsTryEnd() const
387 {
388     return GetField<TryEndBlock>();
389 }
390 
SetOsrEntry(bool v)391 void BasicBlock::SetOsrEntry(bool v)
392 {
393     SetField<OsrEntry>(v);
394 }
395 
IsOsrEntry() const396 bool BasicBlock::IsOsrEntry() const
397 {
398     return GetField<OsrEntry>();
399 }
400 
CopyTryCatchProps(BasicBlock * block)401 void BasicBlock::CopyTryCatchProps(BasicBlock *block)
402 {
403     if (block->IsTry()) {
404         SetTry(true);
405         SetTryId(block->GetTryId());
406     }
407     if (block->IsCatch()) {
408         SetCatch(true);
409     }
410 }
411 
GetTryId() const412 uint32_t BasicBlock::GetTryId() const
413 {
414     return tryId_;
415 }
416 
SetTryId(uint32_t tryId)417 void BasicBlock::SetTryId(uint32_t tryId)
418 {
419     tryId_ = tryId;
420 }
421 
SetNeedsJump(bool v)422 void BasicBlock::SetNeedsJump(bool v)
423 {
424     SetField<JumpFlag>(v);
425 }
426 
NeedsJump() const427 bool BasicBlock::NeedsJump() const
428 {
429     return GetField<JumpFlag>();
430 }
431 
IsIfBlock() const432 bool BasicBlock::IsIfBlock() const
433 {
434     if (lastInst_ != nullptr) {
435         if (lastInst_->GetOpcode() == Opcode::If || lastInst_->GetOpcode() == Opcode::IfImm) {
436             return true;
437         }
438     }
439     return false;
440 }
441 
IsStartBlock() const442 bool BasicBlock::IsStartBlock() const
443 {
444     return (graph_->GetStartBlock() == this);
445 }
IsEndBlock() const446 bool BasicBlock::IsEndBlock() const
447 {
448     return (graph_->GetEndBlock() == this);
449 }
IsPseudoControlFlowBlock() const450 bool BasicBlock::IsPseudoControlFlowBlock() const
451 {
452     return IsStartBlock() || IsEndBlock() || IsTryBegin() || IsTryEnd();
453 }
454 
IsLoopHeader() const455 bool BasicBlock::IsLoopHeader() const
456 {
457     ASSERT(GetLoop() != nullptr);
458     return (GetLoop()->GetHeader() == this);
459 }
460 
IsLoopPostExit() const461 bool BasicBlock::IsLoopPostExit() const
462 {
463     for (auto innerLoop : GetLoop()->GetInnerLoops()) {
464         if (innerLoop->IsPostExitBlock(this)) {
465             return true;
466         }
467     }
468 
469     return false;
470 }
471 
IsTryCatch() const472 bool BasicBlock::IsTryCatch() const
473 {
474     return IsTry() || IsTryBegin() || IsTryEnd() || IsCatch() || IsCatchBegin();
475 }
476 
SplitBlockAfterInstruction(Inst * inst,bool makeEdge)477 BasicBlock *BasicBlock::SplitBlockAfterInstruction(Inst *inst, bool makeEdge)
478 {
479     ASSERT(inst != nullptr);
480     ASSERT(inst->GetBasicBlock() == this);
481     ASSERT(!IsStartBlock() && !IsEndBlock());
482 
483     auto nextInst = inst->GetNext();
484     auto newBb = GetGraph()->CreateEmptyBlock((nextInst != nullptr) ? nextInst->GetPc() : INVALID_PC);
485     newBb->SetAllFields(this->GetAllFields());
486     newBb->SetOsrEntry(false);
487     GetLoop()->AppendBlock(newBb);
488 
489     for (; nextInst != nullptr; nextInst = nextInst->GetNext()) {
490         newBb->AppendInst(nextInst);
491     }
492     inst->SetNext(nullptr);
493     lastInst_ = inst;
494     if (inst->IsPhi()) {
495         firstInst_ = nullptr;
496     }
497     for (auto succ : GetSuccsBlocks()) {
498         succ->ReplacePred(this, newBb);
499     }
500     GetSuccsBlocks().clear();
501 
502     ASSERT(GetSuccsBlocks().empty());
503     if (makeEdge) {
504         AddSucc(newBb);
505     }
506     return newBb;
507 }
508 
AddSucc(BasicBlock * succ,bool canAddEmptyBlock)509 void BasicBlock::AddSucc(BasicBlock *succ, bool canAddEmptyBlock)
510 {
511     auto it = std::find(succs_.begin(), succs_.end(), succ);
512     ASSERT_PRINT(it == succs_.end() || canAddEmptyBlock, "Uncovered case where empty block needed to fix CFG");
513     if (it != succs_.end() && canAddEmptyBlock) {
514         // If edge already exists we create empty block on it
515         auto emptyBb = GetGraph()->CreateEmptyBlock(GetGuestPc());
516         ReplaceSucc(succ, emptyBb);
517         succ->ReplacePred(this, emptyBb);
518     }
519     succs_.push_back(succ);
520     succ->GetPredsBlocks().push_back(this);
521 }
522 
ReplaceSucc(const BasicBlock * prevSucc,BasicBlock * newSucc,bool canAddEmptyBlock)523 void BasicBlock::ReplaceSucc(const BasicBlock *prevSucc, BasicBlock *newSucc, bool canAddEmptyBlock)
524 {
525     auto it = std::find(succs_.begin(), succs_.end(), newSucc);
526     ASSERT_PRINT(it == succs_.end() || canAddEmptyBlock, "Uncovered case where empty block needed to fix CFG");
527     if (it != succs_.end() && canAddEmptyBlock) {
528         // If edge already exists we create empty block on it
529         auto emptyBb = GetGraph()->CreateEmptyBlock(GetGuestPc());
530         ReplaceSucc(newSucc, emptyBb);
531         newSucc->ReplacePred(this, emptyBb);
532     }
533     succs_[GetSuccBlockIndex(prevSucc)] = newSucc;
534     newSucc->preds_.push_back(this);
535 }
536 
InsertNewBlockToSuccEdge(BasicBlock * succ)537 BasicBlock *BasicBlock::InsertNewBlockToSuccEdge(BasicBlock *succ)
538 {
539     auto block = GetGraph()->CreateEmptyBlock(succ->GetGuestPc());
540     this->ReplaceSucc(succ, block);
541     succ->ReplacePred(this, block);
542     return block;
543 }
544 
InsertEmptyBlockBefore()545 BasicBlock *BasicBlock::InsertEmptyBlockBefore()
546 {
547     auto block = GetGraph()->CreateEmptyBlock(this->GetGuestPc());
548     for (auto pred : preds_) {
549         pred->ReplaceSucc(this, block);
550         this->RemovePred(pred);
551     }
552     block->AddSucc(this);
553     return block;
554 }
555 
InsertBlockBeforeSucc(BasicBlock * block,BasicBlock * succ)556 void BasicBlock::InsertBlockBeforeSucc(BasicBlock *block, BasicBlock *succ)
557 {
558     this->ReplaceSucc(succ, block);
559     succ->ReplacePred(this, block);
560 }
561 
RemovePhiProcessing(BasicBlock * bb,BasicBlock * succ)562 static void RemovePhiProcessing(BasicBlock *bb, BasicBlock *succ)
563 {
564     size_t numPreds = bb->GetPredsBlocks().size();
565 
566     for (auto phi : succ->PhiInsts()) {
567         auto index = phi->CastToPhi()->GetPredBlockIndex(bb);
568         auto inst = phi->GetInput(index).GetInst();
569         if (inst->GetBasicBlock() == bb) {  // When INST is from empty basic block ...
570             ASSERT(inst->IsPhi());
571             // ... we have to copy it's inputs into corresponding inputs of PHI
572             auto predBb = bb->GetPredBlockByIndex(0);
573             phi->SetInput(index, inst->CastToPhi()->GetPhiInput(predBb));
574             for (size_t i = 1; i < numPreds; i++) {
575                 predBb = bb->GetPredBlockByIndex(i);
576                 phi->AppendInput(inst->CastToPhi()->GetPhiInput(predBb));
577             }
578         } else {  // otherwise, just copy inputs for new arrived predecessors
579             for (size_t i = 1; i < numPreds; i++) {
580                 phi->AppendInput(inst);
581             }
582         }
583     }
584     // And now we should remove Phis from the empty block
585     for (auto phi : bb->PhiInstsSafe()) {
586         bb->RemoveInst(phi);
587     }
588 }
589 
590 // Remove empty block with one successor, may have more than one predecessors and Phi(s)
RemoveEmptyBlock(bool irrLoop)591 void BasicBlock::RemoveEmptyBlock(bool irrLoop)
592 {
593     ASSERT(GetFirstInst() == nullptr);
594     ASSERT(!GetPredsBlocks().empty());
595     ASSERT(GetSuccsBlocks().size() == 1);
596     auto succ = succs_[0];
597 
598     // Save old amount of predecessors in successor block
599     size_t succPredsNum = succ->GetPredsBlocks().size();
600 
601     size_t numPreds = preds_.size();
602     // If empty block had more than one predecessors
603     if (numPreds > 1) {
604         if (succPredsNum > 1) {
605             // We have to process Phi instructions in successor block in a special way
606             RemovePhiProcessing(this, succ);
607         } else {  // successor didn't have other predecessors, we are moving Phi(s) into successor
608             ASSERT(!succ->HasPhi());
609             for (auto phi : PhiInstsSafe()) {
610                 succ->AppendPhi(phi);
611             }
612             firstPhi_ = nullptr;
613             lastInst_ = nullptr;
614         }
615     }
616 
617     // Set successor for all predecessor blocks, at the same time in successor we replace one predecessor
618     // and add others to the end (if there were many of them in empty block)
619     auto pred = preds_[0];
620     pred->succs_[pred->GetSuccBlockIndex(this)] = succ;
621     succ->preds_[succ->GetPredBlockIndex(this)] = pred;
622     for (size_t i = 1; i < numPreds; ++i) {
623         pred = preds_[i];
624         pred->succs_[pred->GetSuccBlockIndex(this)] = succ;
625         succ->preds_.push_back(pred);
626     }
627 
628     ASSERT(GetLastInst() == nullptr);
629     ASSERT(GetLoop()->IsIrreducible() == irrLoop);
630     // N.B. info about Irreducible loop can not be fixed on the fly
631     if (!irrLoop) {
632         RemoveFixLoopInfo();
633     }
634     // Finally clean lists
635     preds_.clear();
636     succs_.clear();
637 }
638 
FixLoopInfoHelper(BasicBlock * bb)639 static void FixLoopInfoHelper(BasicBlock *bb)
640 {
641     ASSERT(!bb->GetPredsBlocks().empty());
642     auto loop = bb->GetLoop();
643     auto firstPred = bb->GetPredBlockByIndex(0);
644     // Do not dup back-edge
645     if (loop->HasBackEdge(firstPred)) {
646         loop->RemoveBackEdge(bb);
647     } else {
648         loop->ReplaceBackEdge(bb, firstPred);
649     }
650     // If empty block has more than 1 predecessor, append others to the loop back-edges' list
651     for (size_t i = 1; i < bb->GetPredsBlocks().size(); ++i) {
652         auto pred = bb->GetPredBlockByIndex(i);
653         if (!loop->HasBackEdge(pred)) {
654             loop->AppendBackEdge(pred);
655         }
656     }
657 }
658 
RemoveFixLoopInfo()659 void BasicBlock::RemoveFixLoopInfo()
660 {
661     auto loop = GetLoop();
662     ASSERT(loop != nullptr);
663     ASSERT(!loop->IsIrreducible());
664     while (!loop->IsRoot()) {
665         if (loop->HasBackEdge(this)) {
666             FixLoopInfoHelper(this);
667         }
668         loop = loop->GetOuterLoop();
669     }
670     if (this == GetLoop()->GetHeader()) {
671         GetLoop()->MoveHeaderToSucc();
672     }
673     GetLoop()->RemoveBlock(this);
674 }
675 
676 /**
677  * Join single successor into single predecessor.
678  * Block must have one successor, and its successor must have one predecessor (this block).
679  * EXAMPLE:
680  *              [1]
681  *               |
682  *              [2]
683  *
684  * turns into this:
685  *              [1']
686  */
JoinSuccessorBlock()687 void BasicBlock::JoinSuccessorBlock()
688 {
689     ASSERT(!IsStartBlock());
690 
691     ASSERT(GetSuccsBlocks().size() == 1);
692     auto succ = GetSuccessor(0);
693     ASSERT(!succ->IsEndBlock());
694 
695     ASSERT(succ->GetPredsBlocks().size() == 1);
696     ASSERT(succ->GetPredBlockByIndex(0) == this);
697 
698     // moving instructions from successor
699     ASSERT(!succ->HasPhi());
700     for (auto succInst : succ->Insts()) {
701         AppendInst(succInst);
702     }
703 
704     // moving successor blocks from the successor
705     GetSuccsBlocks().clear();
706     for (auto succSucc : succ->GetSuccsBlocks()) {
707         succSucc->ReplacePred(succ, this);
708     }
709 
710     if (GetGraph()->IsAnalysisValid<LoopAnalyzer>()) {
711         // fixing loop information
712         // invariant: succ has one predecessor, so it cannot be a loop header
713         auto loop = succ->GetLoop();
714         ASSERT(loop != nullptr);
715         // Irreducible loop can not be fixed on the fly
716         if (loop->IsIrreducible() || GetGraph()->IsThrowApplied()) {
717             GetGraph()->InvalidateAnalysis<LoopAnalyzer>();
718         } else {
719             // edge can have 2 successors, so it can be back-edge in 2 loops: own loop and outer loop
720             ReplaceSuccessorLoopBackEdges(loop, succ);
721             loop->RemoveBlock(succ);
722         }
723     }
724 
725     succ->firstInst_ = nullptr;
726     succ->lastInst_ = nullptr;
727     succ->GetPredsBlocks().clear();
728     succ->GetSuccsBlocks().clear();
729 
730     this->bitFields_ |= succ->bitFields_;
731     // NOTE (a.popov) replace by assert
732     if (succ->tryId_ != INVALID_ID) {
733         this->tryId_ = succ->tryId_;
734     }
735     GetGraph()->RemoveEmptyBlock(succ);
736 }
737 
ReplaceSuccessorLoopBackEdges(Loop * loop,BasicBlock * succ)738 void BasicBlock::ReplaceSuccessorLoopBackEdges(Loop *loop, BasicBlock *succ)
739 {
740     if (loop->HasBackEdge(succ)) {
741         loop->ReplaceBackEdge(succ, this);
742     }
743     for (auto outerLoop = loop->GetOuterLoop(); outerLoop != nullptr; outerLoop = outerLoop->GetOuterLoop()) {
744         if (outerLoop->HasBackEdge(succ)) {
745             outerLoop->ReplaceBackEdge(succ, this);
746         }
747     }
748     for (auto innerLoop : loop->GetInnerLoops()) {
749         if (innerLoop->GetPreHeader() == succ) {
750             innerLoop->SetPreHeader(this);
751         }
752     }
753 }
754 
755 /**
756  * Join successor block into the block, which have another successor;
757  * Used in if-conversion pass and fixes dataflow using Select instructions.
758  * @param succ is a successor block which must have one predecessor and
759  * one successor, function will remove Phi(s) from the latter successor.
760  * @param select_bb is a block to insert generated Select instructions.
761  * When 'select_bb' is nullptr, we generate Select(s) in 'this' block.
762  * @param swapped == true means 'succ' is False successor (instead of True).
763  * How conversion works in the following two cases:
764  *
765  * EXAMPLE 1 (Comes from TryTriangle in if_conversion.cpp):
766  *
767  *                [this] ('select_bb' == nullptr)
768  *                (last inst: if-jump)
769  *                 |  \
770  *                 |  [succ]
771  *                 |  (one inst: arithmetic)
772  *                 |  /
773  *                (first inst: phi)
774  *                [other]
775  *
776  * turns into this:
777  *                [this]
778  *                (arithmetic)
779  *                (select)
780  *                 |
781  *                 |
782  *                (may be phi if there are another predecessors)
783  *                [other]
784  *
785  * EXAMPLE 2 (Comes from TryDiamond in if_conversion.cpp):
786  *
787  *                [this]
788  *                (last inst: if-jump)
789  *                /   \
790  *       [select_bb]  [succ]
791  *     (arithmetic2)  (arithmetic1)
792  *                \   /
793  *                (first inst: phi)
794  *                [other]
795  *
796  * turns into this:
797  *                [this]
798  *                (arithmetic1)
799  *                 |
800  *                 |
801  *                [select_bb]
802  *                (arithmetic2)
803  *                (select)
804  *                 |
805  *                 |
806  *                (may be phi if there are another predecessors)
807  *                [other]
808  *
809  * Function returns whether we need DCE for If inputs.
810  */
JoinBlocksUsingSelect(BasicBlock * succ,BasicBlock * selectBb,bool swapped)811 void BasicBlock::JoinBlocksUsingSelect(BasicBlock *succ, BasicBlock *selectBb, bool swapped)
812 {
813     ASSERT(!IsStartBlock());
814     ASSERT(GetSuccsBlocks().size() == MAX_SUCCS_NUM);
815     ASSERT(succ == GetSuccessor(0) || succ == GetSuccessor(1));
816     ASSERT(!succ->IsEndBlock());
817     ASSERT(succ->GetPredsBlocks().size() == 1);
818     ASSERT(succ->GetPredBlockByIndex(0) == this);
819     ASSERT(succ->GetSuccsBlocks().size() == 1);
820     /**
821      * There are 2 steps in Join operation.
822      * Step 1. Move instructions from 'succ' into 'this'.
823      */
824     Inst *ifInst = GetLastInst();
825     SavedIfInfo ifInfo {succ,
826                         swapped,
827                         0,
828                         ConditionCode::CC_FIRST,
829                         DataType::NO_TYPE,
830                         ifInst->GetPc(),
831                         ifInst->GetOpcode(),
832                         ifInst->GetInput(0).GetInst(),
833                         nullptr};
834 
835     // Save necessary info
836     if (ifInfo.ifOpcode == Opcode::IfImm) {
837         ifInfo.ifImm = ifInst->CastToIfImm()->GetImm();
838         ifInfo.ifCc = ifInst->CastToIfImm()->GetCc();
839         ifInfo.ifType = ifInst->CastToIfImm()->GetOperandsType();
840     } else if (ifInfo.ifOpcode == Opcode::If) {
841         ifInfo.ifInput1 = ifInst->GetInput(1).GetInst();
842         ifInfo.ifCc = ifInst->CastToIf()->GetCc();
843         ifInfo.ifType = ifInst->CastToIf()->GetOperandsType();
844     } else {
845         UNREACHABLE();
846     }
847 
848     // Remove 'If' instruction
849     RemoveInst(ifInst);
850 
851     // Remove incoming 'this->succ' edge
852     RemoveSucc(succ);
853     succ->GetPredsBlocks().clear();
854 
855     // Main loop in "Step 1", moving instructions from successor.
856     ASSERT(!succ->HasPhi());
857     for (auto inst : succ->Insts()) {
858         AppendInst(inst);
859     }
860     succ->firstInst_ = nullptr;
861     succ->lastInst_ = nullptr;
862 
863     auto other = succ->GetSuccessor(0);
864     /**
865      * Step 2. Generate Select(s).
866      * We generate them in 'select_bb' if provided (another successor in Diamond case),
867      * or in 'this' block otherwise (Triangle case).
868      */
869     if (selectBb == nullptr) {
870         selectBb = this;
871     }
872     selectBb->GenerateSelects(&ifInfo);
873     succ->SelectsFixLoopInfo(selectBb, other);
874 }
875 
GenerateSelect(Inst * phi,Inst * inst1,Inst * inst2,const SavedIfInfo * ifInfo)876 void BasicBlock::GenerateSelect(Inst *phi, Inst *inst1, Inst *inst2, const SavedIfInfo *ifInfo)
877 {
878     auto other = ifInfo->succ->GetSuccessor(0);
879     Inst *select = nullptr;
880     ASSERT(GetGraph()->GetEncoder()->CanEncodeFloatSelect() || !DataType::IsFloatType(phi->GetType()));
881     if (ifInfo->ifOpcode == Opcode::IfImm) {
882         select = GetGraph()->CreateInstSelectImm(phi->GetType(), ifInfo->ifPc, ifInfo->swapped ? inst2 : inst1,
883                                                  ifInfo->swapped ? inst1 : inst2, ifInfo->ifInput0, ifInfo->ifImm,
884                                                  ifInfo->ifType, ifInfo->ifCc);
885     } else if (ifInfo->ifOpcode == Opcode::If) {
886         select = GetGraph()->CreateInstSelect(phi->GetType(), ifInfo->ifPc,
887                                               std::array<Inst *, 4U> {ifInfo->swapped ? inst2 : inst1,
888                                                                       ifInfo->swapped ? inst1 : inst2, ifInfo->ifInput0,
889                                                                       ifInfo->ifInput1},
890                                               ifInfo->ifType, ifInfo->ifCc);
891     } else {
892         UNREACHABLE();
893     }
894 
895     AppendInst(select);
896 
897     if (other->GetPredsBlocks().size() > 2U) {
898         // Change input (from this block) to new Select instruction
899         auto index = phi->CastToPhi()->GetPredBlockIndex(this);
900         phi->CastToPhi()->SetInput(index, select);
901         // Remove input from 'succ'
902         index = phi->CastToPhi()->GetPredBlockIndex(ifInfo->succ);
903         phi->CastToPhi()->RemoveInput(index);
904     } else {
905         // Remove Phi
906         phi->ReplaceUsers(select);
907         other->RemoveInst(phi);
908     }
909     // Select now must have users
910     ASSERT(select->HasUsers());
911 }
912 
GenerateSelects(const SavedIfInfo * ifInfo)913 void BasicBlock::GenerateSelects(const SavedIfInfo *ifInfo)
914 {
915     auto succ = ifInfo->succ;
916 
917     // The only successor whether we will check Phi(s)
918     auto other = succ->GetSuccessor(0);
919     constexpr auto TWO = 2;
920     ASSERT(other->GetPredsBlocks().size() >= TWO);
921 
922     // Main loop in "Step 2", generate select(s) and drop phi(s) when possible
923     for (auto phi : other->PhiInstsSafe()) {
924         size_t index1 = phi->CastToPhi()->GetPredBlockIndex(succ);
925         size_t index2 = phi->CastToPhi()->GetPredBlockIndex(this);
926         ASSERT(index1 != index2);
927 
928         auto inst1 = phi->GetInput(index1).GetInst();
929         auto inst2 = phi->GetInput(index2).GetInst();
930         if (inst1 == inst2) {
931             // No select needed
932             if (other->GetPredsBlocks().size() > TWO) {
933                 // Remove input from 'succ'
934                 auto index = phi->CastToPhi()->GetPredBlockIndex(succ);
935                 phi->CastToPhi()->RemoveInput(index);
936             } else {
937                 // Remove Phi
938                 phi->ReplaceUsers(inst1);
939                 other->RemoveInst(phi);
940             }
941             continue;
942         }
943 
944         GenerateSelect(phi, inst1, inst2, ifInfo);
945     }
946 }
947 
SelectsFixLoopInfo(BasicBlock * selectBb,BasicBlock * other)948 void BasicBlock::SelectsFixLoopInfo(BasicBlock *selectBb, BasicBlock *other)
949 {
950     // invariant: 'this' block has one predecessor, so it cannot be a loop header
951     auto loop = GetLoop();
952     ASSERT(loop != nullptr);
953     // Irreducible loop can not be fixed on the fly
954     if (loop->IsIrreducible()) {
955         GetGraph()->InvalidateAnalysis<LoopAnalyzer>();
956     } else {
957         if (loop->HasBackEdge(this)) {
958             loop->RemoveBackEdge(this);
959         }
960         for (auto innerLoop : loop->GetInnerLoops()) {
961             if (innerLoop->GetPreHeader() == this) {
962                 innerLoop->SetPreHeader(selectBb);
963                 break;
964             }
965         }
966         loop->RemoveBlock(this);
967     }
968 
969     // Remove outgoing 'this->other' edge
970     RemoveSucc(other);
971     other->RemovePred(this);
972     // Disconnect
973     GetGraph()->RemoveEmptyBlock(this);
974 }
975 
AppendPhi(Inst * inst)976 void BasicBlock::AppendPhi(Inst *inst)
977 {
978     ASSERT_PRINT(inst->IsPhi(), "Instruction must be phi");
979     inst->SetBasicBlock(this);
980     if (firstPhi_ == nullptr) {
981         inst->SetNext(firstInst_);
982         if (firstInst_ != nullptr) {
983             firstInst_->SetPrev(inst);
984         }
985         firstPhi_ = inst;
986         if (lastInst_ == nullptr) {
987             lastInst_ = inst;
988         }
989     } else {
990         if (firstInst_ != nullptr) {
991             Inst *prev = firstInst_->GetPrev();
992             ASSERT_PRINT(prev && prev->IsPhi(), "There is no phi in the block");
993             inst->SetPrev(prev);
994             prev->SetNext(inst);
995             inst->SetNext(firstInst_);
996             firstInst_->SetPrev(inst);
997         } else {
998             ASSERT_PRINT(lastInst_ && lastInst_->IsPhi(),
999                          "If first_phi is defined and first_inst is undefined, last_inst must be phi");
1000             lastInst_->SetNext(inst);
1001             inst->SetPrev(lastInst_);
1002             lastInst_ = inst;
1003         }
1004     }
1005 }
1006 
1007 template <bool TO_END>
AddInst(Inst * inst)1008 void BasicBlock::AddInst(Inst *inst)
1009 {
1010     ASSERT_PRINT(!inst->IsPhi(), "Instruction mustn't be phi");
1011     inst->SetBasicBlock(this);
1012     if (firstInst_ == nullptr) {
1013         inst->SetPrev(lastInst_);
1014         if (lastInst_ != nullptr) {
1015             ASSERT(lastInst_->IsPhi());
1016             lastInst_->SetNext(inst);
1017         }
1018         firstInst_ = inst;
1019         lastInst_ = inst;
1020     } else {
1021         // NOLINTNEXTLINE(readability-braces-around-statements)
1022         if constexpr (TO_END) {
1023             ASSERT_PRINT(lastInst_, "Last instruction is undefined");
1024             inst->SetPrev(lastInst_);
1025             lastInst_->SetNext(inst);
1026             lastInst_ = inst;
1027             // NOLINTNEXTLINE(readability-misleading-indentation)
1028         } else {
1029             auto firstPrev = firstInst_->GetPrev();
1030             if (firstPrev != nullptr) {
1031                 firstPrev->SetNext(inst);
1032             }
1033             inst->SetPrev(firstPrev);
1034             inst->SetNext(firstInst_);
1035             firstInst_->SetPrev(inst);
1036             firstInst_ = inst;
1037         }
1038     }
1039 }
1040 
AppendRangeInst(Inst * rangeFirst,Inst * rangeLast)1041 void BasicBlock::AppendRangeInst(Inst *rangeFirst, Inst *rangeLast)
1042 {
1043 #ifndef NDEBUG
1044     ASSERT(rangeFirst && rangeLast && rangeFirst->IsDominate(rangeLast));
1045     ASSERT(rangeFirst->GetPrev() == nullptr);
1046     ASSERT(rangeLast->GetNext() == nullptr);
1047     auto instDb = rangeFirst;
1048     while (instDb != rangeLast) {
1049         ASSERT_PRINT(!instDb->IsPhi(), "Instruction mustn't be phi");
1050         ASSERT_PRINT(instDb->GetBasicBlock() == this, "Inst::SetBasicBlock() should be called beforehand");
1051         instDb = instDb->GetNext();
1052     }
1053     ASSERT_PRINT(!instDb->IsPhi(), "Instruction mustn't be phi");
1054     ASSERT_PRINT(instDb->GetBasicBlock() == this, "Inst::SetBasicBlock() should be called beforehand");
1055 #endif
1056 
1057     if (firstInst_ == nullptr) {
1058         rangeFirst->SetPrev(lastInst_);
1059         if (lastInst_ != nullptr) {
1060             ASSERT(lastInst_->IsPhi());
1061             lastInst_->SetNext(rangeFirst);
1062         }
1063         firstInst_ = rangeFirst;
1064         lastInst_ = rangeLast;
1065     } else {
1066         ASSERT_PRINT(lastInst_, "Last instruction is undefined");
1067         rangeFirst->SetPrev(lastInst_);
1068         lastInst_->SetNext(rangeFirst);
1069         lastInst_ = rangeLast;
1070     }
1071 }
1072 
InsertAfter(Inst * inst,Inst * after)1073 void BasicBlock::InsertAfter(Inst *inst, Inst *after)
1074 {
1075     ASSERT(inst && after);
1076     ASSERT(inst->IsPhi() == after->IsPhi());
1077     ASSERT(after->GetBasicBlock() == this);
1078     ASSERT(inst->GetBasicBlock() == nullptr);
1079     inst->SetBasicBlock(this);
1080     Inst *next = after->GetNext();
1081     inst->SetPrev(after);
1082     inst->SetNext(next);
1083     after->SetNext(inst);
1084     if (next != nullptr) {
1085         next->SetPrev(inst);
1086     } else {
1087         ASSERT(after == lastInst_);
1088         lastInst_ = inst;
1089     }
1090 }
1091 
InsertBefore(Inst * inst,Inst * before)1092 void BasicBlock::InsertBefore(Inst *inst, Inst *before)
1093 {
1094     ASSERT(inst && before);
1095     ASSERT(inst->IsPhi() == before->IsPhi());
1096     ASSERT(before->GetBasicBlock() == this);
1097     ASSERT(inst->GetBasicBlock() == nullptr);
1098     inst->SetBasicBlock(this);
1099     Inst *prev = before->GetPrev();
1100     inst->SetPrev(prev);
1101     inst->SetNext(before);
1102     before->SetPrev(inst);
1103     if (prev != nullptr) {
1104         prev->SetNext(inst);
1105     }
1106     if (before == firstPhi_) {
1107         firstPhi_ = inst;
1108     }
1109     if (before == firstInst_) {
1110         firstInst_ = inst;
1111     }
1112 }
1113 
InsertRangeBefore(Inst * rangeFirst,Inst * rangeLast,Inst * before)1114 void BasicBlock::InsertRangeBefore(Inst *rangeFirst, Inst *rangeLast, Inst *before)
1115 {
1116 #ifndef NDEBUG
1117     ASSERT(rangeFirst && rangeLast && rangeFirst->IsDominate(rangeLast));
1118     ASSERT(before && !before->IsPhi());
1119     ASSERT(rangeFirst->GetPrev() == nullptr);
1120     ASSERT(rangeLast->GetNext() == nullptr);
1121     ASSERT(before->GetBasicBlock() == this);
1122     auto instDb = rangeFirst;
1123     while (instDb != rangeLast) {
1124         ASSERT_PRINT(!instDb->IsPhi(), "Instruction mustn't be phi");
1125         ASSERT_PRINT(instDb->GetBasicBlock() == this, "Inst::SetBasicBlock() should be called beforehand");
1126         instDb = instDb->GetNext();
1127     }
1128     ASSERT_PRINT(!instDb->IsPhi(), "Instruction mustn't be phi");
1129     ASSERT_PRINT(instDb->GetBasicBlock() == this, "Inst::SetBasicBlock() should be called beforehand");
1130 #endif
1131 
1132     Inst *prev = before->GetPrev();
1133     rangeFirst->SetPrev(prev);
1134     rangeLast->SetNext(before);
1135     before->SetPrev(rangeLast);
1136     if (prev != nullptr) {
1137         prev->SetNext(rangeFirst);
1138     }
1139     if (before == firstInst_) {
1140         firstInst_ = rangeFirst;
1141     }
1142 }
1143 
ReplaceInst(Inst * oldInst,Inst * newInst)1144 void BasicBlock::ReplaceInst(Inst *oldInst, Inst *newInst)
1145 {
1146     ASSERT(oldInst && newInst);
1147     ASSERT(oldInst->IsPhi() == newInst->IsPhi());
1148     ASSERT(oldInst->GetBasicBlock() == this);
1149     ASSERT(newInst->GetBasicBlock() == nullptr);
1150     newInst->SetBasicBlock(this);
1151     Inst *prev = oldInst->GetPrev();
1152     Inst *next = oldInst->GetNext();
1153 
1154     oldInst->SetBasicBlock(nullptr);
1155     if (prev != nullptr) {
1156         prev->SetNext(newInst);
1157     }
1158     if (next != nullptr) {
1159         next->SetPrev(newInst);
1160     }
1161     newInst->SetPrev(prev);
1162     newInst->SetNext(next);
1163     if (firstPhi_ == oldInst) {
1164         firstPhi_ = newInst;
1165     }
1166     if (firstInst_ == oldInst) {
1167         firstInst_ = newInst;
1168     }
1169     if (lastInst_ == oldInst) {
1170         lastInst_ = newInst;
1171     }
1172 
1173     if (graph_->IsInstThrowable(oldInst)) {
1174         graph_->ReplaceThrowableInst(oldInst, newInst);
1175     }
1176 }
1177 
ReplaceInstByDeoptimize(Inst * inst)1178 void BasicBlock::ReplaceInstByDeoptimize(Inst *inst)
1179 {
1180     ASSERT(inst != nullptr);
1181     ASSERT(inst->GetBasicBlock() == this);
1182     auto ss = inst->GetSaveState();
1183     ASSERT(ss != nullptr);
1184     auto callInst = ss->GetCallerInst();
1185     // if inst in inlined method, we need to build all return.inlined before deoptimize to correct restore registers.
1186     while (callInst != nullptr && callInst->IsInlined()) {
1187         ss = callInst->GetSaveState();
1188         ASSERT(ss != nullptr);
1189         auto retInl = GetGraph()->CreateInstReturnInlined(DataType::NO_TYPE, INVALID_PC, ss);
1190         retInl->SetExtendedLiveness();
1191         InsertBefore(retInl, inst);
1192         callInst = ss->GetCallerInst();
1193     }
1194     // Replace Inst
1195     auto deopt = GetGraph()->CreateInstDeoptimize(DataType::NO_TYPE, inst->GetPc(), inst->GetSaveState());
1196     deopt->SetDeoptimizeType(inst);
1197     inst->RemoveInputs();
1198     inst->RemoveUsers();
1199     ReplaceInst(inst, deopt);
1200     // Build control flow
1201     BasicBlock *succ = GetSuccsBlocks()[0];
1202     if (GetLastInst() != deopt) {
1203         succ = SplitBlockAfterInstruction(deopt, true);
1204     }
1205     ASSERT(GetSuccsBlocks().size() == 1);
1206     GetGraph()->RemoveSuccessors(this);
1207     auto endBlock = GetGraph()->HasEndBlock() ? GetGraph()->GetEndBlock() : GetGraph()->CreateEndBlock();
1208     ASSERT(endBlock->GetGraph() != nullptr);
1209     this->AddSucc(endBlock);
1210     ASSERT(GetGraph()->IsAnalysisValid<LoopAnalyzer>());
1211     GetGraph()->DisconnectBlockRec(succ, true, false);
1212 }
1213 
RemoveOverflowCheck(Inst * inst)1214 void BasicBlock::RemoveOverflowCheck(Inst *inst)
1215 {
1216     // replace by Add/Sub
1217     Inst *newInst = nullptr;
1218     switch (inst->GetOpcode()) {
1219         case Opcode::AddOverflowCheck:
1220             newInst = GetGraph()->CreateInstAdd(inst->GetType(), inst->GetPc());
1221             break;
1222         case Opcode::SubOverflowCheck:
1223             newInst = GetGraph()->CreateInstSub(inst->GetType(), inst->GetPc());
1224             break;
1225         case Opcode::NegOverflowAndZeroCheck:
1226             newInst = GetGraph()->CreateInstNeg(inst->GetType(), inst->GetPc());
1227             break;
1228         default:
1229             UNREACHABLE();
1230     }
1231     // clone inputs, except savestate
1232     for (size_t i = 0; i < inst->GetInputsCount() - 1; ++i) {
1233         newInst->SetInput(i, inst->GetInput(i).GetInst());
1234     }
1235     inst->ReplaceUsers(newInst);
1236     inst->RemoveInputs();
1237     ReplaceInst(inst, newInst);
1238 }
1239 
EraseInst(Inst * inst,bool willBeMoved)1240 void BasicBlock::EraseInst(Inst *inst, [[maybe_unused]] bool willBeMoved)
1241 {
1242     ASSERT(willBeMoved || !GetGraph()->IsInstThrowable(inst));
1243     Inst *prev = inst->GetPrev();
1244     Inst *next = inst->GetNext();
1245 
1246     ASSERT(inst->GetBasicBlock() == this);
1247     inst->SetBasicBlock(nullptr);
1248     if (prev != nullptr) {
1249         prev->SetNext(next);
1250     }
1251     if (next != nullptr) {
1252         next->SetPrev(prev);
1253     }
1254     inst->SetPrev(nullptr);
1255     inst->SetNext(nullptr);
1256     if (inst == firstPhi_) {
1257         firstPhi_ = (next != nullptr && next->IsPhi()) ? next : nullptr;
1258     }
1259     if (inst == firstInst_) {
1260         firstInst_ = next;
1261     }
1262     if (inst == lastInst_) {
1263         lastInst_ = prev;
1264     }
1265 }
1266 
RemoveInst(Inst * inst)1267 void BasicBlock::RemoveInst(Inst *inst)
1268 {
1269     inst->RemoveUsers();
1270     ASSERT(!inst->HasUsers());
1271     inst->RemoveInputs();
1272     if (inst->GetOpcode() == Opcode::NullPtr) {
1273         graph_->UnsetNullPtrInst();
1274     } else if (inst->GetOpcode() == Opcode::LoadUndefined) {
1275         graph_->UnsetUndefinedInst();
1276     } else if (inst->GetOpcode() == Opcode::Constant) {
1277         graph_->RemoveConstFromList(static_cast<ConstantInst *>(inst));
1278     } else if (inst->GetOpcode() == Opcode::LoadUndefined) {
1279         graph_->UnsetUndefinedInst();
1280     }
1281 
1282     if (graph_->IsInstThrowable(inst)) {
1283         graph_->RemoveThrowableInst(inst);
1284     }
1285     EraseInst(inst);
1286 }
1287 
Clear()1288 void BasicBlock::Clear()
1289 {
1290     for (auto inst : AllInstsSafeReverse()) {
1291         RemoveInst(inst);
1292     }
1293 }
1294 
1295 /*
1296  * Check if this block is dominate other
1297  */
IsDominate(const BasicBlock * other) const1298 bool BasicBlock::IsDominate(const BasicBlock *other) const
1299 {
1300     if (other == this) {
1301         return true;
1302     }
1303     ASSERT(GetGraph()->IsAnalysisValid<DominatorsTree>());
1304     BasicBlock *domBlock = other->GetDominator();
1305     while (domBlock != nullptr) {
1306         if (domBlock == this) {
1307             return true;
1308         }
1309         // Otherwise we are in infinite loop!?
1310         ASSERT(domBlock != domBlock->GetDominator());
1311         domBlock = domBlock->GetDominator();
1312     }
1313     return false;
1314 }
1315 
CreateImmediateDominator()1316 BasicBlock *BasicBlock::CreateImmediateDominator()
1317 {
1318     ASSERT(GetGraph()->IsAnalysisValid<DominatorsTree>());
1319     auto dominator = GetGraph()->CreateEmptyBlock();
1320     GetGraph()->GetAnalysis<DominatorsTree>().SetValid(true);
1321     if (GetDominator() != nullptr) {
1322         GetDominator()->RemoveDominatedBlock(this);
1323         GetDominator()->AddDominatedBlock(dominator);
1324         dominator->SetDominator(GetDominator());
1325     }
1326     dominator->AddDominatedBlock(this);
1327     SetDominator(dominator);
1328     return dominator;
1329 }
1330 
GetDominator() const1331 BasicBlock *BasicBlock::GetDominator() const
1332 {
1333     ASSERT(GetGraph()->IsAnalysisValid<DominatorsTree>());
1334     return dominator_;
1335 }
1336 
GetDominatedBlocks() const1337 const ArenaVector<BasicBlock *> &BasicBlock::GetDominatedBlocks() const
1338 {
1339     ASSERT(GetGraph()->IsAnalysisValid<DominatorsTree>());
1340     return domBlocks_;
1341 }
1342 
PhiInsts() const1343 PhiInstIter BasicBlock::PhiInsts() const
1344 {
1345     return PhiInstIter(*this);
1346 }
Insts() const1347 InstIter BasicBlock::Insts() const
1348 {
1349     return InstIter(*this);
1350 }
AllInsts() const1351 AllInstIter BasicBlock::AllInsts() const
1352 {
1353     return AllInstIter(*this);
1354 }
1355 
InstsReverse() const1356 InstReverseIter BasicBlock::InstsReverse() const
1357 {
1358     return InstReverseIter(*this);
1359 }
1360 
PhiInstsSafe() const1361 PhiInstSafeIter BasicBlock::PhiInstsSafe() const
1362 {
1363     return PhiInstSafeIter(*this);
1364 }
InstsSafe() const1365 InstSafeIter BasicBlock::InstsSafe() const
1366 {
1367     return InstSafeIter(*this);
1368 }
AllInstsSafe() const1369 AllInstSafeIter BasicBlock::AllInstsSafe() const
1370 {
1371     return AllInstSafeIter(*this);
1372 }
1373 
PhiInstsSafeReverse() const1374 PhiInstSafeReverseIter BasicBlock::PhiInstsSafeReverse() const
1375 {
1376     return PhiInstSafeReverseIter(*this);
1377 }
InstsSafeReverse() const1378 InstSafeReverseIter BasicBlock::InstsSafeReverse() const
1379 {
1380     return InstSafeReverseIter(*this);
1381 }
AllInstsSafeReverse() const1382 AllInstSafeReverseIter BasicBlock::AllInstsSafeReverse() const
1383 {
1384     return AllInstSafeReverseIter(*this);
1385 }
1386 
1387 template void BasicBlock::AddInst<false>(Inst *inst);
1388 template void BasicBlock::AddInst<true>(Inst *inst);
1389 
InsertBlockBefore(BasicBlock * block)1390 void BasicBlock::InsertBlockBefore(BasicBlock *block)
1391 {
1392     for (auto pred : GetPredsBlocks()) {
1393         pred->ReplaceSucc(this, block);
1394     }
1395     GetPredsBlocks().clear();
1396     block->AddSucc(this);
1397 }
1398 
Clone(Graph * targetGraph) const1399 BasicBlock *BasicBlock::Clone(Graph *targetGraph) const
1400 {
1401     BasicBlock *clone = nullptr;
1402 #ifndef NDEBUG
1403     if (GetGraph() == targetGraph) {
1404         clone = targetGraph->CreateEmptyBlock();
1405     } else {
1406         clone = targetGraph->CreateEmptyBlock(GetId(), GetGuestPc());
1407     }
1408 #else
1409     clone = targetGraph->CreateEmptyBlock();
1410 #endif
1411     clone->SetAllFields(this->GetAllFields());
1412     clone->tryId_ = GetTryId();
1413     if (this->IsStartBlock()) {
1414         targetGraph->SetStartBlock(clone);
1415     } else if (this->IsEndBlock()) {
1416         targetGraph->SetEndBlock(clone);
1417     }
1418     return clone;
1419 }
1420 
GetFistThrowableInst() const1421 Inst *BasicBlock::GetFistThrowableInst() const
1422 {
1423     if (!IsTry()) {
1424         return nullptr;
1425     }
1426     for (auto inst : AllInsts()) {
1427         if (GetGraph()->IsInstThrowable(inst)) {
1428             return inst;
1429         }
1430     }
1431     return nullptr;
1432 }
1433 
FindSaveStateDeoptimize() const1434 Inst *BasicBlock::FindSaveStateDeoptimize() const
1435 {
1436     for (auto inst : InstsReverse()) {
1437         if (inst->GetOpcode() == Opcode::SaveStateDeoptimize) {
1438             return inst;
1439         }
1440     }
1441     return nullptr;
1442 }
1443 
InvalidateLoopIfIrreducible()1444 void BasicBlock::InvalidateLoopIfIrreducible()
1445 {
1446     auto loop = GetLoop();
1447     ASSERT(loop != nullptr);
1448     if (loop->IsIrreducible()) {
1449         GetGraph()->InvalidateAnalysis<LoopAnalyzer>();
1450     }
1451 }
1452 
CountInsts() const1453 uint32_t BasicBlock::CountInsts() const
1454 {
1455     uint32_t count = 0;
1456     for ([[maybe_unused]] auto inst : AllInsts()) {
1457         count++;
1458     }
1459     return count;
1460 }
1461 
BlocksPathDfsSearch(Marker marker,BasicBlock * block,const BasicBlock * targetBlock,const BasicBlock * excludeBlock)1462 bool BlocksPathDfsSearch(Marker marker, BasicBlock *block, const BasicBlock *targetBlock,
1463                          const BasicBlock *excludeBlock)
1464 {
1465     ASSERT(marker != UNDEF_MARKER);
1466     if (block == targetBlock) {
1467         return true;
1468     }
1469     block->SetMarker(marker);
1470 
1471     for (auto succBlock : block->GetSuccsBlocks()) {
1472         if (!succBlock->IsMarked(marker) && succBlock != excludeBlock) {
1473             if (BlocksPathDfsSearch(marker, succBlock, targetBlock, excludeBlock)) {
1474                 return true;
1475             }
1476         }
1477     }
1478     return false;
1479 }
1480 }  // namespace ark::compiler
1481