Index: lib/Analysis/ScalarEvolution.cpp =================================================================== --- lib/Analysis/ScalarEvolution.cpp +++ lib/Analysis/ScalarEvolution.cpp @@ -6782,6 +6782,66 @@ RHS, LHS, FoundLHS, FoundRHS); } + // Check if we can make progress by sharpening ranges. + if (FoundPred == ICmpInst::ICMP_NE && + (isa(FoundLHS) || isa(FoundRHS))) { + + const SCEVConstant *C = nullptr; + const SCEV *V = nullptr; + + if (isa(FoundLHS)) { + C = cast(FoundLHS); + V = FoundRHS; + } else { + C = cast(FoundRHS); + V = FoundLHS; + } + + // The guarding predicate tells us that C != V. If the known range + // of V is [C, t), we can sharpen the range to [C + 1, t). The + // range we consider has to correspond to same signedness as the + // predicate we're interested in folding. + + APInt Min = ICmpInst::isSigned(Pred) ? + getSignedRange(V).getSignedMin() : getUnsignedRange(V).getUnsignedMin(); + + if (Min == C->getValue()->getValue()) { + // Given (V >= Min && V != Min) we conclude V >= (Min + 1). + // This is true even if (Min + 1) wraps around -- in case of + // wraparound, (Min + 1) < Min, so (V >= Min => V >= (Min + 1)). + + APInt SharperMin = Min + 1; + + switch (Pred) { + case ICmpInst::ICMP_SGE: + case ICmpInst::ICMP_UGE: + // We know V `Pred` SharperMin. If this implies LHS `Pred` + // RHS, we're done. + if (isImpliedCondOperands(Pred, LHS, RHS, V, + getConstant(SharperMin))) + return true; + + case ICmpInst::ICMP_SGT: + case ICmpInst::ICMP_UGT: + // We know from the range information that (V `Pred` Min || + // V == Min). We know from the guarding condition that !(V + // == Min). This gives us + // + // V `Pred` Min || V == Min && !(V == Min) + // => V `Pred` Min + // + // If V `Pred` Min implies LHS `Pred` RHS, we're done. + + if (isImpliedCondOperands(Pred, LHS, RHS, V, getConstant(Min))) + return true; + + default: + // No change + break; + } + } + } + // Check whether the actual condition is beyond sufficient. if (FoundPred == ICmpInst::ICMP_EQ) if (ICmpInst::isTrueWhenEqual(Pred)) Index: test/Transforms/IndVarSimplify/sharpen-range.ll =================================================================== --- /dev/null +++ test/Transforms/IndVarSimplify/sharpen-range.ll @@ -0,0 +1,113 @@ +;; RUN: opt -S < %s -indvars | FileCheck %s + +;; Check if llvm can narrow !range metadata based on loop entry +;; predicates. + +declare void @abort() + +define i1 @bounded_below_slt(i32* nocapture readonly %buffer) { +; CHECK-LABEL: bounded_below_slt +entry: + %length = load i32* %buffer, !range !0 + %entry.pred = icmp eq i32 %length, 0 + br i1 %entry.pred, label %abort, label %loop.preheader + +loop.preheader: + br label %loop + +loop: +; CHECK: loop + %idx = phi i32 [ %idx.inc, %loop.next ], [ 0, %loop.preheader ] + %oob.pred = icmp slt i32 %idx, %length + br i1 %oob.pred, label %loop.next, label %oob +; CHECK: br i1 true, label %loop.next, label %oob + +loop.next: +; CHECK: loop.next + %idx.inc = add i32 %idx, 1 + %exit.pred = icmp slt i32 %idx.inc, %length + br i1 %exit.pred, label %loop, label %abort.loopexit + +abort.loopexit: + br label %abort + +abort: + ret i1 false + +oob: + tail call void @abort() + ret i1 false +} + +define i1 @bounded_below_sle(i32* nocapture readonly %buffer) { +; CHECK-LABEL: bounded_below_sle +entry: + %length = load i32* %buffer, !range !0 + %entry.pred = icmp eq i32 %length, 0 + br i1 %entry.pred, label %abort, label %loop.preheader + +loop.preheader: + br label %loop + +loop: +; CHECK: loop + %idx = phi i32 [ %idx.inc, %loop.next ], [ 0, %loop.preheader ] + %oob.pred = icmp sle i32 %idx, %length + br i1 %oob.pred, label %loop.next, label %oob +; CHECK: br i1 true, label %loop.next, label %oob + +loop.next: +; CHECK: loop.next + %idx.inc = add i32 %idx, 1 + %exit.pred = icmp sle i32 %idx.inc, %length + br i1 %exit.pred, label %loop, label %abort.loopexit + +abort.loopexit: + br label %abort + +abort: + ret i1 false + +oob: + tail call void @abort() + ret i1 false +} + +;; Assert that we're not making an incorrect transform. + +declare i32 @check(i8*) + +define void @NoChange() { +; CHECK-LABEL: NoChange +entry: + br label %loop.begin + +loop.begin: +; CHECK: loop.begin: + %i.01 = phi i64 [ 2, %entry ], [ %add, %loop.end ] + %cmp = icmp ugt i64 %i.01, 1 +; CHECK: %cmp = icmp ugt i64 %i.01, 1 + br i1 %cmp, label %loop, label %loop.end + +loop: +; CHECK: loop + %.sum = add i64 %i.01, -2 + %v = getelementptr inbounds i8* null, i64 %.sum + %r = tail call i32 @check(i8* %v) + %c = icmp eq i32 %r, 0 + br i1 %c, label %loop.end, label %abort.now + +abort.now: + tail call void @abort() + unreachable + +loop.end: + %add = add i64 %i.01, -1 + %eq = icmp eq i64 %add, 0 + br i1 %eq, label %exit, label %loop.begin + +exit: + ret void +} + +!0 = metadata !{i32 0, i32 100} Index: test/Transforms/IndVarSimplify/widen-loop-comp.ll =================================================================== --- test/Transforms/IndVarSimplify/widen-loop-comp.ll +++ test/Transforms/IndVarSimplify/widen-loop-comp.ll @@ -67,8 +67,7 @@ define void @test2([8 x i8]* %a, i8* %b, i8 %limit) { entry: %conv = zext i8 %limit to i32 - %cmp23 = icmp eq i8 %limit, 0 - br i1 %cmp23, label %for.cond1.preheader, label %for.cond1.preheader.us + br i1 undef, label %for.cond1.preheader, label %for.cond1.preheader.us for.cond1.preheader.us: %storemerge5.us = phi i32 [ 0, %entry ], [ %inc14.us, %for.inc13.us ]