[llvm] [DA] Fix absolute value calculation (PR #164967)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 24 05:23:30 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-analysis
Author: Ryotaro Kasuga (kasuga-fj)
<details>
<summary>Changes</summary>
This patch fixes the computation of the absolute value for SCEV. Previously, it was calculated as `AbsX = SE->isKnownNonNegative(X) ? X : -X`, which would incorrectly assume that `!isKnownNonNegative` implies `isKnownNegative`. This assumption does not hold in general, for example, when `X` is a `SCEVUnknown` and it can be an arbitrary value. To compute the absolute value properly, we should use ScalarEvolution::getAbsExpr instead.
Fix #<!-- -->149977
---
Full diff: https://github.com/llvm/llvm-project/pull/164967.diff
2 Files Affected:
- (modified) llvm/lib/Analysis/DependenceAnalysis.cpp (+39-12)
- (added) llvm/test/Analysis/DependenceAnalysis/compute-absolute-value.ll (+48)
``````````diff
diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index 853bd66c8a7f8..a572eefddd20e 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -1582,6 +1582,23 @@ static const SCEV *minusSCEVNoSignedOverflow(const SCEV *A, const SCEV *B,
return nullptr;
}
+/// Returns the absolute value of \p A. In the context of dependence analysis,
+/// we need an absolute value in a mathematical sense. If \p A is the signed
+/// minimum value, we cannot represent it unless extending the original type.
+/// Thus if we cannot prove that \p A is not the signed minimum value, returns
+/// nullptr.
+static const SCEV *absSCEVNoSignedOverflow(const SCEV *A, ScalarEvolution &SE) {
+ IntegerType *Ty = cast<IntegerType>(A->getType());
+ if (!Ty)
+ return nullptr;
+
+ const SCEV *SMin =
+ SE.getConstant(APInt::getSignedMinValue(Ty->getBitWidth()));
+ if (!SE.isKnownPredicate(CmpInst::ICMP_NE, A, SMin))
+ return nullptr;
+ return SE.getAbsExpr(A, /*IsNSW=*/true);
+}
+
/// Returns true iff \p Test is enabled.
static bool isDependenceTestEnabled(DependenceTestType Test) {
if (EnableDependenceTest == DependenceTestType::All)
@@ -1669,21 +1686,25 @@ bool DependenceInfo::strongSIVtest(const SCEV *Coeff, const SCEV *SrcConst,
LLVM_DEBUG(dbgs() << ", " << *Delta->getType() << "\n");
// check that |Delta| < iteration count
- if (const SCEV *UpperBound =
- collectUpperBound(CurSrcLoop, Delta->getType())) {
+ bool IsDeltaLarge = [&] {
+ const SCEV *UpperBound = collectUpperBound(CurSrcLoop, Delta->getType());
+ if (!UpperBound)
+ return false;
+
LLVM_DEBUG(dbgs() << "\t UpperBound = " << *UpperBound);
LLVM_DEBUG(dbgs() << ", " << *UpperBound->getType() << "\n");
- const SCEV *AbsDelta =
- SE->isKnownNonNegative(Delta) ? Delta : SE->getNegativeSCEV(Delta);
- const SCEV *AbsCoeff =
- SE->isKnownNonNegative(Coeff) ? Coeff : SE->getNegativeSCEV(Coeff);
+ const SCEV *AbsDelta = absSCEVNoSignedOverflow(Delta, *SE);
+ const SCEV *AbsCoeff = absSCEVNoSignedOverflow(Coeff, *SE);
+ if (!AbsDelta || !AbsCoeff)
+ return false;
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;
- }
+ return isKnownPredicate(CmpInst::ICMP_SGT, AbsDelta, Product);
+ }();
+ if (IsDeltaLarge) {
+ // Distance greater than trip count - no dependence
+ ++StrongSIVindependence;
+ ++StrongSIVsuccesses;
+ return true;
}
// Can we compute distance?
@@ -2259,6 +2280,9 @@ bool DependenceInfo::weakZeroSrcSIVtest(
const SCEVConstant *ConstCoeff = dyn_cast<SCEVConstant>(DstCoeff);
if (!ConstCoeff)
return false;
+
+ // Since ConstCoeff is constant, !isKnownNegative means it's non-negative.
+ // TODO: Bail out if it's a signed minimum value.
const SCEV *AbsCoeff = SE->isKnownNegative(ConstCoeff)
? SE->getNegativeSCEV(ConstCoeff)
: ConstCoeff;
@@ -2369,6 +2393,9 @@ bool DependenceInfo::weakZeroDstSIVtest(
const SCEVConstant *ConstCoeff = dyn_cast<SCEVConstant>(SrcCoeff);
if (!ConstCoeff)
return false;
+
+ // Since ConstCoeff is constant, !isKnownNegative means it's non-negative.
+ // TODO: Bail out if it's a signed minimum value.
const SCEV *AbsCoeff = SE->isKnownNegative(ConstCoeff)
? SE->getNegativeSCEV(ConstCoeff)
: ConstCoeff;
diff --git a/llvm/test/Analysis/DependenceAnalysis/compute-absolute-value.ll b/llvm/test/Analysis/DependenceAnalysis/compute-absolute-value.ll
new file mode 100644
index 0000000000000..64fad37ab699a
--- /dev/null
+++ b/llvm/test/Analysis/DependenceAnalysis/compute-absolute-value.ll
@@ -0,0 +1,48 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -disable-output "-passes=print<da>" 2>&1 | FileCheck %s
+
+; for (i = 0; i < 3; i++) {
+; a[-k * i] = 1;
+; a[-k * i + (2 * k + 1)] = 2;
+; }
+;
+; When k = -1, dependency exists between the two stores. Accesses will be:
+;
+; - a[-k * i] : a[ 0], a[-1], a[-2]
+; - a[-k * i + (2 * k + 1)] : a[-1], a[-2], a[-3]
+;
+; We cannot determine the sign of `k` and `2*k + 1` at compile time,
+;
+define void @unknown_sign(ptr %a, i64 %k) {
+; CHECK-LABEL: 'unknown_sign'
+; CHECK-NEXT: Src: store i8 1, ptr %idx.0, align 1 --> Dst: store i8 1, ptr %idx.0, align 1
+; CHECK-NEXT: da analyze - none!
+; CHECK-NEXT: Src: store i8 1, ptr %idx.0, align 1 --> Dst: store i8 2, ptr %idx.1, align 1
+; CHECK-NEXT: da analyze - output [<>]!
+; CHECK-NEXT: Src: store i8 2, ptr %idx.1, align 1 --> Dst: store i8 2, ptr %idx.1, align 1
+; CHECK-NEXT: da analyze - none!
+;
+entry:
+ %k.neg = sub nsw i64 0, %k
+ %kk = mul nsw i64 %k, 2
+ %subscript.1.init = add i64 1, %kk
+ br label %loop
+
+loop:
+ %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+ %subscript.0 = phi i64 [ 0, %entry ], [ %subscript.0.next, %loop ]
+ %subscript.1 = phi i64 [ %subscript.1.init, %entry ], [ %subscript.1.next, %loop ]
+ %idx.0 = getelementptr i8, ptr %a, i64 %subscript.0
+ %idx.1 = getelementptr i8, ptr %a, i64 %subscript.1
+ store i8 1, ptr %idx.0
+ store i8 2, ptr %idx.1
+ %i.next = add i64 %i, 1
+ %subscript.0.next = add nsw i64 %subscript.0, %k.neg
+ %subscript.1.next = add nsw i64 %subscript.1, %k.neg
+ %cond.exit = icmp eq i64 %i.next, 3
+ br i1 %cond.exit, label %exit, label %loop
+
+exit:
+ ret void
+}
+
``````````
</details>
https://github.com/llvm/llvm-project/pull/164967
More information about the llvm-commits
mailing list