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