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