[llvm] [DA] Fix the check between Subscript and Size after delinearization (PR #151326)

Ryotaro Kasuga via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 31 05:07:27 PDT 2025


https://github.com/kasuga-fj updated https://github.com/llvm/llvm-project/pull/151326

>From 14aced9c6757286cb31e4278e71e19b40fd395fb Mon Sep 17 00:00:00 2001
From: Ryotaro Kasuga <kasuga.ryotaro at fujitsu.com>
Date: Tue, 29 Jul 2025 12:15:19 +0000
Subject: [PATCH 1/4] [DA] Ensure delinearized sizes are non-negative

---
 llvm/lib/Analysis/DependenceAnalysis.cpp      | 33 ++++++--
 .../Analysis/DependenceAnalysis/DADelin.ll    | 82 ++++++++++++++++++-
 2 files changed, 103 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index f1473b2694ca4..fbf60dc34ee33 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -1126,17 +1126,32 @@ bool DependenceInfo::isKnownLessThan(const SCEV *S, const SCEV *Size) const {
   Size = SE->getTruncateOrZeroExtend(Size, MaxType);
 
   // Special check for addrecs using BE taken count
-  const SCEV *Bound = SE->getMinusSCEV(S, Size);
-  if (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(Bound)) {
-    if (AddRec->isAffine()) {
+  if (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(S))
+    if (AddRec->isAffine() && AddRec->hasNoSignedWrap() &&
+        AddRec->hasNoUnsignedWrap()) {
       const SCEV *BECount = SE->getBackedgeTakenCount(AddRec->getLoop());
-      if (!isa<SCEVCouldNotCompute>(BECount)) {
-        const SCEV *Limit = AddRec->evaluateAtIteration(BECount, *SE);
-        if (SE->isKnownNegative(Limit))
-          return true;
-      }
+      const SCEV *Start = AddRec->getStart();
+      const SCEV *Step = AddRec->getStepRecurrence(*SE);
+      const SCEV *End = AddRec->evaluateAtIteration(BECount, *SE);
+      const SCEV *Diff0 = SE->getMinusSCEV(Start, Size);
+      const SCEV *Diff1 = SE->getMinusSCEV(End, Size);
+
+      // If the value of Step is non-negative and the AddRec is non-wrap, it
+      // reaches its maximum at the last iteration. So it's enouth to check
+      // whether End - Size is negative.
+      if (SE->isKnownNonNegative(Step) && SE->isKnownNegative(Diff1))
+        return true;
+
+      // If the value of Step is non-positive and the AddRec is non-wrap, the
+      // initial value is its maximum.
+      if (SE->isKnownNonPositive(Step) && SE->isKnownNegative(Diff0))
+        return true;
+
+      // Even if we don't know the sign of Step, either Start or End must be
+      // the maximum value of the AddRec since it is non-wrap.
+      if (SE->isKnownNegative(Diff0) && SE->isKnownNegative(Diff1))
+        return true;
     }
-  }
 
   // Check using normal isKnownNegative
   const SCEV *LimitedBound =
diff --git a/llvm/test/Analysis/DependenceAnalysis/DADelin.ll b/llvm/test/Analysis/DependenceAnalysis/DADelin.ll
index b2e4959a7812e..410480188f364 100644
--- a/llvm/test/Analysis/DependenceAnalysis/DADelin.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/DADelin.ll
@@ -594,14 +594,15 @@ for.end12:                                        ; preds = %for.inc10, %entry
 }
 
 
+; FIXME? It seems that we cannot prove that %N is non-negative...
 define void @nonnegative(ptr nocapture %A, i32 %N) {
 ; CHECK-LABEL: 'nonnegative'
 ; CHECK-NEXT:  Src: store i32 1, ptr %arrayidx, align 4 --> Dst: store i32 1, ptr %arrayidx, align 4
-; CHECK-NEXT:    da analyze - none!
+; CHECK-NEXT:    da analyze - output [* *]!
 ; CHECK-NEXT:  Src: store i32 1, ptr %arrayidx, align 4 --> Dst: store i32 2, ptr %arrayidx, align 4
-; CHECK-NEXT:    da analyze - consistent output [0 0|<]!
+; CHECK-NEXT:    da analyze - output [* *|<]!
 ; CHECK-NEXT:  Src: store i32 2, ptr %arrayidx, align 4 --> Dst: store i32 2, ptr %arrayidx, align 4
-; CHECK-NEXT:    da analyze - none!
+; CHECK-NEXT:    da analyze - output [* *]!
 ;
 entry:
   %cmp44 = icmp eq i32 %N, 0
@@ -630,3 +631,78 @@ for.latch:
 exit:
   ret void
 }
+
+; i = 0;
+; do {
+;   a[k * i] = 42;
+;   a[k * (i + 1)] = 42;
+;   i++;
+; } while (i < k);
+;
+; The dependency direction between the two stores depends on the sign of k.
+; FIXME: Each store has loop-carried dependencies on itself if k is zero.
+;
+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:  Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
+; CHECK-NEXT:    da analyze - consistent output [-1]!
+; 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!
+;
+entry:
+  br label %loop
+
+loop:
+  %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
+  %i.next = add i32 %i, 1
+  %subscript.0 = mul i32 %i, %k
+  %subscript.1 = mul i32 %i.next, %k
+  %idx.0 = getelementptr i8, ptr %a, i32 %subscript.0
+  %idx.1 = getelementptr i8, ptr %a, i32 %subscript.1
+  store i8 42, ptr %idx.0
+  store i8 42, ptr %idx.1
+  %cond.exit = icmp eq i32 %i.next, %k
+  br i1 %cond.exit, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+; i = 0;
+; do {
+;   a[k * i] = 42;
+;   a[k * (i + 1)] = 42;
+;   i++;
+; } while (i < k);
+;
+; We can infer that the value of k is non-negative from the nsw flag.
+;
+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:  Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
+; CHECK-NEXT:    da analyze - consistent output [-1]!
+; 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!
+;
+entry:
+  br label %loop
+
+loop:
+  %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
+  %i.next = add nsw i32 %i, 1
+  %subscript.0 = mul i32 %i, %k
+  %subscript.1 = mul i32 %i.next, %k
+  %idx.0 = getelementptr i8, ptr %a, i32 %subscript.0
+  %idx.1 = getelementptr i8, ptr %a, i32 %subscript.1
+  store i8 42, ptr %idx.0
+  store i8 42, ptr %idx.1
+  %cond.exit = icmp eq i32 %i.next, %k
+  br i1 %cond.exit, label %exit, label %loop
+
+exit:
+  ret void
+}

>From 7fdb37dbfebb52b25dd4cb1e15ea32005d63dae8 Mon Sep 17 00:00:00 2001
From: Ryotaro Kasuga <kasuga.ryotaro at fujitsu.com>
Date: Thu, 31 Jul 2025 11:35:07 +0000
Subject: [PATCH 2/4] Replace `S - smax(1, Size)` with `S - Size`

---
 llvm/lib/Analysis/DependenceAnalysis.cpp         | 9 ++++-----
 llvm/test/Analysis/DependenceAnalysis/Coupled.ll | 4 +++-
 llvm/test/Analysis/DependenceAnalysis/DADelin.ll | 7 ++++---
 3 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index fbf60dc34ee33..ef23739251bc4 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -1111,9 +1111,9 @@ bool DependenceInfo::isKnownPredicate(ICmpInst::Predicate Pred, const SCEV *X,
   }
 }
 
-/// Compare to see if S is less than Size, using isKnownNegative(S - max(Size, 1))
-/// with some extra checking if S is an AddRec and we can prove less-than using
-/// the loop bounds.
+/// Compare to see if S is less than Size, using isKnownNegative(S - Size) with
+/// some extra checking if S is an AddRec and we can prove less-than using the
+/// loop bounds.
 bool DependenceInfo::isKnownLessThan(const SCEV *S, const SCEV *Size) const {
   // First unify to the same type
   auto *SType = dyn_cast<IntegerType>(S->getType());
@@ -1154,8 +1154,7 @@ bool DependenceInfo::isKnownLessThan(const SCEV *S, const SCEV *Size) const {
     }
 
   // Check using normal isKnownNegative
-  const SCEV *LimitedBound =
-      SE->getMinusSCEV(S, SE->getSMaxExpr(Size, SE->getOne(Size->getType())));
+  const SCEV *LimitedBound = SE->getMinusSCEV(S, Size);
   return SE->isKnownNegative(LimitedBound);
 }
 
diff --git a/llvm/test/Analysis/DependenceAnalysis/Coupled.ll b/llvm/test/Analysis/DependenceAnalysis/Coupled.ll
index 06bfc5d2e8573..1d4513429a83c 100644
--- a/llvm/test/Analysis/DependenceAnalysis/Coupled.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/Coupled.ll
@@ -719,12 +719,14 @@ for.end:                                          ; preds = %for.body
 ;;    for(int j = 0; j < M; j+=1)
 ;;      A[M*N + M*i + j] = 2;
 
+; FIXME: Currently failing to infer %M being positive.
+
 define void @couple_weakzerosiv(ptr noalias nocapture %A, i64 %N, i64 %M) {
 ; CHECK-LABEL: 'couple_weakzerosiv'
 ; CHECK-NEXT:  Src: store i32 1, ptr %arrayidx.us, align 4 --> Dst: store i32 1, ptr %arrayidx.us, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 1, ptr %arrayidx.us, align 4 --> Dst: store i32 2, ptr %arrayidx9.us, align 4
-; CHECK-NEXT:    da analyze - output [p>]!
+; CHECK-NEXT:    da analyze - output [*|<]!
 ; CHECK-NEXT:  Src: store i32 2, ptr %arrayidx9.us, align 4 --> Dst: store i32 2, ptr %arrayidx9.us, align 4
 ; CHECK-NEXT:    da analyze - none!
 ;
diff --git a/llvm/test/Analysis/DependenceAnalysis/DADelin.ll b/llvm/test/Analysis/DependenceAnalysis/DADelin.ll
index 410480188f364..929dd1f50d0b9 100644
--- a/llvm/test/Analysis/DependenceAnalysis/DADelin.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/DADelin.ll
@@ -647,7 +647,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 - consistent output [-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!
 ;
@@ -677,14 +677,15 @@ exit:
 ;   i++;
 ; } while (i < k);
 ;
-; We can infer that the value of k is non-negative from the nsw flag.
+; FIXME: In principle, we can infer that the value of k is non-negative from
+; the nsw flag.
 ;
 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:  Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
-; CHECK-NEXT:    da analyze - consistent output [-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!
 ;

>From 17eba494d4d3ec31f433be9c254dd64e5004f7e4 Mon Sep 17 00:00:00 2001
From: Ryotaro Kasuga <kasuga.ryotaro at fujitsu.com>
Date: Thu, 31 Jul 2025 11:39:09 +0000
Subject: [PATCH 3/4] Remove nuw check

---
 llvm/lib/Analysis/DependenceAnalysis.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index ef23739251bc4..b109b74afa971 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -1127,8 +1127,7 @@ bool DependenceInfo::isKnownLessThan(const SCEV *S, const SCEV *Size) const {
 
   // Special check for addrecs using BE taken count
   if (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(S))
-    if (AddRec->isAffine() && AddRec->hasNoSignedWrap() &&
-        AddRec->hasNoUnsignedWrap()) {
+    if (AddRec->isAffine() && AddRec->hasNoSignedWrap()) {
       const SCEV *BECount = SE->getBackedgeTakenCount(AddRec->getLoop());
       const SCEV *Start = AddRec->getStart();
       const SCEV *Step = AddRec->getStepRecurrence(*SE);

>From 91c1ded6893e2bd78b80f118cc289c28b31111a9 Mon Sep 17 00:00:00 2001
From: Ryotaro Kasuga <kasuga.ryotaro at fujitsu.com>
Date: Thu, 31 Jul 2025 12:05:50 +0000
Subject: [PATCH 4/4] Add XFAIL to DDG test

---
 llvm/test/Analysis/DDG/basic-loopnest.ll | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/llvm/test/Analysis/DDG/basic-loopnest.ll b/llvm/test/Analysis/DDG/basic-loopnest.ll
index 325428c13b217..75efff570048b 100644
--- a/llvm/test/Analysis/DDG/basic-loopnest.ll
+++ b/llvm/test/Analysis/DDG/basic-loopnest.ll
@@ -1,5 +1,8 @@
 ; RUN: opt < %s -disable-output "-passes=print<ddg>" 2>&1 | FileCheck %s
 
+; XFAIL: *
+; At the moment, DependenceAnalysis cannot infer `n` to be positive.
+
 
 ; CHECK-LABEL: 'DDG' for loop 'test1.for.cond1.preheader':
 
@@ -378,4 +381,4 @@ for.inc12:                                        ; preds = %for.body4, %test2.f
 
 for.end14:                                        ; preds = %for.inc12, %entry
   ret void
-}
\ No newline at end of file
+}



More information about the llvm-commits mailing list