Index: llvm/include/llvm/Analysis/ScalarEvolution.h =================================================================== --- llvm/include/llvm/Analysis/ScalarEvolution.h +++ llvm/include/llvm/Analysis/ScalarEvolution.h @@ -1089,7 +1089,8 @@ /// invariants, available at L's entry. Otherwise, return None. Optional getLoopInvariantPredicate(ICmpInst::Predicate Pred, const SCEV *LHS, - const SCEV *RHS, const Loop *L); + const SCEV *RHS, const Loop *L, + const Instruction *CtxI = nullptr); /// If the result of the predicate LHS `Pred` RHS is loop invariant with /// respect to L at given Context during at least first MaxIter iterations, Index: llvm/lib/Analysis/ScalarEvolution.cpp =================================================================== --- llvm/lib/Analysis/ScalarEvolution.cpp +++ llvm/lib/Analysis/ScalarEvolution.cpp @@ -10687,8 +10687,8 @@ Optional ScalarEvolution::getLoopInvariantPredicate(ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS, - const Loop *L) { - + const Loop *L, + const Instruction *CtxI) { // If there is a loop-invariant, force it into the RHS, otherwise bail out. if (!isLoopInvariant(RHS, L)) { if (!isLoopInvariant(LHS, L)) @@ -10725,10 +10725,37 @@ bool Increasing = *MonotonicType == ScalarEvolution::MonotonicallyIncreasing; auto P = Increasing ? Pred : ICmpInst::getInversePredicate(Pred); - if (!isLoopBackedgeGuardedByCond(L, P, LHS, RHS)) + if (isLoopBackedgeGuardedByCond(L, P, LHS, RHS)) + return ScalarEvolution::LoopInvariantPredicate(Pred, ArLHS->getStart(), + RHS); + + if (!CtxI) return None; + // Try to prove via context. + // TODO: Support other cases. + switch (Pred) { + default: + break; + case ICmpInst::ICMP_ULE: + case ICmpInst::ICMP_ULT: { + assert(ArLHS->hasNoUnsignedWrap() && "Is a requirement of monotonicity!"); + // If we can prove that ArLHS =s 0, and we know that ArLHS + // does not cross zero, there are two options: + // - ArLHS is always negative. It means that ArLHS ArLHS Start(ArLHS) >=s 0. + auto SignFlippedPred = ICmpInst::getFlippedSignednessPredicate(Pred); + if (isKnownNonNegative(RHS) && + isKnownPredicateAt(SignFlippedPred, ArLHS, RHS, CtxI)) + return ScalarEvolution::LoopInvariantPredicate( + ICmpInst::ICMP_SGE, ArLHS->getStart(), getZero(ArLHS->getType())); + } + } - return ScalarEvolution::LoopInvariantPredicate(Pred, ArLHS->getStart(), RHS); + return None; } Optional Index: llvm/lib/Transforms/Utils/SimplifyIndVar.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyIndVar.cpp +++ llvm/lib/Transforms/Utils/SimplifyIndVar.cpp @@ -213,7 +213,8 @@ auto *PN = dyn_cast(IVOperand); if (!PN) return false; - auto LIP = SE->getLoopInvariantPredicate(Pred, S, X, L); + + auto LIP = SE->getLoopInvariantPredicate(Pred, S, X, L, ICmp); if (!LIP) return false; ICmpInst::Predicate InvariantPredicate = LIP->Pred; Index: llvm/test/Transforms/IndVarSimplify/cycled_phis.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/cycled_phis.ll +++ llvm/test/Transforms/IndVarSimplify/cycled_phis.ll @@ -349,7 +349,7 @@ ; CHECK-NEXT: [[SIGNED_CMP:%.*]] = icmp slt i32 [[IV]], [[LEN]] ; CHECK-NEXT: br i1 [[SIGNED_CMP]], label [[SIGNED_PASSED:%.*]], label [[FAILED_SIGNED:%.*]] ; CHECK: signed.passed: -; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV]], [[LEN]] +; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp sge i32 [[IV_START]], 0 ; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 @@ -467,7 +467,7 @@ ; CHECK-NEXT: [[SIGNED_CMP:%.*]] = icmp slt i32 [[IV]], [[LEN]] ; CHECK-NEXT: br i1 [[SIGNED_CMP]], label [[SIGNED_PASSED:%.*]], label [[FAILED_SIGNED:%.*]] ; CHECK: signed.passed: -; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV]], [[LEN]] +; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp sge i32 [[IV_START]], 0 ; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 Index: llvm/test/Transforms/IndVarSimplify/outer_phi.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/outer_phi.ll +++ llvm/test/Transforms/IndVarSimplify/outer_phi.ll @@ -412,7 +412,7 @@ ; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]] ; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]] ; CHECK: inner.1: -; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]] +; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp sge i32 [[OUTER_IV]], 0 ; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]] ; CHECK: inner.backedge: ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 @@ -974,7 +974,7 @@ ; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]] ; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]] ; CHECK: inner.1: -; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]] +; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp sge i32 [[OUTER_IV]], 0 ; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]] ; CHECK: inner.backedge: ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 @@ -1045,7 +1045,7 @@ ; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]] ; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]] ; CHECK: inner.1: -; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]] +; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp sge i32 [[OUTER_IV]], 0 ; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]] ; CHECK: inner.backedge: ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 @@ -1128,7 +1128,7 @@ ; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]] ; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]] ; CHECK: inner.1: -; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]] +; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp sge i32 [[OUTER_IV]], 0 ; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]] ; CHECK: inner.backedge: ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1