Index: llvm/lib/Transforms/Scalar/IndVarSimplify.cpp =================================================================== --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -2329,6 +2329,29 @@ return MadeAnyChanges; } +// Returns true if the condition of \p BI being checked is invariant and can be +// proved to be trivially true. +static bool isTrivialCond(const Loop *L, BranchInst *BI, ScalarEvolution *SE, + bool Inverted) { + ICmpInst::Predicate Pred; + Value *LHS, *RHS; + using namespace PatternMatch; + if (!match(BI, m_Br(m_ICmp(Pred, m_Value(LHS), m_Value(RHS)), + m_BasicBlock(), m_BasicBlock()))) + return false; + + if (Inverted) + Pred = CmpInst::getInversePredicate(Pred); + + const SCEV *LHSS = SE->getSCEVAtScope(LHS, L); + const SCEV *RHSS = SE->getSCEVAtScope(RHS, L); + // Can we prove it to be trivially true? + if (SE->isKnownPredicate(Pred, LHSS, RHSS)) + return true; + + return false; +} + bool IndVarSimplify::optimizeLoopExits(Loop *L, SCEVExpander &Rewriter) { SmallVector ExitingBlocks; L->getExitingBlocks(ExitingBlocks); @@ -2350,9 +2373,9 @@ if (isa(BI->getCondition())) return true; - const SCEV *ExitCount = SE->getExitCount(L, ExitingBB); - if (isa(ExitCount)) + if (!DT->dominates(ExitingBB, L->getLoopLatch())) return true; + return false; }); ExitingBlocks.erase(NewEnd, ExitingBlocks.end()); @@ -2399,7 +2422,21 @@ SmallSet DominatingExitCounts; for (BasicBlock *ExitingBB : ExitingBlocks) { const SCEV *ExitCount = SE->getExitCount(L, ExitingBB); - assert(!isa(ExitCount) && "checked above"); + if (isa(ExitCount)) { + // Okay, we do not know the exit count here. Can we at least prove that it + // will remain the same within iteration space? + if (isTrivialCond(L, cast(ExitingBB->getTerminator()), SE, + false)) { + FoldExit(ExitingBB, false); + Changed = true; + } + if (isTrivialCond(L, cast(ExitingBB->getTerminator()), SE, + true)) { + FoldExit(ExitingBB, true); + Changed = true; + } + continue; + } // If we know we'd exit on the first iteration, rewrite the exit to // reflect this. This does not imply the loop must exit through this Index: llvm/test/Transforms/IndVarSimplify/eliminate-comparison.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/eliminate-comparison.ll +++ llvm/test/Transforms/IndVarSimplify/eliminate-comparison.ll @@ -14,7 +14,7 @@ ; CHECK-NEXT: [[CMP9:%.*]] = icmp sgt i64 [[N:%.*]], 0 ; CHECK-NEXT: br i1 [[CMP9]], label [[PRE:%.*]], label [[RETURN:%.*]] ; CHECK: pre: -; CHECK-NEXT: [[T3:%.*]] = load i32, i32* [[P:%.*]] +; CHECK-NEXT: [[T3:%.*]] = load i32, i32* [[P:%.*]], align 4 ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp ne i32 [[T3]], 0 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: @@ -23,7 +23,7 @@ ; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN:%.*]], label [[FOR_INC]] ; CHECK: if.then: ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr [0 x double], [0 x double]* @X, i64 0, i64 [[I]] -; CHECK-NEXT: store double 3.200000e+00, double* [[ARRAYIDX]] +; CHECK-NEXT: store double 3.200000e+00, double* [[ARRAYIDX]], align 8 ; CHECK-NEXT: br label [[FOR_INC]] ; CHECK: for.inc: ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I]], 1 @@ -144,7 +144,7 @@ ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[LOOP]] ], [ 0, [[ENTRY:%.*]] ] -; CHECK-NEXT: store i64 [[INDVARS_IV]], i64* null +; CHECK-NEXT: store i64 [[INDVARS_IV]], i64* null, align 8 ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 ; CHECK-NEXT: br i1 false, label [[LOOP]], label [[RETURN:%.*]] ; CHECK: return: @@ -176,32 +176,18 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[FORCOND:%.*]] ; CHECK: forcond: -; CHECK-NEXT: [[__KEY6_0:%.*]] = phi i32 [ 2, [[ENTRY:%.*]] ], [ [[TMP37:%.*]], [[NOASSERT:%.*]] ] -; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[__KEY6_0]], 10 -; CHECK-NEXT: br i1 [[EXITCOND1]], label [[NOASSERT]], label [[FORCOND38_PREHEADER:%.*]] +; CHECK-NEXT: br i1 false, label [[NOASSERT:%.*]], label [[FORCOND38_PREHEADER:%.*]] ; CHECK: forcond38.preheader: ; CHECK-NEXT: br label [[FORCOND38:%.*]] ; CHECK: noassert: -; CHECK-NEXT: [[TMP13:%.*]] = sdiv i32 -32768, [[__KEY6_0]] -; CHECK-NEXT: [[TMP2936:%.*]] = shl i32 [[TMP13]], 24 -; CHECK-NEXT: [[SEXT23:%.*]] = shl i32 [[TMP13]], 24 -; CHECK-NEXT: [[TMP32:%.*]] = icmp eq i32 [[TMP2936]], [[SEXT23]] -; CHECK-NEXT: [[TMP37]] = add nuw nsw i32 [[__KEY6_0]], 1 -; CHECK-NEXT: br i1 [[TMP32]], label [[FORCOND]], label [[ASSERT33:%.*]] +; CHECK-NEXT: br i1 true, label [[FORCOND]], label [[ASSERT33:%.*]] ; CHECK: assert33: ; CHECK-NEXT: tail call void @llvm.trap() ; CHECK-NEXT: unreachable ; CHECK: forcond38: -; CHECK-NEXT: [[__KEY8_0:%.*]] = phi i32 [ [[TMP81:%.*]], [[NOASSERT68:%.*]] ], [ 2, [[FORCOND38_PREHEADER]] ] -; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[__KEY8_0]], 10 -; CHECK-NEXT: br i1 [[EXITCOND]], label [[NOASSERT68]], label [[UNROLLEDEND:%.*]] +; CHECK-NEXT: br i1 false, label [[NOASSERT68:%.*]], label [[UNROLLEDEND:%.*]] ; CHECK: noassert68: -; CHECK-NEXT: [[TMP57:%.*]] = sdiv i32 -32768, [[__KEY8_0]] -; CHECK-NEXT: [[SEXT34:%.*]] = shl i32 [[TMP57]], 16 -; CHECK-NEXT: [[SEXT21:%.*]] = shl i32 [[TMP57]], 16 -; CHECK-NEXT: [[TMP76:%.*]] = icmp eq i32 [[SEXT34]], [[SEXT21]] -; CHECK-NEXT: [[TMP81]] = add nuw nsw i32 [[__KEY8_0]], 1 -; CHECK-NEXT: br i1 [[TMP76]], label [[FORCOND38]], label [[ASSERT77:%.*]] +; CHECK-NEXT: br i1 true, label [[FORCOND38]], label [[ASSERT77:%.*]] ; CHECK: assert77: ; CHECK-NEXT: tail call void @llvm.trap() ; CHECK-NEXT: unreachable @@ -260,18 +246,11 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[FORCOND:%.*]] ; CHECK: forcond: -; CHECK-NEXT: [[__KEY6_0:%.*]] = phi i32 [ 2, [[ENTRY:%.*]] ], [ [[TMP37:%.*]], [[NOASSERT:%.*]] ] -; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[__KEY6_0]], 10 -; CHECK-NEXT: br i1 [[EXITCOND]], label [[NOASSERT]], label [[FORCOND38_PREHEADER:%.*]] +; CHECK-NEXT: br i1 false, label [[NOASSERT:%.*]], label [[FORCOND38_PREHEADER:%.*]] ; CHECK: forcond38.preheader: ; CHECK-NEXT: br label [[FORCOND38:%.*]] ; CHECK: noassert: -; CHECK-NEXT: [[TMP13:%.*]] = sdiv i32 -32768, [[__KEY6_0]] -; CHECK-NEXT: [[TMP2936:%.*]] = shl i32 [[TMP13]], 24 -; CHECK-NEXT: [[SEXT23:%.*]] = shl i32 [[TMP13]], 24 -; CHECK-NEXT: [[TMP32:%.*]] = icmp eq i32 [[TMP2936]], [[SEXT23]] -; CHECK-NEXT: [[TMP37]] = add nuw nsw i32 [[__KEY6_0]], 1 -; CHECK-NEXT: br i1 [[TMP32]], label [[FORCOND]], label [[ASSERT33:%.*]] +; CHECK-NEXT: br i1 true, label [[FORCOND]], label [[ASSERT33:%.*]] ; CHECK: assert33: ; CHECK-NEXT: tail call void @llvm.trap() ; CHECK-NEXT: unreachable @@ -334,7 +313,7 @@ define void @func_13(i32* %len.ptr) { ; CHECK-LABEL: @func_13( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_PTR:%.*]], !range !0 +; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_PTR:%.*]], align 4, [[RNG0:!range !.*]] ; CHECK-NEXT: [[LEN_IS_ZERO:%.*]] = icmp eq i32 [[LEN]], 0 ; CHECK-NEXT: br i1 [[LEN_IS_ZERO]], label [[LEAVE:%.*]], label [[LOOP_PREHEADER:%.*]] ; CHECK: loop.preheader: @@ -378,7 +357,7 @@ define void @func_14(i32* %len.ptr) { ; CHECK-LABEL: @func_14( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_PTR:%.*]], !range !0 +; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_PTR:%.*]], align 4, [[RNG0]] ; CHECK-NEXT: [[LEN_IS_ZERO:%.*]] = icmp eq i32 [[LEN]], 0 ; CHECK-NEXT: [[LEN_IS_INT_MIN:%.*]] = icmp eq i32 [[LEN]], -2147483648 ; CHECK-NEXT: [[NO_ENTRY:%.*]] = or i1 [[LEN_IS_ZERO]], [[LEN_IS_INT_MIN]] @@ -426,7 +405,7 @@ define void @func_15(i32* %len.ptr) { ; CHECK-LABEL: @func_15( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_PTR:%.*]], !range !0 +; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_PTR:%.*]], align 4, [[RNG0]] ; CHECK-NEXT: [[LEN_ADD_1:%.*]] = add i32 [[LEN]], 1 ; CHECK-NEXT: [[LEN_ADD_1_IS_ZERO:%.*]] = icmp eq i32 [[LEN_ADD_1]], 0 ; CHECK-NEXT: br i1 [[LEN_ADD_1_IS_ZERO]], label [[LEAVE:%.*]], label [[LOOP_PREHEADER:%.*]] @@ -471,7 +450,7 @@ define void @func_16(i32* %len.ptr) { ; CHECK-LABEL: @func_16( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_PTR:%.*]], !range !0 +; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_PTR:%.*]], align 4, [[RNG0]] ; CHECK-NEXT: [[LEN_ADD_5:%.*]] = add i32 [[LEN]], 5 ; CHECK-NEXT: [[ENTRY_COND_0:%.*]] = icmp slt i32 [[LEN]], 2147483643 ; CHECK-NEXT: [[ENTRY_COND_1:%.*]] = icmp slt i32 4, [[LEN_ADD_5]] @@ -522,7 +501,7 @@ define void @func_17(i32* %len.ptr) { ; CHECK-LABEL: @func_17( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_PTR:%.*]] +; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_PTR:%.*]], align 4 ; CHECK-NEXT: [[LEN_ADD_5:%.*]] = add i32 [[LEN]], -5 ; CHECK-NEXT: [[ENTRY_COND_0:%.*]] = icmp slt i32 [[LEN]], -2147483643 ; CHECK-NEXT: [[ENTRY_COND_1:%.*]] = icmp slt i32 -6, [[LEN_ADD_5]] @@ -579,7 +558,7 @@ define i1 @func_18(i16* %tmp20, i32* %len.addr) { ; CHECK-LABEL: @func_18( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_ADDR:%.*]], !range !0 +; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_ADDR:%.*]], align 4, [[RNG0]] ; CHECK-NEXT: [[TMP18:%.*]] = icmp eq i32 [[LEN]], 0 ; CHECK-NEXT: br i1 [[TMP18]], label [[BB2:%.*]], label [[BB0_PREHEADER:%.*]] ; CHECK: bb0.preheader: @@ -591,7 +570,7 @@ ; CHECK-NEXT: br i1 true, label [[STAY:%.*]], label [[BB2_LOOPEXIT:%.*]] ; CHECK: stay: ; CHECK-NEXT: [[TMP25:%.*]] = getelementptr inbounds i16, i16* [[TMP20:%.*]], i32 [[VAR_1]] -; CHECK-NEXT: [[TMP26:%.*]] = load i16, i16* [[TMP25]] +; CHECK-NEXT: [[TMP26:%.*]] = load i16, i16* [[TMP25]], align 2 ; CHECK-NEXT: [[TMP29:%.*]] = icmp eq i16 [[TMP26]], 0 ; CHECK-NEXT: br i1 [[TMP29]], label [[BB1]], label [[BB2_LOOPEXIT]] ; CHECK: bb1: @@ -641,7 +620,7 @@ define void @func_19(i32* %length.ptr) { ; CHECK-LABEL: @func_19( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[LENGTH:%.*]] = load i32, i32* [[LENGTH_PTR:%.*]], !range !0 +; CHECK-NEXT: [[LENGTH:%.*]] = load i32, i32* [[LENGTH_PTR:%.*]], align 4, [[RNG0]] ; CHECK-NEXT: [[LENGTH_IS_NONZERO:%.*]] = icmp ne i32 [[LENGTH]], 0 ; CHECK-NEXT: br i1 [[LENGTH_IS_NONZERO]], label [[LOOP_PREHEADER:%.*]], label [[LEAVE:%.*]] ; CHECK: loop.preheader: @@ -684,7 +663,7 @@ define void @func_20(i32* %length.ptr) { ; CHECK-LABEL: @func_20( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[LENGTH:%.*]] = load i32, i32* [[LENGTH_PTR:%.*]] +; CHECK-NEXT: [[LENGTH:%.*]] = load i32, i32* [[LENGTH_PTR:%.*]], align 4 ; CHECK-NEXT: [[LENGTH_IS_NONZERO:%.*]] = icmp ne i32 [[LENGTH]], 0 ; CHECK-NEXT: br i1 [[LENGTH_IS_NONZERO]], label [[LOOP_PREHEADER:%.*]], label [[LEAVE:%.*]] ; CHECK: loop.preheader: @@ -730,7 +709,7 @@ define void @func_21(i32* %length.ptr) { ; CHECK-LABEL: @func_21( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[LENGTH:%.*]] = load i32, i32* [[LENGTH_PTR:%.*]], !range !0 +; CHECK-NEXT: [[LENGTH:%.*]] = load i32, i32* [[LENGTH_PTR:%.*]], align 4, [[RNG0]] ; CHECK-NEXT: [[LIM:%.*]] = sub i32 [[LENGTH]], 1 ; CHECK-NEXT: [[ENTRY_COND:%.*]] = icmp sgt i32 [[LENGTH]], 1 ; CHECK-NEXT: br i1 [[ENTRY_COND]], label [[LOOP_PREHEADER:%.*]], label [[LEAVE:%.*]] @@ -775,7 +754,7 @@ define void @func_22(i32* %length.ptr) { ; CHECK-LABEL: @func_22( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[LENGTH:%.*]] = load i32, i32* [[LENGTH_PTR:%.*]], !range !0 +; CHECK-NEXT: [[LENGTH:%.*]] = load i32, i32* [[LENGTH_PTR:%.*]], align 4, [[RNG0]] ; CHECK-NEXT: [[ENTRY_COND:%.*]] = icmp sgt i32 [[LENGTH]], 1 ; CHECK-NEXT: br i1 [[ENTRY_COND]], label [[LOOP_PREHEADER:%.*]], label [[LEAVE:%.*]] ; CHECK: loop.preheader: @@ -817,7 +796,7 @@ define void @func_23(i32* %length.ptr) { ; CHECK-LABEL: @func_23( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[LENGTH:%.*]] = load i32, i32* [[LENGTH_PTR:%.*]], !range !0 +; CHECK-NEXT: [[LENGTH:%.*]] = load i32, i32* [[LENGTH_PTR:%.*]], align 4, [[RNG0]] ; CHECK-NEXT: [[ENTRY_COND:%.*]] = icmp ult i32 4, [[LENGTH]] ; CHECK-NEXT: br i1 [[ENTRY_COND]], label [[LOOP_PREHEADER:%.*]], label [[LEAVE:%.*]] ; CHECK: loop.preheader: @@ -858,7 +837,7 @@ define void @func_24(i32* %init.ptr) { ; CHECK-LABEL: @func_24( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[INIT:%.*]] = load i32, i32* [[INIT_PTR:%.*]], !range !0 +; CHECK-NEXT: [[INIT:%.*]] = load i32, i32* [[INIT_PTR:%.*]], align 4, [[RNG0]] ; CHECK-NEXT: [[ENTRY_COND:%.*]] = icmp ugt i32 [[INIT]], 4 ; CHECK-NEXT: br i1 [[ENTRY_COND]], label [[LOOP_PREHEADER:%.*]], label [[LEAVE:%.*]] ; CHECK: loop.preheader: