1 /* 2 * Copyright (c) 2021-2024 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 ark::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 using SuccsVector = SmallVector<BasicBlock *, 2U, ArenaAllocatorT<false>, true>; 68 69 public: 70 void SetId(uint32_t id); 71 PANDA_PUBLIC_API uint32_t GetId() const; 72 73 PANDA_PUBLIC_API ArenaVector<BasicBlock *> &GetPredsBlocks(); 74 PANDA_PUBLIC_API const ArenaVector<BasicBlock *> &GetPredsBlocks() const; 75 76 PANDA_PUBLIC_API SuccsVector &GetSuccsBlocks(); 77 PANDA_PUBLIC_API const SuccsVector &GetSuccsBlocks() const; 78 79 PANDA_PUBLIC_API BasicBlock *GetSuccessor(size_t index) const; 80 PANDA_PUBLIC_API BasicBlock *GetPredecessor(size_t index) const; 81 82 template <bool INVERT = false> SwapTrueFalseSuccessors()83 void SwapTrueFalseSuccessors() 84 { 85 ASSERT(succs_.size() > 1); 86 std::swap(succs_[TRUE_SUCC_IDX], succs_[FALSE_SUCC_IDX]); 87 if constexpr (INVERT) { // NOLINT(readability-braces-around-statements,bugprone-suspicious-semicolon) 88 inverted_ = !inverted_; 89 } 90 // If both succs are irruducible loop entrypoints, swapping can invalidate that loop header, since it's not 91 // determined 92 succs_[TRUE_SUCC_IDX]->InvalidateLoopIfIrreducible(); 93 succs_[FALSE_SUCC_IDX]->InvalidateLoopIfIrreducible(); 94 } 95 96 bool IsInverted() const; 97 98 void SetHotness(int64_t hotness); 99 int64_t GetHotness() const; 100 101 PANDA_PUBLIC_API BasicBlock *GetTrueSuccessor() const; 102 PANDA_PUBLIC_API BasicBlock *GetFalseSuccessor() const; 103 104 // Get index of the given block in predecessor container 105 PANDA_PUBLIC_API size_t GetPredBlockIndex(const BasicBlock *block) const; 106 // Get index of the given block in successor container 107 PANDA_PUBLIC_API size_t GetSuccBlockIndex(const BasicBlock *block) const; 108 // Get basic block by its index in predecessors container 109 PANDA_PUBLIC_API BasicBlock *GetPredBlockByIndex(size_t index) const; 110 111 PANDA_PUBLIC_API bool IsStartBlock() const; 112 PANDA_PUBLIC_API bool IsEndBlock() const; 113 bool IsPseudoControlFlowBlock() const; 114 115 PANDA_PUBLIC_API Graph *GetGraph(); 116 PANDA_PUBLIC_API const Graph *GetGraph() const; 117 void SetGraph(Graph *graph); 118 119 PANDA_PUBLIC_API void SetGuestPc(uint32_t guestPc); 120 PANDA_PUBLIC_API uint32_t GetGuestPc() const; 121 122 /** 123 * Split block after the given instruction. Current block will contain instructions before the splitting line and 124 * the created block - after. 125 * @param inst instruction after which block will be split 126 * @param make_edge whether to make control flow edge from first block to the second one 127 * @return return created basic block 128 */ 129 PANDA_PUBLIC_API BasicBlock *SplitBlockAfterInstruction(Inst *inst, bool makeEdge); 130 131 // Add successor in the list 132 PANDA_PUBLIC_API void AddSucc(BasicBlock *succ, bool canAddEmptyBlock = false); 133 PANDA_PUBLIC_API bool HasSucc(BasicBlock *succ); 134 135 void ReplacePred(BasicBlock *prevPred, BasicBlock *newPred); 136 PANDA_PUBLIC_API void ReplaceSucc(const BasicBlock *prevSucc, BasicBlock *newSucc, bool canAddEmptyBlock = false); 137 void ReplaceTrueSuccessor(BasicBlock *newSucc); 138 void ReplaceFalseSuccessor(BasicBlock *newSucc); 139 140 BasicBlock *InsertNewBlockToSuccEdge(BasicBlock *succ); 141 BasicBlock *InsertEmptyBlockBefore(); 142 143 PANDA_PUBLIC_API void InsertBlockBeforeSucc(BasicBlock *block, BasicBlock *succ); 144 145 // Remove empty block with one successor 146 void RemoveEmptyBlock(bool irrLoop = false); 147 void RemoveFixLoopInfo(); 148 149 // Join single successor into single predecessor 150 void JoinSuccessorBlock(); 151 void ReplaceSuccessorLoopBackEdges(Loop *loop, BasicBlock *succ); 152 153 // Join successor block into the block, which have another successor; 154 // Used in if-conversion pass and fixes dataflow using Select instructions. 155 void JoinBlocksUsingSelect(BasicBlock *succ, BasicBlock *selectBb, bool swapped); 156 157 // Add instruction to the end or begin of the BasicBlock 158 template <bool TO_END> 159 void AddInst(Inst *inst); 160 // Insert new instruction(NOT PHI) in BasicBlock at the start of instructions 161 PANDA_PUBLIC_API void PrependInst(Inst *inst); 162 // Insert new instruction(NOT PHI) in BasicBlock at the end of instructions 163 PANDA_PUBLIC_API void AppendInst(Inst *inst); 164 void AppendInsts(std::initializer_list<Inst *> &&insts); 165 // Append range of instructions(NOT PHI) in BasicBlock at the end of instructions 166 // It is implied that for instructions within range was already called correctly SetBasicBlock() and 167 // range_last should dominate range_first. 168 void AppendRangeInst(Inst *rangeFirst, Inst *rangeLast); 169 // Insert new PHI instruction in BasicBlock at the end of PHI instructions 170 PANDA_PUBLIC_API void AppendPhi(Inst *inst); 171 // Insert instruction after given instruction 172 PANDA_PUBLIC_API void InsertAfter(Inst *inst, Inst *after); 173 // Insert instruction before given instruction 174 PANDA_PUBLIC_API void InsertBefore(Inst *inst, Inst *before); 175 // Insert range of instructions before given instruction. 176 // It is implied that for instructions within range was already called correctly SetBasicBlock() and 177 // range_last should dominate range_first. 178 void InsertRangeBefore(Inst *rangeFirst, Inst *rangeLast, Inst *before); 179 // Remove instruction from instructions chain. All other data keep unmodified. 180 PANDA_PUBLIC_API void EraseInst(Inst *inst, [[maybe_unused]] bool willBeMoved = false); 181 // Remove instructions from instructions chain, remove its inputs and check that it hasn't users. 182 PANDA_PUBLIC_API void RemoveInst(Inst *inst); 183 // Replace old_inst in BasicBlock to new_inst 184 PANDA_PUBLIC_API void ReplaceInst(Inst *oldInst, Inst *newInst); 185 // Replace inst by deoptimization 186 void ReplaceInstByDeoptimize(Inst *inst); 187 // Replace inst with overflow check on corresponding inst (e.g. AddOverflowCheck -> Add) 188 void RemoveOverflowCheck(Inst *inst); 189 // Remove all instructions from bb 190 191 bool IsEndWithThrowOrDeoptimize() const; 192 bool IsEndWithThrow() const; 193 PANDA_PUBLIC_API Inst *GetFirstInst() const; 194 PANDA_PUBLIC_API Inst *GetLastInst() const; 195 PANDA_PUBLIC_API Inst *GetFirstPhi() const; 196 197 PANDA_PUBLIC_API void Clear(); 198 PANDA_PUBLIC_API bool IsEmpty() const; 199 PANDA_PUBLIC_API bool HasPhi() const; 200 201 void SetDominator(BasicBlock *dominator); 202 void ClearDominator(); 203 204 BasicBlock *CreateImmediateDominator(); 205 206 void AddDominatedBlock(BasicBlock *block); 207 void RemoveDominatedBlock(BasicBlock *block); 208 void ClearDominatedBlocks(); 209 210 PANDA_PUBLIC_API BasicBlock *GetDominator() const; 211 PANDA_PUBLIC_API const ArenaVector<BasicBlock *> &GetDominatedBlocks() const; 212 PANDA_PUBLIC_API bool IsDominate(const BasicBlock *other) const; 213 214 PANDA_PUBLIC_API void RemovePred(const BasicBlock *pred); 215 PANDA_PUBLIC_API void RemovePred(size_t index); 216 PANDA_PUBLIC_API void RemoveSucc(BasicBlock *succ); 217 218 PANDA_PUBLIC_API void Dump(std::ostream *out) const; 219 220 PANDA_PUBLIC_API Loop *GetLoop() const; 221 void SetLoop(Loop *loop); 222 bool IsLoopValid() const; 223 PANDA_PUBLIC_API bool IsLoopHeader() const; 224 bool IsLoopPostExit() const; 225 bool IsTryCatch() const; 226 227 void SetNextLoop(Loop *loop); 228 Loop *GetNextLoop() const; 229 PANDA_PUBLIC_API bool IsLoopPreHeader() const; 230 PANDA_PUBLIC_API void InsertBlockBefore(BasicBlock *block); 231 232 template <typename Accessor> GetField()233 typename Accessor::ValueType GetField() const 234 { 235 return Accessor::Get(bitFields_); 236 } 237 238 template <typename Accessor> SetField(typename Accessor::ValueType value)239 void SetField(typename Accessor::ValueType value) 240 { 241 Accessor::Set(value, &bitFields_); 242 } 243 244 void SetAllFields(uint32_t bitFields); 245 uint32_t GetAllFields() const; 246 void SetMonitorEntryBlock(bool v); 247 bool GetMonitorEntryBlock(); 248 249 void SetMonitorExitBlock(bool v); 250 bool GetMonitorExitBlock() const; 251 252 void SetMonitorBlock(bool v); 253 bool GetMonitorBlock() const; 254 255 PANDA_PUBLIC_API void SetCatch(bool v); 256 PANDA_PUBLIC_API bool IsCatch() const; 257 258 PANDA_PUBLIC_API void SetCatchBegin(bool v); 259 PANDA_PUBLIC_API bool IsCatchBegin() const; 260 261 PANDA_PUBLIC_API void SetTry(bool v); 262 PANDA_PUBLIC_API bool IsTry() const; 263 264 PANDA_PUBLIC_API void SetTryBegin(bool v); 265 PANDA_PUBLIC_API bool IsTryBegin() const; 266 267 PANDA_PUBLIC_API void SetTryEnd(bool v); 268 PANDA_PUBLIC_API bool IsTryEnd() const; 269 270 void SetOsrEntry(bool v); 271 bool IsOsrEntry() const; 272 273 void CopyTryCatchProps(BasicBlock *block); 274 275 PANDA_PUBLIC_API uint32_t GetTryId() const; 276 PANDA_PUBLIC_API void SetTryId(uint32_t tryId); 277 278 template <class Callback> EnumerateCatchHandlers(const Callback & callback)279 void EnumerateCatchHandlers(const Callback &callback) const 280 { 281 ASSERT(this->IsTryBegin()); 282 auto tryInst = GetTryBeginInst(this); 283 auto typeIds = tryInst->GetCatchTypeIds(); 284 auto catchIndexes = tryInst->GetCatchEdgeIndexes(); 285 ASSERT(typeIds != nullptr && catchIndexes != nullptr); 286 for (size_t idx = 0; idx < typeIds->size(); idx++) { 287 auto succ = GetSuccessor(catchIndexes->at(idx)); 288 while (!succ->IsCatchBegin()) { 289 ASSERT(succ->GetSuccsBlocks().size() == 1); 290 succ = succ->GetSuccessor(0); 291 } 292 ASSERT(succ != nullptr); 293 if (!callback(succ, typeIds->at(idx))) { 294 break; 295 } 296 } 297 } 298 299 BasicBlock *Clone(Graph *targetGraph) const; 300 301 void SetNeedsJump(bool v); 302 PANDA_PUBLIC_API bool NeedsJump() const; 303 bool IsIfBlock() const; 304 305 Inst *GetFistThrowableInst() const; 306 Inst *FindSaveStateDeoptimize() const; 307 308 void InvalidateLoopIfIrreducible(); 309 310 // Member functions to iterate instructions. `Safe` means that you can delete instructions when iterating 311 PANDA_PUBLIC_API PhiInstIter PhiInsts() const; 312 PANDA_PUBLIC_API InstIter Insts() const; 313 PANDA_PUBLIC_API AllInstIter AllInsts() const; 314 315 InstReverseIter InstsReverse() const; 316 317 PANDA_PUBLIC_API PhiInstSafeIter PhiInstsSafe() const; 318 InstSafeIter InstsSafe() const; 319 PANDA_PUBLIC_API AllInstSafeIter AllInstsSafe() const; 320 321 PhiInstSafeReverseIter PhiInstsSafeReverse() const; 322 InstSafeReverseIter InstsSafeReverse() const; 323 AllInstSafeReverseIter AllInstsSafeReverse() const; 324 325 PANDA_PUBLIC_API uint32_t CountInsts() const; 326 327 private: 328 using MonitorEntryBlock = BitField<bool, 0>; // block with MonitorEntry 329 using MonitorExitBlock = MonitorEntryBlock::NextFlag; // block with MonitorExit 330 using MonitorBlock = MonitorExitBlock::NextFlag; // block between MonitorEntryBlock and MonitorExitBlock. 331 using CatchBeginBlock = MonitorBlock::NextFlag; 332 using CatchBlock = CatchBeginBlock::NextFlag; 333 using TryBeginBlock = CatchBlock::NextFlag; 334 using TryEndBlock = TryBeginBlock::NextFlag; 335 using TryBlock = TryEndBlock::NextFlag; 336 using OsrEntry = TryBlock::NextFlag; 337 using JumpFlag = OsrEntry::NextFlag; // signals that Codegen should insert a jump to the successor 338 using LastField = JumpFlag; 339 340 struct SavedIfInfo { 341 BasicBlock *succ; 342 bool swapped; 343 uint64_t ifImm; 344 ConditionCode ifCc; 345 DataType::Type ifType; 346 uint32_t ifPc; 347 Opcode ifOpcode; 348 Inst *ifInput0; 349 Inst *ifInput1; 350 }; 351 352 void GenerateSelect(Inst *phi, Inst *inst1, Inst *inst2, const SavedIfInfo *ifInfo); 353 void GenerateSelects(const SavedIfInfo *ifInfo); 354 void SelectsFixLoopInfo(BasicBlock *selectBb, BasicBlock *other); 355 356 Graph *graph_; 357 358 // List of predessesor blocks. 359 ArenaVector<BasicBlock *> preds_; 360 361 // List of successors blocks. 362 SuccsVector succs_; 363 364 // List of dominated blocks. 365 ArenaVector<BasicBlock *> domBlocks_; 366 367 // Dominator block 368 BasicBlock *dominator_ {nullptr}; 369 370 /// This value hold properties of the basic block. It accessed via BitField types. 371 uint32_t bitFields_ {0}; 372 373 // pc address from bytecode file 374 uint32_t guestPc_; 375 uint32_t bbId_ {INVALID_ID}; 376 377 Inst *firstPhi_ {nullptr}; 378 Inst *firstInst_ {nullptr}; 379 Inst *lastInst_ {nullptr}; 380 381 Loop *loop_ {nullptr}; 382 // Not nullptr if block is pre-header of next_loop_ 383 Loop *nextLoop_ {nullptr}; 384 385 uint32_t tryId_ {INVALID_ID}; 386 bool inverted_ {false}; 387 int64_t hotness_ {}; 388 389 template <const IterationType T, const IterationDirection D> 390 friend class InstIterator; 391 template <const IterationType T> 392 friend class InstForwardIterator; 393 template <const IterationType T> 394 friend class InstBackwardIterator; 395 template <const IterationType T, const IterationDirection D> 396 friend class InstSafeIterator; 397 }; 398 399 /* 400 * Iterators inheritance-tree 401 * 402 * ValueObject 403 * | 404 * | 405 * |----> InstIterator<Type, Direction> [ add field Inst* current_ ] 406 * | 407 * | 408 * |----> InstForwardIterator<Type, Direction::FORWARD> 409 * | | 410 * | |----> InstForwardIterator<Type::PHI, Direction::FORWARD> 411 * | [ add field Inst* final_ ] 412 * | 413 * | 414 * |----> InstSafeIterator<Type, Direction> [ add field Inst* follower_ ] 415 * | 416 * |----> InstSafeIterator<Type::PHI, Direction::FORWARD> 417 * | [ add field Inst* final_ ] 418 * |----> InstSafeIterator<Type::INST, Direction::BACKWARD> 419 * [ add field Inst* final_ ] 420 */ 421 422 template <const IterationType T, const IterationDirection D> 423 class InstIterator { 424 public: 425 // NOLINTBEGIN(readability-identifier-naming) 426 using iterator_category = std::forward_iterator_tag; 427 using value_type = IterationType; 428 using difference_type = std::ptrdiff_t; 429 using pointer = value_type *; 430 using reference = value_type &; 431 // NOLINTEND(readability-identifier-naming) 432 433 const Inst *operator*() const 434 { 435 return current_; 436 } 437 Inst *operator*() 438 { 439 return current_; 440 } 441 GetCurrent()442 Inst *GetCurrent() const 443 { 444 return current_; 445 } 446 SetCurrent(Inst * current)447 void SetCurrent(Inst *current) 448 { 449 current_ = current; 450 } 451 452 protected: InstIterator(const BasicBlock & block,Inst * start)453 InstIterator(const BasicBlock &block, Inst *start) 454 { 455 #ifndef __clang_analyzer__ 456 if constexpr (IterationType::INST == T && IterationDirection::FORWARD == D) { 457 current_ = (start != nullptr) ? start : block.firstInst_; 458 return; 459 } 460 if constexpr (IterationType::ALL == T && IterationDirection::FORWARD == D) { 461 current_ = (block.firstPhi_ != nullptr) ? block.firstPhi_ : block.firstInst_; 462 current_ = (start != nullptr) ? start : current_; 463 return; 464 } 465 if constexpr (IterationType::PHI == T && IterationDirection::BACKWARD == D) { 466 current_ = (block.firstInst_ != nullptr) ? block.firstInst_->GetPrev() : block.lastInst_; 467 current_ = (start != nullptr) ? start : current_; 468 return; 469 } 470 if constexpr (IterationType::ALL == T && IterationDirection::BACKWARD == D) { 471 current_ = (start != nullptr) ? start : block.lastInst_; 472 return; 473 } 474 #else 475 [[maybe_unused]] auto const &tb = block; 476 [[maybe_unused]] auto ts = start; 477 #endif 478 UNREACHABLE(); 479 } InstIterator(Inst * current)480 explicit InstIterator(Inst *current) : current_(current) {}; 481 482 DEFAULT_COPY_SEMANTIC(InstIterator); 483 DEFAULT_MOVE_SEMANTIC(InstIterator); 484 virtual ~InstIterator() = default; 485 486 private: 487 Inst *current_ {nullptr}; 488 }; 489 490 /* 491 * Iterates over the instructions in direct order. 492 * Starts with the 'start' instruction if it's initialized 493 * or with the first phi/non-phi instruction in the basic block 494 */ 495 template <const IterationType T> 496 class InstForwardIterator : public InstIterator<T, IterationDirection::FORWARD> { 497 public: 498 explicit InstForwardIterator(const BasicBlock &block, Inst *start = nullptr) 499 : InstIterator<T, IterationDirection::FORWARD>(block, start) 500 { 501 } 502 503 public: 504 // NOLINTNEXTLINE(readability-identifier-naming) begin()505 InstForwardIterator begin() const 506 { 507 return InstForwardIterator(this->GetCurrent()); 508 } 509 // NOLINTNEXTLINE(readability-identifier-naming) end()510 InstForwardIterator end() const 511 { 512 return InstForwardIterator(nullptr); 513 } 514 InstForwardIterator &operator++() 515 { 516 this->SetCurrent(this->GetCurrent()->GetNext()); 517 return *this; 518 } 519 bool operator!=(const InstForwardIterator &other) const 520 { 521 return this->GetCurrent() != other.GetCurrent(); 522 } 523 bool operator==(const InstForwardIterator &other) const 524 { 525 return this->GetCurrent() == other.GetCurrent(); 526 } 527 528 protected: InstForwardIterator(Inst * current)529 explicit InstForwardIterator(Inst *current) : InstIterator<T, IterationDirection::FORWARD>(current) {}; 530 }; 531 532 /* 533 * Specialization for PHI instructions 534 */ 535 template <> 536 class InstForwardIterator<IterationType::PHI> : public InstForwardIterator<IterationType::INST> { 537 public: 538 explicit InstForwardIterator(const BasicBlock &block, Inst *start = nullptr) 539 : InstForwardIterator<IterationType::INST>(start != nullptr ? start : block.firstPhi_) 540 { 541 final_ = ((block.firstPhi_ != nullptr) && (block.firstInst_ != nullptr)) ? block.firstInst_ : nullptr; 542 } 543 544 public: 545 // NOLINTNEXTLINE(readability-identifier-naming) end()546 InstForwardIterator end() const 547 { 548 return InstForwardIterator(final_); 549 } 550 bool operator!=(const InstForwardIterator &other) const 551 { 552 return this->GetCurrent() != other.GetCurrent(); 553 } 554 bool operator==(const InstForwardIterator &other) const 555 { 556 return this->GetCurrent() == other.GetCurrent(); 557 } 558 559 private: InstForwardIterator(Inst * current)560 explicit InstForwardIterator(Inst *current) : InstForwardIterator<IterationType::INST>(current) {}; 561 562 private: 563 Inst *final_ {nullptr}; 564 }; 565 566 /* 567 * Iterates over the instructions in reverse order. 568 * Starts with the 'start' instruction if it's initialized 569 * or with the first phi/non-phi instruction in the basic block 570 */ 571 template <const IterationType T> 572 class InstBackwardIterator : public InstIterator<T, IterationDirection::BACKWARD> { 573 public: 574 explicit InstBackwardIterator(const BasicBlock &block, Inst *start = nullptr) 575 : InstIterator<T, IterationDirection::BACKWARD>(block, start) 576 { 577 } 578 579 public: 580 // NOLINTNEXTLINE(readability-identifier-naming) begin()581 InstBackwardIterator begin() const 582 { 583 return InstBackwardIterator(this->GetCurrent()); 584 } 585 // NOLINTNEXTLINE(readability-identifier-naming) end()586 InstBackwardIterator end() const 587 { 588 return InstBackwardIterator(nullptr); 589 } 590 InstBackwardIterator &operator++() 591 { 592 this->SetCurrent(this->GetCurrent()->GetPrev()); 593 return *this; 594 } 595 bool operator!=(const InstBackwardIterator &other) const 596 { 597 return this->GetCurrent() != other.GetCurrent(); 598 } 599 bool operator==(const InstBackwardIterator &other) const 600 { 601 return this->GetCurrent() == other.GetCurrent(); 602 } 603 604 protected: InstBackwardIterator(Inst * current)605 explicit InstBackwardIterator(Inst *current) : InstIterator<T, IterationDirection::BACKWARD>(current) {} 606 }; 607 608 /* 609 * Specialization for not-PHI instructions 610 */ 611 template <> 612 class InstBackwardIterator<IterationType::INST> : public InstBackwardIterator<IterationType::ALL> { 613 public: 614 explicit InstBackwardIterator(const BasicBlock &block, Inst *start = nullptr) 615 : InstBackwardIterator<IterationType::ALL>(nullptr) 616 { 617 auto lastInst = (block.firstInst_ != nullptr) ? block.lastInst_ : nullptr; 618 this->SetCurrent(start != nullptr ? start : lastInst); 619 final_ = (block.firstInst_ != nullptr) ? block.firstInst_->GetPrev() : nullptr; 620 } 621 622 public: 623 // NOLINTNEXTLINE(readability-identifier-naming) end()624 InstBackwardIterator end() const 625 { 626 return InstBackwardIterator(final_); 627 } 628 629 private: InstBackwardIterator(Inst * current)630 explicit InstBackwardIterator(Inst *current) : InstBackwardIterator<IterationType::ALL>(current) {} 631 632 private: 633 Inst *final_ {nullptr}; 634 }; 635 636 /* 637 * Iterates over the instructions in `IterationDirection` order, keeping next instruction in case of removing current 638 * instruction 639 */ 640 template <const IterationType T, const IterationDirection D> 641 class InstSafeIterator : public InstIterator<T, D> { 642 public: 643 explicit InstSafeIterator(const BasicBlock &block, Inst *start = nullptr) : InstIterator<T, D>(block, start) 644 { 645 follower_ = GetFollower(); 646 } 647 648 public: 649 // NOLINTNEXTLINE(readability-identifier-naming) begin()650 InstSafeIterator begin() const 651 { 652 return InstSafeIterator(this->GetCurrent(), follower_); 653 } 654 // NOLINTNEXTLINE(readability-identifier-naming) end()655 InstSafeIterator end() const 656 { 657 return InstSafeIterator(nullptr); 658 } 659 InstSafeIterator &operator++() 660 { 661 this->SetCurrent(follower_); 662 follower_ = GetFollower(); 663 return *this; 664 } 665 bool operator!=(const InstSafeIterator &other) const 666 { 667 return this->GetCurrent() != other.GetCurrent(); 668 } 669 bool operator==(const InstSafeIterator &other) const 670 { 671 return this->GetCurrent() == other.GetCurrent(); 672 } 673 674 protected: InstSafeIterator(Inst * current)675 explicit InstSafeIterator(Inst *current) : InstIterator<T, D>(current) {}; InstSafeIterator(Inst * current,Inst * follower)676 explicit InstSafeIterator(Inst *current, Inst *follower) : InstIterator<T, D>(current), follower_(follower) {}; 677 678 protected: GetFollower()679 Inst *GetFollower() 680 { 681 #ifndef __clang_analyzer__ 682 if constexpr (IterationDirection::FORWARD == D) { 683 return this->GetCurrent() == nullptr ? nullptr : this->GetCurrent()->GetNext(); 684 }; 685 if constexpr (IterationDirection::BACKWARD == D) { 686 return this->GetCurrent() == nullptr ? nullptr : this->GetCurrent()->GetPrev(); 687 }; 688 #endif 689 UNREACHABLE(); 690 return nullptr; 691 } 692 SetFollower(Inst * follower)693 void SetFollower(Inst *follower) 694 { 695 follower_ = follower; 696 } 697 698 private: 699 Inst *follower_ {nullptr}; 700 }; 701 702 /* 703 * Specialization for PHI instructions 704 */ 705 template <> 706 class InstSafeIterator<IterationType::PHI, IterationDirection::FORWARD> 707 : public InstSafeIterator<IterationType::INST, IterationDirection::FORWARD> { 708 public: 709 explicit InstSafeIterator(const BasicBlock &block, Inst *start = nullptr) 710 : InstSafeIterator<IterationType::INST, IterationDirection::FORWARD>(start != nullptr ? start : block.firstPhi_) 711 { 712 final_ = ((block.firstPhi_ != nullptr) && (block.firstInst_ != nullptr)) ? block.firstInst_ : nullptr; 713 this->SetFollower(GetFollower()); 714 } 715 716 public: 717 // NOLINTNEXTLINE(readability-identifier-naming) end()718 InstSafeIterator end() const 719 { 720 return InstSafeIterator(final_); 721 } 722 bool operator==(const InstSafeIterator &other) const 723 { 724 return this->GetCurrent() == other.GetCurrent(); 725 } 726 bool operator!=(const InstSafeIterator &other) const 727 { 728 return this->GetCurrent() != other.GetCurrent(); 729 } 730 731 private: InstSafeIterator(Inst * current)732 explicit InstSafeIterator(Inst *current) 733 : InstSafeIterator<IterationType::INST, IterationDirection::FORWARD>(current) {}; 734 735 private: GetFollower()736 Inst *GetFollower() 737 { 738 return this->GetCurrent() == final_ ? nullptr : this->GetCurrent()->GetNext(); 739 } 740 741 private: 742 Inst *final_ {nullptr}; 743 }; 744 745 /* 746 * Specialization for not-PHI instructions 747 */ 748 template <> 749 class InstSafeIterator<IterationType::INST, IterationDirection::BACKWARD> 750 : public InstSafeIterator<IterationType::ALL, IterationDirection::BACKWARD> { 751 public: 752 explicit InstSafeIterator(const BasicBlock &block, Inst *start = nullptr) 753 : InstSafeIterator<IterationType::ALL, IterationDirection::BACKWARD>(nullptr) 754 { 755 auto lastInst = (block.firstInst_ != nullptr) ? block.lastInst_ : nullptr; 756 this->SetCurrent(start != nullptr ? start : lastInst); 757 final_ = (block.firstInst_ != nullptr) ? block.firstInst_->GetPrev() : nullptr; 758 this->SetFollower(GetFollower()); 759 } 760 761 public: 762 // NOLINTNEXTLINE(readability-identifier-naming) end()763 InstSafeIterator end() const 764 { 765 return InstSafeIterator(final_); 766 } 767 bool operator!=(const InstSafeIterator &other) const 768 { 769 return this->GetCurrent() != other.GetCurrent(); 770 } 771 bool operator==(const InstSafeIterator &other) const 772 { 773 return this->GetCurrent() == other.GetCurrent(); 774 } 775 776 private: InstSafeIterator(Inst * current)777 explicit InstSafeIterator(Inst *current) 778 : InstSafeIterator<IterationType::ALL, IterationDirection::BACKWARD>(current) {}; 779 780 private: GetFollower()781 Inst *GetFollower() 782 { 783 return this->GetCurrent() == final_ ? nullptr : this->GetCurrent()->GetPrev(); 784 } 785 786 private: 787 Inst *final_ {nullptr}; 788 }; 789 790 /** 791 * DFS-search to find path between `block` and `target_block`, 792 * `exclude_block` can be set to search path without this block 793 */ 794 bool BlocksPathDfsSearch(Marker marker, BasicBlock *block, const BasicBlock *targetBlock, 795 const BasicBlock *excludeBlock = nullptr); 796 } // namespace ark::compiler 797 #endif // COMPILER_OPTIMIZER_IR_BASICBLOCK_H 798