[llvm] [GVN] add reverse leader map to improve compile time (PR #175870)

Princeton Ferro via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 14 13:26:22 PST 2026


https://github.com/Prince781 updated https://github.com/llvm/llvm-project/pull/175870

>From b33c99e4a840b358c0d088f9bf16f74772b4b1c5 Mon Sep 17 00:00:00 2001
From: Princeton Ferro <pferro at nvidia.com>
Date: Mon, 12 Jan 2026 14:10:35 -0800
Subject: [PATCH 1/2] [GVN] add reverse leader map to improve compile time

The leader map can become very large on unrolled code, making iteration
in verifyRemoved() very slow. Add a reverse mapping from `Value *` to
leader number to avoid costly iteration.
---
 llvm/include/llvm/Transforms/Scalar/GVN.h | 30 +++++++++++++++++++++++
 llvm/lib/Transforms/Scalar/GVN.cpp        | 15 ++++--------
 2 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/Transforms/Scalar/GVN.h b/llvm/include/llvm/Transforms/Scalar/GVN.h
index bc0f108ac8260..75c7dee36cd6f 100644
--- a/llvm/include/llvm/Transforms/Scalar/GVN.h
+++ b/llvm/include/llvm/Transforms/Scalar/GVN.h
@@ -276,6 +276,35 @@ class GVNPass : public PassInfoMixin<GVNPass> {
     DenseMap<uint32_t, LeaderListNode> NumToLeaders;
     BumpPtrAllocator TableAllocator;
 
+    // For a given value, a list of its basic blocks and leader numbers
+    class ReverseMap {
+      DenseMap<Value *, DenseMap<const BasicBlock *, DenseSet<uint32_t>>> Map;
+
+    public:
+      void add(uint32_t N, Value *V, const BasicBlock *BB) {
+        Map[V][BB].insert(N);
+      }
+
+      void del(uint32_t N, Value *V, const BasicBlock *BB) {
+        if (auto It = Map.find(V); It != Map.end()) {
+          if (auto BBIt = It->second.find(BB); BBIt != It->second.end()) {
+            BBIt->second.erase(N);
+            if (BBIt->second.empty())
+              It->second.erase(BB);
+            if (It->second.empty())
+              Map.erase(V);
+          }
+        }
+      }
+
+      bool has(const Value *V) const { return Map.contains(V); }
+
+      void clear() { Map.clear(); }
+    };
+
+    // Maintain reverse map for efficient verification
+    ReverseMap LeaderToNums;
+
   public:
     class leader_iterator {
       const LeaderListNode *Current;
@@ -319,6 +348,7 @@ class GVNPass : public PassInfoMixin<GVNPass> {
     void clear() {
       NumToLeaders.clear();
       TableAllocator.Reset();
+      LeaderToNums.clear();
     }
   };
   LeaderMap LeaderTable;
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index 72e1131a54a86..08e8647dcb92b 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -801,6 +801,8 @@ void GVNPass::LeaderMap::insert(uint32_t N, Value *V, const BasicBlock *BB) {
   Node->Entry.BB = BB;
   Node->Next = Curr.Next;
   Curr.Next = Node;
+
+  LeaderToNums.add(N, V, BB);
 }
 
 /// Scan the list of values corresponding to a given
@@ -831,19 +833,12 @@ void GVNPass::LeaderMap::erase(uint32_t N, Instruction *I,
       Curr->Next = Next->Next;
     }
   }
+
+  LeaderToNums.del(N, I, BB);
 }
 
 void GVNPass::LeaderMap::verifyRemoved(const Value *V) const {
-  // Walk through the value number scope to make sure the instruction isn't
-  // ferreted away in it.
-  for (const auto &I : NumToLeaders) {
-    (void)I;
-    assert(I.second.Entry.Val != V && "Inst still in value numbering scope!");
-    assert(
-        std::none_of(leader_iterator(&I.second), leader_iterator(nullptr),
-                     [=](const LeaderTableEntry &E) { return E.Val == V; }) &&
-        "Inst still in value numbering scope!");
-  }
+  assert(!LeaderToNums.has(V) && "Inst still in value numbering scope!");
 }
 
 //===----------------------------------------------------------------------===//

>From cea59cb572392c9a3cc984f8c4b88227ae38a510 Mon Sep 17 00:00:00 2001
From: Princeton Ferro <pferro at nvidia.com>
Date: Wed, 14 Jan 2026 13:23:25 -0800
Subject: [PATCH 2/2] wrap in NDEBUG

---
 llvm/include/llvm/Transforms/Scalar/GVN.h | 6 ++++++
 llvm/lib/Transforms/Scalar/GVN.cpp        | 4 ++++
 2 files changed, 10 insertions(+)

diff --git a/llvm/include/llvm/Transforms/Scalar/GVN.h b/llvm/include/llvm/Transforms/Scalar/GVN.h
index 75c7dee36cd6f..269e7629ce5ba 100644
--- a/llvm/include/llvm/Transforms/Scalar/GVN.h
+++ b/llvm/include/llvm/Transforms/Scalar/GVN.h
@@ -276,6 +276,7 @@ class GVNPass : public PassInfoMixin<GVNPass> {
     DenseMap<uint32_t, LeaderListNode> NumToLeaders;
     BumpPtrAllocator TableAllocator;
 
+#ifndef NDEBUG
     // For a given value, a list of its basic blocks and leader numbers
     class ReverseMap {
       DenseMap<Value *, DenseMap<const BasicBlock *, DenseSet<uint32_t>>> Map;
@@ -304,6 +305,7 @@ class GVNPass : public PassInfoMixin<GVNPass> {
 
     // Maintain reverse map for efficient verification
     ReverseMap LeaderToNums;
+#endif  // NDEBUG
 
   public:
     class leader_iterator {
@@ -344,7 +346,9 @@ class GVNPass : public PassInfoMixin<GVNPass> {
 
     LLVM_ABI void insert(uint32_t N, Value *V, const BasicBlock *BB);
     LLVM_ABI void erase(uint32_t N, Instruction *I, const BasicBlock *BB);
+#ifndef NDEBUG
     LLVM_ABI void verifyRemoved(const Value *Inst) const;
+#endif
     void clear() {
       NumToLeaders.clear();
       TableAllocator.Reset();
@@ -425,7 +429,9 @@ class GVNPass : public PassInfoMixin<GVNPass> {
   Value *findLeader(const BasicBlock *BB, uint32_t Num);
   void cleanupGlobalSets();
   void removeInstruction(Instruction *I);
+#ifndef NDEBUG
   void verifyRemoved(const Instruction *I) const;
+#endif
   bool splitCriticalEdges();
   BasicBlock *splitCriticalEdges(BasicBlock *Pred, BasicBlock *Succ);
   bool
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index 08e8647dcb92b..2a5c492c6964c 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -802,7 +802,9 @@ void GVNPass::LeaderMap::insert(uint32_t N, Value *V, const BasicBlock *BB) {
   Node->Next = Curr.Next;
   Curr.Next = Node;
 
+#ifndef NDEBUG
   LeaderToNums.add(N, V, BB);
+#endif
 }
 
 /// Scan the list of values corresponding to a given
@@ -834,7 +836,9 @@ void GVNPass::LeaderMap::erase(uint32_t N, Instruction *I,
     }
   }
 
+#ifndef NDEBUG
   LeaderToNums.del(N, I, BB);
+#endif
 }
 
 void GVNPass::LeaderMap::verifyRemoved(const Value *V) const {



More information about the llvm-commits mailing list