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 VPBlockRecursiveTraversalWrapper { 224 BlockTy Entry; 225 226 public: 227 VPBlockRecursiveTraversalWrapper(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 <> 237 struct GraphTraits<VPBlockRecursiveTraversalWrapper<VPBlockBase *>> { 238 using NodeRef = VPBlockBase *; 239 using ChildIteratorType = VPAllSuccessorsIterator<VPBlockBase *>; 240 241 static NodeRef 242 getEntryNode(VPBlockRecursiveTraversalWrapper<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<VPBlockRecursiveTraversalWrapper<const VPBlockBase *>> { 257 using NodeRef = const VPBlockBase *; 258 using ChildIteratorType = VPAllSuccessorsIterator<const VPBlockBase *>; 259 260 static NodeRef 261 getEntryNode(VPBlockRecursiveTraversalWrapper<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 } // namespace llvm 275 276 #endif // LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H 277