diff options
author | Sanjoy Das <sanjoy@playingwithpointers.com> | 2015-10-22 19:57:29 +0000 |
---|---|---|
committer | Sanjoy Das <sanjoy@playingwithpointers.com> | 2015-10-22 19:57:29 +0000 |
commit | 1123148d40691a9ce08879fff878a02acd0f6822 (patch) | |
tree | 4c4e3e23406d6426468339e9fd908880b69c835b | |
parent | a060e602fd6afa836f17da5b7fc865651714d259 (diff) | |
download | bcm5719-llvm-1123148d40691a9ce08879fff878a02acd0f6822.tar.gz bcm5719-llvm-1123148d40691a9ce08879fff878a02acd0f6822.zip |
[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: 251050
-rw-r--r-- | llvm/include/llvm/Analysis/ScalarEvolution.h | 8 | ||||
-rw-r--r-- | llvm/lib/Analysis/ScalarEvolution.cpp | 59 | ||||
-rw-r--r-- | llvm/test/Transforms/IndVarSimplify/eliminate-comparison.ll | 59 |
3 files changed, 124 insertions, 2 deletions
diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h index d70f9d6fe42..0413b6849bd 100644 --- a/llvm/include/llvm/Analysis/ScalarEvolution.h +++ b/llvm/include/llvm/Analysis/ScalarEvolution.h @@ -576,6 +576,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, diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index c5ca839e474..d30e982c8d5 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -7162,6 +7162,60 @@ 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) != 0; + }; + + 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; + + 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; + } + + return false; +} + bool ScalarEvolution::isKnownPredicateViaSplitting(ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS) { @@ -7811,8 +7865,9 @@ ScalarEvolution::isImpliedCondOperandsHelper(ICmpInst::Predicate Pred, auto IsKnownPredicateFull = [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); + IsKnownPredicateViaMinOrMax(*this, Pred, LHS, RHS) || + IsKnownPredicateViaAddRecStart(*this, Pred, LHS, RHS) || + isKnownPredicateViaNoOverflow(Pred, LHS, RHS); }; switch (Pred) { diff --git a/llvm/test/Transforms/IndVarSimplify/eliminate-comparison.ll b/llvm/test/Transforms/IndVarSimplify/eliminate-comparison.ll index 177e0f74da6..563ea3a1b43 100644 --- a/llvm/test/Transforms/IndVarSimplify/eliminate-comparison.ll +++ b/llvm/test/Transforms/IndVarSimplify/eliminate-comparison.ll @@ -477,4 +477,63 @@ define void @func_21(i32* %length.ptr, i32 %init) { 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 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_23(i32* %length.ptr) { +; CHECK-LABEL: @func_23( + +; 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 +} + + !0 = !{i32 0, i32 2147483647} |