[llvm] [LoopInfo] Reuse DomTree's own DFS numbering in analyze() (PR #207650)

via llvm-commits llvm-commits at lists.llvm.org
Sun Jul 5 21:28:37 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-support

Author: Fangrui Song (MaskRay)

<details>
<summary>Changes</summary>

analyze() discovers loop headers with a post_order(DomRoot) walk, then
tests each back-edge candidate with DomTree.dominates(). Initial queries
use `dominatedBySlowTreeWalk` and then switch to `updateDFSNumbers`
(Euler tour technique), requiring two tree walks in total.

Optimize this with an upfront updateDFSNumbers to avoid the post-order
walk. This works because natural loop identification just requires
sub-loops to be identified before super-loops. Both post-order and
reverse pre-order walk.

DFS numbers, of [0, 2*N), have many nullptr gaps. Simplify
updateDFSNumbers() so DFSNumOut no longer consumes its own counter tick:
DFSNumIn becomes a dense [0, N) preorder rank.


---
Full diff: https://github.com/llvm/llvm-project/pull/207650.diff


4 Files Affected:

- (modified) llvm/include/llvm/Support/GenericDomTree.h (+12-2) 
- (modified) llvm/include/llvm/Support/GenericDomTreeConstruction.h (+2-2) 
- (modified) llvm/include/llvm/Support/GenericLoopInfoImpl.h (+11-4) 
- (modified) llvm/unittests/IR/DominatorTreeTest.cpp (+11-11) 


``````````diff
diff --git a/llvm/include/llvm/Support/GenericDomTree.h b/llvm/include/llvm/Support/GenericDomTree.h
index 920983e7bd800..45bc6269177c7 100644
--- a/llvm/include/llvm/Support/GenericDomTree.h
+++ b/llvm/include/llvm/Support/GenericDomTree.h
@@ -46,6 +46,8 @@ namespace llvm {
 template <typename NodeT, bool IsPostDom>
 class DominatorTreeBase;
 
+template <class BlockT, class LoopT> class LoopInfoBase;
+
 namespace DomTreeBuilder {
 template <typename DomTreeT>
 struct SemiNCAInfo;
@@ -316,8 +318,9 @@ class DominatorTreeBase {
   unsigned BlockNumberEpoch = 0;
 
   friend struct DomTreeBuilder::SemiNCAInfo<DominatorTreeBase>;
+  template <class BlockT, class LoopT> friend class LoopInfoBase;
 
- public:
+public:
   DominatorTreeBase() = default;
 
   DominatorTreeBase(const DominatorTreeBase &) = delete;
@@ -382,6 +385,13 @@ class DominatorTreeBase {
   }
 
 private:
+  // For LoopInfoBase's use in deriving a reverse-preorder traversal.
+  auto nodes() const {
+    return make_filter_range(DomTreeNodes, [](const DomTreeNodeBase<NodeT> *N) {
+      return N != nullptr;
+    });
+  }
+
   std::optional<unsigned> getNodeIndex(const NodeT *BB) const {
     if constexpr (GraphHasNodeNumbers<NodeT *>) {
       assert(BlockNumberEpoch ==
@@ -850,7 +860,7 @@ class DominatorTreeBase {
       // If we visited all of the children of this node, "recurse" back up the
       // stack setting the DFOutNum.
       if (ChildIt == Node->end()) {
-        Node->DFSNumOut = DFSNum++;
+        Node->DFSNumOut = DFSNum;
         WorkStack.pop_back();
       } else {
         // Otherwise, recursively visit this child.
diff --git a/llvm/include/llvm/Support/GenericDomTreeConstruction.h b/llvm/include/llvm/Support/GenericDomTreeConstruction.h
index 9ac5c5444c88a..80365e72e8d07 100644
--- a/llvm/include/llvm/Support/GenericDomTreeConstruction.h
+++ b/llvm/include/llvm/Support/GenericDomTreeConstruction.h
@@ -1444,13 +1444,13 @@ template <typename DomTreeT> struct SemiNCAInfo {
         return false;
       }
 
-      if (Children.back()->getDFSNumOut() + 1 != Node->getDFSNumOut()) {
+      if (Children.back()->getDFSNumOut() != Node->getDFSNumOut()) {
         PrintChildrenError(Children.back(), nullptr);
         return false;
       }
 
       for (size_t i = 0, e = Children.size() - 1; i != e; ++i) {
-        if (Children[i]->getDFSNumOut() + 1 != Children[i + 1]->getDFSNumIn()) {
+        if (Children[i]->getDFSNumOut() != Children[i + 1]->getDFSNumIn()) {
           PrintChildrenError(Children[i], Children[i + 1]);
           return false;
         }
diff --git a/llvm/include/llvm/Support/GenericLoopInfoImpl.h b/llvm/include/llvm/Support/GenericLoopInfoImpl.h
index 4666f4dac9cb6..9579a236b4da6 100644
--- a/llvm/include/llvm/Support/GenericLoopInfoImpl.h
+++ b/llvm/include/llvm/Support/GenericLoopInfoImpl.h
@@ -560,8 +560,8 @@ void PopulateLoopsDFS<BlockT, LoopT>::insertIntoLoop(BlockT *Block) {
     Subloop->addBlockEntry(Block);
 }
 
-/// Analyze LoopInfo discovers loops during a postorder DominatorTree traversal
-/// interleaved with backward CFG traversals within each subloop
+/// Analyze LoopInfo discovers loops during a reverse preorder DominatorTree
+/// traversal interleaved with backward CFG traversals within each subloop
 /// (discoverAndMapSubloop). The backward traversal skips inner subloops, so
 /// this part of the algorithm is linear in the number of CFG edges. Subloop and
 /// Block vectors are then populated during a single forward CFG traversal
@@ -576,7 +576,6 @@ void PopulateLoopsDFS<BlockT, LoopT>::insertIntoLoop(BlockT *Block) {
 /// insertions per block.
 template <class BlockT, class LoopT>
 void LoopInfoBase<BlockT, LoopT>::analyze(const DomTreeBase<BlockT> &DomTree) {
-  // Postorder traversal of the dominator tree.
   const DomTreeNodeBase<BlockT> *DomRoot = DomTree.getRootNode();
   if constexpr (GraphHasNodeNumbers<const BlockT *>) {
     ParentPtr = DomRoot->getBlock()->getParent();
@@ -584,8 +583,16 @@ void LoopInfoBase<BlockT, LoopT>::analyze(const DomTreeBase<BlockT> &DomTree) {
     unsigned Max = GraphTraits<ParentT>::getMaxNumber(ParentPtr);
     BBMap.resize(Max);
   }
-  for (auto DomNode : post_order(DomRoot)) {
 
+  // Visit dominator tree nodes in reverse preorder: like postorder, this
+  // guarantees a subloop is discovered before the super loop.
+  DomTree.updateDFSNumbers();
+  SmallVector<const DomTreeNodeBase<BlockT> *, 32> PreorderNodes(
+      DomRoot->getDFSNumOut());
+  for (const DomTreeNodeBase<BlockT> *Node : DomTree.nodes())
+    PreorderNodes[Node->getDFSNumIn()] = Node;
+
+  for (const DomTreeNodeBase<BlockT> *DomNode : llvm::reverse(PreorderNodes)) {
     BlockT *Header = DomNode->getBlock();
     SmallVector<BlockT *, 4> Backedges;
 
diff --git a/llvm/unittests/IR/DominatorTreeTest.cpp b/llvm/unittests/IR/DominatorTreeTest.cpp
index 042b7f449ba89..070a7325bf28e 100644
--- a/llvm/unittests/IR/DominatorTreeTest.cpp
+++ b/llvm/unittests/IR/DominatorTreeTest.cpp
@@ -253,13 +253,13 @@ TEST(DominatorTree, Unreachable) {
         // Check DFS Numbers before
         DT->updateDFSNumbers();
         EXPECT_EQ(DT->getNode(BB0)->getDFSNumIn(), 0UL);
-        EXPECT_EQ(DT->getNode(BB0)->getDFSNumOut(), 7UL);
+        EXPECT_EQ(DT->getNode(BB0)->getDFSNumOut(), 4UL);
         EXPECT_EQ(DT->getNode(BB1)->getDFSNumIn(), 1UL);
         EXPECT_EQ(DT->getNode(BB1)->getDFSNumOut(), 2UL);
-        EXPECT_EQ(DT->getNode(BB2)->getDFSNumIn(), 5UL);
-        EXPECT_EQ(DT->getNode(BB2)->getDFSNumOut(), 6UL);
-        EXPECT_EQ(DT->getNode(BB4)->getDFSNumIn(), 3UL);
-        EXPECT_EQ(DT->getNode(BB4)->getDFSNumOut(), 4UL);
+        EXPECT_EQ(DT->getNode(BB2)->getDFSNumIn(), 3UL);
+        EXPECT_EQ(DT->getNode(BB2)->getDFSNumOut(), 4UL);
+        EXPECT_EQ(DT->getNode(BB4)->getDFSNumIn(), 2UL);
+        EXPECT_EQ(DT->getNode(BB4)->getDFSNumOut(), 3UL);
 
         // Check levels before
         EXPECT_EQ(DT->getNode(BB0)->getLevel(), 0U);
@@ -275,15 +275,15 @@ TEST(DominatorTree, Unreachable) {
         // Check DFS Numbers after
         DT->updateDFSNumbers();
         EXPECT_EQ(DT->getNode(BB0)->getDFSNumIn(), 0UL);
-        EXPECT_EQ(DT->getNode(BB0)->getDFSNumOut(), 9UL);
+        EXPECT_EQ(DT->getNode(BB0)->getDFSNumOut(), 5UL);
         EXPECT_EQ(DT->getNode(BB1)->getDFSNumIn(), 1UL);
-        EXPECT_EQ(DT->getNode(BB1)->getDFSNumOut(), 4UL);
-        EXPECT_EQ(DT->getNode(BB2)->getDFSNumIn(), 7UL);
-        EXPECT_EQ(DT->getNode(BB2)->getDFSNumOut(), 8UL);
+        EXPECT_EQ(DT->getNode(BB1)->getDFSNumOut(), 3UL);
+        EXPECT_EQ(DT->getNode(BB2)->getDFSNumIn(), 4UL);
+        EXPECT_EQ(DT->getNode(BB2)->getDFSNumOut(), 5UL);
         EXPECT_EQ(DT->getNode(BB3)->getDFSNumIn(), 2UL);
         EXPECT_EQ(DT->getNode(BB3)->getDFSNumOut(), 3UL);
-        EXPECT_EQ(DT->getNode(BB4)->getDFSNumIn(), 5UL);
-        EXPECT_EQ(DT->getNode(BB4)->getDFSNumOut(), 6UL);
+        EXPECT_EQ(DT->getNode(BB4)->getDFSNumIn(), 3UL);
+        EXPECT_EQ(DT->getNode(BB4)->getDFSNumOut(), 4UL);
 
         // Check levels after
         EXPECT_EQ(DT->getNode(BB0)->getLevel(), 0U);

``````````

</details>


https://github.com/llvm/llvm-project/pull/207650


More information about the llvm-commits mailing list