[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