forked from OSchip/llvm-project
[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 llvm-svn: 362006
This commit is contained in:
parent
5feead5752
commit
5382803b04
|
@ -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<SaturatingInst>(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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue