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