[llvm] [DA] Extract the logic shared by the Exact SIV/RDIV test (PR #189951)
Ryotaro Kasuga via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 1 06:32:59 PDT 2026
https://github.com/kasuga-fj updated https://github.com/llvm/llvm-project/pull/189951
>From 03074caa120efafc63eb41f755a70648a61327e4 Mon Sep 17 00:00:00 2001
From: Ryotaro Kasuga <kasuga.ryotaro at fujitsu.com>
Date: Wed, 1 Apr 2026 12:42:44 +0000
Subject: [PATCH 1/2] [DA] Extract the logic shared by the Exact SIV/RDIV test
---
.../llvm/Analysis/DependenceAnalysis.h | 8 +
llvm/lib/Analysis/DependenceAnalysis.cpp | 196 +++++-------------
2 files changed, 62 insertions(+), 142 deletions(-)
diff --git a/llvm/include/llvm/Analysis/DependenceAnalysis.h b/llvm/include/llvm/Analysis/DependenceAnalysis.h
index ac819ec271b07..a52f7bf09cc44 100644
--- a/llvm/include/llvm/Analysis/DependenceAnalysis.h
+++ b/llvm/include/llvm/Analysis/DependenceAnalysis.h
@@ -586,6 +586,14 @@ class DependenceInfo {
bool exactRDIVtest(const SCEVAddRecExpr *Src, const SCEVAddRecExpr *Dst,
FullDependence &Result) const;
+ /// exactTestImpl - Core implementation shared by the Exact SIV test and the
+ /// Exact RDIV test. Returns true if any possible dependence is disproved. If
+ /// \p Level is provided, this function will also attempt to explore
+ /// directions and refine \p Result for the given level.
+ bool exactTestImpl(const SCEVAddRecExpr *Src, const SCEVAddRecExpr *Dst,
+ FullDependence &Result,
+ std::optional<unsigned> Level) const;
+
/// gcdMIVtest - Tests an MIV subscript pair for dependence.
/// Returns true if any possible dependence is disproved.
/// Can sometimes disprove the equal direction for 1 or more loops.
diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index bca72d64fe780..00539697d9ad3 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -1619,148 +1619,11 @@ bool DependenceInfo::exactSIVtest(const SCEVAddRecExpr *Src,
if (!isDependenceTestEnabled(DependenceTestType::ExactSIV))
return false;
- const SCEV *SrcCoeff = Src->getStepRecurrence(*SE);
- const SCEV *SrcConst = Src->getStart();
- const SCEV *DstCoeff = Dst->getStepRecurrence(*SE);
- const SCEV *DstConst = Dst->getStart();
LLVM_DEBUG(dbgs() << "\tExact SIV test\n");
- LLVM_DEBUG(dbgs() << "\t SrcCoeff = " << *SrcCoeff << "\n");
- LLVM_DEBUG(dbgs() << "\t DstCoeff = " << *DstCoeff << "\n");
- LLVM_DEBUG(dbgs() << "\t SrcConst = " << *SrcConst << "\n");
- LLVM_DEBUG(dbgs() << "\t DstConst = " << *DstConst << "\n");
++ExactSIVapplications;
assert(0 < Level && Level <= CommonLevels && "Level out of range");
Level--;
-
- if (!Src->hasNoSignedWrap() || !Dst->hasNoSignedWrap())
- return false;
-
- const SCEV *Delta = minusSCEVNoSignedOverflow(DstConst, SrcConst, *SE);
- if (!Delta)
- return false;
- LLVM_DEBUG(dbgs() << "\t Delta = " << *Delta << "\n");
- const SCEVConstant *ConstDelta = dyn_cast<SCEVConstant>(Delta);
- const SCEVConstant *ConstSrcCoeff = dyn_cast<SCEVConstant>(SrcCoeff);
- const SCEVConstant *ConstDstCoeff = dyn_cast<SCEVConstant>(DstCoeff);
- if (!ConstDelta || !ConstSrcCoeff || !ConstDstCoeff)
- return false;
-
- // find gcd
- APInt G, X, Y;
- APInt AM = ConstSrcCoeff->getAPInt();
- APInt BM = ConstDstCoeff->getAPInt();
- APInt CM = ConstDelta->getAPInt();
- unsigned Bits = AM.getBitWidth();
- if (findGCD(Bits, AM, BM, CM, G, X, Y)) {
- // gcd doesn't divide Delta, no dependence
- ++ExactSIVindependence;
- ++ExactSIVsuccesses;
- return true;
- }
-
- LLVM_DEBUG(dbgs() << "\t X = " << X << ", Y = " << Y << "\n");
-
- // since SCEV construction normalizes, LM = 0
- std::optional<APInt> UM =
- collectNonNegativeConstantUpperBound(Src->getLoop(), Delta->getType());
- if (UM)
- LLVM_DEBUG(dbgs() << "\t UM = " << *UM << "\n");
-
- APInt TU(APInt::getSignedMaxValue(Bits));
- APInt TL(APInt::getSignedMinValue(Bits));
- APInt TC = CM.sdiv(G);
- APInt TX = X * TC;
- APInt TY = Y * TC;
- LLVM_DEBUG(dbgs() << "\t TC = " << TC << "\n");
- LLVM_DEBUG(dbgs() << "\t TX = " << TX << "\n");
- LLVM_DEBUG(dbgs() << "\t TY = " << TY << "\n");
-
- APInt TB = BM.sdiv(G);
- APInt TA = AM.sdiv(G);
-
- // 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 GetMaxOrMin = [](const OverflowSafeSignedAPInt &V0,
- const OverflowSafeSignedAPInt &V1,
- bool IsMin) -> std::optional<APInt> {
- if (V0 && V1)
- return IsMin ? APIntOps::smin(*V0, *V1) : APIntOps::smax(*V0, *V1);
- if (V0)
- return *V0;
- if (V1)
- return *V1;
- return std::nullopt;
- };
-
- LLVM_DEBUG(dbgs() << "\t TA = " << TA << "\n");
- LLVM_DEBUG(dbgs() << "\t TB = " << TB << "\n");
-
- std::optional<APInt> OptTL = GetMaxOrMin(TL0, TL1, false);
- std::optional<APInt> OptTU = GetMaxOrMin(TU0, TU1, true);
- if (!OptTL || !OptTU)
- return false;
-
- TL = std::move(*OptTL);
- TU = std::move(*OptTU);
- LLVM_DEBUG(dbgs() << "\t TL = " << TL << "\n");
- LLVM_DEBUG(dbgs() << "\t TU = " << TU << "\n");
-
- if (TL.sgt(TU)) {
- ++ExactSIVindependence;
- ++ExactSIVsuccesses;
- return true;
- }
-
- // explore directions
- unsigned NewDirection = Dependence::DVEntry::NONE;
- OverflowSafeSignedAPInt LowerDistance, UpperDistance;
- OverflowSafeSignedAPInt OTY(TY), OTX(TX), OTA(TA), OTB(TB), OTL(TL), OTU(TU);
- // NOTE: It's unclear whether these calculations can overflow. At the moment,
- // we conservatively assume they can.
- if (TA.sgt(TB)) {
- LowerDistance = (OTY - OTX) + (OTA - OTB) * OTL;
- UpperDistance = (OTY - OTX) + (OTA - OTB) * OTU;
- } else {
- LowerDistance = (OTY - OTX) + (OTA - OTB) * OTU;
- UpperDistance = (OTY - OTX) + (OTA - OTB) * OTL;
- }
-
- if (!LowerDistance || !UpperDistance)
- return false;
-
- LLVM_DEBUG(dbgs() << "\t LowerDistance = " << *LowerDistance << "\n");
- LLVM_DEBUG(dbgs() << "\t UpperDistance = " << *UpperDistance << "\n");
-
- if (LowerDistance->sle(0) && UpperDistance->sge(0)) {
- NewDirection |= Dependence::DVEntry::EQ;
- ++ExactSIVsuccesses;
- }
- if (LowerDistance->slt(0)) {
- NewDirection |= Dependence::DVEntry::GT;
- ++ExactSIVsuccesses;
- }
- if (UpperDistance->sgt(0)) {
- NewDirection |= Dependence::DVEntry::LT;
- ++ExactSIVsuccesses;
- }
-
- // finished
- Result.DV[Level].Direction &= NewDirection;
- if (Result.DV[Level].Direction == Dependence::DVEntry::NONE)
- ++ExactSIVindependence;
- LLVM_DEBUG(dbgs() << "\t Result = ");
- LLVM_DEBUG(Result.dump(dbgs()));
- return Result.DV[Level].Direction == Dependence::DVEntry::NONE;
+ return exactTestImpl(Src, Dst, Result, Level);
}
// Return true if the divisor evenly divides the dividend.
@@ -1946,16 +1809,23 @@ bool DependenceInfo::exactRDIVtest(const SCEVAddRecExpr *Src,
if (!isDependenceTestEnabled(DependenceTestType::ExactRDIV))
return false;
+ LLVM_DEBUG(dbgs() << "\tExact RDIV test\n");
+ ++ExactRDIVapplications;
+ return exactTestImpl(Src, Dst, Result, std::nullopt);
+}
+
+bool DependenceInfo::exactTestImpl(const SCEVAddRecExpr *Src,
+ const SCEVAddRecExpr *Dst,
+ FullDependence &Result,
+ std::optional<unsigned> Level) const {
const SCEV *SrcCoeff = Src->getStepRecurrence(*SE);
const SCEV *SrcConst = Src->getStart();
const SCEV *DstCoeff = Dst->getStepRecurrence(*SE);
const SCEV *DstConst = Dst->getStart();
- LLVM_DEBUG(dbgs() << "\tExact RDIV test\n");
LLVM_DEBUG(dbgs() << "\t SrcCoeff = " << *SrcCoeff << "\n");
LLVM_DEBUG(dbgs() << "\t DstCoeff = " << *DstCoeff << "\n");
LLVM_DEBUG(dbgs() << "\t SrcConst = " << *SrcConst << "\n");
LLVM_DEBUG(dbgs() << "\t DstConst = " << *DstConst << "\n");
- ++ExactRDIVapplications;
if (!Src->hasNoSignedWrap() || !Dst->hasNoSignedWrap())
return false;
@@ -2045,8 +1915,50 @@ bool DependenceInfo::exactRDIVtest(const SCEVAddRecExpr *Src,
LLVM_DEBUG(dbgs() << "\t TU = " << TU << "\n");
if (TL.sgt(TU))
- ++ExactRDIVindependence;
- return TL.sgt(TU);
+ return true;
+
+ if (!Level)
+ return false;
+ assert(SrcUM == DstUM && "Expecting same upper bound for Src and Dst");
+
+ // explore directions
+ unsigned NewDirection = Dependence::DVEntry::NONE;
+ OverflowSafeSignedAPInt LowerDistance, UpperDistance;
+ OverflowSafeSignedAPInt OTY(TY), OTX(TX), OTA(TA), OTB(TB), OTL(TL), OTU(TU);
+ // NOTE: It's unclear whether these calculations can overflow. At the moment,
+ // we conservatively assume they can.
+ if (TA.sgt(TB)) {
+ LowerDistance = (OTY - OTX) + (OTA - OTB) * OTL;
+ UpperDistance = (OTY - OTX) + (OTA - OTB) * OTU;
+ } else {
+ LowerDistance = (OTY - OTX) + (OTA - OTB) * OTU;
+ UpperDistance = (OTY - OTX) + (OTA - OTB) * OTL;
+ }
+
+ if (!LowerDistance || !UpperDistance)
+ return false;
+
+ LLVM_DEBUG(dbgs() << "\t LowerDistance = " << *LowerDistance << "\n");
+ LLVM_DEBUG(dbgs() << "\t UpperDistance = " << *UpperDistance << "\n");
+
+ if (LowerDistance->sle(0) && UpperDistance->sge(0)) {
+ NewDirection |= Dependence::DVEntry::EQ;
+ ++ExactSIVsuccesses;
+ }
+ if (LowerDistance->slt(0)) {
+ NewDirection |= Dependence::DVEntry::GT;
+ ++ExactSIVsuccesses;
+ }
+ if (UpperDistance->sgt(0)) {
+ NewDirection |= Dependence::DVEntry::LT;
+ ++ExactSIVsuccesses;
+ }
+
+ // finished
+ Result.DV[*Level].Direction &= NewDirection;
+ LLVM_DEBUG(dbgs() << "\t Result = ");
+ LLVM_DEBUG(Result.dump(dbgs()));
+ return Result.DV[*Level].Direction == Dependence::DVEntry::NONE;
}
// testSIV -
>From b8edefdaa2b8f59ab3324bc13fad354fc6da657a Mon Sep 17 00:00:00 2001
From: Ryotaro Kasuga <kasuga.ryotaro at fujitsu.com>
Date: Wed, 1 Apr 2026 13:32:34 +0000
Subject: [PATCH 2/2] fix unused variable error
---
llvm/lib/Analysis/DependenceAnalysis.cpp | 25 ++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index 00539697d9ad3..6c4b3f70f64ad 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -1623,7 +1623,12 @@ bool DependenceInfo::exactSIVtest(const SCEVAddRecExpr *Src,
++ExactSIVapplications;
assert(0 < Level && Level <= CommonLevels && "Level out of range");
Level--;
- return exactTestImpl(Src, Dst, Result, Level);
+ bool Res = exactTestImpl(Src, Dst, Result, Level);
+ if (Res) {
+ ++ExactSIVsuccesses;
+ ++ExactSIVindependence;
+ }
+ return Res;
}
// Return true if the divisor evenly divides the dividend.
@@ -1811,7 +1816,10 @@ bool DependenceInfo::exactRDIVtest(const SCEVAddRecExpr *Src,
LLVM_DEBUG(dbgs() << "\tExact RDIV test\n");
++ExactRDIVapplications;
- return exactTestImpl(Src, Dst, Result, std::nullopt);
+ bool Res = exactTestImpl(Src, Dst, Result, std::nullopt);
+ if (Res)
+ ++ExactRDIVindependence;
+ return Res;
}
bool DependenceInfo::exactTestImpl(const SCEVAddRecExpr *Src,
@@ -1848,7 +1856,6 @@ bool DependenceInfo::exactTestImpl(const SCEVAddRecExpr *Src,
unsigned Bits = AM.getBitWidth();
if (findGCD(Bits, AM, BM, CM, G, X, Y)) {
// gcd doesn't divide Delta, no dependence
- ++ExactRDIVindependence;
return true;
}
@@ -1941,18 +1948,12 @@ bool DependenceInfo::exactTestImpl(const SCEVAddRecExpr *Src,
LLVM_DEBUG(dbgs() << "\t LowerDistance = " << *LowerDistance << "\n");
LLVM_DEBUG(dbgs() << "\t UpperDistance = " << *UpperDistance << "\n");
- if (LowerDistance->sle(0) && UpperDistance->sge(0)) {
+ if (LowerDistance->sle(0) && UpperDistance->sge(0))
NewDirection |= Dependence::DVEntry::EQ;
- ++ExactSIVsuccesses;
- }
- if (LowerDistance->slt(0)) {
+ if (LowerDistance->slt(0))
NewDirection |= Dependence::DVEntry::GT;
- ++ExactSIVsuccesses;
- }
- if (UpperDistance->sgt(0)) {
+ if (UpperDistance->sgt(0))
NewDirection |= Dependence::DVEntry::LT;
- ++ExactSIVsuccesses;
- }
// finished
Result.DV[*Level].Direction &= NewDirection;
More information about the llvm-commits
mailing list