xref: /llvm-project/llvm/lib/Transforms/Vectorize/VPlanCFG.h (revision c95138392a75021c98f53b423b29995cb8a3283b)
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 NodeRef = VPBlockBase *;
33   using ChildIteratorType = SmallVectorImpl<VPBlockBase *>::iterator;
34 
35   static NodeRef getEntryNode(NodeRef N) { return N; }
36 
37   static inline ChildIteratorType child_begin(NodeRef N) {
38     return N->getSuccessors().begin();
39   }
40 
41   static inline ChildIteratorType child_end(NodeRef N) {
42     return N->getSuccessors().end();
43   }
44 };
45 
46 template <> struct GraphTraits<const VPBlockBase *> {
47   using NodeRef = const VPBlockBase *;
48   using ChildIteratorType = SmallVectorImpl<VPBlockBase *>::const_iterator;
49 
50   static NodeRef getEntryNode(NodeRef N) { return N; }
51 
52   static inline ChildIteratorType child_begin(NodeRef N) {
53     return N->getSuccessors().begin();
54   }
55 
56   static inline ChildIteratorType child_end(NodeRef N) {
57     return N->getSuccessors().end();
58   }
59 };
60 
61 // Inverse order specialization for VPBasicBlocks. Predecessors are used instead
62 // of successors for the inverse traversal.
63 template <> struct GraphTraits<Inverse<VPBlockBase *>> {
64   using NodeRef = VPBlockBase *;
65   using ChildIteratorType = SmallVectorImpl<VPBlockBase *>::iterator;
66 
67   static NodeRef getEntryNode(Inverse<NodeRef> B) { return B.Graph; }
68 
69   static inline ChildIteratorType child_begin(NodeRef N) {
70     return N->getPredecessors().begin();
71   }
72 
73   static inline ChildIteratorType child_end(NodeRef N) {
74     return N->getPredecessors().end();
75   }
76 };
77 
78 // The following set of template specializations implement GraphTraits to
79 // treat VPRegionBlock as a graph and recurse inside its nodes. It's important
80 // to note that the blocks inside the VPRegionBlock are treated as VPBlockBases
81 // (i.e., no dyn_cast is performed, VPBlockBases specialization is used), so
82 // there won't be automatic recursion into other VPBlockBases that turn to be
83 // VPRegionBlocks.
84 
85 template <>
86 struct GraphTraits<VPRegionBlock *> : public GraphTraits<VPBlockBase *> {
87   using GraphRef = VPRegionBlock *;
88   using nodes_iterator = df_iterator<NodeRef>;
89 
90   static NodeRef getEntryNode(GraphRef N) { return N->getEntry(); }
91 
92   static nodes_iterator nodes_begin(GraphRef N) {
93     return nodes_iterator::begin(N->getEntry());
94   }
95 
96   static nodes_iterator nodes_end(GraphRef N) {
97     // df_iterator::end() returns an empty iterator so the node used doesn't
98     // matter.
99     return nodes_iterator::end(N);
100   }
101 };
102 
103 template <>
104 struct GraphTraits<const VPRegionBlock *>
105     : public GraphTraits<const VPBlockBase *> {
106   using GraphRef = const VPRegionBlock *;
107   using nodes_iterator = df_iterator<NodeRef>;
108 
109   static NodeRef getEntryNode(GraphRef N) { return N->getEntry(); }
110 
111   static nodes_iterator nodes_begin(GraphRef N) {
112     return nodes_iterator::begin(N->getEntry());
113   }
114 
115   static nodes_iterator nodes_end(GraphRef N) {
116     // df_iterator::end() returns an empty iterator so the node used doesn't
117     // matter.
118     return nodes_iterator::end(N);
119   }
120 };
121 
122 template <>
123 struct GraphTraits<Inverse<VPRegionBlock *>>
124     : public GraphTraits<Inverse<VPBlockBase *>> {
125   using GraphRef = VPRegionBlock *;
126   using nodes_iterator = df_iterator<NodeRef>;
127 
128   static NodeRef getEntryNode(Inverse<GraphRef> N) {
129     return N.Graph->getExiting();
130   }
131 
132   static nodes_iterator nodes_begin(GraphRef N) {
133     return nodes_iterator::begin(N->getExiting());
134   }
135 
136   static nodes_iterator nodes_end(GraphRef N) {
137     // df_iterator::end() returns an empty iterator so the node used doesn't
138     // matter.
139     return nodes_iterator::end(N);
140   }
141 };
142 
143 /// Iterator to traverse all successors of a VPBlockBase node. This includes the
144 /// entry node of VPRegionBlocks. Exit blocks of a region implicitly have their
145 /// parent region's successors. This ensures all blocks in a region are visited
146 /// before any blocks in a successor region when doing a reverse post-order
147 // traversal of the graph.
148 template <typename BlockPtrTy>
149 class VPAllSuccessorsIterator
150     : public iterator_facade_base<VPAllSuccessorsIterator<BlockPtrTy>,
151                                   std::forward_iterator_tag, VPBlockBase> {
152   BlockPtrTy Block;
153   /// Index of the current successor. For VPBasicBlock nodes, this simply is the
154   /// index for the successor array. For VPRegionBlock, SuccessorIdx == 0 is
155   /// used for the region's entry block, and SuccessorIdx - 1 are the indices
156   /// for the successor array.
157   size_t SuccessorIdx;
158 
159   static BlockPtrTy getBlockWithSuccs(BlockPtrTy Current) {
160     while (Current && Current->getNumSuccessors() == 0)
161       Current = Current->getParent();
162     return Current;
163   }
164 
165   /// Templated helper to dereference successor \p SuccIdx of \p Block. Used by
166   /// both the const and non-const operator* implementations.
167   template <typename T1> static T1 deref(T1 Block, unsigned SuccIdx) {
168     if (auto *R = dyn_cast<VPRegionBlock>(Block)) {
169       if (SuccIdx == 0)
170         return R->getEntry();
171       SuccIdx--;
172     }
173 
174     // For exit blocks, use the next parent region with successors.
175     return getBlockWithSuccs(Block)->getSuccessors()[SuccIdx];
176   }
177 
178 public:
179   VPAllSuccessorsIterator(BlockPtrTy Block, size_t Idx = 0)
180       : Block(Block), SuccessorIdx(Idx) {}
181   VPAllSuccessorsIterator(const VPAllSuccessorsIterator &Other)
182       : Block(Other.Block), SuccessorIdx(Other.SuccessorIdx) {}
183 
184   VPAllSuccessorsIterator &operator=(const VPAllSuccessorsIterator &R) {
185     Block = R.Block;
186     SuccessorIdx = R.SuccessorIdx;
187     return *this;
188   }
189 
190   static VPAllSuccessorsIterator end(BlockPtrTy Block) {
191     BlockPtrTy ParentWithSuccs = getBlockWithSuccs(Block);
192     unsigned NumSuccessors =
193         ParentWithSuccs ? ParentWithSuccs->getNumSuccessors() : 0;
194 
195     if (auto *R = dyn_cast<VPRegionBlock>(Block))
196       return {R, NumSuccessors + 1};
197     return {Block, NumSuccessors};
198   }
199 
200   bool operator==(const VPAllSuccessorsIterator &R) const {
201     return Block == R.Block && SuccessorIdx == R.SuccessorIdx;
202   }
203 
204   const VPBlockBase *operator*() const { return deref(Block, SuccessorIdx); }
205 
206   BlockPtrTy operator*() { return deref(Block, SuccessorIdx); }
207 
208   VPAllSuccessorsIterator &operator++() {
209     SuccessorIdx++;
210     return *this;
211   }
212 
213   VPAllSuccessorsIterator operator++(int X) {
214     VPAllSuccessorsIterator Orig = *this;
215     SuccessorIdx++;
216     return Orig;
217   }
218 };
219 
220 /// Helper for GraphTraits specialization that traverses through VPRegionBlocks.
221 template <typename BlockTy> class VPBlockRecursiveTraversalWrapper {
222   BlockTy Entry;
223 
224 public:
225   VPBlockRecursiveTraversalWrapper(BlockTy Entry) : Entry(Entry) {}
226   BlockTy getEntry() { return Entry; }
227 };
228 
229 /// GraphTraits specialization to recursively traverse VPBlockBase nodes,
230 /// including traversing through VPRegionBlocks.  Exit blocks of a region
231 /// implicitly have their parent region's successors. This ensures all blocks in
232 /// a region are visited before any blocks in a successor region when doing a
233 /// reverse post-order traversal of the graph.
234 template <>
235 struct GraphTraits<VPBlockRecursiveTraversalWrapper<VPBlockBase *>> {
236   using NodeRef = VPBlockBase *;
237   using ChildIteratorType = VPAllSuccessorsIterator<VPBlockBase *>;
238 
239   static NodeRef
240   getEntryNode(VPBlockRecursiveTraversalWrapper<VPBlockBase *> N) {
241     return N.getEntry();
242   }
243 
244   static inline ChildIteratorType child_begin(NodeRef N) {
245     return ChildIteratorType(N);
246   }
247 
248   static inline ChildIteratorType child_end(NodeRef N) {
249     return ChildIteratorType::end(N);
250   }
251 };
252 
253 template <>
254 struct GraphTraits<VPBlockRecursiveTraversalWrapper<const VPBlockBase *>> {
255   using NodeRef = const VPBlockBase *;
256   using ChildIteratorType = VPAllSuccessorsIterator<const VPBlockBase *>;
257 
258   static NodeRef
259   getEntryNode(VPBlockRecursiveTraversalWrapper<const VPBlockBase *> N) {
260     return N.getEntry();
261   }
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 } // namespace llvm
273 
274 #endif // LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H
275