-
Couldn't load subscription status.
- Fork 15k
[DA] Fix absolute value calculation #164967
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@llvm/pr-subscribers-llvm-analysis Author: Ryotaro Kasuga (kasuga-fj) ChangesThis patch fixes the computation of the absolute value for SCEV. Previously, it was calculated as Fix #149977 Full diff: https://github.com/llvm/llvm-project/pull/164967.diff 2 Files Affected:
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
+}
+
|
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 llvm#149977
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!isKnownNonNegativeimpliesisKnownNegative. This assumption does not hold in general, for example, whenXis aSCEVUnknownand it can be an arbitrary value. To compute the absolute value properly, we should use ScalarEvolution::getAbsExpr instead.Fix #149977