1 | //===- VPlanCFG.h - GraphTraits for VP blocks -------------------*- 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 | /// Specializations of GraphTraits that allow VPBlockBase graphs to be |
9 | /// treated as proper graphs for generic algorithms; |
10 | //===----------------------------------------------------------------------===// |
11 | |
12 | #ifndef LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H |
13 | #define LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H |
14 | |
15 | #include "VPlan.h" |
16 | #include "llvm/ADT/DepthFirstIterator.h" |
17 | #include "llvm/ADT/GraphTraits.h" |
18 | #include "llvm/ADT/SmallVector.h" |
19 | |
20 | namespace llvm { |
21 | |
22 | //===----------------------------------------------------------------------===// |
23 | // GraphTraits specializations for VPlan Hierarchical Control-Flow Graphs // |
24 | //===----------------------------------------------------------------------===// |
25 | |
26 | /// Iterator to traverse all successors of a VPBlockBase node. This includes the |
27 | /// entry node of VPRegionBlocks. Exit blocks of a region implicitly have their |
28 | /// parent region's successors. This ensures all blocks in a region are visited |
29 | /// before any blocks in a successor region when doing a reverse post-order |
30 | // traversal of the graph. Region blocks themselves traverse only their entries |
31 | // directly and not their successors. Those will be traversed when a region's |
32 | // exiting block is traversed |
33 | template <typename BlockPtrTy> |
34 | class VPAllSuccessorsIterator |
35 | : public iterator_facade_base<VPAllSuccessorsIterator<BlockPtrTy>, |
36 | std::bidirectional_iterator_tag, |
37 | VPBlockBase> { |
38 | BlockPtrTy Block; |
39 | /// Index of the current successor. For VPBasicBlock nodes, this simply is the |
40 | /// index for the successor array. For VPRegionBlock, SuccessorIdx == 0 is |
41 | /// used for the region's entry block, and SuccessorIdx - 1 are the indices |
42 | /// for the successor array. |
43 | size_t SuccessorIdx; |
44 | |
45 | static BlockPtrTy getBlockWithSuccs(BlockPtrTy Current) { |
46 | while (Current && Current->getNumSuccessors() == 0) |
47 | Current = Current->getParent(); |
48 | return Current; |
49 | } |
50 | |
51 | /// Templated helper to dereference successor \p SuccIdx of \p Block. Used by |
52 | /// both the const and non-const operator* implementations. |
53 | template <typename T1> static T1 deref(T1 Block, unsigned SuccIdx) { |
54 | if (auto *R = dyn_cast<VPRegionBlock>(Block)) { |
55 | assert(SuccIdx == 0); |
56 | return R->getEntry(); |
57 | } |
58 | |
59 | // For exit blocks, use the next parent region with successors. |
60 | return getBlockWithSuccs(Current: Block)->getSuccessors()[SuccIdx]; |
61 | } |
62 | |
63 | public: |
64 | /// Used by iterator_facade_base with bidirectional_iterator_tag. |
65 | using reference = BlockPtrTy; |
66 | |
67 | VPAllSuccessorsIterator(BlockPtrTy Block, size_t Idx = 0) |
68 | : Block(Block), SuccessorIdx(Idx) {} |
69 | VPAllSuccessorsIterator(const VPAllSuccessorsIterator &Other) |
70 | : Block(Other.Block), SuccessorIdx(Other.SuccessorIdx) {} |
71 | |
72 | VPAllSuccessorsIterator &operator=(const VPAllSuccessorsIterator &R) { |
73 | Block = R.Block; |
74 | SuccessorIdx = R.SuccessorIdx; |
75 | return *this; |
76 | } |
77 | |
78 | static VPAllSuccessorsIterator end(BlockPtrTy Block) { |
79 | if (auto *R = dyn_cast<VPRegionBlock>(Block)) { |
80 | // Traverse through the region's entry node. |
81 | return {R, 1}; |
82 | } |
83 | BlockPtrTy ParentWithSuccs = getBlockWithSuccs(Current: Block); |
84 | unsigned NumSuccessors = |
85 | ParentWithSuccs ? ParentWithSuccs->getNumSuccessors() : 0; |
86 | return {Block, NumSuccessors}; |
87 | } |
88 | |
89 | bool operator==(const VPAllSuccessorsIterator &R) const { |
90 | return Block == R.Block && SuccessorIdx == R.SuccessorIdx; |
91 | } |
92 | |
93 | const VPBlockBase *operator*() const { return deref(Block, SuccessorIdx); } |
94 | |
95 | BlockPtrTy operator*() { return deref(Block, SuccessorIdx); } |
96 | |
97 | VPAllSuccessorsIterator &operator++() { |
98 | SuccessorIdx++; |
99 | return *this; |
100 | } |
101 | |
102 | VPAllSuccessorsIterator &operator--() { |
103 | SuccessorIdx--; |
104 | return *this; |
105 | } |
106 | |
107 | VPAllSuccessorsIterator operator++(int X) { |
108 | VPAllSuccessorsIterator Orig = *this; |
109 | SuccessorIdx++; |
110 | return Orig; |
111 | } |
112 | }; |
113 | |
114 | /// Helper for GraphTraits specialization that traverses through VPRegionBlocks. |
115 | template <typename BlockTy> class VPBlockDeepTraversalWrapper { |
116 | BlockTy Entry; |
117 | |
118 | public: |
119 | VPBlockDeepTraversalWrapper(BlockTy Entry) : Entry(Entry) {} |
120 | BlockTy getEntry() { return Entry; } |
121 | }; |
122 | |
123 | /// GraphTraits specialization to recursively traverse VPBlockBase nodes, |
124 | /// including traversing through VPRegionBlocks. Exit blocks of a region |
125 | /// implicitly have their parent region's successors. This ensures all blocks in |
126 | /// a region are visited before any blocks in a successor region when doing a |
127 | /// reverse post-order traversal of the graph. |
128 | template <> struct GraphTraits<VPBlockDeepTraversalWrapper<VPBlockBase *>> { |
129 | using NodeRef = VPBlockBase *; |
130 | using ChildIteratorType = VPAllSuccessorsIterator<VPBlockBase *>; |
131 | |
132 | static NodeRef getEntryNode(VPBlockDeepTraversalWrapper<VPBlockBase *> N) { |
133 | return N.getEntry(); |
134 | } |
135 | |
136 | static inline ChildIteratorType child_begin(NodeRef N) { |
137 | return ChildIteratorType(N); |
138 | } |
139 | |
140 | static inline ChildIteratorType child_end(NodeRef N) { |
141 | return ChildIteratorType::end(Block: N); |
142 | } |
143 | }; |
144 | |
145 | template <> |
146 | struct GraphTraits<VPBlockDeepTraversalWrapper<const VPBlockBase *>> { |
147 | using NodeRef = const VPBlockBase *; |
148 | using ChildIteratorType = VPAllSuccessorsIterator<const VPBlockBase *>; |
149 | |
150 | static NodeRef |
151 | getEntryNode(VPBlockDeepTraversalWrapper<const VPBlockBase *> N) { |
152 | return N.getEntry(); |
153 | } |
154 | |
155 | static inline ChildIteratorType child_begin(NodeRef N) { |
156 | return ChildIteratorType(N); |
157 | } |
158 | |
159 | static inline ChildIteratorType child_end(NodeRef N) { |
160 | return ChildIteratorType::end(Block: N); |
161 | } |
162 | }; |
163 | |
164 | /// Helper for GraphTraits specialization that does not traverses through |
165 | /// VPRegionBlocks. |
166 | template <typename BlockTy> class VPBlockShallowTraversalWrapper { |
167 | BlockTy Entry; |
168 | |
169 | public: |
170 | VPBlockShallowTraversalWrapper(BlockTy Entry) : Entry(Entry) {} |
171 | BlockTy getEntry() { return Entry; } |
172 | }; |
173 | |
174 | template <> struct GraphTraits<VPBlockShallowTraversalWrapper<VPBlockBase *>> { |
175 | using NodeRef = VPBlockBase *; |
176 | using ChildIteratorType = SmallVectorImpl<VPBlockBase *>::iterator; |
177 | |
178 | static NodeRef getEntryNode(VPBlockShallowTraversalWrapper<VPBlockBase *> N) { |
179 | return N.getEntry(); |
180 | } |
181 | |
182 | static inline ChildIteratorType child_begin(NodeRef N) { |
183 | return N->getSuccessors().begin(); |
184 | } |
185 | |
186 | static inline ChildIteratorType child_end(NodeRef N) { |
187 | return N->getSuccessors().end(); |
188 | } |
189 | }; |
190 | |
191 | template <> |
192 | struct GraphTraits<VPBlockShallowTraversalWrapper<const VPBlockBase *>> { |
193 | using NodeRef = const VPBlockBase *; |
194 | using ChildIteratorType = SmallVectorImpl<VPBlockBase *>::const_iterator; |
195 | |
196 | static NodeRef |
197 | getEntryNode(VPBlockShallowTraversalWrapper<const VPBlockBase *> N) { |
198 | return N.getEntry(); |
199 | } |
200 | |
201 | static inline ChildIteratorType child_begin(NodeRef N) { |
202 | return N->getSuccessors().begin(); |
203 | } |
204 | |
205 | static inline ChildIteratorType child_end(NodeRef N) { |
206 | return N->getSuccessors().end(); |
207 | } |
208 | }; |
209 | |
210 | /// Returns an iterator range to traverse the graph starting at \p G in |
211 | /// depth-first order. The iterator won't traverse through region blocks. |
212 | inline iterator_range< |
213 | df_iterator<VPBlockShallowTraversalWrapper<VPBlockBase *>>> |
214 | vp_depth_first_shallow(VPBlockBase *G) { |
215 | return depth_first(G: VPBlockShallowTraversalWrapper<VPBlockBase *>(G)); |
216 | } |
217 | inline iterator_range< |
218 | df_iterator<VPBlockShallowTraversalWrapper<const VPBlockBase *>>> |
219 | vp_depth_first_shallow(const VPBlockBase *G) { |
220 | return depth_first(G: VPBlockShallowTraversalWrapper<const VPBlockBase *>(G)); |
221 | } |
222 | |
223 | /// Returns an iterator range to traverse the graph starting at \p G in |
224 | /// depth-first order while traversing through region blocks. |
225 | inline iterator_range<df_iterator<VPBlockDeepTraversalWrapper<VPBlockBase *>>> |
226 | vp_depth_first_deep(VPBlockBase *G) { |
227 | return depth_first(G: VPBlockDeepTraversalWrapper<VPBlockBase *>(G)); |
228 | } |
229 | inline iterator_range< |
230 | df_iterator<VPBlockDeepTraversalWrapper<const VPBlockBase *>>> |
231 | vp_depth_first_deep(const VPBlockBase *G) { |
232 | return depth_first(G: VPBlockDeepTraversalWrapper<const VPBlockBase *>(G)); |
233 | } |
234 | |
235 | // The following set of template specializations implement GraphTraits to treat |
236 | // any VPBlockBase as a node in a graph of VPBlockBases. It's important to note |
237 | // that VPBlockBase traits don't recurse into VPRegioBlocks, i.e., if the |
238 | // VPBlockBase is a VPRegionBlock, this specialization provides access to its |
239 | // successors/predecessors but not to the blocks inside the region. |
240 | |
241 | template <> struct GraphTraits<VPBlockBase *> { |
242 | using NodeRef = VPBlockBase *; |
243 | using ChildIteratorType = VPAllSuccessorsIterator<VPBlockBase *>; |
244 | |
245 | static NodeRef getEntryNode(NodeRef N) { return N; } |
246 | |
247 | static inline ChildIteratorType child_begin(NodeRef N) { |
248 | return ChildIteratorType(N); |
249 | } |
250 | |
251 | static inline ChildIteratorType child_end(NodeRef N) { |
252 | return ChildIteratorType::end(Block: N); |
253 | } |
254 | }; |
255 | |
256 | template <> struct GraphTraits<const VPBlockBase *> { |
257 | using NodeRef = const VPBlockBase *; |
258 | using ChildIteratorType = VPAllSuccessorsIterator<const VPBlockBase *>; |
259 | |
260 | static NodeRef getEntryNode(NodeRef N) { return N; } |
261 | |
262 | static inline ChildIteratorType child_begin(NodeRef N) { |
263 | return ChildIteratorType(N); |
264 | } |
265 | |
266 | static inline ChildIteratorType child_end(NodeRef N) { |
267 | return ChildIteratorType::end(Block: N); |
268 | } |
269 | }; |
270 | |
271 | /// Inverse graph traits are not implemented yet. |
272 | /// TODO: Implement a version of VPBlockNonRecursiveTraversalWrapper to traverse |
273 | /// predecessors recursively through regions. |
274 | template <> struct GraphTraits<Inverse<VPBlockBase *>> { |
275 | using NodeRef = VPBlockBase *; |
276 | using ChildIteratorType = SmallVectorImpl<VPBlockBase *>::iterator; |
277 | |
278 | static NodeRef getEntryNode(Inverse<NodeRef> B) { |
279 | llvm_unreachable("not implemented" ); |
280 | } |
281 | |
282 | static inline ChildIteratorType child_begin(NodeRef N) { |
283 | llvm_unreachable("not implemented" ); |
284 | } |
285 | |
286 | static inline ChildIteratorType child_end(NodeRef N) { |
287 | llvm_unreachable("not implemented" ); |
288 | } |
289 | }; |
290 | |
291 | template <> struct GraphTraits<VPlan *> { |
292 | using GraphRef = VPlan *; |
293 | using NodeRef = VPBlockBase *; |
294 | using nodes_iterator = df_iterator<NodeRef>; |
295 | |
296 | static NodeRef getEntryNode(GraphRef N) { return N->getEntry(); } |
297 | |
298 | static nodes_iterator nodes_begin(GraphRef N) { |
299 | return nodes_iterator::begin(G: N->getEntry()); |
300 | } |
301 | |
302 | static nodes_iterator nodes_end(GraphRef N) { |
303 | // df_iterator::end() returns an empty iterator so the node used doesn't |
304 | // matter. |
305 | return nodes_iterator::end(G: N->getEntry()); |
306 | } |
307 | }; |
308 | |
309 | } // namespace llvm |
310 | |
311 | #endif // LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H |
312 | |