Index: llvm/include/llvm/Analysis/ScalarEvolution.h =================================================================== --- llvm/include/llvm/Analysis/ScalarEvolution.h +++ llvm/include/llvm/Analysis/ScalarEvolution.h @@ -766,12 +766,22 @@ /// SCEVCouldNotCompute object. const SCEV *getConstantMaxBackedgeTakenCount(const Loop *L) { return getBackedgeTakenCount(L, ConstantMaximum); - } + } + + /// Return a symbolic upper bound for the backedge taken count of the loop, + /// provided that we will not exit by either block in \p IgnoreBlocks. + /// This is more general than getConstantMaxBackedgeTakenCount as it returns + /// an arbitrary expression as opposed to only constants. + const SCEV *computeMaxBackedgeTakenCount( + const Loop *L, const DenseSet &IgnoreBlocks); /// Return a symbolic upper bound for the backedge taken count of the loop. /// This is more general than getConstantMaxBackedgeTakenCount as it returns /// an arbitrary expression as opposed to only constants. - const SCEV* computeMaxBackedgeTakenCount(const Loop *L); + const SCEV *computeMaxBackedgeTakenCount(const Loop *L) { + DenseSet IgnoreBlocks; + return computeMaxBackedgeTakenCount(L, IgnoreBlocks); + } /// Return true if the backedge taken count is either the value returned by /// getConstantMaxBackedgeTakenCount or zero. Index: llvm/lib/Analysis/ScalarEvolution.cpp =================================================================== --- llvm/lib/Analysis/ScalarEvolution.cpp +++ llvm/lib/Analysis/ScalarEvolution.cpp @@ -12507,7 +12507,8 @@ return false; } -const SCEV* ScalarEvolution::computeMaxBackedgeTakenCount(const Loop *L) { +const SCEV *ScalarEvolution::computeMaxBackedgeTakenCount( + const Loop *L, const DenseSet &IgnoreBlocks) { SmallVector ExitingBlocks; L->getExitingBlocks(ExitingBlocks); @@ -12516,6 +12517,8 @@ // getConstantMaxBackedgeTakenCount which isn't restricted to just constants. SmallVector ExitCounts; for (BasicBlock *ExitingBB : ExitingBlocks) { + if (IgnoreBlocks.count(ExitingBB)) + continue; const SCEV *ExitCount = getExitCount(L, ExitingBB); if (isa(ExitCount)) ExitCount = getExitCount(L, ExitingBB, Index: llvm/lib/Transforms/Utils/SimplifyIndVar.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyIndVar.cpp +++ llvm/lib/Transforms/Utils/SimplifyIndVar.cpp @@ -242,6 +242,73 @@ return true; } +static bool canEliminateMonotonicComparison(ICmpInst::Predicate Pred, + ICmpInst *ICmp, const SCEV *S, + const SCEV *X, const Loop *ICmpLoop, + ScalarEvolution *SE) { + auto *AR = dyn_cast(S); + // TODO: Lift affinity limitation in the future. + if (!AR || !AR->isAffine()) + return false; + // The predicate must be monotonic. + bool Increasing; + if (!SE->isMonotonicPredicate(AR, Pred, Increasing)) + return false; + + // Compute how much max iteration the loop will make if we eliminate this + // comparison. + DenseSet IgnoreBlocks; + IgnoreBlocks.insert(ICmp->getParent()); + const SCEV *MaxIter = + SE->computeMaxBackedgeTakenCount(ICmpLoop, IgnoreBlocks); + if (isa(MaxIter)) + return false; + + // First, check the predicate on the 1st iteration. + const SCEV *Base = AR->getOperand(0); + if (!SE->isKnownPredicate(Pred, Base, X)) + return false; + + // If the loop never goes on 2nd iteraiton, we are done. + if (MaxIter != SE->getZero(MaxIter->getType())) { + // Type mismatch here means that MaxIter is potentially larger than max + // unsigned value in base type, which mean we cannot prove no wrap for the + // indvar. + if (Base->getType() != MaxIter->getType()) + return false; + + // TODO: Support steps other than +/- 1. + const SCEV *Step = AR->getOperand(1); + auto *One = SE->getOne(Step->getType()); + auto *MinusOne = SE->getNegativeSCEV(One); + if (Step != One && Step != MinusOne) + return false; + // Value of IV on max possible last iteration. + const SCEV *Last = SE->getAddExpr(Base, SE->getMulExpr(Step, MaxIter)); + // Does it still meet the requirement? + if (!SE->isKnownPredicate(Pred, Last, X)) + return false; + // Now, we've proved + // Because step is +/- 1 and MaxIter has same type as Base (i.e. it does not + // exceed max + // unsigned value of this type), this effectively proves that there is no + // wrap during + // the iteration. To prove that there is no signed/unsigned wrap, we need to + // check that + // Base <= Last for step = 1 or Base >= Last for step = -1. + ICmpInst::Predicate OverflowPred; + if (Step == One) + OverflowPred = + CmpInst::isSigned(Pred) ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE; + else + OverflowPred = + CmpInst::isSigned(Pred) ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE; + if (!SE->isKnownPredicate(OverflowPred, Base, Last)) + return false; + } + return true; +} + /// SimplifyIVUsers helper for eliminating useless /// comparisons against an induction variable. void SimplifyIndvar::eliminateIVComparison(ICmpInst *ICmp, Value *IVOperand) { @@ -271,6 +338,10 @@ ICmp->replaceAllUsesWith(ConstantInt::getFalse(ICmp->getContext())); DeadInsts.emplace_back(ICmp); LLVM_DEBUG(dbgs() << "INDVARS: Eliminated comparison: " << *ICmp << '\n'); + } else if (canEliminateMonotonicComparison(Pred, ICmp, S, X, ICmpLoop, SE)) { + LLVM_DEBUG(dbgs() << "INDVARS: Eliminated comparison: " << *ICmp << '\n'); + ICmp->replaceAllUsesWith(ConstantInt::getTrue(ICmp->getContext())); + DeadInsts.emplace_back(ICmp); } else if (makeIVComparisonInvariant(ICmp, IVOperand)) { // fallthrough to end of function } else if (ICmpInst::isSigned(OriginalPred) && Index: llvm/test/Transforms/IndVarSimplify/monotonic_checks.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/monotonic_checks.ll +++ llvm/test/Transforms/IndVarSimplify/monotonic_checks.ll @@ -12,8 +12,7 @@ ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[LEN]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], -1 -; CHECK-NEXT: [[RC:%.*]] = icmp slt i32 [[IV_NEXT]], [[LEN]] -; CHECK-NEXT: br i1 [[RC]], label [[BACKEDGE]], label [[FAIL:%.*]] +; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[FAIL:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ne i32 [[IV]], 0 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] @@ -172,8 +171,7 @@ ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[LEN]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 -; CHECK-NEXT: [[RC:%.*]] = icmp ugt i32 [[IV_NEXT]], [[LEN]] -; CHECK-NEXT: br i1 [[RC]], label [[BACKEDGE]], label [[FAIL:%.*]] +; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[FAIL:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ne i32 [[IV]], 1000 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] @@ -211,8 +209,7 @@ ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[LEN]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], -1 -; CHECK-NEXT: [[RC:%.*]] = icmp slt i32 [[IV_NEXT]], [[LEN]] -; CHECK-NEXT: br i1 [[RC]], label [[BACKEDGE]], label [[FAIL:%.*]] +; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[FAIL:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ne i32 [[IV]], 0 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]