From bd3185fcaf6d5307d1f9905e0b904d4606b967b7 Mon Sep 17 00:00:00 2001 From: Ryotaro Kasuga Date: Fri, 24 Oct 2025 12:08:07 +0000 Subject: [PATCH] [DA] Fix absolute value calculation --- llvm/lib/Analysis/DependenceAnalysis.cpp | 51 ++++++++++++++----- .../compute-absolute-value.ll | 48 +++++++++++++++++ 2 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 llvm/test/Analysis/DependenceAnalysis/compute-absolute-value.ll 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(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(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(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" 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 +} +