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