[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