Index: llvm/trunk/include/llvm/Analysis/ScalarEvolution.h =================================================================== --- llvm/trunk/include/llvm/Analysis/ScalarEvolution.h +++ llvm/trunk/include/llvm/Analysis/ScalarEvolution.h @@ -253,6 +253,10 @@ /// conditions dominating the backedge of a loop. bool WalkingBEDominatingConds; + /// Set to true by isKnownPredicateViaSplitting when we're trying to prove a + /// predicate by splitting it into a set of independent predicates. + bool ProvingSplitPredicate; + /// Information about the number of loop iterations for which a loop exit's /// branch condition evaluates to the not-taken path. This is a temporary /// pair of exact and max expressions that are eventually summarized in @@ -559,6 +563,11 @@ bool isKnownPredicateWithRanges(ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS); + /// Try to split Pred LHS RHS into logical conjunctions (and's) and try to + /// prove them individually. + bool isKnownPredicateViaSplitting(ICmpInst::Predicate Pred, const SCEV *LHS, + const SCEV *RHS); + /// Drop memoized information computed for S. void forgetMemoizedResults(const SCEV *S); Index: llvm/trunk/lib/Analysis/ScalarEvolution.cpp =================================================================== --- llvm/trunk/lib/Analysis/ScalarEvolution.cpp +++ llvm/trunk/lib/Analysis/ScalarEvolution.cpp @@ -6764,6 +6764,9 @@ if (LeftGuarded && RightGuarded) return true; + if (isKnownPredicateViaSplitting(Pred, LHS, RHS)) + return true; + // Otherwise see what can be done with known constant ranges. return isKnownPredicateWithRanges(Pred, LHS, RHS); } @@ -6969,6 +6972,31 @@ return false; } +bool ScalarEvolution::isKnownPredicateViaSplitting(ICmpInst::Predicate Pred, + const SCEV *LHS, + const SCEV *RHS) { + if (ProvingSplitPredicate) + return false; + + // Allowing arbitrary number of activations of isKnownPredicateViaSplitting on + // the stack can result in exponential time complexity. + SaveAndRestore Restore(ProvingSplitPredicate, true); + + // If L >= 0 then I `ult` L <=> I >= 0 && I `slt` L + // + // To prove L >= 0 we use isKnownNonNegative whereas to prove I >= 0 we use + // isKnownPredicate. isKnownPredicate is more powerful, but also more + // expensive; and using isKnownNonNegative(RHS) is sufficient for most of the + // interesting cases seen in practice. We can consider "upgrading" L >= 0 to + // use isKnownPredicate later if needed. + if (Pred == ICmpInst::ICMP_ULT && isKnownNonNegative(RHS) && + isKnownPredicate(CmpInst::ICMP_SGE, LHS, getZero(LHS->getType())) && + isKnownPredicate(CmpInst::ICMP_SLT, LHS, RHS)) + return true; + + return false; +} + /// isLoopBackedgeGuardedByCond - Test whether the backedge of the loop is /// protected by a conditional between LHS and RHS. This is used to /// to eliminate casts. @@ -8529,14 +8557,15 @@ LoopInfo &LI) : F(F), TLI(TLI), AC(AC), DT(DT), LI(LI), CouldNotCompute(new SCEVCouldNotCompute()), - WalkingBEDominatingConds(false), ValuesAtScopes(64), LoopDispositions(64), - BlockDispositions(64), FirstUnknown(nullptr) {} + WalkingBEDominatingConds(false), ProvingSplitPredicate(false), + ValuesAtScopes(64), LoopDispositions(64), BlockDispositions(64), + FirstUnknown(nullptr) {} ScalarEvolution::ScalarEvolution(ScalarEvolution &&Arg) : F(Arg.F), TLI(Arg.TLI), AC(Arg.AC), DT(Arg.DT), LI(Arg.LI), CouldNotCompute(std::move(Arg.CouldNotCompute)), ValueExprMap(std::move(Arg.ValueExprMap)), - WalkingBEDominatingConds(false), + WalkingBEDominatingConds(false), ProvingSplitPredicate(false), BackedgeTakenCounts(std::move(Arg.BackedgeTakenCounts)), ConstantEvolutionLoopExitValue( std::move(Arg.ConstantEvolutionLoopExitValue)), @@ -8573,6 +8602,7 @@ assert(PendingLoopPredicates.empty() && "isImpliedCond garbage"); assert(!WalkingBEDominatingConds && "isLoopBackedgeGuardedByCond garbage!"); + assert(!ProvingSplitPredicate && "ProvingSplitPredicate garbage!"); } bool ScalarEvolution::hasLoopInvariantBackedgeTakenCount(const Loop *L) { Index: llvm/trunk/test/Transforms/IndVarSimplify/eliminate-comparison.ll =================================================================== --- llvm/trunk/test/Transforms/IndVarSimplify/eliminate-comparison.ll +++ llvm/trunk/test/Transforms/IndVarSimplify/eliminate-comparison.ll @@ -394,4 +394,87 @@ ret i1 true } +define void @func_19(i32* %length.ptr) { +; CHECK-LABEL: @func_19( + entry: + %length = load i32, i32* %length.ptr, !range !0 + %length.is.nonzero = icmp ne i32 %length, 0 + br i1 %length.is.nonzero, label %loop, label %leave + + loop: +; CHECK: loop: + %iv = phi i32 [ 0, %entry ], [ %iv.inc, %be ] + %iv.inc = add i32 %iv, 1 + %range.check = icmp ult i32 %iv, %length + br i1 %range.check, label %be, label %leave +; CHECK: br i1 true, label %be, label %leave.loopexit +; CHECK: be: + + be: + call void @side_effect() + %be.cond = icmp slt i32 %iv.inc, %length + br i1 %be.cond, label %loop, label %leave + + leave: + ret void +} + +define void @func_20(i32* %length.ptr) { +; Like @func_19, but %length is no longer provably positive, so +; %range.check cannot be proved to be always true. + +; CHECK-LABEL: @func_20( + entry: + %length = load i32, i32* %length.ptr + %length.is.nonzero = icmp ne i32 %length, 0 + br i1 %length.is.nonzero, label %loop, label %leave + + loop: +; CHECK: loop: + %iv = phi i32 [ 0, %entry ], [ %iv.inc, %be ] + %iv.inc = add i32 %iv, 1 + %range.check = icmp ult i32 %iv, %length + br i1 %range.check, label %be, label %leave +; CHECK: br i1 %range.check, label %be, label %leave.loopexit +; CHECK: be: + + be: + call void @side_effect() + %be.cond = icmp slt i32 %iv.inc, %length + br i1 %be.cond, label %loop, label %leave + + leave: + ret void +} + +define void @func_21(i32* %length.ptr, i32 %init) { +; Like @func_19, but it is no longer possible to prove %iv's start +; value is positive without doing some control flow analysis. + +; CHECK-LABEL: @func_21( + entry: + %length = load i32, i32* %length.ptr, !range !0 + %length.is.nonzero = icmp ne i32 %length, 0 + %init.is.positive = icmp sgt i32 %init, 0 + %entry.cond = and i1 %length.is.nonzero, %init.is.positive + br i1 %length.is.nonzero, label %loop, label %leave + + loop: +; CHECK: loop: + %iv = phi i32 [ 0, %entry ], [ %iv.inc, %be ] + %iv.inc = add i32 %iv, 1 + %range.check = icmp ult i32 %iv, %length + br i1 %range.check, label %be, label %leave +; CHECK: br i1 true, label %be, label %leave.loopexit +; CHECK: be: + + be: + call void @side_effect() + %be.cond = icmp slt i32 %iv.inc, %length + br i1 %be.cond, label %loop, label %leave + + leave: + ret void +} + !0 = !{i32 0, i32 2147483647}