[llvm] [DA] Fix the check between Subscript and Size after delinearization (PR #151326)
Ryotaro Kasuga via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 30 06:00:26 PDT 2025
https://github.com/kasuga-fj created https://github.com/llvm/llvm-project/pull/151326
Delinearization provides two values: the size of the array, and the subscript of the access. DA checks their validity (`0 <= subscript < size`), with some special handling. In particular, to ensure `subscript < size`, calculate the maximum value of `subscript - size` and check if it is negative. There was an issue in its process: when `subscript - size` is expressed as an affine format like `init + step * i`, the value in the last iteration (`start + step * (num_iterations - 1)`) was assumed to be the maximum value. This assumption is incorrect in the following cases:
- When `step` is negative
- When the AddRec wraps
This patch introduces extra checks to ensure the sign of `step` and verify the existence of nsw/nuw flags.
Fix #150604
>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] [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
+}
More information about the llvm-commits
mailing list