[llvm] [Delinearization] Remove `isKnownLessThan` (PR #171821)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 11 04:49:08 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-analysis
Author: Ryotaro Kasuga (kasuga-fj)
<details>
<summary>Changes</summary>
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
---
Full diff: https://github.com/llvm/llvm-project/pull/171821.diff
1 Files Affected:
- (modified) llvm/lib/Analysis/Delinearization.cpp (+7-68)
``````````diff
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;
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/171821
More information about the llvm-commits
mailing list