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