[llvm] [Delinearization] Remove `isKnownLessThan` (PR #171821)

Ryotaro Kasuga via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 11 04:48:36 PST 2025


https://github.com/kasuga-fj created https://github.com/llvm/llvm-project/pull/171821

Delinearization has `isKnownLessThan(a, b)` function to check if `a < b` is known at compile time. To check the predicate, it calls `isKnownNegative(a - b)`. There are at least two issues with this approach:

- It mixed up a signed interpretation with an unsigned one.
- It doesn't consider overflow.

This function includes some additional logic, which suffers from the same issues. This patch replace the call to `isKnownLessThan(a, b)` with `ScalarEvolution::isKnownPredicate(ICmpInst::ICMP_SLT, a, b)` and removes the former function entirely, since using it is risky and may lead to incorrect results.

Resolve #169812

>From ac8995b10acc1c3c77da0b665254f2430869e811 Mon Sep 17 00:00:00 2001
From: Ryotaro Kasuga <kasuga.ryotaro at fujitsu.com>
Date: Thu, 11 Dec 2025 12:36:58 +0000
Subject: [PATCH] [Delinearization] Remove `isKnownLessThan`

---
 llvm/lib/Analysis/Delinearization.cpp | 75 +++------------------------
 1 file changed, 7 insertions(+), 68 deletions(-)

diff --git a/llvm/lib/Analysis/Delinearization.cpp b/llvm/lib/Analysis/Delinearization.cpp
index 7bf83ccf9c172..c3e3bc33a8b69 100644
--- a/llvm/lib/Analysis/Delinearization.cpp
+++ b/llvm/lib/Analysis/Delinearization.cpp
@@ -686,73 +686,6 @@ static bool isKnownNonNegative(ScalarEvolution *SE, const SCEV *S,
   return SE->isKnownNonNegative(S);
 }
 
-/// Compare to see if S is less than Size, using
-///
-///    isKnownNegative(S - Size)
-///
-/// with some extra checking if S is an AddRec and we can prove less-than using
-/// the loop bounds.
-static bool isKnownLessThan(ScalarEvolution *SE, const SCEV *S,
-                            const SCEV *Size) {
-  // First unify to the same type
-  auto *SType = dyn_cast<IntegerType>(S->getType());
-  auto *SizeType = dyn_cast<IntegerType>(Size->getType());
-  if (!SType || !SizeType)
-    return false;
-  Type *MaxType =
-      (SType->getBitWidth() >= SizeType->getBitWidth()) ? SType : SizeType;
-  S = SE->getTruncateOrZeroExtend(S, MaxType);
-  Size = SE->getTruncateOrZeroExtend(Size, MaxType);
-
-  auto CollectUpperBound = [&](const Loop *L, Type *T) -> const SCEV * {
-    if (SE->hasLoopInvariantBackedgeTakenCount(L)) {
-      const SCEV *UB = SE->getBackedgeTakenCount(L);
-      return SE->getTruncateOrZeroExtend(UB, T);
-    }
-    return nullptr;
-  };
-
-  auto CheckAddRecBECount = [&]() {
-    const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(S);
-    if (!AddRec || !AddRec->isAffine() || !AddRec->hasNoSignedWrap())
-      return false;
-    const SCEV *BECount = CollectUpperBound(AddRec->getLoop(), MaxType);
-    // If the BTC cannot be computed, check the base case for S.
-    if (!BECount || isa<SCEVCouldNotCompute>(BECount))
-      return false;
-    const SCEV *Start = AddRec->getStart();
-    const SCEV *Step = AddRec->getStepRecurrence(*SE);
-    const SCEV *End = AddRec->evaluateAtIteration(BECount, *SE);
-    const SCEV *Diff0 = SE->getMinusSCEV(Start, Size);
-    const SCEV *Diff1 = SE->getMinusSCEV(End, Size);
-
-    // If the value of Step is non-negative and the AddRec is non-wrap, it
-    // reaches its maximum at the last iteration. So it's enouth to check
-    // whether End - Size is negative.
-    if (SE->isKnownNonNegative(Step) && SE->isKnownNegative(Diff1))
-      return true;
-
-    // If the value of Step is non-positive and the AddRec is non-wrap, the
-    // initial value is its maximum.
-    if (SE->isKnownNonPositive(Step) && SE->isKnownNegative(Diff0))
-      return true;
-
-    // Even if we don't know the sign of Step, either Start or End must be
-    // the maximum value of the AddRec since it is non-wrap.
-    if (SE->isKnownNegative(Diff0) && SE->isKnownNegative(Diff1))
-      return true;
-
-    return false;
-  };
-
-  if (CheckAddRecBECount())
-    return true;
-
-  // Check using normal isKnownNegative
-  const SCEV *LimitedBound = SE->getMinusSCEV(S, Size);
-  return SE->isKnownNegative(LimitedBound);
-}
-
 bool llvm::validateDelinearizationResult(ScalarEvolution &SE,
                                          ArrayRef<const SCEV *> Sizes,
                                          ArrayRef<const SCEV *> Subscripts,
@@ -782,7 +715,13 @@ bool llvm::validateDelinearizationResult(ScalarEvolution &SE,
     const SCEV *Subscript = Subscripts[I];
     if (!isKnownNonNegative(&SE, Subscript, Ptr))
       return false;
-    if (!isKnownLessThan(&SE, Subscript, Size))
+
+    // TODO: It may be better that delinearization itself unifies the types of
+    // all elements in Sizes and Subscripts.
+    Type *WiderTy = SE.getWiderType(Subscript->getType(), Size->getType());
+    Subscript = SE.getNoopOrSignExtend(Subscript, WiderTy);
+    Size = SE.getNoopOrSignExtend(Size, WiderTy);
+    if (!SE.isKnownPredicate(ICmpInst::ICMP_SLT, Subscript, Size))
       return false;
   }
 



More information about the llvm-commits mailing list