• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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