Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1920,6 +1920,23 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
if (match(IIOperand, m_SRem(m_Value(X), m_APInt(C))) && *C == 2)
return BinaryOperator::CreateAnd(X, ConstantInt::get(II->getType(), 1));

// abs (sub (sext X, sext Y)) -> zext (sub (smax (x, y) - smin(x, y)))
bool AbsSExtDiff = match(
IIOperand, m_OneUse(m_Sub(m_SExt(m_Value(X)), m_SExt(m_Value(Y)))));
// abs (sub (zext X, zext Y)) -> zext (sub (umax (x, y) - umin(x, y)))
bool AbsZExtDiff =
!AbsSExtDiff && match(IIOperand, m_OneUse(m_Sub(m_ZExt(m_Value(X)),
m_ZExt(m_Value(Y)))));
if ((AbsSExtDiff || AbsZExtDiff) && X->getType() == Y->getType()) {
bool IsSigned = AbsSExtDiff;
Value *Max = Builder.CreateBinaryIntrinsic(
IsSigned ? Intrinsic::smax : Intrinsic::umax, X, Y);
Value *Min = Builder.CreateBinaryIntrinsic(
IsSigned ? Intrinsic::smin : Intrinsic::umin, X, Y);
Value *Sub = Builder.CreateSub(Max, Min);
return CastInst::Create(Instruction::ZExt, Sub, II->getType());
}

break;
}
case Intrinsic::umin: {
Expand Down
104 changes: 104 additions & 0 deletions llvm/test/Transforms/InstCombine/abs-of-extend.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt < %s -passes=instcombine -S | FileCheck %s

; abs (sub (sext X, sext Y)) -> zext (sub (smax (x, y) - smin(x, y)))
; Proof: https://alive2.llvm.org/ce/z/D5E4bJ

; abs (sub (zext X, zext Y)) -> zext (sub (umax (x, y) - umin(x, y)))
; Proof: https://alive2.llvm.org/ce/z/rChrWe

define i32 @sext_i8(i8 %a, i8 %b) {
; CHECK-LABEL: define i32 @sext_i8(
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[A]], i8 [[B]])
; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smin.i8(i8 [[A]], i8 [[B]])
; CHECK-NEXT: [[TMP3:%.*]] = sub i8 [[TMP1]], [[TMP2]]
; CHECK-NEXT: [[ABS:%.*]] = zext i8 [[TMP3]] to i32
; CHECK-NEXT: ret i32 [[ABS]]
;
%ext.a = sext i8 %a to i32
%ext.b = sext i8 %b to i32
%sub = sub nsw i32 %ext.a, %ext.b
%abs = call i32 @llvm.abs(i32 %sub, i1 true)
ret i32 %abs
}

define i32 @zext_i8(i8 %a, i8 %b) {
; CHECK-LABEL: define i32 @zext_i8(
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[A]], i8 [[B]])
; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.umin.i8(i8 [[A]], i8 [[B]])
; CHECK-NEXT: [[TMP3:%.*]] = sub i8 [[TMP1]], [[TMP2]]
; CHECK-NEXT: [[ABS:%.*]] = zext i8 [[TMP3]] to i32
; CHECK-NEXT: ret i32 [[ABS]]
;
%ext.a = zext i8 %a to i32
%ext.b = zext i8 %b to i32
%sub = sub nsw i32 %ext.a, %ext.b
%abs = call i32 @llvm.abs(i32 %sub, i1 true)
ret i32 %abs
}

define i64 @zext_i32(i32 %a, i32 %b) {
; CHECK-LABEL: define i64 @zext_i32(
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[A]], i32 [[B]])
; CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.umin.i32(i32 [[A]], i32 [[B]])
; CHECK-NEXT: [[TMP3:%.*]] = sub i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT: [[ABS:%.*]] = zext i32 [[TMP3]] to i64
; CHECK-NEXT: ret i64 [[ABS]]
;
%ext.a = zext i32 %a to i64
%ext.b = zext i32 %b to i64
%sub = sub nsw i64 %ext.a, %ext.b
%abs = call i64 @llvm.abs(i64 %sub, i1 true)
ret i64 %abs
}

define <16 x i32> @vec_source(<16 x i8> %a, <16 x i8> %b) {
; CHECK-LABEL: define <16 x i32> @vec_source(
; CHECK-SAME: <16 x i8> [[A:%.*]], <16 x i8> [[B:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call <16 x i8> @llvm.smax.v16i8(<16 x i8> [[A]], <16 x i8> [[B]])
; CHECK-NEXT: [[TMP2:%.*]] = call <16 x i8> @llvm.smin.v16i8(<16 x i8> [[A]], <16 x i8> [[B]])
; CHECK-NEXT: [[TMP3:%.*]] = sub <16 x i8> [[TMP1]], [[TMP2]]
; CHECK-NEXT: [[ABS:%.*]] = zext <16 x i8> [[TMP3]] to <16 x i32>
; CHECK-NEXT: ret <16 x i32> [[ABS]]
;
%ext.a = sext <16 x i8> %a to <16 x i32>
%ext.b = sext <16 x i8> %b to <16 x i32>
%sub = sub nsw <16 x i32> %ext.a, %ext.b
%abs = call <16 x i32> @llvm.abs(<16 x i32> %sub, i1 true)
ret <16 x i32> %abs
}

define i32 @mixed_extend(i8 %a, i8 %b) {
; CHECK-LABEL: define i32 @mixed_extend(
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT: [[EXT_A:%.*]] = sext i8 [[A]] to i32
; CHECK-NEXT: [[EXT_B:%.*]] = zext i8 [[B]] to i32
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[EXT_A]], [[EXT_B]]
; CHECK-NEXT: [[ABS:%.*]] = call i32 @llvm.abs.i32(i32 [[SUB]], i1 true)
; CHECK-NEXT: ret i32 [[ABS]]
;
%ext.a = sext i8 %a to i32
%ext.b = zext i8 %b to i32
%sub = sub nsw i32 %ext.a, %ext.b
%abs = call i32 @llvm.abs(i32 %sub, i1 true)
ret i32 %abs
}

define i32 @mixed_source_types(i16 %a, i8 %b) {
; CHECK-LABEL: define i32 @mixed_source_types(
; CHECK-SAME: i16 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT: [[EXT_A:%.*]] = zext i16 [[A]] to i32
; CHECK-NEXT: [[EXT_B:%.*]] = zext i8 [[B]] to i32
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[EXT_A]], [[EXT_B]]
; CHECK-NEXT: [[ABS:%.*]] = call i32 @llvm.abs.i32(i32 [[SUB]], i1 true)
; CHECK-NEXT: ret i32 [[ABS]]
;
%ext.a = zext i16 %a to i32
%ext.b = zext i8 %b to i32
%sub = sub nsw i32 %ext.a, %ext.b
%abs = call i32 @llvm.abs(i32 %sub, i1 true)
ret i32 %abs
}
8 changes: 4 additions & 4 deletions llvm/test/Transforms/InstCombine/icmp.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4065,10 +4065,10 @@ define <2 x i1> @f4_vec(<2 x i64> %a, <2 x i64> %b) {
define i32 @f5(i8 %a, i8 %b) {
; CHECK-LABEL: define i32 @f5(
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[A]] to i32
; CHECK-NEXT: [[CONV3:%.*]] = zext i8 [[B]] to i32
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[CONV]], [[CONV3]]
; CHECK-NEXT: [[SUB7_SUB:%.*]] = call i32 @llvm.abs.i32(i32 [[SUB]], i1 true)
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[A]], i8 [[B]])
; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.umin.i8(i8 [[A]], i8 [[B]])
; CHECK-NEXT: [[TMP3:%.*]] = sub i8 [[TMP1]], [[TMP2]]
; CHECK-NEXT: [[SUB7_SUB:%.*]] = zext i8 [[TMP3]] to i32
; CHECK-NEXT: ret i32 [[SUB7_SUB]]
;
%conv = zext i8 %a to i32
Expand Down
Loading
Loading