[llvm] [SimplifyIndVar] ICMP predicate conversion to EQ/NE (PR #144945)
Philip Reames via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 2 11:45:35 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) {
+ NewBoundA = IVStart->getAPInt();
+ NewPredicate = FirstIterResult->isAllOnesValue() ? CmpInst::ICMP_EQ
+ : CmpInst::ICMP_NE;
+ }
+ }
+ }
+
+ if (!ICmpInst::isEquality(NewPredicate)) {
+ // Check to see the 'chosen one' value is the very last IV value.
+ // To put it differently, check to see if ICmp directly or indirectly
+ // defines maximum loop trip count (or simply has aligned behavior by
+ // accident). This is different from loop exit condition rewriting as here
+ // not only ICmp instructions directly writing to exiting branch are
+ // considered.
+
+ // check to see if max trip count and IV parameters are constant
+ const SCEVConstant *MaxBackCount =
+ dyn_cast<SCEVConstant>(SE->getConstantMaxBackedgeTakenCount(L));
+ if (!MaxBackCount) {
+ return false;
+ }
+
+ // compute the number of consecutive iterations in which produced
+ // predicate value will be the same
+ bool ExitIfTrue = false;
+ auto EL = SE->computeExitLimitFromCond(L, ICmp, ExitIfTrue, false);
----------------
preames wrote:
>From the docs: "Compute the number of times the backedge of the specified loop will execute if its exit condition were a conditional branch of ExitCond.". Nothing in this code ensures that the condition *is branched on by a loop exiting branch*. As such, the use here is invalid.
The major case which comes up here is when the condition produces poison on some iteration, but is only possible branched on before that iteration. (i.e. the condition is used down some conditional path)
https://github.com/llvm/llvm-project/pull/144945
More information about the llvm-commits
mailing list