From 47b5845e3b56a389239d9b0f4a7ccb8eea0ce52c Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Thu, 22 Oct 2015 19:57:29 +0000 Subject: [PATCH] [SCEV] Teach SCEV some axioms about non-wrapping arithmetic Summary: - A s< (A + C) if C > 0 - A s<= (A + C) if C >= 0 - (A + C) s< A if C < 0 - (A + C) 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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@251050 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Analysis/ScalarEvolution.h | 8 +++ lib/Analysis/ScalarEvolution.cpp | 59 ++++++++++++++++++- .../IndVarSimplify/eliminate-comparison.ll | 59 +++++++++++++++++++ 3 files changed, 124 insertions(+), 2 deletions(-) diff --git a/include/llvm/Analysis/ScalarEvolution.h b/include/llvm/Analysis/ScalarEvolution.h index d70f9d6fe42..0413b6849bd 100644 --- a/include/llvm/Analysis/ScalarEvolution.h +++ b/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)" 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/lib/Analysis/ScalarEvolution.cpp b/lib/Analysis/ScalarEvolution.cpp index c5ca839e474..d30e982c8d5 100644 --- a/lib/Analysis/ScalarEvolution.cpp +++ b/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) 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(ConstOp) || NonConstOp != X) + return false; + + OutY = cast(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) if C >= 0 + if (MatchBinaryAddToConst(RHS, LHS, C, SCEV::FlagNSW) && C.isNonNegative()) + return true; + + // (X + C) 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) if C > 0 + if (MatchBinaryAddToConst(RHS, LHS, C, SCEV::FlagNSW) && + C.isStrictlyPositive()) + return true; + + // (X + C) 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/test/Transforms/IndVarSimplify/eliminate-comparison.ll b/test/Transforms/IndVarSimplify/eliminate-comparison.ll index 177e0f74da6..563ea3a1b43 100644 --- a/test/Transforms/IndVarSimplify/eliminate-comparison.ll +++ b/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}