Skip to content

Conversation

sebpop
Copy link
Contributor

@sebpop sebpop commented Sep 9, 2025

Address GitHub issue #149501.
Fixes incorrect independence conclusions in symbolic RDIV test and improves
Strong SIV bound checking for symbolic expressions.

The patch fixes:

  • Strong SIV: Improve bound checking for symbolic expressions, avoid impossible
    assumptions like 0 <= -1 when Delta and UpperBound have inverse relationships.

  • Symbolic RDIV: Detect when C2-C1 == N1+1 creates trivially true comparisons
    leading to wrong none! conclusions, now returns conservative analysis. The
    symbolic RDIV fix prevents cases where expressions like (m-n) > (m-n-1)
    incorrectly conclude independence. Now returns conservative output [*|<]!
    instead of wrong none! for symbolic expressions with problematic bounds.

…149501)

Address GitHub issue llvm#149501.
Fixes incorrect independence conclusions in symbolic RDIV test and improves
Strong SIV bound checking for symbolic expressions.

The patch fixes:

- Strong SIV: Improve bound checking for symbolic expressions, avoid impossible
  assumptions like '0 <= -1' when Delta and UpperBound have inverse relationships.

- Symbolic RDIV: Detect when C2-C1 == N1+1 creates trivially true comparisons
  leading to wrong 'none!' conclusions, now returns conservative analysis. The
  symbolic RDIV fix prevents cases where expressions like (m-n) > (m-n-1)
  incorrectly conclude independence. Now returns conservative 'output [*|<]!'
  instead of wrong 'none!' for symbolic expressions with problematic bounds.
@llvmbot llvmbot added the llvm:analysis Includes value tracking, cost tables and constant folding label Sep 9, 2025
@llvmbot
Copy link
Member

llvmbot commented Sep 9, 2025

@llvm/pr-subscribers-llvm-analysis

Author: Sebastian Pop (sebpop)

Changes

Address GitHub issue #149501.
Fixes incorrect independence conclusions in symbolic RDIV test and improves
Strong SIV bound checking for symbolic expressions.

The patch fixes:

  • Strong SIV: Improve bound checking for symbolic expressions, avoid impossible
    assumptions like '0 <= -1' when Delta and UpperBound have inverse relationships.

  • Symbolic RDIV: Detect when C2-C1 == N1+1 creates trivially true comparisons
    leading to wrong 'none!' conclusions, now returns conservative analysis. The
    symbolic RDIV fix prevents cases where expressions like (m-n) > (m-n-1)
    incorrectly conclude independence. Now returns conservative 'output [*|<]!'
    instead of wrong 'none!' for symbolic expressions with problematic bounds.


Patch is 29.20 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/157761.diff

10 Files Affected:

  • (modified) llvm/include/llvm/Analysis/DependenceAnalysis.h (+29-2)
  • (modified) llvm/lib/Analysis/DependenceAnalysis.cpp (+169-38)
  • (modified) llvm/test/Analysis/DependenceAnalysis/BasePtrBug.ll (+1-1)
  • (modified) llvm/test/Analysis/DependenceAnalysis/DADelin.ll (+2-2)
  • (modified) llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll (-5)
  • (modified) llvm/test/Analysis/DependenceAnalysis/MIVCheckConst.ll (-3)
  • (added) llvm/test/Analysis/DependenceAnalysis/PR149501.ll (+90)
  • (added) llvm/test/Analysis/DependenceAnalysis/PR149977.ll (+45)
  • (modified) llvm/test/Analysis/DependenceAnalysis/StrongSIV.ll (+1-1)
  • (modified) llvm/test/Analysis/DependenceAnalysis/SymbolicSIV.ll (+1-1)
diff --git a/llvm/include/llvm/Analysis/DependenceAnalysis.h b/llvm/include/llvm/Analysis/DependenceAnalysis.h
index f66c79d915665..300cfb73af5c1 100644
--- a/llvm/include/llvm/Analysis/DependenceAnalysis.h
+++ b/llvm/include/llvm/Analysis/DependenceAnalysis.h
@@ -285,7 +285,8 @@ class LLVM_ABI FullDependence final : public Dependence {
 class DependenceInfo {
 public:
   DependenceInfo(Function *F, AAResults *AA, ScalarEvolution *SE, LoopInfo *LI)
-      : AA(AA), SE(SE), LI(LI), F(F) {}
+      : AA(AA), SE(SE), LI(LI), F(F), Assumptions({}, *SE),
+        UnderRuntimeAssumptions(false) {}
 
   /// Handle transitive invalidation when the cached analysis results go away.
   LLVM_ABI bool invalidate(Function &F, const PreservedAnalyses &PA,
@@ -355,7 +356,33 @@ class DependenceInfo {
   ScalarEvolution *SE;
   LoopInfo *LI;
   Function *F;
-  SmallVector<const SCEVPredicate *, 4> Assumptions;
+
+  /// Runtime assumptions collected during dependence analysis.
+  ///
+  /// The dependence analysis employs a cascade of tests from simple to complex:
+  /// ZIV -> SIV (Strong/Weak-Crossing/Weak-Zero) -> RDIV -> MIV -> Banerjee.
+  /// Each test attempts to characterize the dependence with increasing
+  /// precision.
+  ///
+  /// Assumption Management Strategy:
+  /// - Each test may require runtime assumptions (e.g., "coefficient != 0")
+  ///   to provide precise analysis.
+  /// - If UnderRuntimeAssumptions=true: tests can add assumptions and continue.
+  /// - If UnderRuntimeAssumptions=false: tests that need assumptions fail
+  ///   gracefully, allowing more complex tests to attempt analysis.
+  /// - Only assumptions from successful tests contribute to the final result.
+  /// - SCEVUnionPredicate automatically deduplicates redundant assumptions.
+  ///
+  /// This design ensures:
+  /// 1. Simpler tests get priority (better performance).
+  /// 2. Complex tests serve as fallbacks when simple tests fail.
+  /// 3. No unnecessary runtime checks from failed test attempts.
+  /// 4. Maintains the intended cascade behavior of the dependence analysis.
+  SCEVUnionPredicate Assumptions;
+
+  /// Indicates whether runtime assumptions are collected during the analysis.
+  /// When false, dependence tests that would require runtime assumptions fail.
+  bool UnderRuntimeAssumptions;
 
   /// 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 da86a8d2cc9c0..ef7ba48c8fa9a 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -1243,16 +1243,76 @@ bool DependenceInfo::strongSIVtest(const SCEV *Coeff, const SCEV *SrcConst,
   if (const SCEV *UpperBound = collectUpperBound(CurLoop, Delta->getType())) {
     LLVM_DEBUG(dbgs() << "\t    UpperBound = " << *UpperBound);
     LLVM_DEBUG(dbgs() << ", " << *UpperBound->getType() << "\n");
+
+    // Handle negative upper bound - loop doesn't execute.
+    if (SE->isKnownNegative(UpperBound)) {
+      LLVM_DEBUG(dbgs() << "\t    Negative upper bound - no dependence\n");
+      ++StrongSIVindependence;
+      ++StrongSIVsuccesses;
+      return true;
+    }
+
     const SCEV *AbsDelta =
         SE->isKnownNonNegative(Delta) ? Delta : SE->getNegativeSCEV(Delta);
     const SCEV *AbsCoeff =
         SE->isKnownNonNegative(Coeff) ? Coeff : SE->getNegativeSCEV(Coeff);
     const SCEV *Product = SE->getMulExpr(UpperBound, AbsCoeff);
+
     if (isKnownPredicate(CmpInst::ICMP_SGT, AbsDelta, Product)) {
-      // Distance greater than trip count - no dependence
-      ++StrongSIVindependence;
-      ++StrongSIVsuccesses;
-      return true;
+      // Check if this involves symbolic expressions where we might be too
+      // conservative.
+      if (isa<SCEVUnknown>(Delta) || isa<SCEVUnknown>(Coeff) ||
+          !isa<SCEVConstant>(AbsDelta) || !isa<SCEVConstant>(Product)) {
+        // Check if the assumption would be meaningful and not trivially
+        // impossible. For relationships like Delta=n-m, UpperBound=m-n-1, the
+        // assumption |n-m| <= (m-n-1) can be impossible (e.g., 0 <= -1 when
+        // n=m).
+        bool MeaningfulAssumption = true;
+
+        // Detect cases where Delta and UpperBound have inverse relationships
+        // that could lead to impossible assumptions.
+        if (isa<SCEVAddExpr>(Delta) && isa<SCEVAddExpr>(UpperBound)) {
+          // Look for patterns where UpperBound = -Delta - 1 (or similar).
+          const SCEV *NegDelta = SE->getNegativeSCEV(Delta);
+          const SCEV *NegDeltaMinusOne =
+              SE->getAddExpr(NegDelta, SE->getConstant(Delta->getType(), -1));
+          if (UpperBound == NegDeltaMinusOne) {
+            MeaningfulAssumption = false;
+            LLVM_DEBUG(dbgs() << "\t    Detected inverse relationship - "
+                                 "assumption would be impossible\n");
+          }
+        }
+
+        if (MeaningfulAssumption && !SE->isKnownNonPositive(Product)) {
+          // For symbolic expressions, add runtime assumption rather than
+          // rejecting.
+          const SCEVPredicate *BoundPred =
+              SE->getComparePredicate(ICmpInst::ICMP_SLE, AbsDelta, Product);
+          if (UnderRuntimeAssumptions) {
+            SmallVector<const SCEVPredicate *, 4> NewPreds(
+                Assumptions.getPredicates());
+            NewPreds.push_back(BoundPred);
+            const_cast<DependenceInfo *>(this)->Assumptions =
+                SCEVUnionPredicate(NewPreds, *SE);
+            LLVM_DEBUG(dbgs() << "\t    Added runtime bound assumption\n");
+          } else {
+            // Cannot add runtime assumptions, let more complex tests try.
+            LLVM_DEBUG(dbgs() << "\t    Would need runtime bound assumption "
+                                 "but not allowed. Failing this test.\n");
+            return false;
+          }
+        } else {
+          LLVM_DEBUG(dbgs() << "\t    Cannot add meaningful assumption\n");
+          // When bound check fails and we can't add meaningful assumptions,
+          // this test cannot handle this case reliably.
+          return false;
+        }
+      } else {
+        // Distance definitely greater than trip count - no dependence.
+        ++StrongSIVindependence;
+        ++StrongSIVsuccesses;
+        return true;
+      }
     }
   }
 
@@ -1293,9 +1353,40 @@ bool DependenceInfo::strongSIVtest(const SCEV *Coeff, const SCEV *SrcConst,
       Result.DV[Level].Distance = Delta; // since X/1 == X
       NewConstraint.setDistance(Delta, CurLoop);
     } else {
-      Result.Consistent = false;
-      NewConstraint.setLine(Coeff, SE->getNegativeSCEV(Coeff),
-                            SE->getNegativeSCEV(Delta), CurLoop);
+      // Try symbolic division: Distance = Delta / Coeff.
+      if (const SCEV *Distance = SE->getUDivExactExpr(Delta, Coeff)) {
+        LLVM_DEBUG(dbgs() << "\t    Symbolic distance = " << *Distance << "\n");
+        Result.DV[Level].Distance = Distance;
+        NewConstraint.setDistance(Distance, CurLoop);
+      } else {
+        // Cannot compute exact division - check if we can add runtime
+        // assumptions.
+        if (isa<SCEVUnknown>(Coeff) && !SE->isKnownNonZero(Coeff)) {
+          // Add runtime assumption that coefficient is non-zero for division.
+          const SCEV *Zero = SE->getZero(Coeff->getType());
+          const SCEVPredicate *NonZeroPred =
+              SE->getComparePredicate(ICmpInst::ICMP_NE, Coeff, Zero);
+          if (UnderRuntimeAssumptions) {
+            SmallVector<const SCEVPredicate *, 4> NewPreds(
+                Assumptions.getPredicates());
+            NewPreds.push_back(NonZeroPred);
+            const_cast<DependenceInfo *>(this)->Assumptions =
+                SCEVUnionPredicate(NewPreds, *SE);
+            LLVM_DEBUG(dbgs() << "\t    Added runtime assumption: " << *Coeff
+                              << " != 0 for symbolic division\n");
+          } else {
+            // Cannot add runtime assumptions, this test fails.
+            LLVM_DEBUG(dbgs()
+                       << "\t    Would need runtime assumption " << *Coeff
+                       << " != 0 but not allowed. Failing this test.\n");
+            return false;
+          }
+        }
+
+        Result.Consistent = false;
+        NewConstraint.setLine(Coeff, SE->getNegativeSCEV(Coeff),
+                              SE->getNegativeSCEV(Delta), CurLoop);
+      }
     }
 
     // maybe we can get a useful direction
@@ -2135,8 +2226,39 @@ bool DependenceInfo::symbolicRDIVtest(const SCEV *A1, const SCEV *A2,
   const SCEV *N2 = collectUpperBound(Loop2, A1->getType());
   LLVM_DEBUG(if (N1) dbgs() << "\t    N1 = " << *N1 << "\n");
   LLVM_DEBUG(if (N2) dbgs() << "\t    N2 = " << *N2 << "\n");
+
   const SCEV *C2_C1 = SE->getMinusSCEV(C2, C1);
   const SCEV *C1_C2 = SE->getMinusSCEV(C1, C2);
+
+  // Check for negative or problematic upper bounds
+  auto CheckUpperBound = [&](const SCEV *N, const SCEV *Delta,
+                             const char *Name) -> bool {
+    if (!N)
+      // No bound to check.
+      return true;
+
+    if (SE->isKnownNegative(N)) {
+      LLVM_DEBUG(dbgs() << "\t    " << Name
+                        << " is negative - analysis unreliable\n");
+      return false;
+    }
+
+    // Check for degenerate cases where upper bounds are too close to the delta
+    // values. This can happen when N is an expression like (Delta - 1), leading
+    // to trivially true comparisons like Delta > (Delta - 1).
+    const SCEV *NPlusOne = SE->getAddExpr(N, SE->getOne(N->getType()));
+    if (Delta == NPlusOne) {
+      LLVM_DEBUG(dbgs() << "\t    Degenerate case: Delta == " << Name
+                        << "+1 - analysis unreliable\n");
+      return false;
+    }
+    // Bound is OK.
+    return true;
+  };
+
+  if (!CheckUpperBound(N1, C2_C1, "N1") || !CheckUpperBound(N2, C1_C2, "N2"))
+    return false;
+
   LLVM_DEBUG(dbgs() << "\t    C2 - C1 = " << *C2_C1 << "\n");
   LLVM_DEBUG(dbgs() << "\t    C1 - C2 = " << *C1_C2 << "\n");
   if (SE->isKnownNonNegative(A1)) {
@@ -3567,7 +3689,7 @@ bool DependenceInfo::invalidate(Function &F, const PreservedAnalyses &PA,
 }
 
 SCEVUnionPredicate DependenceInfo::getRuntimeAssumptions() const {
-  return SCEVUnionPredicate(Assumptions, *SE);
+  return Assumptions;
 }
 
 // depends -
@@ -3584,7 +3706,12 @@ SCEVUnionPredicate DependenceInfo::getRuntimeAssumptions() const {
 std::unique_ptr<Dependence>
 DependenceInfo::depends(Instruction *Src, Instruction *Dst,
                         bool UnderRuntimeAssumptions) {
-  SmallVector<const SCEVPredicate *, 4> Assume;
+  // Set the flag for whether we're allowed to add runtime assumptions.
+  this->UnderRuntimeAssumptions = UnderRuntimeAssumptions;
+
+  // Clear any previous assumptions
+  Assumptions = SCEVUnionPredicate({}, *SE);
+
   bool PossiblyLoopIndependent = true;
   if (Src == Dst)
     PossiblyLoopIndependent = false;
@@ -3596,8 +3723,7 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
   if (!isLoadOrStore(Src) || !isLoadOrStore(Dst)) {
     // can only analyze simple loads and stores, i.e., no calls, invokes, etc.
     LLVM_DEBUG(dbgs() << "can only handle simple loads and stores\n");
-    return std::make_unique<Dependence>(Src, Dst,
-                                        SCEVUnionPredicate(Assume, *SE));
+    return std::make_unique<Dependence>(Src, Dst, getRuntimeAssumptions());
   }
 
   const MemoryLocation &DstLoc = MemoryLocation::get(Dst);
@@ -3608,8 +3734,7 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
   case AliasResult::PartialAlias:
     // cannot analyse objects if we don't understand their aliasing.
     LLVM_DEBUG(dbgs() << "can't analyze may or partial alias\n");
-    return std::make_unique<Dependence>(Src, Dst,
-                                        SCEVUnionPredicate(Assume, *SE));
+    return std::make_unique<Dependence>(Src, Dst, getRuntimeAssumptions());
   case AliasResult::NoAlias:
     // If the objects noalias, they are distinct, accesses are independent.
     LLVM_DEBUG(dbgs() << "no alias\n");
@@ -3623,8 +3748,7 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
     // The dependence test gets confused if the size of the memory accesses
     // differ.
     LLVM_DEBUG(dbgs() << "can't analyze must alias with different sizes\n");
-    return std::make_unique<Dependence>(Src, Dst,
-                                        SCEVUnionPredicate(Assume, *SE));
+    return std::make_unique<Dependence>(Src, Dst, getRuntimeAssumptions());
   }
 
   Value *SrcPtr = getLoadStorePointerOperand(Src);
@@ -3643,8 +3767,7 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
     // We check this upfront so we don't crash in cases where getMinusSCEV()
     // returns a SCEVCouldNotCompute.
     LLVM_DEBUG(dbgs() << "can't analyze SCEV with different pointer base\n");
-    return std::make_unique<Dependence>(Src, Dst,
-                                        SCEVUnionPredicate(Assume, *SE));
+    return std::make_unique<Dependence>(Src, Dst, getRuntimeAssumptions());
   }
 
   // Even if the base pointers are the same, they may not be loop-invariant. It
@@ -3656,8 +3779,7 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
   if (!isLoopInvariant(SrcBase, SrcLoop) ||
       !isLoopInvariant(DstBase, DstLoop)) {
     LLVM_DEBUG(dbgs() << "The base pointer is not loop invariant.\n");
-    return std::make_unique<Dependence>(Src, Dst,
-                                        SCEVUnionPredicate(Assume, *SE));
+    return std::make_unique<Dependence>(Src, Dst, getRuntimeAssumptions());
   }
 
   uint64_t EltSize = SrcLoc.Size.toRaw();
@@ -3665,35 +3787,40 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
   const SCEV *DstEv = SE->getMinusSCEV(DstSCEV, DstBase);
 
   // Check that memory access offsets are multiples of element sizes.
-  if (!SE->isKnownMultipleOf(SrcEv, EltSize, Assume) ||
-      !SE->isKnownMultipleOf(DstEv, EltSize, Assume)) {
+  SmallVector<const SCEVPredicate *, 4> TempAssumptions;
+  if (!SE->isKnownMultipleOf(SrcEv, EltSize, TempAssumptions) ||
+      !SE->isKnownMultipleOf(DstEv, EltSize, TempAssumptions)) {
     LLVM_DEBUG(dbgs() << "can't analyze SCEV with different offsets\n");
-    return std::make_unique<Dependence>(Src, Dst,
-                                        SCEVUnionPredicate(Assume, *SE));
+    return std::make_unique<Dependence>(Src, Dst, getRuntimeAssumptions());
   }
 
-  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);
+  // Add any new assumptions from the isKnownMultipleOf calls
+  if (!TempAssumptions.empty()) {
+    if (UnderRuntimeAssumptions) {
+      SmallVector<const SCEVPredicate *, 4> NewPreds(
+          Assumptions.getPredicates());
+      NewPreds.append(TempAssumptions.begin(), TempAssumptions.end());
+      const_cast<DependenceInfo *>(this)->Assumptions =
+          SCEVUnionPredicate(NewPreds, *SE);
+    } else {
+      // Runtime assumptions needed but not allowed.
+      // Return confused dependence since we cannot proceed with precise
+      // analysis.
+      LLVM_DEBUG(dbgs() << "Runtime assumptions needed for offset analysis but "
+                           "not allowed\n");
+      return std::make_unique<Dependence>(Src, Dst, getRuntimeAssumptions());
     }
   }
 
+  // Assert that we haven't added runtime assumptions when not allowed
+  assert(UnderRuntimeAssumptions || Assumptions.isAlwaysTrue());
+
   establishNestingLevels(Src, Dst);
   LLVM_DEBUG(dbgs() << "    common nesting levels = " << CommonLevels << "\n");
   LLVM_DEBUG(dbgs() << "    maximum nesting levels = " << MaxLevels << "\n");
 
-  FullDependence Result(Src, Dst, SCEVUnionPredicate(Assume, *SE),
-                        PossiblyLoopIndependent, CommonLevels);
+  FullDependence Result(Src, Dst, Assumptions, PossiblyLoopIndependent,
+                        CommonLevels);
   ++TotalArrayPairs;
 
   unsigned Pairs = 1;
@@ -4036,6 +4163,10 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
       return nullptr;
   }
 
+  // Assert that we haven't added runtime assumptions when not allowed
+  assert(UnderRuntimeAssumptions || Assumptions.isAlwaysTrue());
+
+  Result.Assumptions = getRuntimeAssumptions();
   return std::make_unique<FullDependence>(std::move(Result));
 }
 
diff --git a/llvm/test/Analysis/DependenceAnalysis/BasePtrBug.ll b/llvm/test/Analysis/DependenceAnalysis/BasePtrBug.ll
index 81e461a5e092d..8933c5fa6520a 100644
--- a/llvm/test/Analysis/DependenceAnalysis/BasePtrBug.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/BasePtrBug.ll
@@ -18,7 +18,7 @@ define void @test1(ptr nocapture %A, ptr nocapture %B, i32 %N) #0 {
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %gep.0, align 4 --> Dst: %0 = load i32, ptr %gep.0, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %gep.0, align 4 --> Dst: %1 = load i32, ptr %gep.1, align 4
-; CHECK-NEXT:    da analyze - input [*|<]!
+; CHECK-NEXT:    da analyze - consistent input [((-4 * (sext i32 %div to i64))<nsw> /u 4)|<]!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %gep.0, align 4 --> Dst: store i32 %add, ptr %gep.B, align 4
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: %1 = load i32, ptr %gep.1, align 4 --> Dst: %1 = load i32, ptr %gep.1, align 4
diff --git a/llvm/test/Analysis/DependenceAnalysis/DADelin.ll b/llvm/test/Analysis/DependenceAnalysis/DADelin.ll
index 8f94a455d3724..6e50712d6b458 100644
--- a/llvm/test/Analysis/DependenceAnalysis/DADelin.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/DADelin.ll
@@ -648,7 +648,7 @@ define void @coeff_may_negative(ptr %a, i32 %k) {
 ; 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:  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:    da analyze - consistent output [((-1 * %k) /u %k)|<]!
 ; 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!
 ;
@@ -687,7 +687,7 @@ define void @coeff_positive(ptr %a, i32 %k) {
 ; 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:  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:    da analyze - consistent output [((-1 * %k) /u %k)|<]!
 ; 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!
 ;
diff --git a/llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll b/llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll
index d9ccea55dd478..719a62a3d5113 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
@@ -56,7 +54,6 @@ define i32 @alias_with_parametric_expr(ptr nocapture %A, i64 %n, i64 %m) {
 ; 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 pre...
[truncated]

Copy link
Contributor

@kasuga-fj kasuga-fj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using Stacked Pull Requests.

Comment on lines +1247 to +1253
// Handle negative upper bound - loop doesn't execute.
if (SE->isKnownNegative(UpperBound)) {
LLVM_DEBUG(dbgs() << "\t Negative upper bound - no dependence\n");
++StrongSIVindependence;
++StrongSIVsuccesses;
return true;
}
Copy link
Contributor

@kasuga-fj kasuga-fj Sep 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Although I haven't looked at the other parts) I think this is incorrect. In general, UpperBound is an unsigned value, may be interpreted as negative in a signed sense. That is, isKnownNegative(UpperBound) does not mean that the loop will not be executed.

@sebpop
Copy link
Contributor Author

sebpop commented Sep 10, 2025

Consider using Stacked Pull Requests.

Thanks for the pointer: a very helpful read.
I found out a way to re-stack my existing PRs.

@sebpop sebpop changed the base branch from main to users/sebpop/pr149977 September 10, 2025 23:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
llvm:analysis Includes value tracking, cost tables and constant folding
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants