Index: llvm/lib/Transforms/Scalar/IndVarSimplify.cpp =================================================================== --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -2306,18 +2306,24 @@ return MadeAnyChanges; } +enum ExitCondAnalysisResult { + CanBeRemoved, + CanBeReplacedWithFirstIterCheck, + CannotOptimize +}; + // Returns true if the condition of \p BI being checked is invariant and can be // proved to be trivially true during at least first \p MaxIter iterations. -static bool isTrivialCond(const Loop *L, BranchInst *BI, ScalarEvolution *SE, - bool ProvingLoopExit, const SCEV *MaxIter, - bool SkipLastIter) { +static ExitCondAnalysisResult +analyzeCond(const Loop *L, BranchInst *BI, ScalarEvolution *SE, + bool ProvingLoopExit, const SCEV *MaxIter, bool SkipLastIter) { ICmpInst::Predicate Pred; Value *LHS, *RHS; using namespace PatternMatch; BasicBlock *TrueSucc, *FalseSucc; if (!match(BI, m_Br(m_ICmp(Pred, m_Value(LHS), m_Value(RHS)), m_BasicBlock(TrueSucc), m_BasicBlock(FalseSucc)))) - return false; + return CannotOptimize; assert((L->contains(TrueSucc) != L->contains(FalseSucc)) && "Not a loop exit!"); @@ -2334,10 +2340,10 @@ const SCEV *RHSS = SE->getSCEVAtScope(RHS, L); // Can we prove it to be trivially true? if (SE->isKnownPredicateAt(Pred, LHSS, RHSS, BI)) - return true; + return CanBeRemoved; if (ProvingLoopExit) - return false; + return CannotOptimize; ICmpInst::Predicate InvariantPred; const SCEV *InvariantLHS, *InvariantRHS; @@ -2351,10 +2357,13 @@ if (!SE->isLoopInvariantExitCondDuringFirstIterations( Pred, LHSS, RHSS, L, BI, MaxIter, InvariantPred, InvariantLHS, InvariantRHS)) - return false; + return CannotOptimize; // Can we prove it to be trivially true? - return SE->isKnownPredicateAt(InvariantPred, InvariantLHS, InvariantRHS, BI); + if (SE->isKnownPredicateAt(InvariantPred, InvariantLHS, InvariantRHS, BI)) + return CanBeRemoved; + else + return CanBeReplacedWithFirstIterCheck; } bool IndVarSimplify::optimizeLoopExits(Loop *L, SCEVExpander &Rewriter) { @@ -2437,11 +2446,29 @@ // will remain the same within iteration space? auto *BI = cast(ExitingBB->getTerminator()); auto OptimizeCond = [&](bool Inverted, bool SkipLastIter) { - if (isTrivialCond(L, BI, SE, Inverted, MaxExitCount, SkipLastIter)) { + switch (analyzeCond(L, BI, SE, Inverted, MaxExitCount, SkipLastIter)) { + case CanBeRemoved: FoldExit(ExitingBB, Inverted); return true; + case CanBeReplacedWithFirstIterCheck: { + auto *Cond = cast(BI->getCondition()); + const SCEV *StartSCEV = cast( + SE->getSCEV(Cond->getOperand(0)))->getStart(); + Rewriter.setInsertPoint(BI); + auto *StartV = Rewriter.expandCodeFor(StartSCEV); + IRBuilder<> Builder(BI); + auto *NewCond = + Builder.CreateICmp(Cond->getPredicate(), StartV, + Cond->getOperand(1), Cond->getName()); + BI->setOperand(0, NewCond); + if (Cond->getNumUses() == 0) + Cond->eraseFromParent(); + return true; } - return false; + case CannotOptimize: + return false; + } + llvm_unreachable("Unknown analysis result!"); }; if (OptimizeCond(false, false) || OptimizeCond(true, false)) Changed = true; Index: llvm/test/Transforms/IndVarSimplify/predicated_ranges.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/predicated_ranges.ll +++ llvm/test/Transforms/IndVarSimplify/predicated_ranges.ll @@ -470,6 +470,7 @@ ; CHECK-LABEL: @test_can_predicate_simple_unsigned( ; CHECK-NEXT: preheader: ; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[P:%.*]], align 4 +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[LEN]], -1 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[LEN]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] @@ -477,8 +478,8 @@ ; CHECK-NEXT: br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]] ; CHECK: range_check_block: ; CHECK-NEXT: [[IV_NEXT]] = sub i32 [[IV]], 1 -; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[IV_NEXT]], [[LEN]] -; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[FAIL:%.*]] +; CHECK-NEXT: [[RANGE_CHECK1:%.*]] = icmp ult i32 [[TMP0]], [[LEN]] +; CHECK-NEXT: br i1 [[RANGE_CHECK1]], label [[BACKEDGE]], label [[FAIL:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, i32* [[P]], i32 [[IV]] ; CHECK-NEXT: [[EL:%.*]] = load i32, i32* [[EL_PTR]], align 4