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() const291 Loop *BasicBlock::GetNextLoop() const
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 ASSERT(!IsLoopPreHeader());
698 if (succ->IsLoopPreHeader()) {
699 succ->GetNextLoop()->SetPreHeader(this);
700 }
701
702 // moving instructions from successor
703 ASSERT(!succ->HasPhi());
704 for (auto succInst : succ->Insts()) {
705 AppendInst(succInst);
706 }
707
708 // moving successor blocks from the successor
709 GetSuccsBlocks().clear();
710 for (auto succSucc : succ->GetSuccsBlocks()) {
711 succSucc->ReplacePred(succ, this);
712 }
713
714 if (GetGraph()->IsAnalysisValid<LoopAnalyzer>()) {
715 // fixing loop information
716 // invariant: succ has one predecessor, so it cannot be a loop header
717 auto loop = succ->GetLoop();
718 ASSERT(loop != nullptr);
719 // Irreducible loop can not be fixed on the fly
720 if (loop->IsIrreducible() || GetGraph()->IsThrowApplied()) {
721 GetGraph()->InvalidateAnalysis<LoopAnalyzer>();
722 } else {
723 // edge can have 2 successors, so it can be back-edge in 2 loops: own loop and outer loop
724 ReplaceSuccessorLoopBackEdges(loop, succ);
725 loop->RemoveBlock(succ);
726 }
727 }
728
729 succ->firstInst_ = nullptr;
730 succ->lastInst_ = nullptr;
731 succ->GetPredsBlocks().clear();
732 succ->GetSuccsBlocks().clear();
733
734 this->bitFields_ |= succ->bitFields_;
735 // NOTE (a.popov) replace by assert
736 if (succ->tryId_ != INVALID_ID) {
737 this->tryId_ = succ->tryId_;
738 }
739 GetGraph()->RemoveEmptyBlock(succ);
740 }
741
ReplaceSuccessorLoopBackEdges(Loop * loop,BasicBlock * succ)742 void BasicBlock::ReplaceSuccessorLoopBackEdges(Loop *loop, BasicBlock *succ)
743 {
744 if (loop->HasBackEdge(succ)) {
745 loop->ReplaceBackEdge(succ, this);
746 }
747 for (auto outerLoop = loop->GetOuterLoop(); outerLoop != nullptr; outerLoop = outerLoop->GetOuterLoop()) {
748 if (outerLoop->HasBackEdge(succ)) {
749 outerLoop->ReplaceBackEdge(succ, this);
750 }
751 }
752 for (auto innerLoop : loop->GetInnerLoops()) {
753 if (innerLoop->GetPreHeader() == succ) {
754 innerLoop->SetPreHeader(this);
755 }
756 }
757 }
758
759 /**
760 * Join successor block into the block, which have another successor;
761 * Used in if-conversion pass and fixes dataflow using Select instructions.
762 * @param succ is a successor block which must have one predecessor and
763 * one successor, function will remove Phi(s) from the latter successor.
764 * @param select_bb is a block to insert generated Select instructions.
765 * When 'select_bb' is nullptr, we generate Select(s) in 'this' block.
766 * @param swapped == true means 'succ' is False successor (instead of True).
767 * How conversion works in the following two cases:
768 *
769 * EXAMPLE 1 (Comes from TryTriangle in if_conversion.cpp):
770 *
771 * [this] ('select_bb' == nullptr)
772 * (last inst: if-jump)
773 * | \
774 * | [succ]
775 * | (one inst: arithmetic)
776 * | /
777 * (first inst: phi)
778 * [other]
779 *
780 * turns into this:
781 * [this]
782 * (arithmetic)
783 * (select)
784 * |
785 * |
786 * (may be phi if there are another predecessors)
787 * [other]
788 *
789 * EXAMPLE 2 (Comes from TryDiamond in if_conversion.cpp):
790 *
791 * [this]
792 * (last inst: if-jump)
793 * / \
794 * [select_bb] [succ]
795 * (arithmetic2) (arithmetic1)
796 * \ /
797 * (first inst: phi)
798 * [other]
799 *
800 * turns into this:
801 * [this]
802 * (arithmetic1)
803 * |
804 * |
805 * [select_bb]
806 * (arithmetic2)
807 * (select)
808 * |
809 * |
810 * (may be phi if there are another predecessors)
811 * [other]
812 *
813 * Function returns whether we need DCE for If inputs.
814 */
JoinBlocksUsingSelect(BasicBlock * succ,BasicBlock * selectBb,bool swapped)815 void BasicBlock::JoinBlocksUsingSelect(BasicBlock *succ, BasicBlock *selectBb, bool swapped)
816 {
817 ASSERT(!IsStartBlock());
818 ASSERT(GetSuccsBlocks().size() == MAX_SUCCS_NUM);
819 ASSERT(succ == GetSuccessor(0) || succ == GetSuccessor(1));
820 ASSERT(!succ->IsEndBlock());
821 ASSERT(succ->GetPredsBlocks().size() == 1);
822 ASSERT(succ->GetPredBlockByIndex(0) == this);
823 ASSERT(succ->GetSuccsBlocks().size() == 1);
824 /**
825 * There are 2 steps in Join operation.
826 * Step 1. Move instructions from 'succ' into 'this'.
827 */
828 Inst *ifInst = GetLastInst();
829 SavedIfInfo ifInfo {succ,
830 swapped,
831 0,
832 ConditionCode::CC_FIRST,
833 DataType::NO_TYPE,
834 ifInst->GetPc(),
835 ifInst->GetOpcode(),
836 ifInst->GetInput(0).GetInst(),
837 nullptr};
838
839 // Save necessary info
840 if (ifInfo.ifOpcode == Opcode::IfImm) {
841 ifInfo.ifImm = ifInst->CastToIfImm()->GetImm();
842 ifInfo.ifCc = ifInst->CastToIfImm()->GetCc();
843 ifInfo.ifType = ifInst->CastToIfImm()->GetOperandsType();
844 } else if (ifInfo.ifOpcode == Opcode::If) {
845 ifInfo.ifInput1 = ifInst->GetInput(1).GetInst();
846 ifInfo.ifCc = ifInst->CastToIf()->GetCc();
847 ifInfo.ifType = ifInst->CastToIf()->GetOperandsType();
848 } else {
849 UNREACHABLE();
850 }
851
852 // Remove 'If' instruction
853 RemoveInst(ifInst);
854
855 // Remove incoming 'this->succ' edge
856 RemoveSucc(succ);
857 succ->GetPredsBlocks().clear();
858
859 // Main loop in "Step 1", moving instructions from successor.
860 ASSERT(!succ->HasPhi());
861 for (auto inst : succ->Insts()) {
862 AppendInst(inst);
863 }
864 succ->firstInst_ = nullptr;
865 succ->lastInst_ = nullptr;
866
867 auto other = succ->GetSuccessor(0);
868 /**
869 * Step 2. Generate Select(s).
870 * We generate them in 'select_bb' if provided (another successor in Diamond case),
871 * or in 'this' block otherwise (Triangle case).
872 */
873 if (selectBb == nullptr) {
874 selectBb = this;
875 }
876 selectBb->GenerateSelects(&ifInfo);
877 succ->SelectsFixLoopInfo(selectBb, other);
878 }
879
GenerateSelect(Inst * phi,Inst * inst1,Inst * inst2,const SavedIfInfo * ifInfo)880 void BasicBlock::GenerateSelect(Inst *phi, Inst *inst1, Inst *inst2, const SavedIfInfo *ifInfo)
881 {
882 auto other = ifInfo->succ->GetSuccessor(0);
883 Inst *select = nullptr;
884 ASSERT(GetGraph()->GetEncoder()->CanEncodeFloatSelect() || !DataType::IsFloatType(phi->GetType()));
885 if (ifInfo->ifOpcode == Opcode::IfImm) {
886 select = GetGraph()->CreateInstSelectImm(phi->GetType(), ifInfo->ifPc, ifInfo->swapped ? inst2 : inst1,
887 ifInfo->swapped ? inst1 : inst2, ifInfo->ifInput0, ifInfo->ifImm,
888 ifInfo->ifType, ifInfo->ifCc);
889 } else if (ifInfo->ifOpcode == Opcode::If) {
890 select = GetGraph()->CreateInstSelect(phi->GetType(), ifInfo->ifPc,
891 std::array<Inst *, 4U> {ifInfo->swapped ? inst2 : inst1,
892 ifInfo->swapped ? inst1 : inst2, ifInfo->ifInput0,
893 ifInfo->ifInput1},
894 ifInfo->ifType, ifInfo->ifCc);
895 } else {
896 UNREACHABLE();
897 }
898
899 AppendInst(select);
900
901 if (other->GetPredsBlocks().size() > 2U) {
902 // Change input (from this block) to new Select instruction
903 auto index = phi->CastToPhi()->GetPredBlockIndex(this);
904 phi->CastToPhi()->SetInput(index, select);
905 // Remove input from 'succ'
906 index = phi->CastToPhi()->GetPredBlockIndex(ifInfo->succ);
907 phi->CastToPhi()->RemoveInput(index);
908 } else {
909 // Remove Phi
910 phi->ReplaceUsers(select);
911 other->RemoveInst(phi);
912 }
913 // Select now must have users
914 ASSERT(select->HasUsers());
915 }
916
GenerateSelects(const SavedIfInfo * ifInfo)917 void BasicBlock::GenerateSelects(const SavedIfInfo *ifInfo)
918 {
919 auto succ = ifInfo->succ;
920
921 // The only successor whether we will check Phi(s)
922 auto other = succ->GetSuccessor(0);
923 constexpr auto TWO = 2;
924 ASSERT(other->GetPredsBlocks().size() >= TWO);
925
926 // Main loop in "Step 2", generate select(s) and drop phi(s) when possible
927 for (auto phi : other->PhiInstsSafe()) {
928 size_t index1 = phi->CastToPhi()->GetPredBlockIndex(succ);
929 size_t index2 = phi->CastToPhi()->GetPredBlockIndex(this);
930 ASSERT(index1 != index2);
931
932 auto inst1 = phi->GetInput(index1).GetInst();
933 auto inst2 = phi->GetInput(index2).GetInst();
934 if (inst1 == inst2) {
935 // No select needed
936 if (other->GetPredsBlocks().size() > TWO) {
937 // Remove input from 'succ'
938 auto index = phi->CastToPhi()->GetPredBlockIndex(succ);
939 phi->CastToPhi()->RemoveInput(index);
940 } else {
941 // Remove Phi
942 phi->ReplaceUsers(inst1);
943 other->RemoveInst(phi);
944 }
945 continue;
946 }
947
948 GenerateSelect(phi, inst1, inst2, ifInfo);
949 }
950 }
951
SelectsFixLoopInfo(BasicBlock * selectBb,BasicBlock * other)952 void BasicBlock::SelectsFixLoopInfo(BasicBlock *selectBb, BasicBlock *other)
953 {
954 // invariant: 'this' block has one predecessor, so it cannot be a loop header
955 auto loop = GetLoop();
956 ASSERT(loop != nullptr);
957 // Irreducible loop can not be fixed on the fly
958 if (loop->IsIrreducible()) {
959 GetGraph()->InvalidateAnalysis<LoopAnalyzer>();
960 } else {
961 if (loop->HasBackEdge(this)) {
962 loop->RemoveBackEdge(this);
963 }
964 for (auto innerLoop : loop->GetInnerLoops()) {
965 if (innerLoop->GetPreHeader() == this) {
966 innerLoop->SetPreHeader(selectBb);
967 break;
968 }
969 }
970 loop->RemoveBlock(this);
971 }
972
973 // Remove outgoing 'this->other' edge
974 RemoveSucc(other);
975 other->RemovePred(this);
976 // Disconnect
977 GetGraph()->RemoveEmptyBlock(this);
978 }
979
AppendPhi(Inst * inst)980 void BasicBlock::AppendPhi(Inst *inst)
981 {
982 ASSERT_PRINT(inst->IsPhi(), "Instruction must be phi");
983 inst->SetBasicBlock(this);
984 if (firstPhi_ == nullptr) {
985 inst->SetNext(firstInst_);
986 if (firstInst_ != nullptr) {
987 firstInst_->SetPrev(inst);
988 }
989 firstPhi_ = inst;
990 if (lastInst_ == nullptr) {
991 lastInst_ = inst;
992 }
993 } else {
994 if (firstInst_ != nullptr) {
995 Inst *prev = firstInst_->GetPrev();
996 ASSERT_PRINT(prev && prev->IsPhi(), "There is no phi in the block");
997 inst->SetPrev(prev);
998 prev->SetNext(inst);
999 inst->SetNext(firstInst_);
1000 firstInst_->SetPrev(inst);
1001 } else {
1002 ASSERT_PRINT(lastInst_ && lastInst_->IsPhi(),
1003 "If first_phi is defined and first_inst is undefined, last_inst must be phi");
1004 lastInst_->SetNext(inst);
1005 inst->SetPrev(lastInst_);
1006 lastInst_ = inst;
1007 }
1008 }
1009 }
1010
1011 template <bool TO_END>
AddInst(Inst * inst)1012 void BasicBlock::AddInst(Inst *inst)
1013 {
1014 ASSERT_PRINT(!inst->IsPhi(), "Instruction mustn't be phi");
1015 inst->SetBasicBlock(this);
1016 if (firstInst_ == nullptr) {
1017 inst->SetPrev(lastInst_);
1018 if (lastInst_ != nullptr) {
1019 ASSERT(lastInst_->IsPhi());
1020 lastInst_->SetNext(inst);
1021 }
1022 firstInst_ = inst;
1023 lastInst_ = inst;
1024 } else {
1025 // NOLINTNEXTLINE(readability-braces-around-statements)
1026 if constexpr (TO_END) {
1027 ASSERT_PRINT(lastInst_, "Last instruction is undefined");
1028 inst->SetPrev(lastInst_);
1029 lastInst_->SetNext(inst);
1030 lastInst_ = inst;
1031 // NOLINTNEXTLINE(readability-misleading-indentation)
1032 } else {
1033 auto firstPrev = firstInst_->GetPrev();
1034 if (firstPrev != nullptr) {
1035 firstPrev->SetNext(inst);
1036 }
1037 inst->SetPrev(firstPrev);
1038 inst->SetNext(firstInst_);
1039 firstInst_->SetPrev(inst);
1040 firstInst_ = inst;
1041 }
1042 }
1043 }
1044
AppendRangeInst(Inst * rangeFirst,Inst * rangeLast)1045 void BasicBlock::AppendRangeInst(Inst *rangeFirst, Inst *rangeLast)
1046 {
1047 #ifndef NDEBUG
1048 ASSERT(rangeFirst && rangeLast && rangeFirst->IsDominate(rangeLast));
1049 ASSERT(rangeFirst->GetPrev() == nullptr);
1050 ASSERT(rangeLast->GetNext() == nullptr);
1051 auto instDb = rangeFirst;
1052 while (instDb != rangeLast) {
1053 ASSERT_PRINT(!instDb->IsPhi(), "Instruction mustn't be phi");
1054 ASSERT_PRINT(instDb->GetBasicBlock() == this, "Inst::SetBasicBlock() should be called beforehand");
1055 instDb = instDb->GetNext();
1056 }
1057 ASSERT_PRINT(!instDb->IsPhi(), "Instruction mustn't be phi");
1058 ASSERT_PRINT(instDb->GetBasicBlock() == this, "Inst::SetBasicBlock() should be called beforehand");
1059 #endif
1060
1061 if (firstInst_ == nullptr) {
1062 rangeFirst->SetPrev(lastInst_);
1063 if (lastInst_ != nullptr) {
1064 ASSERT(lastInst_->IsPhi());
1065 lastInst_->SetNext(rangeFirst);
1066 }
1067 firstInst_ = rangeFirst;
1068 lastInst_ = rangeLast;
1069 } else {
1070 ASSERT_PRINT(lastInst_, "Last instruction is undefined");
1071 rangeFirst->SetPrev(lastInst_);
1072 lastInst_->SetNext(rangeFirst);
1073 lastInst_ = rangeLast;
1074 }
1075 }
1076
InsertAfter(Inst * inst,Inst * after)1077 void BasicBlock::InsertAfter(Inst *inst, Inst *after)
1078 {
1079 ASSERT(inst && after);
1080 ASSERT(inst->IsPhi() == after->IsPhi());
1081 ASSERT(after->GetBasicBlock() == this);
1082 ASSERT(inst->GetBasicBlock() == nullptr);
1083 inst->SetBasicBlock(this);
1084 Inst *next = after->GetNext();
1085 inst->SetPrev(after);
1086 inst->SetNext(next);
1087 after->SetNext(inst);
1088 if (next != nullptr) {
1089 next->SetPrev(inst);
1090 } else {
1091 ASSERT(after == lastInst_);
1092 lastInst_ = inst;
1093 }
1094 }
1095
InsertBefore(Inst * inst,Inst * before)1096 void BasicBlock::InsertBefore(Inst *inst, Inst *before)
1097 {
1098 ASSERT(inst && before);
1099 ASSERT(inst->IsPhi() == before->IsPhi());
1100 ASSERT(before->GetBasicBlock() == this);
1101 ASSERT(inst->GetBasicBlock() == nullptr);
1102 inst->SetBasicBlock(this);
1103 Inst *prev = before->GetPrev();
1104 inst->SetPrev(prev);
1105 inst->SetNext(before);
1106 before->SetPrev(inst);
1107 if (prev != nullptr) {
1108 prev->SetNext(inst);
1109 }
1110 if (before == firstPhi_) {
1111 firstPhi_ = inst;
1112 }
1113 if (before == firstInst_) {
1114 firstInst_ = inst;
1115 }
1116 }
1117
InsertRangeBefore(Inst * rangeFirst,Inst * rangeLast,Inst * before)1118 void BasicBlock::InsertRangeBefore(Inst *rangeFirst, Inst *rangeLast, Inst *before)
1119 {
1120 #ifndef NDEBUG
1121 ASSERT(rangeFirst && rangeLast && rangeFirst->IsDominate(rangeLast));
1122 ASSERT(before && !before->IsPhi());
1123 ASSERT(rangeFirst->GetPrev() == nullptr);
1124 ASSERT(rangeLast->GetNext() == nullptr);
1125 ASSERT(before->GetBasicBlock() == this);
1126 auto instDb = rangeFirst;
1127 while (instDb != rangeLast) {
1128 ASSERT_PRINT(!instDb->IsPhi(), "Instruction mustn't be phi");
1129 ASSERT_PRINT(instDb->GetBasicBlock() == this, "Inst::SetBasicBlock() should be called beforehand");
1130 instDb = instDb->GetNext();
1131 }
1132 ASSERT_PRINT(!instDb->IsPhi(), "Instruction mustn't be phi");
1133 ASSERT_PRINT(instDb->GetBasicBlock() == this, "Inst::SetBasicBlock() should be called beforehand");
1134 #endif
1135
1136 Inst *prev = before->GetPrev();
1137 rangeFirst->SetPrev(prev);
1138 rangeLast->SetNext(before);
1139 before->SetPrev(rangeLast);
1140 if (prev != nullptr) {
1141 prev->SetNext(rangeFirst);
1142 }
1143 if (before == firstInst_) {
1144 firstInst_ = rangeFirst;
1145 }
1146 }
1147
ReplaceInst(Inst * oldInst,Inst * newInst)1148 void BasicBlock::ReplaceInst(Inst *oldInst, Inst *newInst)
1149 {
1150 ASSERT(oldInst && newInst);
1151 ASSERT(oldInst->IsPhi() == newInst->IsPhi());
1152 ASSERT(oldInst->GetBasicBlock() == this);
1153 ASSERT(newInst->GetBasicBlock() == nullptr);
1154 newInst->SetBasicBlock(this);
1155 Inst *prev = oldInst->GetPrev();
1156 Inst *next = oldInst->GetNext();
1157
1158 oldInst->SetBasicBlock(nullptr);
1159 if (prev != nullptr) {
1160 prev->SetNext(newInst);
1161 }
1162 if (next != nullptr) {
1163 next->SetPrev(newInst);
1164 }
1165 newInst->SetPrev(prev);
1166 newInst->SetNext(next);
1167 if (firstPhi_ == oldInst) {
1168 firstPhi_ = newInst;
1169 }
1170 if (firstInst_ == oldInst) {
1171 firstInst_ = newInst;
1172 }
1173 if (lastInst_ == oldInst) {
1174 lastInst_ = newInst;
1175 }
1176
1177 if (graph_->IsInstThrowable(oldInst)) {
1178 graph_->ReplaceThrowableInst(oldInst, newInst);
1179 }
1180 }
1181
ReplaceInstByDeoptimize(Inst * inst)1182 void BasicBlock::ReplaceInstByDeoptimize(Inst *inst)
1183 {
1184 ASSERT(inst != nullptr);
1185 ASSERT(inst->GetBasicBlock() == this);
1186 auto ss = inst->GetSaveState();
1187 ASSERT(ss != nullptr);
1188 auto callInst = ss->GetCallerInst();
1189 // if inst in inlined method, we need to build all return.inlined before deoptimize to correct restore registers.
1190 while (callInst != nullptr && callInst->IsInlined()) {
1191 ss = callInst->GetSaveState();
1192 ASSERT(ss != nullptr);
1193 auto retInl = GetGraph()->CreateInstReturnInlined(DataType::NO_TYPE, INVALID_PC, ss);
1194 retInl->SetExtendedLiveness();
1195 InsertBefore(retInl, inst);
1196 callInst = ss->GetCallerInst();
1197 }
1198 // Replace Inst
1199 auto deopt = GetGraph()->CreateInstDeoptimize(DataType::NO_TYPE, inst->GetPc(), inst->GetSaveState());
1200 deopt->SetDeoptimizeType(inst);
1201 inst->RemoveInputs();
1202 inst->RemoveUsers();
1203 ReplaceInst(inst, deopt);
1204 // Build control flow
1205 BasicBlock *succ = GetSuccsBlocks()[0];
1206 if (GetLastInst() != deopt) {
1207 succ = SplitBlockAfterInstruction(deopt, true);
1208 }
1209 ASSERT(GetSuccsBlocks().size() == 1);
1210 GetGraph()->RemoveSuccessors(this);
1211 auto endBlock = GetGraph()->HasEndBlock() ? GetGraph()->GetEndBlock() : GetGraph()->CreateEndBlock();
1212 ASSERT(endBlock->GetGraph() != nullptr);
1213 this->AddSucc(endBlock);
1214 ASSERT(GetGraph()->IsAnalysisValid<LoopAnalyzer>());
1215 GetGraph()->DisconnectBlockRec(succ, true, false);
1216 }
1217
RemoveOverflowCheck(Inst * inst)1218 void BasicBlock::RemoveOverflowCheck(Inst *inst)
1219 {
1220 // replace by Add/Sub
1221 Inst *newInst = nullptr;
1222 switch (inst->GetOpcode()) {
1223 case Opcode::AddOverflowCheck:
1224 newInst = GetGraph()->CreateInstAdd(inst->GetType(), inst->GetPc());
1225 break;
1226 case Opcode::SubOverflowCheck:
1227 newInst = GetGraph()->CreateInstSub(inst->GetType(), inst->GetPc());
1228 break;
1229 case Opcode::NegOverflowAndZeroCheck:
1230 newInst = GetGraph()->CreateInstNeg(inst->GetType(), inst->GetPc());
1231 break;
1232 default:
1233 UNREACHABLE();
1234 }
1235 // clone inputs, except savestate
1236 for (size_t i = 0; i < inst->GetInputsCount() - 1; ++i) {
1237 newInst->SetInput(i, inst->GetInput(i).GetInst());
1238 }
1239 inst->ReplaceUsers(newInst);
1240 inst->RemoveInputs();
1241 ReplaceInst(inst, newInst);
1242 }
1243
EraseInst(Inst * inst,bool willBeMoved)1244 void BasicBlock::EraseInst(Inst *inst, [[maybe_unused]] bool willBeMoved)
1245 {
1246 ASSERT(willBeMoved || !GetGraph()->IsInstThrowable(inst));
1247 Inst *prev = inst->GetPrev();
1248 Inst *next = inst->GetNext();
1249
1250 ASSERT(inst->GetBasicBlock() == this);
1251 inst->SetBasicBlock(nullptr);
1252 if (prev != nullptr) {
1253 prev->SetNext(next);
1254 }
1255 if (next != nullptr) {
1256 next->SetPrev(prev);
1257 }
1258 inst->SetPrev(nullptr);
1259 inst->SetNext(nullptr);
1260 if (inst == firstPhi_) {
1261 firstPhi_ = (next != nullptr && next->IsPhi()) ? next : nullptr;
1262 }
1263 if (inst == firstInst_) {
1264 firstInst_ = next;
1265 }
1266 if (inst == lastInst_) {
1267 lastInst_ = prev;
1268 }
1269 }
1270
RemoveInst(Inst * inst)1271 void BasicBlock::RemoveInst(Inst *inst)
1272 {
1273 inst->RemoveUsers();
1274 ASSERT(!inst->HasUsers());
1275 inst->RemoveInputs();
1276 if (inst->GetOpcode() == Opcode::NullPtr) {
1277 graph_->UnsetNullPtrInst();
1278 } else if (inst->GetOpcode() == Opcode::LoadUndefined) {
1279 graph_->UnsetUndefinedInst();
1280 } else if (inst->GetOpcode() == Opcode::Constant) {
1281 graph_->RemoveConstFromList(static_cast<ConstantInst *>(inst));
1282 } else if (inst->GetOpcode() == Opcode::LoadUndefined) {
1283 graph_->UnsetUndefinedInst();
1284 }
1285
1286 if (graph_->IsInstThrowable(inst)) {
1287 graph_->RemoveThrowableInst(inst);
1288 }
1289 EraseInst(inst);
1290 }
1291
Clear()1292 void BasicBlock::Clear()
1293 {
1294 for (auto inst : AllInstsSafeReverse()) {
1295 RemoveInst(inst);
1296 }
1297 }
1298
1299 /*
1300 * Check if this block is dominate other
1301 */
IsDominate(const BasicBlock * other) const1302 bool BasicBlock::IsDominate(const BasicBlock *other) const
1303 {
1304 if (other == this) {
1305 return true;
1306 }
1307 ASSERT(GetGraph()->IsAnalysisValid<DominatorsTree>());
1308 BasicBlock *domBlock = other->GetDominator();
1309 while (domBlock != nullptr) {
1310 if (domBlock == this) {
1311 return true;
1312 }
1313 // Otherwise we are in infinite loop!?
1314 ASSERT(domBlock != domBlock->GetDominator());
1315 domBlock = domBlock->GetDominator();
1316 }
1317 return false;
1318 }
1319
CreateImmediateDominator()1320 BasicBlock *BasicBlock::CreateImmediateDominator()
1321 {
1322 ASSERT(GetGraph()->IsAnalysisValid<DominatorsTree>());
1323 auto dominator = GetGraph()->CreateEmptyBlock();
1324 GetGraph()->GetAnalysis<DominatorsTree>().SetValid(true);
1325 if (GetDominator() != nullptr) {
1326 GetDominator()->RemoveDominatedBlock(this);
1327 GetDominator()->AddDominatedBlock(dominator);
1328 dominator->SetDominator(GetDominator());
1329 }
1330 dominator->AddDominatedBlock(this);
1331 SetDominator(dominator);
1332 return dominator;
1333 }
1334
GetDominator() const1335 BasicBlock *BasicBlock::GetDominator() const
1336 {
1337 ASSERT(GetGraph()->IsAnalysisValid<DominatorsTree>());
1338 return dominator_;
1339 }
1340
GetDominatedBlocks() const1341 const ArenaVector<BasicBlock *> &BasicBlock::GetDominatedBlocks() const
1342 {
1343 ASSERT(GetGraph()->IsAnalysisValid<DominatorsTree>());
1344 return domBlocks_;
1345 }
1346
PhiInsts() const1347 PhiInstIter BasicBlock::PhiInsts() const
1348 {
1349 return PhiInstIter(*this);
1350 }
Insts() const1351 InstIter BasicBlock::Insts() const
1352 {
1353 return InstIter(*this);
1354 }
AllInsts() const1355 AllInstIter BasicBlock::AllInsts() const
1356 {
1357 return AllInstIter(*this);
1358 }
1359
InstsReverse() const1360 InstReverseIter BasicBlock::InstsReverse() const
1361 {
1362 return InstReverseIter(*this);
1363 }
1364
PhiInstsSafe() const1365 PhiInstSafeIter BasicBlock::PhiInstsSafe() const
1366 {
1367 return PhiInstSafeIter(*this);
1368 }
InstsSafe() const1369 InstSafeIter BasicBlock::InstsSafe() const
1370 {
1371 return InstSafeIter(*this);
1372 }
AllInstsSafe() const1373 AllInstSafeIter BasicBlock::AllInstsSafe() const
1374 {
1375 return AllInstSafeIter(*this);
1376 }
1377
PhiInstsSafeReverse() const1378 PhiInstSafeReverseIter BasicBlock::PhiInstsSafeReverse() const
1379 {
1380 return PhiInstSafeReverseIter(*this);
1381 }
InstsSafeReverse() const1382 InstSafeReverseIter BasicBlock::InstsSafeReverse() const
1383 {
1384 return InstSafeReverseIter(*this);
1385 }
AllInstsSafeReverse() const1386 AllInstSafeReverseIter BasicBlock::AllInstsSafeReverse() const
1387 {
1388 return AllInstSafeReverseIter(*this);
1389 }
1390
1391 template void BasicBlock::AddInst<false>(Inst *inst);
1392 template void BasicBlock::AddInst<true>(Inst *inst);
1393
InsertBlockBefore(BasicBlock * block)1394 void BasicBlock::InsertBlockBefore(BasicBlock *block)
1395 {
1396 for (auto pred : GetPredsBlocks()) {
1397 pred->ReplaceSucc(this, block);
1398 }
1399 GetPredsBlocks().clear();
1400 block->AddSucc(this);
1401 }
1402
Clone(Graph * targetGraph) const1403 BasicBlock *BasicBlock::Clone(Graph *targetGraph) const
1404 {
1405 BasicBlock *clone = nullptr;
1406 #ifndef NDEBUG
1407 if (GetGraph() == targetGraph) {
1408 clone = targetGraph->CreateEmptyBlock();
1409 } else {
1410 clone = targetGraph->CreateEmptyBlock(GetId(), GetGuestPc());
1411 }
1412 #else
1413 clone = targetGraph->CreateEmptyBlock();
1414 #endif
1415 clone->SetAllFields(GetAllFields());
1416 clone->tryId_ = GetTryId();
1417 if (IsStartBlock()) {
1418 targetGraph->SetStartBlock(clone);
1419 } else if (IsEndBlock()) {
1420 targetGraph->SetEndBlock(clone);
1421 }
1422 return clone;
1423 }
1424
GetFistThrowableInst() const1425 Inst *BasicBlock::GetFistThrowableInst() const
1426 {
1427 if (!IsTry()) {
1428 return nullptr;
1429 }
1430 for (auto inst : AllInsts()) {
1431 if (GetGraph()->IsInstThrowable(inst)) {
1432 return inst;
1433 }
1434 }
1435 return nullptr;
1436 }
1437
FindSaveStateDeoptimize() const1438 Inst *BasicBlock::FindSaveStateDeoptimize() const
1439 {
1440 for (auto inst : InstsReverse()) {
1441 if (inst->GetOpcode() == Opcode::SaveStateDeoptimize) {
1442 return inst;
1443 }
1444 }
1445 return nullptr;
1446 }
1447
InvalidateLoopIfIrreducible()1448 void BasicBlock::InvalidateLoopIfIrreducible()
1449 {
1450 auto loop = GetLoop();
1451 ASSERT(loop != nullptr);
1452 if (loop->IsIrreducible()) {
1453 GetGraph()->InvalidateAnalysis<LoopAnalyzer>();
1454 }
1455 }
1456
CountInsts() const1457 uint32_t BasicBlock::CountInsts() const
1458 {
1459 uint32_t count = 0;
1460 for ([[maybe_unused]] auto inst : AllInsts()) {
1461 count++;
1462 }
1463 return count;
1464 }
1465
BlocksPathDfsSearch(Marker marker,BasicBlock * block,const BasicBlock * targetBlock,const BasicBlock * excludeBlock)1466 bool BlocksPathDfsSearch(Marker marker, BasicBlock *block, const BasicBlock *targetBlock,
1467 const BasicBlock *excludeBlock)
1468 {
1469 ASSERT(marker != UNDEF_MARKER);
1470 if (block == targetBlock) {
1471 return true;
1472 }
1473 block->SetMarker(marker);
1474
1475 for (auto succBlock : block->GetSuccsBlocks()) {
1476 if (!succBlock->IsMarked(marker) && succBlock != excludeBlock) {
1477 if (BlocksPathDfsSearch(marker, succBlock, targetBlock, excludeBlock)) {
1478 return true;
1479 }
1480 }
1481 }
1482 return false;
1483 }
1484 } // namespace ark::compiler
1485