RHS, LHS, FoundLHS, FoundRHS);
}
+ // Check if we can make progress by sharpening ranges.
+ if (FoundPred == ICmpInst::ICMP_NE &&
+ (isa<SCEVConstant>(FoundLHS) || isa<SCEVConstant>(FoundRHS))) {
+
+ const SCEVConstant *C = nullptr;
+ const SCEV *V = nullptr;
+
+ if (isa<SCEVConstant>(FoundLHS)) {
+ C = cast<SCEVConstant>(FoundLHS);
+ V = FoundRHS;
+ } else {
+ C = cast<SCEVConstant>(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))
--- /dev/null
+;; 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}