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