Re-apply r251050 with a for PR25421

The bug: I missed adding break statements in the switch / case.

Original commit message:

[SCEV] Teach SCEV some axioms about non-wrapping arithmetic

Summary:
 - A s<  (A + C)<nsw> if C >  0
 - A s<= (A + C)<nsw> if C >= 0
 - (A + C)<nsw> s<  A if C <  0
 - (A + C)<nsw> s<= A if C <= 0

Right now `C` needs to be a constant, but we can later generalize it to
be a non-constant if needed.

Reviewers: atrick, hfinkel, reames, nlewycky

Subscribers: sanjoy, llvm-commits

Differential Revision: http://reviews.llvm.org/D13686

llvm-svn: 252236
This commit is contained in:
Sanjoy Das 2015-11-05 23:45:38 +00:00
parent 8307ede58f
commit c1a2977fb2
4 changed files with 154 additions and 1 deletions

View File

@ -732,6 +732,14 @@ namespace llvm {
bool isKnownPredicateWithRanges(ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS);
/// Try to prove the condition described by "LHS Pred RHS" by ruling out
/// integer overflow.
///
/// For instance, this will return true for "A s< (A + C)<nsw>" if C is
/// positive.
bool isKnownPredicateViaNoOverflow(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,

View File

@ -7348,6 +7348,62 @@ ScalarEvolution::isKnownPredicateWithRanges(ICmpInst::Predicate Pred,
return false;
}
bool ScalarEvolution::isKnownPredicateViaNoOverflow(ICmpInst::Predicate Pred,
const SCEV *LHS,
const SCEV *RHS) {
// Match Result to (X + Y)<ExpectedFlags> where Y is a constant integer.
// Return Y via OutY.
auto MatchBinaryAddToConst =
[this](const SCEV *Result, const SCEV *X, APInt &OutY,
SCEV::NoWrapFlags ExpectedFlags) {
const SCEV *NonConstOp, *ConstOp;
SCEV::NoWrapFlags FlagsPresent;
if (!splitBinaryAdd(Result, ConstOp, NonConstOp, FlagsPresent) ||
!isa<SCEVConstant>(ConstOp) || NonConstOp != X)
return false;
OutY = cast<SCEVConstant>(ConstOp)->getValue()->getValue();
return (FlagsPresent & ExpectedFlags) == ExpectedFlags;
};
APInt C;
switch (Pred) {
default:
break;
case ICmpInst::ICMP_SGE:
std::swap(LHS, RHS);
case ICmpInst::ICMP_SLE:
// X s<= (X + C)<nsw> if C >= 0
if (MatchBinaryAddToConst(RHS, LHS, C, SCEV::FlagNSW) && C.isNonNegative())
return true;
// (X + C)<nsw> s<= X if C <= 0
if (MatchBinaryAddToConst(LHS, RHS, C, SCEV::FlagNSW) &&
!C.isStrictlyPositive())
return true;
break;
case ICmpInst::ICMP_SGT:
std::swap(LHS, RHS);
case ICmpInst::ICMP_SLT:
// X s< (X + C)<nsw> if C > 0
if (MatchBinaryAddToConst(RHS, LHS, C, SCEV::FlagNSW) &&
C.isStrictlyPositive())
return true;
// (X + C)<nsw> s< X if C < 0
if (MatchBinaryAddToConst(LHS, RHS, C, SCEV::FlagNSW) && C.isNegative())
return true;
break;
}
return false;
}
bool ScalarEvolution::isKnownPredicateViaSplitting(ICmpInst::Predicate Pred,
const SCEV *LHS,
const SCEV *RHS) {
@ -8004,7 +8060,8 @@ ScalarEvolution::isImpliedCondOperandsHelper(ICmpInst::Predicate Pred,
[this](ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS) {
return isKnownPredicateWithRanges(Pred, LHS, RHS) ||
IsKnownPredicateViaMinOrMax(*this, Pred, LHS, RHS) ||
IsKnownPredicateViaAddRecStart(*this, Pred, LHS, RHS);
IsKnownPredicateViaAddRecStart(*this, Pred, LHS, RHS) ||
isKnownPredicateViaNoOverflow(Pred, LHS, RHS);
};
switch (Pred) {

View File

@ -447,6 +447,64 @@ define void @func_20(i32* %length.ptr) {
ret void
}
define void @func_21(i32* %length.ptr) {
; CHECK-LABEL: @func_21(
; This checks that the backedge condition, (I + 1) < Length - 1 implies
; (I + 1) < Length
entry:
%length = load i32, i32* %length.ptr, !range !0
%lim = sub i32 %length, 1
%entry.cond = icmp sgt i32 %length, 1
br i1 %entry.cond, label %loop, label %leave
loop:
; CHECK: loop:
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %be ]
%iv.inc = add i32 %iv, 1
%range.check = icmp slt 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, %lim
br i1 %be.cond, label %loop, label %leave
leave:
ret void
}
define void @func_22(i32* %length.ptr) {
; CHECK-LABEL: @func_22(
; This checks that the backedge condition, (I + 1) < Length - 1 implies
; (I + 1) < Length
entry:
%length = load i32, i32* %length.ptr, !range !0
%lim = sub i32 %length, 1
%entry.cond = icmp sgt i32 %length, 1
br i1 %entry.cond, label %loop, label %leave
loop:
; CHECK: loop:
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %be ]
%iv.inc = add i32 %iv, 1
%range.check = icmp sle 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 sle i32 %iv.inc, %lim
br i1 %be.cond, label %loop, label %leave
leave:
ret void
}
define void @func_23(i32* %length.ptr) {
; CHECK-LABEL: @func_23(
entry:

View File

@ -0,0 +1,30 @@
; RUN: opt -S -indvars < %s | FileCheck %s
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.11.0"
declare void @use(i1)
define void @f(i32 %x) {
; CHECK-LABEL: @f(
entry:
%conv = sext i32 %x to i64
%sub = add i64 %conv, -1
%ec = icmp sgt i32 %x, 0
br i1 %ec, label %loop, label %leave
loop:
; CHECK: loop:
%iv = phi i64 [ 0, %entry ], [ %iv.inc, %loop ]
%iv.inc = add i64 %iv, 1
%cmp = icmp slt i64 %iv, %sub
call void @use(i1 %cmp)
; CHECK: call void @use(i1 %cmp)
; CHECK-NOT: call void @use(i1 true)
%be.cond = icmp slt i64 %iv.inc, %conv
br i1 %be.cond, label %loop, label %leave
leave:
ret void
}