[llvm] [DA] Check monotonicity for subscripts (PR #154527)
Ryotaro Kasuga via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 20 05:48:36 PDT 2025
https://github.com/kasuga-fj created https://github.com/llvm/llvm-project/pull/154527
None
>From a0d05ec13ce11b3e895a502adfe50fc94aa54bbb Mon Sep 17 00:00:00 2001
From: Ryotaro Kasuga <kasuga.ryotaro at fujitsu.com>
Date: Wed, 20 Aug 2025 12:42:06 +0000
Subject: [PATCH] [DA] Check monotonicity for subscripts
---
.../llvm/Analysis/DependenceAnalysis.h | 8 ++
llvm/lib/Analysis/DependenceAnalysis.cpp | 118 +++++++++++++++++-
2 files changed, 121 insertions(+), 5 deletions(-)
diff --git a/llvm/include/llvm/Analysis/DependenceAnalysis.h b/llvm/include/llvm/Analysis/DependenceAnalysis.h
index f66c79d915665..7ea7f96b5c8e5 100644
--- a/llvm/include/llvm/Analysis/DependenceAnalysis.h
+++ b/llvm/include/llvm/Analysis/DependenceAnalysis.h
@@ -921,6 +921,14 @@ class DependenceInfo {
/// checkDstSubscript to avoid duplicate code
bool checkSubscript(const SCEV *Expr, const Loop *LoopNest,
SmallBitVector &Loops, bool IsSrc);
+
+ /// Test whether \p Expr is monotonic or not. Return true if we can prove it
+ /// is monotonic. The term "monotonic" means that all AddRec Exprs in \p Expr
+ /// doesn't wrap in signed sense. When it is monotonic, the minimum and
+ /// maximum values of \p Expr are stored in \p Min and \p Max, respectively.
+ bool isMonotonicSCEV(const SCEV *Expr, const SCEV *&Min, const SCEV *&Max,
+ ScalarEvolution *SE, const Loop *OutermostLoop,
+ IntegerType *Ty, const Value *Ptr = nullptr) const;
}; // class DependenceInfo
/// AnalysisPass to compute dependence information in a function
diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index f33e04e804e3d..deb12c1026580 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -3500,16 +3500,28 @@ bool DependenceInfo::tryDelinearizeParametricSize(
// to the dependency checks.
if (!DisableDelinearizationChecks)
for (size_t I = 1; I < Size; ++I) {
- if (!isKnownNonNegative(SrcSubscripts[I], SrcPtr))
+ const Loop *OutermostLoop =
+ LI->getLoopFor(Src->getParent())->getOutermostLoop();
+ IntegerType *Ty = cast<IntegerType>(Sizes[I - 1]->getType());
+ if (!Ty)
return false;
- if (!isKnownLessThan(SrcSubscripts[I], Sizes[I - 1]))
+ const SCEV *SrcMin = nullptr, *SrcMax = nullptr;
+ if (!isMonotonicSCEV(SrcSubscripts[I], SrcMin, SrcMax, SE, OutermostLoop,
+ Ty, SrcPtr))
return false;
-
- if (!isKnownNonNegative(DstSubscripts[I], DstPtr))
+ if (!SE->isKnownNonNegative(SrcMin))
+ return false;
+ if (!SE->isKnownPredicate(CmpInst::ICMP_SLT, SrcMax, Sizes[I - 1]))
return false;
- if (!isKnownLessThan(DstSubscripts[I], Sizes[I - 1]))
+ const SCEV *DstMin = nullptr, *DstMax = nullptr;
+ if (!isMonotonicSCEV(DstSubscripts[I], DstMin, DstMax, SE, OutermostLoop,
+ Ty, DstPtr))
+ return false;
+ if (!SE->isKnownNonNegative(DstMin))
+ return false;
+ if (!SE->isKnownPredicate(CmpInst::ICMP_SLT, DstMax, Sizes[I - 1]))
return false;
}
@@ -3548,6 +3560,102 @@ SCEVUnionPredicate DependenceInfo::getRuntimeAssumptions() const {
return SCEVUnionPredicate(Assumptions, *SE);
}
+bool DependenceInfo::isMonotonicSCEV(const SCEV *Expr, const SCEV *&Min,
+ const SCEV *&Max, ScalarEvolution *SE,
+ const Loop *OutermostLoop, IntegerType *Ty,
+ const Value *Ptr) const {
+ const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(Expr);
+ if (!AddRec) {
+ if (!SE->isLoopInvariant(Expr, OutermostLoop))
+ return false;
+ const SCEV *Init = Expr ? Expr : SE->getZero(Ty);
+ Min = Init;
+ Max = Init;
+ return true;
+ }
+
+ if (!AddRec->isAffine())
+ return false;
+
+ // TODO: Support cast?
+ auto *AddRecTy = dyn_cast<IntegerType>(AddRec->getType());
+ if (!AddRecTy || AddRecTy->getBitWidth() != Ty->getBitWidth())
+ return false;
+
+ if (!isMonotonicSCEV(AddRec->getStart(), Min, Max, SE, OutermostLoop, Ty))
+ return false;
+
+ const SCEV *Coeff = AddRec->getStepRecurrence(*SE);
+ const Loop *L = AddRec->getLoop();
+
+ // Bail out if the coefficient can be zero.
+ if (!SE->isKnownNonZero(Coeff))
+ return false;
+ if (!SE->isLoopInvariant(Coeff, OutermostLoop))
+ return false;
+
+ bool IsKnownCoeffPositive = SE->isKnownPositive(Coeff);
+ bool IsKnownCoeffNegative = SE->isKnownNegative(Coeff);
+
+ bool IsNoWrap = AddRec->hasNoUnsignedWrap();
+ if (Ptr) {
+ // TODO: This seems incorrect. Maybe we should check the reachability from
+ // the GEP to the target instruction.
+ auto *GEP = dyn_cast<GetElementPtrInst>(Ptr);
+ if (GEP && GEP->hasNoUnsignedSignedWrap())
+ IsNoWrap = true;
+ }
+
+ if (!IsNoWrap) {
+ if (!IsKnownCoeffNegative)
+ // If the coefficient can be positive value, ensure that the AddRec is
+ // monotonically increasing.
+ if (!SE->isKnownOnEveryIteration(ICmpInst::ICMP_SGE, AddRec,
+ AddRec->getStart()))
+ return false;
+
+ if (!IsKnownCoeffPositive)
+ // If the coefficient can be positive value, ensure that the AddRec is
+ // monotonically decreasing.
+ if (!SE->isKnownOnEveryIteration(ICmpInst::ICMP_SLE, AddRec,
+ AddRec->getStart()))
+ return false;
+ }
+
+ const SCEV *BTC = SE->getBackedgeTakenCount(L);
+ if (!BTC || !SE->isLoopInvariant(BTC, OutermostLoop))
+ return false;
+
+ const SCEVAddRecExpr *MinAddRec = dyn_cast<SCEVAddRecExpr>(
+ SE->getAddRecExpr(Min, Coeff, L, AddRec->getNoWrapFlags()));
+ if (!MinAddRec)
+ return false;
+
+ const SCEVAddRecExpr *MaxAddRec = dyn_cast<SCEVAddRecExpr>(
+ SE->getAddRecExpr(Max, Coeff, L, AddRec->getNoWrapFlags()));
+ if (!MaxAddRec)
+ return false;
+
+ // If we know the coefficient is positive, the maximum value of AddRec is
+ // MaxLast. Similarly, if we know the coefficient is negative, the minimum
+ // value of AddRec is MinLast. If we don't know the sign of the coefficient,
+ // use SMin/SMax.
+ const SCEV *MinLast = MinAddRec->evaluateAtIteration(BTC, *SE);
+ const SCEV *MaxLast = MaxAddRec->evaluateAtIteration(BTC, *SE);
+ if (IsKnownCoeffPositive) {
+ Max = MaxLast;
+ } else if (IsKnownCoeffNegative) {
+ Min = MinLast;
+ } else {
+ assert(!IsKnownCoeffPositive && !IsKnownCoeffNegative &&
+ "Unexpected coefficient sign");
+ Min = SE->getSMinExpr(Min, MinLast);
+ Max = SE->getSMaxExpr(Max, MaxLast);
+ }
+
+ return true;
+}
+
// depends -
// Returns NULL if there is no dependence.
// Otherwise, return a Dependence with as many details as possible.
More information about the llvm-commits
mailing list