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 getBlockWithSuccs(BlockPtrTy Current)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. deref(T1 Block,unsigned SuccIdx)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(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) Block(Block)70 : Block(Block), SuccessorIdx(Idx) {} VPAllSuccessorsIterator(const VPAllSuccessorsIterator & Other)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 end(BlockPtrTy Block)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(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: VPBlockDeepTraversalWrapper(BlockTy Entry)121 VPBlockDeepTraversalWrapper(BlockTy Entry) : Entry(Entry) {} getEntry()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(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(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(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(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(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(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(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(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(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(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(N->getEntry()); 316 } 317 }; 318 319 } // namespace llvm 320 321 #endif // LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H 322