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