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. 148 template <typename BlockPtrTy> 149 class VPAllSuccessorsIterator 150 : public iterator_facade_base<VPAllSuccessorsIterator<BlockPtrTy>, 151 std::forward_iterator_tag, VPBlockBase> { 152 BlockPtrTy Block; 153 /// Index of the current successor. For VPBasicBlock nodes, this simply is the 154 /// index for the successor array. For VPRegionBlock, SuccessorIdx == 0 is 155 /// used for the region's entry block, and SuccessorIdx - 1 are the indices 156 /// for the successor array. 157 size_t SuccessorIdx; 158 159 static BlockPtrTy getBlockWithSuccs(BlockPtrTy Current) { 160 while (Current && Current->getNumSuccessors() == 0) 161 Current = Current->getParent(); 162 return Current; 163 } 164 165 /// Templated helper to dereference successor \p SuccIdx of \p Block. Used by 166 /// both the const and non-const operator* implementations. 167 template <typename T1> static T1 deref(T1 Block, unsigned SuccIdx) { 168 if (auto *R = dyn_cast<VPRegionBlock>(Block)) { 169 if (SuccIdx == 0) 170 return R->getEntry(); 171 SuccIdx--; 172 } 173 174 // For exit blocks, use the next parent region with successors. 175 return getBlockWithSuccs(Block)->getSuccessors()[SuccIdx]; 176 } 177 178 public: 179 VPAllSuccessorsIterator(BlockPtrTy Block, size_t Idx = 0) 180 : Block(Block), SuccessorIdx(Idx) {} 181 VPAllSuccessorsIterator(const VPAllSuccessorsIterator &Other) 182 : Block(Other.Block), SuccessorIdx(Other.SuccessorIdx) {} 183 184 VPAllSuccessorsIterator &operator=(const VPAllSuccessorsIterator &R) { 185 Block = R.Block; 186 SuccessorIdx = R.SuccessorIdx; 187 return *this; 188 } 189 190 static VPAllSuccessorsIterator end(BlockPtrTy Block) { 191 BlockPtrTy ParentWithSuccs = getBlockWithSuccs(Block); 192 unsigned NumSuccessors = 193 ParentWithSuccs ? ParentWithSuccs->getNumSuccessors() : 0; 194 195 if (auto *R = dyn_cast<VPRegionBlock>(Block)) 196 return {R, NumSuccessors + 1}; 197 return {Block, NumSuccessors}; 198 } 199 200 bool operator==(const VPAllSuccessorsIterator &R) const { 201 return Block == R.Block && SuccessorIdx == R.SuccessorIdx; 202 } 203 204 const VPBlockBase *operator*() const { return deref(Block, SuccessorIdx); } 205 206 BlockPtrTy operator*() { return deref(Block, SuccessorIdx); } 207 208 VPAllSuccessorsIterator &operator++() { 209 SuccessorIdx++; 210 return *this; 211 } 212 213 VPAllSuccessorsIterator operator++(int X) { 214 VPAllSuccessorsIterator Orig = *this; 215 SuccessorIdx++; 216 return Orig; 217 } 218 }; 219 220 /// Helper for GraphTraits specialization that traverses through VPRegionBlocks. 221 template <typename BlockTy> class VPBlockRecursiveTraversalWrapper { 222 BlockTy Entry; 223 224 public: 225 VPBlockRecursiveTraversalWrapper(BlockTy Entry) : Entry(Entry) {} 226 BlockTy getEntry() { return Entry; } 227 }; 228 229 /// GraphTraits specialization to recursively traverse VPBlockBase nodes, 230 /// including traversing through VPRegionBlocks. Exit blocks of a region 231 /// implicitly have their parent region's successors. This ensures all blocks in 232 /// a region are visited before any blocks in a successor region when doing a 233 /// reverse post-order traversal of the graph. 234 template <> 235 struct GraphTraits<VPBlockRecursiveTraversalWrapper<VPBlockBase *>> { 236 using NodeRef = VPBlockBase *; 237 using ChildIteratorType = VPAllSuccessorsIterator<VPBlockBase *>; 238 239 static NodeRef 240 getEntryNode(VPBlockRecursiveTraversalWrapper<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<VPBlockRecursiveTraversalWrapper<const VPBlockBase *>> { 255 using NodeRef = const VPBlockBase *; 256 using ChildIteratorType = VPAllSuccessorsIterator<const VPBlockBase *>; 257 258 static NodeRef 259 getEntryNode(VPBlockRecursiveTraversalWrapper<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 } // namespace llvm 273 274 #endif // LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H 275