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