[llvm] [DA] Fix zero coeff bug in Strong SIV test with runtime assumptions (#149991) (PR #155037)

Sebastian Pop via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 28 02:47:49 PST 2025


https://github.com/sebpop updated https://github.com/llvm/llvm-project/pull/155037

>From 711843055667e81724e3f5468c40633cda6fb20b Mon Sep 17 00:00:00 2001
From: Sebastian Pop <spop at nvidia.com>
Date: Tue, 25 Nov 2025 13:59:49 -0500
Subject: [PATCH 1/4] [DA] Simplify runtime predicate collection

Removes DependenceInfo::getRuntimeAssumptions(), DependenceInfo::Assumptions,
and the print of "Runtime Assumptions:". The runtime assumptions are still
properly attached to each Dependence result and printed as part of the
per-dependence output.
---
 .../llvm/Analysis/DependenceAnalysis.h        |  5 ----
 llvm/lib/Analysis/DependenceAnalysis.cpp      | 27 +++----------------
 .../DependenceAnalysis/DifferentOffsets.ll    |  7 -----
 .../DependenceAnalysis/MIVCheckConst.ll       |  3 ---
 4 files changed, 4 insertions(+), 38 deletions(-)

diff --git a/llvm/include/llvm/Analysis/DependenceAnalysis.h b/llvm/include/llvm/Analysis/DependenceAnalysis.h
index f603ae8dbd70f..a39a9d4b66442 100644
--- a/llvm/include/llvm/Analysis/DependenceAnalysis.h
+++ b/llvm/include/llvm/Analysis/DependenceAnalysis.h
@@ -355,16 +355,11 @@ class DependenceInfo {
 
   Function *getFunction() const { return F; }
 
-  /// getRuntimeAssumptions - Returns all the runtime assumptions under which
-  /// the dependence test is valid.
-  LLVM_ABI SCEVUnionPredicate getRuntimeAssumptions() const;
-
 private:
   AAResults *AA;
   ScalarEvolution *SE;
   LoopInfo *LI;
   Function *F;
-  SmallVector<const SCEVPredicate *, 4> Assumptions;
 
   /// Subscript - This private struct represents a pair of subscripts from
   /// a pair of potentially multi-dimensional array references. We use a
diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index b0398fe7e93b3..5fc9614298c77 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -441,11 +441,6 @@ static void dumpExampleDependence(raw_ostream &OS, DependenceInfo *DA,
       }
     }
   }
-  SCEVUnionPredicate Assumptions = DA->getRuntimeAssumptions();
-  if (!Assumptions.isAlwaysTrue()) {
-    OS << "Runtime Assumptions:\n";
-    Assumptions.print(OS, 0);
-  }
 }
 
 void DependenceAnalysisWrapperPass::print(raw_ostream &OS,
@@ -3510,10 +3505,6 @@ bool DependenceInfo::invalidate(Function &F, const PreservedAnalyses &PA,
          Inv.invalidate<LoopAnalysis>(F, PA);
 }
 
-SCEVUnionPredicate DependenceInfo::getRuntimeAssumptions() const {
-  return SCEVUnionPredicate(Assumptions, *SE);
-}
-
 // depends -
 // Returns NULL if there is no dependence.
 // Otherwise, return a Dependence with as many details as possible.
@@ -3614,20 +3605,10 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
                                         SCEVUnionPredicate(Assume, *SE));
   }
 
-  if (!Assume.empty()) {
-    if (!UnderRuntimeAssumptions)
-      return std::make_unique<Dependence>(Src, Dst,
-                                          SCEVUnionPredicate(Assume, *SE));
-    // Add non-redundant assumptions.
-    unsigned N = Assumptions.size();
-    for (const SCEVPredicate *P : Assume) {
-      bool Implied = false;
-      for (unsigned I = 0; I != N && !Implied; I++)
-        if (Assumptions[I]->implies(P, *SE))
-          Implied = true;
-      if (!Implied)
-        Assumptions.push_back(P);
-    }
+  if (!Assume.empty() && !UnderRuntimeAssumptions) {
+    // Runtime assumptions needed but not allowed.
+    return std::make_unique<Dependence>(Src, Dst,
+                                        SCEVUnionPredicate(Assume, *SE));
   }
 
   unsigned Pairs = 1;
diff --git a/llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll b/llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll
index 069a540ea0295..91d127cfc09d6 100644
--- a/llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll
@@ -34,8 +34,6 @@ define i32 @alias_with_parametric_offset(ptr nocapture %A, i64 %n) {
 ; CHECK-NEXT:    Equal predicate: (zext i2 (trunc i64 %n to i2) to i64) == 0
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %A, align 1 --> Dst: %0 = load i32, ptr %A, align 1
 ; CHECK-NEXT:    da analyze - none!
-; CHECK-NEXT:  Runtime Assumptions:
-; CHECK-NEXT:  Equal predicate: (zext i2 (trunc i64 %n to i2) to i64) == 0
 ;
 entry:
   %arrayidx = getelementptr inbounds i8, ptr %A, i64 %n
@@ -55,9 +53,6 @@ define i32 @alias_with_parametric_expr(ptr nocapture %A, i64 %n, i64 %m) {
 ; CHECK-NEXT:    Equal predicate: (zext i2 (-2 + (trunc i64 %m to i2)) to i64) == 0
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx1, align 1 --> Dst: %0 = load i32, ptr %arrayidx1, align 1
 ; CHECK-NEXT:    da analyze - none!
-; CHECK-NEXT:  Runtime Assumptions:
-; CHECK-NEXT:  Equal predicate: (zext i2 ((trunc i64 %m to i2) + (-2 * (trunc i64 %n to i2))) to i64) == 0
-; CHECK-NEXT:  Equal predicate: (zext i2 (-2 + (trunc i64 %m to i2)) to i64) == 0
 ;
 entry:
   %mul = mul nsw i64 %n, 10
@@ -81,8 +76,6 @@ define i32 @gep_i8_vs_i32(ptr nocapture %A, i64 %n, i64 %m) {
 ; CHECK-NEXT:    Equal predicate: (zext i2 (trunc i64 %n to i2) to i64) == 0
 ; CHECK-NEXT:  Src: store i32 42, ptr %arrayidx1, align 4 --> Dst: store i32 42, ptr %arrayidx1, align 4
 ; CHECK-NEXT:    da analyze - none!
-; CHECK-NEXT:  Runtime Assumptions:
-; CHECK-NEXT:  Equal predicate: (zext i2 (trunc i64 %n to i2) to i64) == 0
 ;
 entry:
   %arrayidx0 = getelementptr inbounds i8, ptr %A, i64 %n
diff --git a/llvm/test/Analysis/DependenceAnalysis/MIVCheckConst.ll b/llvm/test/Analysis/DependenceAnalysis/MIVCheckConst.ll
index f5be89a51f484..bcf73683e4dab 100644
--- a/llvm/test/Analysis/DependenceAnalysis/MIVCheckConst.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/MIVCheckConst.ll
@@ -50,9 +50,6 @@ define void @test(ptr %A, ptr %B, i1 %arg, i32 %n, i32 %m) align 2 {
 ; CHECK-NEXT:    Equal predicate: (8 * (zext i4 (trunc i32 %v1 to i4) to i32))<nuw><nsw> == 0
 ; CHECK-NEXT:  Src: %v32 = load <32 x i32>, ptr %v30, align 128 --> Dst: %v32 = load <32 x i32>, ptr %v30, align 128
 ; CHECK-NEXT:    da analyze - consistent input [0 S S]!
-; CHECK-NEXT:  Runtime Assumptions:
-; CHECK-NEXT:  Equal predicate: (zext i7 (4 * (trunc i32 %v1 to i7) * (1 + (trunc i32 %n to i7))) to i32) == 0
-; CHECK-NEXT:  Equal predicate: (8 * (zext i4 (trunc i32 %v1 to i4) to i32))<nuw><nsw> == 0
 ;
 entry:
   %v1 = load i32, ptr %B, align 4

>From fd4d67022088272e5b8fc23f633cdab6715ebeee Mon Sep 17 00:00:00 2001
From: Sebastian Pop <spop at nvidia.com>
Date: Tue, 25 Nov 2025 14:11:26 -0500
Subject: [PATCH 2/4] [DA] Fix zero coefficient bug in Strong SIV test using
 runtime assumptions

The Strong SIV test was incorrectly concluding "no dependence" when the
coefficient is symbolic and the delta (difference between source and
destination) is zero.

When delta=0, the Strong SIV test divides delta/coeff to get the distance.
The bug occurs when coeff is an unknown symbolic value: if coeff=0 at runtime,
then 0/0 is undefined and all iterations access the same memory location,
creating a true dependence that was being missed.
---
 .../llvm/Analysis/DependenceAnalysis.h        |  4 +-
 llvm/lib/Analysis/DependenceAnalysis.cpp      | 57 ++++++++++++++++---
 .../Analysis/DependenceAnalysis/DADelin.ll    | 16 ++++--
 .../DependenceAnalysis/zero-coefficient.ll    | 34 +++++++++++
 4 files changed, 98 insertions(+), 13 deletions(-)
 create mode 100644 llvm/test/Analysis/DependenceAnalysis/zero-coefficient.ll

diff --git a/llvm/include/llvm/Analysis/DependenceAnalysis.h b/llvm/include/llvm/Analysis/DependenceAnalysis.h
index a39a9d4b66442..0ed069385cf8c 100644
--- a/llvm/include/llvm/Analysis/DependenceAnalysis.h
+++ b/llvm/include/llvm/Analysis/DependenceAnalysis.h
@@ -554,7 +554,7 @@ class DependenceInfo {
   /// If the dependence isn't proven to exist,
   /// marks the Result as inconsistent.
   bool testSIV(const SCEV *Src, const SCEV *Dst, unsigned &Level,
-               FullDependence &Result) const;
+               FullDependence &Result, bool UnderRuntimeAssumptions);
 
   /// testRDIV - Tests the RDIV subscript pair (Src and Dst) for dependence.
   /// Things of the form [c1 + a1*i] and [c2 + a2*j]
@@ -584,7 +584,7 @@ class DependenceInfo {
   bool strongSIVtest(const SCEV *Coeff, const SCEV *SrcConst,
                      const SCEV *DstConst, const Loop *CurrentSrcLoop,
                      const Loop *CurrentDstLoop, unsigned Level,
-                     FullDependence &Result) const;
+                     FullDependence &Result, bool UnderRuntimeAssumptions);
 
   /// weakCrossingSIVtest - Tests the weak-crossing SIV subscript pair
   /// (Src and Dst) for dependence.
diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index 5fc9614298c77..a8bd72ed62829 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -1373,7 +1373,8 @@ bool DependenceInfo::testZIV(const SCEV *Src, const SCEV *Dst,
 bool DependenceInfo::strongSIVtest(const SCEV *Coeff, const SCEV *SrcConst,
                                    const SCEV *DstConst, const Loop *CurSrcLoop,
                                    const Loop *CurDstLoop, unsigned Level,
-                                   FullDependence &Result) const {
+                                   FullDependence &Result,
+                                   bool UnderRuntimeAssumptions) {
   if (!isDependenceTestEnabled(DependenceTestType::StrongSIV))
     return false;
 
@@ -1445,7 +1446,38 @@ bool DependenceInfo::strongSIVtest(const SCEV *Coeff, const SCEV *SrcConst,
       Result.DV[Level].Direction &= Dependence::DVEntry::EQ;
     ++StrongSIVsuccesses;
   } else if (Delta->isZero()) {
-    // since 0/X == 0
+    // Check if coefficient could be zero. If so, 0/0 is undefined and we
+    // cannot conclude that only same-iteration dependencies exist.
+    // When coeff=0, all iterations access the same location.
+    if (isa<SCEVUnknown>(Coeff)) {
+      // Use both isKnownNonZero and range analysis to prove coefficient != 0.
+      bool CoeffKnownNonZero = SE->isKnownNonZero(Coeff) ||
+                               isKnownPredicate(CmpInst::ICMP_NE, Coeff,
+                                                SE->getZero(Coeff->getType()));
+      if (!CoeffKnownNonZero) {
+        // Cannot prove at compile time, would need runtime assumption.
+        if (UnderRuntimeAssumptions) {
+          const SCEVPredicate *Pred = SE->getComparePredicate(
+              ICmpInst::ICMP_NE, Coeff, SE->getZero(Coeff->getType()));
+          SmallVector<const SCEVPredicate *, 4> NewPreds(
+              Result.Assumptions.getPredicates());
+          NewPreds.push_back(Pred);
+          Result.Assumptions = SCEVUnionPredicate(NewPreds, *SE);
+          LLVM_DEBUG(dbgs() << "\t    Added runtime assumption: " << *Coeff
+                            << " != 0\n");
+        } else {
+          // Cannot add runtime assumptions, this test cannot handle this case.
+          // Let more complex tests try.
+          LLVM_DEBUG(dbgs() << "\t    Would need runtime assumption " << *Coeff
+                            << " != 0, but not allowed. Failing this test.\n");
+          return false;
+        }
+      } else {
+        LLVM_DEBUG(
+            dbgs() << "\t    Coefficient proven non-zero by SCEV analysis\n");
+      }
+    }
+    // Since 0/X == 0 (where X is known non-zero or assumed non-zero).
     Result.DV[Level].Distance = Delta;
     Result.DV[Level].Direction &= Dependence::DVEntry::EQ;
     ++StrongSIVsuccesses;
@@ -2408,7 +2440,8 @@ bool DependenceInfo::symbolicRDIVtest(const SCEV *A1, const SCEV *A2,
 //
 // Return true if dependence disproved.
 bool DependenceInfo::testSIV(const SCEV *Src, const SCEV *Dst, unsigned &Level,
-                             FullDependence &Result) const {
+                             FullDependence &Result,
+                             bool UnderRuntimeAssumptions) {
   LLVM_DEBUG(dbgs() << "    src = " << *Src << "\n");
   LLVM_DEBUG(dbgs() << "    dst = " << *Dst << "\n");
   const SCEVAddRecExpr *SrcAddRec = dyn_cast<SCEVAddRecExpr>(Src);
@@ -2426,8 +2459,9 @@ bool DependenceInfo::testSIV(const SCEV *Src, const SCEV *Dst, unsigned &Level,
     Level = mapSrcLoop(CurSrcLoop);
     bool disproven;
     if (SrcCoeff == DstCoeff)
-      disproven = strongSIVtest(SrcCoeff, SrcConst, DstConst, CurSrcLoop,
-                                CurDstLoop, Level, Result);
+      disproven =
+          strongSIVtest(SrcCoeff, SrcConst, DstConst, CurSrcLoop, CurDstLoop,
+                        Level, Result, UnderRuntimeAssumptions);
     else if (SrcCoeff == SE->getNegativeSCEV(DstCoeff))
       disproven = weakCrossingSIVtest(SrcCoeff, SrcConst, DstConst, CurSrcLoop,
                                       CurDstLoop, Level, Result);
@@ -3666,6 +3700,10 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
 
   FullDependence Result(Src, Dst, SCEVUnionPredicate(Assume, *SE),
                         PossiblyLoopIndependent, CommonLevels);
+  // Track assumptions before running dependence tests. If new assumptions are
+  // added during tests, we must return the result even if AllEqual to preserve
+  // those assumptions for the caller.
+  size_t AssumptionsBeforeTests = Result.Assumptions.getPredicates().size();
   ++TotalArrayPairs;
 
   for (unsigned P = 0; P < Pairs; ++P) {
@@ -3709,7 +3747,8 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
     case Subscript::SIV: {
       LLVM_DEBUG(dbgs() << ", SIV\n");
       unsigned Level;
-      if (testSIV(Pair[SI].Src, Pair[SI].Dst, Level, Result))
+      if (testSIV(Pair[SI].Src, Pair[SI].Dst, Level, Result,
+                  UnderRuntimeAssumptions))
         return nullptr;
       break;
     }
@@ -3790,6 +3829,8 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
   } else {
     // On the other hand, if all directions are equal and there's no
     // loop-independent dependence possible, then no dependence exists.
+    // However, if we added runtime assumptions during the dependence tests,
+    // we must return the result to preserve those assumptions for the caller.
     bool AllEqual = true;
     for (unsigned II = 1; II <= CommonLevels; ++II) {
       if (Result.getDirection(II) != Dependence::DVEntry::EQ) {
@@ -3797,7 +3838,9 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
         break;
       }
     }
-    if (AllEqual)
+    bool AddedAssumptionsDuringTests =
+        Result.Assumptions.getPredicates().size() > AssumptionsBeforeTests;
+    if (AllEqual && !AddedAssumptionsDuringTests)
       return nullptr;
   }
 
diff --git a/llvm/test/Analysis/DependenceAnalysis/DADelin.ll b/llvm/test/Analysis/DependenceAnalysis/DADelin.ll
index 8f94a455d3724..60ce6a96abd5f 100644
--- a/llvm/test/Analysis/DependenceAnalysis/DADelin.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/DADelin.ll
@@ -646,11 +646,15 @@ exit:
 define void @coeff_may_negative(ptr %a, i32 %k) {
 ; CHECK-LABEL: 'coeff_may_negative'
 ; CHECK-NEXT:  Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.0, align 1
-; CHECK-NEXT:    da analyze - none!
+; CHECK-NEXT:    da analyze - consistent output [0]!
+; CHECK-NEXT:    Runtime Assumptions:
+; CHECK-NEXT:    Compare predicate: %k ne) 0
 ; CHECK-NEXT:  Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
 ; CHECK-NEXT:    da analyze - output [*|<]!
 ; CHECK-NEXT:  Src: store i8 42, ptr %idx.1, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
-; CHECK-NEXT:    da analyze - none!
+; CHECK-NEXT:    da analyze - consistent output [0]!
+; CHECK-NEXT:    Runtime Assumptions:
+; CHECK-NEXT:    Compare predicate: %k ne) 0
 ;
 entry:
   br label %loop
@@ -685,11 +689,15 @@ exit:
 define void @coeff_positive(ptr %a, i32 %k) {
 ; CHECK-LABEL: 'coeff_positive'
 ; CHECK-NEXT:  Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.0, align 1
-; CHECK-NEXT:    da analyze - none!
+; CHECK-NEXT:    da analyze - consistent output [0]!
+; CHECK-NEXT:    Runtime Assumptions:
+; CHECK-NEXT:    Compare predicate: %k ne) 0
 ; CHECK-NEXT:  Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
 ; CHECK-NEXT:    da analyze - output [*|<]!
 ; CHECK-NEXT:  Src: store i8 42, ptr %idx.1, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
-; CHECK-NEXT:    da analyze - none!
+; CHECK-NEXT:    da analyze - consistent output [0]!
+; CHECK-NEXT:    Runtime Assumptions:
+; CHECK-NEXT:    Compare predicate: %k ne) 0
 ;
 entry:
   br label %loop
diff --git a/llvm/test/Analysis/DependenceAnalysis/zero-coefficient.ll b/llvm/test/Analysis/DependenceAnalysis/zero-coefficient.ll
new file mode 100644
index 0000000000000..7181e0bfb9a3d
--- /dev/null
+++ b/llvm/test/Analysis/DependenceAnalysis/zero-coefficient.ll
@@ -0,0 +1,34 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -disable-output "-passes=print<da>" -aa-pipeline=basic-aa 2>&1 \
+; RUN: | FileCheck %s
+
+; Test case for bug fix where Strong SIV test incorrectly concludes "no dependence"
+; when the coefficient is symbolic (unknown at compile time) and delta is zero.
+;
+; In this case, the array access is A[k*i] with both src and dst at the same
+; location in the same iteration. If k=0, then all iterations access the same
+; element, meaning there IS a dependence between different iterations.
+; The Strong SIV test should add a runtime assumption that k != 0.
+
+define void @test_zero_coefficient(ptr noalias %A, i64 %k) {
+; CHECK-LABEL: 'test_zero_coefficient'
+; CHECK-NEXT:  Src: store i8 42, ptr %idx, align 1 --> Dst: store i8 42, ptr %idx, align 1
+; CHECK-NEXT:    da analyze - consistent output [0]!
+; CHECK-NEXT:    Runtime Assumptions:
+; CHECK-NEXT:    Compare predicate: %k ne) 0
+;
+entry:
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+  %off = mul nsw i64 %i, %k
+  %idx = getelementptr inbounds i8, ptr %A, i64 %off
+  store i8 42, ptr %idx, align 1
+  %i.next = add nsw i64 %i, 1
+  %cmp = icmp slt i64 %i.next, 100
+  br i1 %cmp, label %loop, label %exit
+
+exit:
+  ret void
+}

>From 7f8455716ecf03c795347df962be0b7d915ea17a Mon Sep 17 00:00:00 2001
From: Sebastian Pop <spop at nvidia.com>
Date: Fri, 28 Nov 2025 05:35:30 -0500
Subject: [PATCH 3/4] [SCEV] Add SCEVUnionPredicate::getUnionWith method

---
 llvm/include/llvm/Analysis/ScalarEvolution.h | 9 +++++++++
 llvm/lib/Analysis/DependenceAnalysis.cpp     | 5 +----
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h
index 04ea769bd06d1..f594c26cc5a77 100644
--- a/llvm/include/llvm/Analysis/ScalarEvolution.h
+++ b/llvm/include/llvm/Analysis/ScalarEvolution.h
@@ -427,6 +427,15 @@ class LLVM_ABI SCEVUnionPredicate final : public SCEVPredicate {
 
   ArrayRef<const SCEVPredicate *> getPredicates() const { return Preds; }
 
+  /// Returns a new SCEVUnionPredicate that is the union of this predicate
+  /// and the given predicate \p N.
+  SCEVUnionPredicate getUnionWith(const SCEVPredicate *N,
+                                  ScalarEvolution &SE) const {
+    SCEVUnionPredicate Result(Preds, SE);
+    Result.add(N, SE);
+    return Result;
+  }
+
   /// Implementation of the SCEVPredicate interface
   bool isAlwaysTrue() const override;
   bool implies(const SCEVPredicate *N, ScalarEvolution &SE) const override;
diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index a8bd72ed62829..fafdc9d464784 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -1459,10 +1459,7 @@ bool DependenceInfo::strongSIVtest(const SCEV *Coeff, const SCEV *SrcConst,
         if (UnderRuntimeAssumptions) {
           const SCEVPredicate *Pred = SE->getComparePredicate(
               ICmpInst::ICMP_NE, Coeff, SE->getZero(Coeff->getType()));
-          SmallVector<const SCEVPredicate *, 4> NewPreds(
-              Result.Assumptions.getPredicates());
-          NewPreds.push_back(Pred);
-          Result.Assumptions = SCEVUnionPredicate(NewPreds, *SE);
+          Result.Assumptions = Result.Assumptions.getUnionWith(Pred, *SE);
           LLVM_DEBUG(dbgs() << "\t    Added runtime assumption: " << *Coeff
                             << " != 0\n");
         } else {

>From 69358ba13325b2b30dae823714f6ed3a2cc65d56 Mon Sep 17 00:00:00 2001
From: Sebastian Pop <spop at nvidia.com>
Date: Fri, 28 Nov 2025 05:43:59 -0500
Subject: [PATCH 4/4] small other fixes

---
 llvm/lib/Analysis/DependenceAnalysis.cpp                  | 5 ++---
 llvm/test/Analysis/DependenceAnalysis/zero-coefficient.ll | 2 +-
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index fafdc9d464784..82554399ac2a8 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -3636,11 +3636,10 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
                                         SCEVUnionPredicate(Assume, *SE));
   }
 
-  if (!Assume.empty() && !UnderRuntimeAssumptions) {
-    // Runtime assumptions needed but not allowed.
+  // Runtime assumptions needed but not allowed.
+  if (!Assume.empty() && !UnderRuntimeAssumptions)
     return std::make_unique<Dependence>(Src, Dst,
                                         SCEVUnionPredicate(Assume, *SE));
-  }
 
   unsigned Pairs = 1;
   SmallVector<Subscript, 2> Pair(Pairs);
diff --git a/llvm/test/Analysis/DependenceAnalysis/zero-coefficient.ll b/llvm/test/Analysis/DependenceAnalysis/zero-coefficient.ll
index 7181e0bfb9a3d..55f0ecc123e3a 100644
--- a/llvm/test/Analysis/DependenceAnalysis/zero-coefficient.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/zero-coefficient.ll
@@ -2,7 +2,7 @@
 ; RUN: opt < %s -disable-output "-passes=print<da>" -aa-pipeline=basic-aa 2>&1 \
 ; RUN: | FileCheck %s
 
-; Test case for bug fix where Strong SIV test incorrectly concludes "no dependence"
+; Test case for bug #149991 where Strong SIV test incorrectly concludes "no dependence"
 ; when the coefficient is symbolic (unknown at compile time) and delta is zero.
 ;
 ; In this case, the array access is A[k*i] with both src and dst at the same



More information about the llvm-commits mailing list