[Mlir-commits] [llvm] [mlir] [WIP] Refactor post order traversal (PR #191047)

Alexis Engelke llvmlistbot at llvm.org
Wed Apr 8 13:09:31 PDT 2026


https://github.com/aengelke created https://github.com/llvm/llvm-project/pull/191047

Currently, po_iterator holds the traversal state. This makes copying
and moving po_iterator fairly expensive and the code cannot be optimized
away in several cases (most of it isn't even inlined in a default
build).

Therefore, refactor post-order traversal to hold the state in a wrapper
class with cheap iterators. Additionally, replace po_storage base class
with a CRTP implementation where users can provide their own storage.

Benefits:

- Performance in stage2-O3 improves by 0.19%.

- Users that use a custom storage/iteration limitation can do so in a
  more clean way by subclassing PostIteratorTraversalBase. See e.g.
  LoopBlocksTraversal.

- For graphs with block numbers, reserving can now be implemented
  reasonably easy (not done yet).

Implications:

- PostOrderTraversal::iterator is no longer a forward iterator. This
  property was never really used, though.

- PostOrderTraversal must be live while iterators are live. For typical
  uses (for (X x : post_order(...))), this is no problem, but could end
  up being problematic if the iterator is wrapped (e.g.
  for (X x : make_filter_range(post_order(...), ...)) -- problematic,
  because make_filter_range doesn't preserve the range but only the two
  iterators, which become invalid as the for loop is entered). This is a
  limitation of the way LLVM implements ranges.

---

This is not ready, but I'm opening this early for feedback before fixing
Clang+MLIR. Clang has one weird po_iterator use (two GraphTraits for one
type), and I haven't really looked into MLIR yet.

**Questions:**

- Should we drop or embrace the GraphTraits template parameter? If the
  former, how to fix Clang CFGView? If the latter, I'd make it the
  template parameter of PostOrderTraversalBase instead of GraphT, fine?

- Do something about CTAD (i.e., add template deduction guides for
  PostOrderTraversal)?

TODOs:

- Fix Clang and MLIR. The latter is probably difficult due to the use of
  our somewhat broken ranges...
- Write documentation.


>From aa004c0eed82a0651178f73d2c7bbeb7dc359462 Mon Sep 17 00:00:00 2001
From: Alexis Engelke <engelke at in.tum.de>
Date: Wed, 8 Apr 2026 20:08:51 +0000
Subject: [PATCH] [spr] initial version

Created using spr 1.3.8-wip
---
 llvm/include/llvm/ADT/PostOrderIterator.h     | 218 ++++++++++++------
 .../llvm/Analysis/BlockFrequencyInfoImpl.h    |   3 +-
 llvm/include/llvm/Analysis/LoopIterator.h     |  46 +---
 llvm/lib/Analysis/BranchProbabilityInfo.cpp   |   2 +-
 llvm/lib/Analysis/CFGPrinter.cpp              |   2 +-
 llvm/lib/Analysis/LoopInfo.cpp                |   4 +-
 llvm/lib/CodeGen/MachineTraceMetrics.cpp      |  19 +-
 .../Transforms/Vectorize/SLPVectorizer.cpp    |   2 +-
 llvm/lib/Transforms/Vectorize/VPlanCFG.h      |   5 +-
 .../Transforms/Vectorize/VPlanTransforms.cpp  |  10 +-
 llvm/lib/Transforms/Vectorize/VPlanUtils.h    |   3 +-
 llvm/unittests/ADT/PostOrderIteratorTest.cpp  |  34 +--
 .../Transforms/Vectorize/VPlanTest.cpp        |   9 +-
 mlir/include/mlir/IR/Iterators.h              |   4 +-
 14 files changed, 190 insertions(+), 171 deletions(-)

diff --git a/llvm/include/llvm/ADT/PostOrderIterator.h b/llvm/include/llvm/ADT/PostOrderIterator.h
index 1dfd259e58897..cb777d6c3055b 100644
--- a/llvm/include/llvm/ADT/PostOrderIterator.h
+++ b/llvm/include/llvm/ADT/PostOrderIterator.h
@@ -120,6 +120,142 @@ using DefaultSet =
 
 } // namespace po_detail
 
+template <typename DerivedT, typename GraphT> class PostOrderTraversalBase {
+  using GT = GraphTraits<GraphT>;
+  using NodeRef = typename GT::NodeRef;
+  using ChildItTy = typename GT::ChildIteratorType;
+
+  /// Used to maintain the ordering.
+  /// First element is basic block pointer, second is iterator for the next
+  /// child to visit, third is the end iterator.
+  SmallVector<std::tuple<NodeRef, ChildItTy, ChildItTy>, 8> VisitStack;
+
+public:
+  class iterator {
+    friend class PostOrderTraversalBase;
+
+  public:
+    using iterator_category = std::input_iterator_tag;
+    using value_type = NodeRef;
+    using difference_type = std::ptrdiff_t;
+    using pointer = value_type *;
+    using reference = NodeRef;
+
+  private:
+    DerivedT *POT = nullptr;
+    NodeRef V = nullptr;
+
+  public:
+    iterator() = default;
+
+  private:
+    iterator(DerivedT &POT, value_type V) : POT(&POT), V(V) {}
+
+  public:
+    bool operator==(const iterator &X) const { return V == X.V; }
+    bool operator!=(const iterator &X) const { return !(*this == X); }
+
+    NodeRef operator*() const { return V; }
+
+    // This is a nonstandard operator-> that dereferences the pointer an extra
+    // time... so that you can actually call methods ON the BasicBlock, because
+    // the contained type is a pointer.  This allows BBIt->getTerminator() f.e.
+    //
+    NodeRef operator->() const { return **this; }
+
+    iterator &operator++() { // Preincrement
+      V = POT->next();
+      return *this;
+    }
+
+    iterator operator++(int) { // Postincrement
+      iterator tmp = *this;
+      ++*this;
+      return tmp;
+    }
+  };
+
+protected:
+  PostOrderTraversalBase() = default;
+
+  DerivedT *derived() { return static_cast<DerivedT *>(this); }
+
+  void init(NodeRef Start) {
+    if (derived()->insertEdge(std::optional<NodeRef>(), Start)) {
+      VisitStack.emplace_back(Start, GT::child_begin(Start),
+                              GT::child_end(Start));
+      traverseChild();
+    }
+  }
+
+private:
+  void traverseChild() {
+    while (true) {
+      auto &Entry = VisitStack.back();
+      if (std::get<1>(Entry) == std::get<2>(Entry))
+        break;
+      NodeRef BB = *std::get<1>(Entry)++;
+      if (derived()->insertEdge(std::optional<NodeRef>(std::get<0>(Entry)),
+                                BB)) {
+        // If the block is not visited...
+        VisitStack.emplace_back(BB, GT::child_begin(BB), GT::child_end(BB));
+      }
+    }
+  }
+
+  NodeRef next() {
+    derived()->finishPostorder(std::get<0>(VisitStack.back()));
+    VisitStack.pop_back();
+    if (!VisitStack.empty())
+      traverseChild();
+    return !VisitStack.empty() ? std::get<0>(VisitStack.back()) : nullptr;
+  }
+
+public:
+  iterator begin() {
+    if (VisitStack.empty())
+      return iterator(); // We don't even want to see the start node.
+    return iterator(*derived(), std::get<0>(VisitStack.back()));
+  }
+  iterator end() { return iterator(); }
+
+  // Methods that are intended to be overridden by sub-classes.
+
+  /// Add edge and return whether To should be visited. From is nullopt for the
+  /// root node.
+  bool insertEdge(std::optional<NodeRef> From, NodeRef To);
+
+  /// Callback just before the iterator moves to the next block.
+  void finishPostorder(NodeRef) {}
+};
+
+/// Post-order traversal of a graph.
+template <typename GraphT, typename SetType = po_detail::DefaultSet<GraphT>>
+class PostOrderTraversal
+    : public PostOrderTraversalBase<PostOrderTraversal<GraphT, SetType>,
+                                    GraphT> {
+  using NodeRef = typename GraphTraits<GraphT>::NodeRef;
+
+  SetType Visited;
+
+public:
+  PostOrderTraversal(const GraphT &G) {
+    this->init(GraphTraits<GraphT>::getEntryNode(G));
+#if 0
+    if constexpr (GraphHasNodeNumbers<GraphT>)
+      Visited.reserve(GraphTraits<GraphT>::getMaxNumber(G));
+#endif
+  }
+
+  PostOrderTraversal(const GraphT &G, SetType &S) : Visited(S) {
+    this->init(GraphTraits<GraphT>::getEntryNode(G));
+  }
+
+  bool insertEdge(std::optional<NodeRef> From, NodeRef To) {
+    return Visited.insert(To).second;
+  }
+};
+
 template <class GraphT, class SetType = po_detail::DefaultSet<GraphT>,
           bool ExtStorage = false, class GT = GraphTraits<GraphT>>
 class po_iterator : public po_iterator_storage<SetType, ExtStorage> {
@@ -217,83 +353,15 @@ class po_iterator : public po_iterator_storage<SetType, ExtStorage> {
 
 // Provide global constructors that automatically figure out correct types...
 //
-template <class T>
-po_iterator<T> po_begin(const T &G) { return po_iterator<T>::begin(G); }
-template <class T>
-po_iterator<T> po_end  (const T &G) { return po_iterator<T>::end(G); }
-
-template <class T> iterator_range<po_iterator<T>> post_order(const T &G) {
-  return make_range(po_begin(G), po_end(G));
-}
-
-// Provide global definitions of external postorder iterators...
-template <class T, class SetType = std::set<typename GraphTraits<T>::NodeRef>>
-struct po_ext_iterator : po_iterator<T, SetType, true> {
-  po_ext_iterator(const po_iterator<T, SetType, true> &V) :
-  po_iterator<T, SetType, true>(V) {}
-};
-
-template <class T, class SetType>
-po_ext_iterator<T, SetType> po_ext_begin(const T &G, SetType &S) {
-  return po_ext_iterator<T, SetType>::begin(G, S);
-}
-
-template <class T, class SetType>
-po_ext_iterator<T, SetType> po_ext_end(const T &G, SetType &S) {
-  return po_ext_iterator<T, SetType>::end(G, S);
-}
-
-template <class T, class SetType>
-iterator_range<po_ext_iterator<T, SetType>> post_order_ext(const T &G, SetType &S) {
-  return make_range(po_ext_begin(G, S), po_ext_end(G, S));
-}
-
-// Provide global definitions of inverse post order iterators...
-template <class T, class SetType = std::set<typename GraphTraits<T>::NodeRef>,
-          bool External = false>
-struct ipo_iterator : po_iterator<Inverse<T>, SetType, External> {
-  ipo_iterator(const po_iterator<Inverse<T>, SetType, External> &V) :
-     po_iterator<Inverse<T>, SetType, External> (V) {}
-};
-
-template <class T>
-ipo_iterator<T> ipo_begin(const T &G) {
-  return ipo_iterator<T>::begin(G);
+template <class T> auto post_order(const T &G) {
+  return PostOrderTraversal<T>(G);
 }
-
-template <class T>
-ipo_iterator<T> ipo_end(const T &G){
-  return ipo_iterator<T>::end(G);
+template <class T, class SetType> auto post_order_ext(const T &G, SetType &S) {
+  return PostOrderTraversal<T, SetType &>(G, S);
 }
-
-template <class T>
-iterator_range<ipo_iterator<T>> inverse_post_order(const T &G) {
-  return make_range(ipo_begin(G), ipo_end(G));
-}
-
-// Provide global definitions of external inverse postorder iterators...
-template <class T, class SetType = std::set<typename GraphTraits<T>::NodeRef>>
-struct ipo_ext_iterator : ipo_iterator<T, SetType, true> {
-  ipo_ext_iterator(const ipo_iterator<T, SetType, true> &V) :
-    ipo_iterator<T, SetType, true>(V) {}
-  ipo_ext_iterator(const po_iterator<Inverse<T>, SetType, true> &V) :
-    ipo_iterator<T, SetType, true>(V) {}
-};
-
-template <class T, class SetType>
-ipo_ext_iterator<T, SetType> ipo_ext_begin(const T &G, SetType &S) {
-  return ipo_ext_iterator<T, SetType>::begin(G, S);
-}
-
-template <class T, class SetType>
-ipo_ext_iterator<T, SetType> ipo_ext_end(const T &G, SetType &S) {
-  return ipo_ext_iterator<T, SetType>::end(G, S);
-}
-
 template <class T, class SetType>
-iterator_range<ipo_ext_iterator<T, SetType>>
-inverse_post_order_ext(const T &G, SetType &S) {
-  return make_range(ipo_ext_begin(G, S), ipo_ext_end(G, S));
+auto inverse_post_order_ext(const T &G, SetType &S) {
+  return PostOrderTraversal<Inverse<T>, SetType &>(G, S);
 }
 
 //===--------------------------------------------------------------------===//
@@ -331,7 +399,7 @@ class ReversePostOrderTraversal {
   VecTy Blocks; // Block list in normal PO order
 
   void Initialize(const GraphT &G) {
-    std::copy(po_begin(G), po_end(G), std::back_inserter(Blocks));
+    llvm::copy(post_order(G), std::back_inserter(Blocks));
   }
 
 public:
diff --git a/llvm/include/llvm/Analysis/BlockFrequencyInfoImpl.h b/llvm/include/llvm/Analysis/BlockFrequencyInfoImpl.h
index cc2404a0249e7..7cc40084b9247 100644
--- a/llvm/include/llvm/Analysis/BlockFrequencyInfoImpl.h
+++ b/llvm/include/llvm/Analysis/BlockFrequencyInfoImpl.h
@@ -1106,9 +1106,8 @@ void BlockFrequencyInfoImpl<BT>::setBlockFreq(const BlockT *BB,
 }
 
 template <class BT> void BlockFrequencyInfoImpl<BT>::initializeRPOT() {
-  const BlockT *Entry = &F->front();
   RPOT.reserve(F->size());
-  for (const BlockT *BB : post_order(Entry))
+  for (const BlockT *BB : post_order(F))
     RPOT.emplace_back(BB);
   std::reverse(RPOT.begin(), RPOT.end());
 
diff --git a/llvm/include/llvm/Analysis/LoopIterator.h b/llvm/include/llvm/Analysis/LoopIterator.h
index 1ac8e68bfa2f1..b359812d396cd 100644
--- a/llvm/include/llvm/Analysis/LoopIterator.h
+++ b/llvm/include/llvm/Analysis/LoopIterator.h
@@ -186,49 +186,33 @@ class LoopBlocksRPO {
   LoopBlocksDFS::RPOIterator end() const { return DFS.endRPO(); }
 };
 
-/// Specialize po_iterator_storage to record postorder numbers.
-template<> class po_iterator_storage<LoopBlocksTraversal, true> {
-  LoopBlocksTraversal &LBT;
-public:
-  po_iterator_storage(LoopBlocksTraversal &lbs) : LBT(lbs) {}
-  // These functions are defined below.
-  bool insertEdge(std::optional<BasicBlock *> From, BasicBlock *To);
-  void finishPostorder(BasicBlock *BB);
-};
-
 /// Traverse the blocks in a loop using a depth-first search.
-class LoopBlocksTraversal {
-public:
-  /// Graph traversal iterator.
-  typedef po_iterator<BasicBlock*, LoopBlocksTraversal, true> POTIterator;
-
-private:
+class LoopBlocksTraversal
+    : public PostOrderTraversalBase<LoopBlocksTraversal, Function *> {
   LoopBlocksDFS &DFS;
   const LoopInfo *LI;
 
 public:
-  LoopBlocksTraversal(LoopBlocksDFS &Storage, const LoopInfo *LInfo) :
-    DFS(Storage), LI(LInfo) {}
+  LoopBlocksTraversal(LoopBlocksDFS &Storage, const LoopInfo *LInfo)
+      : DFS(Storage), LI(LInfo) {}
 
   /// Postorder traversal over the graph. This only needs to be done once.
   /// po_iterator "automatically" calls back to visitPreorder and
   /// finishPostorder to record the DFS result.
-  POTIterator begin() {
+  iterator begin() {
     assert(DFS.PostBlocks.empty() && "Need clear DFS result before traversing");
-    assert(DFS.L->getNumBlocks() && "po_iterator cannot handle an empty graph");
-    return po_ext_begin(DFS.L->getHeader(), *this);
-  }
-  POTIterator end() {
-    // po_ext_end interface requires a basic block, but ignores its value.
-    return po_ext_end(DFS.L->getHeader(), *this);
+    assert(DFS.L->getNumBlocks() && "cannot handle an empty graph");
+    init(DFS.L->getHeader());
+    return PostOrderTraversalBase::begin();
   }
+  iterator end() { return PostOrderTraversalBase::end(); }
 
   /// Called by po_iterator upon reaching a block via a CFG edge. If this block
   /// is contained in the loop and has not been visited, then mark it preorder
   /// visited and return true.
   ///
   /// TODO: If anyone is interested, we could record preorder numbers here.
-  bool visitPreorder(BasicBlock *BB) {
+  bool insertEdge(std::optional<BasicBlock *> /*From*/, BasicBlock *BB) {
     if (!DFS.L->contains(LI->getLoopFor(BB)))
       return false;
 
@@ -244,16 +228,6 @@ class LoopBlocksTraversal {
   }
 };
 
-inline bool po_iterator_storage<LoopBlocksTraversal, true>::insertEdge(
-    std::optional<BasicBlock *> From, BasicBlock *To) {
-  return LBT.visitPreorder(To);
-}
-
-inline void po_iterator_storage<LoopBlocksTraversal, true>::
-finishPostorder(BasicBlock *BB) {
-  LBT.finishPostorder(BB);
-}
-
 } // End namespace llvm
 
 #endif
diff --git a/llvm/lib/Analysis/BranchProbabilityInfo.cpp b/llvm/lib/Analysis/BranchProbabilityInfo.cpp
index 490bfbc0fb7ca..fdb539d91313c 100644
--- a/llvm/lib/Analysis/BranchProbabilityInfo.cpp
+++ b/llvm/lib/Analysis/BranchProbabilityInfo.cpp
@@ -1263,7 +1263,7 @@ void BPIConstruction::calculate(const Function &F, const LoopInfo &LoopI,
 
   // Walk the basic blocks in post-order so that we can build up state about
   // the successors of a block iteratively.
-  for (const auto *BB : post_order(&F.getEntryBlock())) {
+  for (const auto *BB : post_order(&F)) {
     LLVM_DEBUG(dbgs() << "Computing probabilities for " << BB->getName()
                       << "\n");
     // If there is no at least two successors, no sense to set probability.
diff --git a/llvm/lib/Analysis/CFGPrinter.cpp b/llvm/lib/Analysis/CFGPrinter.cpp
index 39108a906f081..18776bc539b32 100644
--- a/llvm/lib/Analysis/CFGPrinter.cpp
+++ b/llvm/lib/Analysis/CFGPrinter.cpp
@@ -206,7 +206,7 @@ void DOTGraphTraits<DOTFuncInfo *>::computeDeoptOrUnreachablePaths(
   };
   /// The post order traversal iteration is done to know the status of
   /// isOnDeoptOrUnreachablePath for all the successors on the current BB.
-  llvm::for_each(post_order(&F->getEntryBlock()), evaluateBB);
+  llvm::for_each(post_order(F), evaluateBB);
 }
 
 bool DOTGraphTraits<DOTFuncInfo *>::isNodeHidden(const BasicBlock *Node,
diff --git a/llvm/lib/Analysis/LoopInfo.cpp b/llvm/lib/Analysis/LoopInfo.cpp
index 8e08a70e69cdd..b459b12d47e8e 100644
--- a/llvm/lib/Analysis/LoopInfo.cpp
+++ b/llvm/lib/Analysis/LoopInfo.cpp
@@ -1284,8 +1284,6 @@ PreservedAnalyses LoopVerifierPass::run(Function &F,
 /// visit blocks during the initial traversal.
 void LoopBlocksDFS::perform(const LoopInfo *LI) {
   LoopBlocksTraversal Traversal(*this, LI);
-  for (LoopBlocksTraversal::POTIterator POI = Traversal.begin(),
-                                        POE = Traversal.end();
-       POI != POE; ++POI)
+  for ([[maybe_unused]] BasicBlock *BB : Traversal)
     ;
 }
diff --git a/llvm/lib/CodeGen/MachineTraceMetrics.cpp b/llvm/lib/CodeGen/MachineTraceMetrics.cpp
index 81dd68a519e76..9b7bf6ea3cc82 100644
--- a/llvm/lib/CodeGen/MachineTraceMetrics.cpp
+++ b/llvm/lib/CodeGen/MachineTraceMetrics.cpp
@@ -484,13 +484,17 @@ struct LoopBounds {
 
 // Specialize po_iterator_storage in order to prune the post-order traversal so
 // it is limited to the current loop and doesn't traverse the loop back edges.
-template <> class llvm::po_iterator_storage<LoopBounds, true> {
+template <typename GraphT>
+class LoopBoundsPostOrderTraversal
+    : public PostOrderTraversalBase<LoopBoundsPostOrderTraversal<GraphT>,
+                                    GraphT> {
   LoopBounds &LB;
 
 public:
-  po_iterator_storage(LoopBounds &lb) : LB(lb) {}
-
-  void finishPostorder(const MachineBasicBlock*) {}
+  LoopBoundsPostOrderTraversal(const MachineBasicBlock *Start, LoopBounds &LB)
+      : LB(LB) {
+    this->init(Start);
+  }
 
   bool insertEdge(std::optional<const MachineBasicBlock *> From,
                   const MachineBasicBlock *To) {
@@ -525,7 +529,9 @@ void MachineTraceMetrics::Ensemble::computeTrace(const MachineBasicBlock *MBB) {
   // Run an upwards post-order search for the trace start.
   Bounds.Downward = false;
   Bounds.Visited.clear();
-  for (const auto *I : inverse_post_order_ext(MBB, Bounds)) {
+  for (const auto *I :
+       LoopBoundsPostOrderTraversal<Inverse<const MachineBasicBlock *>>(
+           MBB, Bounds)) {
     LLVM_DEBUG(dbgs() << "  pred for " << printMBBReference(*I) << ": ");
     TraceBlockInfo &TBI = BlockInfo[I->getNumber()];
     // All the predecessors have been visited, pick the preferred one.
@@ -543,7 +549,8 @@ void MachineTraceMetrics::Ensemble::computeTrace(const MachineBasicBlock *MBB) {
   // Run a downwards post-order search for the trace end.
   Bounds.Downward = true;
   Bounds.Visited.clear();
-  for (const auto *I : post_order_ext(MBB, Bounds)) {
+  for (const auto *I :
+       LoopBoundsPostOrderTraversal<const MachineBasicBlock *>(MBB, Bounds)) {
     LLVM_DEBUG(dbgs() << "  succ for " << printMBBReference(*I) << ": ");
     TraceBlockInfo &TBI = BlockInfo[I->getNumber()];
     // All the successors have been visited, pick the preferred one.
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index f2ccf198c4c81..bc26d74ba3e67 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -25250,7 +25250,7 @@ bool SLPVectorizerPass::runImpl(Function &F, ScalarEvolution *SE_,
   DT->updateDFSNumbers();
 
   // Scan the blocks in the function in post order.
-  for (auto *BB : post_order(&F.getEntryBlock())) {
+  for (auto *BB : post_order(&F)) {
     if (BB->isEHPad() || isa_and_nonnull<UnreachableInst>(BB->getTerminator()))
       continue;
 
diff --git a/llvm/lib/Transforms/Vectorize/VPlanCFG.h b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
index 963d84675693a..58e43a9d81809 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanCFG.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
@@ -261,15 +261,14 @@ vp_depth_first_shallow(const VPBlockBase *G) {
 
 /// Returns an iterator range to traverse the graph starting at \p G in
 /// post order. The iterator won't traverse through region blocks.
-inline iterator_range<
-    po_iterator<VPBlockShallowTraversalWrapper<VPBlockBase *>>>
+inline PostOrderTraversal<VPBlockShallowTraversalWrapper<VPBlockBase *>>
 vp_post_order_shallow(VPBlockBase *G) {
   return post_order(VPBlockShallowTraversalWrapper<VPBlockBase *>(G));
 }
 
 /// Returns an iterator range to traverse the graph starting at \p G in
 /// post order while traversing through region blocks.
-inline iterator_range<po_iterator<VPBlockDeepTraversalWrapper<VPBlockBase *>>>
+inline PostOrderTraversal<VPBlockDeepTraversalWrapper<VPBlockBase *>>
 vp_post_order_deep(VPBlockBase *G) {
   return post_order(VPBlockDeepTraversalWrapper<VPBlockBase *>(G));
 }
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index 5fbdb2aa98d9f..8ce2d682a123f 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -734,8 +734,9 @@ static bool isDeadRecipe(VPRecipeBase &R) {
 }
 
 void VPlanTransforms::removeDeadRecipes(VPlan &Plan) {
-  for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(
-           vp_post_order_deep(Plan.getEntry()))) {
+  PostOrderTraversal<VPBlockDeepTraversalWrapper<VPBlockBase *>> POT(
+      Plan.getEntry());
+  for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(POT)) {
     // The recipes in the block are processed in reverse order, to catch chains
     // of dead recipes.
     for (VPRecipeBase &R : make_early_inc_range(reverse(*VPBB))) {
@@ -2711,8 +2712,9 @@ static void licm(VPlan &Plan) {
   // Sink recipes with no users inside the vector loop region if all users are
   // in the same exit block of the region.
   // TODO: Extend to sink recipes from inner loops.
-  for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(
-           vp_post_order_shallow(LoopRegion->getEntry()))) {
+  PostOrderTraversal<VPBlockShallowTraversalWrapper<VPBlockBase *>> POT(
+      LoopRegion->getEntry());
+  for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(POT)) {
     for (VPRecipeBase &R : make_early_inc_range(reverse(*VPBB))) {
       if (cannotHoistOrSinkRecipe(R))
         continue;
diff --git a/llvm/lib/Transforms/Vectorize/VPlanUtils.h b/llvm/lib/Transforms/Vectorize/VPlanUtils.h
index 5fdd5ea4204e0..2cab5967b42f7 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanUtils.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanUtils.h
@@ -269,8 +269,7 @@ class VPBlockUtils {
 
   /// Return an iterator range over \p Range which only includes \p BlockTy
   /// blocks. The accesses are casted to \p BlockTy.
-  template <typename BlockTy, typename T>
-  static auto blocksOnly(const T &Range) {
+  template <typename BlockTy, typename T> static auto blocksOnly(T &&Range) {
     // Create BaseTy with correct const-ness based on BlockTy.
     using BaseTy = std::conditional_t<std::is_const<BlockTy>::value,
                                       const VPBlockBase, VPBlockBase>;
diff --git a/llvm/unittests/ADT/PostOrderIteratorTest.cpp b/llvm/unittests/ADT/PostOrderIteratorTest.cpp
index 11da6925bb1fb..f66d9b6bc8b83 100644
--- a/llvm/unittests/ADT/PostOrderIteratorTest.cpp
+++ b/llvm/unittests/ADT/PostOrderIteratorTest.cpp
@@ -38,9 +38,9 @@ TEST(PostOrderIteratorTest, Compiles) {
   Graph<6> G;
   using NodeType = Graph<6>::NodeType;
   NodeType *NullNode = nullptr;
-  auto PI = po_end(G);
+  auto PI = post_order(G);
   PI.insertEdge(std::optional<NodeType *>(), NullNode);
-  auto PIExt = po_ext_end(G, Ext);
+  auto PIExt = post_order_ext(G, Ext);
   PIExt.insertEdge(std::optional<NodeType *>(), NullNode);
 }
 
@@ -83,34 +83,4 @@ TEST(PostOrderIteratorTest, PostOrderAndReversePostOrderTraverrsal) {
   EXPECT_EQ(1, FromIterator[4]);
   EXPECT_EQ(4, FromIterator[5]);
 }
-
-// po_iterator should be (at-least) a forward-iterator
-static_assert(std::is_base_of_v<std::forward_iterator_tag,
-                                po_iterator<Graph<4>>::iterator_category>);
-
-// po_ext_iterator cannot provide multi-pass guarantee, therefore its only
-// an input-iterator
-static_assert(std::is_same_v<po_ext_iterator<Graph<4>>::iterator_category,
-                             std::input_iterator_tag>);
-
-TEST(PostOrderIteratorTest, MultiPassSafeWithInternalSet) {
-  Graph<4> G;
-  G.AddEdge(0, 1);
-  G.AddEdge(1, 2);
-  G.AddEdge(1, 3);
-
-  std::array<decltype(G)::NodeType *, 4> NodesFirstPass, NodesSecondPass;
-
-  auto B = po_begin(G), E = po_end(G);
-
-  std::size_t I = 0;
-  for (auto It = B; It != E; ++It)
-    NodesFirstPass[I++] = *It;
-
-  I = 0;
-  for (auto It = B; It != E; ++It)
-    NodesSecondPass[I++] = *It;
-
-  EXPECT_EQ(NodesFirstPass, NodesSecondPass);
-}
 }
diff --git a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
index 017aa6dab705e..b378b74618258 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
@@ -546,7 +546,7 @@ TEST_F(VPBasicBlockTest, TraversingIteratorTest) {
 
     // Post-order.
     FromIterator.clear();
-    FromIterator.append(po_begin(Start), po_end(Start));
+    copy(post_order(Start), std::back_inserter(FromIterator));
     EXPECT_EQ(10u, FromIterator.size());
     EXPECT_EQ(VPBB2, FromIterator[0]);
     EXPECT_EQ(R1BB3, FromIterator[1]);
@@ -597,7 +597,7 @@ TEST_F(VPBasicBlockTest, TraversingIteratorTest) {
 
     // Post-order.
     FromIterator.clear();
-    FromIterator.append(po_begin(Start), po_end(Start));
+    copy(post_order(Start), std::back_inserter(FromIterator));
     EXPECT_EQ(5u, FromIterator.size());
     EXPECT_EQ(R2BB2, FromIterator[0]);
     EXPECT_EQ(R2BB1, FromIterator[1]);
@@ -678,8 +678,9 @@ TEST_F(VPBasicBlockTest, TraversingIteratorTest) {
 
     // Post-order, const VPRegionBlocks only.
     VPBlockDeepTraversalWrapper<const VPBlockBase *> StartConst(VPBB1);
-    SmallVector<const VPRegionBlock *> FromIteratorVPRegion(
-        VPBlockUtils::blocksOnly<const VPRegionBlock>(post_order(StartConst)));
+    SmallVector<const VPRegionBlock *> FromIteratorVPRegion;
+    copy(VPBlockUtils::blocksOnly<const VPRegionBlock>(post_order(StartConst)),
+         std::back_inserter(FromIteratorVPRegion));
     EXPECT_EQ(3u, FromIteratorVPRegion.size());
     EXPECT_EQ(R3, FromIteratorVPRegion[0]);
     EXPECT_EQ(R2, FromIteratorVPRegion[1]);
diff --git a/mlir/include/mlir/IR/Iterators.h b/mlir/include/mlir/IR/Iterators.h
index dcb738c549438..4754d3beb2c6e 100644
--- a/mlir/include/mlir/IR/Iterators.h
+++ b/mlir/include/mlir/IR/Iterators.h
@@ -100,9 +100,10 @@ struct ReverseDominanceIterator {
   static constexpr auto makeIterable(Operation &range) {
     return llvm::reverse(ForwardIterator::makeIterable(range));
   }
-
+#if 0
   static auto makeIterable(Region &region) {
     Block *null = nullptr;
+    llvm::PostOrderTraversal<Block *>::iterator sentinel;
     if (SkipGraphRegion && !mayHaveSSADominance(region)) {
       // Skip graph regions.
       return llvm::make_pointee_range(
@@ -118,6 +119,7 @@ struct ReverseDominanceIterator {
     // Walk API expects Block references instead of pointers.
     return llvm::make_pointee_range(it);
   }
+#endif
 };
 } // namespace mlir
 



More information about the Mlir-commits mailing list