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