[llvm] [IndVarSimplify] Batch forgetValue calls in sinkUnusedInvariants (PR #219025)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 26 15:48:08 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Anonmiraj (AnonMiraj)
<details>
<summary>Changes</summary>
It looks like every `forgetValue` clears the cached SCEV for an instruction and everything downstream of it, by walking its def-use children in `visitAndClearUsers` / `PushDefUseChildren` with a fresh `Visited` each call. Since `sinkUnusedInvariants` calls `forgetValue` once per sunk instruction, the overlapping users get re-walked over and over, so it ends up $O(n^2)$.
```cpp
void ScalarEvolution::forgetValue(Value *V) {
SmallPtrSet<Instruction *, 8> Visited;
visitAndClearUsers(Worklist, Visited, ToForget);
...
}
// visitAndClearUsers
while (!Worklist.empty()) {
Instruction *I = Worklist.pop_back_val();
...
ValueExprMap ... erase ...
PushDefUseChildren(I, Worklist, Visited);
}
// PushDefUseChildren
for (User *U : I->users()) {
auto *UserInsn = cast<Instruction>(U);
if (Visited.insert(UserInsn).second)
Worklist.push_back(UserInsn);
}
```
Collecting the sunk instructions and clearing them in one batched call fixes the issue.
Before / after on the reproducer from the issue
| | before | after |
|---|---|---|
| `IndVarSimplifyPass` | 226.70s | 0.087s |
| total compile (wall) | 3:45.7 | 3.9s |
fixes #<!-- -->194308
---
Full diff: https://github.com/llvm/llvm-project/pull/219025.diff
3 Files Affected:
- (modified) llvm/include/llvm/Analysis/ScalarEvolution.h (+4)
- (modified) llvm/lib/Analysis/ScalarEvolution.cpp (+13)
- (modified) llvm/lib/Transforms/Scalar/IndVarSimplify.cpp (+5-1)
``````````diff
diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h
index 0a9a4370d5e80..147da1af980cf 100644
--- a/llvm/include/llvm/Analysis/ScalarEvolution.h
+++ b/llvm/include/llvm/Analysis/ScalarEvolution.h
@@ -1154,6 +1154,10 @@ class ScalarEvolution {
/// def-use chain linking it to a loop.
LLVM_ABI void forgetValue(Value *V);
+ /// Batched forgetValue: invalidates all \p Values in one shared def-use walk,
+ /// avoiding the redundant re-traversal of overlapping users.
+ LLVM_ABI void forgetValues(ArrayRef<Value *> Values);
+
/// Forget LCSSA phi node V of loop L to which a new predecessor was added,
/// such that it may no longer be trivial.
LLVM_ABI void forgetLcssaPhiWithNewPredecessor(Loop *L, PHINode *V);
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index c74708fc73e5a..2e95b8db6def2 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -8856,6 +8856,19 @@ void ScalarEvolution::forgetValue(Value *V) {
forgetMemoizedResults(ToForget);
}
+void ScalarEvolution::forgetValues(ArrayRef<Value *> Values) {
+ SmallVector<Instruction *, 16> Worklist;
+ SmallPtrSet<Instruction *, 8> Visited;
+ SmallVector<SCEVUse, 8> ToForget;
+ for (Value *V : Values)
+ if (auto *I = dyn_cast<Instruction>(V))
+ if (Visited.insert(I).second)
+ Worklist.push_back(I);
+ visitAndClearUsers(Worklist, Visited, ToForget);
+
+ forgetMemoizedResults(ToForget);
+}
+
void ScalarEvolution::forgetLcssaPhiWithNewPredecessor(Loop *L, PHINode *V) {
if (!isSCEVable(V->getType()))
return;
diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
index c92efadded635..a5eefade336b7 100644
--- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
+++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
@@ -1211,6 +1211,7 @@ bool IndVarSimplify::sinkUnusedInvariants(Loop *L) {
if (!Preheader) return false;
bool MadeAnyChanges = false;
+ SmallVector<Value *, 16> SunkInsts;
for (Instruction &I : llvm::make_early_inc_range(llvm::reverse(*Preheader))) {
// Skip BB Terminator.
@@ -1268,10 +1269,13 @@ bool IndVarSimplify::sinkUnusedInvariants(Loop *L) {
// Otherwise, sink it to the exit block.
I.moveBefore(ExitBlock->getFirstInsertionPt());
- SE->forgetValue(&I);
+ SunkInsts.push_back(&I);
MadeAnyChanges = true;
}
+ if (MadeAnyChanges)
+ SE->forgetValues(SunkInsts);
+
return MadeAnyChanges;
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/219025
More information about the llvm-commits
mailing list