[llvm] [DA] Rewrite BanerjeeMIV test with safe APInt interval arithmetic (PR #207662)
Ryotaro Kasuga via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 6 06:42:43 PDT 2026
================
@@ -1922,36 +1922,167 @@ bool DependenceInfo::gcdMIVtest(const SCEV *Src, const SCEV *Dst,
}
//===----------------------------------------------------------------------===//
+
+namespace {
+struct BanerjeeInterval {
+ std::optional<APInt> Lower;
+ std::optional<APInt> Upper;
+
+ BanerjeeInterval(std::optional<APInt> Lower, std::optional<APInt> Upper)
+ : Lower(std::move(Lower)), Upper(std::move(Upper)) {}
+};
+} // namespace
+
+static APInt signedMin(const APInt &A, const APInt &B) {
+ return A.slt(B) ? A : B;
+}
+
+static APInt signedMax(const APInt &A, const APInt &B) {
+ return A.sgt(B) ? A : B;
+}
+
+static BanerjeeInterval addIntervals(const BanerjeeInterval &A,
+ const BanerjeeInterval &B) {
+ std::optional<APInt> Lower;
+ std::optional<APInt> Upper;
+ if (A.Lower && B.Lower)
+ Lower = *A.Lower + *B.Lower;
+ if (A.Upper && B.Upper)
+ Upper = *A.Upper + *B.Upper;
+ return BanerjeeInterval(std::move(Lower), std::move(Upper));
+}
+
+static BanerjeeInterval constantInterval(const APInt &C) {
+ return BanerjeeInterval(C, C);
+}
+
+static BanerjeeInterval emptyInterval(unsigned Bits) {
+ return BanerjeeInterval(APInt(Bits, 1, true), APInt(Bits, 0, true));
+}
+
+static bool isEmptyInterval(const BanerjeeInterval &Interval) {
+ return Interval.Lower && Interval.Upper &&
+ Interval.Lower->sgt(*Interval.Upper);
+}
+
+static BanerjeeInterval signedRangeInterval(const APInt &Coeff,
+ const APInt &Lower,
+ const APInt &Upper) {
+ APInt LowerValue = Coeff * Lower;
+ APInt UpperValue = Coeff * Upper;
+ return BanerjeeInterval(signedMin(LowerValue, UpperValue),
+ signedMax(LowerValue, UpperValue));
+}
+
+static BanerjeeInterval variableInterval(const APInt &Coeff,
+ const std::optional<APInt> &Upper) {
+ APInt Zero(Coeff.getBitWidth(), 0, true);
+ if (Coeff.isZero())
+ return constantInterval(Zero);
+ if (!Upper) {
+ if (Coeff.isNegative())
+ return BanerjeeInterval(std::nullopt, Zero);
+ return BanerjeeInterval(Zero, std::nullopt);
+ }
+ return signedRangeInterval(Coeff, Zero, *Upper);
+}
+
+static BanerjeeInterval
+unboundedStrictDirectionInterval(const APInt &ACoeff, const APInt &BCoeff,
+ unsigned char Direction) {
+ APInt DeltaCoeff = ACoeff - BCoeff;
+
+ switch (Direction) {
+ case Dependence::DVEntry::LT: {
+ APInt Boundary = -BCoeff;
+ std::optional<APInt> Lower;
+ std::optional<APInt> Upper;
+ if (DeltaCoeff.isNonNegative() && BCoeff.isNonPositive())
+ Lower = Boundary;
+ if (DeltaCoeff.isNonPositive() && BCoeff.isNonNegative())
+ Upper = Boundary;
+ return BanerjeeInterval(std::move(Lower), std::move(Upper));
+ }
+ case Dependence::DVEntry::GT: {
+ std::optional<APInt> Lower;
+ std::optional<APInt> Upper;
+ if (ACoeff.isNonNegative() && DeltaCoeff.isNonNegative())
+ Lower = ACoeff;
+ if (ACoeff.isNonPositive() && DeltaCoeff.isNonPositive())
+ Upper = ACoeff;
+ return BanerjeeInterval(std::move(Lower), std::move(Upper));
+ }
+ default:
+ llvm_unreachable("unexpected direction");
+ }
+}
+
+static BanerjeeInterval intervalFromValues(ArrayRef<APInt> Values) {
+ assert(!Values.empty() && "expected at least one value");
+ APInt Lower = Values.front();
+ APInt Upper = Values.front();
+ for (const APInt &Value : Values.drop_front()) {
+ Lower = signedMin(Lower, Value);
+ Upper = signedMax(Upper, Value);
+ }
+ return BanerjeeInterval(std::move(Lower), std::move(Upper));
+}
+
+static APInt evaluateBanerjeeTerm(const APInt &A, const APInt &SrcIndex,
+ const APInt &B, const APInt &DstIndex) {
+ return A * SrcIndex - B * DstIndex;
+}
+
+static APInt extendOrTruncateKnownNonNegative(const APInt &Value,
+ unsigned Width) {
+ if (Value.getBitWidth() < Width)
+ return Value.zext(Width);
+ return Value.trunc(Width);
+}
+
+static APInt extendOrTruncateKnownSigned(const APInt &Value, unsigned Width) {
+ if (Value.getBitWidth() < Width)
+ return Value.sext(Width);
+ return Value.trunc(Width);
+}
+
+static std::optional<APInt> getConstantMaxIterationIndex(const Loop *L,
+ unsigned BaseBits,
+ unsigned WideBits,
+ ScalarEvolution &SE) {
+ if (!SE.hasLoopInvariantBackedgeTakenCount(L))
+ return std::nullopt;
+
+ const SCEV *BackedgeTakenCount = SE.getBackedgeTakenCount(L);
+ if (isa<SCEVCouldNotCompute>(BackedgeTakenCount))
+ return std::nullopt;
+
+ auto *Constant = dyn_cast<SCEVConstant>(BackedgeTakenCount);
+ if (!Constant)
+ return std::nullopt;
+
+ APInt MaxIndex = Constant->getAPInt();
+ if (MaxIndex.isNegative() || MaxIndex.getActiveBits() > BaseBits)
+ return std::nullopt;
+ return extendOrTruncateKnownNonNegative(MaxIndex, WideBits);
----------------
kasuga-fj wrote:
Maybe this can be simplified by using `collectNonNegativeConstantUpperBound`.
https://github.com/llvm/llvm-project/pull/207662
More information about the llvm-commits
mailing list