File: | llvm/lib/Target/Hexagon/HexagonCFGOptimizer.cpp |
Warning: | line 196, column 26 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- HexagonCFGOptimizer.cpp - CFG optimizations ------------------------===// | ||||||
2 | // | ||||||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||||
4 | // See https://llvm.org/LICENSE.txt for license information. | ||||||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||||
6 | // | ||||||
7 | //===----------------------------------------------------------------------===// | ||||||
8 | |||||||
9 | #include "Hexagon.h" | ||||||
10 | #include "MCTargetDesc/HexagonMCTargetDesc.h" | ||||||
11 | #include "llvm/CodeGen/MachineBasicBlock.h" | ||||||
12 | #include "llvm/CodeGen/MachineBranchProbabilityInfo.h" | ||||||
13 | #include "llvm/CodeGen/MachineFunction.h" | ||||||
14 | #include "llvm/CodeGen/MachineFunctionPass.h" | ||||||
15 | #include "llvm/CodeGen/MachineInstr.h" | ||||||
16 | #include "llvm/CodeGen/MachineOperand.h" | ||||||
17 | #include "llvm/CodeGen/TargetInstrInfo.h" | ||||||
18 | #include "llvm/CodeGen/TargetSubtargetInfo.h" | ||||||
19 | #include "llvm/Pass.h" | ||||||
20 | #include "llvm/Support/ErrorHandling.h" | ||||||
21 | #include <cassert> | ||||||
22 | #include <vector> | ||||||
23 | |||||||
24 | using namespace llvm; | ||||||
25 | |||||||
26 | #define DEBUG_TYPE"hexagon_cfg" "hexagon_cfg" | ||||||
27 | |||||||
28 | namespace llvm { | ||||||
29 | |||||||
30 | FunctionPass *createHexagonCFGOptimizer(); | ||||||
31 | void initializeHexagonCFGOptimizerPass(PassRegistry&); | ||||||
32 | |||||||
33 | } // end namespace llvm | ||||||
34 | |||||||
35 | namespace { | ||||||
36 | |||||||
37 | class HexagonCFGOptimizer : public MachineFunctionPass { | ||||||
38 | private: | ||||||
39 | void InvertAndChangeJumpTarget(MachineInstr &, MachineBasicBlock *); | ||||||
40 | bool isOnFallThroughPath(MachineBasicBlock *MBB); | ||||||
41 | |||||||
42 | public: | ||||||
43 | static char ID; | ||||||
44 | |||||||
45 | HexagonCFGOptimizer() : MachineFunctionPass(ID) { | ||||||
46 | initializeHexagonCFGOptimizerPass(*PassRegistry::getPassRegistry()); | ||||||
47 | } | ||||||
48 | |||||||
49 | StringRef getPassName() const override { return "Hexagon CFG Optimizer"; } | ||||||
50 | bool runOnMachineFunction(MachineFunction &Fn) override; | ||||||
51 | |||||||
52 | MachineFunctionProperties getRequiredProperties() const override { | ||||||
53 | return MachineFunctionProperties().set( | ||||||
54 | MachineFunctionProperties::Property::NoVRegs); | ||||||
55 | } | ||||||
56 | }; | ||||||
57 | |||||||
58 | } // end anonymous namespace | ||||||
59 | |||||||
60 | char HexagonCFGOptimizer::ID = 0; | ||||||
61 | |||||||
62 | static bool IsConditionalBranch(int Opc) { | ||||||
63 | switch (Opc) { | ||||||
64 | case Hexagon::J2_jumpt: | ||||||
65 | case Hexagon::J2_jumptpt: | ||||||
66 | case Hexagon::J2_jumpf: | ||||||
67 | case Hexagon::J2_jumpfpt: | ||||||
68 | case Hexagon::J2_jumptnew: | ||||||
69 | case Hexagon::J2_jumpfnew: | ||||||
70 | case Hexagon::J2_jumptnewpt: | ||||||
71 | case Hexagon::J2_jumpfnewpt: | ||||||
72 | return true; | ||||||
73 | } | ||||||
74 | return false; | ||||||
75 | } | ||||||
76 | |||||||
77 | static bool IsUnconditionalJump(int Opc) { | ||||||
78 | return (Opc == Hexagon::J2_jump); | ||||||
79 | } | ||||||
80 | |||||||
81 | void HexagonCFGOptimizer::InvertAndChangeJumpTarget( | ||||||
82 | MachineInstr &MI, MachineBasicBlock *NewTarget) { | ||||||
83 | const TargetInstrInfo *TII = | ||||||
84 | MI.getParent()->getParent()->getSubtarget().getInstrInfo(); | ||||||
85 | int NewOpcode = 0; | ||||||
86 | switch (MI.getOpcode()) { | ||||||
87 | case Hexagon::J2_jumpt: | ||||||
88 | NewOpcode = Hexagon::J2_jumpf; | ||||||
89 | break; | ||||||
90 | case Hexagon::J2_jumpf: | ||||||
91 | NewOpcode = Hexagon::J2_jumpt; | ||||||
92 | break; | ||||||
93 | case Hexagon::J2_jumptnewpt: | ||||||
94 | NewOpcode = Hexagon::J2_jumpfnewpt; | ||||||
95 | break; | ||||||
96 | case Hexagon::J2_jumpfnewpt: | ||||||
97 | NewOpcode = Hexagon::J2_jumptnewpt; | ||||||
98 | break; | ||||||
99 | default: | ||||||
100 | llvm_unreachable("Cannot handle this case")__builtin_unreachable(); | ||||||
101 | } | ||||||
102 | |||||||
103 | MI.setDesc(TII->get(NewOpcode)); | ||||||
104 | MI.getOperand(1).setMBB(NewTarget); | ||||||
105 | } | ||||||
106 | |||||||
107 | bool HexagonCFGOptimizer::isOnFallThroughPath(MachineBasicBlock *MBB) { | ||||||
108 | if (MBB->canFallThrough()) | ||||||
109 | return true; | ||||||
110 | for (MachineBasicBlock *PB : MBB->predecessors()) | ||||||
111 | if (PB->isLayoutSuccessor(MBB) && PB->canFallThrough()) | ||||||
112 | return true; | ||||||
113 | return false; | ||||||
114 | } | ||||||
115 | |||||||
116 | bool HexagonCFGOptimizer::runOnMachineFunction(MachineFunction &Fn) { | ||||||
117 | if (skipFunction(Fn.getFunction())) | ||||||
| |||||||
118 | return false; | ||||||
119 | |||||||
120 | // Loop over all of the basic blocks. | ||||||
121 | for (MachineFunction::iterator MBBb = Fn.begin(), MBBe = Fn.end(); | ||||||
122 | MBBb != MBBe; ++MBBb) { | ||||||
123 | MachineBasicBlock *MBB = &*MBBb; | ||||||
124 | |||||||
125 | // Traverse the basic block. | ||||||
126 | MachineBasicBlock::iterator MII = MBB->getFirstTerminator(); | ||||||
127 | if (MII != MBB->end()) { | ||||||
128 | MachineInstr &MI = *MII; | ||||||
129 | int Opc = MI.getOpcode(); | ||||||
130 | if (IsConditionalBranch(Opc)) { | ||||||
131 | // (Case 1) Transform the code if the following condition occurs: | ||||||
132 | // BB1: if (p0) jump BB3 | ||||||
133 | // ...falls-through to BB2 ... | ||||||
134 | // BB2: jump BB4 | ||||||
135 | // ...next block in layout is BB3... | ||||||
136 | // BB3: ... | ||||||
137 | // | ||||||
138 | // Transform this to: | ||||||
139 | // BB1: if (!p0) jump BB4 | ||||||
140 | // Remove BB2 | ||||||
141 | // BB3: ... | ||||||
142 | // | ||||||
143 | // (Case 2) A variation occurs when BB3 contains a JMP to BB4: | ||||||
144 | // BB1: if (p0) jump BB3 | ||||||
145 | // ...falls-through to BB2 ... | ||||||
146 | // BB2: jump BB4 | ||||||
147 | // ...other basic blocks ... | ||||||
148 | // BB4: | ||||||
149 | // ...not a fall-thru | ||||||
150 | // BB3: ... | ||||||
151 | // jump BB4 | ||||||
152 | // | ||||||
153 | // Transform this to: | ||||||
154 | // BB1: if (!p0) jump BB4 | ||||||
155 | // Remove BB2 | ||||||
156 | // BB3: ... | ||||||
157 | // BB4: ... | ||||||
158 | unsigned NumSuccs = MBB->succ_size(); | ||||||
159 | MachineBasicBlock::succ_iterator SI = MBB->succ_begin(); | ||||||
160 | MachineBasicBlock* FirstSucc = *SI; | ||||||
161 | MachineBasicBlock* SecondSucc = *(++SI); | ||||||
162 | MachineBasicBlock* LayoutSucc = nullptr; | ||||||
163 | MachineBasicBlock* JumpAroundTarget = nullptr; | ||||||
164 | |||||||
165 | if (MBB->isLayoutSuccessor(FirstSucc)) { | ||||||
166 | LayoutSucc = FirstSucc; | ||||||
167 | JumpAroundTarget = SecondSucc; | ||||||
168 | } else if (MBB->isLayoutSuccessor(SecondSucc)) { | ||||||
169 | LayoutSucc = SecondSucc; | ||||||
170 | JumpAroundTarget = FirstSucc; | ||||||
171 | } else { | ||||||
172 | // Odd case...cannot handle. | ||||||
173 | } | ||||||
174 | |||||||
175 | // The target of the unconditional branch must be JumpAroundTarget. | ||||||
176 | // TODO: If not, we should not invert the unconditional branch. | ||||||
177 | MachineBasicBlock* CondBranchTarget = nullptr; | ||||||
178 | if (MI.getOpcode() == Hexagon::J2_jumpt || | ||||||
179 | MI.getOpcode() == Hexagon::J2_jumpf) { | ||||||
180 | CondBranchTarget = MI.getOperand(1).getMBB(); | ||||||
181 | } | ||||||
182 | |||||||
183 | if (!LayoutSucc || (CondBranchTarget != JumpAroundTarget)) { | ||||||
184 | continue; | ||||||
185 | } | ||||||
186 | |||||||
187 | if ((NumSuccs == 2) && LayoutSucc
| ||||||
188 | // Ensure that BB2 has one instruction -- an unconditional jump. | ||||||
189 | if ((LayoutSucc->size() == 1) && | ||||||
190 | IsUnconditionalJump(LayoutSucc->front().getOpcode())) { | ||||||
191 | assert(JumpAroundTarget && "jump target is needed to process second basic block")(static_cast<void> (0)); | ||||||
192 | MachineBasicBlock* UncondTarget = | ||||||
193 | LayoutSucc->front().getOperand(0).getMBB(); | ||||||
194 | // Check if the layout successor of BB2 is BB3. | ||||||
195 | bool case1 = LayoutSucc->isLayoutSuccessor(JumpAroundTarget); | ||||||
196 | bool case2 = JumpAroundTarget->isSuccessor(UncondTarget) && | ||||||
| |||||||
197 | !JumpAroundTarget->empty() && | ||||||
198 | IsUnconditionalJump(JumpAroundTarget->back().getOpcode()) && | ||||||
199 | JumpAroundTarget->pred_size() == 1 && | ||||||
200 | JumpAroundTarget->succ_size() == 1; | ||||||
201 | |||||||
202 | if (case1 || case2) { | ||||||
203 | InvertAndChangeJumpTarget(MI, UncondTarget); | ||||||
204 | MBB->replaceSuccessor(JumpAroundTarget, UncondTarget); | ||||||
205 | |||||||
206 | // Remove the unconditional branch in LayoutSucc. | ||||||
207 | LayoutSucc->erase(LayoutSucc->begin()); | ||||||
208 | LayoutSucc->replaceSuccessor(UncondTarget, JumpAroundTarget); | ||||||
209 | |||||||
210 | // This code performs the conversion for case 2, which moves | ||||||
211 | // the block to the fall-thru case (BB3 in the code above). | ||||||
212 | if (case2 && !case1) { | ||||||
213 | JumpAroundTarget->moveAfter(LayoutSucc); | ||||||
214 | // only move a block if it doesn't have a fall-thru. otherwise | ||||||
215 | // the CFG will be incorrect. | ||||||
216 | if (!isOnFallThroughPath(UncondTarget)) | ||||||
217 | UncondTarget->moveAfter(JumpAroundTarget); | ||||||
218 | } | ||||||
219 | |||||||
220 | // Correct live-in information. Is used by post-RA scheduler | ||||||
221 | // The live-in to LayoutSucc is now all values live-in to | ||||||
222 | // JumpAroundTarget. | ||||||
223 | std::vector<MachineBasicBlock::RegisterMaskPair> OrigLiveIn( | ||||||
224 | LayoutSucc->livein_begin(), LayoutSucc->livein_end()); | ||||||
225 | std::vector<MachineBasicBlock::RegisterMaskPair> NewLiveIn( | ||||||
226 | JumpAroundTarget->livein_begin(), | ||||||
227 | JumpAroundTarget->livein_end()); | ||||||
228 | for (const auto &OrigLI : OrigLiveIn) | ||||||
229 | LayoutSucc->removeLiveIn(OrigLI.PhysReg); | ||||||
230 | for (const auto &NewLI : NewLiveIn) | ||||||
231 | LayoutSucc->addLiveIn(NewLI); | ||||||
232 | } | ||||||
233 | } | ||||||
234 | } | ||||||
235 | } | ||||||
236 | } | ||||||
237 | } | ||||||
238 | return true; | ||||||
239 | } | ||||||
240 | |||||||
241 | //===----------------------------------------------------------------------===// | ||||||
242 | // Public Constructor Functions | ||||||
243 | //===----------------------------------------------------------------------===// | ||||||
244 | |||||||
245 | INITIALIZE_PASS(HexagonCFGOptimizer, "hexagon-cfg", "Hexagon CFG Optimizer",static void *initializeHexagonCFGOptimizerPassOnce(PassRegistry &Registry) { PassInfo *PI = new PassInfo( "Hexagon CFG Optimizer" , "hexagon-cfg", &HexagonCFGOptimizer::ID, PassInfo::NormalCtor_t (callDefaultCtor<HexagonCFGOptimizer>), false, false); Registry .registerPass(*PI, true); return PI; } static llvm::once_flag InitializeHexagonCFGOptimizerPassFlag; void llvm::initializeHexagonCFGOptimizerPass (PassRegistry &Registry) { llvm::call_once(InitializeHexagonCFGOptimizerPassFlag , initializeHexagonCFGOptimizerPassOnce, std::ref(Registry)); } | ||||||
246 | false, false)static void *initializeHexagonCFGOptimizerPassOnce(PassRegistry &Registry) { PassInfo *PI = new PassInfo( "Hexagon CFG Optimizer" , "hexagon-cfg", &HexagonCFGOptimizer::ID, PassInfo::NormalCtor_t (callDefaultCtor<HexagonCFGOptimizer>), false, false); Registry .registerPass(*PI, true); return PI; } static llvm::once_flag InitializeHexagonCFGOptimizerPassFlag; void llvm::initializeHexagonCFGOptimizerPass (PassRegistry &Registry) { llvm::call_once(InitializeHexagonCFGOptimizerPassFlag , initializeHexagonCFGOptimizerPassOnce, std::ref(Registry)); } | ||||||
247 | |||||||
248 | FunctionPass *llvm::createHexagonCFGOptimizer() { | ||||||
249 | return new HexagonCFGOptimizer(); | ||||||
250 | } |
1 | //===- llvm/ADT/ilist_iterator.h - Intrusive List Iterator ------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef LLVM_ADT_ILIST_ITERATOR_H |
10 | #define LLVM_ADT_ILIST_ITERATOR_H |
11 | |
12 | #include "llvm/ADT/ilist_node.h" |
13 | #include <cassert> |
14 | #include <cstddef> |
15 | #include <iterator> |
16 | #include <type_traits> |
17 | |
18 | namespace llvm { |
19 | |
20 | namespace ilist_detail { |
21 | |
22 | /// Find const-correct node types. |
23 | template <class OptionsT, bool IsConst> struct IteratorTraits; |
24 | template <class OptionsT> struct IteratorTraits<OptionsT, false> { |
25 | using value_type = typename OptionsT::value_type; |
26 | using pointer = typename OptionsT::pointer; |
27 | using reference = typename OptionsT::reference; |
28 | using node_pointer = ilist_node_impl<OptionsT> *; |
29 | using node_reference = ilist_node_impl<OptionsT> &; |
30 | }; |
31 | template <class OptionsT> struct IteratorTraits<OptionsT, true> { |
32 | using value_type = const typename OptionsT::value_type; |
33 | using pointer = typename OptionsT::const_pointer; |
34 | using reference = typename OptionsT::const_reference; |
35 | using node_pointer = const ilist_node_impl<OptionsT> *; |
36 | using node_reference = const ilist_node_impl<OptionsT> &; |
37 | }; |
38 | |
39 | template <bool IsReverse> struct IteratorHelper; |
40 | template <> struct IteratorHelper<false> : ilist_detail::NodeAccess { |
41 | using Access = ilist_detail::NodeAccess; |
42 | |
43 | template <class T> static void increment(T *&I) { I = Access::getNext(*I); } |
44 | template <class T> static void decrement(T *&I) { I = Access::getPrev(*I); } |
45 | }; |
46 | template <> struct IteratorHelper<true> : ilist_detail::NodeAccess { |
47 | using Access = ilist_detail::NodeAccess; |
48 | |
49 | template <class T> static void increment(T *&I) { I = Access::getPrev(*I); } |
50 | template <class T> static void decrement(T *&I) { I = Access::getNext(*I); } |
51 | }; |
52 | |
53 | } // end namespace ilist_detail |
54 | |
55 | /// Iterator for intrusive lists based on ilist_node. |
56 | template <class OptionsT, bool IsReverse, bool IsConst> |
57 | class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> { |
58 | friend ilist_iterator<OptionsT, IsReverse, !IsConst>; |
59 | friend ilist_iterator<OptionsT, !IsReverse, IsConst>; |
60 | friend ilist_iterator<OptionsT, !IsReverse, !IsConst>; |
61 | |
62 | using Traits = ilist_detail::IteratorTraits<OptionsT, IsConst>; |
63 | using Access = ilist_detail::SpecificNodeAccess<OptionsT>; |
64 | |
65 | public: |
66 | using value_type = typename Traits::value_type; |
67 | using pointer = typename Traits::pointer; |
68 | using reference = typename Traits::reference; |
69 | using difference_type = ptrdiff_t; |
70 | using iterator_category = std::bidirectional_iterator_tag; |
71 | using const_pointer = typename OptionsT::const_pointer; |
72 | using const_reference = typename OptionsT::const_reference; |
73 | |
74 | private: |
75 | using node_pointer = typename Traits::node_pointer; |
76 | using node_reference = typename Traits::node_reference; |
77 | |
78 | node_pointer NodePtr = nullptr; |
79 | |
80 | public: |
81 | /// Create from an ilist_node. |
82 | explicit ilist_iterator(node_reference N) : NodePtr(&N) {} |
83 | |
84 | explicit ilist_iterator(pointer NP) : NodePtr(Access::getNodePtr(NP)) {} |
85 | explicit ilist_iterator(reference NR) : NodePtr(Access::getNodePtr(&NR)) {} |
86 | ilist_iterator() = default; |
87 | |
88 | // This is templated so that we can allow constructing a const iterator from |
89 | // a nonconst iterator... |
90 | template <bool RHSIsConst> |
91 | ilist_iterator(const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS, |
92 | std::enable_if_t<IsConst || !RHSIsConst, void *> = nullptr) |
93 | : NodePtr(RHS.NodePtr) {} |
94 | |
95 | // This is templated so that we can allow assigning to a const iterator from |
96 | // a nonconst iterator... |
97 | template <bool RHSIsConst> |
98 | std::enable_if_t<IsConst || !RHSIsConst, ilist_iterator &> |
99 | operator=(const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS) { |
100 | NodePtr = RHS.NodePtr; |
101 | return *this; |
102 | } |
103 | |
104 | /// Explicit conversion between forward/reverse iterators. |
105 | /// |
106 | /// Translate between forward and reverse iterators without changing range |
107 | /// boundaries. The resulting iterator will dereference (and have a handle) |
108 | /// to the previous node, which is somewhat unexpected; but converting the |
109 | /// two endpoints in a range will give the same range in reverse. |
110 | /// |
111 | /// This matches std::reverse_iterator conversions. |
112 | explicit ilist_iterator( |
113 | const ilist_iterator<OptionsT, !IsReverse, IsConst> &RHS) |
114 | : ilist_iterator(++RHS.getReverse()) {} |
115 | |
116 | /// Get a reverse iterator to the same node. |
117 | /// |
118 | /// Gives a reverse iterator that will dereference (and have a handle) to the |
119 | /// same node. Converting the endpoint iterators in a range will give a |
120 | /// different range; for range operations, use the explicit conversions. |
121 | ilist_iterator<OptionsT, !IsReverse, IsConst> getReverse() const { |
122 | if (NodePtr) |
123 | return ilist_iterator<OptionsT, !IsReverse, IsConst>(*NodePtr); |
124 | return ilist_iterator<OptionsT, !IsReverse, IsConst>(); |
125 | } |
126 | |
127 | /// Const-cast. |
128 | ilist_iterator<OptionsT, IsReverse, false> getNonConst() const { |
129 | if (NodePtr) |
130 | return ilist_iterator<OptionsT, IsReverse, false>( |
131 | const_cast<typename ilist_iterator<OptionsT, IsReverse, |
132 | false>::node_reference>(*NodePtr)); |
133 | return ilist_iterator<OptionsT, IsReverse, false>(); |
134 | } |
135 | |
136 | // Accessors... |
137 | reference operator*() const { |
138 | assert(!NodePtr->isKnownSentinel())(static_cast<void> (0)); |
139 | return *Access::getValuePtr(NodePtr); |
140 | } |
141 | pointer operator->() const { return &operator*(); } |
142 | |
143 | // Comparison operators |
144 | friend bool operator==(const ilist_iterator &LHS, const ilist_iterator &RHS) { |
145 | return LHS.NodePtr == RHS.NodePtr; |
146 | } |
147 | friend bool operator!=(const ilist_iterator &LHS, const ilist_iterator &RHS) { |
148 | return LHS.NodePtr != RHS.NodePtr; |
149 | } |
150 | |
151 | // Increment and decrement operators... |
152 | ilist_iterator &operator--() { |
153 | NodePtr = IsReverse ? NodePtr->getNext() : NodePtr->getPrev(); |
154 | return *this; |
155 | } |
156 | ilist_iterator &operator++() { |
157 | NodePtr = IsReverse ? NodePtr->getPrev() : NodePtr->getNext(); |
158 | return *this; |
159 | } |
160 | ilist_iterator operator--(int) { |
161 | ilist_iterator tmp = *this; |
162 | --*this; |
163 | return tmp; |
164 | } |
165 | ilist_iterator operator++(int) { |
166 | ilist_iterator tmp = *this; |
167 | ++*this; |
168 | return tmp; |
169 | } |
170 | |
171 | /// Get the underlying ilist_node. |
172 | node_pointer getNodePtr() const { return static_cast<node_pointer>(NodePtr); } |
173 | |
174 | /// Check for end. Only valid if ilist_sentinel_tracking<true>. |
175 | bool isEnd() const { return NodePtr ? NodePtr->isSentinel() : false; } |
176 | }; |
177 | |
178 | template <typename From> struct simplify_type; |
179 | |
180 | /// Allow ilist_iterators to convert into pointers to a node automatically when |
181 | /// used by the dyn_cast, cast, isa mechanisms... |
182 | /// |
183 | /// FIXME: remove this, since there is no implicit conversion to NodeTy. |
184 | template <class OptionsT, bool IsConst> |
185 | struct simplify_type<ilist_iterator<OptionsT, false, IsConst>> { |
186 | using iterator = ilist_iterator<OptionsT, false, IsConst>; |
187 | using SimpleType = typename iterator::pointer; |
188 | |
189 | static SimpleType getSimplifiedValue(const iterator &Node) { return &*Node; } |
190 | }; |
191 | template <class OptionsT, bool IsConst> |
192 | struct simplify_type<const ilist_iterator<OptionsT, false, IsConst>> |
193 | : simplify_type<ilist_iterator<OptionsT, false, IsConst>> {}; |
194 | |
195 | } // end namespace llvm |
196 | |
197 | #endif // LLVM_ADT_ILIST_ITERATOR_H |
1 | //===- llvm/CodeGen/MachineInstrBundleIterator.h ----------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // Defines an iterator class that bundles MachineInstr. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_CODEGEN_MACHINEINSTRBUNDLEITERATOR_H |
14 | #define LLVM_CODEGEN_MACHINEINSTRBUNDLEITERATOR_H |
15 | |
16 | #include "llvm/ADT/ilist.h" |
17 | #include "llvm/ADT/simple_ilist.h" |
18 | #include <cassert> |
19 | #include <iterator> |
20 | #include <type_traits> |
21 | |
22 | namespace llvm { |
23 | |
24 | template <class T, bool IsReverse> struct MachineInstrBundleIteratorTraits; |
25 | template <class T> struct MachineInstrBundleIteratorTraits<T, false> { |
26 | using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>; |
27 | using instr_iterator = typename list_type::iterator; |
28 | using nonconst_instr_iterator = typename list_type::iterator; |
29 | using const_instr_iterator = typename list_type::const_iterator; |
30 | }; |
31 | template <class T> struct MachineInstrBundleIteratorTraits<T, true> { |
32 | using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>; |
33 | using instr_iterator = typename list_type::reverse_iterator; |
34 | using nonconst_instr_iterator = typename list_type::reverse_iterator; |
35 | using const_instr_iterator = typename list_type::const_reverse_iterator; |
36 | }; |
37 | template <class T> struct MachineInstrBundleIteratorTraits<const T, false> { |
38 | using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>; |
39 | using instr_iterator = typename list_type::const_iterator; |
40 | using nonconst_instr_iterator = typename list_type::iterator; |
41 | using const_instr_iterator = typename list_type::const_iterator; |
42 | }; |
43 | template <class T> struct MachineInstrBundleIteratorTraits<const T, true> { |
44 | using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>; |
45 | using instr_iterator = typename list_type::const_reverse_iterator; |
46 | using nonconst_instr_iterator = typename list_type::reverse_iterator; |
47 | using const_instr_iterator = typename list_type::const_reverse_iterator; |
48 | }; |
49 | |
50 | template <bool IsReverse> struct MachineInstrBundleIteratorHelper; |
51 | template <> struct MachineInstrBundleIteratorHelper<false> { |
52 | /// Get the beginning of the current bundle. |
53 | template <class Iterator> static Iterator getBundleBegin(Iterator I) { |
54 | if (!I.isEnd()) |
55 | while (I->isBundledWithPred()) |
56 | --I; |
57 | return I; |
58 | } |
59 | |
60 | /// Get the final node of the current bundle. |
61 | template <class Iterator> static Iterator getBundleFinal(Iterator I) { |
62 | if (!I.isEnd()) |
63 | while (I->isBundledWithSucc()) |
64 | ++I; |
65 | return I; |
66 | } |
67 | |
68 | /// Increment forward ilist iterator. |
69 | template <class Iterator> static void increment(Iterator &I) { |
70 | I = std::next(getBundleFinal(I)); |
71 | } |
72 | |
73 | /// Decrement forward ilist iterator. |
74 | template <class Iterator> static void decrement(Iterator &I) { |
75 | I = getBundleBegin(std::prev(I)); |
76 | } |
77 | }; |
78 | |
79 | template <> struct MachineInstrBundleIteratorHelper<true> { |
80 | /// Get the beginning of the current bundle. |
81 | template <class Iterator> static Iterator getBundleBegin(Iterator I) { |
82 | return MachineInstrBundleIteratorHelper<false>::getBundleBegin( |
83 | I.getReverse()) |
84 | .getReverse(); |
85 | } |
86 | |
87 | /// Get the final node of the current bundle. |
88 | template <class Iterator> static Iterator getBundleFinal(Iterator I) { |
89 | return MachineInstrBundleIteratorHelper<false>::getBundleFinal( |
90 | I.getReverse()) |
91 | .getReverse(); |
92 | } |
93 | |
94 | /// Increment reverse ilist iterator. |
95 | template <class Iterator> static void increment(Iterator &I) { |
96 | I = getBundleBegin(std::next(I)); |
97 | } |
98 | |
99 | /// Decrement reverse ilist iterator. |
100 | template <class Iterator> static void decrement(Iterator &I) { |
101 | I = std::prev(getBundleFinal(I)); |
102 | } |
103 | }; |
104 | |
105 | /// MachineBasicBlock iterator that automatically skips over MIs that are |
106 | /// inside bundles (i.e. walk top level MIs only). |
107 | template <typename Ty, bool IsReverse = false> |
108 | class MachineInstrBundleIterator : MachineInstrBundleIteratorHelper<IsReverse> { |
109 | using Traits = MachineInstrBundleIteratorTraits<Ty, IsReverse>; |
110 | using instr_iterator = typename Traits::instr_iterator; |
111 | |
112 | instr_iterator MII; |
113 | |
114 | public: |
115 | using value_type = typename instr_iterator::value_type; |
116 | using difference_type = typename instr_iterator::difference_type; |
117 | using pointer = typename instr_iterator::pointer; |
118 | using reference = typename instr_iterator::reference; |
119 | using const_pointer = typename instr_iterator::const_pointer; |
120 | using const_reference = typename instr_iterator::const_reference; |
121 | using iterator_category = std::bidirectional_iterator_tag; |
122 | |
123 | private: |
124 | using nonconst_instr_iterator = typename Traits::nonconst_instr_iterator; |
125 | using const_instr_iterator = typename Traits::const_instr_iterator; |
126 | using nonconst_iterator = |
127 | MachineInstrBundleIterator<typename nonconst_instr_iterator::value_type, |
128 | IsReverse>; |
129 | using reverse_iterator = MachineInstrBundleIterator<Ty, !IsReverse>; |
130 | |
131 | public: |
132 | MachineInstrBundleIterator(instr_iterator MI) : MII(MI) { |
133 | assert((!MI.getNodePtr() || MI.isEnd() || !MI->isBundledWithPred()) &&(static_cast<void> (0)) |
134 | "It's not legal to initialize MachineInstrBundleIterator with a "(static_cast<void> (0)) |
135 | "bundled MI")(static_cast<void> (0)); |
136 | } |
137 | |
138 | MachineInstrBundleIterator(reference MI) : MII(MI) { |
139 | assert(!MI.isBundledWithPred() && "It's not legal to initialize "(static_cast<void> (0)) |
140 | "MachineInstrBundleIterator with a "(static_cast<void> (0)) |
141 | "bundled MI")(static_cast<void> (0)); |
142 | } |
143 | |
144 | MachineInstrBundleIterator(pointer MI) : MII(MI) { |
145 | // FIXME: This conversion should be explicit. |
146 | assert((!MI || !MI->isBundledWithPred()) && "It's not legal to initialize "(static_cast<void> (0)) |
147 | "MachineInstrBundleIterator "(static_cast<void> (0)) |
148 | "with a bundled MI")(static_cast<void> (0)); |
149 | } |
150 | |
151 | // Template allows conversion from const to nonconst. |
152 | template <class OtherTy> |
153 | MachineInstrBundleIterator( |
154 | const MachineInstrBundleIterator<OtherTy, IsReverse> &I, |
155 | std::enable_if_t<std::is_convertible<OtherTy *, Ty *>::value, void *> = |
156 | nullptr) |
157 | : MII(I.getInstrIterator()) {} |
158 | |
159 | MachineInstrBundleIterator() : MII(nullptr) {} |
160 | |
161 | /// Explicit conversion between forward/reverse iterators. |
162 | /// |
163 | /// Translate between forward and reverse iterators without changing range |
164 | /// boundaries. The resulting iterator will dereference (and have a handle) |
165 | /// to the previous node, which is somewhat unexpected; but converting the |
166 | /// two endpoints in a range will give the same range in reverse. |
167 | /// |
168 | /// This matches std::reverse_iterator conversions. |
169 | explicit MachineInstrBundleIterator( |
170 | const MachineInstrBundleIterator<Ty, !IsReverse> &I) |
171 | : MachineInstrBundleIterator(++I.getReverse()) {} |
172 | |
173 | /// Get the bundle iterator for the given instruction's bundle. |
174 | static MachineInstrBundleIterator getAtBundleBegin(instr_iterator MI) { |
175 | return MachineInstrBundleIteratorHelper<IsReverse>::getBundleBegin(MI); |
176 | } |
177 | |
178 | reference operator*() const { return *MII; } |
179 | pointer operator->() const { return &operator*(); } |
180 | |
181 | /// Check for null. |
182 | bool isValid() const { return MII.getNodePtr(); } |
183 | |
184 | friend bool operator==(const MachineInstrBundleIterator &L, |
185 | const MachineInstrBundleIterator &R) { |
186 | return L.MII == R.MII; |
187 | } |
188 | friend bool operator==(const MachineInstrBundleIterator &L, |
189 | const const_instr_iterator &R) { |
190 | return L.MII == R; // Avoid assertion about validity of R. |
191 | } |
192 | friend bool operator==(const const_instr_iterator &L, |
193 | const MachineInstrBundleIterator &R) { |
194 | return L == R.MII; // Avoid assertion about validity of L. |
195 | } |
196 | friend bool operator==(const MachineInstrBundleIterator &L, |
197 | const nonconst_instr_iterator &R) { |
198 | return L.MII == R; // Avoid assertion about validity of R. |
199 | } |
200 | friend bool operator==(const nonconst_instr_iterator &L, |
201 | const MachineInstrBundleIterator &R) { |
202 | return L == R.MII; // Avoid assertion about validity of L. |
203 | } |
204 | friend bool operator==(const MachineInstrBundleIterator &L, const_pointer R) { |
205 | return L == const_instr_iterator(R); // Avoid assertion about validity of R. |
206 | } |
207 | friend bool operator==(const_pointer L, const MachineInstrBundleIterator &R) { |
208 | return const_instr_iterator(L) == R; // Avoid assertion about validity of L. |
209 | } |
210 | friend bool operator==(const MachineInstrBundleIterator &L, |
211 | const_reference R) { |
212 | return L == &R; // Avoid assertion about validity of R. |
213 | } |
214 | friend bool operator==(const_reference L, |
215 | const MachineInstrBundleIterator &R) { |
216 | return &L == R; // Avoid assertion about validity of L. |
217 | } |
218 | |
219 | friend bool operator!=(const MachineInstrBundleIterator &L, |
220 | const MachineInstrBundleIterator &R) { |
221 | return !(L == R); |
222 | } |
223 | friend bool operator!=(const MachineInstrBundleIterator &L, |
224 | const const_instr_iterator &R) { |
225 | return !(L == R); |
226 | } |
227 | friend bool operator!=(const const_instr_iterator &L, |
228 | const MachineInstrBundleIterator &R) { |
229 | return !(L == R); |
230 | } |
231 | friend bool operator!=(const MachineInstrBundleIterator &L, |
232 | const nonconst_instr_iterator &R) { |
233 | return !(L == R); |
234 | } |
235 | friend bool operator!=(const nonconst_instr_iterator &L, |
236 | const MachineInstrBundleIterator &R) { |
237 | return !(L == R); |
238 | } |
239 | friend bool operator!=(const MachineInstrBundleIterator &L, const_pointer R) { |
240 | return !(L == R); |
241 | } |
242 | friend bool operator!=(const_pointer L, const MachineInstrBundleIterator &R) { |
243 | return !(L == R); |
244 | } |
245 | friend bool operator!=(const MachineInstrBundleIterator &L, |
246 | const_reference R) { |
247 | return !(L == R); |
248 | } |
249 | friend bool operator!=(const_reference L, |
250 | const MachineInstrBundleIterator &R) { |
251 | return !(L == R); |
252 | } |
253 | |
254 | // Increment and decrement operators... |
255 | MachineInstrBundleIterator &operator--() { |
256 | this->decrement(MII); |
257 | return *this; |
258 | } |
259 | MachineInstrBundleIterator &operator++() { |
260 | this->increment(MII); |
261 | return *this; |
262 | } |
263 | MachineInstrBundleIterator operator--(int) { |
264 | MachineInstrBundleIterator Temp = *this; |
265 | --*this; |
266 | return Temp; |
267 | } |
268 | MachineInstrBundleIterator operator++(int) { |
269 | MachineInstrBundleIterator Temp = *this; |
270 | ++*this; |
271 | return Temp; |
272 | } |
273 | |
274 | instr_iterator getInstrIterator() const { return MII; } |
275 | |
276 | nonconst_iterator getNonConstIterator() const { return MII.getNonConst(); } |
277 | |
278 | /// Get a reverse iterator to the same node. |
279 | /// |
280 | /// Gives a reverse iterator that will dereference (and have a handle) to the |
281 | /// same node. Converting the endpoint iterators in a range will give a |
282 | /// different range; for range operations, use the explicit conversions. |
283 | reverse_iterator getReverse() const { return MII.getReverse(); } |
284 | }; |
285 | |
286 | } // end namespace llvm |
287 | |
288 | #endif // LLVM_CODEGEN_MACHINEINSTRBUNDLEITERATOR_H |