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