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