[llvm] [SLSR] Guard variable delta reuse with canReuseInstruction (PR #225377)

Adrian Kuegel via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 22:58:46 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 4fa462da9ec47..ad2f0eae01adc 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 6377701a4d289..1a2f2047f4871 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