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