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