aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis/DependenceAnalysis.cpp
diff options
context:
space:
mode:
authorRyotaro Kasuga <kasuga.ryotaro@fujitsu.com>2025-08-13 17:45:28 +0900
committerGitHub <noreply@github.com>2025-08-13 17:45:28 +0900
commitbf6796fa8f3e0e855165d49e40e6bb2a77eb05e1 (patch)
tree1d857b6abc11480623d6b3ac594826aa10fc99ca /llvm/lib/Analysis/DependenceAnalysis.cpp
parent56131e3959de744e994a0a9409b079cab3c549a7 (diff)
downloadllvm-bf6796fa8f3e0e855165d49e40e6bb2a77eb05e1.zip
llvm-bf6796fa8f3e0e855165d49e40e6bb2a77eb05e1.tar.gz
llvm-bf6796fa8f3e0e855165d49e40e6bb2a77eb05e1.tar.bz2
[DA] Extract duplicated logic from exactSIVtest and exactRDIVtest (NFC) (#152712)
This patch refactors `exactSIVtest` and `exactRDIVtest` by consolidating duplicated logic into a single function. Same as #152688, the main goal is to improve code maintainability, since extra validation logic (as written in TODO comments) may be necessary.
Diffstat (limited to 'llvm/lib/Analysis/DependenceAnalysis.cpp')
-rw-r--r--llvm/lib/Analysis/DependenceAnalysis.cpp195
1 files changed, 113 insertions, 82 deletions
diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index 777a040..f33e04e 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -1531,6 +1531,62 @@ static APInt ceilingOfQuotient(const APInt &A, const APInt &B) {
return Q;
}
+/// Given an affine expression of the form A*k + B, where k is an arbitrary
+/// integer, infer the possible range of k based on the known range of the
+/// affine expression. If we know A*k + B is non-negative, i.e.,
+///
+/// A*k + B >= 0
+///
+/// we can derive the following inequalities for k when A is positive:
+///
+/// k >= -B / A
+///
+/// Since k is an integer, it means k is greater than or equal to the
+/// ceil(-B / A).
+///
+/// If the upper bound of the affine expression \p UB is passed, the following
+/// inequality can be derived as well:
+///
+/// A*k + B <= UB
+///
+/// which leads to:
+///
+/// k <= (UB - B) / A
+///
+/// Again, as k is an integer, it means k is less than or equal to the
+/// floor((UB - B) / A).
+///
+/// The similar logic applies when A is negative, but the inequalities sign flip
+/// while working with them.
+///
+/// Preconditions: \p A is non-zero, and we know A*k + B is non-negative.
+static std::pair<std::optional<APInt>, std::optional<APInt>>
+inferDomainOfAffine(const APInt &A, const APInt &B,
+ const std::optional<APInt> &UB) {
+ assert(A != 0 && "A must be non-zero");
+ std::optional<APInt> TL, TU;
+ if (A.sgt(0)) {
+ TL = ceilingOfQuotient(-B, A);
+ LLVM_DEBUG(dbgs() << "\t Possible TL = " << *TL << "\n");
+ // New bound check - modification to Banerjee's e3 check
+ if (UB) {
+ // TODO?: Overflow check for UB - B
+ TU = floorOfQuotient(*UB - B, A);
+ LLVM_DEBUG(dbgs() << "\t Possible TU = " << *TU << "\n");
+ }
+ } else {
+ TU = floorOfQuotient(-B, A);
+ LLVM_DEBUG(dbgs() << "\t Possible TU = " << *TU << "\n");
+ // New bound check - modification to Banerjee's e3 check
+ if (UB) {
+ // TODO?: Overflow check for UB - B
+ TL = ceilingOfQuotient(*UB - B, A);
+ LLVM_DEBUG(dbgs() << "\t Possible TL = " << *TL << "\n");
+ }
+ }
+ return std::make_pair(TL, TU);
+}
+
// exactSIVtest -
// When we have a pair of subscripts of the form [c1 + a1*i] and [c2 + a2*i],
// where i is an induction variable, c1 and c2 are loop invariant, and a1
@@ -1590,14 +1646,12 @@ bool DependenceInfo::exactSIVtest(const SCEV *SrcCoeff, const SCEV *DstCoeff,
LLVM_DEBUG(dbgs() << "\t X = " << X << ", Y = " << Y << "\n");
// since SCEV construction normalizes, LM = 0
- APInt UM(Bits, 1, true);
- bool UMValid = false;
+ std::optional<APInt> UM;
// UM is perhaps unavailable, let's check
if (const SCEVConstant *CUB =
collectConstantUpperBound(CurLoop, Delta->getType())) {
UM = CUB->getAPInt();
- LLVM_DEBUG(dbgs() << "\t UM = " << UM << "\n");
- UMValid = true;
+ LLVM_DEBUG(dbgs() << "\t UM = " << *UM << "\n");
}
APInt TU(APInt::getSignedMaxValue(Bits));
@@ -1609,44 +1663,33 @@ bool DependenceInfo::exactSIVtest(const SCEV *SrcCoeff, const SCEV *DstCoeff,
LLVM_DEBUG(dbgs() << "\t TX = " << TX << "\n");
LLVM_DEBUG(dbgs() << "\t TY = " << TY << "\n");
- SmallVector<APInt, 2> TLVec, TUVec;
APInt TB = BM.sdiv(G);
- if (TB.sgt(0)) {
- TLVec.push_back(ceilingOfQuotient(-TX, TB));
- LLVM_DEBUG(dbgs() << "\t Possible TL = " << TLVec.back() << "\n");
- // New bound check - modification to Banerjee's e3 check
- if (UMValid) {
- TUVec.push_back(floorOfQuotient(UM - TX, TB));
- LLVM_DEBUG(dbgs() << "\t Possible TU = " << TUVec.back() << "\n");
- }
- } else {
- TUVec.push_back(floorOfQuotient(-TX, TB));
- LLVM_DEBUG(dbgs() << "\t Possible TU = " << TUVec.back() << "\n");
- // New bound check - modification to Banerjee's e3 check
- if (UMValid) {
- TLVec.push_back(ceilingOfQuotient(UM - TX, TB));
- LLVM_DEBUG(dbgs() << "\t Possible TL = " << TLVec.back() << "\n");
- }
- }
-
APInt TA = AM.sdiv(G);
- if (TA.sgt(0)) {
- if (UMValid) {
- TUVec.push_back(floorOfQuotient(UM - TY, TA));
- LLVM_DEBUG(dbgs() << "\t Possible TU = " << TUVec.back() << "\n");
- }
- // New bound check - modification to Banerjee's e3 check
- TLVec.push_back(ceilingOfQuotient(-TY, TA));
- LLVM_DEBUG(dbgs() << "\t Possible TL = " << TLVec.back() << "\n");
- } else {
- if (UMValid) {
- TLVec.push_back(ceilingOfQuotient(UM - TY, TA));
- LLVM_DEBUG(dbgs() << "\t Possible TL = " << TLVec.back() << "\n");
- }
- // New bound check - modification to Banerjee's e3 check
- TUVec.push_back(floorOfQuotient(-TY, TA));
- LLVM_DEBUG(dbgs() << "\t Possible TU = " << TUVec.back() << "\n");
- }
+
+ // At this point, we have the following equations:
+ //
+ // TA*i0 - TB*i1 = TC
+ //
+ // Also, we know that the all pairs of (i0, i1) can be expressed as:
+ //
+ // (TX + k*TB, TY + k*TA)
+ //
+ // where k is an arbitrary integer.
+ auto [TL0, TU0] = inferDomainOfAffine(TB, TX, UM);
+ auto [TL1, TU1] = inferDomainOfAffine(TA, TY, UM);
+
+ auto CreateVec = [](const std::optional<APInt> &V0,
+ const std::optional<APInt> &V1) {
+ SmallVector<APInt, 2> Vec;
+ if (V0)
+ Vec.push_back(*V0);
+ if (V1)
+ Vec.push_back(*V1);
+ return Vec;
+ };
+
+ SmallVector<APInt, 2> TLVec = CreateVec(TL0, TL1);
+ SmallVector<APInt, 2> TUVec = CreateVec(TU0, TU1);
LLVM_DEBUG(dbgs() << "\t TA = " << TA << "\n");
LLVM_DEBUG(dbgs() << "\t TB = " << TB << "\n");
@@ -1967,24 +2010,20 @@ bool DependenceInfo::exactRDIVtest(const SCEV *SrcCoeff, const SCEV *DstCoeff,
LLVM_DEBUG(dbgs() << "\t X = " << X << ", Y = " << Y << "\n");
// since SCEV construction seems to normalize, LM = 0
- APInt SrcUM(Bits, 1, true);
- bool SrcUMvalid = false;
+ std::optional<APInt> SrcUM;
// SrcUM is perhaps unavailable, let's check
if (const SCEVConstant *UpperBound =
collectConstantUpperBound(SrcLoop, Delta->getType())) {
SrcUM = UpperBound->getAPInt();
- LLVM_DEBUG(dbgs() << "\t SrcUM = " << SrcUM << "\n");
- SrcUMvalid = true;
+ LLVM_DEBUG(dbgs() << "\t SrcUM = " << *SrcUM << "\n");
}
- APInt DstUM(Bits, 1, true);
- bool DstUMvalid = false;
+ std::optional<APInt> DstUM;
// UM is perhaps unavailable, let's check
if (const SCEVConstant *UpperBound =
collectConstantUpperBound(DstLoop, Delta->getType())) {
DstUM = UpperBound->getAPInt();
- LLVM_DEBUG(dbgs() << "\t DstUM = " << DstUM << "\n");
- DstUMvalid = true;
+ LLVM_DEBUG(dbgs() << "\t DstUM = " << *DstUM << "\n");
}
APInt TU(APInt::getSignedMaxValue(Bits));
@@ -1996,47 +2035,39 @@ bool DependenceInfo::exactRDIVtest(const SCEV *SrcCoeff, const SCEV *DstCoeff,
LLVM_DEBUG(dbgs() << "\t TX = " << TX << "\n");
LLVM_DEBUG(dbgs() << "\t TY = " << TY << "\n");
- SmallVector<APInt, 2> TLVec, TUVec;
APInt TB = BM.sdiv(G);
- if (TB.sgt(0)) {
- TLVec.push_back(ceilingOfQuotient(-TX, TB));
- LLVM_DEBUG(dbgs() << "\t Possible TL = " << TLVec.back() << "\n");
- if (SrcUMvalid) {
- TUVec.push_back(floorOfQuotient(SrcUM - TX, TB));
- LLVM_DEBUG(dbgs() << "\t Possible TU = " << TUVec.back() << "\n");
- }
- } else {
- TUVec.push_back(floorOfQuotient(-TX, TB));
- LLVM_DEBUG(dbgs() << "\t Possible TU = " << TUVec.back() << "\n");
- if (SrcUMvalid) {
- TLVec.push_back(ceilingOfQuotient(SrcUM - TX, TB));
- LLVM_DEBUG(dbgs() << "\t Possible TL = " << TLVec.back() << "\n");
- }
- }
-
APInt TA = AM.sdiv(G);
- if (TA.sgt(0)) {
- TLVec.push_back(ceilingOfQuotient(-TY, TA));
- LLVM_DEBUG(dbgs() << "\t Possible TL = " << TLVec.back() << "\n");
- if (DstUMvalid) {
- TUVec.push_back(floorOfQuotient(DstUM - TY, TA));
- LLVM_DEBUG(dbgs() << "\t Possible TU = " << TUVec.back() << "\n");
- }
- } else {
- TUVec.push_back(floorOfQuotient(-TY, TA));
- LLVM_DEBUG(dbgs() << "\t Possible TU = " << TUVec.back() << "\n");
- if (DstUMvalid) {
- TLVec.push_back(ceilingOfQuotient(DstUM - TY, TA));
- LLVM_DEBUG(dbgs() << "\t Possible TL = " << TLVec.back() << "\n");
- }
- }
- if (TLVec.empty() || TUVec.empty())
- return false;
+ // At this point, we have the following equations:
+ //
+ // TA*i - TB*j = TC
+ //
+ // Also, we know that the all pairs of (i, j) can be expressed as:
+ //
+ // (TX + k*TB, TY + k*TA)
+ //
+ // where k is an arbitrary integer.
+ auto [TL0, TU0] = inferDomainOfAffine(TB, TX, SrcUM);
+ auto [TL1, TU1] = inferDomainOfAffine(TA, TY, DstUM);
LLVM_DEBUG(dbgs() << "\t TA = " << TA << "\n");
LLVM_DEBUG(dbgs() << "\t TB = " << TB << "\n");
+ auto CreateVec = [](const std::optional<APInt> &V0,
+ const std::optional<APInt> &V1) {
+ SmallVector<APInt, 2> Vec;
+ if (V0)
+ Vec.push_back(*V0);
+ if (V1)
+ Vec.push_back(*V1);
+ return Vec;
+ };
+
+ SmallVector<APInt, 2> TLVec = CreateVec(TL0, TL1);
+ SmallVector<APInt, 2> TUVec = CreateVec(TU0, TU1);
+ if (TLVec.empty() || TUVec.empty())
+ return false;
+
TL = APIntOps::smax(TLVec.front(), TLVec.back());
TU = APIntOps::smin(TUVec.front(), TUVec.back());
LLVM_DEBUG(dbgs() << "\t TL = " << TL << "\n");