1 //===- VPlanCFG.h - GraphTraits for VP blocks -------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
8 /// Specializations of GraphTraits that allow VPBlockBase graphs to be
9 /// treated as proper graphs for generic algorithms;
10 //===----------------------------------------------------------------------===//
12 #ifndef LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H
13 #define LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H
16 #include "llvm/ADT/DepthFirstIterator.h"
17 #include "llvm/ADT/GraphTraits.h"
18 #include "llvm/ADT/SmallVector.h"
22 //===----------------------------------------------------------------------===//
23 // GraphTraits specializations for VPlan Hierarchical Control-Flow Graphs //
24 //===----------------------------------------------------------------------===//
26 /// Iterator to traverse all successors of a VPBlockBase node. This includes the
27 /// entry node of VPRegionBlocks. Exit blocks of a region implicitly have their
28 /// parent region's successors. This ensures all blocks in a region are visited
29 /// before any blocks in a successor region when doing a reverse post-order
30 // traversal of the graph. Region blocks themselves traverse only their entries
31 // directly and not their successors. Those will be traversed when a region's
32 // exiting block is traversed
33 template <typename BlockPtrTy
>
34 class VPAllSuccessorsIterator
35 : public iterator_facade_base
<VPAllSuccessorsIterator
<BlockPtrTy
>,
36 std::bidirectional_iterator_tag
,
39 /// Index of the current successor. For VPBasicBlock nodes, this simply is the
40 /// index for the successor array. For VPRegionBlock, SuccessorIdx == 0 is
41 /// used for the region's entry block, and SuccessorIdx - 1 are the indices
42 /// for the successor array.
45 static BlockPtrTy
getBlockWithSuccs(BlockPtrTy Current
) {
46 while (Current
&& Current
->getNumSuccessors() == 0)
47 Current
= Current
->getParent();
51 /// Templated helper to dereference successor \p SuccIdx of \p Block. Used by
52 /// both the const and non-const operator* implementations.
53 template <typename T1
> static T1
deref(T1 Block
, unsigned SuccIdx
) {
54 if (auto *R
= dyn_cast
<VPRegionBlock
>(Block
)) {
59 // For exit blocks, use the next parent region with successors.
60 return getBlockWithSuccs(Block
)->getSuccessors()[SuccIdx
];
64 /// Used by iterator_facade_base with bidirectional_iterator_tag.
65 using reference
= BlockPtrTy
;
67 VPAllSuccessorsIterator(BlockPtrTy Block
, size_t Idx
= 0)
68 : Block(Block
), SuccessorIdx(Idx
) {}
69 VPAllSuccessorsIterator(const VPAllSuccessorsIterator
&Other
)
70 : Block(Other
.Block
), SuccessorIdx(Other
.SuccessorIdx
) {}
72 VPAllSuccessorsIterator
&operator=(const VPAllSuccessorsIterator
&R
) {
74 SuccessorIdx
= R
.SuccessorIdx
;
78 static VPAllSuccessorsIterator
end(BlockPtrTy Block
) {
79 if (auto *R
= dyn_cast
<VPRegionBlock
>(Block
)) {
80 // Traverse through the region's entry node.
83 BlockPtrTy ParentWithSuccs
= getBlockWithSuccs(Block
);
84 unsigned NumSuccessors
=
85 ParentWithSuccs
? ParentWithSuccs
->getNumSuccessors() : 0;
86 return {Block
, NumSuccessors
};
89 bool operator==(const VPAllSuccessorsIterator
&R
) const {
90 return Block
== R
.Block
&& SuccessorIdx
== R
.SuccessorIdx
;
93 const VPBlockBase
*operator*() const { return deref(Block
, SuccessorIdx
); }
95 BlockPtrTy
operator*() { return deref(Block
, SuccessorIdx
); }
97 VPAllSuccessorsIterator
&operator++() {
102 VPAllSuccessorsIterator
&operator--() {
107 VPAllSuccessorsIterator
operator++(int X
) {
108 VPAllSuccessorsIterator Orig
= *this;
114 /// Helper for GraphTraits specialization that traverses through VPRegionBlocks.
115 template <typename BlockTy
> class VPBlockDeepTraversalWrapper
{
119 VPBlockDeepTraversalWrapper(BlockTy Entry
) : Entry(Entry
) {}
120 BlockTy
getEntry() { return Entry
; }
123 /// GraphTraits specialization to recursively traverse VPBlockBase nodes,
124 /// including traversing through VPRegionBlocks. Exit blocks of a region
125 /// implicitly have their parent region's successors. This ensures all blocks in
126 /// a region are visited before any blocks in a successor region when doing a
127 /// reverse post-order traversal of the graph.
128 template <> struct GraphTraits
<VPBlockDeepTraversalWrapper
<VPBlockBase
*>> {
129 using NodeRef
= VPBlockBase
*;
130 using ChildIteratorType
= VPAllSuccessorsIterator
<VPBlockBase
*>;
132 static NodeRef
getEntryNode(VPBlockDeepTraversalWrapper
<VPBlockBase
*> N
) {
136 static inline ChildIteratorType
child_begin(NodeRef N
) {
137 return ChildIteratorType(N
);
140 static inline ChildIteratorType
child_end(NodeRef N
) {
141 return ChildIteratorType::end(N
);
146 struct GraphTraits
<VPBlockDeepTraversalWrapper
<const VPBlockBase
*>> {
147 using NodeRef
= const VPBlockBase
*;
148 using ChildIteratorType
= VPAllSuccessorsIterator
<const VPBlockBase
*>;
151 getEntryNode(VPBlockDeepTraversalWrapper
<const VPBlockBase
*> N
) {
155 static inline ChildIteratorType
child_begin(NodeRef N
) {
156 return ChildIteratorType(N
);
159 static inline ChildIteratorType
child_end(NodeRef N
) {
160 return ChildIteratorType::end(N
);
164 /// Helper for GraphTraits specialization that does not traverses through
166 template <typename BlockTy
> class VPBlockShallowTraversalWrapper
{
170 VPBlockShallowTraversalWrapper(BlockTy Entry
) : Entry(Entry
) {}
171 BlockTy
getEntry() { return Entry
; }
174 template <> struct GraphTraits
<VPBlockShallowTraversalWrapper
<VPBlockBase
*>> {
175 using NodeRef
= VPBlockBase
*;
176 using ChildIteratorType
= SmallVectorImpl
<VPBlockBase
*>::iterator
;
178 static NodeRef
getEntryNode(VPBlockShallowTraversalWrapper
<VPBlockBase
*> N
) {
182 static inline ChildIteratorType
child_begin(NodeRef N
) {
183 return N
->getSuccessors().begin();
186 static inline ChildIteratorType
child_end(NodeRef N
) {
187 return N
->getSuccessors().end();
192 struct GraphTraits
<VPBlockShallowTraversalWrapper
<const VPBlockBase
*>> {
193 using NodeRef
= const VPBlockBase
*;
194 using ChildIteratorType
= SmallVectorImpl
<VPBlockBase
*>::const_iterator
;
197 getEntryNode(VPBlockShallowTraversalWrapper
<const VPBlockBase
*> N
) {
201 static inline ChildIteratorType
child_begin(NodeRef N
) {
202 return N
->getSuccessors().begin();
205 static inline ChildIteratorType
child_end(NodeRef N
) {
206 return N
->getSuccessors().end();
210 /// Returns an iterator range to traverse the graph starting at \p G in
211 /// depth-first order. The iterator won't traverse through region blocks.
212 inline iterator_range
<
213 df_iterator
<VPBlockShallowTraversalWrapper
<VPBlockBase
*>>>
214 vp_depth_first_shallow(VPBlockBase
*G
) {
215 return depth_first(VPBlockShallowTraversalWrapper
<VPBlockBase
*>(G
));
217 inline iterator_range
<
218 df_iterator
<VPBlockShallowTraversalWrapper
<const VPBlockBase
*>>>
219 vp_depth_first_shallow(const VPBlockBase
*G
) {
220 return depth_first(VPBlockShallowTraversalWrapper
<const VPBlockBase
*>(G
));
223 /// Returns an iterator range to traverse the graph starting at \p G in
224 /// depth-first order while traversing through region blocks.
225 inline iterator_range
<df_iterator
<VPBlockDeepTraversalWrapper
<VPBlockBase
*>>>
226 vp_depth_first_deep(VPBlockBase
*G
) {
227 return depth_first(VPBlockDeepTraversalWrapper
<VPBlockBase
*>(G
));
229 inline iterator_range
<
230 df_iterator
<VPBlockDeepTraversalWrapper
<const VPBlockBase
*>>>
231 vp_depth_first_deep(const VPBlockBase
*G
) {
232 return depth_first(VPBlockDeepTraversalWrapper
<const VPBlockBase
*>(G
));
235 // The following set of template specializations implement GraphTraits to treat
236 // any VPBlockBase as a node in a graph of VPBlockBases. It's important to note
237 // that VPBlockBase traits don't recurse into VPRegioBlocks, i.e., if the
238 // VPBlockBase is a VPRegionBlock, this specialization provides access to its
239 // successors/predecessors but not to the blocks inside the region.
241 template <> struct GraphTraits
<VPBlockBase
*> {
242 using NodeRef
= VPBlockBase
*;
243 using ChildIteratorType
= VPAllSuccessorsIterator
<VPBlockBase
*>;
245 static NodeRef
getEntryNode(NodeRef N
) { return N
; }
247 static inline ChildIteratorType
child_begin(NodeRef N
) {
248 return ChildIteratorType(N
);
251 static inline ChildIteratorType
child_end(NodeRef N
) {
252 return ChildIteratorType::end(N
);
256 template <> struct GraphTraits
<const VPBlockBase
*> {
257 using NodeRef
= const VPBlockBase
*;
258 using ChildIteratorType
= VPAllSuccessorsIterator
<const VPBlockBase
*>;
260 static NodeRef
getEntryNode(NodeRef N
) { return N
; }
262 static inline ChildIteratorType
child_begin(NodeRef N
) {
263 return ChildIteratorType(N
);
266 static inline ChildIteratorType
child_end(NodeRef N
) {
267 return ChildIteratorType::end(N
);
271 /// Inverse graph traits are not implemented yet.
272 /// TODO: Implement a version of VPBlockNonRecursiveTraversalWrapper to traverse
273 /// predecessors recursively through regions.
274 template <> struct GraphTraits
<Inverse
<VPBlockBase
*>> {
275 using NodeRef
= VPBlockBase
*;
276 using ChildIteratorType
= SmallVectorImpl
<VPBlockBase
*>::iterator
;
278 static NodeRef
getEntryNode(Inverse
<NodeRef
> B
) {
279 llvm_unreachable("not implemented");
282 static inline ChildIteratorType
child_begin(NodeRef N
) {
283 llvm_unreachable("not implemented");
286 static inline ChildIteratorType
child_end(NodeRef N
) {
287 llvm_unreachable("not implemented");
291 template <> struct GraphTraits
<VPlan
*> {
292 using GraphRef
= VPlan
*;
293 using NodeRef
= VPBlockBase
*;
294 using nodes_iterator
= df_iterator
<NodeRef
>;
296 static NodeRef
getEntryNode(GraphRef N
) { return N
->getEntry(); }
298 static nodes_iterator
nodes_begin(GraphRef N
) {
299 return nodes_iterator::begin(N
->getEntry());
302 static nodes_iterator
nodes_end(GraphRef N
) {
303 // df_iterator::end() returns an empty iterator so the node used doesn't
305 return nodes_iterator::end(N
->getEntry());
309 inline auto VPlan::getExitBlocks() {
310 VPBlockBase
*ScalarHeader
= getScalarHeader();
311 return make_filter_range(
312 VPBlockUtils::blocksOnly
<VPIRBasicBlock
>(
313 vp_depth_first_shallow(getVectorLoopRegion()->getSingleSuccessor())),
314 [ScalarHeader
](VPIRBasicBlock
*VPIRBB
) {
315 return VPIRBB
!= ScalarHeader
&& VPIRBB
->getNumSuccessors() == 0;
320 #endif // LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H