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