[llvm] [SimplifyIndVar] ICMP predicate conversion to EQ/NE (PR #144945)
Sergey Shcherbinin via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 4 08:21:43 PST 2025
================
@@ -244,6 +245,128 @@ bool SimplifyIndvar::makeIVComparisonInvariant(ICmpInst *ICmp,
return true;
}
+/// Try to change predicate of ICmp to EQ/NE to facilitate better work of OSR.
+/// This can be done only if all possible IV values but one lead to the same
+/// produced comparison result, while the 'chosen one' value gives the opposite
+/// result.
+bool SimplifyIndvar::forceEqualityForICmp(ICmpInst *ICmp,
+ Instruction *IVOperand) {
+ if (ICmp->isEquality()) {
+ // nothing to do
+ return false;
+ }
+
+ unsigned BoundOperandIdx = IVOperand == ICmp->getOperand(0) ? 1 : 0;
+ const SCEV *BoundSCEV = SE->getSCEV(ICmp->getOperand(BoundOperandIdx));
+ const SCEVConstant *BoundC = dyn_cast<SCEVConstant>(BoundSCEV);
+ CmpInst::Predicate OrigPredicate = ICmp->getPredicate();
+ CmpInst::Predicate NewPredicate = CmpInst::BAD_ICMP_PREDICATE;
+ Type *Ty = IVOperand->getType();
+ APInt NewBoundA;
+
+ if (BoundC) {
+ // Try to find the 'chosen one' value basing on predicate type and bound
+ const APInt &BoundA = BoundC->getAPInt();
+ ConstantRange ExactCR =
+ ConstantRange::makeExactICmpRegion(OrigPredicate, BoundA);
+ if (!ExactCR.getEquivalentICmp(NewPredicate, NewBoundA)) {
+ NewPredicate = CmpInst::BAD_ICMP_PREDICATE;
+ }
+ }
+
+ if (!ICmpInst::isEquality(NewPredicate)) {
+ const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(SE->getSCEV(IVOperand));
+ if (!AR) {
+ return false;
+ }
+ const SCEVConstant *IVStart = dyn_cast<SCEVConstant>(AR->getStart());
+ const SCEVConstant *IVStep =
+ dyn_cast<SCEVConstant>(AR->getStepRecurrence(*SE));
+ if (!IVStart || !IVStep || !IVStep->getValue()->getValue()) {
+ return false;
+ }
+
+ if (BoundC) {
+ // Check to see the 'chosen one' value is the IV start value
+ bool HasNoWrap = ICmpInst::isSigned(OrigPredicate)
+ ? AR->hasNoSignedWrap()
+ : AR->hasNoUnsignedWrap();
+ if (HasNoWrap) {
+ const DataLayout &DL = ICmp->getParent()->getDataLayout();
+ Constant *SecondIterIV =
+ ConstantInt::get(Ty, IVStart->getAPInt() + IVStep->getAPInt());
+ Constant *FirstIterResult = ConstantFoldCompareInstOperands(
+ OrigPredicate, IVStart->getValue(), BoundC->getValue(), DL);
+ Constant *SecondIterResult = ConstantFoldCompareInstOperands(
+ OrigPredicate, SecondIterIV, BoundC->getValue(), DL);
+ if (FirstIterResult != SecondIterResult) {
----------------
SergeyShch01 wrote:
> If I'm following correctly, you're claiming that for an AR which is nuw/nsw, if the non-equality condition changes between iteration 0/1 that the value of that condition on all iterations 2+ must be either a) the value at iteration 1, or poison? I believe that holds.
yes
> Though, shouldn't this be a subset of computeExitCountExhaustively? (Ignore the bit about not controlling an exit for the moment.)
In context of forceEqualityForICmp() this can be ICmp not controlling loop exit.
> Do you actually see this case come up much? I don't think the "first iteration is special" case is one we've optimized much for beyond basic peeling.
I don't know the statistics, but for example the change in llvm/test/Transforms/IndVarSimplify/AArch64/loop-guards.ll your asked about above is due to this rule (and there a loop-local branch reads the condition). Please note that the motivation behind this change is not to optimize the first iteration but to optimize the loop body itself (as the comparison will be executed on all loop iterations).
https://github.com/llvm/llvm-project/pull/144945
More information about the llvm-commits
mailing list