From 2a507f15555c34ea28b5c5d2c505034e09a9465f Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 29 May 2019 18:37:13 +0000 Subject: [PATCH] [InstCombine] Optimize always overflowing signed saturating add/sub Based on the overflow direction information added in D62463, we can now fold always overflowing signed saturating add/sub to signed min/max. Differential Revision: https://reviews.llvm.org/D62544 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@362006 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/InstCombine/InstCombineCalls.cpp | 20 ++++++++++++-------- test/Transforms/InstCombine/saturating-add-sub.ll | 20 ++++---------------- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp index 9c6297e4c17..39aae2f2e14 100644 --- a/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -13,6 +13,7 @@ #include "InstCombineInternal.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" @@ -2053,6 +2054,7 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { case Intrinsic::usub_sat: case Intrinsic::ssub_sat: { SaturatingInst *SI = cast(II); + Type *Ty = SI->getType(); Value *Arg0 = SI->getLHS(); Value *Arg1 = SI->getRHS(); @@ -2067,14 +2069,16 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { return BinaryOperator::CreateNSW(SI->getBinaryOp(), Arg0, Arg1); else return BinaryOperator::CreateNUW(SI->getBinaryOp(), Arg0, Arg1); - case OverflowResult::AlwaysOverflowsLow: - if (SI->isSigned()) break; // TODO: Support signed. - return replaceInstUsesWith(*SI, - ConstantInt::getNullValue(II->getType())); - case OverflowResult::AlwaysOverflowsHigh: - if (SI->isSigned()) break; // TODO: Support signed. - return replaceInstUsesWith(*SI, - ConstantInt::getAllOnesValue(II->getType())); + case OverflowResult::AlwaysOverflowsLow: { + unsigned BitWidth = Ty->getScalarSizeInBits(); + APInt Min = APSInt::getMinValue(BitWidth, !SI->isSigned()); + return replaceInstUsesWith(*SI, ConstantInt::get(Ty, Min)); + } + case OverflowResult::AlwaysOverflowsHigh: { + unsigned BitWidth = Ty->getScalarSizeInBits(); + APInt Max = APSInt::getMaxValue(BitWidth, !SI->isSigned()); + return replaceInstUsesWith(*SI, ConstantInt::get(Ty, Max)); + } } // ssub.sat(X, C) -> sadd.sat(X, -C) if C != MIN diff --git a/test/Transforms/InstCombine/saturating-add-sub.ll b/test/Transforms/InstCombine/saturating-add-sub.ll index 26374a501e7..fa0cc56447c 100644 --- a/test/Transforms/InstCombine/saturating-add-sub.ll +++ b/test/Transforms/InstCombine/saturating-add-sub.ll @@ -341,10 +341,7 @@ define <2 x i8> @test_vector_sadd_neg_neg(<2 x i8> %a) { define i8 @test_scalar_sadd_always_overflows_low(i8 %a) { ; CHECK-LABEL: @test_scalar_sadd_always_overflows_low( -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[A:%.*]], -120 -; CHECK-NEXT: [[MIN:%.*]] = select i1 [[CMP]], i8 [[A]], i8 -120 -; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[MIN]], i8 -10) -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 -128 ; %cmp = icmp slt i8 %a, -120 %min = select i1 %cmp, i8 %a, i8 -120 @@ -354,10 +351,7 @@ define i8 @test_scalar_sadd_always_overflows_low(i8 %a) { define i8 @test_scalar_sadd_always_overflows_high(i8 %a) { ; CHECK-LABEL: @test_scalar_sadd_always_overflows_high( -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[A:%.*]], 120 -; CHECK-NEXT: [[MAX:%.*]] = select i1 [[CMP]], i8 [[A]], i8 120 -; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[MAX]], i8 10) -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 127 ; %cmp = icmp sgt i8 %a, 120 %max = select i1 %cmp, i8 %a, i8 120 @@ -829,10 +823,7 @@ define <2 x i8> @test_vector_ssub_neg_nneg(<2 x i8> %a) { define i8 @test_scalar_ssub_always_overflows_low(i8 %a) { ; CHECK-LABEL: @test_scalar_ssub_always_overflows_low( -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[A:%.*]], 120 -; CHECK-NEXT: [[MAX:%.*]] = select i1 [[CMP]], i8 [[A]], i8 120 -; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.ssub.sat.i8(i8 -10, i8 [[MAX]]) -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 -128 ; %cmp = icmp sgt i8 %a, 120 %max = select i1 %cmp, i8 %a, i8 120 @@ -842,10 +833,7 @@ define i8 @test_scalar_ssub_always_overflows_low(i8 %a) { define i8 @test_scalar_ssub_always_overflows_high(i8 %a) { ; CHECK-LABEL: @test_scalar_ssub_always_overflows_high( -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[A:%.*]], -120 -; CHECK-NEXT: [[MIN:%.*]] = select i1 [[CMP]], i8 [[A]], i8 -120 -; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.ssub.sat.i8(i8 10, i8 [[MIN]]) -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 127 ; %cmp = icmp slt i8 %a, -120 %min = select i1 %cmp, i8 %a, i8 -120 -- 2.11.0