2018-02-03 01:43:16 +08:00
|
|
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
|
|
; RUN: opt -instcombine -S < %s | FileCheck %s
|
|
|
|
|
|
|
|
; Transforms for unsigned saturated subtraction idioms are tested here.
|
|
|
|
; In all cases, we want to form a canonical min/max op (the compare and
|
|
|
|
; select operands are the same), so that is recognized by the backend.
|
|
|
|
; The backend recognition is tested in test/CodeGen/X86/psubus.ll.
|
|
|
|
|
2018-02-03 05:40:54 +08:00
|
|
|
declare void @use(i64)
|
|
|
|
|
2018-02-03 01:43:16 +08:00
|
|
|
; (a > b) ? a - b : 0 -> ((a > b) ? a : b) - b)
|
|
|
|
|
2018-02-03 05:40:54 +08:00
|
|
|
define i64 @max_sub_ugt(i64 %a, i64 %b) {
|
2018-02-03 01:43:16 +08:00
|
|
|
; CHECK-LABEL: @max_sub_ugt(
|
2018-02-06 01:53:29 +08:00
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i64 [[A:%.*]], [[B:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i64 [[A]], i64 [[B]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = sub i64 [[TMP2]], [[B]]
|
|
|
|
; CHECK-NEXT: ret i64 [[TMP3]]
|
2018-02-03 01:43:16 +08:00
|
|
|
;
|
2018-02-03 05:40:54 +08:00
|
|
|
%cmp = icmp ugt i64 %a, %b
|
|
|
|
%sub = sub i64 %a, %b
|
2018-02-03 01:43:16 +08:00
|
|
|
%sel = select i1 %cmp, i64 %sub ,i64 0
|
|
|
|
ret i64 %sel
|
|
|
|
}
|
|
|
|
|
2018-02-06 01:53:29 +08:00
|
|
|
; (a >= b) ? a - b : 0 -> ((a >= b) ? a : b) - b)
|
|
|
|
|
|
|
|
define i64 @max_sub_uge(i64 %a, i64 %b) {
|
|
|
|
; CHECK-LABEL: @max_sub_uge(
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[A:%.*]], [[B:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i64 [[B]], i64 [[A]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = sub i64 [[TMP2]], [[B]]
|
|
|
|
; CHECK-NEXT: ret i64 [[TMP3]]
|
|
|
|
;
|
|
|
|
%cmp = icmp uge i64 %a, %b
|
|
|
|
%sub = sub i64 %a, %b
|
|
|
|
%sel = select i1 %cmp, i64 %sub ,i64 0
|
|
|
|
ret i64 %sel
|
|
|
|
}
|
|
|
|
|
2018-02-03 05:40:54 +08:00
|
|
|
; Again, with vectors:
|
|
|
|
; (a > b) ? a - b : 0 -> ((a > b) ? a : b) - b)
|
2018-02-03 01:43:16 +08:00
|
|
|
|
2018-02-03 05:40:54 +08:00
|
|
|
define <4 x i32> @max_sub_ugt_vec(<4 x i32> %a, <4 x i32> %b) {
|
|
|
|
; CHECK-LABEL: @max_sub_ugt_vec(
|
2018-02-06 01:53:29 +08:00
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt <4 x i32> [[A:%.*]], [[B:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = select <4 x i1> [[TMP1]], <4 x i32> [[A]], <4 x i32> [[B]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = sub <4 x i32> [[TMP2]], [[B]]
|
|
|
|
; CHECK-NEXT: ret <4 x i32> [[TMP3]]
|
2018-02-03 01:43:16 +08:00
|
|
|
;
|
2018-02-03 05:40:54 +08:00
|
|
|
%cmp = icmp ugt <4 x i32> %a, %b
|
|
|
|
%sub = sub <4 x i32> %a, %b
|
2018-02-03 01:43:16 +08:00
|
|
|
%sel = select <4 x i1> %cmp, <4 x i32> %sub, <4 x i32> zeroinitializer
|
|
|
|
ret <4 x i32> %sel
|
|
|
|
}
|
|
|
|
|
2018-02-03 05:40:54 +08:00
|
|
|
; Use extra ops to thwart icmp swapping canonicalization.
|
2018-02-03 01:43:16 +08:00
|
|
|
; (b < a) ? a - b : 0 -> ((a > b) ? a : b) - b)
|
|
|
|
|
2018-02-03 05:40:54 +08:00
|
|
|
define i64 @max_sub_ult(i64 %a, i64 %b) {
|
2018-02-03 01:43:16 +08:00
|
|
|
; CHECK-LABEL: @max_sub_ult(
|
2018-02-06 01:53:29 +08:00
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[B:%.*]], [[A:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i64 [[A]], i64 [[B]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = sub i64 [[TMP2]], [[B]]
|
2018-02-03 05:40:54 +08:00
|
|
|
; CHECK-NEXT: [[EXTRASUB:%.*]] = sub i64 [[B]], [[A]]
|
|
|
|
; CHECK-NEXT: call void @use(i64 [[EXTRASUB]])
|
2018-02-06 01:53:29 +08:00
|
|
|
; CHECK-NEXT: ret i64 [[TMP3]]
|
2018-02-03 01:43:16 +08:00
|
|
|
;
|
2018-02-03 05:40:54 +08:00
|
|
|
%cmp = icmp ult i64 %b, %a
|
|
|
|
%sub = sub i64 %a, %b
|
2018-02-03 01:43:16 +08:00
|
|
|
%sel = select i1 %cmp, i64 %sub ,i64 0
|
2018-02-03 05:40:54 +08:00
|
|
|
%extrasub = sub i64 %b, %a
|
|
|
|
call void @use(i64 %extrasub)
|
2018-02-03 01:43:16 +08:00
|
|
|
ret i64 %sel
|
|
|
|
}
|
|
|
|
|
|
|
|
; (b > a) ? 0 : a - b -> ((a > b) ? a : b) - b)
|
|
|
|
|
2018-02-03 05:40:54 +08:00
|
|
|
define i64 @max_sub_ugt_sel_swapped(i64 %a, i64 %b) {
|
2018-02-03 01:43:16 +08:00
|
|
|
; CHECK-LABEL: @max_sub_ugt_sel_swapped(
|
2018-02-06 01:53:29 +08:00
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i64 [[B:%.*]], [[A:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i64 [[B]], i64 [[A]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = sub i64 [[TMP2]], [[B]]
|
2018-02-03 05:40:54 +08:00
|
|
|
; CHECK-NEXT: [[EXTRASUB:%.*]] = sub i64 [[B]], [[A]]
|
|
|
|
; CHECK-NEXT: call void @use(i64 [[EXTRASUB]])
|
2018-02-06 01:53:29 +08:00
|
|
|
; CHECK-NEXT: ret i64 [[TMP3]]
|
2018-02-03 01:43:16 +08:00
|
|
|
;
|
2018-02-03 05:40:54 +08:00
|
|
|
%cmp = icmp ugt i64 %b, %a
|
|
|
|
%sub = sub i64 %a, %b
|
2018-02-03 01:43:16 +08:00
|
|
|
%sel = select i1 %cmp, i64 0 ,i64 %sub
|
2018-02-03 05:40:54 +08:00
|
|
|
%extrasub = sub i64 %b, %a
|
|
|
|
call void @use(i64 %extrasub)
|
2018-02-03 01:43:16 +08:00
|
|
|
ret i64 %sel
|
|
|
|
}
|
|
|
|
|
|
|
|
; (a < b) ? 0 : a - b -> ((a > b) ? a : b) - b)
|
|
|
|
|
2018-02-03 05:40:54 +08:00
|
|
|
define i64 @max_sub_ult_sel_swapped(i64 %a, i64 %b) {
|
2018-02-03 01:43:16 +08:00
|
|
|
; CHECK-LABEL: @max_sub_ult_sel_swapped(
|
2018-02-06 01:53:29 +08:00
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[A:%.*]], [[B:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i64 [[B]], i64 [[A]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = sub i64 [[TMP2]], [[B]]
|
|
|
|
; CHECK-NEXT: ret i64 [[TMP3]]
|
2018-02-03 01:43:16 +08:00
|
|
|
;
|
2018-02-03 05:40:54 +08:00
|
|
|
%cmp = icmp ult i64 %a, %b
|
|
|
|
%sub = sub i64 %a, %b
|
2018-02-03 01:43:16 +08:00
|
|
|
%sel = select i1 %cmp, i64 0 ,i64 %sub
|
|
|
|
ret i64 %sel
|
|
|
|
}
|
|
|
|
|
|
|
|
; ((a > b) ? b - a : 0) -> (b - ((a > b) ? a : b))
|
|
|
|
|
2018-02-03 05:40:54 +08:00
|
|
|
define i64 @neg_max_sub_ugt(i64 %a, i64 %b) {
|
2018-02-03 01:43:16 +08:00
|
|
|
; CHECK-LABEL: @neg_max_sub_ugt(
|
2018-02-06 01:53:29 +08:00
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i64 [[A:%.*]], [[B:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i64 [[A]], i64 [[B]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = sub i64 [[B]], [[TMP2]]
|
2018-02-03 05:40:54 +08:00
|
|
|
; CHECK-NEXT: [[EXTRASUB:%.*]] = sub i64 [[A]], [[B]]
|
|
|
|
; CHECK-NEXT: call void @use(i64 [[EXTRASUB]])
|
2018-02-06 01:53:29 +08:00
|
|
|
; CHECK-NEXT: ret i64 [[TMP3]]
|
2018-02-03 01:43:16 +08:00
|
|
|
;
|
2018-02-03 05:40:54 +08:00
|
|
|
%cmp = icmp ugt i64 %a, %b
|
|
|
|
%sub = sub i64 %b, %a
|
2018-02-03 01:43:16 +08:00
|
|
|
%sel = select i1 %cmp, i64 %sub ,i64 0
|
2018-02-03 05:40:54 +08:00
|
|
|
%extrasub = sub i64 %a, %b
|
|
|
|
call void @use(i64 %extrasub)
|
2018-02-03 01:43:16 +08:00
|
|
|
ret i64 %sel
|
|
|
|
}
|
|
|
|
|
|
|
|
; ((b < a) ? b - a : 0) -> - ((a > b) ? a : b) - b)
|
|
|
|
|
2018-02-03 05:40:54 +08:00
|
|
|
define i64 @neg_max_sub_ult(i64 %a, i64 %b) {
|
2018-02-03 01:43:16 +08:00
|
|
|
; CHECK-LABEL: @neg_max_sub_ult(
|
2018-02-06 01:53:29 +08:00
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i64 [[A:%.*]], [[B:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i64 [[A]], i64 [[B]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = sub i64 [[B]], [[TMP2]]
|
|
|
|
; CHECK-NEXT: ret i64 [[TMP3]]
|
2018-02-03 01:43:16 +08:00
|
|
|
;
|
2018-02-03 05:40:54 +08:00
|
|
|
%cmp = icmp ult i64 %b, %a
|
|
|
|
%sub = sub i64 %b, %a
|
2018-02-03 01:43:16 +08:00
|
|
|
%sel = select i1 %cmp, i64 %sub ,i64 0
|
|
|
|
ret i64 %sel
|
|
|
|
}
|
|
|
|
|
|
|
|
; ((b > a) ? 0 : b - a) -> - ((a > b) ? a : b) - b)
|
|
|
|
|
2018-02-03 05:40:54 +08:00
|
|
|
define i64 @neg_max_sub_ugt_sel_swapped(i64 %a, i64 %b) {
|
2018-02-03 01:43:16 +08:00
|
|
|
; CHECK-LABEL: @neg_max_sub_ugt_sel_swapped(
|
2018-02-06 01:53:29 +08:00
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[A:%.*]], [[B:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i64 [[B]], i64 [[A]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = sub i64 [[B]], [[TMP2]]
|
|
|
|
; CHECK-NEXT: ret i64 [[TMP3]]
|
2018-02-03 01:43:16 +08:00
|
|
|
;
|
2018-02-03 05:40:54 +08:00
|
|
|
%cmp = icmp ugt i64 %b, %a
|
|
|
|
%sub = sub i64 %b, %a
|
2018-02-03 01:43:16 +08:00
|
|
|
%sel = select i1 %cmp, i64 0 ,i64 %sub
|
|
|
|
ret i64 %sel
|
|
|
|
}
|
|
|
|
|
|
|
|
; ((a < b) ? 0 : b - a) -> - ((a > b) ? a : b) - b)
|
|
|
|
|
2018-02-03 05:40:54 +08:00
|
|
|
define i64 @neg_max_sub_ult_sel_swapped(i64 %a, i64 %b) {
|
2018-02-03 01:43:16 +08:00
|
|
|
; CHECK-LABEL: @neg_max_sub_ult_sel_swapped(
|
2018-02-06 01:53:29 +08:00
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[A:%.*]], [[B:%.*]]
|
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i64 [[B]], i64 [[A]]
|
|
|
|
; CHECK-NEXT: [[TMP3:%.*]] = sub i64 [[B]], [[TMP2]]
|
2018-02-03 05:40:54 +08:00
|
|
|
; CHECK-NEXT: [[EXTRASUB:%.*]] = sub i64 [[A]], [[B]]
|
|
|
|
; CHECK-NEXT: call void @use(i64 [[EXTRASUB]])
|
2018-02-06 01:53:29 +08:00
|
|
|
; CHECK-NEXT: ret i64 [[TMP3]]
|
2018-02-03 01:43:16 +08:00
|
|
|
;
|
2018-02-03 05:40:54 +08:00
|
|
|
%cmp = icmp ult i64 %a, %b
|
|
|
|
%sub = sub i64 %b, %a
|
2018-02-03 01:43:16 +08:00
|
|
|
%sel = select i1 %cmp, i64 0 ,i64 %sub
|
2018-02-03 05:40:54 +08:00
|
|
|
%extrasub = sub i64 %a, %b
|
|
|
|
call void @use(i64 %extrasub)
|
2018-02-03 01:43:16 +08:00
|
|
|
ret i64 %sel
|
|
|
|
}
|
|
|
|
|