Teach ScalarEvolution to sharpen range information.

If x is known to have the range [a, b), in a loop predicated by (icmp
ne x, a) its range can be sharpened to [a + 1, b).  Get
ScalarEvolution and hence IndVars to exploit this fact.

This change triggers an optimization to widen-loop-comp.ll, so it had
to be edited to get it to pass.

This change was originally landed in r219834 but had a bug and broke
ASan. It was reverted in r219878, and is now being re-landed after
fixing the original bug.

phabricator: http://reviews.llvm.org/D5639
reviewed by: atrick



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@221839 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sanjoy Das 2014-11-13 00:00:58 +00:00
parent 72c32c6c82
commit de87c9165a
3 changed files with 174 additions and 2 deletions

View File

@ -6782,6 +6782,66 @@ bool ScalarEvolution::isImpliedCond(ICmpInst::Predicate Pred,
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))

View File

@ -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}

View File

@ -67,8 +67,7 @@ for.end:
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 ]