[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) {
----------------
preames wrote:
This is an interesting little bit of logic. If I'm following correctly, you're claiming that for an AR which is nuw/nsw, if the 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.
Though, shouldn't this be a subset of computeExitCountExhaustively? (Ignore the bit about not controlling an exit for the moment.)
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.
https://github.com/llvm/llvm-project/pull/144945
More information about the llvm-commits
mailing list