[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