[llvm] [SpeculativeExecution] Drop poison-generating flags when hoisting instructions (PR #225377)
Adrian Kuegel via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 23 06:12:55 PDT 2026
https://github.com/akuegel updated https://github.com/llvm/llvm-project/pull/225377
>From 02f8ae86d49e9c7868b015733b24194dc723413e Mon Sep 17 00:00:00 2001
From: Adrian Kuegel <akuegel at google.com>
Date: Wed, 23 Sep 2026 13:11:26 +0000
Subject: [PATCH] [SLSR] Guard variable delta reuse with canReuseInstruction
StraightLineStrengthReduce checks ScalarEvolution::canReuseInstruction
when recording candidate instructions in CandidateDict as a Basis, and
drops poison-generating annotations on Basis.DropList when rewriting.
However, getAndRecordSCEV unconditionally inserted instructions into
SCEVToInsts without checking canReuseInstruction, and getNearestValueOfSCEV
reused those instructions as variable BaseDelta/StrideDelta values without
checking canReuseInstruction or dropping poison-generating annotations.
In particular, this allowed SLSR to reuse a speculated 'or disjoint'
instruction as an additive variable delta on a path where the disjointness
precondition did not hold.
Check SE->canReuseInstruction in getAndRecordSCEV before inserting into
SCEVToInsts, and drop poison-generating annotations for reused delta
instructions in rewriteCandidate.
---
.../Scalar/StraightLineStrengthReduce.cpp | 27 +++++++-
.../NVPTX/slsr-invalid.ll | 68 +++++++++++++++++++
2 files changed, 92 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp b/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp
index 4fa462da9ec474..ad2f0eae01adca 100644
--- a/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp
+++ b/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp
@@ -421,6 +421,11 @@ class StraightLineStrengthReduce {
// instructions are sorted in depth-first order.
DenseMap<const SCEV *, SmallSetVector<Instruction *, 2>> SCEVToInsts;
+ // Map from reusable delta instruction to instructions whose poison-generating
+ // annotations must be dropped if the instruction is used as a delta in an
+ // executed rewrite.
+ DenseMap<Instruction *, SmallVector<Instruction *>> InstDropLists;
+
using SCEVUnknownSet = SmallPtrSet<const SCEVUnknown *, 4>;
DenseMap<const SCEV *, SCEVUnknownSet> SCEVUnknownsCache;
@@ -505,9 +510,20 @@ class StraightLineStrengthReduce {
const SCEV *getAndRecordSCEV(Value *V) {
auto *S = SE->getSCEV(V);
- if (isa<Instruction>(V) && !(isa<SCEVCouldNotCompute>(S) ||
- isa<SCEVUnknown>(S) || isa<SCEVConstant>(S)))
- SCEVToInsts[S].insert(cast<Instruction>(V));
+ if (auto *I = dyn_cast<Instruction>(V);
+ I && !(isa<SCEVCouldNotCompute>(S) || isa<SCEVUnknown>(S) ||
+ isa<SCEVConstant>(S))) {
+ auto &Insts = SCEVToInsts[S];
+ if (!Insts.contains(I)) {
+ SmallVector<Instruction *> DropList;
+ if (!EnablePoisonReuseGuard ||
+ SE->canReuseInstruction(S, I, DropList)) {
+ Insts.insert(I);
+ if (!DropList.empty())
+ InstDropLists[I] = std::move(DropList);
+ }
+ }
+ }
return S;
}
@@ -1352,6 +1368,11 @@ void StraightLineStrengthReduce::rewriteCandidate(const Candidate &C) {
for (Instruction *I : Basis.DropList)
I->dropPoisonGeneratingAnnotations();
+ if (auto *DeltaInst = dyn_cast<Instruction>(C.Delta)) {
+ if (auto It = InstDropLists.find(DeltaInst); It != InstDropLists.end())
+ for (Instruction *I : It->second)
+ I->dropPoisonGeneratingAnnotations();
+ }
IRBuilder<> Builder(C.Ins);
Value *Bump = emitBump(Basis, C, Builder, DL);
diff --git a/llvm/test/Transforms/StraightLineStrengthReduce/NVPTX/slsr-invalid.ll b/llvm/test/Transforms/StraightLineStrengthReduce/NVPTX/slsr-invalid.ll
index 6377701a4d2896..1a2f2047f4871b 100644
--- a/llvm/test/Transforms/StraightLineStrengthReduce/NVPTX/slsr-invalid.ll
+++ b/llvm/test/Transforms/StraightLineStrengthReduce/NVPTX/slsr-invalid.ll
@@ -138,3 +138,71 @@ define void @invalid_add_reuse(i64 %0, ptr writeonly align 256 captures(none) de
declare i64 @foo(i64)
declare i64 @bar(i64)
+declare void @use(i32)
+
+define i32 @invalid_var_delta_or_disjoint(i32 %a, i32 %b, i32 %idx, i1 %cond) {
+; CHECK-LABEL: define i32 @invalid_var_delta_or_disjoint(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[IDX:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[A_MINUS_3:%.*]] = add i32 [[A]], -3
+; CHECK-NEXT: [[BASIS:%.*]] = add i32 [[A_MINUS_3]], [[B]]
+; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint i32 [[IDX]], -2
+; CHECK-NEXT: [[USE_OR:%.*]] = add i32 [[A]], [[OR_DISJOINT]]
+; CHECK-NEXT: br i1 [[COND]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK: [[THEN]]:
+; CHECK-NEXT: call void @use(i32 [[USE_OR]])
+; CHECK-NEXT: br label %[[ELSE]]
+; CHECK: [[ELSE]]:
+; CHECK-NEXT: [[IDX_MINUS_5:%.*]] = add i32 [[IDX]], -5
+; CHECK-NEXT: [[T1:%.*]] = add i32 [[IDX_MINUS_5]], [[A]]
+; CHECK-NEXT: [[RES:%.*]] = add i32 [[T1]], [[B]]
+; CHECK-NEXT: ret i32 [[RES]]
+;
+ %a_minus_3 = add i32 %a, -3
+ %basis = add i32 %a_minus_3, %b
+ %or_disjoint = or disjoint i32 %idx, -2
+ %use_or = add i32 %a, %or_disjoint
+ br i1 %cond, label %then, label %else
+
+then:
+ call void @use(i32 %use_or)
+ br label %else
+
+else:
+ %idx_minus_5 = add i32 %idx, -5
+ %t1 = add i32 %idx_minus_5, %a
+ %res = add i32 %t1, %b
+ ret i32 %res
+}
+
+define i32 @var_delta_drop_poison_flags(i32 %a, i32 %b, i32 %idx, i1 %cond) {
+; CHECK-LABEL: define i32 @var_delta_drop_poison_flags(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[IDX:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[A_MINUS_3:%.*]] = add i32 [[A]], -3
+; CHECK-NEXT: [[BASIS:%.*]] = add i32 [[A_MINUS_3]], [[B]]
+; CHECK-NEXT: [[ADD_NSW:%.*]] = add i32 [[IDX]], -2
+; CHECK-NEXT: [[USE_ADD:%.*]] = add i32 [[A]], [[ADD_NSW]]
+; CHECK-NEXT: br i1 [[COND]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK: [[THEN]]:
+; CHECK-NEXT: call void @use(i32 [[USE_ADD]])
+; CHECK-NEXT: br label %[[ELSE]]
+; CHECK: [[ELSE]]:
+; CHECK-NEXT: [[RES:%.*]] = add i32 [[BASIS]], [[ADD_NSW]]
+; CHECK-NEXT: ret i32 [[RES]]
+;
+ %a_minus_3 = add i32 %a, -3
+ %basis = add i32 %a_minus_3, %b
+ %add_nsw = add nsw i32 %idx, -2
+ %use_add = add i32 %a, %add_nsw
+ br i1 %cond, label %then, label %else
+
+then:
+ call void @use(i32 %use_add)
+ br label %else
+
+else:
+ %idx_minus_5 = add i32 %idx, -5
+ %t1 = add i32 %idx_minus_5, %a
+ %res = add i32 %t1, %b
+ ret i32 %res
+}
+
More information about the llvm-commits
mailing list