1003 lines
32 KiB
LLVM
1003 lines
32 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
|
|
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
|
|
|
declare i5 @llvm.umin.i5(i5, i5)
|
|
declare <2 x i8> @llvm.smin.v2i8(<2 x i8>, <2 x i8>)
|
|
declare <2 x i8> @llvm.smax.v2i8(<2 x i8>, <2 x i8>)
|
|
declare <2 x i8> @llvm.umin.v2i8(<2 x i8>, <2 x i8>)
|
|
declare <2 x i8> @llvm.umax.v2i8(<2 x i8>, <2 x i8>)
|
|
|
|
declare i8 @llvm.smax.i8(i8, i8)
|
|
declare i8 @llvm.smin.i8(i8, i8)
|
|
declare i8 @llvm.umax.i8(i8, i8)
|
|
declare i8 @llvm.umin.i8(i8, i8)
|
|
|
|
define i32 @max_na_b_minux_na(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: define {{[^@]+}}@max_na_b_minux_na
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[NOT]], i32 [[B]])
|
|
; CHECK-NEXT: [[X:%.*]] = sub i32 0, [[TMP1]]
|
|
; CHECK-NEXT: ret i32 [[X]]
|
|
;
|
|
%not = xor i32 %A, -1
|
|
%l0 = icmp ult i32 %not, %B
|
|
%l1 = select i1 %l0, i32 %not, i32 %B
|
|
%x = sub i32 %l1, %not
|
|
ret i32 %x
|
|
}
|
|
|
|
define i32 @na_minus_max_na_b(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: define {{[^@]+}}@na_minus_max_na_b
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[NOT]], i32 [[B]])
|
|
; CHECK-NEXT: ret i32 [[TMP1]]
|
|
;
|
|
%not = xor i32 %A, -1
|
|
%l0 = icmp ult i32 %not, %B
|
|
%l1 = select i1 %l0, i32 %not, i32 %B
|
|
%x = sub i32 %not, %l1
|
|
ret i32 %x
|
|
}
|
|
|
|
define i5 @sub_umin(i5 %a, i5 %b) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_umin
|
|
; CHECK-SAME: (i5 [[A:%.*]], i5 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.usub.sat.i5(i5 [[A]], i5 [[B]])
|
|
; CHECK-NEXT: ret i5 [[TMP1]]
|
|
;
|
|
%umin = call i5 @llvm.umin.i5(i5 %a, i5 %b)
|
|
%r = sub i5 %a, %umin
|
|
ret i5 %r
|
|
}
|
|
|
|
define <2 x i8> @sub_umin_commute_vec(<2 x i8> %a, <2 x i8> %b) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_umin_commute_vec
|
|
; CHECK-SAME: (<2 x i8> [[A:%.*]], <2 x i8> [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[B]], <2 x i8> [[A]])
|
|
; CHECK-NEXT: ret <2 x i8> [[TMP1]]
|
|
;
|
|
%umin = call <2 x i8> @llvm.umin.v2i8(<2 x i8> %b, <2 x i8> %a)
|
|
%r = sub <2 x i8> %b, %umin
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
define i5 @sub_umin_uses(i5 %a, i5 %b, ptr %p) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_umin_uses
|
|
; CHECK-SAME: (i5 [[A:%.*]], i5 [[B:%.*]], ptr [[P:%.*]]) {
|
|
; CHECK-NEXT: [[UMIN:%.*]] = call i5 @llvm.umin.i5(i5 [[A]], i5 [[B]])
|
|
; CHECK-NEXT: store i5 [[UMIN]], ptr [[P]], align 1
|
|
; CHECK-NEXT: [[R:%.*]] = sub i5 [[A]], [[UMIN]]
|
|
; CHECK-NEXT: ret i5 [[R]]
|
|
;
|
|
%umin = call i5 @llvm.umin.i5(i5 %a, i5 %b)
|
|
store i5 %umin, ptr %p
|
|
%r = sub i5 %a, %umin
|
|
ret i5 %r
|
|
}
|
|
|
|
define i5 @sub_umin_no_common_op(i5 %a, i5 %b, i5 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_umin_no_common_op
|
|
; CHECK-SAME: (i5 [[A:%.*]], i5 [[B:%.*]], i5 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[UMIN:%.*]] = call i5 @llvm.umin.i5(i5 [[A]], i5 [[B]])
|
|
; CHECK-NEXT: [[R:%.*]] = sub i5 [[C]], [[UMIN]]
|
|
; CHECK-NEXT: ret i5 [[R]]
|
|
;
|
|
%umin = call i5 @llvm.umin.i5(i5 %a, i5 %b)
|
|
%r = sub i5 %c, %umin
|
|
ret i5 %r
|
|
}
|
|
|
|
define i32 @max_b_na_minus_na(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: define {{[^@]+}}@max_b_na_minus_na
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[NOT]], i32 [[B]])
|
|
; CHECK-NEXT: [[X:%.*]] = sub i32 0, [[TMP1]]
|
|
; CHECK-NEXT: ret i32 [[X]]
|
|
;
|
|
%not = xor i32 %A, -1
|
|
%l0 = icmp ugt i32 %not, %B
|
|
%l1 = select i1 %l0, i32 %B, i32 %not
|
|
%x = sub i32 %l1, %not
|
|
ret i32 %x
|
|
}
|
|
|
|
define i32 @na_minus_max_b_na(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: define {{[^@]+}}@na_minus_max_b_na
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[NOT]], i32 [[B]])
|
|
; CHECK-NEXT: ret i32 [[TMP1]]
|
|
;
|
|
%not = xor i32 %A, -1
|
|
%l0 = icmp ugt i32 %not, %B
|
|
%l1 = select i1 %l0, i32 %B, i32 %not
|
|
%x = sub i32 %not, %l1
|
|
ret i32 %x
|
|
}
|
|
|
|
|
|
define i32 @max_na_bi_minux_na(i32 %A, i32 %Bi) {
|
|
; CHECK-LABEL: define {{[^@]+}}@max_na_bi_minux_na
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[BI:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[BI]], i32 [[A]])
|
|
; CHECK-NEXT: [[X:%.*]] = sub i32 0, [[TMP1]]
|
|
; CHECK-NEXT: ret i32 [[X]]
|
|
;
|
|
%B = xor i32 %Bi, -1
|
|
%not = xor i32 %A, -1
|
|
%l0 = icmp ult i32 %not, %B
|
|
%l1 = select i1 %l0, i32 %not, i32 %B
|
|
%x = sub i32 %l1, %not
|
|
ret i32 %x
|
|
}
|
|
|
|
define i32 @na_minus_max_na_bi(i32 %A, i32 %Bi) {
|
|
; CHECK-LABEL: define {{[^@]+}}@na_minus_max_na_bi
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[BI:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[BI]], i32 [[A]])
|
|
; CHECK-NEXT: ret i32 [[TMP1]]
|
|
;
|
|
%B = xor i32 %Bi, -1
|
|
%not = xor i32 %A, -1
|
|
%l0 = icmp ult i32 %not, %B
|
|
%l1 = select i1 %l0, i32 %not, i32 %B
|
|
%x = sub i32 %not, %l1
|
|
ret i32 %x
|
|
}
|
|
|
|
define i32 @max_bi_na_minus_na(i32 %A, i32 %Bi) {
|
|
; CHECK-LABEL: define {{[^@]+}}@max_bi_na_minus_na
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[BI:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[BI]], i32 [[A]])
|
|
; CHECK-NEXT: [[X:%.*]] = sub i32 0, [[TMP1]]
|
|
; CHECK-NEXT: ret i32 [[X]]
|
|
;
|
|
%B = xor i32 %Bi, -1
|
|
%not = xor i32 %A, -1
|
|
%l0 = icmp ugt i32 %not, %B
|
|
%l1 = select i1 %l0, i32 %B, i32 %not
|
|
%x = sub i32 %l1, %not
|
|
ret i32 %x
|
|
}
|
|
|
|
define i32 @na_minus_max_bi_na(i32 %A, i32 %Bi) {
|
|
; CHECK-LABEL: define {{[^@]+}}@na_minus_max_bi_na
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[BI:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[BI]], i32 [[A]])
|
|
; CHECK-NEXT: ret i32 [[TMP1]]
|
|
;
|
|
%B = xor i32 %Bi, -1
|
|
%not = xor i32 %A, -1
|
|
%l0 = icmp ugt i32 %not, %B
|
|
%l1 = select i1 %l0, i32 %B, i32 %not
|
|
%x = sub i32 %not, %l1
|
|
ret i32 %x
|
|
}
|
|
|
|
|
|
define i32 @max_na_bi_minux_na_use(i32 %A, i32 %Bi) {
|
|
; CHECK-LABEL: define {{[^@]+}}@max_na_bi_minux_na_use
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[BI:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[A]], i32 -32)
|
|
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], -1
|
|
; CHECK-NEXT: [[X:%.*]] = sub i32 [[A]], [[TMP1]]
|
|
; CHECK-NEXT: call void @use32(i32 [[TMP2]])
|
|
; CHECK-NEXT: ret i32 [[X]]
|
|
;
|
|
%not = xor i32 %A, -1
|
|
%l0 = icmp ult i32 %not, 31
|
|
%l1 = select i1 %l0, i32 %not, i32 31
|
|
%x = sub i32 %l1, %not
|
|
call void @use32(i32 %l1)
|
|
ret i32 %x
|
|
}
|
|
|
|
define i32 @na_minus_max_na_bi_use(i32 %A, i32 %Bi) {
|
|
; CHECK-LABEL: define {{[^@]+}}@na_minus_max_na_bi_use
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[BI:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[A]], i32 -32)
|
|
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], -1
|
|
; CHECK-NEXT: [[X:%.*]] = sub i32 [[TMP1]], [[A]]
|
|
; CHECK-NEXT: call void @use32(i32 [[TMP2]])
|
|
; CHECK-NEXT: ret i32 [[X]]
|
|
;
|
|
%not = xor i32 %A, -1
|
|
%l0 = icmp ult i32 %not, 31
|
|
%l1 = select i1 %l0, i32 %not, i32 31
|
|
%x = sub i32 %not, %l1
|
|
call void @use32(i32 %l1)
|
|
ret i32 %x
|
|
}
|
|
|
|
define i32 @max_bi_na_minus_na_use(i32 %A, i32 %Bi) {
|
|
; CHECK-LABEL: define {{[^@]+}}@max_bi_na_minus_na_use
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[BI:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[BI]], i32 [[A]])
|
|
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], -1
|
|
; CHECK-NEXT: [[X:%.*]] = sub i32 [[A]], [[TMP1]]
|
|
; CHECK-NEXT: call void @use32(i32 [[TMP2]])
|
|
; CHECK-NEXT: ret i32 [[X]]
|
|
;
|
|
%not = xor i32 %A, -1
|
|
%B = xor i32 %Bi, -1
|
|
%l0 = icmp ult i32 %B, %not
|
|
%l1 = select i1 %l0, i32 %B, i32 %not
|
|
%x = sub i32 %l1, %not
|
|
call void @use32(i32 %l1)
|
|
ret i32 %x
|
|
}
|
|
|
|
define i32 @na_minus_max_bi_na_use(i32 %A, i32 %Bi) {
|
|
; CHECK-LABEL: define {{[^@]+}}@na_minus_max_bi_na_use
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[BI:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[BI]], i32 [[A]])
|
|
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], -1
|
|
; CHECK-NEXT: [[X:%.*]] = sub i32 [[TMP1]], [[A]]
|
|
; CHECK-NEXT: call void @use32(i32 [[TMP2]])
|
|
; CHECK-NEXT: ret i32 [[X]]
|
|
;
|
|
%not = xor i32 %A, -1
|
|
%B = xor i32 %Bi, -1
|
|
%l0 = icmp ult i32 %B, %not
|
|
%l1 = select i1 %l0, i32 %B, i32 %not
|
|
%x = sub i32 %not, %l1
|
|
call void @use32(i32 %l1)
|
|
ret i32 %x
|
|
}
|
|
|
|
|
|
define i32 @max_na_bi_minux_na_use2(i32 %A, i32 %Bi) {
|
|
; CHECK-LABEL: define {{[^@]+}}@max_na_bi_minux_na_use2
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[BI:%.*]]) {
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[NOT]], i32 31)
|
|
; CHECK-NEXT: [[X:%.*]] = sub i32 [[TMP1]], [[NOT]]
|
|
; CHECK-NEXT: call void @use32(i32 [[TMP1]])
|
|
; CHECK-NEXT: call void @use32(i32 [[NOT]])
|
|
; CHECK-NEXT: ret i32 [[X]]
|
|
;
|
|
%not = xor i32 %A, -1
|
|
%l0 = icmp ult i32 %not, 31
|
|
%l1 = select i1 %l0, i32 %not, i32 31
|
|
%x = sub i32 %l1, %not
|
|
call void @use32(i32 %l1)
|
|
call void @use32(i32 %not)
|
|
ret i32 %x
|
|
}
|
|
|
|
define i32 @na_minus_max_na_bi_use2(i32 %A, i32 %Bi) {
|
|
; CHECK-LABEL: define {{[^@]+}}@na_minus_max_na_bi_use2
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[BI:%.*]]) {
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[NOT]], i32 31)
|
|
; CHECK-NEXT: [[X:%.*]] = sub i32 [[NOT]], [[TMP1]]
|
|
; CHECK-NEXT: call void @use32(i32 [[TMP1]])
|
|
; CHECK-NEXT: call void @use32(i32 [[NOT]])
|
|
; CHECK-NEXT: ret i32 [[X]]
|
|
;
|
|
%not = xor i32 %A, -1
|
|
%l0 = icmp ult i32 %not, 31
|
|
%l1 = select i1 %l0, i32 %not, i32 31
|
|
%x = sub i32 %not, %l1
|
|
call void @use32(i32 %l1)
|
|
call void @use32(i32 %not)
|
|
ret i32 %x
|
|
}
|
|
|
|
define i32 @max_bi_na_minus_na_use2(i32 %A, i32 %Bi) {
|
|
; CHECK-LABEL: define {{[^@]+}}@max_bi_na_minus_na_use2
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[BI:%.*]]) {
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[BI]], i32 [[A]])
|
|
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], -1
|
|
; CHECK-NEXT: [[X:%.*]] = sub i32 [[A]], [[TMP1]]
|
|
; CHECK-NEXT: call void @use32(i32 [[TMP2]])
|
|
; CHECK-NEXT: call void @use32(i32 [[NOT]])
|
|
; CHECK-NEXT: ret i32 [[X]]
|
|
;
|
|
%not = xor i32 %A, -1
|
|
%B = xor i32 %Bi, -1
|
|
%l0 = icmp ult i32 %B, %not
|
|
%l1 = select i1 %l0, i32 %B, i32 %not
|
|
%x = sub i32 %l1, %not
|
|
call void @use32(i32 %l1)
|
|
call void @use32(i32 %not)
|
|
ret i32 %x
|
|
}
|
|
|
|
define i32 @na_minus_max_bi_na_use2(i32 %A, i32 %Bi) {
|
|
; CHECK-LABEL: define {{[^@]+}}@na_minus_max_bi_na_use2
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[BI:%.*]]) {
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[BI]], i32 [[A]])
|
|
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], -1
|
|
; CHECK-NEXT: [[X:%.*]] = sub i32 [[TMP1]], [[A]]
|
|
; CHECK-NEXT: call void @use32(i32 [[TMP2]])
|
|
; CHECK-NEXT: call void @use32(i32 [[NOT]])
|
|
; CHECK-NEXT: ret i32 [[X]]
|
|
;
|
|
%not = xor i32 %A, -1
|
|
%B = xor i32 %Bi, -1
|
|
%l0 = icmp ult i32 %B, %not
|
|
%l1 = select i1 %l0, i32 %B, i32 %not
|
|
%x = sub i32 %not, %l1
|
|
call void @use32(i32 %l1)
|
|
call void @use32(i32 %not)
|
|
ret i32 %x
|
|
}
|
|
|
|
define i8 @umin_not_sub(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umin_not_sub
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: [[TMP2:%.*]] = xor i8 [[TMP1]], -1
|
|
; CHECK-NEXT: [[SUBX:%.*]] = sub i8 [[TMP1]], [[X]]
|
|
; CHECK-NEXT: [[SUBY:%.*]] = sub i8 [[TMP1]], [[Y]]
|
|
; CHECK-NEXT: call void @use8(i8 [[SUBX]])
|
|
; CHECK-NEXT: call void @use8(i8 [[SUBY]])
|
|
; CHECK-NEXT: ret i8 [[TMP2]]
|
|
;
|
|
%nx = xor i8 %x, -1
|
|
%ny = xor i8 %y, -1
|
|
%cmpxy = icmp ult i8 %nx, %ny
|
|
%minxy = select i1 %cmpxy, i8 %nx, i8 %ny
|
|
%subx = sub i8 %nx, %minxy
|
|
%suby = sub i8 %ny, %minxy
|
|
call void @use8(i8 %subx)
|
|
call void @use8(i8 %suby)
|
|
ret i8 %minxy
|
|
}
|
|
|
|
define i8 @umin_not_sub_rev(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umin_not_sub_rev
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: [[TMP2:%.*]] = xor i8 [[TMP1]], -1
|
|
; CHECK-NEXT: [[SUBX:%.*]] = sub i8 [[X]], [[TMP1]]
|
|
; CHECK-NEXT: [[SUBY:%.*]] = sub i8 [[Y]], [[TMP1]]
|
|
; CHECK-NEXT: call void @use8(i8 [[SUBX]])
|
|
; CHECK-NEXT: call void @use8(i8 [[SUBY]])
|
|
; CHECK-NEXT: ret i8 [[TMP2]]
|
|
;
|
|
%nx = xor i8 %x, -1
|
|
%ny = xor i8 %y, -1
|
|
%cmpxy = icmp ult i8 %nx, %ny
|
|
%minxy = select i1 %cmpxy, i8 %nx, i8 %ny
|
|
%subx = sub i8 %minxy, %nx
|
|
%suby = sub i8 %minxy, %ny
|
|
call void @use8(i8 %subx)
|
|
call void @use8(i8 %suby)
|
|
ret i8 %minxy
|
|
}
|
|
|
|
define void @umin3_not_all_ops_extra_uses_invert_subs(i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umin3_not_all_ops_extra_uses_invert_subs
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Z]])
|
|
; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.umax.i8(i8 [[Y]], i8 [[TMP1]])
|
|
; CHECK-NEXT: [[TMP3:%.*]] = xor i8 [[TMP2]], -1
|
|
; CHECK-NEXT: [[XMIN:%.*]] = sub i8 [[TMP2]], [[X]]
|
|
; CHECK-NEXT: [[YMIN:%.*]] = sub i8 [[TMP2]], [[Y]]
|
|
; CHECK-NEXT: [[ZMIN:%.*]] = sub i8 [[TMP2]], [[Z]]
|
|
; CHECK-NEXT: call void @use8(i8 [[TMP3]])
|
|
; CHECK-NEXT: call void @use8(i8 [[XMIN]])
|
|
; CHECK-NEXT: call void @use8(i8 [[YMIN]])
|
|
; CHECK-NEXT: call void @use8(i8 [[ZMIN]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%xn = xor i8 %x, -1
|
|
%yn = xor i8 %y, -1
|
|
%zn = xor i8 %z, -1
|
|
%cmpxz = icmp ult i8 %xn, %zn
|
|
%minxz = select i1 %cmpxz, i8 %xn, i8 %zn
|
|
%cmpxyz = icmp ult i8 %minxz, %yn
|
|
%minxyz = select i1 %cmpxyz, i8 %minxz, i8 %yn
|
|
%xmin = sub i8 %xn, %minxyz
|
|
%ymin = sub i8 %yn, %minxyz
|
|
%zmin = sub i8 %zn, %minxyz
|
|
call void @use8(i8 %minxyz)
|
|
call void @use8(i8 %xmin)
|
|
call void @use8(i8 %ymin)
|
|
call void @use8(i8 %zmin)
|
|
ret void
|
|
}
|
|
|
|
; Handle this pattern with extra uses because it shows up in benchmarks.
|
|
; ~X - Min/Max(~X, Y) -> ~Min/Max(X, ~Y) - X
|
|
; ~X - Min/Max(Y, ~X) -> ~Min/Max(X, ~Y) - X
|
|
; Min/Max(~X, Y) - ~X -> X - ~Min/Max(X, ~Y)
|
|
; Min/Max(Y, ~X) - ~X -> X - ~Min/Max(X, ~Y)
|
|
|
|
define i8 @umin_not_sub_intrinsic_commute0(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umin_not_sub_intrinsic_commute0
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y]], -1
|
|
; CHECK-NEXT: call void @use8(i8 [[NY]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: [[M:%.*]] = xor i8 [[TMP1]], -1
|
|
; CHECK-NEXT: call void @use8(i8 [[M]])
|
|
; CHECK-NEXT: [[SUBX:%.*]] = sub i8 [[TMP1]], [[X]]
|
|
; CHECK-NEXT: ret i8 [[SUBX]]
|
|
;
|
|
%nx = xor i8 %x, -1
|
|
%ny = xor i8 %y, -1
|
|
call void @use8(i8 %ny)
|
|
%m = call i8 @llvm.umin.i8(i8 %nx, i8 %ny)
|
|
call void @use8(i8 %m)
|
|
%subx = sub i8 %nx, %m
|
|
ret i8 %subx
|
|
}
|
|
|
|
define i8 @umax_not_sub_intrinsic_commute1(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umax_not_sub_intrinsic_commute1
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y]], -1
|
|
; CHECK-NEXT: call void @use8(i8 [[NY]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: [[M:%.*]] = xor i8 [[TMP1]], -1
|
|
; CHECK-NEXT: call void @use8(i8 [[M]])
|
|
; CHECK-NEXT: [[SUBX:%.*]] = sub i8 [[TMP1]], [[X]]
|
|
; CHECK-NEXT: ret i8 [[SUBX]]
|
|
;
|
|
%nx = xor i8 %x, -1
|
|
%ny = xor i8 %y, -1
|
|
call void @use8(i8 %ny)
|
|
%m = call i8 @llvm.umax.i8(i8 %ny, i8 %nx)
|
|
call void @use8(i8 %m)
|
|
%subx = sub i8 %nx, %m
|
|
ret i8 %subx
|
|
}
|
|
|
|
define i8 @smin_not_sub_intrinsic_commute2(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@smin_not_sub_intrinsic_commute2
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y]], -1
|
|
; CHECK-NEXT: call void @use8(i8 [[NY]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: [[M:%.*]] = xor i8 [[TMP1]], -1
|
|
; CHECK-NEXT: call void @use8(i8 [[M]])
|
|
; CHECK-NEXT: [[SUBX:%.*]] = sub i8 [[X]], [[TMP1]]
|
|
; CHECK-NEXT: ret i8 [[SUBX]]
|
|
;
|
|
%nx = xor i8 %x, -1
|
|
%ny = xor i8 %y, -1
|
|
call void @use8(i8 %ny)
|
|
%m = call i8 @llvm.smin.i8(i8 %nx, i8 %ny)
|
|
call void @use8(i8 %m)
|
|
%subx = sub i8 %m, %nx
|
|
ret i8 %subx
|
|
}
|
|
|
|
define i8 @smax_not_sub_intrinsic_commute3(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@smax_not_sub_intrinsic_commute3
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y]], -1
|
|
; CHECK-NEXT: call void @use8(i8 [[NY]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: [[M:%.*]] = xor i8 [[TMP1]], -1
|
|
; CHECK-NEXT: call void @use8(i8 [[M]])
|
|
; CHECK-NEXT: [[SUBX:%.*]] = sub i8 [[X]], [[TMP1]]
|
|
; CHECK-NEXT: ret i8 [[SUBX]]
|
|
;
|
|
%nx = xor i8 %x, -1
|
|
%ny = xor i8 %y, -1
|
|
call void @use8(i8 %ny)
|
|
%m = call i8 @llvm.smax.i8(i8 %ny, i8 %nx)
|
|
call void @use8(i8 %m)
|
|
%subx = sub i8 %m, %nx
|
|
ret i8 %subx
|
|
}
|
|
|
|
; negative test - don't increase instruction count
|
|
|
|
define i8 @umin_not_sub_intrinsic_uses(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umin_not_sub_intrinsic_uses
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[NX:%.*]] = xor i8 [[X]], -1
|
|
; CHECK-NEXT: call void @use8(i8 [[NX]])
|
|
; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y]], -1
|
|
; CHECK-NEXT: call void @use8(i8 [[NY]])
|
|
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[NX]], i8 [[NY]])
|
|
; CHECK-NEXT: call void @use8(i8 [[M]])
|
|
; CHECK-NEXT: [[SUBX:%.*]] = sub i8 [[NX]], [[M]]
|
|
; CHECK-NEXT: ret i8 [[SUBX]]
|
|
;
|
|
%nx = xor i8 %x, -1
|
|
call void @use8(i8 %nx)
|
|
%ny = xor i8 %y, -1
|
|
call void @use8(i8 %ny)
|
|
%m = call i8 @llvm.umin.i8(i8 %nx, i8 %ny)
|
|
call void @use8(i8 %m)
|
|
%subx = sub i8 %nx, %m
|
|
ret i8 %subx
|
|
}
|
|
|
|
define i8 @umax_sub_op0(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umax_sub_op0
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: ret i8 [[TMP1]]
|
|
;
|
|
%u = call i8 @llvm.umax.i8(i8 %y, i8 %x)
|
|
%r = sub i8 %u, %y
|
|
ret i8 %r
|
|
}
|
|
|
|
define <2 x i8> @umax_sub_op0_vec_commute(<2 x i8> %x, <2 x i8> %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umax_sub_op0_vec_commute
|
|
; CHECK-SAME: (<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[X]], <2 x i8> [[Y]])
|
|
; CHECK-NEXT: ret <2 x i8> [[TMP1]]
|
|
;
|
|
%u = call <2 x i8> @llvm.umax.v2i8(<2 x i8> %x, <2 x i8> %y)
|
|
%r = sub <2 x i8> %u, %y
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
define i8 @umax_sub_op0_use(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umax_sub_op0_use
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[U:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: call void @use8(i8 [[U]])
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 [[U]], [[Y]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%u = call i8 @llvm.umax.i8(i8 %x, i8 %y)
|
|
call void @use8(i8 %u)
|
|
%r = sub i8 %u, %y
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @umax_sub_op1(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umax_sub_op1
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 0, [[TMP1]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%u = call i8 @llvm.umax.i8(i8 %x, i8 %y)
|
|
%r = sub i8 %y, %u
|
|
ret i8 %r
|
|
}
|
|
|
|
define <2 x i8> @umax_sub_op1_vec_commute(<2 x i8> %x, <2 x i8> %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umax_sub_op1_vec_commute
|
|
; CHECK-SAME: (<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[X]], <2 x i8> [[Y]])
|
|
; CHECK-NEXT: [[R:%.*]] = sub <2 x i8> zeroinitializer, [[TMP1]]
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%u = call <2 x i8> @llvm.umax.v2i8(<2 x i8> %y, <2 x i8> %x)
|
|
%r = sub <2 x i8> %y, %u
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
define i8 @umax_sub_op1_use(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umax_sub_op1_use
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[U:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: call void @use8(i8 [[U]])
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 [[Y]], [[U]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%u = call i8 @llvm.umax.i8(i8 %x, i8 %y)
|
|
call void @use8(i8 %u)
|
|
%r = sub i8 %y, %u
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @umin_sub_op1(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umin_sub_op1
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[Y]], i8 [[X]])
|
|
; CHECK-NEXT: ret i8 [[TMP1]]
|
|
;
|
|
%u = call i8 @llvm.umin.i8(i8 %y, i8 %x)
|
|
%r = sub i8 %y, %u
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @umin_sub_op1_commute(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umin_sub_op1_commute
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[Y]], i8 [[X]])
|
|
; CHECK-NEXT: ret i8 [[TMP1]]
|
|
;
|
|
%u = call i8 @llvm.umin.i8(i8 %x, i8 %y)
|
|
%r = sub i8 %y, %u
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @umin_sub_op0(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umin_sub_op0
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[Y]], i8 [[X]])
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 0, [[TMP1]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%u = call i8 @llvm.umin.i8(i8 %y, i8 %x)
|
|
%r = sub i8 %u, %y
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @umin_sub_op0_commute(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umin_sub_op0_commute
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[Y]], i8 [[X]])
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 0, [[TMP1]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%u = call i8 @llvm.umin.i8(i8 %x, i8 %y)
|
|
%r = sub i8 %u, %y
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @umin_sub_op1_use(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umin_sub_op1_use
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[U:%.*]] = call i8 @llvm.umin.i8(i8 [[Y]], i8 [[X]])
|
|
; CHECK-NEXT: call void @use8(i8 [[U]])
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 [[Y]], [[U]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%u = call i8 @llvm.umin.i8(i8 %y, i8 %x)
|
|
call void @use8(i8 %u)
|
|
%r = sub i8 %y, %u
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @umin_sub_op0_use(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@umin_sub_op0_use
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[U:%.*]] = call i8 @llvm.umin.i8(i8 [[Y]], i8 [[X]])
|
|
; CHECK-NEXT: call void @use8(i8 [[U]])
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 [[U]], [[Y]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%u = call i8 @llvm.umin.i8(i8 %y, i8 %x)
|
|
call void @use8(i8 %u)
|
|
%r = sub i8 %u, %y
|
|
ret i8 %r
|
|
}
|
|
|
|
;
|
|
; sub(add(X,Y), s/umin(X,Y)) --> s/umax(X,Y)
|
|
; sub(add(X,Y), s/umax(X,Y)) --> s/umin(X,Y)
|
|
;
|
|
|
|
define i8 @diff_add_smin(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@diff_add_smin
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%a = add i8 %x, %y
|
|
%m = call i8 @llvm.smin.i8(i8 %x, i8 %y)
|
|
%s = sub i8 %a, %m
|
|
ret i8 %s
|
|
}
|
|
|
|
define i8 @diff_add_smax(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@diff_add_smax
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.smin.i8(i8 [[Y]], i8 [[X]])
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%a = add i8 %x, %y
|
|
%m = call i8 @llvm.smax.i8(i8 %y, i8 %x)
|
|
%s = sub i8 %a, %m
|
|
ret i8 %s
|
|
}
|
|
|
|
define i8 @diff_add_umin(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@diff_add_umin
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%a = add i8 %x, %y
|
|
%m = call i8 @llvm.umin.i8(i8 %x, i8 %y)
|
|
%s = sub i8 %a, %m
|
|
ret i8 %s
|
|
}
|
|
|
|
define i8 @diff_add_umax(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@diff_add_umax
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.umin.i8(i8 [[Y]], i8 [[X]])
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%a = add i8 %x, %y
|
|
%m = call i8 @llvm.umax.i8(i8 %y, i8 %x)
|
|
%s = sub i8 %a, %m
|
|
ret i8 %s
|
|
}
|
|
|
|
define i8 @diff_add_smin_use(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@diff_add_smin_use
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: call void @use8(i8 [[M]])
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%a = add i8 %x, %y
|
|
%m = call i8 @llvm.smin.i8(i8 %x, i8 %y)
|
|
%s = sub i8 %a, %m
|
|
call void @use8(i8 %m)
|
|
ret i8 %s
|
|
}
|
|
|
|
define i8 @diff_add_use_smax(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@diff_add_use_smax
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = add i8 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.smin.i8(i8 [[Y]], i8 [[X]])
|
|
; CHECK-NEXT: call void @use8(i8 [[A]])
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%a = add i8 %x, %y
|
|
%m = call i8 @llvm.smax.i8(i8 %y, i8 %x)
|
|
%s = sub i8 %a, %m
|
|
call void @use8(i8 %a)
|
|
ret i8 %s
|
|
}
|
|
|
|
define i8 @diff_add_use_umin_use(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@diff_add_use_umin_use
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = add i8 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: [[S:%.*]] = sub i8 [[A]], [[M]]
|
|
; CHECK-NEXT: call void @use8(i8 [[A]])
|
|
; CHECK-NEXT: call void @use8(i8 [[M]])
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%a = add i8 %x, %y
|
|
%m = call i8 @llvm.umin.i8(i8 %x, i8 %y)
|
|
%s = sub i8 %a, %m
|
|
call void @use8(i8 %a)
|
|
call void @use8(i8 %m)
|
|
ret i8 %s
|
|
}
|
|
|
|
; sub(add(X,Y),umin(Y,Z)) --> add(X,usubsat(Y,Z))
|
|
|
|
define i8 @sub_add_umin(i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_add_umin
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[Y]], i8 [[Z]])
|
|
; CHECK-NEXT: [[S:%.*]] = add i8 [[TMP1]], [[X]]
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%a = add i8 %x, %y
|
|
%m = call i8 @llvm.umin.i8(i8 %y, i8 %z)
|
|
%s = sub i8 %a, %m
|
|
ret i8 %s
|
|
}
|
|
|
|
define i8 @sub_add_umin_commute_umin(i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_add_umin_commute_umin
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[Y]], i8 [[Z]])
|
|
; CHECK-NEXT: [[S:%.*]] = add i8 [[TMP1]], [[X]]
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%a = add i8 %x, %y
|
|
%m = call i8 @llvm.umin.i8(i8 %z, i8 %y)
|
|
%s = sub i8 %a, %m
|
|
ret i8 %s
|
|
}
|
|
|
|
define i8 @sub_add_umin_commute_add(i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_add_umin_commute_add
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[Y]], i8 [[Z]])
|
|
; CHECK-NEXT: [[S:%.*]] = add i8 [[TMP1]], [[X]]
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%a = add i8 %y, %x
|
|
%m = call i8 @llvm.umin.i8(i8 %y, i8 %z)
|
|
%s = sub i8 %a, %m
|
|
ret i8 %s
|
|
}
|
|
|
|
define i8 @sub_add_umin_commute_add_umin(i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_add_umin_commute_add_umin
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[Y]], i8 [[Z]])
|
|
; CHECK-NEXT: [[S:%.*]] = add i8 [[TMP1]], [[X]]
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%a = add i8 %y, %x
|
|
%m = call i8 @llvm.umin.i8(i8 %z, i8 %y)
|
|
%s = sub i8 %a, %m
|
|
ret i8 %s
|
|
}
|
|
|
|
define <2 x i8> @sub_add_umin_vec(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_add_umin_vec
|
|
; CHECK-SAME: (<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]], <2 x i8> [[Z:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[Y]], <2 x i8> [[Z]])
|
|
; CHECK-NEXT: [[S:%.*]] = add <2 x i8> [[TMP1]], [[X]]
|
|
; CHECK-NEXT: ret <2 x i8> [[S]]
|
|
;
|
|
%a = add <2 x i8> %x, %y
|
|
%m = call <2 x i8> @llvm.umin.v2i8(<2 x i8> %y, <2 x i8> %z)
|
|
%s = sub <2 x i8> %a, %m
|
|
ret <2 x i8> %s
|
|
}
|
|
|
|
; negative test
|
|
|
|
define i8 @sub_add_umin_mismatch(i8 %x, i8 %y, i8 %z, i8 %t) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_add_umin_mismatch
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]], i8 [[T:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = add i8 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[T]], i8 [[Z]])
|
|
; CHECK-NEXT: [[S:%.*]] = sub i8 [[A]], [[M]]
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%a = add i8 %x, %y
|
|
%m = call i8 @llvm.umin.i8(i8 %t, i8 %z)
|
|
%s = sub i8 %a, %m
|
|
ret i8 %s
|
|
}
|
|
|
|
define i8 @sub_add_umin_use_a(i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_add_umin_use_a
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = add i8 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[Y]], i8 [[Z]])
|
|
; CHECK-NEXT: [[S:%.*]] = sub i8 [[A]], [[M]]
|
|
; CHECK-NEXT: call void @use8(i8 [[A]])
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%a = add i8 %x, %y
|
|
%m = call i8 @llvm.umin.i8(i8 %y, i8 %z)
|
|
%s = sub i8 %a, %m
|
|
call void @use8(i8 %a)
|
|
ret i8 %s
|
|
}
|
|
|
|
define i8 @sub_add_umin_use_m(i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_add_umin_use_m
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = add i8 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[Y]], i8 [[Z]])
|
|
; CHECK-NEXT: [[S:%.*]] = sub i8 [[A]], [[M]]
|
|
; CHECK-NEXT: call void @use8(i8 [[M]])
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%a = add i8 %x, %y
|
|
%m = call i8 @llvm.umin.i8(i8 %y, i8 %z)
|
|
%s = sub i8 %a, %m
|
|
call void @use8(i8 %m)
|
|
ret i8 %s
|
|
}
|
|
|
|
define <2 x i8> @sub_smax0_sub_nsw(<2 x i8> %x, <2 x i8> %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_smax0_sub_nsw
|
|
; CHECK-SAME: (<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[R:%.*]] = call <2 x i8> @llvm.smin.v2i8(<2 x i8> [[X]], <2 x i8> [[Y]])
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%sub = sub nsw <2 x i8> %x, %y
|
|
%m = call <2 x i8> @llvm.smax.v2i8(<2 x i8> %sub, <2 x i8> <i8 0, i8 poison>)
|
|
%r = sub <2 x i8> %x, %m
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
define i8 @sub_smax0_sub_nsw_use(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_smax0_sub_nsw_use
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i8 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[SUB]], i8 0)
|
|
; CHECK-NEXT: call void @use8(i8 [[M]])
|
|
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%sub = sub nsw i8 %x, %y
|
|
%m = call i8 @llvm.smax.i8(i8 %sub, i8 0)
|
|
call void @use8(i8 %m)
|
|
%r = sub i8 %x, %m
|
|
ret i8 %r
|
|
}
|
|
|
|
; negative test - must have nsw
|
|
|
|
define i8 @sub_smax0_sub(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_smax0_sub
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[SUB]], i8 0)
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 [[X]], [[M]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%sub = sub i8 %x, %y
|
|
%m = call i8 @llvm.smax.i8(i8 %sub, i8 0)
|
|
%r = sub i8 %x, %m
|
|
ret i8 %r
|
|
}
|
|
|
|
; negative test - wrong op
|
|
|
|
define i8 @sub_smax0_sub_commute(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_smax0_sub_commute
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i8 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[SUB]], i8 0)
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 [[M]], [[X]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%sub = sub nsw i8 %x, %y
|
|
%m = call i8 @llvm.smax.i8(i8 %sub, i8 0)
|
|
%r = sub i8 %m, %x
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @sub_smin0_sub_nsw_use(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_smin0_sub_nsw_use
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i8 [[X]], [[Y]]
|
|
; CHECK-NEXT: call void @use8(i8 [[SUB]])
|
|
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 [[Y]])
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%sub = sub nsw i8 %x, %y
|
|
call void @use8(i8 %sub)
|
|
%m = call i8 @llvm.smin.i8(i8 %sub, i8 0)
|
|
%r = sub i8 %x, %m
|
|
ret i8 %r
|
|
}
|
|
|
|
define <2 x i8> @sub_smin0_sub_nsw(<2 x i8> %x, <2 x i8> %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_smin0_sub_nsw
|
|
; CHECK-SAME: (<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[R:%.*]] = call <2 x i8> @llvm.smax.v2i8(<2 x i8> [[X]], <2 x i8> [[Y]])
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%sub = sub nsw <2 x i8> %x, %y
|
|
%m = call <2 x i8> @llvm.smin.v2i8(<2 x i8> %sub, <2 x i8> zeroinitializer)
|
|
%r = sub <2 x i8> %x, %m
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
; negative test - must have nsw
|
|
|
|
define i8 @sub_smin0_sub(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_smin0_sub
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[SUB]], i8 0)
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 [[X]], [[M]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%sub = sub i8 %x, %y
|
|
%m = call i8 @llvm.smin.i8(i8 %sub, i8 0)
|
|
%r = sub i8 %x, %m
|
|
ret i8 %r
|
|
}
|
|
|
|
; negative test - wrong op
|
|
|
|
define i8 @sub_smin0_sub_nsw_commute(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sub_smin0_sub_nsw_commute
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i8 [[Y]], [[X]]
|
|
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[SUB]], i8 0)
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 [[X]], [[M]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%sub = sub nsw i8 %y, %x
|
|
%m = call i8 @llvm.smin.i8(i8 %sub, i8 0)
|
|
%r = sub i8 %x, %m
|
|
ret i8 %r
|
|
}
|
|
|
|
declare void @use8(i8)
|
|
declare void @use32(i32 %u)
|