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