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