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