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