//===- VPlanCFG.h - GraphTraits for VP blocks -------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// Specializations of GraphTraits that allow VPBlockBase graphs to be /// treated as proper graphs for generic algorithms; //===----------------------------------------------------------------------===// #ifndef LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H #define LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H #include "VPlan.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/SmallVector.h" namespace llvm { //===----------------------------------------------------------------------===// // GraphTraits specializations for VPlan Hierarchical Control-Flow Graphs // //===----------------------------------------------------------------------===// /// Iterator to traverse all successors of a VPBlockBase node. This includes the /// entry node of VPRegionBlocks. Exit blocks of a region implicitly have their /// parent region's successors. This ensures all blocks in a region are visited /// before any blocks in a successor region when doing a reverse post-order // traversal of the graph. Region blocks themselves traverse only their entries // directly and not their successors. Those will be traversed when a region's // exiting block is traversed template <typename BlockPtrTy> class VPAllSuccessorsIterator : public iterator_facade_base<VPAllSuccessorsIterator<BlockPtrTy>, std::bidirectional_iterator_tag, VPBlockBase> { BlockPtrTy Block; /// Index of the current successor. For VPBasicBlock nodes, this simply is the /// index for the successor array. For VPRegionBlock, SuccessorIdx == 0 is /// used for the region's entry block, and SuccessorIdx - 1 are the indices /// for the successor array. size_t SuccessorIdx; static BlockPtrTy getBlockWithSuccs(BlockPtrTy Current) { while (Current && Current->getNumSuccessors() == 0) Current = Current->getParent(); return Current; } /// Templated helper to dereference successor \p SuccIdx of \p Block. Used by /// both the const and non-const operator* implementations. template <typename T1> static T1 deref(T1 Block, unsigned SuccIdx) { if (auto *R = dyn_cast<VPRegionBlock>(Block)) { assert(SuccIdx == 0); return R->getEntry(); } // For exit blocks, use the next parent region with successors. return getBlockWithSuccs(Block)->getSuccessors()[SuccIdx]; } public: /// Used by iterator_facade_base with bidirectional_iterator_tag. using reference = BlockPtrTy; VPAllSuccessorsIterator(BlockPtrTy Block, size_t Idx = 0) : Block(Block), SuccessorIdx(Idx) {} VPAllSuccessorsIterator(const VPAllSuccessorsIterator &Other) : Block(Other.Block), SuccessorIdx(Other.SuccessorIdx) {} VPAllSuccessorsIterator &operator=(const VPAllSuccessorsIterator &R) { Block = R.Block; SuccessorIdx = R.SuccessorIdx; return *this; } static VPAllSuccessorsIterator end(BlockPtrTy Block) { if (auto *R = dyn_cast<VPRegionBlock>(Block)) { // Traverse through the region's entry node. return {R, 1}; } BlockPtrTy ParentWithSuccs = getBlockWithSuccs(Block); unsigned NumSuccessors = ParentWithSuccs ? ParentWithSuccs->getNumSuccessors() : 0; return {Block, NumSuccessors}; } bool operator==(const VPAllSuccessorsIterator &R) const { return Block == R.Block && SuccessorIdx == R.SuccessorIdx; } const VPBlockBase *operator*() const { return deref(Block, SuccessorIdx); } BlockPtrTy operator*() { return deref(Block, SuccessorIdx); } VPAllSuccessorsIterator &operator++() { SuccessorIdx++; return *this; } VPAllSuccessorsIterator &operator--() { SuccessorIdx--; return *this; } VPAllSuccessorsIterator operator++(int X) { VPAllSuccessorsIterator Orig = *this; SuccessorIdx++; return Orig; } }; /// Helper for GraphTraits specialization that traverses through VPRegionBlocks. template <typename BlockTy> class VPBlockDeepTraversalWrapper { BlockTy Entry; public: VPBlockDeepTraversalWrapper(BlockTy Entry) : Entry(Entry) {} BlockTy getEntry() { return Entry; } }; /// GraphTraits specialization to recursively traverse VPBlockBase nodes, /// including traversing through VPRegionBlocks. Exit blocks of a region /// implicitly have their parent region's successors. This ensures all blocks in /// a region are visited before any blocks in a successor region when doing a /// reverse post-order traversal of the graph. template <> struct GraphTraits<VPBlockDeepTraversalWrapper<VPBlockBase *>> { using NodeRef = VPBlockBase *; using ChildIteratorType = VPAllSuccessorsIterator<VPBlockBase *>; static NodeRef getEntryNode(VPBlockDeepTraversalWrapper<VPBlockBase *> N) { return N.getEntry(); } static inline ChildIteratorType child_begin(NodeRef N) { return ChildIteratorType(N); } static inline ChildIteratorType child_end(NodeRef N) { return ChildIteratorType::end(N); } }; template <> struct GraphTraits<VPBlockDeepTraversalWrapper<const VPBlockBase *>> { using NodeRef = const VPBlockBase *; using ChildIteratorType = VPAllSuccessorsIterator<const VPBlockBase *>; static NodeRef getEntryNode(VPBlockDeepTraversalWrapper<const VPBlockBase *> N) { return N.getEntry(); } static inline ChildIteratorType child_begin(NodeRef N) { return ChildIteratorType(N); } static inline ChildIteratorType child_end(NodeRef N) { return ChildIteratorType::end(N); } }; /// Helper for GraphTraits specialization that does not traverses through /// VPRegionBlocks. template <typename BlockTy> class VPBlockShallowTraversalWrapper { BlockTy Entry; public: VPBlockShallowTraversalWrapper(BlockTy Entry) : Entry(Entry) {} BlockTy getEntry() { return Entry; } }; template <> struct GraphTraits<VPBlockShallowTraversalWrapper<VPBlockBase *>> { using NodeRef = VPBlockBase *; using ChildIteratorType = SmallVectorImpl<VPBlockBase *>::iterator; static NodeRef getEntryNode(VPBlockShallowTraversalWrapper<VPBlockBase *> N) { return N.getEntry(); } static inline ChildIteratorType child_begin(NodeRef N) { return N->getSuccessors().begin(); } static inline ChildIteratorType child_end(NodeRef N) { return N->getSuccessors().end(); } }; template <> struct GraphTraits<VPBlockShallowTraversalWrapper<const VPBlockBase *>> { using NodeRef = const VPBlockBase *; using ChildIteratorType = SmallVectorImpl<VPBlockBase *>::const_iterator; static NodeRef getEntryNode(VPBlockShallowTraversalWrapper<const VPBlockBase *> N) { return N.getEntry(); } static inline ChildIteratorType child_begin(NodeRef N) { return N->getSuccessors().begin(); } static inline ChildIteratorType child_end(NodeRef N) { return N->getSuccessors().end(); } }; /// Returns an iterator range to traverse the graph starting at \p G in /// depth-first order. The iterator won't traverse through region blocks. inline iterator_range< df_iterator<VPBlockShallowTraversalWrapper<VPBlockBase *>>> vp_depth_first_shallow(VPBlockBase *G) { return depth_first(VPBlockShallowTraversalWrapper<VPBlockBase *>(G)); } inline iterator_range< df_iterator<VPBlockShallowTraversalWrapper<const VPBlockBase *>>> vp_depth_first_shallow(const VPBlockBase *G) { return depth_first(VPBlockShallowTraversalWrapper<const VPBlockBase *>(G)); } /// Returns an iterator range to traverse the graph starting at \p G in /// depth-first order while traversing through region blocks. inline iterator_range<df_iterator<VPBlockDeepTraversalWrapper<VPBlockBase *>>> vp_depth_first_deep(VPBlockBase *G) { return depth_first(VPBlockDeepTraversalWrapper<VPBlockBase *>(G)); } inline iterator_range< df_iterator<VPBlockDeepTraversalWrapper<const VPBlockBase *>>> vp_depth_first_deep(const VPBlockBase *G) { return depth_first(VPBlockDeepTraversalWrapper<const VPBlockBase *>(G)); } // The following set of template specializations implement GraphTraits to treat // any VPBlockBase as a node in a graph of VPBlockBases. It's important to note // that VPBlockBase traits don't recurse into VPRegioBlocks, i.e., if the // VPBlockBase is a VPRegionBlock, this specialization provides access to its // successors/predecessors but not to the blocks inside the region. template <> struct GraphTraits<VPBlockBase *> { using NodeRef = VPBlockBase *; using ChildIteratorType = VPAllSuccessorsIterator<VPBlockBase *>; static NodeRef getEntryNode(NodeRef N) { return N; } static inline ChildIteratorType child_begin(NodeRef N) { return ChildIteratorType(N); } static inline ChildIteratorType child_end(NodeRef N) { return ChildIteratorType::end(N); } }; template <> struct GraphTraits<const VPBlockBase *> { using NodeRef = const VPBlockBase *; using ChildIteratorType = VPAllSuccessorsIterator<const VPBlockBase *>; static NodeRef getEntryNode(NodeRef N) { return N; } static inline ChildIteratorType child_begin(NodeRef N) { return ChildIteratorType(N); } static inline ChildIteratorType child_end(NodeRef N) { return ChildIteratorType::end(N); } }; /// Inverse graph traits are not implemented yet. /// TODO: Implement a version of VPBlockNonRecursiveTraversalWrapper to traverse /// predecessors recursively through regions. template <> struct GraphTraits<Inverse<VPBlockBase *>> { using NodeRef = VPBlockBase *; using ChildIteratorType = SmallVectorImpl<VPBlockBase *>::iterator; static NodeRef getEntryNode(Inverse<NodeRef> B) { llvm_unreachable("not implemented"); } static inline ChildIteratorType child_begin(NodeRef N) { llvm_unreachable("not implemented"); } static inline ChildIteratorType child_end(NodeRef N) { llvm_unreachable("not implemented"); } }; template <> struct GraphTraits<VPlan *> { using GraphRef = VPlan *; using NodeRef = VPBlockBase *; using nodes_iterator = df_iterator<NodeRef>; static NodeRef getEntryNode(GraphRef N) { return N->getEntry(); } static nodes_iterator nodes_begin(GraphRef N) { return nodes_iterator::begin(N->getEntry()); } static nodes_iterator nodes_end(GraphRef N) { // df_iterator::end() returns an empty iterator so the node used doesn't // matter. return nodes_iterator::end(N->getEntry()); } }; } // namespace llvm #endif // LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H