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 VPBlockDeepTraversalWrapper { 224 BlockTy Entry; 225 226 public: 227 VPBlockDeepTraversalWrapper(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 <> struct GraphTraits<VPBlockDeepTraversalWrapper<VPBlockBase *>> { 237 using NodeRef = VPBlockBase *; 238 using ChildIteratorType = VPAllSuccessorsIterator<VPBlockBase *>; 239 240 static NodeRef getEntryNode(VPBlockDeepTraversalWrapper<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<VPBlockDeepTraversalWrapper<const VPBlockBase *>> { 255 using NodeRef = const VPBlockBase *; 256 using ChildIteratorType = VPAllSuccessorsIterator<const VPBlockBase *>; 257 258 static NodeRef 259 getEntryNode(VPBlockDeepTraversalWrapper<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 /// Helper for GraphTraits specialization that does not traverses through 273 /// VPRegionBlocks. 274 template <typename BlockTy> class VPBlockShallowTraversalWrapper { 275 BlockTy Entry; 276 277 public: 278 VPBlockShallowTraversalWrapper(BlockTy Entry) : Entry(Entry) {} 279 BlockTy getEntry() { return Entry; } 280 }; 281 282 template <> struct GraphTraits<VPBlockShallowTraversalWrapper<VPBlockBase *>> { 283 using NodeRef = VPBlockBase *; 284 using ChildIteratorType = SmallVectorImpl<VPBlockBase *>::iterator; 285 286 static NodeRef getEntryNode(VPBlockShallowTraversalWrapper<VPBlockBase *> N) { 287 return N.getEntry(); 288 } 289 290 static inline ChildIteratorType child_begin(NodeRef N) { 291 return N->getSuccessors().begin(); 292 } 293 294 static inline ChildIteratorType child_end(NodeRef N) { 295 return N->getSuccessors().end(); 296 } 297 }; 298 299 template <> 300 struct GraphTraits<VPBlockShallowTraversalWrapper<const VPBlockBase *>> { 301 using NodeRef = const VPBlockBase *; 302 using ChildIteratorType = SmallVectorImpl<VPBlockBase *>::const_iterator; 303 304 static NodeRef 305 getEntryNode(VPBlockShallowTraversalWrapper<const VPBlockBase *> N) { 306 return N.getEntry(); 307 } 308 309 static inline ChildIteratorType child_begin(NodeRef N) { 310 return N->getSuccessors().begin(); 311 } 312 313 static inline ChildIteratorType child_end(NodeRef N) { 314 return N->getSuccessors().end(); 315 } 316 }; 317 318 /// Returns an iterator range to traverse the graph starting at \p G in 319 /// depth-first order. The iterator won't traverse through region blocks. 320 inline iterator_range< 321 df_iterator<VPBlockShallowTraversalWrapper<VPBlockBase *>>> 322 vp_depth_first_shallow(VPBlockBase *G) { 323 return depth_first(VPBlockShallowTraversalWrapper<VPBlockBase *>(G)); 324 } 325 inline iterator_range< 326 df_iterator<VPBlockShallowTraversalWrapper<const VPBlockBase *>>> 327 vp_depth_first_shallow(const VPBlockBase *G) { 328 return depth_first(VPBlockShallowTraversalWrapper<const VPBlockBase *>(G)); 329 } 330 331 /// Returns an iterator range to traverse the graph starting at \p G in 332 /// depth-first order while traversing through region blocks. 333 inline iterator_range<df_iterator<VPBlockDeepTraversalWrapper<VPBlockBase *>>> 334 vp_depth_first_deep(VPBlockBase *G) { 335 return depth_first(VPBlockDeepTraversalWrapper<VPBlockBase *>(G)); 336 } 337 inline iterator_range< 338 df_iterator<VPBlockDeepTraversalWrapper<const VPBlockBase *>>> 339 vp_depth_first_deep(const VPBlockBase *G) { 340 return depth_first(VPBlockDeepTraversalWrapper<const VPBlockBase *>(G)); 341 } 342 343 } // namespace llvm 344 345 #endif // LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H 346