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 #ifndef COMPILER_OPTIMIZER_IR_BASICBLOCK_H 17 #define COMPILER_OPTIMIZER_IR_BASICBLOCK_H 18 19 #include "constants.h" 20 #include "inst.h" 21 #include "marker.h" 22 #include "macros.h" 23 #include <iterator> 24 25 namespace panda::compiler { 26 class Graph; 27 class Loop; 28 29 enum class IterationType : uint8_t { 30 PHI, 31 INST, 32 ALL, 33 }; 34 35 enum class IterationDirection : uint8_t { 36 FORWARD, 37 BACKWARD, 38 }; 39 40 template <const IterationType T> 41 class InstForwardIterator; 42 template <const IterationType T> 43 class InstBackwardIterator; 44 template <const IterationType T, const IterationDirection D> 45 class InstSafeIterator; 46 47 using PhiInstIter = InstForwardIterator<IterationType::PHI>; 48 using InstIter = InstForwardIterator<IterationType::INST>; 49 using AllInstIter = InstForwardIterator<IterationType::ALL>; 50 51 using InstReverseIter = InstBackwardIterator<IterationType::INST>; 52 53 using PhiInstSafeIter = InstSafeIterator<IterationType::PHI, IterationDirection::FORWARD>; 54 using InstSafeIter = InstSafeIterator<IterationType::INST, IterationDirection::FORWARD>; 55 using AllInstSafeIter = InstSafeIterator<IterationType::ALL, IterationDirection::FORWARD>; 56 57 using PhiInstSafeReverseIter = InstSafeIterator<IterationType::PHI, IterationDirection::BACKWARD>; 58 using InstSafeReverseIter = InstSafeIterator<IterationType::INST, IterationDirection::BACKWARD>; 59 using AllInstSafeReverseIter = InstSafeIterator<IterationType::ALL, IterationDirection::BACKWARD>; 60 61 class BasicBlock : public MarkerSet { // , public ArenaObject<ARENA_ALLOC_BASIC_BLOCK> 62 public: 63 static constexpr size_t TRUE_SUCC_IDX = 0; 64 static constexpr size_t FALSE_SUCC_IDX = 1; 65 explicit BasicBlock(Graph *graph, uint32_t guestPc = INVALID_PC); 66 67 public: SetId(uint32_t id)68 void SetId(uint32_t id) 69 { 70 bbId_ = id; 71 } GetId()72 uint32_t GetId() const 73 { 74 return bbId_; 75 } 76 GetPredsBlocks()77 ArenaVector<BasicBlock *> &GetPredsBlocks() 78 { 79 return preds_; 80 } GetPredsBlocks()81 const ArenaVector<BasicBlock *> &GetPredsBlocks() const 82 { 83 return preds_; 84 } 85 GetSuccsBlocks()86 ArenaVector<BasicBlock *> &GetSuccsBlocks() 87 { 88 return succs_; 89 } GetSuccsBlocks()90 const ArenaVector<BasicBlock *> &GetSuccsBlocks() const 91 { 92 return succs_; 93 } 94 GetSuccessor(size_t index)95 BasicBlock *GetSuccessor(size_t index) const 96 { 97 ASSERT(index < succs_.size()); 98 return succs_[index]; 99 } 100 GetPredecessor(size_t index)101 BasicBlock *GetPredecessor(size_t index) const 102 { 103 ASSERT(index < preds_.size()); 104 return preds_[index]; 105 } 106 107 template <bool INVERT = false> SwapTrueFalseSuccessors()108 void SwapTrueFalseSuccessors() 109 { 110 ASSERT(succs_.size() > 1); 111 std::swap(succs_[TRUE_SUCC_IDX], succs_[FALSE_SUCC_IDX]); 112 if constexpr (INVERT) { // NOLINT(readability-braces-around-statements,bugprone-suspicious-semicolon) 113 inverted_ = !inverted_; 114 } 115 // If both succs are irruducible loop entrypoints, swapping can invalidate that loop header, since it's not 116 // determined 117 succs_[TRUE_SUCC_IDX]->InvalidateLoopIfIrreducible(); 118 succs_[FALSE_SUCC_IDX]->InvalidateLoopIfIrreducible(); 119 } 120 IsInverted()121 bool IsInverted() const 122 { 123 return inverted_; 124 } 125 GetTrueSuccessor()126 BasicBlock *GetTrueSuccessor() const 127 { 128 ASSERT(!succs_.empty()); 129 return succs_[TRUE_SUCC_IDX]; 130 } 131 GetFalseSuccessor()132 BasicBlock *GetFalseSuccessor() const 133 { 134 ASSERT(succs_.size() > 1); 135 return succs_[FALSE_SUCC_IDX]; 136 } 137 138 // Get index of the given block in predecessor container GetPredBlockIndex(const BasicBlock * block)139 size_t GetPredBlockIndex(const BasicBlock *block) const 140 { 141 auto it = std::find(preds_.begin(), preds_.end(), block); 142 ASSERT(it != preds_.end()); 143 ASSERT(std::find(it + 1, preds_.end(), block) == preds_.end()); 144 return std::distance(preds_.begin(), it); 145 } 146 147 // Get index of the given block in successor container GetSuccBlockIndex(const BasicBlock * block)148 size_t GetSuccBlockIndex(const BasicBlock *block) const 149 { 150 auto it = std::find(succs_.begin(), succs_.end(), block); 151 ASSERT(it != succs_.end()); 152 ASSERT(std::find(it + 1, succs_.end(), block) == succs_.end()); 153 return std::distance(succs_.begin(), it); 154 } 155 156 // Get basic block by its index in predecessors container GetPredBlockByIndex(size_t index)157 BasicBlock *GetPredBlockByIndex(size_t index) const 158 { 159 ASSERT(index < preds_.size()); 160 return preds_[index]; 161 } 162 163 bool IsStartBlock() const; 164 bool IsEndBlock() const; 165 bool IsPseudoControlFlowBlock() const; 166 GetGraph()167 Graph *GetGraph() 168 { 169 return graph_; 170 } GetGraph()171 const Graph *GetGraph() const 172 { 173 return graph_; 174 } SetGraph(Graph * graph)175 void SetGraph(Graph *graph) 176 { 177 graph_ = graph; 178 } 179 SetGuestPc(uint32_t guestPc)180 void SetGuestPc(uint32_t guestPc) 181 { 182 guestPc_ = guestPc; 183 } GetGuestPc()184 uint32_t GetGuestPc() const 185 { 186 return guestPc_; 187 } 188 189 /** 190 * Split block after the given instruction. Current block will contain instructions before the splitting line and 191 * the created block - after. 192 * @param inst instruction after which block will be split 193 * @param make_edge whether to make control flow edge from first block to the second one 194 * @return return created basic block 195 */ 196 BasicBlock *SplitBlockAfterInstruction(Inst *inst, bool makeEdge); 197 198 // Add successor in the list 199 void AddSucc(BasicBlock *succ, bool canAddEmptyBlock = false); 200 HasSucc(BasicBlock * succ)201 bool HasSucc(BasicBlock *succ) 202 { 203 return std::find(succs_.begin(), succs_.end(), succ) != succs_.end(); 204 } 205 ReplacePred(BasicBlock * prevPred,BasicBlock * newPred)206 void ReplacePred(BasicBlock *prevPred, BasicBlock *newPred) 207 { 208 preds_[GetPredBlockIndex(prevPred)] = newPred; 209 newPred->succs_.push_back(this); 210 } 211 212 void ReplaceSucc(const BasicBlock *prevSucc, BasicBlock *newSucc, bool canAddEmptyBlock = false); 213 ReplaceTrueSuccessor(BasicBlock * newSucc)214 void ReplaceTrueSuccessor(BasicBlock *newSucc) 215 { 216 ASSERT(!succs_.empty()); 217 succs_[TRUE_SUCC_IDX] = newSucc; 218 newSucc->preds_.push_back(this); 219 } 220 ReplaceFalseSuccessor(BasicBlock * newSucc)221 void ReplaceFalseSuccessor(BasicBlock *newSucc) 222 { 223 ASSERT(succs_.size() > 1); 224 succs_[FALSE_SUCC_IDX] = newSucc; 225 newSucc->preds_.push_back(this); 226 } 227 228 BasicBlock *InsertNewBlockToSuccEdge(BasicBlock *succ); 229 BasicBlock *InsertEmptyBlockBefore(); 230 231 void InsertBlockBeforeSucc(BasicBlock *block, BasicBlock *succ); 232 233 // Remove empty block with one successor 234 void RemoveEmptyBlock(bool irrLoop = false); 235 void RemoveFixLoopInfo(); 236 237 // Join single successor into single predecessor 238 void JoinSuccessorBlock(); 239 void ReplaceSuccessorLoopBackEdges(Loop *loop, BasicBlock *succ); 240 241 // Join successor block into the block, which have another successor; 242 // Used in if-conversion pass and fixes dataflow using Select instructions. 243 void JoinBlocksUsingSelect(BasicBlock *succ, BasicBlock *selectBb, bool swapped); 244 245 // Add instruction to the end or begin of the BasicBlock 246 template <bool TO_END> 247 void AddInst(Inst *inst); 248 // Insert new instruction(NOT PHI) in BasicBlock at the start of instructions PrependInst(Inst * inst)249 void PrependInst(Inst *inst) 250 { 251 AddInst<false>(inst); 252 } 253 // Insert new instruction(NOT PHI) in BasicBlock at the end of instructions AppendInst(Inst * inst)254 void AppendInst(Inst *inst) 255 { 256 AddInst<true>(inst); 257 } AppendInsts(std::initializer_list<Inst * > && insts)258 void AppendInsts(std::initializer_list<Inst *> &&insts) 259 { 260 for (auto inst : insts) { 261 AddInst<true>(inst); 262 } 263 } 264 // Append range of instructions(NOT PHI) in BasicBlock at the end of instructions 265 // It is implied that for instructions within range was already called correctly SetBasicBlock() and 266 // range_last should dominate range_first. 267 void AppendRangeInst(Inst *rangeFirst, Inst *rangeLast); 268 // Insert new PHI instruction in BasicBlock at the end of PHI instructions 269 void AppendPhi(Inst *inst); 270 // Insert instruction after given instruction 271 void InsertAfter(Inst *inst, Inst *after); 272 // Insert instruction before given instruction 273 void InsertBefore(Inst *inst, Inst *before); 274 // Insert range of instructions before given instruction. 275 // It is implied that for instructions within range was already called correctly SetBasicBlock() and 276 // range_last should dominate range_first. 277 void InsertRangeBefore(Inst *rangeFirst, Inst *rangeLast, Inst *before); 278 // Remove instruction from instructions chain. All other data keep unmodified. 279 void EraseInst(Inst *inst, [[maybe_unused]] bool willBeMoved = false); 280 // Remove instructions from instructions chain, remove its inputs and check that it hasn't users. 281 void RemoveInst(Inst *inst); 282 // Replace old_inst in BasicBlock to new_inst 283 void ReplaceInst(Inst *oldInst, Inst *newInst); 284 // Replace inst by deoptimization 285 void ReplaceInstByDeoptimize(Inst *inst); 286 // Replace inst with overflow check on corresponding inst (e.g. AddOverflowCheck -> Add) 287 void RemoveOverflowCheck(Inst *inst); 288 // Remove all instructions from bb 289 void Clear(); 290 GetLastInst()291 Inst *GetLastInst() const 292 { 293 return lastInst_; 294 } 295 IsEndWithThrowOrDeoptimize()296 bool IsEndWithThrowOrDeoptimize() const 297 { 298 if (lastInst_ == nullptr) { 299 return false; 300 } 301 return lastInst_->IsControlFlow() && lastInst_->CanThrow() && lastInst_->IsTerminator(); 302 } 303 GetFirstInst()304 Inst *GetFirstInst() const 305 { 306 return firstInst_; 307 } 308 GetFirstPhi()309 Inst *GetFirstPhi() const 310 { 311 return firstPhi_; 312 } 313 IsEmpty()314 bool IsEmpty() const 315 { 316 return firstInst_ == nullptr; 317 } 318 HasPhi()319 bool HasPhi() const 320 { 321 return firstPhi_ != nullptr; 322 } 323 SetDominator(BasicBlock * dominator)324 void SetDominator(BasicBlock *dominator) 325 { 326 dominator_ = dominator; 327 } ClearDominator()328 void ClearDominator() 329 { 330 dominator_ = nullptr; 331 } 332 333 BasicBlock *CreateImmediateDominator(); 334 AddDominatedBlock(BasicBlock * block)335 void AddDominatedBlock(BasicBlock *block) 336 { 337 domBlocks_.push_back(block); 338 } RemoveDominatedBlock(BasicBlock * block)339 void RemoveDominatedBlock(BasicBlock *block) 340 { 341 domBlocks_.erase(std::find(domBlocks_.begin(), domBlocks_.end(), block)); 342 } ClearDominatedBlocks()343 void ClearDominatedBlocks() 344 { 345 domBlocks_.clear(); 346 } 347 348 BasicBlock *GetDominator() const; 349 const ArenaVector<BasicBlock *> &GetDominatedBlocks() const; 350 bool IsDominate(const BasicBlock *other) const; 351 RemovePred(const BasicBlock * pred)352 void RemovePred(const BasicBlock *pred) 353 { 354 ASSERT(GetPredBlockIndex(pred) < preds_.size()); 355 preds_[GetPredBlockIndex(pred)] = preds_.back(); 356 preds_.pop_back(); 357 } 358 RemovePred(size_t index)359 void RemovePred(size_t index) 360 { 361 ASSERT(index < preds_.size()); 362 preds_[index] = preds_.back(); 363 preds_.pop_back(); 364 } 365 RemoveSucc(BasicBlock * succ)366 void RemoveSucc(BasicBlock *succ) 367 { 368 auto it = std::find(succs_.begin(), succs_.end(), succ); 369 ASSERT(it != succs_.end()); 370 succs_.erase(it); 371 } 372 373 void Dump(std::ostream *out) const; 374 GetLoop()375 Loop *GetLoop() const 376 { 377 return loop_; 378 } SetLoop(Loop * loop)379 void SetLoop(Loop *loop) 380 { 381 loop_ = loop; 382 } IsLoopValid()383 bool IsLoopValid() const 384 { 385 return GetLoop() != nullptr; 386 } 387 bool IsLoopHeader() const; 388 SetNextLoop(Loop * loop)389 void SetNextLoop(Loop *loop) 390 { 391 nextLoop_ = loop; 392 } GetNextLoop()393 Loop *GetNextLoop() 394 { 395 return nextLoop_; 396 } IsLoopPreHeader()397 bool IsLoopPreHeader() const 398 { 399 return (nextLoop_ != nullptr); 400 } 401 402 void InsertBlockBefore(BasicBlock *block); 403 404 template <typename Accessor> GetField()405 typename Accessor::ValueType GetField() const 406 { 407 return Accessor::Get(bitFields_); 408 } 409 410 template <typename Accessor> SetField(typename Accessor::ValueType value)411 void SetField(typename Accessor::ValueType value) 412 { 413 Accessor::Set(value, &bitFields_); 414 } 415 SetAllFields(uint32_t bitFields)416 void SetAllFields(uint32_t bitFields) 417 { 418 bitFields_ = bitFields; 419 } 420 GetAllFields()421 uint32_t GetAllFields() const 422 { 423 return bitFields_; 424 } 425 SetMonitorEntryBlock(bool v)426 void SetMonitorEntryBlock(bool v) 427 { 428 SetField<MonitorEntryBlock>(v); 429 } 430 GetMonitorEntryBlock()431 bool GetMonitorEntryBlock() 432 { 433 return GetField<MonitorEntryBlock>(); 434 } 435 SetMonitorExitBlock(bool v)436 void SetMonitorExitBlock(bool v) 437 { 438 SetField<MonitorExitBlock>(v); 439 } 440 GetMonitorExitBlock()441 bool GetMonitorExitBlock() const 442 { 443 return GetField<MonitorExitBlock>(); 444 } 445 SetMonitorBlock(bool v)446 void SetMonitorBlock(bool v) 447 { 448 SetField<MonitorBlock>(v); 449 } 450 GetMonitorBlock()451 bool GetMonitorBlock() const 452 { 453 return GetField<MonitorBlock>(); 454 } 455 SetCatch(bool v)456 void SetCatch(bool v) 457 { 458 SetField<CatchBlock>(v); 459 } 460 IsCatch()461 bool IsCatch() const 462 { 463 return GetField<CatchBlock>(); 464 } 465 SetCatchBegin(bool v)466 void SetCatchBegin(bool v) 467 { 468 SetField<CatchBeginBlock>(v); 469 } 470 IsCatchBegin()471 bool IsCatchBegin() const 472 { 473 return GetField<CatchBeginBlock>(); 474 } 475 SetCatchEnd(bool v)476 void SetCatchEnd(bool v) 477 { 478 SetField<CatchEndBlock>(v); 479 } 480 IsCatchEnd()481 bool IsCatchEnd() const 482 { 483 return GetField<CatchEndBlock>(); 484 } 485 SetTry(bool v)486 void SetTry(bool v) 487 { 488 SetField<TryBlock>(v); 489 } 490 IsTry()491 bool IsTry() const 492 { 493 return GetField<TryBlock>(); 494 } 495 SetTryBegin(bool v)496 void SetTryBegin(bool v) 497 { 498 SetField<TryBeginBlock>(v); 499 } 500 IsTryBegin()501 bool IsTryBegin() const 502 { 503 return GetField<TryBeginBlock>(); 504 } 505 SetTryEnd(bool v)506 void SetTryEnd(bool v) 507 { 508 SetField<TryEndBlock>(v); 509 } 510 IsTryEnd()511 bool IsTryEnd() const 512 { 513 return GetField<TryEndBlock>(); 514 } 515 SetOsrEntry(bool v)516 void SetOsrEntry(bool v) 517 { 518 SetField<OsrEntry>(v); 519 } 520 IsOsrEntry()521 bool IsOsrEntry() const 522 { 523 return GetField<OsrEntry>(); 524 } 525 CopyTryCatchProps(BasicBlock * block)526 void CopyTryCatchProps(BasicBlock *block) 527 { 528 if (block->IsTry()) { 529 SetTry(true); 530 SetTryId(block->GetTryId()); 531 } 532 if (block->IsCatch()) { 533 SetCatch(true); 534 } 535 } 536 GetTryId()537 uint32_t GetTryId() const 538 { 539 return tryId_; 540 } 541 SetTryId(uint32_t tryId)542 void SetTryId(uint32_t tryId) 543 { 544 tryId_ = tryId; 545 } 546 547 template <class Callback> EnumerateCatchHandlers(const Callback & callback)548 void EnumerateCatchHandlers(const Callback &callback) const 549 { 550 ASSERT(this->IsTryBegin()); 551 auto tryInst = GetTryBeginInst(this); 552 auto typeIds = tryInst->GetCatchTypeIds(); 553 auto catchIndexes = tryInst->GetCatchEdgeIndexes(); 554 ASSERT(typeIds != nullptr && catchIndexes != nullptr); 555 for (size_t idx = 0; idx < typeIds->size(); idx++) { 556 auto succ = GetSuccessor(catchIndexes->at(idx)); 557 while (!succ->IsCatchBegin()) { 558 ASSERT(succ->GetSuccsBlocks().size() == 1); 559 succ = succ->GetSuccessor(0); 560 } 561 ASSERT(succ != nullptr); 562 if (!callback(succ, typeIds->at(idx))) { 563 break; 564 } 565 } 566 } 567 568 BasicBlock *Clone(Graph *targetGraph) const; 569 SetNeedsJump(bool v)570 void SetNeedsJump(bool v) 571 { 572 SetField<JumpFlag>(v); 573 } 574 NeedsJump()575 bool NeedsJump() const 576 { 577 return GetField<JumpFlag>(); 578 } 579 IsIfBlock()580 bool IsIfBlock() const 581 { 582 if (lastInst_ != nullptr) { 583 if (lastInst_->GetOpcode() == Opcode::If || lastInst_->GetOpcode() == Opcode::IfImm) { 584 return true; 585 } 586 } 587 return false; 588 } 589 590 Inst *GetFistThrowableInst() const; 591 Inst *FindSaveStateDeoptimize() const; 592 593 void InvalidateLoopIfIrreducible(); 594 595 // Member functions to iterate instructions. `Safe` means that you can delete instructions when iterating 596 PhiInstIter PhiInsts() const; 597 InstIter Insts() const; 598 AllInstIter AllInsts() const; 599 600 InstReverseIter InstsReverse() const; 601 602 PhiInstSafeIter PhiInstsSafe() const; 603 InstSafeIter InstsSafe() const; 604 AllInstSafeIter AllInstsSafe() const; 605 606 PhiInstSafeReverseIter PhiInstsSafeReverse() const; 607 InstSafeReverseIter InstsSafeReverse() const; 608 AllInstSafeReverseIter AllInstsSafeReverse() const; 609 610 uint32_t CountInsts() const; 611 612 private: 613 using MonitorEntryBlock = BitField<bool, 0>; // block with MonitorEntry 614 using MonitorExitBlock = MonitorEntryBlock::NextFlag; // block with MonitorExit 615 using MonitorBlock = MonitorExitBlock::NextFlag; // block between MonitorEntryBlock and MonitorExitBlock. 616 using CatchBeginBlock = MonitorBlock::NextFlag; 617 using CatchEndBlock = CatchBeginBlock::NextFlag; 618 using CatchBlock = CatchEndBlock::NextFlag; 619 using TryBeginBlock = CatchBlock::NextFlag; 620 using TryEndBlock = TryBeginBlock::NextFlag; 621 using TryBlock = TryEndBlock::NextFlag; 622 using OsrEntry = TryBlock::NextFlag; 623 using JumpFlag = OsrEntry::NextFlag; // signals that Codegen should insert a jump to the successor 624 using LastField = JumpFlag; 625 626 struct SavedIfInfo { 627 BasicBlock *succ; 628 bool swapped; 629 uint64_t ifImm; 630 ConditionCode ifCc; 631 DataType::Type ifType; 632 uint32_t ifPc; 633 Opcode ifOpcode; 634 Inst *ifInput0; 635 Inst *ifInput1; 636 }; 637 638 void GenerateSelect(Inst *phi, Inst *inst1, Inst *inst2, const SavedIfInfo *ifInfo); 639 void GenerateSelects(const SavedIfInfo *ifInfo); 640 void SelectsFixLoopInfo(BasicBlock *selectBb, BasicBlock *other); 641 642 Graph *graph_; 643 644 // List of predessesor blocks. 645 ArenaVector<BasicBlock *> preds_; 646 647 // List of successors blocks. 648 ArenaVector<BasicBlock *> succs_; 649 650 // List of dominated blocks. 651 ArenaVector<BasicBlock *> domBlocks_; 652 653 // Dominator block 654 BasicBlock *dominator_ {nullptr}; 655 656 /// This value hold properties of the basic block. It accessed via BitField types. 657 uint32_t bitFields_ {0}; 658 659 // pc address from bytecode file 660 uint32_t guestPc_; 661 uint32_t bbId_ {INVALID_ID}; 662 663 Inst *firstPhi_ {nullptr}; 664 Inst *firstInst_ {nullptr}; 665 Inst *lastInst_ {nullptr}; 666 667 Loop *loop_ {nullptr}; 668 // Not nullptr if block is pre-header of next_loop_ 669 Loop *nextLoop_ {nullptr}; 670 671 uint32_t tryId_ {INVALID_ID}; 672 bool inverted_ {false}; 673 674 template <const IterationType T, const IterationDirection D> 675 friend class InstIterator; 676 template <const IterationType T> 677 friend class InstForwardIterator; 678 template <const IterationType T> 679 friend class InstBackwardIterator; 680 template <const IterationType T, const IterationDirection D> 681 friend class InstSafeIterator; 682 }; 683 684 /* 685 * Iterators inheritance-tree 686 * 687 * ValueObject 688 * | 689 * | 690 * |----> InstIterator<Type, Direction> [ add field Inst* current_ ] 691 * | 692 * | 693 * |----> InstForwardIterator<Type, Direction::FORWARD> 694 * | | 695 * | |----> InstForwardIterator<Type::PHI, Direction::FORWARD> 696 * | [ add field Inst* final_ ] 697 * | 698 * | 699 * |----> InstSafeIterator<Type, Direction> [ add field Inst* follower_ ] 700 * | 701 * |----> InstSafeIterator<Type::PHI, Direction::FORWARD> 702 * | [ add field Inst* final_ ] 703 * |----> InstSafeIterator<Type::INST, Direction::BACKWARD> 704 * [ add field Inst* final_ ] 705 */ 706 707 template <const IterationType T, const IterationDirection D> 708 class InstIterator { 709 public: 710 // NOLINTBEGIN(readability-identifier-naming) 711 using iterator_category = std::forward_iterator_tag; 712 using value_type = IterationType; 713 using difference_type = std::ptrdiff_t; 714 using pointer = value_type *; 715 using reference = value_type &; 716 // NOLINTEND(readability-identifier-naming) 717 718 const Inst *operator*() const 719 { 720 return current_; 721 } 722 Inst *operator*() 723 { 724 return current_; 725 } 726 GetCurrent()727 Inst *GetCurrent() const 728 { 729 return current_; 730 } 731 SetCurrent(Inst * current)732 void SetCurrent(Inst *current) 733 { 734 current_ = current; 735 } 736 737 protected: InstIterator(const BasicBlock & block,Inst * start)738 InstIterator(const BasicBlock &block, Inst *start) 739 { 740 #ifndef __clang_analyzer__ 741 if constexpr (IterationType::INST == T && IterationDirection::FORWARD == D) { 742 current_ = (start != nullptr) ? start : block.firstInst_; 743 return; 744 } 745 if constexpr (IterationType::ALL == T && IterationDirection::FORWARD == D) { 746 current_ = (block.firstPhi_ != nullptr) ? block.firstPhi_ : block.firstInst_; 747 current_ = (start != nullptr) ? start : current_; 748 return; 749 } 750 if constexpr (IterationType::PHI == T && IterationDirection::BACKWARD == D) { 751 current_ = (block.firstInst_ != nullptr) ? block.firstInst_->GetPrev() : block.lastInst_; 752 current_ = (start != nullptr) ? start : current_; 753 return; 754 } 755 if constexpr (IterationType::ALL == T && IterationDirection::BACKWARD == D) { 756 current_ = (start != nullptr) ? start : block.lastInst_; 757 return; 758 } 759 #else 760 [[maybe_unused]] auto const &tb = block; 761 [[maybe_unused]] auto ts = start; 762 #endif 763 UNREACHABLE(); 764 } InstIterator(Inst * current)765 explicit InstIterator(Inst *current) : current_(current) {}; 766 767 DEFAULT_COPY_SEMANTIC(InstIterator); 768 DEFAULT_MOVE_SEMANTIC(InstIterator); 769 virtual ~InstIterator() = default; 770 771 private: 772 Inst *current_ {nullptr}; 773 }; 774 775 /* 776 * Iterates over the instructions in direct order. 777 * Starts with the 'start' instruction if it's initialized 778 * or with the first phi/non-phi instruction in the basic block 779 */ 780 template <const IterationType T> 781 class InstForwardIterator : public InstIterator<T, IterationDirection::FORWARD> { 782 public: 783 explicit InstForwardIterator(const BasicBlock &block, Inst *start = nullptr) 784 : InstIterator<T, IterationDirection::FORWARD>(block, start) 785 { 786 } 787 788 public: 789 // NOLINTNEXTLINE(readability-identifier-naming) begin()790 InstForwardIterator begin() const 791 { 792 return InstForwardIterator(this->GetCurrent()); 793 } 794 // NOLINTNEXTLINE(readability-identifier-naming) end()795 InstForwardIterator end() const 796 { 797 return InstForwardIterator(nullptr); 798 } 799 InstForwardIterator &operator++() 800 { 801 this->SetCurrent(this->GetCurrent()->GetNext()); 802 return *this; 803 } 804 bool operator!=(const InstForwardIterator &other) const 805 { 806 return this->GetCurrent() != other.GetCurrent(); 807 } 808 bool operator==(const InstForwardIterator &other) const 809 { 810 return this->GetCurrent() == other.GetCurrent(); 811 } 812 813 protected: InstForwardIterator(Inst * current)814 explicit InstForwardIterator(Inst *current) : InstIterator<T, IterationDirection::FORWARD>(current) {}; 815 }; 816 817 /* 818 * Specialization for PHI instructions 819 */ 820 template <> 821 class InstForwardIterator<IterationType::PHI> : public InstForwardIterator<IterationType::INST> { 822 public: 823 explicit InstForwardIterator(const BasicBlock &block, Inst *start = nullptr) 824 : InstForwardIterator<IterationType::INST>(start != nullptr ? start : block.firstPhi_) 825 { 826 final_ = ((block.firstPhi_ != nullptr) && (block.firstInst_ != nullptr)) ? block.firstInst_ : nullptr; 827 } 828 829 public: 830 // NOLINTNEXTLINE(readability-identifier-naming) end()831 InstForwardIterator end() const 832 { 833 return InstForwardIterator(final_); 834 } 835 bool operator!=(const InstForwardIterator &other) const 836 { 837 return this->GetCurrent() != other.GetCurrent(); 838 } 839 bool operator==(const InstForwardIterator &other) const 840 { 841 return this->GetCurrent() == other.GetCurrent(); 842 } 843 844 private: InstForwardIterator(Inst * current)845 explicit InstForwardIterator(Inst *current) : InstForwardIterator<IterationType::INST>(current) {}; 846 847 private: 848 Inst *final_ {nullptr}; 849 }; 850 851 /* 852 * Iterates over the instructions in reverse order. 853 * Starts with the 'start' instruction if it's initialized 854 * or with the first phi/non-phi instruction in the basic block 855 */ 856 template <const IterationType T> 857 class InstBackwardIterator : public InstIterator<T, IterationDirection::BACKWARD> { 858 public: 859 explicit InstBackwardIterator(const BasicBlock &block, Inst *start = nullptr) 860 : InstIterator<T, IterationDirection::BACKWARD>(block, start) 861 { 862 } 863 864 public: 865 // NOLINTNEXTLINE(readability-identifier-naming) begin()866 InstBackwardIterator begin() const 867 { 868 return InstBackwardIterator(this->GetCurrent()); 869 } 870 // NOLINTNEXTLINE(readability-identifier-naming) end()871 InstBackwardIterator end() const 872 { 873 return InstBackwardIterator(nullptr); 874 } 875 InstBackwardIterator &operator++() 876 { 877 this->SetCurrent(this->GetCurrent()->GetPrev()); 878 return *this; 879 } 880 bool operator!=(const InstBackwardIterator &other) const 881 { 882 return this->GetCurrent() != other.GetCurrent(); 883 } 884 bool operator==(const InstBackwardIterator &other) const 885 { 886 return this->GetCurrent() == other.GetCurrent(); 887 } 888 889 protected: InstBackwardIterator(Inst * current)890 explicit InstBackwardIterator(Inst *current) : InstIterator<T, IterationDirection::BACKWARD>(current) {} 891 }; 892 893 /* 894 * Specialization for not-PHI instructions 895 */ 896 template <> 897 class InstBackwardIterator<IterationType::INST> : public InstBackwardIterator<IterationType::ALL> { 898 public: 899 explicit InstBackwardIterator(const BasicBlock &block, Inst *start = nullptr) 900 : InstBackwardIterator<IterationType::ALL>(nullptr) 901 { 902 auto lastInst = (block.firstInst_ != nullptr) ? block.lastInst_ : nullptr; 903 this->SetCurrent(start != nullptr ? start : lastInst); 904 final_ = (block.firstInst_ != nullptr) ? block.firstInst_->GetPrev() : nullptr; 905 } 906 907 public: 908 // NOLINTNEXTLINE(readability-identifier-naming) end()909 InstBackwardIterator end() const 910 { 911 return InstBackwardIterator(final_); 912 } 913 914 private: InstBackwardIterator(Inst * current)915 explicit InstBackwardIterator(Inst *current) : InstBackwardIterator<IterationType::ALL>(current) {} 916 917 private: 918 Inst *final_ {nullptr}; 919 }; 920 921 /* 922 * Iterates over the instructions in `IterationDirection` order, keeping next instruction in case of removing current 923 * instruction 924 */ 925 template <const IterationType T, const IterationDirection D> 926 class InstSafeIterator : public InstIterator<T, D> { 927 public: 928 explicit InstSafeIterator(const BasicBlock &block, Inst *start = nullptr) : InstIterator<T, D>(block, start) 929 { 930 follower_ = GetFollower(); 931 } 932 933 public: 934 // NOLINTNEXTLINE(readability-identifier-naming) begin()935 InstSafeIterator begin() const 936 { 937 return InstSafeIterator(this->GetCurrent(), follower_); 938 } 939 // NOLINTNEXTLINE(readability-identifier-naming) end()940 InstSafeIterator end() const 941 { 942 return InstSafeIterator(nullptr); 943 } 944 InstSafeIterator &operator++() 945 { 946 this->SetCurrent(follower_); 947 follower_ = GetFollower(); 948 return *this; 949 } 950 bool operator!=(const InstSafeIterator &other) const 951 { 952 return this->GetCurrent() != other.GetCurrent(); 953 } 954 bool operator==(const InstSafeIterator &other) const 955 { 956 return this->GetCurrent() == other.GetCurrent(); 957 } 958 959 protected: InstSafeIterator(Inst * current)960 explicit InstSafeIterator(Inst *current) : InstIterator<T, D>(current) {}; InstSafeIterator(Inst * current,Inst * follower)961 explicit InstSafeIterator(Inst *current, Inst *follower) : InstIterator<T, D>(current), follower_(follower) {}; 962 963 protected: GetFollower()964 Inst *GetFollower() 965 { 966 #ifndef __clang_analyzer__ 967 if constexpr (IterationDirection::FORWARD == D) { 968 return this->GetCurrent() == nullptr ? nullptr : this->GetCurrent()->GetNext(); 969 }; 970 if constexpr (IterationDirection::BACKWARD == D) { 971 return this->GetCurrent() == nullptr ? nullptr : this->GetCurrent()->GetPrev(); 972 }; 973 #endif 974 UNREACHABLE(); 975 return nullptr; 976 } 977 SetFollower(Inst * follower)978 void SetFollower(Inst *follower) 979 { 980 follower_ = follower; 981 } 982 983 private: 984 Inst *follower_ {nullptr}; 985 }; 986 987 /* 988 * Specialization for PHI instructions 989 */ 990 template <> 991 class InstSafeIterator<IterationType::PHI, IterationDirection::FORWARD> 992 : public InstSafeIterator<IterationType::INST, IterationDirection::FORWARD> { 993 public: 994 explicit InstSafeIterator(const BasicBlock &block, Inst *start = nullptr) 995 : InstSafeIterator<IterationType::INST, IterationDirection::FORWARD>(start != nullptr ? start : block.firstPhi_) 996 { 997 final_ = ((block.firstPhi_ != nullptr) && (block.firstInst_ != nullptr)) ? block.firstInst_ : nullptr; 998 this->SetFollower(GetFollower()); 999 } 1000 1001 public: 1002 // NOLINTNEXTLINE(readability-identifier-naming) end()1003 InstSafeIterator end() const 1004 { 1005 return InstSafeIterator(final_); 1006 } 1007 bool operator!=(const InstSafeIterator &other) const 1008 { 1009 return this->GetCurrent() != other.GetCurrent(); 1010 } 1011 bool operator==(const InstSafeIterator &other) const 1012 { 1013 return this->GetCurrent() == other.GetCurrent(); 1014 } 1015 1016 private: InstSafeIterator(Inst * current)1017 explicit InstSafeIterator(Inst *current) 1018 : InstSafeIterator<IterationType::INST, IterationDirection::FORWARD>(current) {}; 1019 1020 private: GetFollower()1021 Inst *GetFollower() 1022 { 1023 return this->GetCurrent() == final_ ? nullptr : this->GetCurrent()->GetNext(); 1024 } 1025 1026 private: 1027 Inst *final_ {nullptr}; 1028 }; 1029 1030 /* 1031 * Specialization for not-PHI instructions 1032 */ 1033 template <> 1034 class InstSafeIterator<IterationType::INST, IterationDirection::BACKWARD> 1035 : public InstSafeIterator<IterationType::ALL, IterationDirection::BACKWARD> { 1036 public: 1037 explicit InstSafeIterator(const BasicBlock &block, Inst *start = nullptr) 1038 : InstSafeIterator<IterationType::ALL, IterationDirection::BACKWARD>(nullptr) 1039 { 1040 auto lastInst = (block.firstInst_ != nullptr) ? block.lastInst_ : nullptr; 1041 this->SetCurrent(start != nullptr ? start : lastInst); 1042 final_ = (block.firstInst_ != nullptr) ? block.firstInst_->GetPrev() : nullptr; 1043 this->SetFollower(GetFollower()); 1044 } 1045 1046 public: 1047 // NOLINTNEXTLINE(readability-identifier-naming) end()1048 InstSafeIterator end() const 1049 { 1050 return InstSafeIterator(final_); 1051 } 1052 bool operator!=(const InstSafeIterator &other) const 1053 { 1054 return this->GetCurrent() != other.GetCurrent(); 1055 } 1056 bool operator==(const InstSafeIterator &other) const 1057 { 1058 return this->GetCurrent() == other.GetCurrent(); 1059 } 1060 1061 private: InstSafeIterator(Inst * current)1062 explicit InstSafeIterator(Inst *current) 1063 : InstSafeIterator<IterationType::ALL, IterationDirection::BACKWARD>(current) {}; 1064 1065 private: GetFollower()1066 Inst *GetFollower() 1067 { 1068 return this->GetCurrent() == final_ ? nullptr : this->GetCurrent()->GetPrev(); 1069 } 1070 1071 private: 1072 Inst *final_ {nullptr}; 1073 }; 1074 1075 /** 1076 * DFS-search to find path between `block` and `target_block`, 1077 * `exclude_block` can be set to search path without this block 1078 */ 1079 bool BlocksPathDfsSearch(Marker marker, BasicBlock *block, const BasicBlock *targetBlock, 1080 const BasicBlock *excludeBlock = nullptr); 1081 } // namespace panda::compiler 1082 #endif // COMPILER_OPTIMIZER_IR_BASICBLOCK_H 1083