From 224555f18cc4171b3029edbc13a9ebc1e47b78c2 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Thu, 5 Nov 2015 23:45:38 +0000 Subject: [PATCH] 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) 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 llvm-svn: 252236 --- include/llvm/Analysis/ScalarEvolution.h | 8 +++ lib/Analysis/ScalarEvolution.cpp | 59 ++++++++++++++++++- .../IndVarSimplify/eliminate-comparison.ll | 58 ++++++++++++++++++ test/Transforms/IndVarSimplify/pr25421.ll | 30 ++++++++++ 4 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 test/Transforms/IndVarSimplify/pr25421.ll diff --git a/include/llvm/Analysis/ScalarEvolution.h b/include/llvm/Analysis/ScalarEvolution.h index 65125a7da5e..c180ce37e39 100644 --- a/include/llvm/Analysis/ScalarEvolution.h +++ b/include/llvm/Analysis/ScalarEvolution.h @@ -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)" 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 4652e449f4b..c2db02fe85a 100644 --- a/lib/Analysis/ScalarEvolution.cpp +++ b/lib/Analysis/ScalarEvolution.cpp @@ -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) 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) == ExpectedFlags; + }; + + 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; + break; + + 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; + 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) { diff --git a/test/Transforms/IndVarSimplify/eliminate-comparison.ll b/test/Transforms/IndVarSimplify/eliminate-comparison.ll index 89f625111d4..612f01e3cad 100644 --- a/test/Transforms/IndVarSimplify/eliminate-comparison.ll +++ b/test/Transforms/IndVarSimplify/eliminate-comparison.ll @@ -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: diff --git a/test/Transforms/IndVarSimplify/pr25421.ll b/test/Transforms/IndVarSimplify/pr25421.ll new file mode 100644 index 00000000000..efb71f9c303 --- /dev/null +++ b/test/Transforms/IndVarSimplify/pr25421.ll @@ -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 +}