blob: 44aa7deb4acc5e51b7689a4cefdb0ca112e3e790 [file] [log] [blame]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -instcombine -S < %s | FileCheck %s
; Canonicalization of unsigned saturated subtraction idioms to
; usub.sat() intrinsics is tested here.
declare void @use(i64)
; (a > b) ? a - b : 0 -> usub.sat(a, b)
define i64 @max_sub_ugt(i64 %a, i64 %b) {
; CHECK-LABEL: @max_sub_ugt(
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
; CHECK-NEXT: ret i64 [[TMP1]]
;
%cmp = icmp ugt i64 %a, %b
%sub = sub i64 %a, %b
%sel = select i1 %cmp, i64 %sub ,i64 0
ret i64 %sel
}
; (a >= b) ? a - b : 0 -> usub.sat(a, b)
define i64 @max_sub_uge(i64 %a, i64 %b) {
; CHECK-LABEL: @max_sub_uge(
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
; CHECK-NEXT: ret i64 [[TMP1]]
;
%cmp = icmp uge i64 %a, %b
%sub = sub i64 %a, %b
%sel = select i1 %cmp, i64 %sub ,i64 0
ret i64 %sel
}
; Again, with vectors:
; (a > b) ? a - b : 0 -> usub.sat(a, b)
define <4 x i32> @max_sub_ugt_vec(<4 x i32> %a, <4 x i32> %b) {
; CHECK-LABEL: @max_sub_ugt_vec(
; CHECK-NEXT: [[TMP1:%.*]] = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]])
; CHECK-NEXT: ret <4 x i32> [[TMP1]]
;
%cmp = icmp ugt <4 x i32> %a, %b
%sub = sub <4 x i32> %a, %b
%sel = select <4 x i1> %cmp, <4 x i32> %sub, <4 x i32> zeroinitializer
ret <4 x i32> %sel
}
; Use extra ops to thwart icmp swapping canonicalization.
; (b < a) ? a - b : 0 -> usub.sat(a, b)
define i64 @max_sub_ult(i64 %a, i64 %b) {
; CHECK-LABEL: @max_sub_ult(
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
; CHECK-NEXT: [[EXTRASUB:%.*]] = sub i64 [[B]], [[A]]
; CHECK-NEXT: call void @use(i64 [[EXTRASUB]])
; CHECK-NEXT: ret i64 [[TMP1]]
;
%cmp = icmp ult i64 %b, %a
%sub = sub i64 %a, %b
%sel = select i1 %cmp, i64 %sub ,i64 0
%extrasub = sub i64 %b, %a
call void @use(i64 %extrasub)
ret i64 %sel
}
; (b > a) ? 0 : a - b -> usub.sat(a, b)
define i64 @max_sub_ugt_sel_swapped(i64 %a, i64 %b) {
; CHECK-LABEL: @max_sub_ugt_sel_swapped(
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
; CHECK-NEXT: [[EXTRASUB:%.*]] = sub i64 [[B]], [[A]]
; CHECK-NEXT: call void @use(i64 [[EXTRASUB]])
; CHECK-NEXT: ret i64 [[TMP1]]
;
%cmp = icmp ugt i64 %b, %a
%sub = sub i64 %a, %b
%sel = select i1 %cmp, i64 0 ,i64 %sub
%extrasub = sub i64 %b, %a
call void @use(i64 %extrasub)
ret i64 %sel
}
; (a < b) ? 0 : a - b -> usub.sat(a, b)
define i64 @max_sub_ult_sel_swapped(i64 %a, i64 %b) {
; CHECK-LABEL: @max_sub_ult_sel_swapped(
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
; CHECK-NEXT: ret i64 [[TMP1]]
;
%cmp = icmp ult i64 %a, %b
%sub = sub i64 %a, %b
%sel = select i1 %cmp, i64 0 ,i64 %sub
ret i64 %sel
}
; ((a > b) ? b - a : 0) -> -usub.sat(a, b)
define i64 @neg_max_sub_ugt(i64 %a, i64 %b) {
; CHECK-LABEL: @neg_max_sub_ugt(
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = sub i64 0, [[TMP1]]
; CHECK-NEXT: [[EXTRASUB:%.*]] = sub i64 [[A]], [[B]]
; CHECK-NEXT: call void @use(i64 [[EXTRASUB]])
; CHECK-NEXT: ret i64 [[TMP2]]
;
%cmp = icmp ugt i64 %a, %b
%sub = sub i64 %b, %a
%sel = select i1 %cmp, i64 %sub ,i64 0
%extrasub = sub i64 %a, %b
call void @use(i64 %extrasub)
ret i64 %sel
}
; ((b < a) ? b - a : 0) -> -usub.sat(a, b)
define i64 @neg_max_sub_ult(i64 %a, i64 %b) {
; CHECK-LABEL: @neg_max_sub_ult(
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = sub i64 0, [[TMP1]]
; CHECK-NEXT: ret i64 [[TMP2]]
;
%cmp = icmp ult i64 %b, %a
%sub = sub i64 %b, %a
%sel = select i1 %cmp, i64 %sub ,i64 0
ret i64 %sel
}
; ((b > a) ? 0 : b - a) -> -usub.sat(a, b)
define i64 @neg_max_sub_ugt_sel_swapped(i64 %a, i64 %b) {
; CHECK-LABEL: @neg_max_sub_ugt_sel_swapped(
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = sub i64 0, [[TMP1]]
; CHECK-NEXT: ret i64 [[TMP2]]
;
%cmp = icmp ugt i64 %b, %a
%sub = sub i64 %b, %a
%sel = select i1 %cmp, i64 0 ,i64 %sub
ret i64 %sel
}
; ((a < b) ? 0 : b - a) -> -usub.sat(a, b)
define i64 @neg_max_sub_ult_sel_swapped(i64 %a, i64 %b) {
; CHECK-LABEL: @neg_max_sub_ult_sel_swapped(
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = sub i64 0, [[TMP1]]
; CHECK-NEXT: [[EXTRASUB:%.*]] = sub i64 [[A]], [[B]]
; CHECK-NEXT: call void @use(i64 [[EXTRASUB]])
; CHECK-NEXT: ret i64 [[TMP2]]
;
%cmp = icmp ult i64 %a, %b
%sub = sub i64 %b, %a
%sel = select i1 %cmp, i64 0 ,i64 %sub
%extrasub = sub i64 %a, %b
call void @use(i64 %extrasub)
ret i64 %sel
}