xref: /llvm-project/llvm/lib/Transforms/Vectorize/VPlanCFG.h (revision feee22db52259d19a8624318517ef5688abfc67c)
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. Region blocks themselves traverse only their entries
148 // directly and not their successors. Those will be traversed when a region's
149 // exiting block is traversed
150 template <typename BlockPtrTy>
151 class VPAllSuccessorsIterator
152     : public iterator_facade_base<VPAllSuccessorsIterator<BlockPtrTy>,
153                                   std::forward_iterator_tag, VPBlockBase> {
154   BlockPtrTy Block;
155   /// Index of the current successor. For VPBasicBlock nodes, this simply is the
156   /// index for the successor array. For VPRegionBlock, SuccessorIdx == 0 is
157   /// used for the region's entry block, and SuccessorIdx - 1 are the indices
158   /// for the successor array.
159   size_t SuccessorIdx;
160 
161   static BlockPtrTy getBlockWithSuccs(BlockPtrTy Current) {
162     while (Current && Current->getNumSuccessors() == 0)
163       Current = Current->getParent();
164     return Current;
165   }
166 
167   /// Templated helper to dereference successor \p SuccIdx of \p Block. Used by
168   /// both the const and non-const operator* implementations.
169   template <typename T1> static T1 deref(T1 Block, unsigned SuccIdx) {
170     if (auto *R = dyn_cast<VPRegionBlock>(Block)) {
171       assert(SuccIdx == 0);
172       return R->getEntry();
173     }
174 
175     // For exit blocks, use the next parent region with successors.
176     return getBlockWithSuccs(Block)->getSuccessors()[SuccIdx];
177   }
178 
179 public:
180   VPAllSuccessorsIterator(BlockPtrTy Block, size_t Idx = 0)
181       : Block(Block), SuccessorIdx(Idx) {}
182   VPAllSuccessorsIterator(const VPAllSuccessorsIterator &Other)
183       : Block(Other.Block), SuccessorIdx(Other.SuccessorIdx) {}
184 
185   VPAllSuccessorsIterator &operator=(const VPAllSuccessorsIterator &R) {
186     Block = R.Block;
187     SuccessorIdx = R.SuccessorIdx;
188     return *this;
189   }
190 
191   static VPAllSuccessorsIterator end(BlockPtrTy Block) {
192     if (auto *R = dyn_cast<VPRegionBlock>(Block)) {
193       // Traverse through the region's entry node.
194       return {R, 1};
195     }
196     BlockPtrTy ParentWithSuccs = getBlockWithSuccs(Block);
197     unsigned NumSuccessors =
198         ParentWithSuccs ? ParentWithSuccs->getNumSuccessors() : 0;
199     return {Block, NumSuccessors};
200   }
201 
202   bool operator==(const VPAllSuccessorsIterator &R) const {
203     return Block == R.Block && SuccessorIdx == R.SuccessorIdx;
204   }
205 
206   const VPBlockBase *operator*() const { return deref(Block, SuccessorIdx); }
207 
208   BlockPtrTy operator*() { return deref(Block, SuccessorIdx); }
209 
210   VPAllSuccessorsIterator &operator++() {
211     SuccessorIdx++;
212     return *this;
213   }
214 
215   VPAllSuccessorsIterator operator++(int X) {
216     VPAllSuccessorsIterator Orig = *this;
217     SuccessorIdx++;
218     return Orig;
219   }
220 };
221 
222 /// Helper for GraphTraits specialization that traverses through VPRegionBlocks.
223 template <typename BlockTy> class VPBlockRecursiveTraversalWrapper {
224   BlockTy Entry;
225 
226 public:
227   VPBlockRecursiveTraversalWrapper(BlockTy Entry) : Entry(Entry) {}
228   BlockTy getEntry() { return Entry; }
229 };
230 
231 /// GraphTraits specialization to recursively traverse VPBlockBase nodes,
232 /// including traversing through VPRegionBlocks.  Exit blocks of a region
233 /// implicitly have their parent region's successors. This ensures all blocks in
234 /// a region are visited before any blocks in a successor region when doing a
235 /// reverse post-order traversal of the graph.
236 template <>
237 struct GraphTraits<VPBlockRecursiveTraversalWrapper<VPBlockBase *>> {
238   using NodeRef = VPBlockBase *;
239   using ChildIteratorType = VPAllSuccessorsIterator<VPBlockBase *>;
240 
241   static NodeRef
242   getEntryNode(VPBlockRecursiveTraversalWrapper<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<VPBlockRecursiveTraversalWrapper<const VPBlockBase *>> {
257   using NodeRef = const VPBlockBase *;
258   using ChildIteratorType = VPAllSuccessorsIterator<const VPBlockBase *>;
259 
260   static NodeRef
261   getEntryNode(VPBlockRecursiveTraversalWrapper<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 } // namespace llvm
275 
276 #endif // LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H
277