Use KnownBits to infer the nneg flag on zext instructions. Currently we only set nneg when converting sext -> zext, but don't set it when we have a zext in the first place. If we want to use it in optimizations, we should make sure the flag inference is consistent.
1422 lines
46 KiB
LLVM
1422 lines
46 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt -S -passes=instcombine < %s | FileCheck %s
|
|
|
|
; This is the canonical form for a type-changing min/max.
|
|
define i64 @t1(i32 %a) {
|
|
; CHECK-LABEL: @t1(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[A:%.*]], i32 5)
|
|
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i64
|
|
; CHECK-NEXT: ret i64 [[TMP2]]
|
|
;
|
|
%1 = icmp slt i32 %a, 5
|
|
%2 = select i1 %1, i32 %a, i32 5
|
|
%3 = sext i32 %2 to i64
|
|
ret i64 %3
|
|
}
|
|
|
|
; Check this is converted into canonical form, as above.
|
|
define i64 @t2(i32 %a) {
|
|
; CHECK-LABEL: @t2(
|
|
; CHECK-NEXT: [[NARROW:%.*]] = call i32 @llvm.smin.i32(i32 [[A:%.*]], i32 5)
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[NARROW]] to i64
|
|
; CHECK-NEXT: ret i64 [[TMP1]]
|
|
;
|
|
%1 = icmp slt i32 %a, 5
|
|
%2 = sext i32 %a to i64
|
|
%3 = select i1 %1, i64 %2, i64 5
|
|
ret i64 %3
|
|
}
|
|
|
|
; Same as @t2, with flipped operands and zext instead of sext.
|
|
define i64 @t3(i32 %a) {
|
|
; CHECK-LABEL: @t3(
|
|
; CHECK-NEXT: [[NARROW:%.*]] = call i32 @llvm.umax.i32(i32 [[A:%.*]], i32 5)
|
|
; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[NARROW]] to i64
|
|
; CHECK-NEXT: ret i64 [[TMP1]]
|
|
;
|
|
%1 = icmp ult i32 %a, 5
|
|
%2 = zext i32 %a to i64
|
|
%3 = select i1 %1, i64 5, i64 %2
|
|
ret i64 %3
|
|
}
|
|
|
|
; Same again, with trunc.
|
|
define i32 @t4(i64 %a) {
|
|
; CHECK-LABEL: @t4(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.smin.i64(i64 [[A:%.*]], i64 5)
|
|
; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32
|
|
; CHECK-NEXT: ret i32 [[TMP2]]
|
|
;
|
|
%1 = icmp slt i64 %a, 5
|
|
%2 = trunc i64 %a to i32
|
|
%3 = select i1 %1, i32 %2, i32 5
|
|
ret i32 %3
|
|
}
|
|
|
|
; Same as @t3, but with mismatched signedness between icmp and zext.
|
|
define i64 @t5(i32 %a) {
|
|
; CHECK-LABEL: @t5(
|
|
; CHECK-NEXT: [[NARROW:%.*]] = call i32 @llvm.smax.i32(i32 [[A:%.*]], i32 5)
|
|
; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[NARROW]] to i64
|
|
; CHECK-NEXT: ret i64 [[TMP1]]
|
|
;
|
|
%1 = icmp slt i32 %a, 5
|
|
%2 = zext i32 %a to i64
|
|
%3 = select i1 %1, i64 5, i64 %2
|
|
ret i64 %3
|
|
}
|
|
|
|
define float @t6(i32 %a) {
|
|
; CHECK-LABEL: @t6(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[A:%.*]], i32 0)
|
|
; CHECK-NEXT: [[TMP2:%.*]] = sitofp i32 [[TMP1]] to float
|
|
; CHECK-NEXT: ret float [[TMP2]]
|
|
;
|
|
%1 = icmp slt i32 %a, 0
|
|
%2 = select i1 %1, i32 %a, i32 0
|
|
%3 = sitofp i32 %2 to float
|
|
ret float %3
|
|
}
|
|
|
|
define i16 @t7(i32 %a) {
|
|
; CHECK-LABEL: @t7(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[A:%.*]], i32 -32768)
|
|
; CHECK-NEXT: [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
|
|
; CHECK-NEXT: ret i16 [[TMP2]]
|
|
;
|
|
%1 = icmp slt i32 %a, -32768
|
|
%2 = trunc i32 %a to i16
|
|
%3 = select i1 %1, i16 %2, i16 -32768
|
|
ret i16 %3
|
|
}
|
|
|
|
; Just check for no infinite loop. InstSimplify liked to
|
|
; "simplify" -32767 by removing all the sign bits,
|
|
; which led to a canonicalization fight between different
|
|
; parts of instcombine.
|
|
define i32 @t8(i64 %a, i32 %b) {
|
|
; CHECK-LABEL: @t8(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.smin.i64(i64 [[A:%.*]], i64 -32767)
|
|
; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32
|
|
; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i32 [[B:%.*]], 42
|
|
; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP2]], [[B]]
|
|
; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i1 true, i1 [[TMP4]]
|
|
; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
|
|
; CHECK-NEXT: ret i32 [[TMP6]]
|
|
;
|
|
%1 = icmp slt i64 %a, -32767
|
|
%2 = select i1 %1, i64 %a, i64 -32767
|
|
%3 = trunc i64 %2 to i32
|
|
%4 = icmp slt i32 %b, 42
|
|
%5 = select i1 %4, i32 42, i32 %3
|
|
%6 = icmp ne i32 %5, %b
|
|
%7 = zext i1 %6 to i32
|
|
ret i32 %7
|
|
}
|
|
|
|
; Ensure this doesn't get converted to a min/max.
|
|
define i64 @t9(i32 %a) {
|
|
; CHECK-LABEL: @t9(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[A:%.*]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[A]] to i64
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i64 [[TMP2]], i64 4294967295
|
|
; CHECK-NEXT: ret i64 [[TMP3]]
|
|
;
|
|
%1 = icmp sgt i32 %a, -1
|
|
%2 = sext i32 %a to i64
|
|
%3 = select i1 %1, i64 %2, i64 4294967295
|
|
ret i64 %3
|
|
}
|
|
|
|
define float @t10(i32 %x) {
|
|
; CHECK-LABEL: @t10(
|
|
; CHECK-NEXT: [[R1:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 255)
|
|
; CHECK-NEXT: [[R:%.*]] = sitofp i32 [[R1]] to float
|
|
; CHECK-NEXT: ret float [[R]]
|
|
;
|
|
%f_x = sitofp i32 %x to float
|
|
%cmp = icmp sgt i32 %x, 255
|
|
%r = select i1 %cmp, float %f_x, float 255.0
|
|
ret float %r
|
|
}
|
|
|
|
define float @t11(i64 %x) {
|
|
; CHECK-LABEL: @t11(
|
|
; CHECK-NEXT: [[R1:%.*]] = call i64 @llvm.smax.i64(i64 [[X:%.*]], i64 255)
|
|
; CHECK-NEXT: [[R:%.*]] = sitofp i64 [[R1]] to float
|
|
; CHECK-NEXT: ret float [[R]]
|
|
;
|
|
%f_x = sitofp i64 %x to float
|
|
%cmp = icmp sgt i64 %x, 255
|
|
%r = select i1 %cmp, float %f_x, float 255.0
|
|
ret float %r
|
|
}
|
|
|
|
; Reuse the first 2 bitcasts as the select operands.
|
|
|
|
define <4 x i32> @bitcasts_fcmp_1(<2 x i64> %a, <2 x i64> %b) {
|
|
; CHECK-LABEL: @bitcasts_fcmp_1(
|
|
; CHECK-NEXT: [[T0:%.*]] = bitcast <2 x i64> [[A:%.*]] to <4 x float>
|
|
; CHECK-NEXT: [[T1:%.*]] = bitcast <2 x i64> [[B:%.*]] to <4 x float>
|
|
; CHECK-NEXT: [[T2:%.*]] = fcmp olt <4 x float> [[T1]], [[T0]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = select <4 x i1> [[T2]], <4 x float> [[T0]], <4 x float> [[T1]]
|
|
; CHECK-NEXT: [[T5:%.*]] = bitcast <4 x float> [[TMP1]] to <4 x i32>
|
|
; CHECK-NEXT: ret <4 x i32> [[T5]]
|
|
;
|
|
%t0 = bitcast <2 x i64> %a to <4 x float>
|
|
%t1 = bitcast <2 x i64> %b to <4 x float>
|
|
%t2 = fcmp olt <4 x float> %t1, %t0
|
|
%t3 = bitcast <2 x i64> %a to <4 x i32>
|
|
%t4 = bitcast <2 x i64> %b to <4 x i32>
|
|
%t5 = select <4 x i1> %t2, <4 x i32> %t3, <4 x i32> %t4
|
|
ret <4 x i32> %t5
|
|
}
|
|
|
|
; Switch cmp operand order.
|
|
|
|
define <4 x i32> @bitcasts_fcmp_2(<2 x i64> %a, <2 x i64> %b) {
|
|
; CHECK-LABEL: @bitcasts_fcmp_2(
|
|
; CHECK-NEXT: [[T0:%.*]] = bitcast <2 x i64> [[A:%.*]] to <4 x float>
|
|
; CHECK-NEXT: [[T1:%.*]] = bitcast <2 x i64> [[B:%.*]] to <4 x float>
|
|
; CHECK-NEXT: [[T2:%.*]] = fcmp olt <4 x float> [[T0]], [[T1]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = select <4 x i1> [[T2]], <4 x float> [[T0]], <4 x float> [[T1]]
|
|
; CHECK-NEXT: [[T5:%.*]] = bitcast <4 x float> [[TMP1]] to <4 x i32>
|
|
; CHECK-NEXT: ret <4 x i32> [[T5]]
|
|
;
|
|
%t0 = bitcast <2 x i64> %a to <4 x float>
|
|
%t1 = bitcast <2 x i64> %b to <4 x float>
|
|
%t2 = fcmp olt <4 x float> %t0, %t1
|
|
%t3 = bitcast <2 x i64> %a to <4 x i32>
|
|
%t4 = bitcast <2 x i64> %b to <4 x i32>
|
|
%t5 = select <4 x i1> %t2, <4 x i32> %t3, <4 x i32> %t4
|
|
ret <4 x i32> %t5
|
|
}
|
|
|
|
; Integer cmp should have the same transforms.
|
|
|
|
define <4 x float> @bitcasts_icmp(<2 x i64> %a, <2 x i64> %b) {
|
|
; CHECK-LABEL: @bitcasts_icmp(
|
|
; CHECK-NEXT: [[T0:%.*]] = bitcast <2 x i64> [[A:%.*]] to <4 x i32>
|
|
; CHECK-NEXT: [[T1:%.*]] = bitcast <2 x i64> [[B:%.*]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call <4 x i32> @llvm.smax.v4i32(<4 x i32> [[T1]], <4 x i32> [[T0]])
|
|
; CHECK-NEXT: [[T5:%.*]] = bitcast <4 x i32> [[TMP1]] to <4 x float>
|
|
; CHECK-NEXT: ret <4 x float> [[T5]]
|
|
;
|
|
%t0 = bitcast <2 x i64> %a to <4 x i32>
|
|
%t1 = bitcast <2 x i64> %b to <4 x i32>
|
|
%t2 = icmp slt <4 x i32> %t1, %t0
|
|
%t3 = bitcast <2 x i64> %a to <4 x float>
|
|
%t4 = bitcast <2 x i64> %b to <4 x float>
|
|
%t5 = select <4 x i1> %t2, <4 x float> %t3, <4 x float> %t4
|
|
ret <4 x float> %t5
|
|
}
|
|
|
|
; SMIN(SMIN(X, 11), 92) -> SMIN(X, 11)
|
|
define i32 @test68(i32 %x) {
|
|
; CHECK-LABEL: @test68(
|
|
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.smin.i32(i32 [[X:%.*]], i32 11)
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%cmp = icmp slt i32 11, %x
|
|
%cond = select i1 %cmp, i32 11, i32 %x
|
|
%cmp3 = icmp slt i32 92, %cond
|
|
%retval = select i1 %cmp3, i32 92, i32 %cond
|
|
ret i32 %retval
|
|
}
|
|
|
|
define <2 x i32> @test68vec(<2 x i32> %x) {
|
|
; CHECK-LABEL: @test68vec(
|
|
; CHECK-NEXT: [[COND:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[X:%.*]], <2 x i32> <i32 11, i32 11>)
|
|
; CHECK-NEXT: ret <2 x i32> [[COND]]
|
|
;
|
|
%cmp = icmp slt <2 x i32> <i32 11, i32 11>, %x
|
|
%cond = select <2 x i1> %cmp, <2 x i32> <i32 11, i32 11>, <2 x i32> %x
|
|
%cmp3 = icmp slt <2 x i32> <i32 92, i32 92>, %cond
|
|
%retval = select <2 x i1> %cmp3, <2 x i32> <i32 92, i32 92>, <2 x i32> %cond
|
|
ret <2 x i32> %retval
|
|
}
|
|
|
|
; MIN(MIN(X, 24), 83) -> MIN(X, 24)
|
|
define i32 @test69(i32 %x) {
|
|
; CHECK-LABEL: @test69(
|
|
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 24)
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%cmp = icmp ult i32 24, %x
|
|
%cond = select i1 %cmp, i32 24, i32 %x
|
|
%cmp3 = icmp ult i32 83, %cond
|
|
%retval = select i1 %cmp3, i32 83, i32 %cond
|
|
ret i32 %retval
|
|
}
|
|
|
|
; SMAX(SMAX(X, 75), 36) -> SMAX(X, 75)
|
|
define i32 @test70(i32 %x) {
|
|
; CHECK-LABEL: @test70(
|
|
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 75)
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%cmp = icmp slt i32 %x, 75
|
|
%cond = select i1 %cmp, i32 75, i32 %x
|
|
%cmp3 = icmp slt i32 %cond, 36
|
|
%retval = select i1 %cmp3, i32 36, i32 %cond
|
|
ret i32 %retval
|
|
}
|
|
|
|
; MAX(MAX(X, 68), 47) -> MAX(X, 68)
|
|
define i32 @test71(i32 %x) {
|
|
; CHECK-LABEL: @test71(
|
|
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 68)
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%cmp = icmp ult i32 %x, 68
|
|
%cond = select i1 %cmp, i32 68, i32 %x
|
|
%cmp3 = icmp ult i32 %cond, 47
|
|
%retval = select i1 %cmp3, i32 47, i32 %cond
|
|
ret i32 %retval
|
|
}
|
|
|
|
; SMIN(SMIN(X, 92), 11) -> SMIN(X, 11)
|
|
define i32 @test72(i32 %x) {
|
|
; CHECK-LABEL: @test72(
|
|
; CHECK-NEXT: [[RETVAL:%.*]] = call i32 @llvm.smin.i32(i32 [[X:%.*]], i32 11)
|
|
; CHECK-NEXT: ret i32 [[RETVAL]]
|
|
;
|
|
%cmp = icmp sgt i32 %x, 92
|
|
%cond = select i1 %cmp, i32 92, i32 %x
|
|
%cmp3 = icmp sgt i32 %cond, 11
|
|
%retval = select i1 %cmp3, i32 11, i32 %cond
|
|
ret i32 %retval
|
|
}
|
|
|
|
define <2 x i32> @test72vec(<2 x i32> %x) {
|
|
; CHECK-LABEL: @test72vec(
|
|
; CHECK-NEXT: [[RETVAL:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[X:%.*]], <2 x i32> <i32 11, i32 11>)
|
|
; CHECK-NEXT: ret <2 x i32> [[RETVAL]]
|
|
;
|
|
%cmp = icmp sgt <2 x i32> %x, <i32 92, i32 92>
|
|
%cond = select <2 x i1> %cmp, <2 x i32> <i32 92, i32 92>, <2 x i32> %x
|
|
%cmp3 = icmp sgt <2 x i32> %cond, <i32 11, i32 11>
|
|
%retval = select <2 x i1> %cmp3, <2 x i32> <i32 11, i32 11>, <2 x i32> %cond
|
|
ret <2 x i32> %retval
|
|
}
|
|
|
|
; MIN(MIN(X, 83), 24) -> MIN(X, 24)
|
|
define i32 @test73(i32 %x) {
|
|
; CHECK-LABEL: @test73(
|
|
; CHECK-NEXT: [[RETVAL:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 24)
|
|
; CHECK-NEXT: ret i32 [[RETVAL]]
|
|
;
|
|
%cmp = icmp ugt i32 %x, 83
|
|
%cond = select i1 %cmp, i32 83, i32 %x
|
|
%cmp3 = icmp ugt i32 %cond, 24
|
|
%retval = select i1 %cmp3, i32 24, i32 %cond
|
|
ret i32 %retval
|
|
}
|
|
|
|
; SMAX(SMAX(X, 36), 75) -> SMAX(X, 75)
|
|
define i32 @test74(i32 %x) {
|
|
; CHECK-LABEL: @test74(
|
|
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 36)
|
|
; CHECK-NEXT: [[RETVAL:%.*]] = call i32 @llvm.umax.i32(i32 [[COND]], i32 75)
|
|
; CHECK-NEXT: ret i32 [[RETVAL]]
|
|
;
|
|
%cmp = icmp slt i32 %x, 36
|
|
%cond = select i1 %cmp, i32 36, i32 %x
|
|
%cmp3 = icmp slt i32 %cond, 75
|
|
%retval = select i1 %cmp3, i32 75, i32 %cond
|
|
ret i32 %retval
|
|
}
|
|
|
|
; MAX(MAX(X, 47), 68) -> MAX(X, 68)
|
|
define i32 @test75(i32 %x) {
|
|
; CHECK-LABEL: @test75(
|
|
; CHECK-NEXT: [[RETVAL:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 68)
|
|
; CHECK-NEXT: ret i32 [[RETVAL]]
|
|
;
|
|
%cmp = icmp ult i32 %x, 47
|
|
%cond = select i1 %cmp, i32 47, i32 %x
|
|
%cmp3 = icmp ult i32 %cond, 68
|
|
%retval = select i1 %cmp3, i32 68, i32 %cond
|
|
ret i32 %retval
|
|
}
|
|
|
|
; The next 10 tests are value clamping with constants:
|
|
; https://llvm.org/bugs/show_bug.cgi?id=31693
|
|
|
|
; (X <s C1) ? C1 : SMIN(X, C2) ==> SMAX(SMIN(X, C2), C1)
|
|
|
|
define i32 @clamp_signed1(i32 %x) {
|
|
; CHECK-LABEL: @clamp_signed1(
|
|
; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.smin.i32(i32 [[X:%.*]], i32 255)
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.smax.i32(i32 [[MIN]], i32 15)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%cmp2 = icmp slt i32 %x, 255
|
|
%min = select i1 %cmp2, i32 %x, i32 255
|
|
%cmp1 = icmp slt i32 %x, 15
|
|
%r = select i1 %cmp1, i32 15, i32 %min
|
|
ret i32 %r
|
|
}
|
|
|
|
; (X >s C1) ? C1 : SMAX(X, C2) ==> SMIN(SMAX(X, C2), C1)
|
|
|
|
define i32 @clamp_signed2(i32 %x) {
|
|
; CHECK-LABEL: @clamp_signed2(
|
|
; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 15)
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.smin.i32(i32 [[MAX]], i32 255)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%cmp2 = icmp sgt i32 %x, 15
|
|
%max = select i1 %cmp2, i32 %x, i32 15
|
|
%cmp1 = icmp sgt i32 %x, 255
|
|
%r = select i1 %cmp1, i32 255, i32 %max
|
|
ret i32 %r
|
|
}
|
|
|
|
; (X >s C1) ? SMIN(X, C2) : C1 ==> SMAX(SMIN(X, C2), C1)
|
|
|
|
define i32 @clamp_signed3(i32 %x) {
|
|
; CHECK-LABEL: @clamp_signed3(
|
|
; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.smin.i32(i32 [[X:%.*]], i32 255)
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.smax.i32(i32 [[MIN]], i32 15)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%cmp2 = icmp slt i32 %x, 255
|
|
%min = select i1 %cmp2, i32 %x, i32 255
|
|
%cmp1 = icmp sgt i32 %x, 15
|
|
%r = select i1 %cmp1, i32 %min, i32 15
|
|
ret i32 %r
|
|
}
|
|
|
|
; (X <s C1) ? SMAX(X, C2) : C1 ==> SMIN(SMAX(X, C1), C2)
|
|
|
|
define i32 @clamp_signed4(i32 %x) {
|
|
; CHECK-LABEL: @clamp_signed4(
|
|
; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 15)
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.smin.i32(i32 [[MAX]], i32 255)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%cmp2 = icmp sgt i32 %x, 15
|
|
%max = select i1 %cmp2, i32 %x, i32 15
|
|
%cmp1 = icmp slt i32 %x, 255
|
|
%r = select i1 %cmp1, i32 %max, i32 255
|
|
ret i32 %r
|
|
}
|
|
|
|
; (X <u C1) ? C1 : UMIN(X, C2) ==> UMAX(UMIN(X, C2), C1)
|
|
|
|
define i32 @clamp_unsigned1(i32 %x) {
|
|
; CHECK-LABEL: @clamp_unsigned1(
|
|
; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 255)
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.umax.i32(i32 [[MIN]], i32 15)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%cmp2 = icmp ult i32 %x, 255
|
|
%min = select i1 %cmp2, i32 %x, i32 255
|
|
%cmp1 = icmp ult i32 %x, 15
|
|
%r = select i1 %cmp1, i32 15, i32 %min
|
|
ret i32 %r
|
|
}
|
|
|
|
; (X >u C1) ? C1 : UMAX(X, C2) ==> UMIN(UMAX(X, C2), C1)
|
|
|
|
define i32 @clamp_unsigned2(i32 %x) {
|
|
; CHECK-LABEL: @clamp_unsigned2(
|
|
; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 15)
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.umin.i32(i32 [[MAX]], i32 255)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%cmp2 = icmp ugt i32 %x, 15
|
|
%max = select i1 %cmp2, i32 %x, i32 15
|
|
%cmp1 = icmp ugt i32 %x, 255
|
|
%r = select i1 %cmp1, i32 255, i32 %max
|
|
ret i32 %r
|
|
}
|
|
|
|
; (X >u C1) ? UMIN(X, C2) : C1 ==> UMAX(UMIN(X, C2), C1)
|
|
|
|
define i32 @clamp_unsigned3(i32 %x) {
|
|
; CHECK-LABEL: @clamp_unsigned3(
|
|
; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 255)
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.umax.i32(i32 [[MIN]], i32 15)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%cmp2 = icmp ult i32 %x, 255
|
|
%min = select i1 %cmp2, i32 %x, i32 255
|
|
%cmp1 = icmp ugt i32 %x, 15
|
|
%r = select i1 %cmp1, i32 %min, i32 15
|
|
ret i32 %r
|
|
}
|
|
|
|
; (X <u C1) ? UMAX(X, C2) : C1 ==> UMIN(UMAX(X, C2), C1)
|
|
|
|
define i32 @clamp_unsigned4(i32 %x) {
|
|
; CHECK-LABEL: @clamp_unsigned4(
|
|
; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 15)
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.umin.i32(i32 [[MAX]], i32 255)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%cmp2 = icmp ugt i32 %x, 15
|
|
%max = select i1 %cmp2, i32 %x, i32 15
|
|
%cmp1 = icmp ult i32 %x, 255
|
|
%r = select i1 %cmp1, i32 %max, i32 255
|
|
ret i32 %r
|
|
}
|
|
|
|
; Check that clamp is recognized and there is no infinite
|
|
; loop because of reverse cmp transformation:
|
|
; (icmp sgt smin(PositiveA, B) 0) -> (icmp sgt B 0)
|
|
define i32 @clamp_check_for_no_infinite_loop1(i32 %i) {
|
|
; CHECK-LABEL: @clamp_check_for_no_infinite_loop1(
|
|
; CHECK-NEXT: [[SEL1:%.*]] = call i32 @llvm.smin.i32(i32 [[I:%.*]], i32 255)
|
|
; CHECK-NEXT: [[RES:%.*]] = call i32 @llvm.smax.i32(i32 [[SEL1]], i32 0)
|
|
; CHECK-NEXT: ret i32 [[RES]]
|
|
;
|
|
%cmp1 = icmp slt i32 %i, 255
|
|
%sel1 = select i1 %cmp1, i32 %i, i32 255
|
|
%cmp2 = icmp slt i32 %i, 0
|
|
%res = select i1 %cmp2, i32 0, i32 %sel1
|
|
ret i32 %res
|
|
}
|
|
; Check that there is no infinite loop in case of:
|
|
; (icmp slt smax(NegativeA, B) 0) -> (icmp slt B 0)
|
|
define i32 @clamp_check_for_no_infinite_loop2(i32 %i) {
|
|
; CHECK-LABEL: @clamp_check_for_no_infinite_loop2(
|
|
; CHECK-NEXT: [[SEL1:%.*]] = call i32 @llvm.smax.i32(i32 [[I:%.*]], i32 -255)
|
|
; CHECK-NEXT: [[RES:%.*]] = call i32 @llvm.smin.i32(i32 [[SEL1]], i32 0)
|
|
; CHECK-NEXT: ret i32 [[RES]]
|
|
;
|
|
%cmp1 = icmp sgt i32 %i, -255
|
|
%sel1 = select i1 %cmp1, i32 %i, i32 -255
|
|
%cmp2 = icmp slt i32 %i, 0
|
|
%res = select i1 %cmp2, i32 %sel1, i32 0
|
|
ret i32 %res
|
|
}
|
|
|
|
; Check that there is no infinite loop because of reverse cmp transformation:
|
|
; (icmp slt smax(PositiveA, B) 2) -> (icmp eq B 1)
|
|
define i32 @clamp_check_for_no_infinite_loop3(i32 %i) {
|
|
; CHECK-LABEL: @clamp_check_for_no_infinite_loop3(
|
|
; CHECK-NEXT: br i1 true, label [[TRUELABEL:%.*]], label [[FALSELABEL:%.*]]
|
|
; CHECK: truelabel:
|
|
; CHECK-NEXT: [[I3:%.*]] = call i32 @llvm.smax.i32(i32 [[I:%.*]], i32 1)
|
|
; CHECK-NEXT: [[I6:%.*]] = call i32 @llvm.umin.i32(i32 [[I3]], i32 2)
|
|
; CHECK-NEXT: [[I7:%.*]] = shl nuw nsw i32 [[I6]], 2
|
|
; CHECK-NEXT: ret i32 [[I7]]
|
|
; CHECK: falselabel:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
|
|
%i2 = icmp sgt i32 %i, 1
|
|
%i3 = select i1 %i2, i32 %i, i32 1
|
|
%i4 = icmp sgt i32 %i3, 0
|
|
br i1 %i4, label %truelabel, label %falselabel
|
|
|
|
truelabel: ; %i<=1, %i3>0
|
|
%i5 = icmp slt i32 %i3, 2
|
|
%i6 = select i1 %i5, i32 %i3, i32 2
|
|
%i7 = shl nuw nsw i32 %i6, 2
|
|
ret i32 %i7
|
|
|
|
falselabel:
|
|
ret i32 0
|
|
}
|
|
|
|
; The next 3 min tests should canonicalize to the same form...and not infinite loop.
|
|
|
|
define double @PR31751_umin1(i32 %x) {
|
|
; CHECK-LABEL: @PR31751_umin1(
|
|
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 2147483647)
|
|
; CHECK-NEXT: [[CONV:%.*]] = sitofp i32 [[SEL]] to double
|
|
; CHECK-NEXT: ret double [[CONV]]
|
|
;
|
|
%cmp = icmp slt i32 %x, 0
|
|
%sel = select i1 %cmp, i32 2147483647, i32 %x
|
|
%conv = sitofp i32 %sel to double
|
|
ret double %conv
|
|
}
|
|
|
|
define double @PR31751_umin2(i32 %x) {
|
|
; CHECK-LABEL: @PR31751_umin2(
|
|
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 2147483647)
|
|
; CHECK-NEXT: [[CONV:%.*]] = sitofp i32 [[SEL]] to double
|
|
; CHECK-NEXT: ret double [[CONV]]
|
|
;
|
|
%cmp = icmp ult i32 %x, 2147483647
|
|
%sel = select i1 %cmp, i32 %x, i32 2147483647
|
|
%conv = sitofp i32 %sel to double
|
|
ret double %conv
|
|
}
|
|
|
|
define double @PR31751_umin3(i32 %x) {
|
|
; CHECK-LABEL: @PR31751_umin3(
|
|
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 2147483647)
|
|
; CHECK-NEXT: [[CONV:%.*]] = sitofp i32 [[SEL]] to double
|
|
; CHECK-NEXT: ret double [[CONV]]
|
|
;
|
|
%cmp = icmp ugt i32 %x, 2147483647
|
|
%sel = select i1 %cmp, i32 2147483647, i32 %x
|
|
%conv = sitofp i32 %sel to double
|
|
ret double %conv
|
|
}
|
|
|
|
; The next 3 max tests should canonicalize to the same form...and not infinite loop.
|
|
|
|
define double @PR31751_umax1(i32 %x) {
|
|
; CHECK-LABEL: @PR31751_umax1(
|
|
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 -2147483648)
|
|
; CHECK-NEXT: [[CONV:%.*]] = sitofp i32 [[SEL]] to double
|
|
; CHECK-NEXT: ret double [[CONV]]
|
|
;
|
|
%cmp = icmp sgt i32 %x, -1
|
|
%sel = select i1 %cmp, i32 2147483648, i32 %x
|
|
%conv = sitofp i32 %sel to double
|
|
ret double %conv
|
|
}
|
|
|
|
define double @PR31751_umax2(i32 %x) {
|
|
; CHECK-LABEL: @PR31751_umax2(
|
|
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 -2147483648)
|
|
; CHECK-NEXT: [[CONV:%.*]] = sitofp i32 [[SEL]] to double
|
|
; CHECK-NEXT: ret double [[CONV]]
|
|
;
|
|
%cmp = icmp ugt i32 %x, 2147483648
|
|
%sel = select i1 %cmp, i32 %x, i32 2147483648
|
|
%conv = sitofp i32 %sel to double
|
|
ret double %conv
|
|
}
|
|
|
|
define double @PR31751_umax3(i32 %x) {
|
|
; CHECK-LABEL: @PR31751_umax3(
|
|
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 -2147483648)
|
|
; CHECK-NEXT: [[CONV:%.*]] = sitofp i32 [[SEL]] to double
|
|
; CHECK-NEXT: ret double [[CONV]]
|
|
;
|
|
%cmp = icmp ult i32 %x, 2147483648
|
|
%sel = select i1 %cmp, i32 2147483648, i32 %x
|
|
%conv = sitofp i32 %sel to double
|
|
ret double %conv
|
|
}
|
|
|
|
; The icmp/select form a canonical smax, so don't hide that by folding the final bitcast into the select.
|
|
|
|
define float @bitcast_scalar_smax(float %x, float %y) {
|
|
; CHECK-LABEL: @bitcast_scalar_smax(
|
|
; CHECK-NEXT: [[BCX:%.*]] = bitcast float [[X:%.*]] to i32
|
|
; CHECK-NEXT: [[BCY:%.*]] = bitcast float [[Y:%.*]] to i32
|
|
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.smax.i32(i32 [[BCX]], i32 [[BCY]])
|
|
; CHECK-NEXT: [[BCS:%.*]] = bitcast i32 [[SEL]] to float
|
|
; CHECK-NEXT: ret float [[BCS]]
|
|
;
|
|
%bcx = bitcast float %x to i32
|
|
%bcy = bitcast float %y to i32
|
|
%cmp = icmp sgt i32 %bcx, %bcy
|
|
%sel = select i1 %cmp, i32 %bcx, i32 %bcy
|
|
%bcs = bitcast i32 %sel to float
|
|
ret float %bcs
|
|
}
|
|
|
|
; FIXME: Create a canonical umax by bitcasting the select.
|
|
|
|
define float @bitcast_scalar_umax(float %x, float %y) {
|
|
; CHECK-LABEL: @bitcast_scalar_umax(
|
|
; CHECK-NEXT: [[BCX:%.*]] = bitcast float [[X:%.*]] to i32
|
|
; CHECK-NEXT: [[BCY:%.*]] = bitcast float [[Y:%.*]] to i32
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[BCX]], [[BCY]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[Y]]
|
|
; CHECK-NEXT: ret float [[SEL]]
|
|
;
|
|
%bcx = bitcast float %x to i32
|
|
%bcy = bitcast float %y to i32
|
|
%cmp = icmp ugt i32 %bcx, %bcy
|
|
%sel = select i1 %cmp, float %x, float %y
|
|
ret float %sel
|
|
}
|
|
|
|
; PR32306 - https://bugs.llvm.org/show_bug.cgi?id=32306
|
|
; The icmp/select form a canonical smin, so don't hide that by folding the final bitcast into the select.
|
|
|
|
define <8 x float> @bitcast_vector_smin(<8 x float> %x, <8 x float> %y) {
|
|
; CHECK-LABEL: @bitcast_vector_smin(
|
|
; CHECK-NEXT: [[BCX:%.*]] = bitcast <8 x float> [[X:%.*]] to <8 x i32>
|
|
; CHECK-NEXT: [[BCY:%.*]] = bitcast <8 x float> [[Y:%.*]] to <8 x i32>
|
|
; CHECK-NEXT: [[SEL:%.*]] = call <8 x i32> @llvm.smin.v8i32(<8 x i32> [[BCX]], <8 x i32> [[BCY]])
|
|
; CHECK-NEXT: [[BCS:%.*]] = bitcast <8 x i32> [[SEL]] to <8 x float>
|
|
; CHECK-NEXT: ret <8 x float> [[BCS]]
|
|
;
|
|
%bcx = bitcast <8 x float> %x to <8 x i32>
|
|
%bcy = bitcast <8 x float> %y to <8 x i32>
|
|
%cmp = icmp slt <8 x i32> %bcx, %bcy
|
|
%sel = select <8 x i1> %cmp, <8 x i32> %bcx, <8 x i32> %bcy
|
|
%bcs = bitcast <8 x i32> %sel to <8 x float>
|
|
ret <8 x float> %bcs
|
|
}
|
|
|
|
; FIXME: Create a canonical umin by bitcasting the select.
|
|
|
|
define <8 x float> @bitcast_vector_umin(<8 x float> %x, <8 x float> %y) {
|
|
; CHECK-LABEL: @bitcast_vector_umin(
|
|
; CHECK-NEXT: [[BCX:%.*]] = bitcast <8 x float> [[X:%.*]] to <8 x i32>
|
|
; CHECK-NEXT: [[BCY:%.*]] = bitcast <8 x float> [[Y:%.*]] to <8 x i32>
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <8 x i32> [[BCX]], [[BCY]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = select <8 x i1> [[CMP]], <8 x float> [[X]], <8 x float> [[Y]]
|
|
; CHECK-NEXT: ret <8 x float> [[SEL]]
|
|
;
|
|
%bcx = bitcast <8 x float> %x to <8 x i32>
|
|
%bcy = bitcast <8 x float> %y to <8 x i32>
|
|
%cmp = icmp slt <8 x i32> %bcx, %bcy
|
|
%sel = select <8 x i1> %cmp, <8 x float> %x, <8 x float> %y
|
|
ret <8 x float> %sel
|
|
}
|
|
|
|
; Check that we look through cast and recognize min idiom.
|
|
|
|
define zeroext i8 @look_through_cast1(i32 %x) {
|
|
; CHECK-LABEL: @look_through_cast1(
|
|
; CHECK-NEXT: [[RES1:%.*]] = call i32 @llvm.smin.i32(i32 [[X:%.*]], i32 511)
|
|
; CHECK-NEXT: [[RES:%.*]] = trunc i32 [[RES1]] to i8
|
|
; CHECK-NEXT: ret i8 [[RES]]
|
|
;
|
|
%cmp1 = icmp slt i32 %x, 511
|
|
%x_trunc = trunc i32 %x to i8
|
|
%res = select i1 %cmp1, i8 %x_trunc, i8 255
|
|
ret i8 %res
|
|
}
|
|
|
|
; Check that we look through cast but min is not recognized.
|
|
|
|
define zeroext i8 @look_through_cast2(i32 %x) {
|
|
; CHECK-LABEL: @look_through_cast2(
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[X:%.*]], 510
|
|
; CHECK-NEXT: [[X_TRUNC:%.*]] = trunc i32 [[X]] to i8
|
|
; CHECK-NEXT: [[RES:%.*]] = select i1 [[CMP1]], i8 [[X_TRUNC]], i8 -1
|
|
; CHECK-NEXT: ret i8 [[RES]]
|
|
;
|
|
%cmp1 = icmp slt i32 %x, 510
|
|
%x_trunc = trunc i32 %x to i8
|
|
%res = select i1 %cmp1, i8 %x_trunc, i8 255
|
|
ret i8 %res
|
|
}
|
|
|
|
define <2 x i8> @min_through_cast_vec1(<2 x i32> %x) {
|
|
; CHECK-LABEL: @min_through_cast_vec1(
|
|
; CHECK-NEXT: [[RES1:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[X:%.*]], <2 x i32> <i32 510, i32 511>)
|
|
; CHECK-NEXT: [[RES:%.*]] = trunc <2 x i32> [[RES1]] to <2 x i8>
|
|
; CHECK-NEXT: ret <2 x i8> [[RES]]
|
|
;
|
|
%cmp = icmp slt <2 x i32> %x, <i32 510, i32 511>
|
|
%x_trunc = trunc <2 x i32> %x to <2 x i8>
|
|
%res = select <2 x i1> %cmp, <2 x i8> %x_trunc, <2 x i8> <i8 254, i8 255>
|
|
ret <2 x i8> %res
|
|
}
|
|
|
|
define <2 x i8> @min_through_cast_vec2(<2 x i32> %x) {
|
|
; CHECK-LABEL: @min_through_cast_vec2(
|
|
; CHECK-NEXT: [[RES1:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[X:%.*]], <2 x i32> <i32 511, i32 511>)
|
|
; CHECK-NEXT: [[RES:%.*]] = trunc <2 x i32> [[RES1]] to <2 x i8>
|
|
; CHECK-NEXT: ret <2 x i8> [[RES]]
|
|
;
|
|
%cmp = icmp slt <2 x i32> %x, <i32 511, i32 511>
|
|
%x_trunc = trunc <2 x i32> %x to <2 x i8>
|
|
%res = select <2 x i1> %cmp, <2 x i8> %x_trunc, <2 x i8> <i8 255, i8 255>
|
|
ret <2 x i8> %res
|
|
}
|
|
|
|
; Remove a min/max op in a sequence with a common operand.
|
|
; PR35717: https://bugs.llvm.org/show_bug.cgi?id=35717
|
|
|
|
; min(min(a, b), min(b, c)) --> min(min(a, b), c)
|
|
|
|
define i32 @common_factor_smin(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: @common_factor_smin(
|
|
; CHECK-NEXT: [[MIN_BC:%.*]] = call i32 @llvm.smin.i32(i32 [[B:%.*]], i32 [[C:%.*]])
|
|
; CHECK-NEXT: [[MIN_ABC:%.*]] = call i32 @llvm.smin.i32(i32 [[MIN_BC]], i32 [[A:%.*]])
|
|
; CHECK-NEXT: ret i32 [[MIN_ABC]]
|
|
;
|
|
%cmp_ab = icmp slt i32 %a, %b
|
|
%min_ab = select i1 %cmp_ab, i32 %a, i32 %b
|
|
%cmp_bc = icmp slt i32 %b, %c
|
|
%min_bc = select i1 %cmp_bc, i32 %b, i32 %c
|
|
%cmp_ab_bc = icmp slt i32 %min_ab, %min_bc
|
|
%min_abc = select i1 %cmp_ab_bc, i32 %min_ab, i32 %min_bc
|
|
ret i32 %min_abc
|
|
}
|
|
|
|
; max(max(a, b), max(c, b)) --> max(max(a, b), c)
|
|
|
|
define <2 x i32> @common_factor_smax(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c) {
|
|
; CHECK-LABEL: @common_factor_smax(
|
|
; CHECK-NEXT: [[MAX_CB:%.*]] = call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[C:%.*]], <2 x i32> [[B:%.*]])
|
|
; CHECK-NEXT: [[MAX_ABC:%.*]] = call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[MAX_CB]], <2 x i32> [[A:%.*]])
|
|
; CHECK-NEXT: ret <2 x i32> [[MAX_ABC]]
|
|
;
|
|
%cmp_ab = icmp sgt <2 x i32> %a, %b
|
|
%max_ab = select <2 x i1> %cmp_ab, <2 x i32> %a, <2 x i32> %b
|
|
%cmp_cb = icmp sgt <2 x i32> %c, %b
|
|
%max_cb = select <2 x i1> %cmp_cb, <2 x i32> %c, <2 x i32> %b
|
|
%cmp_ab_cb = icmp sgt <2 x i32> %max_ab, %max_cb
|
|
%max_abc = select <2 x i1> %cmp_ab_cb, <2 x i32> %max_ab, <2 x i32> %max_cb
|
|
ret <2 x i32> %max_abc
|
|
}
|
|
|
|
; min(min(b, c), min(a, b)) --> min(min(b, c), a)
|
|
|
|
define <2 x i32> @common_factor_umin(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c) {
|
|
; CHECK-LABEL: @common_factor_umin(
|
|
; CHECK-NEXT: [[MIN_AB:%.*]] = call <2 x i32> @llvm.umin.v2i32(<2 x i32> [[A:%.*]], <2 x i32> [[B:%.*]])
|
|
; CHECK-NEXT: [[MIN_ABC:%.*]] = call <2 x i32> @llvm.umin.v2i32(<2 x i32> [[MIN_AB]], <2 x i32> [[C:%.*]])
|
|
; CHECK-NEXT: ret <2 x i32> [[MIN_ABC]]
|
|
;
|
|
%cmp_bc = icmp ult <2 x i32> %b, %c
|
|
%min_bc = select <2 x i1> %cmp_bc, <2 x i32> %b, <2 x i32> %c
|
|
%cmp_ab = icmp ult <2 x i32> %a, %b
|
|
%min_ab = select <2 x i1> %cmp_ab, <2 x i32> %a, <2 x i32> %b
|
|
%cmp_bc_ab = icmp ult <2 x i32> %min_bc, %min_ab
|
|
%min_abc = select <2 x i1> %cmp_bc_ab, <2 x i32> %min_bc, <2 x i32> %min_ab
|
|
ret <2 x i32> %min_abc
|
|
}
|
|
|
|
; max(max(b, c), max(b, a)) --> max(max(b, c), a)
|
|
|
|
define i32 @common_factor_umax(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: @common_factor_umax(
|
|
; CHECK-NEXT: [[MAX_BA:%.*]] = call i32 @llvm.umax.i32(i32 [[B:%.*]], i32 [[A:%.*]])
|
|
; CHECK-NEXT: [[MAX_ABC:%.*]] = call i32 @llvm.umax.i32(i32 [[MAX_BA]], i32 [[C:%.*]])
|
|
; CHECK-NEXT: ret i32 [[MAX_ABC]]
|
|
;
|
|
%cmp_bc = icmp ugt i32 %b, %c
|
|
%max_bc = select i1 %cmp_bc, i32 %b, i32 %c
|
|
%cmp_ba = icmp ugt i32 %b, %a
|
|
%max_ba = select i1 %cmp_ba, i32 %b, i32 %a
|
|
%cmp_bc_ba = icmp ugt i32 %max_bc, %max_ba
|
|
%max_abc = select i1 %cmp_bc_ba, i32 %max_bc, i32 %max_ba
|
|
ret i32 %max_abc
|
|
}
|
|
|
|
declare void @extra_use(i32)
|
|
|
|
define i32 @common_factor_umax_extra_use_lhs(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: @common_factor_umax_extra_use_lhs(
|
|
; CHECK-NEXT: [[MAX_BC:%.*]] = call i32 @llvm.umax.i32(i32 [[B:%.*]], i32 [[C:%.*]])
|
|
; CHECK-NEXT: [[MAX_ABC:%.*]] = call i32 @llvm.umax.i32(i32 [[MAX_BC]], i32 [[A:%.*]])
|
|
; CHECK-NEXT: call void @extra_use(i32 [[MAX_BC]])
|
|
; CHECK-NEXT: ret i32 [[MAX_ABC]]
|
|
;
|
|
%cmp_bc = icmp ugt i32 %b, %c
|
|
%max_bc = select i1 %cmp_bc, i32 %b, i32 %c
|
|
%cmp_ba = icmp ugt i32 %b, %a
|
|
%max_ba = select i1 %cmp_ba, i32 %b, i32 %a
|
|
%cmp_bc_ba = icmp ugt i32 %max_bc, %max_ba
|
|
%max_abc = select i1 %cmp_bc_ba, i32 %max_bc, i32 %max_ba
|
|
call void @extra_use(i32 %max_bc)
|
|
ret i32 %max_abc
|
|
}
|
|
|
|
define i32 @common_factor_umax_extra_use_rhs(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: @common_factor_umax_extra_use_rhs(
|
|
; CHECK-NEXT: [[MAX_BA:%.*]] = call i32 @llvm.umax.i32(i32 [[B:%.*]], i32 [[A:%.*]])
|
|
; CHECK-NEXT: [[MAX_ABC:%.*]] = call i32 @llvm.umax.i32(i32 [[MAX_BA]], i32 [[C:%.*]])
|
|
; CHECK-NEXT: call void @extra_use(i32 [[MAX_BA]])
|
|
; CHECK-NEXT: ret i32 [[MAX_ABC]]
|
|
;
|
|
%cmp_bc = icmp ugt i32 %b, %c
|
|
%max_bc = select i1 %cmp_bc, i32 %b, i32 %c
|
|
%cmp_ba = icmp ugt i32 %b, %a
|
|
%max_ba = select i1 %cmp_ba, i32 %b, i32 %a
|
|
%cmp_bc_ba = icmp ugt i32 %max_bc, %max_ba
|
|
%max_abc = select i1 %cmp_bc_ba, i32 %max_bc, i32 %max_ba
|
|
call void @extra_use(i32 %max_ba)
|
|
ret i32 %max_abc
|
|
}
|
|
|
|
define i32 @common_factor_umax_extra_use_both(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: @common_factor_umax_extra_use_both(
|
|
; CHECK-NEXT: [[MAX_BC:%.*]] = call i32 @llvm.umax.i32(i32 [[B:%.*]], i32 [[C:%.*]])
|
|
; CHECK-NEXT: [[MAX_BA:%.*]] = call i32 @llvm.umax.i32(i32 [[B]], i32 [[A:%.*]])
|
|
; CHECK-NEXT: [[MAX_ABC:%.*]] = call i32 @llvm.umax.i32(i32 [[MAX_BC]], i32 [[MAX_BA]])
|
|
; CHECK-NEXT: call void @extra_use(i32 [[MAX_BC]])
|
|
; CHECK-NEXT: call void @extra_use(i32 [[MAX_BA]])
|
|
; CHECK-NEXT: ret i32 [[MAX_ABC]]
|
|
;
|
|
%cmp_bc = icmp ugt i32 %b, %c
|
|
%max_bc = select i1 %cmp_bc, i32 %b, i32 %c
|
|
%cmp_ba = icmp ugt i32 %b, %a
|
|
%max_ba = select i1 %cmp_ba, i32 %b, i32 %a
|
|
%cmp_bc_ba = icmp ugt i32 %max_bc, %max_ba
|
|
%max_abc = select i1 %cmp_bc_ba, i32 %max_bc, i32 %max_ba
|
|
call void @extra_use(i32 %max_bc)
|
|
call void @extra_use(i32 %max_ba)
|
|
ret i32 %max_abc
|
|
}
|
|
|
|
; This would assert. Don't assume that earlier min/max types match a possible later min/max.
|
|
|
|
define float @not_min_of_min(i8 %i, float %x) {
|
|
; CHECK-LABEL: @not_min_of_min(
|
|
; CHECK-NEXT: [[CMP1_INV:%.*]] = fcmp fast oge float [[X:%.*]], 1.000000e+00
|
|
; CHECK-NEXT: [[MIN1:%.*]] = select fast i1 [[CMP1_INV]], float 1.000000e+00, float [[X]]
|
|
; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp fast oge float [[X]], 2.000000e+00
|
|
; CHECK-NEXT: [[MIN2:%.*]] = select fast i1 [[CMP2_INV]], float 2.000000e+00, float [[X]]
|
|
; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i8 [[I:%.*]], 16
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP3]], float [[MIN1]], float [[MIN2]]
|
|
; CHECK-NEXT: ret float [[R]]
|
|
;
|
|
%cmp1 = fcmp fast ult float %x, 1.0
|
|
%min1 = select i1 %cmp1, float %x, float 1.0
|
|
%cmp2 = fcmp fast ult float %x, 2.0
|
|
%min2 = select i1 %cmp2, float %x, float 2.0
|
|
%cmp3 = icmp ult i8 %i, 16
|
|
%r = select i1 %cmp3, float %min1, float %min2
|
|
ret float %r
|
|
}
|
|
|
|
define i32 @add_umin(i32 %x) {
|
|
; CHECK-LABEL: @add_umin(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 27)
|
|
; CHECK-NEXT: [[R:%.*]] = add nuw nsw i32 [[TMP1]], 15
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nuw i32 %x, 15
|
|
%c = icmp ult i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @add_umin_constant_limit(i32 %x) {
|
|
; CHECK-LABEL: @add_umin_constant_limit(
|
|
; CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[DOTNOT]], i32 41, i32 42
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nuw i32 %x, 41
|
|
%c = icmp ult i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
; Negative test
|
|
; TODO: assert that instsimplify always gets this?
|
|
|
|
define i32 @add_umin_simplify(i32 %x) {
|
|
; CHECK-LABEL: @add_umin_simplify(
|
|
; CHECK-NEXT: ret i32 42
|
|
;
|
|
%a = add nuw i32 %x, 42
|
|
%c = icmp ult i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
; Negative test
|
|
; TODO: assert that instsimplify always gets this?
|
|
|
|
define i32 @add_umin_simplify2(i32 %x) {
|
|
; CHECK-LABEL: @add_umin_simplify2(
|
|
; CHECK-NEXT: ret i32 42
|
|
;
|
|
%a = add nuw i32 %x, 43
|
|
%c = icmp ult i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
; Negative test
|
|
|
|
define i32 @add_umin_wrong_pred(i32 %x) {
|
|
; CHECK-LABEL: @add_umin_wrong_pred(
|
|
; CHECK-NEXT: [[A:%.*]] = add nuw i32 [[X:%.*]], 15
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.smin.i32(i32 [[A]], i32 42)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nuw i32 %x, 15
|
|
%c = icmp slt i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
; Negative test
|
|
|
|
define i32 @add_umin_wrong_wrap(i32 %x) {
|
|
; CHECK-LABEL: @add_umin_wrong_wrap(
|
|
; CHECK-NEXT: [[A:%.*]] = add nsw i32 [[X:%.*]], 15
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.umin.i32(i32 [[A]], i32 42)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nsw i32 %x, 15
|
|
%c = icmp ult i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
; Negative test
|
|
|
|
define i32 @add_umin_extra_use(i32 %x, ptr %p) {
|
|
; CHECK-LABEL: @add_umin_extra_use(
|
|
; CHECK-NEXT: [[A:%.*]] = add nuw i32 [[X:%.*]], 15
|
|
; CHECK-NEXT: store i32 [[A]], ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.umin.i32(i32 [[A]], i32 42)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nuw i32 %x, 15
|
|
store i32 %a, ptr %p
|
|
%c = icmp ult i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
define <2 x i16> @add_umin_vec(<2 x i16> %x) {
|
|
; CHECK-LABEL: @add_umin_vec(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i16> @llvm.umin.v2i16(<2 x i16> [[X:%.*]], <2 x i16> <i16 225, i16 225>)
|
|
; CHECK-NEXT: [[R:%.*]] = add nuw nsw <2 x i16> [[TMP1]], <i16 15, i16 15>
|
|
; CHECK-NEXT: ret <2 x i16> [[R]]
|
|
;
|
|
%a = add nuw <2 x i16> %x, <i16 15, i16 15>
|
|
%c = icmp ult <2 x i16> %a, <i16 240, i16 240>
|
|
%r = select <2 x i1> %c, <2 x i16> %a, <2 x i16> <i16 240, i16 240>
|
|
ret <2 x i16> %r
|
|
}
|
|
|
|
define i37 @add_umax(i37 %x) {
|
|
; CHECK-LABEL: @add_umax(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i37 @llvm.umax.i37(i37 [[X:%.*]], i37 37)
|
|
; CHECK-NEXT: [[R:%.*]] = add nuw i37 [[TMP1]], 5
|
|
; CHECK-NEXT: ret i37 [[R]]
|
|
;
|
|
%a = add nuw i37 %x, 5
|
|
%c = icmp ugt i37 %a, 42
|
|
%r = select i1 %c, i37 %a, i37 42
|
|
ret i37 %r
|
|
}
|
|
|
|
define i37 @add_umax_constant_limit(i37 %x) {
|
|
; CHECK-LABEL: @add_umax_constant_limit(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i37 @llvm.umax.i37(i37 [[X:%.*]], i37 1)
|
|
; CHECK-NEXT: [[R:%.*]] = add nuw i37 [[TMP1]], 81
|
|
; CHECK-NEXT: ret i37 [[R]]
|
|
;
|
|
%a = add nuw i37 %x, 81
|
|
%c = icmp ugt i37 %a, 82
|
|
%r = select i1 %c, i37 %a, i37 82
|
|
ret i37 %r
|
|
}
|
|
|
|
; Negative test
|
|
; TODO: assert that instsimplify always gets this?
|
|
|
|
define i37 @add_umax_simplify(i37 %x) {
|
|
; CHECK-LABEL: @add_umax_simplify(
|
|
; CHECK-NEXT: [[A:%.*]] = add nuw i37 [[X:%.*]], 42
|
|
; CHECK-NEXT: ret i37 [[A]]
|
|
;
|
|
%a = add nuw i37 %x, 42
|
|
%c = icmp ugt i37 %a, 42
|
|
%r = select i1 %c, i37 %a, i37 42
|
|
ret i37 %r
|
|
}
|
|
|
|
; Negative test
|
|
; TODO: assert that instsimplify always gets this?
|
|
|
|
define i32 @add_umax_simplify2(i32 %x) {
|
|
; CHECK-LABEL: @add_umax_simplify2(
|
|
; CHECK-NEXT: [[A:%.*]] = add nuw i32 [[X:%.*]], 57
|
|
; CHECK-NEXT: ret i32 [[A]]
|
|
;
|
|
%a = add nuw i32 %x, 57
|
|
%c = icmp ugt i32 %a, 56
|
|
%r = select i1 %c, i32 %a, i32 56
|
|
ret i32 %r
|
|
}
|
|
|
|
; Negative test
|
|
|
|
define i32 @add_umax_wrong_pred(i32 %x) {
|
|
; CHECK-LABEL: @add_umax_wrong_pred(
|
|
; CHECK-NEXT: [[A:%.*]] = add nuw i32 [[X:%.*]], 15
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.smax.i32(i32 [[A]], i32 42)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nuw i32 %x, 15
|
|
%c = icmp sgt i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
; Negative test
|
|
|
|
; Without the nuw that would allow pushing the add through the umax, the
|
|
; add + icmp ugt combination can be interpreted as a range check, and would
|
|
; normally be canonicalized to use ult instead. However, this is not done when
|
|
; used as part of a umax to avoid breaking the SPF pattern.
|
|
define i32 @add_umax_wrong_wrap(i32 %x) {
|
|
; CHECK-LABEL: @add_umax_wrong_wrap(
|
|
; CHECK-NEXT: [[A:%.*]] = add nsw i32 [[X:%.*]], 15
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.umax.i32(i32 [[A]], i32 42)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nsw i32 %x, 15
|
|
%c = icmp ugt i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
; Negative test
|
|
|
|
define i32 @add_umax_extra_use(i32 %x, ptr %p) {
|
|
; CHECK-LABEL: @add_umax_extra_use(
|
|
; CHECK-NEXT: [[A:%.*]] = add nuw i32 [[X:%.*]], 15
|
|
; CHECK-NEXT: store i32 [[A]], ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.umax.i32(i32 [[A]], i32 42)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nuw i32 %x, 15
|
|
store i32 %a, ptr %p
|
|
%c = icmp ugt i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
define <2 x i33> @add_umax_vec(<2 x i33> %x) {
|
|
; CHECK-LABEL: @add_umax_vec(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i33> @llvm.umax.v2i33(<2 x i33> [[X:%.*]], <2 x i33> <i33 235, i33 235>)
|
|
; CHECK-NEXT: [[R:%.*]] = add nuw <2 x i33> [[TMP1]], <i33 5, i33 5>
|
|
; CHECK-NEXT: ret <2 x i33> [[R]]
|
|
;
|
|
%a = add nuw <2 x i33> %x, <i33 5, i33 5>
|
|
%c = icmp ugt <2 x i33> %a, <i33 240, i33 240>
|
|
%r = select <2 x i1> %c, <2 x i33> %a, <2 x i33> <i33 240, i33 240>
|
|
ret <2 x i33> %r
|
|
}
|
|
|
|
define i8 @PR14613_umin(i8 %x) {
|
|
; CHECK-LABEL: @PR14613_umin(
|
|
; CHECK-NEXT: [[NARROW:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 15)
|
|
; CHECK-NEXT: ret i8 [[NARROW]]
|
|
;
|
|
%u4 = zext i8 %x to i32
|
|
%u5 = add nuw nsw i32 %u4, 15
|
|
%u6 = icmp ult i32 %u5, 255
|
|
%u7 = select i1 %u6, i32 %u5, i32 255
|
|
%r = trunc i32 %u7 to i8
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @PR14613_umax(i8 %x) {
|
|
; CHECK-LABEL: @PR14613_umax(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X:%.*]], i8 -16)
|
|
; CHECK-NEXT: [[U7:%.*]] = add nsw i8 [[TMP1]], 15
|
|
; CHECK-NEXT: ret i8 [[U7]]
|
|
;
|
|
%u4 = zext i8 %x to i32
|
|
%u5 = add nuw nsw i32 %u4, 15
|
|
%u6 = icmp ugt i32 %u5, 255
|
|
%u7 = select i1 %u6, i32 %u5, i32 255
|
|
%r = trunc i32 %u7 to i8
|
|
ret i8 %r
|
|
}
|
|
|
|
define i32 @add_smin(i32 %x) {
|
|
; CHECK-LABEL: @add_smin(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[X:%.*]], i32 27)
|
|
; CHECK-NEXT: [[R:%.*]] = add nsw i32 [[TMP1]], 15
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nsw i32 %x, 15
|
|
%c = icmp slt i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @add_smin_constant_limit(i32 %x) {
|
|
; CHECK-LABEL: @add_smin_constant_limit(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[X:%.*]], i32 2147483646)
|
|
; CHECK-NEXT: [[R:%.*]] = add nsw i32 [[TMP1]], -3
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nsw i32 %x, -3
|
|
%c = icmp slt i32 %a, 2147483643
|
|
%r = select i1 %c, i32 %a, i32 2147483643
|
|
ret i32 %r
|
|
}
|
|
|
|
; Negative test
|
|
; TODO: assert that instsimplify always gets this?
|
|
|
|
define i32 @add_smin_simplify(i32 %x) {
|
|
; CHECK-LABEL: @add_smin_simplify(
|
|
; CHECK-NEXT: [[A:%.*]] = add nsw i32 [[X:%.*]], -3
|
|
; CHECK-NEXT: ret i32 [[A]]
|
|
;
|
|
%a = add nsw i32 %x, -3
|
|
%c = icmp slt i32 %a, 2147483644
|
|
%r = select i1 %c, i32 %a, i32 2147483644
|
|
ret i32 %r
|
|
}
|
|
|
|
; Negative test
|
|
; TODO: assert that instsimplify always gets this?
|
|
|
|
define i32 @add_smin_simplify2(i32 %x) {
|
|
; CHECK-LABEL: @add_smin_simplify2(
|
|
; CHECK-NEXT: [[A:%.*]] = add nsw i32 [[X:%.*]], -3
|
|
; CHECK-NEXT: ret i32 [[A]]
|
|
;
|
|
%a = add nsw i32 %x, -3
|
|
%c = icmp slt i32 %a, 2147483645
|
|
%r = select i1 %c, i32 %a, i32 2147483645
|
|
ret i32 %r
|
|
}
|
|
|
|
; Negative test
|
|
|
|
define i32 @add_smin_wrong_pred(i32 %x) {
|
|
; CHECK-LABEL: @add_smin_wrong_pred(
|
|
; CHECK-NEXT: [[A:%.*]] = add nsw i32 [[X:%.*]], 15
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.umin.i32(i32 [[A]], i32 42)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nsw i32 %x, 15
|
|
%c = icmp ult i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
; Negative test
|
|
|
|
define i32 @add_smin_wrong_wrap(i32 %x) {
|
|
; CHECK-LABEL: @add_smin_wrong_wrap(
|
|
; CHECK-NEXT: [[A:%.*]] = add nuw i32 [[X:%.*]], 15
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.smin.i32(i32 [[A]], i32 42)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nuw i32 %x, 15
|
|
%c = icmp slt i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
; Negative test
|
|
|
|
define i32 @add_smin_extra_use(i32 %x, ptr %p) {
|
|
; CHECK-LABEL: @add_smin_extra_use(
|
|
; CHECK-NEXT: [[A:%.*]] = add nsw i32 [[X:%.*]], 15
|
|
; CHECK-NEXT: store i32 [[A]], ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.smin.i32(i32 [[A]], i32 42)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nsw i32 %x, 15
|
|
store i32 %a, ptr %p
|
|
%c = icmp slt i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
define <2 x i16> @add_smin_vec(<2 x i16> %x) {
|
|
; CHECK-LABEL: @add_smin_vec(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i16> @llvm.smin.v2i16(<2 x i16> [[X:%.*]], <2 x i16> <i16 225, i16 225>)
|
|
; CHECK-NEXT: [[R:%.*]] = add nsw <2 x i16> [[TMP1]], <i16 15, i16 15>
|
|
; CHECK-NEXT: ret <2 x i16> [[R]]
|
|
;
|
|
%a = add nsw <2 x i16> %x, <i16 15, i16 15>
|
|
%c = icmp slt <2 x i16> %a, <i16 240, i16 240>
|
|
%r = select <2 x i1> %c, <2 x i16> %a, <2 x i16> <i16 240, i16 240>
|
|
ret <2 x i16> %r
|
|
}
|
|
|
|
define i37 @add_smax(i37 %x) {
|
|
; CHECK-LABEL: @add_smax(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i37 @llvm.smax.i37(i37 [[X:%.*]], i37 37)
|
|
; CHECK-NEXT: [[R:%.*]] = add nuw nsw i37 [[TMP1]], 5
|
|
; CHECK-NEXT: ret i37 [[R]]
|
|
;
|
|
%a = add nsw i37 %x, 5
|
|
%c = icmp sgt i37 %a, 42
|
|
%r = select i1 %c, i37 %a, i37 42
|
|
ret i37 %r
|
|
}
|
|
|
|
define i8 @add_smax_constant_limit(i8 %x) {
|
|
; CHECK-LABEL: @add_smax_constant_limit(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 -127)
|
|
; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[TMP1]], 125
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%a = add nsw i8 %x, 125
|
|
%c = icmp sgt i8 %a, -2
|
|
%r = select i1 %c, i8 %a, i8 -2
|
|
ret i8 %r
|
|
}
|
|
|
|
; Negative test
|
|
; TODO: assert that instsimplify always gets this?
|
|
|
|
define i8 @add_smax_simplify(i8 %x) {
|
|
; CHECK-LABEL: @add_smax_simplify(
|
|
; CHECK-NEXT: [[A:%.*]] = add nsw i8 [[X:%.*]], 126
|
|
; CHECK-NEXT: ret i8 [[A]]
|
|
;
|
|
%a = add nsw i8 %x, 126
|
|
%c = icmp sgt i8 %a, -2
|
|
%r = select i1 %c, i8 %a, i8 -2
|
|
ret i8 %r
|
|
}
|
|
|
|
; Negative test
|
|
; TODO: assert that instsimplify always gets this?
|
|
|
|
define i8 @add_smax_simplify2(i8 %x) {
|
|
; CHECK-LABEL: @add_smax_simplify2(
|
|
; CHECK-NEXT: [[A:%.*]] = add nsw i8 [[X:%.*]], 127
|
|
; CHECK-NEXT: ret i8 [[A]]
|
|
;
|
|
%a = add nsw i8 %x, 127
|
|
%c = icmp sgt i8 %a, -2
|
|
%r = select i1 %c, i8 %a, i8 -2
|
|
ret i8 %r
|
|
}
|
|
|
|
; Negative test
|
|
|
|
define i32 @add_smax_wrong_pred(i32 %x) {
|
|
; CHECK-LABEL: @add_smax_wrong_pred(
|
|
; CHECK-NEXT: [[A:%.*]] = add nsw i32 [[X:%.*]], 15
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.umax.i32(i32 [[A]], i32 42)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nsw i32 %x, 15
|
|
%c = icmp ugt i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
; Negative test
|
|
|
|
define i32 @add_smax_wrong_wrap(i32 %x) {
|
|
; CHECK-LABEL: @add_smax_wrong_wrap(
|
|
; CHECK-NEXT: [[A:%.*]] = add nuw i32 [[X:%.*]], 15
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.smax.i32(i32 [[A]], i32 42)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nuw i32 %x, 15
|
|
%c = icmp sgt i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
; Negative test
|
|
|
|
define i32 @add_smax_extra_use(i32 %x, ptr %p) {
|
|
; CHECK-LABEL: @add_smax_extra_use(
|
|
; CHECK-NEXT: [[A:%.*]] = add nsw i32 [[X:%.*]], 15
|
|
; CHECK-NEXT: store i32 [[A]], ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.smax.i32(i32 [[A]], i32 42)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nsw i32 %x, 15
|
|
store i32 %a, ptr %p
|
|
%c = icmp sgt i32 %a, 42
|
|
%r = select i1 %c, i32 %a, i32 42
|
|
ret i32 %r
|
|
}
|
|
|
|
define <2 x i33> @add_smax_vec(<2 x i33> %x) {
|
|
; CHECK-LABEL: @add_smax_vec(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i33> @llvm.smax.v2i33(<2 x i33> [[X:%.*]], <2 x i33> <i33 235, i33 235>)
|
|
; CHECK-NEXT: [[R:%.*]] = add nuw nsw <2 x i33> [[TMP1]], <i33 5, i33 5>
|
|
; CHECK-NEXT: ret <2 x i33> [[R]]
|
|
;
|
|
%a = add nsw <2 x i33> %x, <i33 5, i33 5>
|
|
%c = icmp sgt <2 x i33> %a, <i33 240, i33 240>
|
|
%r = select <2 x i1> %c, <2 x i33> %a, <2 x i33> <i33 240, i33 240>
|
|
ret <2 x i33> %r
|
|
}
|
|
|
|
define i8 @PR14613_smin(i8 %x) {
|
|
; CHECK-LABEL: @PR14613_smin(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 40)
|
|
; CHECK-NEXT: [[NARROW:%.*]] = add nsw i8 [[TMP1]], 15
|
|
; CHECK-NEXT: ret i8 [[NARROW]]
|
|
;
|
|
%u4 = sext i8 %x to i32
|
|
%u5 = add nuw nsw i32 %u4, 15
|
|
%u6 = icmp slt i32 %u5, 55
|
|
%u7 = select i1 %u6, i32 %u5, i32 55
|
|
%r = trunc i32 %u7 to i8
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @PR14613_smax(i8 %x) {
|
|
; CHECK-LABEL: @PR14613_smax(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 40)
|
|
; CHECK-NEXT: [[NARROW:%.*]] = add nuw i8 [[TMP1]], 15
|
|
; CHECK-NEXT: ret i8 [[NARROW]]
|
|
;
|
|
%u4 = sext i8 %x to i32
|
|
%u5 = add nuw nsw i32 %u4, 15
|
|
%u6 = icmp sgt i32 %u5, 55
|
|
%u7 = select i1 %u6, i32 %u5, i32 55
|
|
%r = trunc i32 %u7 to i8
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @PR46271(<2 x i8> %x) {
|
|
; CHECK-LABEL: @PR46271(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i8> @llvm.smax.v2i8(<2 x i8> [[X:%.*]], <2 x i8> <i8 -1, i8 -1>)
|
|
; CHECK-NEXT: [[TMP2:%.*]] = extractelement <2 x i8> [[TMP1]], i64 1
|
|
; CHECK-NEXT: [[R:%.*]] = xor i8 [[TMP2]], -1
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%a = icmp sgt <2 x i8> %x, <i8 -1, i8 -1>
|
|
%b = select <2 x i1> %a, <2 x i8> %x, <2 x i8> <i8 undef, i8 -1>
|
|
%not = xor <2 x i8> %b, <i8 undef, i8 -1>
|
|
%r = extractelement <2 x i8> %not, i32 1
|
|
ret i8 %r
|
|
}
|
|
|
|
define i32 @twoway_clamp_lt(i32 %num) {
|
|
; CHECK-LABEL: @twoway_clamp_lt(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[NUM:%.*]], 13767
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP0]], i32 13768, i32 13767
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
entry:
|
|
%cmp1 = icmp slt i32 %num, 13768
|
|
%s1 = select i1 %cmp1, i32 %num, i32 13768
|
|
%cmp2 = icmp sgt i32 %s1, 13767
|
|
%r = select i1 %cmp2, i32 %s1, i32 13767
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @twoway_clamp_gt(i32 %num) {
|
|
; CHECK-LABEL: @twoway_clamp_gt(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[S1:%.*]] = call i32 @llvm.smax.i32(i32 [[NUM:%.*]], i32 13767)
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.umin.i32(i32 [[S1]], i32 13768)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
entry:
|
|
%cmp1 = icmp sgt i32 %num, 13767
|
|
%s1 = select i1 %cmp1, i32 %num, i32 13767
|
|
%cmp2 = icmp slt i32 %s1, 13768
|
|
%r = select i1 %cmp2, i32 %s1, i32 13768
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @twoway_clamp_gt_nonconst(i32 %num, i32 %k) {
|
|
; CHECK-LABEL: @twoway_clamp_gt_nonconst(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[K1:%.*]] = add i32 [[K:%.*]], 1
|
|
; CHECK-NEXT: [[S1:%.*]] = call i32 @llvm.smax.i32(i32 [[NUM:%.*]], i32 [[K]])
|
|
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.smin.i32(i32 [[S1]], i32 [[K1]])
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
entry:
|
|
%k1 = add i32 %k, 1
|
|
%cmp1 = icmp sgt i32 %num, %k
|
|
%s1 = select i1 %cmp1, i32 %num, i32 %k
|
|
%cmp2 = icmp slt i32 %s1, %k1
|
|
%r = select i1 %cmp2, i32 %s1, i32 %k1
|
|
ret i32 %r
|
|
}
|