[llvm] [SCCP] Resolve undefs in blocks marked executable after specialization (PR #219269)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 27 12:07:48 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Advit Arora (advitrocks9)
<details>
<summary>Changes</summary>
Some call handlers in SCCP skip an instruction without giving it a lattice value and count on
`resolvedUndefsIn(F)` to fill it in later. `solveWhileResolvedUndefs()` never runs that sweep,
but its `solve()` can make new blocks executable. An instruction in one of those blocks can stay
unrecorded all the way to `runIPSCCP`:
```
opt: llvm/lib/Transforms/Utils/SCCPSolver.cpp:992: Assertion `I != ValueState.end() &&
"V not found in ValueState nor Paramstate map!"' failed.
```
In the test, `%if.then` is dead before specialization and live after, and the `fmod` call inside
it is what gets skipped.
The fix: `mar kBlockExecutable` records the blocks it opens, and the driver resolves undefs in
them after each `solve()`. Blocks whose function became unreachable are skipped, and resolving an
instruction twice is a no-op.
Not a regression, a cost-model change just moved the reporter's function across the
specialization size gate. Seeding values at the skip sites instead would fold unresolved values
to `undef`, a miscompile instead of a crash.
Fixes https://github.com/llvm/llvm-project/issues/215866
---
Full diff: https://github.com/llvm/llvm-project/pull/219269.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/Utils/SCCPSolver.cpp (+12)
- (added) llvm/test/Transforms/FunctionSpecialization/compiler-crash-215866.ll (+34)
``````````diff
diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
index b613df7e1c81f..6d37ebb5bca62 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -598,6 +598,8 @@ class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
/// Populated by resetLatticeValueFor(), cleared after resolving undefs.
DenseSet<Value *> Invalidated;
+ SmallVector<BasicBlock *, 8> NewlyExecutableBlocks;
+
/// MRVFunctionsTracked - Each function in TrackedMultipleRetVals is
/// represented here for efficient lookup.
SmallPtrSet<Function *, 16> MRVFunctionsTracked;
@@ -1054,6 +1056,7 @@ class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
for (Function &F : M)
ResolvedUndefs |= resolvedUndefsIn(F);
}
+ NewlyExecutableBlocks.clear();
}
void solveWhileResolvedUndefsIn(SmallVectorImpl<Function *> &WorkList) {
@@ -1074,6 +1077,14 @@ class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
for (Value *V : Invalidated)
if (auto *I = dyn_cast<Instruction>(V))
ResolvedUndefs |= resolvedUndef(*I);
+ // Invalidated does not cover blocks solve() has just opened.
+ while (!NewlyExecutableBlocks.empty()) {
+ BasicBlock *BB = NewlyExecutableBlocks.pop_back_val();
+ if (!BBExecutable.count(BB))
+ continue;
+ for (Instruction &I : *BB)
+ ResolvedUndefs |= resolvedUndef(I);
+ }
}
Invalidated.clear();
}
@@ -1086,6 +1097,7 @@ bool SCCPInstVisitor::markBlockExecutable(BasicBlock *BB) {
return false;
LLVM_DEBUG(dbgs() << "Marking Block Executable: " << BB->getName() << '\n');
BBWorkList.push_back(BB); // Add the block to the work list!
+ NewlyExecutableBlocks.push_back(BB);
return true;
}
diff --git a/llvm/test/Transforms/FunctionSpecialization/compiler-crash-215866.ll b/llvm/test/Transforms/FunctionSpecialization/compiler-crash-215866.ll
new file mode 100644
index 0000000000000..a6ab576a36d13
--- /dev/null
+++ b/llvm/test/Transforms/FunctionSpecialization/compiler-crash-215866.ll
@@ -0,0 +1,34 @@
+; RUN: opt -S --passes="ipsccp<func-spec>" -force-specialization < %s | FileCheck %s
+
+; %if.then only becomes executable during the post-specialization solve, so nothing assigns %rem a lattice value.
+; CHECK-DAG: callee.specialized.1
+; CHECK-DAG: call double @fmod(double undef, double 2.000000e+00)
+
+declare double @fmod(double, double)
+
+define internal i32 @callee(i32 %arg) {
+entry:
+ %c = icmp eq i32 %arg, 1
+ br i1 %c, label %ret, label %loop
+
+loop:
+ br label %loop
+
+ret:
+ ret i32 0
+}
+
+define void @caller() {
+entry:
+ %c1 = call i32 @callee(i32 1)
+ %call = call i32 @callee(i32 0)
+ %cmp = icmp sgt i32 %call, 0
+ br i1 %cmp, label %if.then, label %exit
+
+if.then:
+ %rem = call double @fmod(double undef, double 2.000000e+00)
+ br label %exit
+
+exit:
+ ret void
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/219269
More information about the llvm-commits
mailing list