• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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 panda::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()->Adapter()),
28       domBlocks_(graph_->GetAllocator()->Adapter()),
29       guestPc_(guestPc)
30 {
31 }
32 
IsStartBlock() const33 bool BasicBlock::IsStartBlock() const
34 {
35     return (graph_->GetStartBlock() == this);
36 }
IsEndBlock() const37 bool BasicBlock::IsEndBlock() const
38 {
39     return (graph_->GetEndBlock() == this);
40 }
IsPseudoControlFlowBlock() const41 bool BasicBlock::IsPseudoControlFlowBlock() const
42 {
43     return IsStartBlock() || IsEndBlock() || IsTryBegin() || IsTryEnd();
44 }
45 
IsLoopHeader() const46 bool BasicBlock::IsLoopHeader() const
47 {
48     ASSERT(GetLoop() != nullptr);
49     return (GetLoop()->GetHeader() == this);
50 }
51 
SplitBlockAfterInstruction(Inst * inst,bool makeEdge)52 BasicBlock *BasicBlock::SplitBlockAfterInstruction(Inst *inst, bool makeEdge)
53 {
54     ASSERT(inst != nullptr);
55     ASSERT(inst->GetBasicBlock() == this);
56     ASSERT(!IsStartBlock() && !IsEndBlock());
57 
58     auto nextInst = inst->GetNext();
59     auto newBb = GetGraph()->CreateEmptyBlock((nextInst != nullptr) ? nextInst->GetPc() : INVALID_PC);
60     newBb->SetAllFields(this->GetAllFields());
61     newBb->SetOsrEntry(false);
62     GetLoop()->AppendBlock(newBb);
63 
64     for (; nextInst != nullptr; nextInst = nextInst->GetNext()) {
65         newBb->AppendInst(nextInst);
66     }
67     inst->SetNext(nullptr);
68     lastInst_ = inst;
69     if (inst->IsPhi()) {
70         firstInst_ = nullptr;
71     }
72     for (auto succ : GetSuccsBlocks()) {
73         succ->ReplacePred(this, newBb);
74     }
75     GetSuccsBlocks().clear();
76 
77     ASSERT(GetSuccsBlocks().empty());
78     if (makeEdge) {
79         AddSucc(newBb);
80     }
81     return newBb;
82 }
83 
AddSucc(BasicBlock * succ,bool canAddEmptyBlock)84 void BasicBlock::AddSucc(BasicBlock *succ, bool canAddEmptyBlock)
85 {
86     auto it = std::find(succs_.begin(), succs_.end(), succ);
87     ASSERT_PRINT(it == succs_.end() || canAddEmptyBlock, "Uncovered case where empty block needed to fix CFG");
88     if (it != succs_.end() && canAddEmptyBlock) {
89         // If edge already exists we create empty block on it
90         auto emptyBb = GetGraph()->CreateEmptyBlock(GetGuestPc());
91         ReplaceSucc(succ, emptyBb);
92         succ->ReplacePred(this, emptyBb);
93     }
94     succs_.push_back(succ);
95     succ->GetPredsBlocks().push_back(this);
96 }
97 
ReplaceSucc(const BasicBlock * prevSucc,BasicBlock * newSucc,bool canAddEmptyBlock)98 void BasicBlock::ReplaceSucc(const BasicBlock *prevSucc, BasicBlock *newSucc, bool canAddEmptyBlock)
99 {
100     auto it = std::find(succs_.begin(), succs_.end(), newSucc);
101     ASSERT_PRINT(it == succs_.end() || canAddEmptyBlock, "Uncovered case where empty block needed to fix CFG");
102     if (it != succs_.end() && canAddEmptyBlock) {
103         // If edge already exists we create empty block on it
104         auto emptyBb = GetGraph()->CreateEmptyBlock(GetGuestPc());
105         ReplaceSucc(newSucc, emptyBb);
106         newSucc->ReplacePred(this, emptyBb);
107     }
108     succs_[GetSuccBlockIndex(prevSucc)] = newSucc;
109     newSucc->preds_.push_back(this);
110 }
111 
InsertNewBlockToSuccEdge(BasicBlock * succ)112 BasicBlock *BasicBlock::InsertNewBlockToSuccEdge(BasicBlock *succ)
113 {
114     auto block = GetGraph()->CreateEmptyBlock(succ->GetGuestPc());
115     this->ReplaceSucc(succ, block);
116     succ->ReplacePred(this, block);
117     return block;
118 }
119 
InsertEmptyBlockBefore()120 BasicBlock *BasicBlock::InsertEmptyBlockBefore()
121 {
122     auto block = GetGraph()->CreateEmptyBlock(this->GetGuestPc());
123     for (auto pred : preds_) {
124         pred->ReplaceSucc(this, block);
125         this->RemovePred(pred);
126     }
127     block->AddSucc(this);
128     return block;
129 }
130 
InsertBlockBeforeSucc(BasicBlock * block,BasicBlock * succ)131 void BasicBlock::InsertBlockBeforeSucc(BasicBlock *block, BasicBlock *succ)
132 {
133     this->ReplaceSucc(succ, block);
134     succ->ReplacePred(this, block);
135 }
136 
RemovePhiProcessing(BasicBlock * bb,BasicBlock * succ)137 static void RemovePhiProcessing(BasicBlock *bb, BasicBlock *succ)
138 {
139     size_t numPreds = bb->GetPredsBlocks().size();
140 
141     for (auto phi : succ->PhiInsts()) {
142         auto index = phi->CastToPhi()->GetPredBlockIndex(bb);
143         auto inst = phi->GetInput(index).GetInst();
144         if (inst->GetBasicBlock() == bb) {  // When INST is from empty basic block ...
145             ASSERT(inst->IsPhi());
146             // ... we have to copy it's inputs into corresponding inputs of PHI
147             auto predBb = bb->GetPredBlockByIndex(0);
148             phi->SetInput(index, inst->CastToPhi()->GetPhiInput(predBb));
149             for (size_t i = 1; i < numPreds; i++) {
150                 predBb = bb->GetPredBlockByIndex(i);
151                 phi->AppendInput(inst->CastToPhi()->GetPhiInput(predBb));
152             }
153         } else {  // otherwise, just copy inputs for new arrived predecessors
154             for (size_t i = 1; i < numPreds; i++) {
155                 phi->AppendInput(inst);
156             }
157         }
158     }
159     // And now we should remove Phis from the empty block
160     for (auto phi : bb->PhiInstsSafe()) {
161         bb->RemoveInst(phi);
162     }
163 }
164 
165 // Remove empty block with one successor, may have more than one predecessors and Phi(s)
RemoveEmptyBlock(bool irrLoop)166 void BasicBlock::RemoveEmptyBlock(bool irrLoop)
167 {
168     ASSERT(GetFirstInst() == nullptr);
169     ASSERT(!GetPredsBlocks().empty());
170     ASSERT(GetSuccsBlocks().size() == 1);
171     auto succ = succs_[0];
172 
173     // Save old amount of predecessors in successor block
174     size_t succPredsNum = succ->GetPredsBlocks().size();
175 
176     size_t numPreds = preds_.size();
177     // If empty block had more than one predecessors
178     if (numPreds > 1) {
179         if (succPredsNum > 1) {
180             // We have to process Phi instructions in successor block in a special way
181             RemovePhiProcessing(this, succ);
182         } else {  // successor didn't have other predecessors, we are moving Phi(s) into successor
183             ASSERT(!succ->HasPhi());
184             for (auto phi : PhiInstsSafe()) {
185                 succ->AppendPhi(phi);
186             }
187             firstPhi_ = nullptr;
188             lastInst_ = nullptr;
189         }
190     }
191 
192     // Set successor for all predecessor blocks, at the same time in successor we replace one predecessor
193     // and add others to the end (if there were many of them in empty block)
194     auto pred = preds_[0];
195     pred->succs_[pred->GetSuccBlockIndex(this)] = succ;
196     succ->preds_[succ->GetPredBlockIndex(this)] = pred;
197     for (size_t i = 1; i < numPreds; ++i) {
198         pred = preds_[i];
199         pred->succs_[pred->GetSuccBlockIndex(this)] = succ;
200         succ->preds_.push_back(pred);
201     }
202 
203     ASSERT(GetLastInst() == nullptr);
204     ASSERT(GetLoop()->IsIrreducible() == irrLoop);
205     // N.B. info about Irreducible loop can not be fixed on the fly
206     if (!irrLoop) {
207         RemoveFixLoopInfo();
208     }
209     // Finally clean lists
210     preds_.clear();
211     succs_.clear();
212 }
213 
FixLoopInfoHelper(BasicBlock * bb)214 static void FixLoopInfoHelper(BasicBlock *bb)
215 {
216     ASSERT(!bb->GetPredsBlocks().empty());
217     auto loop = bb->GetLoop();
218     auto firstPred = bb->GetPredBlockByIndex(0);
219     // Do not dup back-edge
220     if (loop->HasBackEdge(firstPred)) {
221         loop->RemoveBackEdge(bb);
222     } else {
223         loop->ReplaceBackEdge(bb, firstPred);
224     }
225     // If empty block has more than 1 predecessor, append others to the loop back-edges' list
226     for (size_t i = 1; i < bb->GetPredsBlocks().size(); ++i) {
227         auto pred = bb->GetPredBlockByIndex(i);
228         if (!loop->HasBackEdge(pred)) {
229             loop->AppendBackEdge(pred);
230         }
231     }
232 }
233 
RemoveFixLoopInfo()234 void BasicBlock::RemoveFixLoopInfo()
235 {
236     auto loop = GetLoop();
237     ASSERT(loop != nullptr);
238     ASSERT(!loop->IsIrreducible());
239     while (!loop->IsRoot()) {
240         if (loop->HasBackEdge(this)) {
241             FixLoopInfoHelper(this);
242         }
243         loop = loop->GetOuterLoop();
244     }
245     if (this == GetLoop()->GetHeader()) {
246         GetLoop()->MoveHeaderToSucc();
247     }
248     GetLoop()->RemoveBlock(this);
249 }
250 
251 /**
252  * Join single successor into single predecessor.
253  * Block must have one successor, and its successor must have one predecessor (this block).
254  * EXAMPLE:
255  *              [1]
256  *               |
257  *              [2]
258  *
259  * turns into this:
260  *              [1']
261  */
JoinSuccessorBlock()262 void BasicBlock::JoinSuccessorBlock()
263 {
264     ASSERT(!IsStartBlock());
265 
266     ASSERT(GetSuccsBlocks().size() == 1);
267     auto succ = GetSuccessor(0);
268     ASSERT(!succ->IsEndBlock());
269 
270     ASSERT(succ->GetPredsBlocks().size() == 1);
271     ASSERT(succ->GetPredBlockByIndex(0) == this);
272 
273     // moving instructions from successor
274     ASSERT(!succ->HasPhi());
275     for (auto succInst : succ->Insts()) {
276         AppendInst(succInst);
277     }
278 
279     // moving successor blocks from the successor
280     GetSuccsBlocks().clear();
281     for (auto succSucc : succ->GetSuccsBlocks()) {
282         succSucc->ReplacePred(succ, this);
283     }
284 
285     if (GetGraph()->IsAnalysisValid<LoopAnalyzer>()) {
286         // fixing loop information
287         // invariant: succ has one predecessor, so it cannot be a loop header
288         auto loop = succ->GetLoop();
289         ASSERT(loop != nullptr);
290         // Irreducible loop can not be fixed on the fly
291         if (loop->IsIrreducible()) {
292             GetGraph()->InvalidateAnalysis<LoopAnalyzer>();
293         } else {
294             // edge can have 2 successors, so it can be back-edge in 2 loops: own loop and outer loop
295             ReplaceSuccessorLoopBackEdges(loop, succ);
296             loop->RemoveBlock(succ);
297         }
298     }
299 
300     succ->firstInst_ = nullptr;
301     succ->lastInst_ = nullptr;
302     succ->GetPredsBlocks().clear();
303     succ->GetSuccsBlocks().clear();
304 
305     this->bitFields_ |= succ->bitFields_;
306     // NOTE (a.popov) replace by assert
307     if (succ->tryId_ != INVALID_ID) {
308         this->tryId_ = succ->tryId_;
309     }
310     GetGraph()->RemoveEmptyBlock(succ);
311 }
312 
ReplaceSuccessorLoopBackEdges(Loop * loop,BasicBlock * succ)313 void BasicBlock::ReplaceSuccessorLoopBackEdges(Loop *loop, BasicBlock *succ)
314 {
315     if (loop->HasBackEdge(succ)) {
316         loop->ReplaceBackEdge(succ, this);
317     }
318     for (auto outerLoop = loop->GetOuterLoop(); outerLoop != nullptr; outerLoop = outerLoop->GetOuterLoop()) {
319         if (outerLoop->HasBackEdge(succ)) {
320             outerLoop->ReplaceBackEdge(succ, this);
321         }
322     }
323     for (auto innerLoop : loop->GetInnerLoops()) {
324         if (innerLoop->GetPreHeader() == succ) {
325             innerLoop->SetPreHeader(this);
326         }
327     }
328 }
329 
330 /**
331  * Join successor block into the block, which have another successor;
332  * Used in if-conversion pass and fixes dataflow using Select instructions.
333  * @param succ is a successor block which must have one predecessor and
334  * one successor, function will remove Phi(s) from the latter successor.
335  * @param select_bb is a block to insert generated Select instructions.
336  * When 'select_bb' is nullptr, we generate Select(s) in 'this' block.
337  * @param swapped == true means 'succ' is False successor (instead of True).
338  * How conversion works in the following two cases:
339  *
340  * EXAMPLE 1 (Comes from TryTriangle in if_conversion.cpp):
341  *
342  *                [this] ('select_bb' == nullptr)
343  *                (last inst: if-jump)
344  *                 |  \
345  *                 |  [succ]
346  *                 |  (one inst: arithmetic)
347  *                 |  /
348  *                (first inst: phi)
349  *                [other]
350  *
351  * turns into this:
352  *                [this]
353  *                (arithmetic)
354  *                (select)
355  *                 |
356  *                 |
357  *                (may be phi if there are another predecessors)
358  *                [other]
359  *
360  * EXAMPLE 2 (Comes from TryDiamond in if_conversion.cpp):
361  *
362  *                [this]
363  *                (last inst: if-jump)
364  *                /   \
365  *       [select_bb]  [succ]
366  *     (arithmetic2)  (arithmetic1)
367  *                \   /
368  *                (first inst: phi)
369  *                [other]
370  *
371  * turns into this:
372  *                [this]
373  *                (arithmetic1)
374  *                 |
375  *                 |
376  *                [select_bb]
377  *                (arithmetic2)
378  *                (select)
379  *                 |
380  *                 |
381  *                (may be phi if there are another predecessors)
382  *                [other]
383  *
384  * Function returns whether we need DCE for If inputs.
385  */
JoinBlocksUsingSelect(BasicBlock * succ,BasicBlock * selectBb,bool swapped)386 void BasicBlock::JoinBlocksUsingSelect(BasicBlock *succ, BasicBlock *selectBb, bool swapped)
387 {
388     ASSERT(!IsStartBlock());
389     ASSERT(GetSuccsBlocks().size() == MAX_SUCCS_NUM);
390     ASSERT(succ == GetSuccessor(0) || succ == GetSuccessor(1));
391     ASSERT(!succ->IsEndBlock());
392     ASSERT(succ->GetPredsBlocks().size() == 1);
393     ASSERT(succ->GetPredBlockByIndex(0) == this);
394     ASSERT(succ->GetSuccsBlocks().size() == 1);
395     /**
396      * There are 2 steps in Join operation.
397      * Step 1. Move instructions from 'succ' into 'this'.
398      */
399     Inst *ifInst = GetLastInst();
400     SavedIfInfo ifInfo {succ,
401                         swapped,
402                         0,
403                         ConditionCode::CC_FIRST,
404                         DataType::NO_TYPE,
405                         ifInst->GetPc(),
406                         ifInst->GetOpcode(),
407                         ifInst->GetInput(0).GetInst(),
408                         nullptr};
409 
410     // Save necessary info
411     if (ifInfo.ifOpcode == Opcode::IfImm) {
412         ifInfo.ifImm = ifInst->CastToIfImm()->GetImm();
413         ifInfo.ifCc = ifInst->CastToIfImm()->GetCc();
414         ifInfo.ifType = ifInst->CastToIfImm()->GetOperandsType();
415     } else if (ifInfo.ifOpcode == Opcode::If) {
416         ifInfo.ifInput1 = ifInst->GetInput(1).GetInst();
417         ifInfo.ifCc = ifInst->CastToIf()->GetCc();
418         ifInfo.ifType = ifInst->CastToIf()->GetOperandsType();
419     } else {
420         UNREACHABLE();
421     }
422 
423     // Remove 'If' instruction
424     RemoveInst(ifInst);
425 
426     // Remove incoming 'this->succ' edge
427     RemoveSucc(succ);
428     succ->GetPredsBlocks().clear();
429 
430     // Main loop in "Step 1", moving instructions from successor.
431     ASSERT(!succ->HasPhi());
432     for (auto inst : succ->Insts()) {
433         AppendInst(inst);
434     }
435     succ->firstInst_ = nullptr;
436     succ->lastInst_ = nullptr;
437 
438     auto other = succ->GetSuccessor(0);
439     /**
440      * Step 2. Generate Select(s).
441      * We generate them in 'select_bb' if provided (another successor in Diamond case),
442      * or in 'this' block otherwise (Triangle case).
443      */
444     if (selectBb == nullptr) {
445         selectBb = this;
446     }
447     selectBb->GenerateSelects(&ifInfo);
448     succ->SelectsFixLoopInfo(selectBb, other);
449 }
450 
GenerateSelect(Inst * phi,Inst * inst1,Inst * inst2,const SavedIfInfo * ifInfo)451 void BasicBlock::GenerateSelect(Inst *phi, Inst *inst1, Inst *inst2, const SavedIfInfo *ifInfo)
452 {
453     auto other = ifInfo->succ->GetSuccessor(0);
454     Inst *select = nullptr;
455     ASSERT(GetGraph()->GetEncoder()->CanEncodeFloatSelect() || !DataType::IsFloatType(phi->GetType()));
456     if (ifInfo->ifOpcode == Opcode::IfImm) {
457         select = GetGraph()->CreateInstSelectImm(phi->GetType(), ifInfo->ifPc, ifInfo->swapped ? inst2 : inst1,
458                                                  ifInfo->swapped ? inst1 : inst2, ifInfo->ifInput0, ifInfo->ifImm,
459                                                  ifInfo->ifType, ifInfo->ifCc);
460     } else if (ifInfo->ifOpcode == Opcode::If) {
461         select = GetGraph()->CreateInstSelect(phi->GetType(), ifInfo->ifPc, ifInfo->swapped ? inst2 : inst1,
462                                               ifInfo->swapped ? inst1 : inst2, ifInfo->ifInput0, ifInfo->ifInput1,
463                                               ifInfo->ifType, ifInfo->ifCc);
464     } else {
465         UNREACHABLE();
466     }
467 
468     AppendInst(select);
469 
470     if (other->GetPredsBlocks().size() > 2U) {
471         // Change input (from this block) to new Select instruction
472         auto index = phi->CastToPhi()->GetPredBlockIndex(this);
473         phi->CastToPhi()->SetInput(index, select);
474         // Remove input from 'succ'
475         index = phi->CastToPhi()->GetPredBlockIndex(ifInfo->succ);
476         phi->CastToPhi()->RemoveInput(index);
477     } else {
478         // Remove Phi
479         phi->ReplaceUsers(select);
480         other->RemoveInst(phi);
481     }
482     // Select now must have users
483     ASSERT(select->HasUsers());
484 }
485 
GenerateSelects(const SavedIfInfo * ifInfo)486 void BasicBlock::GenerateSelects(const SavedIfInfo *ifInfo)
487 {
488     auto succ = ifInfo->succ;
489 
490     // The only successor whether we will check Phi(s)
491     auto other = succ->GetSuccessor(0);
492     constexpr auto TWO = 2;
493     ASSERT(other->GetPredsBlocks().size() >= TWO);
494 
495     // Main loop in "Step 2", generate select(s) and drop phi(s) when possible
496     for (auto phi : other->PhiInstsSafe()) {
497         size_t index1 = phi->CastToPhi()->GetPredBlockIndex(succ);
498         size_t index2 = phi->CastToPhi()->GetPredBlockIndex(this);
499         ASSERT(index1 != index2);
500 
501         auto inst1 = phi->GetInput(index1).GetInst();
502         auto inst2 = phi->GetInput(index2).GetInst();
503         if (inst1 == inst2) {
504             // No select needed
505             if (other->GetPredsBlocks().size() > TWO) {
506                 // Remove input from 'succ'
507                 auto index = phi->CastToPhi()->GetPredBlockIndex(succ);
508                 phi->CastToPhi()->RemoveInput(index);
509             } else {
510                 // Remove Phi
511                 phi->ReplaceUsers(inst1);
512                 other->RemoveInst(phi);
513             }
514             continue;
515         }
516 
517         GenerateSelect(phi, inst1, inst2, ifInfo);
518     }
519 }
520 
SelectsFixLoopInfo(BasicBlock * selectBb,BasicBlock * other)521 void BasicBlock::SelectsFixLoopInfo(BasicBlock *selectBb, BasicBlock *other)
522 {
523     // invariant: 'this' block has one predecessor, so it cannot be a loop header
524     auto loop = GetLoop();
525     ASSERT(loop != nullptr);
526     // Irreducible loop can not be fixed on the fly
527     if (loop->IsIrreducible()) {
528         GetGraph()->InvalidateAnalysis<LoopAnalyzer>();
529     } else {
530         if (loop->HasBackEdge(this)) {
531             loop->RemoveBackEdge(this);
532         }
533         for (auto innerLoop : loop->GetInnerLoops()) {
534             if (innerLoop->GetPreHeader() == this) {
535                 innerLoop->SetPreHeader(selectBb);
536                 break;
537             }
538         }
539         loop->RemoveBlock(this);
540     }
541 
542     // Remove outgoing 'this->other' edge
543     RemoveSucc(other);
544     other->RemovePred(this);
545     // Disconnect
546     GetGraph()->RemoveEmptyBlock(this);
547 }
548 
AppendPhi(Inst * inst)549 void BasicBlock::AppendPhi(Inst *inst)
550 {
551     ASSERT_PRINT(inst->IsPhi(), "Instruction must be phi");
552     inst->SetBasicBlock(this);
553     if (firstPhi_ == nullptr) {
554         inst->SetNext(firstInst_);
555         if (firstInst_ != nullptr) {
556             firstInst_->SetPrev(inst);
557         }
558         firstPhi_ = inst;
559         if (lastInst_ == nullptr) {
560             lastInst_ = inst;
561         }
562     } else {
563         if (firstInst_ != nullptr) {
564             Inst *prev = firstInst_->GetPrev();
565             ASSERT_PRINT(prev && prev->IsPhi(), "There is no phi in the block");
566             inst->SetPrev(prev);
567             prev->SetNext(inst);
568             inst->SetNext(firstInst_);
569             firstInst_->SetPrev(inst);
570         } else {
571             ASSERT_PRINT(lastInst_ && lastInst_->IsPhi(),
572                          "If first_phi is defined and first_inst is undefined, last_inst must be phi");
573             lastInst_->SetNext(inst);
574             inst->SetPrev(lastInst_);
575             lastInst_ = inst;
576         }
577     }
578 }
579 
580 template <bool TO_END>
AddInst(Inst * inst)581 void BasicBlock::AddInst(Inst *inst)
582 {
583     ASSERT_PRINT(!inst->IsPhi(), "Instruction mustn't be phi");
584     inst->SetBasicBlock(this);
585     if (firstInst_ == nullptr) {
586         inst->SetPrev(lastInst_);
587         if (lastInst_ != nullptr) {
588             ASSERT(lastInst_->IsPhi());
589             lastInst_->SetNext(inst);
590         }
591         firstInst_ = inst;
592         lastInst_ = inst;
593     } else {
594         // NOLINTNEXTLINE(readability-braces-around-statements)
595         if constexpr (TO_END) {
596             ASSERT_PRINT(lastInst_, "Last instruction is undefined");
597             inst->SetPrev(lastInst_);
598             lastInst_->SetNext(inst);
599             lastInst_ = inst;
600             // NOLINTNEXTLINE(readability-misleading-indentation)
601         } else {
602             auto firstPrev = firstInst_->GetPrev();
603             if (firstPrev != nullptr) {
604                 firstPrev->SetNext(inst);
605             }
606             inst->SetPrev(firstPrev);
607             inst->SetNext(firstInst_);
608             firstInst_->SetPrev(inst);
609             firstInst_ = inst;
610         }
611     }
612 }
613 
AppendRangeInst(Inst * rangeFirst,Inst * rangeLast)614 void BasicBlock::AppendRangeInst(Inst *rangeFirst, Inst *rangeLast)
615 {
616 #ifndef NDEBUG
617     ASSERT(rangeFirst && rangeLast && rangeFirst->IsDominate(rangeLast));
618     ASSERT(rangeFirst->GetPrev() == nullptr);
619     ASSERT(rangeLast->GetNext() == nullptr);
620     auto instDb = rangeFirst;
621     while (instDb != rangeLast) {
622         ASSERT_PRINT(!instDb->IsPhi(), "Instruction mustn't be phi");
623         ASSERT_PRINT(instDb->GetBasicBlock() == this, "Inst::SetBasicBlock() should be called beforehand");
624         instDb = instDb->GetNext();
625     }
626     ASSERT_PRINT(!instDb->IsPhi(), "Instruction mustn't be phi");
627     ASSERT_PRINT(instDb->GetBasicBlock() == this, "Inst::SetBasicBlock() should be called beforehand");
628 #endif
629 
630     if (firstInst_ == nullptr) {
631         rangeFirst->SetPrev(lastInst_);
632         if (lastInst_ != nullptr) {
633             ASSERT(lastInst_->IsPhi());
634             lastInst_->SetNext(rangeFirst);
635         }
636         firstInst_ = rangeFirst;
637         lastInst_ = rangeLast;
638     } else {
639         ASSERT_PRINT(lastInst_, "Last instruction is undefined");
640         rangeFirst->SetPrev(lastInst_);
641         lastInst_->SetNext(rangeFirst);
642         lastInst_ = rangeLast;
643     }
644 }
645 
InsertAfter(Inst * inst,Inst * after)646 void BasicBlock::InsertAfter(Inst *inst, Inst *after)
647 {
648     ASSERT(inst && after);
649     ASSERT(inst->IsPhi() == after->IsPhi());
650     ASSERT(after->GetBasicBlock() == this);
651     ASSERT(inst->GetBasicBlock() == nullptr);
652     inst->SetBasicBlock(this);
653     Inst *next = after->GetNext();
654     inst->SetPrev(after);
655     inst->SetNext(next);
656     after->SetNext(inst);
657     if (next != nullptr) {
658         next->SetPrev(inst);
659     } else {
660         ASSERT(after == lastInst_);
661         lastInst_ = inst;
662     }
663 }
664 
InsertBefore(Inst * inst,Inst * before)665 void BasicBlock::InsertBefore(Inst *inst, Inst *before)
666 {
667     ASSERT(inst && before);
668     ASSERT(inst->IsPhi() == before->IsPhi());
669     ASSERT(before->GetBasicBlock() == this);
670     ASSERT(inst->GetBasicBlock() == nullptr);
671     inst->SetBasicBlock(this);
672     Inst *prev = before->GetPrev();
673     inst->SetPrev(prev);
674     inst->SetNext(before);
675     before->SetPrev(inst);
676     if (prev != nullptr) {
677         prev->SetNext(inst);
678     }
679     if (before == firstPhi_) {
680         firstPhi_ = inst;
681     }
682     if (before == firstInst_) {
683         firstInst_ = inst;
684     }
685 }
686 
InsertRangeBefore(Inst * rangeFirst,Inst * rangeLast,Inst * before)687 void BasicBlock::InsertRangeBefore(Inst *rangeFirst, Inst *rangeLast, Inst *before)
688 {
689 #ifndef NDEBUG
690     ASSERT(rangeFirst && rangeLast && rangeFirst->IsDominate(rangeLast));
691     ASSERT(before && !before->IsPhi());
692     ASSERT(rangeFirst->GetPrev() == nullptr);
693     ASSERT(rangeLast->GetNext() == nullptr);
694     ASSERT(before->GetBasicBlock() == this);
695     auto instDb = rangeFirst;
696     while (instDb != rangeLast) {
697         ASSERT_PRINT(!instDb->IsPhi(), "Instruction mustn't be phi");
698         ASSERT_PRINT(instDb->GetBasicBlock() == this, "Inst::SetBasicBlock() should be called beforehand");
699         instDb = instDb->GetNext();
700     }
701     ASSERT_PRINT(!instDb->IsPhi(), "Instruction mustn't be phi");
702     ASSERT_PRINT(instDb->GetBasicBlock() == this, "Inst::SetBasicBlock() should be called beforehand");
703 #endif
704 
705     Inst *prev = before->GetPrev();
706     rangeFirst->SetPrev(prev);
707     rangeLast->SetNext(before);
708     before->SetPrev(rangeLast);
709     if (prev != nullptr) {
710         prev->SetNext(rangeFirst);
711     }
712     if (before == firstInst_) {
713         firstInst_ = rangeFirst;
714     }
715 }
716 
ReplaceInst(Inst * oldInst,Inst * newInst)717 void BasicBlock::ReplaceInst(Inst *oldInst, Inst *newInst)
718 {
719     ASSERT(oldInst && newInst);
720     ASSERT(oldInst->IsPhi() == newInst->IsPhi());
721     ASSERT(oldInst->GetBasicBlock() == this);
722     ASSERT(newInst->GetBasicBlock() == nullptr);
723     newInst->SetBasicBlock(this);
724     Inst *prev = oldInst->GetPrev();
725     Inst *next = oldInst->GetNext();
726 
727     oldInst->SetBasicBlock(nullptr);
728     if (prev != nullptr) {
729         prev->SetNext(newInst);
730     }
731     if (next != nullptr) {
732         next->SetPrev(newInst);
733     }
734     newInst->SetPrev(prev);
735     newInst->SetNext(next);
736     if (firstPhi_ == oldInst) {
737         firstPhi_ = newInst;
738     }
739     if (firstInst_ == oldInst) {
740         firstInst_ = newInst;
741     }
742     if (lastInst_ == oldInst) {
743         lastInst_ = newInst;
744     }
745 
746     if (graph_->IsInstThrowable(oldInst)) {
747         graph_->ReplaceThrowableInst(oldInst, newInst);
748     }
749 }
750 
ReplaceInstByDeoptimize(Inst * inst)751 void BasicBlock::ReplaceInstByDeoptimize(Inst *inst)
752 {
753     ASSERT(inst != nullptr);
754     ASSERT(inst->GetBasicBlock() == this);
755     auto ss = inst->GetSaveState();
756     ASSERT(ss != nullptr);
757     auto callInst = ss->GetCallerInst();
758     // if inst in inlined method, we need to build all return.inlined before deoptimize to correct restore registers.
759     while (callInst != nullptr && callInst->IsInlined()) {
760         ss = callInst->GetSaveState();
761         ASSERT(ss != nullptr);
762         auto retInl = GetGraph()->CreateInstReturnInlined(DataType::NO_TYPE, INVALID_PC, ss);
763         retInl->SetExtendedLiveness();
764         InsertBefore(retInl, inst);
765         callInst = ss->GetCallerInst();
766     }
767     // Replace Inst
768     auto deopt = GetGraph()->CreateInstDeoptimize(DataType::NO_TYPE, inst->GetPc(), inst->GetSaveState());
769     deopt->SetDeoptimizeType(inst);
770     inst->RemoveInputs();
771     inst->RemoveUsers();
772     ReplaceInst(inst, deopt);
773     // Build control flow
774     BasicBlock *succ = GetSuccsBlocks()[0];
775     if (GetLastInst() != deopt) {
776         succ = SplitBlockAfterInstruction(deopt, true);
777     }
778     ASSERT(GetSuccsBlocks().size() == 1);
779     GetGraph()->RemoveSuccessors(this);
780     auto endBlock = GetGraph()->HasEndBlock() ? GetGraph()->GetEndBlock() : GetGraph()->CreateEndBlock();
781     ASSERT(endBlock->GetGraph() != nullptr);
782     this->AddSucc(endBlock);
783     ASSERT(GetGraph()->IsAnalysisValid<LoopAnalyzer>());
784     GetGraph()->DisconnectBlockRec(succ, true, false);
785 }
786 
RemoveOverflowCheck(Inst * inst)787 void BasicBlock::RemoveOverflowCheck(Inst *inst)
788 {
789     // replace by Add/Sub
790     Inst *newInst = nullptr;
791     switch (inst->GetOpcode()) {
792         case Opcode::AddOverflowCheck:
793             newInst = GetGraph()->CreateInstAdd(inst->GetType(), inst->GetPc());
794             break;
795         case Opcode::SubOverflowCheck:
796             newInst = GetGraph()->CreateInstSub(inst->GetType(), inst->GetPc());
797             break;
798         case Opcode::NegOverflowAndZeroCheck:
799             newInst = GetGraph()->CreateInstNeg(inst->GetType(), inst->GetPc());
800             break;
801         default:
802             UNREACHABLE();
803     }
804     // clone inputs, except savestate
805     for (size_t i = 0; i < inst->GetInputsCount() - 1; ++i) {
806         newInst->SetInput(i, inst->GetInput(i).GetInst());
807     }
808     inst->ReplaceUsers(newInst);
809     inst->RemoveInputs();
810     ReplaceInst(inst, newInst);
811 }
812 
EraseInst(Inst * inst,bool willBeMoved)813 void BasicBlock::EraseInst(Inst *inst, [[maybe_unused]] bool willBeMoved)
814 {
815     ASSERT(willBeMoved || !GetGraph()->IsInstThrowable(inst));
816     Inst *prev = inst->GetPrev();
817     Inst *next = inst->GetNext();
818 
819     ASSERT(inst->GetBasicBlock() == this);
820     inst->SetBasicBlock(nullptr);
821     if (prev != nullptr) {
822         prev->SetNext(next);
823     }
824     if (next != nullptr) {
825         next->SetPrev(prev);
826     }
827     inst->SetPrev(nullptr);
828     inst->SetNext(nullptr);
829     if (inst == firstPhi_) {
830         firstPhi_ = (next != nullptr && next->IsPhi()) ? next : nullptr;
831     }
832     if (inst == firstInst_) {
833         firstInst_ = next;
834     }
835     if (inst == lastInst_) {
836         lastInst_ = prev;
837     }
838 }
839 
RemoveInst(Inst * inst)840 void BasicBlock::RemoveInst(Inst *inst)
841 {
842     inst->RemoveUsers();
843     ASSERT(!inst->HasUsers());
844     inst->RemoveInputs();
845     if (inst->GetOpcode() == Opcode::NullPtr) {
846         graph_->UnsetNullPtrInst();
847     } else if (inst->GetOpcode() == Opcode::Constant) {
848         graph_->RemoveConstFromList(static_cast<ConstantInst *>(inst));
849     }
850 
851     if (graph_->IsInstThrowable(inst)) {
852         graph_->RemoveThrowableInst(inst);
853     }
854     EraseInst(inst);
855 }
856 
Clear()857 void BasicBlock::Clear()
858 {
859     for (auto inst : AllInstsSafeReverse()) {
860         RemoveInst(inst);
861     }
862 }
863 
864 /*
865  * Check if this block is dominate other
866  */
IsDominate(const BasicBlock * other) const867 bool BasicBlock::IsDominate(const BasicBlock *other) const
868 {
869     if (other == this) {
870         return true;
871     }
872     ASSERT(GetGraph()->IsAnalysisValid<DominatorsTree>());
873     BasicBlock *domBlock = other->GetDominator();
874     while (domBlock != nullptr) {
875         if (domBlock == this) {
876             return true;
877         }
878         // Otherwise we are in infinite loop!?
879         ASSERT(domBlock != domBlock->GetDominator());
880         domBlock = domBlock->GetDominator();
881     }
882     return false;
883 }
884 
CreateImmediateDominator()885 BasicBlock *BasicBlock::CreateImmediateDominator()
886 {
887     ASSERT(GetGraph()->IsAnalysisValid<DominatorsTree>());
888     auto dominator = GetGraph()->CreateEmptyBlock();
889     GetGraph()->GetAnalysis<DominatorsTree>().SetValid(true);
890     if (GetDominator() != nullptr) {
891         GetDominator()->RemoveDominatedBlock(this);
892         GetDominator()->AddDominatedBlock(dominator);
893         dominator->SetDominator(GetDominator());
894     }
895     dominator->AddDominatedBlock(this);
896     SetDominator(dominator);
897     return dominator;
898 }
899 
GetDominator() const900 BasicBlock *BasicBlock::GetDominator() const
901 {
902     ASSERT(GetGraph()->IsAnalysisValid<DominatorsTree>());
903     return dominator_;
904 }
905 
GetDominatedBlocks() const906 const ArenaVector<BasicBlock *> &BasicBlock::GetDominatedBlocks() const
907 {
908     ASSERT(GetGraph()->IsAnalysisValid<DominatorsTree>());
909     return domBlocks_;
910 }
911 
PhiInsts() const912 PhiInstIter BasicBlock::PhiInsts() const
913 {
914     return PhiInstIter(*this);
915 }
Insts() const916 InstIter BasicBlock::Insts() const
917 {
918     return InstIter(*this);
919 }
AllInsts() const920 AllInstIter BasicBlock::AllInsts() const
921 {
922     return AllInstIter(*this);
923 }
924 
InstsReverse() const925 InstReverseIter BasicBlock::InstsReverse() const
926 {
927     return InstReverseIter(*this);
928 }
929 
PhiInstsSafe() const930 PhiInstSafeIter BasicBlock::PhiInstsSafe() const
931 {
932     return PhiInstSafeIter(*this);
933 }
InstsSafe() const934 InstSafeIter BasicBlock::InstsSafe() const
935 {
936     return InstSafeIter(*this);
937 }
AllInstsSafe() const938 AllInstSafeIter BasicBlock::AllInstsSafe() const
939 {
940     return AllInstSafeIter(*this);
941 }
942 
PhiInstsSafeReverse() const943 PhiInstSafeReverseIter BasicBlock::PhiInstsSafeReverse() const
944 {
945     return PhiInstSafeReverseIter(*this);
946 }
InstsSafeReverse() const947 InstSafeReverseIter BasicBlock::InstsSafeReverse() const
948 {
949     return InstSafeReverseIter(*this);
950 }
AllInstsSafeReverse() const951 AllInstSafeReverseIter BasicBlock::AllInstsSafeReverse() const
952 {
953     return AllInstSafeReverseIter(*this);
954 }
955 
956 template void BasicBlock::AddInst<false>(Inst *inst);
957 template void BasicBlock::AddInst<true>(Inst *inst);
958 
InsertBlockBefore(BasicBlock * block)959 void BasicBlock::InsertBlockBefore(BasicBlock *block)
960 {
961     for (auto pred : GetPredsBlocks()) {
962         pred->ReplaceSucc(this, block);
963     }
964     GetPredsBlocks().clear();
965     block->AddSucc(this);
966 }
967 
Clone(Graph * targetGraph) const968 BasicBlock *BasicBlock::Clone(Graph *targetGraph) const
969 {
970     BasicBlock *clone = nullptr;
971 #ifndef NDEBUG
972     if (GetGraph() == targetGraph) {
973         clone = targetGraph->CreateEmptyBlock();
974     } else {
975         clone = targetGraph->CreateEmptyBlock(GetId(), GetGuestPc());
976     }
977 #else
978     clone = targetGraph->CreateEmptyBlock();
979 #endif
980     clone->SetAllFields(this->GetAllFields());
981     clone->tryId_ = GetTryId();
982     if (this->IsStartBlock()) {
983         targetGraph->SetStartBlock(clone);
984     } else if (this->IsEndBlock()) {
985         targetGraph->SetEndBlock(clone);
986     }
987     return clone;
988 }
989 
GetFistThrowableInst() const990 Inst *BasicBlock::GetFistThrowableInst() const
991 {
992     if (!IsTry()) {
993         return nullptr;
994     }
995     for (auto inst : AllInsts()) {
996         if (GetGraph()->IsInstThrowable(inst)) {
997             return inst;
998         }
999     }
1000     return nullptr;
1001 }
1002 
FindSaveStateDeoptimize() const1003 Inst *BasicBlock::FindSaveStateDeoptimize() const
1004 {
1005     for (auto inst : InstsReverse()) {
1006         if (inst->GetOpcode() == Opcode::SaveStateDeoptimize) {
1007             return inst;
1008         }
1009     }
1010     return nullptr;
1011 }
1012 
InvalidateLoopIfIrreducible()1013 void BasicBlock::InvalidateLoopIfIrreducible()
1014 {
1015     auto loop = GetLoop();
1016     ASSERT(loop != nullptr);
1017     if (loop->IsIrreducible()) {
1018         GetGraph()->InvalidateAnalysis<LoopAnalyzer>();
1019     }
1020 }
1021 
CountInsts() const1022 uint32_t BasicBlock::CountInsts() const
1023 {
1024     uint32_t count = 0;
1025     for ([[maybe_unused]] auto inst : AllInsts()) {
1026         count++;
1027     }
1028     return count;
1029 }
1030 
BlocksPathDfsSearch(Marker marker,BasicBlock * block,const BasicBlock * targetBlock,const BasicBlock * excludeBlock)1031 bool BlocksPathDfsSearch(Marker marker, BasicBlock *block, const BasicBlock *targetBlock,
1032                          const BasicBlock *excludeBlock)
1033 {
1034     ASSERT(marker != UNDEF_MARKER);
1035     if (block == targetBlock) {
1036         return true;
1037     }
1038     block->SetMarker(marker);
1039 
1040     for (auto succBlock : block->GetSuccsBlocks()) {
1041         if (!succBlock->IsMarked(marker) && succBlock != excludeBlock) {
1042             if (BlocksPathDfsSearch(marker, succBlock, targetBlock, excludeBlock)) {
1043                 return true;
1044             }
1045         }
1046     }
1047     return false;
1048 }
1049 }  // namespace panda::compiler
1050