Jay Foad f3a02253e9
[test] Remove immarg parameter attribute from calls (#97432)
It is documented that immarg is only valid on intrinsic declarations,
although the verifier also tolerates it on intrinsic calls.

This patch updates tests that are not specifically testing the
behavior of the IR parser or verifier.
2024-07-03 09:02:31 +01:00

1755 lines
54 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
define i1 @bool_true_or_false(i1 %cond) {
; CHECK-LABEL: @bool_true_or_false(
; CHECK-NEXT: ret i1 [[COND:%.*]]
;
%s = select i1 %cond, i1 true, i1 false
ret i1 %s
}
define i1 @cond_constexpr_bool_true_or_false(i1 %cond) {
; CHECK-LABEL: @cond_constexpr_bool_true_or_false(
; CHECK-NEXT: ret i1 ptrtoint (ptr @cond_constexpr_bool_true_or_false to i1)
;
%s = select i1 ptrtoint (ptr @cond_constexpr_bool_true_or_false to i1), i1 true, i1 false
ret i1 %s
}
define <2 x i1> @bool_true_or_false_vec(<2 x i1> %cond) {
; CHECK-LABEL: @bool_true_or_false_vec(
; CHECK-NEXT: ret <2 x i1> [[COND:%.*]]
;
%s = select <2 x i1> %cond, <2 x i1> <i1 true, i1 true>, <2 x i1> zeroinitializer
ret <2 x i1> %s
}
define <2 x i1> @bool_true_or_false_vec_poison(<2 x i1> %cond) {
; CHECK-LABEL: @bool_true_or_false_vec_poison(
; CHECK-NEXT: ret <2 x i1> [[COND:%.*]]
;
%s = select <2 x i1> %cond, <2 x i1> <i1 poison, i1 true>, <2 x i1> <i1 false, i1 poison>
ret <2 x i1> %s
}
define i32 @cond_is_false(i32 %A, i32 %B) {
; CHECK-LABEL: @cond_is_false(
; CHECK-NEXT: ret i32 [[B:%.*]]
;
%C = select i1 false, i32 %A, i32 %B
ret i32 %C
}
define i32 @cond_is_true(i32 %A, i32 %B) {
; CHECK-LABEL: @cond_is_true(
; CHECK-NEXT: ret i32 [[A:%.*]]
;
%C = select i1 true, i32 %A, i32 %B
ret i32 %C
}
define i32 @equal_arms(i1 %cond, i32 %x) {
; CHECK-LABEL: @equal_arms(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%V = select i1 %cond, i32 %x, i32 %x
ret i32 %V
}
define <2 x i32> @equal_arms_vec(<2 x i1> %cond, <2 x i32> %x) {
; CHECK-LABEL: @equal_arms_vec(
; CHECK-NEXT: ret <2 x i32> [[X:%.*]]
;
%V = select <2 x i1> %cond, <2 x i32> %x, <2 x i32> %x
ret <2 x i32> %V
}
define <2 x i32> @equal_arms_vec_poison(<2 x i1> %cond) {
; CHECK-LABEL: @equal_arms_vec_poison(
; CHECK-NEXT: ret <2 x i32> <i32 42, i32 42>
;
%V = select <2 x i1> %cond, <2 x i32> <i32 42, i32 poison>, <2 x i32> <i32 poison, i32 42>
ret <2 x i32> %V
}
define <3 x float> @equal_arms_vec_less_poison(<3 x i1> %cond) {
; CHECK-LABEL: @equal_arms_vec_less_poison(
; CHECK-NEXT: ret <3 x float> <float 4.200000e+01, float 4.200000e+01, float 4.300000e+01>
;
%V = select <3 x i1> %cond, <3 x float> <float 42.0, float poison, float 43.0>, <3 x float> <float 42.0, float 42.0, float 43.0>
ret <3 x float> %V
}
define <3 x float> @equal_arms_vec_more_poison(<3 x i1> %cond) {
; CHECK-LABEL: @equal_arms_vec_more_poison(
; CHECK-NEXT: ret <3 x float> <float 4.200000e+01, float poison, float 4.300000e+01>
;
%V = select <3 x i1> %cond, <3 x float> <float 42.0, float poison, float poison>, <3 x float> <float poison, float poison, float 43.0>
ret <3 x float> %V
}
define <2 x i8> @vsel_tvec(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @vsel_tvec(
; CHECK-NEXT: ret <2 x i8> [[X:%.*]]
;
%s = select <2 x i1><i1 true, i1 true>, <2 x i8> %x, <2 x i8> %y
ret <2 x i8> %s
}
define <2 x i8> @vsel_fvec(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @vsel_fvec(
; CHECK-NEXT: ret <2 x i8> [[Y:%.*]]
;
%s = select <2 x i1><i1 false, i1 false>, <2 x i8> %x, <2 x i8> %y
ret <2 x i8> %s
}
define <2 x i8> @vsel_mixedvec() {
; CHECK-LABEL: @vsel_mixedvec(
; CHECK-NEXT: ret <2 x i8> <i8 0, i8 3>
;
%s = select <2 x i1><i1 true, i1 false>, <2 x i8> <i8 0, i8 1>, <2 x i8> <i8 2, i8 3>
ret <2 x i8> %s
}
define <3 x i8> @vsel_poison_true_op(<3 x i8> %x, <3 x i8> %y) {
; CHECK-LABEL: @vsel_poison_true_op(
; CHECK-NEXT: ret <3 x i8> [[X:%.*]]
;
%s = select <3 x i1><i1 1, i1 poison, i1 1>, <3 x i8> %x, <3 x i8> %y
ret <3 x i8> %s
}
define <3 x i4> @vsel_poison_false_op(<3 x i4> %x, <3 x i4> %y) {
; CHECK-LABEL: @vsel_poison_false_op(
; CHECK-NEXT: ret <3 x i4> [[Y:%.*]]
;
%s = select <3 x i1><i1 0, i1 poison, i1 poison>, <3 x i4> %x, <3 x i4> %y
ret <3 x i4> %s
}
define i32 @test1(i32 %x) {
; CHECK-LABEL: @test1(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%and = and i32 %x, 1
%cmp = icmp eq i32 %and, 0
%and1 = and i32 %x, -2
%and1.x = select i1 %cmp, i32 %and1, i32 %x
ret i32 %and1.x
}
define i32 @test2(i32 %x) {
; CHECK-LABEL: @test2(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%and = and i32 %x, 1
%cmp = icmp ne i32 %and, 0
%and1 = and i32 %x, -2
%and1.x = select i1 %cmp, i32 %x, i32 %and1
ret i32 %and1.x
}
define i32 @test3(i32 %x) {
; CHECK-LABEL: @test3(
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[X:%.*]], -2
; CHECK-NEXT: ret i32 [[AND1]]
;
%and = and i32 %x, 1
%cmp = icmp ne i32 %and, 0
%and1 = and i32 %x, -2
%and1.x = select i1 %cmp, i32 %and1, i32 %x
ret i32 %and1.x
}
define i32 @test4(i32 %X) {
; CHECK-LABEL: @test4(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], -2147483648
; CHECK-NEXT: ret i32 [[OR]]
;
%cmp = icmp slt i32 %X, 0
%or = or i32 %X, -2147483648
%cond = select i1 %cmp, i32 %X, i32 %or
ret i32 %cond
}
define i32 @test4_disjoint(i32 %X) {
; CHECK-LABEL: @test4_disjoint(
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0
; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[X]], -2147483648
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[X]], i32 [[OR]]
; CHECK-NEXT: ret i32 [[COND]]
;
%cmp = icmp slt i32 %X, 0
%or = or disjoint i32 %X, -2147483648
%cond = select i1 %cmp, i32 %X, i32 %or
ret i32 %cond
}
; Same as above, but the compare isn't canonical
define i32 @test4noncanon(i32 %X) {
; CHECK-LABEL: @test4noncanon(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], -2147483648
; CHECK-NEXT: ret i32 [[OR]]
;
%cmp = icmp sle i32 %X, -1
%or = or i32 %X, -2147483648
%cond = select i1 %cmp, i32 %X, i32 %or
ret i32 %cond
}
define i32 @test5(i32 %X) {
; CHECK-LABEL: @test5(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%cmp = icmp slt i32 %X, 0
%or = or i32 %X, -2147483648
%cond = select i1 %cmp, i32 %or, i32 %X
ret i32 %cond
}
define i32 @test5_disjoint(i32 %X) {
; CHECK-LABEL: @test5_disjoint(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%cmp = icmp slt i32 %X, 0
%or = or disjoint i32 %X, -2147483648
%cond = select i1 %cmp, i32 %or, i32 %X
ret i32 %cond
}
define i32 @test6(i32 %X) {
; CHECK-LABEL: @test6(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 2147483647
; CHECK-NEXT: ret i32 [[AND]]
;
%cmp = icmp slt i32 %X, 0
%and = and i32 %X, 2147483647
%cond = select i1 %cmp, i32 %and, i32 %X
ret i32 %cond
}
define i32 @test7(i32 %X) {
; CHECK-LABEL: @test7(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%cmp = icmp slt i32 %X, 0
%and = and i32 %X, 2147483647
%cond = select i1 %cmp, i32 %X, i32 %and
ret i32 %cond
}
define i32 @test8(i32 %X) {
; CHECK-LABEL: @test8(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%cmp = icmp sgt i32 %X, -1
%or = or i32 %X, -2147483648
%cond = select i1 %cmp, i32 %X, i32 %or
ret i32 %cond
}
define i32 @test8_disjoint(i32 %X) {
; CHECK-LABEL: @test8_disjoint(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%cmp = icmp sgt i32 %X, -1
%or = or disjoint i32 %X, -2147483648
%cond = select i1 %cmp, i32 %X, i32 %or
ret i32 %cond
}
define i32 @test9(i32 %X) {
; CHECK-LABEL: @test9(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], -2147483648
; CHECK-NEXT: ret i32 [[OR]]
;
%cmp = icmp sgt i32 %X, -1
%or = or i32 %X, -2147483648
%cond = select i1 %cmp, i32 %or, i32 %X
ret i32 %cond
}
define i32 @test9_disjoint(i32 %X) {
; CHECK-LABEL: @test9_disjoint(
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], -1
; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[X]], -2147483648
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[OR]], i32 [[X]]
; CHECK-NEXT: ret i32 [[COND]]
;
%cmp = icmp sgt i32 %X, -1
%or = or disjoint i32 %X, -2147483648
%cond = select i1 %cmp, i32 %or, i32 %X
ret i32 %cond
}
; Same as above, but the compare isn't canonical
define i32 @test9noncanon(i32 %X) {
; CHECK-LABEL: @test9noncanon(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], -2147483648
; CHECK-NEXT: ret i32 [[OR]]
;
%cmp = icmp sge i32 %X, 0
%or = or i32 %X, -2147483648
%cond = select i1 %cmp, i32 %or, i32 %X
ret i32 %cond
}
define i32 @test10(i32 %X) {
; CHECK-LABEL: @test10(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%cmp = icmp sgt i32 %X, -1
%and = and i32 %X, 2147483647
%cond = select i1 %cmp, i32 %and, i32 %X
ret i32 %cond
}
define i32 @test11(i32 %X) {
; CHECK-LABEL: @test11(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 2147483647
; CHECK-NEXT: ret i32 [[AND]]
;
%cmp = icmp sgt i32 %X, -1
%and = and i32 %X, 2147483647
%cond = select i1 %cmp, i32 %X, i32 %and
ret i32 %cond
}
define <2 x i8> @test11vec(<2 x i8> %X) {
; CHECK-LABEL: @test11vec(
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[X:%.*]], <i8 127, i8 127>
; CHECK-NEXT: ret <2 x i8> [[AND]]
;
%cmp = icmp sgt <2 x i8> %X, <i8 -1, i8 -1>
%and = and <2 x i8> %X, <i8 127, i8 127>
%sel = select <2 x i1> %cmp, <2 x i8> %X, <2 x i8> %and
ret <2 x i8> %sel
}
define i32 @test12(i32 %X) {
; CHECK-LABEL: @test12(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 3
; CHECK-NEXT: ret i32 [[AND]]
;
%cmp = icmp ult i32 %X, 4
%and = and i32 %X, 3
%cond = select i1 %cmp, i32 %X, i32 %and
ret i32 %cond
}
; Same as above, but the compare isn't canonical
define i32 @test12noncanon(i32 %X) {
; CHECK-LABEL: @test12noncanon(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 3
; CHECK-NEXT: ret i32 [[AND]]
;
%cmp = icmp ule i32 %X, 3
%and = and i32 %X, 3
%cond = select i1 %cmp, i32 %X, i32 %and
ret i32 %cond
}
define i32 @test13(i32 %X) {
; CHECK-LABEL: @test13(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 3
; CHECK-NEXT: ret i32 [[AND]]
;
%cmp = icmp ugt i32 %X, 3
%and = and i32 %X, 3
%cond = select i1 %cmp, i32 %and, i32 %X
ret i32 %cond
}
; Same as above, but the compare isn't canonical
define i32 @test13noncanon(i32 %X) {
; CHECK-LABEL: @test13noncanon(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 3
; CHECK-NEXT: ret i32 [[AND]]
;
%cmp = icmp uge i32 %X, 4
%and = and i32 %X, 3
%cond = select i1 %cmp, i32 %and, i32 %X
ret i32 %cond
}
define i32 @select_icmp_and_8_eq_0_or_8(i32 %x) {
; CHECK-LABEL: @select_icmp_and_8_eq_0_or_8(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], 8
; CHECK-NEXT: ret i32 [[OR]]
;
%and = and i32 %x, 8
%cmp = icmp eq i32 %and, 0
%or = or i32 %x, 8
%sel = select i1 %cmp, i32 %or, i32 %x
ret i32 %sel
}
define i32 @select_icmp_and_8_eq_0_or_8_alt(i32 %x) {
; CHECK-LABEL: @select_icmp_and_8_eq_0_or_8_alt(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], 8
; CHECK-NEXT: ret i32 [[OR]]
;
%and = and i32 %x, 8
%cmp = icmp ne i32 %and, 0
%or = or i32 %x, 8
%sel = select i1 %cmp, i32 %x, i32 %or
ret i32 %sel
}
define i32 @select_icmp_and_8_ne_0_or_8(i32 %x) {
; CHECK-LABEL: @select_icmp_and_8_ne_0_or_8(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%and = and i32 %x, 8
%cmp = icmp ne i32 %and, 0
%or = or i32 %x, 8
%sel = select i1 %cmp, i32 %or, i32 %x
ret i32 %sel
}
define i32 @select_icmp_and_8_ne_0_or_8_alt(i32 %x) {
; CHECK-LABEL: @select_icmp_and_8_ne_0_or_8_alt(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%and = and i32 %x, 8
%cmp = icmp eq i32 %and, 0
%or = or i32 %x, 8
%sel = select i1 %cmp, i32 %x, i32 %or
ret i32 %sel
}
define i32 @select_icmp_and_8_eq_0_and_not_8(i32 %x) {
; CHECK-LABEL: @select_icmp_and_8_eq_0_and_not_8(
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[X:%.*]], -9
; CHECK-NEXT: ret i32 [[AND1]]
;
%and = and i32 %x, 8
%cmp = icmp eq i32 %and, 0
%and1 = and i32 %x, -9
%sel = select i1 %cmp, i32 %x, i32 %and1
ret i32 %sel
}
define i32 @select_icmp_and_8_eq_0_and_not_8_alt(i32 %x) {
; CHECK-LABEL: @select_icmp_and_8_eq_0_and_not_8_alt(
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[X:%.*]], -9
; CHECK-NEXT: ret i32 [[AND1]]
;
%and = and i32 %x, 8
%cmp = icmp ne i32 %and, 0
%and1 = and i32 %x, -9
%sel = select i1 %cmp, i32 %and1, i32 %x
ret i32 %sel
}
define i32 @select_icmp_and_8_ne_0_and_not_8(i32 %x) {
; CHECK-LABEL: @select_icmp_and_8_ne_0_and_not_8(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%and = and i32 %x, 8
%cmp = icmp ne i32 %and, 0
%and1 = and i32 %x, -9
%sel = select i1 %cmp, i32 %x, i32 %and1
ret i32 %sel
}
define i32 @select_icmp_and_8_ne_0_and_not_8_alt(i32 %x) {
; CHECK-LABEL: @select_icmp_and_8_ne_0_and_not_8_alt(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%and = and i32 %x, 8
%cmp = icmp eq i32 %and, 0
%and1 = and i32 %x, -9
%sel = select i1 %cmp, i32 %and1, i32 %x
ret i32 %sel
}
; PR28466: https://llvm.org/bugs/show_bug.cgi?id=28466
; Each of the previous 8 patterns has a variant that replaces the
; 'and' with a 'trunc' and the icmp eq/ne with icmp slt/sgt.
define i32 @select_icmp_trunc_8_ne_0_or_128(i32 %x) {
; CHECK-LABEL: @select_icmp_trunc_8_ne_0_or_128(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], 128
; CHECK-NEXT: ret i32 [[OR]]
;
%trunc = trunc i32 %x to i8
%cmp = icmp sgt i8 %trunc, -1
%or = or i32 %x, 128
%sel = select i1 %cmp, i32 %or, i32 %x
ret i32 %sel
}
define i32 @select_icmp_trunc_8_ne_0_or_128_alt(i32 %x) {
; CHECK-LABEL: @select_icmp_trunc_8_ne_0_or_128_alt(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], 128
; CHECK-NEXT: ret i32 [[OR]]
;
%trunc = trunc i32 %x to i8
%cmp = icmp slt i8 %trunc, 0
%or = or i32 %x, 128
%sel = select i1 %cmp, i32 %x, i32 %or
ret i32 %sel
}
define i32 @select_icmp_trunc_8_eq_0_or_128(i32 %x) {
; CHECK-LABEL: @select_icmp_trunc_8_eq_0_or_128(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%trunc = trunc i32 %x to i8
%cmp = icmp slt i8 %trunc, 0
%or = or i32 %x, 128
%sel = select i1 %cmp, i32 %or, i32 %x
ret i32 %sel
}
define i32 @select_icmp_trunc_8_eq_0_or_128_alt(i32 %x) {
; CHECK-LABEL: @select_icmp_trunc_8_eq_0_or_128_alt(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%trunc = trunc i32 %x to i8
%cmp = icmp sgt i8 %trunc, -1
%or = or i32 %x, 128
%sel = select i1 %cmp, i32 %x, i32 %or
ret i32 %sel
}
define i32 @select_icmp_trunc_8_eq_0_and_not_8(i32 %x) {
; CHECK-LABEL: @select_icmp_trunc_8_eq_0_and_not_8(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], -9
; CHECK-NEXT: ret i32 [[AND]]
;
%trunc = trunc i32 %x to i4
%cmp = icmp sgt i4 %trunc, -1
%and = and i32 %x, -9
%sel = select i1 %cmp, i32 %x, i32 %and
ret i32 %sel
}
define i32 @select_icmp_trunc_8_eq_0_and_not_8_alt(i32 %x) {
; CHECK-LABEL: @select_icmp_trunc_8_eq_0_and_not_8_alt(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], -9
; CHECK-NEXT: ret i32 [[AND]]
;
%trunc = trunc i32 %x to i4
%cmp = icmp slt i4 %trunc, 0
%and = and i32 %x, -9
%sel = select i1 %cmp, i32 %and, i32 %x
ret i32 %sel
}
define i32 @select_icmp_trunc_8_ne_0_and_not_8(i32 %x) {
; CHECK-LABEL: @select_icmp_trunc_8_ne_0_and_not_8(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%trunc = trunc i32 %x to i4
%cmp = icmp slt i4 %trunc, 0
%and = and i32 %x, -9
%sel = select i1 %cmp, i32 %x, i32 %and
ret i32 %sel
}
define i32 @select_icmp_trunc_8_ne_0_and_not_8_alt(i32 %x) {
; CHECK-LABEL: @select_icmp_trunc_8_ne_0_and_not_8_alt(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%trunc = trunc i32 %x to i4
%cmp = icmp sgt i4 %trunc, -1
%and = and i32 %x, -9
%sel = select i1 %cmp, i32 %and, i32 %x
ret i32 %sel
}
; Make sure that at least a few of the same patterns are repeated with vector types.
define <2 x i32> @select_icmp_and_8_ne_0_and_not_8_vec(<2 x i32> %x) {
; CHECK-LABEL: @select_icmp_and_8_ne_0_and_not_8_vec(
; CHECK-NEXT: ret <2 x i32> [[X:%.*]]
;
%and = and <2 x i32> %x, <i32 8, i32 8>
%cmp = icmp ne <2 x i32> %and, zeroinitializer
%and1 = and <2 x i32> %x, <i32 -9, i32 -9>
%sel = select <2 x i1> %cmp, <2 x i32> %x, <2 x i32> %and1
ret <2 x i32> %sel
}
define <2 x i32> @select_icmp_trunc_8_ne_0_and_not_8_alt_vec(<2 x i32> %x) {
; CHECK-LABEL: @select_icmp_trunc_8_ne_0_and_not_8_alt_vec(
; CHECK-NEXT: ret <2 x i32> [[X:%.*]]
;
%trunc = trunc <2 x i32> %x to <2 x i4>
%cmp = icmp sgt <2 x i4> %trunc, <i4 -1, i4 -1>
%and = and <2 x i32> %x, <i32 -9, i32 -9>
%sel = select <2 x i1> %cmp, <2 x i32> %and, <2 x i32> %x
ret <2 x i32> %sel
}
; Insert a bit from x into y? This should be possible in InstCombine, but not InstSimplify?
define i32 @select_icmp_x_and_8_eq_0_y_and_not_8(i32 %x, i32 %y) {
; CHECK-LABEL: @select_icmp_x_and_8_eq_0_y_and_not_8(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 8
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y:%.*]], -9
; CHECK-NEXT: [[Y_AND1:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[AND1]]
; CHECK-NEXT: ret i32 [[Y_AND1]]
;
%and = and i32 %x, 8
%cmp = icmp eq i32 %and, 0
%and1 = and i32 %y, -9
%y.and1 = select i1 %cmp, i32 %y, i32 %and1
ret i32 %y.and1
}
define i64 @select_icmp_x_and_8_eq_0_y64_and_not_8(i32 %x, i64 %y) {
; CHECK-LABEL: @select_icmp_x_and_8_eq_0_y64_and_not_8(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 8
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
; CHECK-NEXT: [[AND1:%.*]] = and i64 [[Y:%.*]], -9
; CHECK-NEXT: [[Y_AND1:%.*]] = select i1 [[CMP]], i64 [[Y]], i64 [[AND1]]
; CHECK-NEXT: ret i64 [[Y_AND1]]
;
%and = and i32 %x, 8
%cmp = icmp eq i32 %and, 0
%and1 = and i64 %y, -9
%y.and1 = select i1 %cmp, i64 %y, i64 %and1
ret i64 %y.and1
}
define i64 @select_icmp_x_and_8_ne_0_y64_and_not_8(i32 %x, i64 %y) {
; CHECK-LABEL: @select_icmp_x_and_8_ne_0_y64_and_not_8(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 8
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
; CHECK-NEXT: [[AND1:%.*]] = and i64 [[Y:%.*]], -9
; CHECK-NEXT: [[AND1_Y:%.*]] = select i1 [[CMP]], i64 [[AND1]], i64 [[Y]]
; CHECK-NEXT: ret i64 [[AND1_Y]]
;
%and = and i32 %x, 8
%cmp = icmp eq i32 %and, 0
%and1 = and i64 %y, -9
%and1.y = select i1 %cmp, i64 %and1, i64 %y
ret i64 %and1.y
}
; Don't crash on a pointer or aggregate type.
define ptr @select_icmp_pointers(ptr %x, ptr %y) {
; CHECK-LABEL: @select_icmp_pointers(
; CHECK-NEXT: [[CMP:%.*]] = icmp slt ptr [[X:%.*]], null
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], ptr [[X]], ptr [[Y:%.*]]
; CHECK-NEXT: ret ptr [[SEL]]
;
%cmp = icmp slt ptr %x, null
%sel = select i1 %cmp, ptr %x, ptr %y
ret ptr %sel
}
; If the condition is known, we don't need to select, but we're not
; doing this fold here to avoid compile-time cost.
declare void @llvm.assume(i1)
define i8 @assume_sel_cond(i1 %cond, i8 %x, i8 %y) {
; CHECK-LABEL: @assume_sel_cond(
; CHECK-NEXT: call void @llvm.assume(i1 [[COND:%.*]])
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND]], i8 [[X:%.*]], i8 [[Y:%.*]]
; CHECK-NEXT: ret i8 [[SEL]]
;
call void @llvm.assume(i1 %cond)
%sel = select i1 %cond, i8 %x, i8 %y
ret i8 %sel
}
define i8 @do_not_assume_sel_cond(i1 %cond, i8 %x, i8 %y) {
; CHECK-LABEL: @do_not_assume_sel_cond(
; CHECK-NEXT: [[NOTCOND:%.*]] = icmp eq i1 [[COND:%.*]], false
; CHECK-NEXT: call void @llvm.assume(i1 [[NOTCOND]])
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND]], i8 [[X:%.*]], i8 [[Y:%.*]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%notcond = icmp eq i1 %cond, false
call void @llvm.assume(i1 %notcond)
%sel = select i1 %cond, i8 %x, i8 %y
ret i8 %sel
}
define ptr @select_icmp_eq_0_gep_operand(ptr %base, i64 %n) {
; CHECK-LABEL: @select_icmp_eq_0_gep_operand(
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[BASE:%.*]], i64 [[N:%.*]]
; CHECK-NEXT: ret ptr [[GEP]]
;
%cond = icmp eq i64 %n, 0
%gep = getelementptr i32, ptr %base, i64 %n
%r = select i1 %cond, ptr %base, ptr %gep
ret ptr %r
}
define ptr @select_icmp_ne_0_gep_operand(ptr %base, i64 %n) {
; CHECK-LABEL: @select_icmp_ne_0_gep_operand(
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[BASE:%.*]], i64 [[N:%.*]]
; CHECK-NEXT: ret ptr [[GEP]]
;
%cond = icmp ne i64 %n, 0
%gep = getelementptr i32, ptr %base, i64 %n
%r = select i1 %cond, ptr %gep, ptr %base
ret ptr %r
}
define i1 @and_cmps(i32 %x) {
; CHECK-LABEL: @and_cmps(
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[X:%.*]], 92
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[X]], 11
; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false
; CHECK-NEXT: ret i1 [[R]]
;
%cmp1 = icmp slt i32 %x, 92
%cmp2 = icmp slt i32 %x, 11
%r = select i1 %cmp1, i1 %cmp2, i1 false
ret i1 %r
}
define <2 x i1> @and_cmps_vector(<2 x i32> %x) {
; CHECK-LABEL: @and_cmps_vector(
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt <2 x i32> [[X:%.*]], <i32 92, i32 92>
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt <2 x i32> [[X]], <i32 11, i32 11>
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[CMP1]], <2 x i1> [[CMP2]], <2 x i1> zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%cmp1 = icmp slt <2 x i32> %x, <i32 92, i32 92>
%cmp2 = icmp slt <2 x i32> %x, <i32 11, i32 11>
%r = select <2 x i1> %cmp1, <2 x i1> %cmp2, <2 x i1> <i1 false, i1 false>
ret <2 x i1> %r
}
define i1 @or_cmps(float %x) {
; CHECK-LABEL: @or_cmps(
; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno float [[X:%.*]], 4.200000e+01
; CHECK-NEXT: [[CMP2:%.*]] = fcmp uno float [[X]], 5.200000e+01
; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP2]]
; CHECK-NEXT: ret i1 [[R]]
;
%cmp1 = fcmp uno float %x, 42.0
%cmp2 = fcmp uno float %x, 52.0
%r = select i1 %cmp1, i1 true, i1 %cmp2
ret i1 %r
}
define <2 x i1> @or_logic_vector(<2 x i1> %x, <2 x i1> %y) {
; CHECK-LABEL: @or_logic_vector(
; CHECK-NEXT: ret <2 x i1> [[X:%.*]]
;
%a = and <2 x i1> %x, %y
%r = select <2 x i1> %x, <2 x i1> <i1 true, i1 true>, <2 x i1> %a
ret <2 x i1> %r
}
define i1 @and_not_cmps(i32 %x) {
; CHECK-LABEL: @and_not_cmps(
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[X:%.*]], 92
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[X]], 11
; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], i1 false, i1 [[CMP2]]
; CHECK-NEXT: ret i1 [[R]]
;
%cmp1 = icmp slt i32 %x, 92
%cmp2 = icmp slt i32 %x, 11
%r = select i1 %cmp1, i1 false, i1 %cmp2
ret i1 %r
}
define i1 @or_not_cmps(i32 %x) {
; CHECK-LABEL: @or_not_cmps(
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[X:%.*]], 92
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[X]], 11
; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 true
; CHECK-NEXT: ret i1 [[R]]
;
%cmp1 = icmp slt i32 %x, 92
%cmp2 = icmp slt i32 %x, 11
%r = select i1 %cmp1, i1 %cmp2, i1 true
ret i1 %r
}
define i8 @and_cmps_wrong_type(i32 %x) {
; CHECK-LABEL: @and_cmps_wrong_type(
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[X:%.*]], 92
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[X]], 11
; CHECK-NEXT: [[S:%.*]] = sext i1 [[CMP2]] to i8
; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], i8 [[S]], i8 0
; CHECK-NEXT: ret i8 [[R]]
;
%cmp1 = icmp slt i32 %x, 92
%cmp2 = icmp slt i32 %x, 11
%s = sext i1 %cmp2 to i8
%r = select i1 %cmp1, i8 %s, i8 0
ret i8 %r
}
define i1 @y_might_be_poison(float %x, float %y) {
; CHECK-LABEL: @y_might_be_poison(
; CHECK-NEXT: [[C1:%.*]] = fcmp ord float 0.000000e+00, [[X:%.*]]
; CHECK-NEXT: [[C2:%.*]] = fcmp ord float [[X]], [[Y:%.*]]
; CHECK-NEXT: [[C3:%.*]] = select i1 [[C1]], i1 [[C2]], i1 false
; CHECK-NEXT: ret i1 [[C3]]
;
%c1 = fcmp ord float 0.0, %x
%c2 = fcmp ord float %x, %y
%c3 = select i1 %c1, i1 %c2, i1 false
ret i1 %c3
}
; Negative tests to ensure we don't remove selects with undef true/false values.
; See https://bugs.llvm.org/show_bug.cgi?id=31633
; https://lists.llvm.org/pipermail/llvm-dev/2016-October/106182.html
; https://reviews.llvm.org/D83360
define i32 @false_undef(i1 %cond, i32 %x) {
; CHECK-LABEL: @false_undef(
; CHECK-NEXT: [[S:%.*]] = select i1 [[COND:%.*]], i32 [[X:%.*]], i32 undef
; CHECK-NEXT: ret i32 [[S]]
;
%s = select i1 %cond, i32 %x, i32 undef
ret i32 %s
}
define i32 @true_undef(i1 %cond, i32 %x) {
; CHECK-LABEL: @true_undef(
; CHECK-NEXT: [[S:%.*]] = select i1 [[COND:%.*]], i32 undef, i32 [[X:%.*]]
; CHECK-NEXT: ret i32 [[S]]
;
%s = select i1 %cond, i32 undef, i32 %x
ret i32 %s
}
define <2 x i32> @false_undef_vec(i1 %cond, <2 x i32> %x) {
; CHECK-LABEL: @false_undef_vec(
; CHECK-NEXT: [[S:%.*]] = select i1 [[COND:%.*]], <2 x i32> [[X:%.*]], <2 x i32> undef
; CHECK-NEXT: ret <2 x i32> [[S]]
;
%s = select i1 %cond, <2 x i32> %x, <2 x i32> undef
ret <2 x i32> %s
}
define <2 x i32> @true_undef_vec(i1 %cond, <2 x i32> %x) {
; CHECK-LABEL: @true_undef_vec(
; CHECK-NEXT: [[S:%.*]] = select i1 [[COND:%.*]], <2 x i32> undef, <2 x i32> [[X:%.*]]
; CHECK-NEXT: ret <2 x i32> [[S]]
;
%s = select i1 %cond, <2 x i32> undef, <2 x i32> %x
ret <2 x i32> %s
}
; These can be folded because the other value is guaranteed not to be poison.
define i32 @false_undef_true_constant(i1 %cond) {
; CHECK-LABEL: @false_undef_true_constant(
; CHECK-NEXT: ret i32 10
;
%s = select i1 %cond, i32 10, i32 undef
ret i32 %s
}
define i32 @true_undef_false_constant(i1 %cond) {
; CHECK-LABEL: @true_undef_false_constant(
; CHECK-NEXT: ret i32 20
;
%s = select i1 %cond, i32 undef, i32 20
ret i32 %s
}
define <2 x i32> @false_undef_true_constant_vec(i1 %cond) {
; CHECK-LABEL: @false_undef_true_constant_vec(
; CHECK-NEXT: ret <2 x i32> <i32 42, i32 -42>
;
%s = select i1 %cond, <2 x i32> <i32 42, i32 -42>, <2 x i32> undef
ret <2 x i32> %s
}
define <2 x i32> @true_undef_false_constant_vec(i1 %cond) {
; CHECK-LABEL: @true_undef_false_constant_vec(
; CHECK-NEXT: ret <2 x i32> <i32 -42, i32 42>
;
%s = select i1 %cond, <2 x i32> undef, <2 x i32> <i32 -42, i32 42>
ret <2 x i32> %s
}
; If one input is undef and the other is freeze, we can fold it to the freeze.
define i32 @false_undef_true_freeze(i1 %cond, i32 %x) {
; CHECK-LABEL: @false_undef_true_freeze(
; CHECK-NEXT: [[XF:%.*]] = freeze i32 [[X:%.*]]
; CHECK-NEXT: ret i32 [[XF]]
;
%xf = freeze i32 %x
%s = select i1 %cond, i32 %xf, i32 undef
ret i32 %s
}
define i32 @false_undef_false_freeze(i1 %cond, i32 %x) {
; CHECK-LABEL: @false_undef_false_freeze(
; CHECK-NEXT: [[XF:%.*]] = freeze i32 [[X:%.*]]
; CHECK-NEXT: ret i32 [[XF]]
;
%xf = freeze i32 %x
%s = select i1 %cond, i32 undef, i32 %xf
ret i32 %s
}
@g = external global i32, align 1
define <2 x i32> @false_undef_true_constextpr_vec(i1 %cond) {
; CHECK-LABEL: @false_undef_true_constextpr_vec(
; CHECK-NEXT: ret <2 x i32> <i32 ptrtoint (ptr @g to i32), i32 ptrtoint (ptr @g to i32)>
;
%s = select i1 %cond, <2 x i32> <i32 undef, i32 ptrtoint (ptr @g to i32)>, <2 x i32> <i32 ptrtoint (ptr @g to i32), i32 undef>
ret <2 x i32> %s
}
define i32 @all_constant_true_undef() {
; CHECK-LABEL: @all_constant_true_undef(
; CHECK-NEXT: ret i32 1
;
%s = select i1 ptrtoint (ptr @all_constant_true_undef to i1), i32 undef, i32 1
ret i32 %s
}
define float @all_constant_false_undef() {
; CHECK-LABEL: @all_constant_false_undef(
; CHECK-NEXT: ret float 1.000000e+00
;
%s = select i1 ptrtoint (ptr @all_constant_false_undef to i1), float undef, float 1.0
ret float %s
}
define <2 x i32> @all_constant_true_undef_vec() {
; CHECK-LABEL: @all_constant_true_undef_vec(
; CHECK-NEXT: ret <2 x i32> <i32 1, i32 -1>
;
%s = select i1 ptrtoint (ptr @all_constant_true_undef_vec to i1), <2 x i32> undef, <2 x i32> <i32 1, i32 -1>
ret <2 x i32> %s
}
define <2 x float> @all_constant_false_undef_vec() {
; CHECK-LABEL: @all_constant_false_undef_vec(
; CHECK-NEXT: ret <2 x float> <float 1.000000e+00, float -1.000000e+00>
;
%s = select i1 ptrtoint (ptr @all_constant_false_undef_vec to i1), <2 x float> undef, <2 x float> <float 1.0, float -1.0>
ret <2 x float> %s
}
; Negative tests. Don't fold if the non-undef operand is a constexpr.
define i32 @all_constant_false_undef_true_constexpr() {
; CHECK-LABEL: @all_constant_false_undef_true_constexpr(
; CHECK-NEXT: ret i32 ptrtoint (ptr @all_constant_false_undef_true_constexpr to i32)
;
%s = select i1 ptrtoint (ptr @all_constant_false_undef_true_constexpr to i1), i32 ptrtoint (ptr @all_constant_false_undef_true_constexpr to i32), i32 undef
ret i32 %s
}
define i32 @all_constant_true_undef_false_constexpr() {
; CHECK-LABEL: @all_constant_true_undef_false_constexpr(
; CHECK-NEXT: ret i32 ptrtoint (ptr @all_constant_true_undef_false_constexpr to i32)
;
%s = select i1 ptrtoint (ptr @all_constant_true_undef_false_constexpr to i1), i32 undef, i32 ptrtoint (ptr @all_constant_true_undef_false_constexpr to i32)
ret i32 %s
}
; Negative tests. Don't fold if the non-undef operand is a vector containing a constexpr.
define <2 x i32> @all_constant_false_undef_true_constexpr_vec() {
; CHECK-LABEL: @all_constant_false_undef_true_constexpr_vec(
; CHECK-NEXT: ret <2 x i32> <i32 ptrtoint (ptr @all_constant_false_undef_true_constexpr_vec to i32), i32 -1>
;
%s = select i1 ptrtoint (ptr @all_constant_false_undef_true_constexpr_vec to i1), <2 x i32> <i32 ptrtoint (ptr @all_constant_false_undef_true_constexpr_vec to i32), i32 -1>, <2 x i32> undef
ret <2 x i32> %s
}
define <2 x i32> @all_constant_true_undef_false_constexpr_vec() {
; CHECK-LABEL: @all_constant_true_undef_false_constexpr_vec(
; CHECK-NEXT: ret <2 x i32> <i32 -1, i32 ptrtoint (ptr @all_constant_true_undef_false_constexpr_vec to i32)>
;
%s = select i1 ptrtoint (ptr @all_constant_true_undef_false_constexpr_vec to i1), <2 x i32> undef, <2 x i32><i32 -1, i32 ptrtoint (ptr @all_constant_true_undef_false_constexpr_vec to i32)>
ret <2 x i32> %s
}
define i1 @expand_binop_undef(i32 %x, i32 %y) {
; CHECK-LABEL: @expand_binop_undef(
; CHECK-NEXT: [[CMP15:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[CMP15]]
;
%cmp9.not.1 = icmp eq i32 %x, %y
%cmp15 = icmp slt i32 %x, %y
%spec.select39 = select i1 %cmp9.not.1, i1 undef, i1 %cmp15
%spec.select40 = xor i1 %cmp9.not.1, 1
%spec.select = and i1 %spec.select39, %spec.select40
ret i1 %spec.select
}
define i32 @pr47322_more_poisonous_replacement(i32 %arg) {
; CHECK-LABEL: @pr47322_more_poisonous_replacement(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[ARG:%.*]], 0
; CHECK-NEXT: [[TRAILING:%.*]] = call i32 @llvm.cttz.i32(i32 [[ARG]], i1 true)
; CHECK-NEXT: [[SHIFTED:%.*]] = lshr i32 [[ARG]], [[TRAILING]]
; CHECK-NEXT: [[R1_SROA_0_1:%.*]] = select i1 [[CMP]], i32 0, i32 [[SHIFTED]]
; CHECK-NEXT: ret i32 [[R1_SROA_0_1]]
;
%cmp = icmp eq i32 %arg, 0
%trailing = call i32 @llvm.cttz.i32(i32 %arg, i1 true)
%shifted = lshr i32 %arg, %trailing
%r1.sroa.0.1 = select i1 %cmp, i32 0, i32 %shifted
ret i32 %r1.sroa.0.1
}
declare i32 @llvm.cttz.i32(i32, i1 immarg)
; Partial undef scalable vectors should be ignored.
define <vscale x 2 x i1> @ignore_scalable_undef(<vscale x 2 x i1> %cond) {
; CHECK-LABEL: @ignore_scalable_undef(
; CHECK-NEXT: ret <vscale x 2 x i1> insertelement (<vscale x 2 x i1> undef, i1 true, i32 0)
;
%vec = insertelement <vscale x 2 x i1> undef, i1 true, i32 0
%s = select <vscale x 2 x i1> %cond, <vscale x 2 x i1> undef, <vscale x 2 x i1> %vec
ret <vscale x 2 x i1> %s
}
define i32 @select_neutral_add_rhs(i32 %x, i32 %y) {
; CHECK-LABEL: @select_neutral_add_rhs(
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i32 [[ADD]]
;
%cmp = icmp ne i32 %y, 0
%add = add i32 %x, %y
%sel = select i1 %cmp, i32 %add, i32 %x
ret i32 %sel
}
define i32 @select_neutral_add_lhs(i32 %x, i32 %y) {
; CHECK-LABEL: @select_neutral_add_lhs(
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: ret i32 [[ADD]]
;
%cmp = icmp ne i32 %y, 0
%add = add i32 %y, %x
%sel = select i1 %cmp, i32 %add, i32 %x
ret i32 %sel
}
define <2 x i32> @select_neutral_add_rhs_vec(<2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @select_neutral_add_rhs_vec(
; CHECK-NEXT: [[ADD:%.*]] = add <2 x i32> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x i32> [[ADD]]
;
%cmp = icmp ne <2 x i32> %y, zeroinitializer
%add = add <2 x i32> %x, %y
%sel = select <2 x i1> %cmp, <2 x i32> %add, <2 x i32> %x
ret <2 x i32> %sel
}
define <2 x i32> @select_neutral_add_lhs_vec(<2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @select_neutral_add_lhs_vec(
; CHECK-NEXT: [[ADD:%.*]] = add <2 x i32> [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: ret <2 x i32> [[ADD]]
;
%cmp = icmp ne <2 x i32> %y, zeroinitializer
%add = add <2 x i32> %y, %x
%sel = select <2 x i1> %cmp, <2 x i32> %add, <2 x i32> %x
ret <2 x i32> %sel
}
define i32 @select_neutral_sub_rhs(i32 %x, i32 %y) {
; CHECK-LABEL: @select_neutral_sub_rhs(
; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i32 [[ADD]]
;
%cmp = icmp ne i32 %y, 0
%add = sub i32 %x, %y
%sel = select i1 %cmp, i32 %add, i32 %x
ret i32 %sel
}
define i32 @select_neutral_sub_lhs(i32 %x, i32 %y) {
; CHECK-LABEL: @select_neutral_sub_lhs(
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[Y:%.*]], 0
; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[Y]], [[X:%.*]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[ADD]], i32 [[X]]
; CHECK-NEXT: ret i32 [[SEL]]
;
%cmp = icmp ne i32 %y, 0
%add = sub i32 %y, %x
%sel = select i1 %cmp, i32 %add, i32 %x
ret i32 %sel
}
define i32 @select_ctpop_zero(i32 %x) {
; CHECK-LABEL: @select_ctpop_zero(
; CHECK-NEXT: [[T1:%.*]] = call i32 @llvm.ctpop.i32(i32 [[X:%.*]])
; CHECK-NEXT: ret i32 [[T1]]
;
%t0 = icmp eq i32 %x, 0
%t1 = call i32 @llvm.ctpop.i32(i32 %x)
%sel = select i1 %t0, i32 0, i32 %t1
ret i32 %sel
}
; FIXME: This is safe to fold.
define <2 x i32> @select_ctpop_zero_vec(<2 x i32> %x) {
; CHECK-LABEL: @select_ctpop_zero_vec(
; CHECK-NEXT: [[T0:%.*]] = icmp eq <2 x i32> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[T1:%.*]] = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> [[X]])
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[T0]], <2 x i32> zeroinitializer, <2 x i32> [[T1]]
; CHECK-NEXT: ret <2 x i32> [[SEL]]
;
%t0 = icmp eq <2 x i32> %x, zeroinitializer
%t1 = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> %x)
%sel = select <2 x i1> %t0, <2 x i32> zeroinitializer, <2 x i32> %t1
ret <2 x i32> %sel
}
; Negative test: Cannot fold due to cross-lane intrinsic.
define <2 x i32> @select_vector_reverse(<2 x i32> %x) {
; CHECK-LABEL: @select_vector_reverse(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[REV:%.*]] = call <2 x i32> @llvm.vector.reverse.v2i32(<2 x i32> [[X]])
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i32> zeroinitializer, <2 x i32> [[REV]]
; CHECK-NEXT: ret <2 x i32> [[SEL]]
;
%cmp = icmp eq <2 x i32> %x, zeroinitializer
%rev = call <2 x i32> @llvm.vector.reverse.v2i32(<2 x i32> %x)
%sel = select <2 x i1> %cmp, <2 x i32> zeroinitializer, <2 x i32> %rev
ret <2 x i32> %sel
}
declare i32 @llvm.ctpop.i32(i32)
declare <2 x i32> @llvm.ctpop.v2i32(<2 x i32>)
declare <2 x i32> @llvm.vector.reverse.v2i32(<2 x i32>)
define <2 x i32> @vec_select_no_equivalence(<2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @vec_select_no_equivalence(
; CHECK-NEXT: [[X10:%.*]] = shufflevector <2 x i32> [[X:%.*]], <2 x i32> undef, <2 x i32> <i32 1, i32 0>
; CHECK-NEXT: [[COND:%.*]] = icmp eq <2 x i32> [[X]], zeroinitializer
; CHECK-NEXT: [[S:%.*]] = select <2 x i1> [[COND]], <2 x i32> [[X10]], <2 x i32> zeroinitializer
; CHECK-NEXT: ret <2 x i32> [[S]]
;
%x10 = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> <i32 1, i32 0>
%cond = icmp eq <2 x i32> %x, zeroinitializer
%s = select <2 x i1> %cond, <2 x i32> %x10, <2 x i32> zeroinitializer
ret <2 x i32> %s
}
define i8 @select_eq_xor_recursive(i8 %a, i8 %b) {
; CHECK-LABEL: @select_eq_xor_recursive(
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[INV:%.*]] = xor i8 [[XOR]], -1
; CHECK-NEXT: ret i8 [[INV]]
;
%xor = xor i8 %a, %b
%inv = xor i8 %xor, -1
%cmp = icmp eq i8 %a, %b
%sel = select i1 %cmp, i8 -1, i8 %inv
ret i8 %sel
}
define i8 @select_eq_xor_recursive2(i8 %a, i8 %b) {
; CHECK-LABEL: @select_eq_xor_recursive2(
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[INV:%.*]] = xor i8 [[XOR]], -1
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[INV]], 10
; CHECK-NEXT: ret i8 [[ADD]]
;
%xor = xor i8 %a, %b
%inv = xor i8 %xor, -1
%add = add i8 %inv, 10
%cmp = icmp eq i8 %a, %b
%sel = select i1 %cmp, i8 9, i8 %add
ret i8 %sel
}
define i8 @select_eq_xor_recursive3(i8 %a, i8 %b) {
; CHECK-LABEL: @select_eq_xor_recursive3(
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[INV:%.*]] = xor i8 [[XOR]], -1
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[INV]], 10
; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[ADD]], 3
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[A]], [[B]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 9, i8 [[MUL]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%xor = xor i8 %a, %b
%inv = xor i8 %xor, -1
%add = add i8 %inv, 10
%mul = mul i8 %add, 3
%cmp = icmp eq i8 %a, %b
%sel = select i1 %cmp, i8 9, i8 %mul
ret i8 %sel
}
; Cannot drop select, because this would propagate poison from %a.
define i8 @select_eq_xor_recursive_propagates_poison(i8 %a, i8 %b) {
; CHECK-LABEL: @select_eq_xor_recursive_propagates_poison(
; CHECK-NEXT: [[XOR1:%.*]] = add i8 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[A]], [[XOR1]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[B]], 0
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 0, i8 [[XOR2]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%xor1 = add i8 %a, %b
%xor2 = xor i8 %a, %xor1
%cmp = icmp eq i8 %b, 0
%sel = select i1 %cmp, i8 0, i8 %xor2
ret i8 %sel
}
define i8 @select_eq_and_recursive(i8 %a) {
; CHECK-LABEL: @select_eq_and_recursive(
; CHECK-NEXT: [[NEG:%.*]] = sub i8 0, [[A:%.*]]
; CHECK-NEXT: [[AND:%.*]] = and i8 [[NEG]], [[A]]
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[AND]], 1
; CHECK-NEXT: ret i8 [[ADD]]
;
%neg = sub i8 0, %a
%and = and i8 %neg, %a
%add = add i8 %and, 1
%cmp = icmp eq i8 %a, 0
%sel = select i1 %cmp, i8 1, i8 %add
ret i8 %sel
}
; Cannot drop select, because this would propagate poison from %b.
define i8 @select_eq_and_recursive_propagates_poison(i8 %a, i8 %b) {
; CHECK-LABEL: @select_eq_and_recursive_propagates_poison(
; CHECK-NEXT: [[NEG:%.*]] = sub i8 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: [[AND:%.*]] = and i8 [[NEG]], [[A]]
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[AND]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[A]], 0
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 1, i8 [[ADD]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%neg = sub i8 %b, %a
%and = and i8 %neg, %a
%add = add i8 %and, 1
%cmp = icmp eq i8 %a, 0
%sel = select i1 %cmp, i8 1, i8 %add
ret i8 %sel
}
define i8 @select_eq_xor_recursive_allow_refinement(i8 %a, i8 %b) {
; CHECK-LABEL: @select_eq_xor_recursive_allow_refinement(
; CHECK-NEXT: ret i8 0
;
%xor1 = add i8 %a, %b
%xor2 = xor i8 %a, %xor1
%cmp = icmp eq i8 %b, 0
%sel = select i1 %cmp, i8 %xor2, i8 0
ret i8 %sel
}
define i8 @select_eq_mul_absorber(i8 %x, i8 noundef %y) {
; CHECK-LABEL: @select_eq_mul_absorber(
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X:%.*]], -1
; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[ADD]], [[Y:%.*]]
; CHECK-NEXT: ret i8 [[MUL]]
;
%cmp = icmp eq i8 %x, 1
%add = add i8 %x, -1
%mul = mul i8 %add, %y
%sel = select i1 %cmp, i8 0, i8 %mul
ret i8 %sel
}
define i8 @select_eq_mul_not_absorber(i8 %x, i8 noundef %y) {
; CHECK-LABEL: @select_eq_mul_not_absorber(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], -1
; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[ADD]], [[Y:%.*]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 0, i8 [[MUL]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%cmp = icmp eq i8 %x, 0
%add = add i8 %x, -1
%mul = mul i8 %add, %y
%sel = select i1 %cmp, i8 0, i8 %mul
ret i8 %sel
}
; Vector to scalar options should be treated as lane-crossing.
define <2 x i8> @select_eq_vector_insert_extract(<2 x i8> %a, <2 x i8> %b) {
; CHECK-LABEL: @select_eq_vector_insert_extract(
; CHECK-NEXT: [[EXTRACT0:%.*]] = extractelement <2 x i8> [[A:%.*]], i64 0
; CHECK-NEXT: [[EXTRACT1:%.*]] = extractelement <2 x i8> [[A]], i64 1
; CHECK-NEXT: [[INSERT0:%.*]] = insertelement <2 x i8> poison, i8 [[EXTRACT1]], i64 0
; CHECK-NEXT: [[INSERT1:%.*]] = insertelement <2 x i8> [[INSERT0]], i8 [[EXTRACT0]], i64 1
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[A]], zeroinitializer
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[INSERT1]], <2 x i8> zeroinitializer
; CHECK-NEXT: ret <2 x i8> [[SEL]]
;
%extract0 = extractelement <2 x i8> %a, i64 0
%extract1 = extractelement <2 x i8> %a, i64 1
%insert0 = insertelement <2 x i8> poison, i8 %extract1, i64 0
%insert1 = insertelement <2 x i8> %insert0, i8 %extract0, i64 1
%cmp = icmp eq <2 x i8> %a, zeroinitializer
%sel = select <2 x i1> %cmp, <2 x i8> %insert1, <2 x i8> zeroinitializer
ret <2 x i8> %sel
}
define i32 @poison(i32 %x, i32 %y) {
; CHECK-LABEL: @poison(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%v = select i1 undef, i32 %x, i32 %y
ret i32 %v
}
define i32 @poison2(i1 %cond, i32 %x) {
; CHECK-LABEL: @poison2(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%v = select i1 %cond, i32 poison, i32 %x
ret i32 %v
}
define i32 @poison3(i1 %cond, i32 %x) {
; CHECK-LABEL: @poison3(
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%v = select i1 %cond, i32 %x, i32 poison
ret i32 %v
}
define <2 x i32> @poison4(<2 x i1> %cond, <2 x i32> %x) {
; CHECK-LABEL: @poison4(
; CHECK-NEXT: ret <2 x i32> [[X:%.*]]
;
%v = select <2 x i1> %cond, <2 x i32> %x, <2 x i32> poison
ret <2 x i32> %v
}
; 0 is the absorber constant for 'and'.
; The 'select' can't block extra poison because both sides of 'and' have 'x' operand.
define i8 @replace_false_op_eq_neg_and(i8 %x) {
; CHECK-LABEL: @replace_false_op_eq_neg_and(
; CHECK-NEXT: [[NEG:%.*]] = sub i8 0, [[X:%.*]]
; CHECK-NEXT: [[AND:%.*]] = and i8 [[NEG]], [[X]]
; CHECK-NEXT: ret i8 [[AND]]
;
%eq0 = icmp eq i8 %x, 0
%neg = sub i8 0, %x
%and = and i8 %neg, %x
%sel = select i1 %eq0, i8 0, i8 %and
ret i8 %sel
}
; same as above, but commute 'and'
define i8 @replace_false_op_eq_neg_and_commute(i8 %x) {
; CHECK-LABEL: @replace_false_op_eq_neg_and_commute(
; CHECK-NEXT: [[NEG:%.*]] = sub i8 0, [[X:%.*]]
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], [[NEG]]
; CHECK-NEXT: ret i8 [[AND]]
;
%eq0 = icmp eq i8 %x, 0
%neg = sub i8 0, %x
%and = and i8 %x, %neg
%sel = select i1 %eq0, i8 0, i8 %and
ret i8 %sel
}
; same as above, but swap 'select'
define i8 @replace_false_op_ne_neg_and(i8 %x) {
; CHECK-LABEL: @replace_false_op_ne_neg_and(
; CHECK-NEXT: [[NEG:%.*]] = sub i8 0, [[X:%.*]]
; CHECK-NEXT: [[AND:%.*]] = and i8 [[NEG]], [[X]]
; CHECK-NEXT: ret i8 [[AND]]
;
%ne0 = icmp ne i8 %x, 0
%neg = sub i8 0, %x
%and = and i8 %neg, %x
%sel = select i1 %ne0, i8 %and, i8 0
ret i8 %sel
}
; same as above, but commute 'and' and swap 'select'
define i8 @replace_false_op_ne_neg_and_commute(i8 %x) {
; CHECK-LABEL: @replace_false_op_ne_neg_and_commute(
; CHECK-NEXT: [[NEG:%.*]] = sub i8 0, [[X:%.*]]
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], [[NEG]]
; CHECK-NEXT: ret i8 [[AND]]
;
%ne0 = icmp ne i8 %x, 0
%neg = sub i8 0, %x
%and = and i8 %x, %neg
%sel = select i1 %ne0, i8 %and, i8 0
ret i8 %sel
}
; the first binop can be anything as long as it has the common operand
define i8 @replace_false_op_eq_dec_and(i8 %x) {
; CHECK-LABEL: @replace_false_op_eq_dec_and(
; CHECK-NEXT: [[DEC:%.*]] = add i8 [[X:%.*]], -1
; CHECK-NEXT: [[AND:%.*]] = and i8 [[DEC]], [[X]]
; CHECK-NEXT: ret i8 [[AND]]
;
%eq0 = icmp eq i8 %x, 0
%dec = add i8 %x, -1
%and = and i8 %dec, %x
%sel = select i1 %eq0, i8 0, i8 %and
ret i8 %sel
}
; mul has the same absorber constant - "0"
define i8 @replace_false_op_eq_add_mul(i8 %x) {
; CHECK-LABEL: @replace_false_op_eq_add_mul(
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X:%.*]], 42
; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[ADD]], [[X]]
; CHECK-NEXT: ret i8 [[MUL]]
;
%eq0 = icmp eq i8 %x, 0
%add = add i8 %x, 42
%mul = mul i8 %add, %x
%sel = select i1 %eq0, i8 0, i8 %mul
ret i8 %sel
}
; or has a different absorber constant = "-1"
define i8 @replace_false_op_eq_shl_or(i8 %x) {
; CHECK-LABEL: @replace_false_op_eq_shl_or(
; CHECK-NEXT: [[SHL:%.*]] = shl i8 [[X:%.*]], 3
; CHECK-NEXT: [[OR:%.*]] = or i8 [[X]], [[SHL]]
; CHECK-NEXT: ret i8 [[OR]]
;
%eq0 = icmp eq i8 %x, -1
%shl = shl i8 %x, 3
%or = or i8 %x, %shl
%sel = select i1 %eq0, i8 -1, i8 %or
ret i8 %sel
}
define i8 @replace_false_op_eq_shl_or_disjoint(i8 %x) {
; CHECK-LABEL: @replace_false_op_eq_shl_or_disjoint(
; CHECK-NEXT: [[EQ0:%.*]] = icmp eq i8 [[X:%.*]], -1
; CHECK-NEXT: [[SHL:%.*]] = shl i8 [[X]], 3
; CHECK-NEXT: [[OR:%.*]] = or disjoint i8 [[X]], [[SHL]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[EQ0]], i8 -1, i8 [[OR]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%eq0 = icmp eq i8 %x, -1
%shl = shl i8 %x, 3
%or = or disjoint i8 %x, %shl
%sel = select i1 %eq0, i8 -1, i8 %or
ret i8 %sel
}
; negative test - wrong cmp predicate
define i8 @replace_false_op_sgt_neg_and(i8 %x) {
; CHECK-LABEL: @replace_false_op_sgt_neg_and(
; CHECK-NEXT: [[EQ0:%.*]] = icmp sgt i8 [[X:%.*]], 0
; CHECK-NEXT: [[NEG:%.*]] = sub i8 0, [[X]]
; CHECK-NEXT: [[AND:%.*]] = and i8 [[NEG]], [[X]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[EQ0]], i8 0, i8 [[AND]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%eq0 = icmp sgt i8 %x, 0
%neg = sub i8 0, %x
%and = and i8 %neg, %x
%sel = select i1 %eq0, i8 0, i8 %and
ret i8 %sel
}
; negative test - the binop must use a compare operand
define i8 @replace_false_op_eq_shl_or_wrong_cmp_op(i8 %x, i8 %y) {
; CHECK-LABEL: @replace_false_op_eq_shl_or_wrong_cmp_op(
; CHECK-NEXT: [[EQ0:%.*]] = icmp eq i8 [[Y:%.*]], -1
; CHECK-NEXT: [[SHL:%.*]] = shl i8 [[X:%.*]], 3
; CHECK-NEXT: [[OR:%.*]] = or i8 [[X]], [[SHL]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[EQ0]], i8 -1, i8 [[OR]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%eq0 = icmp eq i8 %y, -1
%shl = shl i8 %x, 3
%or = or i8 %x, %shl
%sel = select i1 %eq0, i8 -1, i8 %or
ret i8 %sel
}
; negative test - can't have extra source of potential poison
define i8 @replace_false_op_eq_neg_and_leak1(i8 %x, i8 %y) {
; CHECK-LABEL: @replace_false_op_eq_neg_and_leak1(
; CHECK-NEXT: [[EQ0:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT: [[NEG:%.*]] = sub i8 0, [[Y:%.*]]
; CHECK-NEXT: [[AND:%.*]] = and i8 [[NEG]], [[X]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[EQ0]], i8 0, i8 [[AND]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%eq0 = icmp eq i8 %x, 0
%neg = sub i8 0, %y
%and = and i8 %neg, %x
%sel = select i1 %eq0, i8 0, i8 %and
ret i8 %sel
}
; negative test - can't have extra source of potential poison
define i8 @replace_false_op_eq_neg_and_leak2(i8 %x, i8 %y) {
; CHECK-LABEL: @replace_false_op_eq_neg_and_leak2(
; CHECK-NEXT: [[EQ0:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT: [[NEG:%.*]] = sub i8 0, [[X]]
; CHECK-NEXT: [[AND:%.*]] = and i8 [[NEG]], [[Y:%.*]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[EQ0]], i8 0, i8 [[AND]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%eq0 = icmp eq i8 %x, 0
%neg = sub i8 0, %x
%and = and i8 %neg, %y
%sel = select i1 %eq0, i8 0, i8 %and
ret i8 %sel
}
; negative test - can't have extra source of potential poison
define i8 @replace_false_op_eq_add_mul_leak3(i8 %x, i8 %y) {
; CHECK-LABEL: @replace_false_op_eq_add_mul_leak3(
; CHECK-NEXT: [[EQ0:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], [[Y:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[ADD]], [[X]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[EQ0]], i8 0, i8 [[MUL]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%eq0 = icmp eq i8 %x, 0
%add = add i8 %x, %y
%mul = mul i8 %add, %x
%sel = select i1 %eq0, i8 0, i8 %mul
ret i8 %sel
}
; negative test - can't have extra source of potential poison
define i8 @replace_false_op_eq_shl_or_leak4(i8 %x, i8 %y) {
; CHECK-LABEL: @replace_false_op_eq_shl_or_leak4(
; CHECK-NEXT: [[EQ0:%.*]] = icmp eq i8 [[X:%.*]], -1
; CHECK-NEXT: [[SHL:%.*]] = shl i8 [[Y:%.*]], [[X]]
; CHECK-NEXT: [[OR:%.*]] = or i8 [[X]], [[SHL]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[EQ0]], i8 -1, i8 [[OR]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%eq0 = icmp eq i8 %x, -1
%shl = shl i8 %y, %x
%or = or i8 %x, %shl
%sel = select i1 %eq0, i8 -1, i8 %or
ret i8 %sel
}
; negative test - wrong cmp constant
define i8 @replace_false_op_eq42_neg_and(i8 %x) {
; CHECK-LABEL: @replace_false_op_eq42_neg_and(
; CHECK-NEXT: [[EQ42:%.*]] = icmp eq i8 [[X:%.*]], 42
; CHECK-NEXT: [[NEG:%.*]] = sub i8 0, [[X]]
; CHECK-NEXT: [[AND:%.*]] = and i8 [[NEG]], [[X]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[EQ42]], i8 0, i8 [[AND]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%eq42 = icmp eq i8 %x, 42
%neg = sub i8 0, %x
%and = and i8 %neg, %x
%sel = select i1 %eq42, i8 0, i8 %and
ret i8 %sel
}
define ptr @select_op_replacement_in_phi(ptr %head) {
; CHECK-LABEL: @select_op_replacement_in_phi(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[CURRENT:%.*]] = phi ptr [ [[HEAD:%.*]], [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[LATCH:%.*]] ]
; CHECK-NEXT: [[PREV:%.*]] = phi ptr [ null, [[ENTRY]] ], [ [[CURRENT]], [[LATCH]] ]
; CHECK-NEXT: [[CURRENT_NULL:%.*]] = icmp eq ptr [[CURRENT]], null
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CURRENT_NULL]], ptr [[PREV]], ptr null
; CHECK-NEXT: br i1 [[CURRENT_NULL]], label [[EXIT:%.*]], label [[LATCH]]
; CHECK: latch:
; CHECK-NEXT: [[NEXT]] = load ptr, ptr [[CURRENT]], align 8
; CHECK-NEXT: br label [[LOOP]]
; CHECK: exit:
; CHECK-NEXT: ret ptr [[SEL]]
;
entry:
br label %loop
loop:
%current = phi ptr [ %head, %entry ], [ %next, %latch ]
%prev = phi ptr [ null, %entry ], [ %current, %latch ]
%current.null = icmp eq ptr %current, null
%sel = select i1 %current.null, ptr %prev, ptr null
br i1 %current.null, label %exit, label %latch
latch:
%next = load ptr, ptr %current
br label %loop
exit:
ret ptr %sel
}
define i8 @select_sub_cmp(i8 %0, i8 %1) {
; CHECK-LABEL: @select_sub_cmp(
; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i8 [[TMP1:%.*]], [[TMP0:%.*]]
; CHECK-NEXT: ret i8 [[TMP3]]
;
%3 = icmp eq i8 %1, %0
%4 = sub nsw i8 %1, %0
%5 = select i1 %3, i8 0, i8 %4
ret i8 %5
}
define <2 x i8> @select_sub_cmp_vec(<2 x i8> %0, <2 x i8> %1) {
; CHECK-LABEL: @select_sub_cmp_vec(
; CHECK-NEXT: [[TMP3:%.*]] = sub nsw <2 x i8> [[TMP1:%.*]], [[TMP0:%.*]]
; CHECK-NEXT: ret <2 x i8> [[TMP3]]
;
%3 = icmp eq <2 x i8> %1, %0
%4 = sub nsw <2 x i8> %1, %0
%5 = select <2 x i1> %3, <2 x i8> <i8 0, i8 0>, <2 x i8> %4
ret <2 x i8> %5
}
define i8 @select_sub_cmp_swap(i8 %0, i8 %1) {
; CHECK-LABEL: @select_sub_cmp_swap(
; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i8 [[TMP0:%.*]], [[TMP1:%.*]]
; CHECK-NEXT: ret i8 [[TMP3]]
;
%3 = icmp eq i8 %1, %0
%4 = sub nsw i8 %0, %1
%5 = select i1 %3, i8 0, i8 %4
ret i8 %5
}
define <2 x i8> @select_sub_cmp_vec_swap(<2 x i8> %0, <2 x i8> %1) {
; CHECK-LABEL: @select_sub_cmp_vec_swap(
; CHECK-NEXT: [[TMP3:%.*]] = sub nsw <2 x i8> [[TMP0:%.*]], [[TMP1:%.*]]
; CHECK-NEXT: ret <2 x i8> [[TMP3]]
;
%3 = icmp eq <2 x i8> %1, %0
%4 = sub nsw <2 x i8> %0, %1
%5 = select <2 x i1> %3, <2 x i8> <i8 0, i8 0>, <2 x i8> %4
ret <2 x i8> %5
}
; negative test
define i8 @select_sub_cmp_nonzero(i8 %0, i8 %1) {
; CHECK-LABEL: @select_sub_cmp_nonzero(
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i8 [[TMP1:%.*]], [[TMP0:%.*]]
; CHECK-NEXT: [[TMP4:%.*]] = sub nsw i8 [[TMP1]], [[TMP0]]
; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i8 42, i8 [[TMP4]]
; CHECK-NEXT: ret i8 [[TMP5]]
;
%3 = icmp eq i8 %1, %0
%4 = sub nsw i8 %1, %0
%5 = select i1 %3, i8 42, i8 %4
ret i8 %5
}
; X == Y ? 0 : X ^ Y --> X ^ Y, https://alive2.llvm.org/ce/z/cykffE
define i8 @select_xor_cmp(i8 %0, i8 %1) {
; CHECK-LABEL: @select_xor_cmp(
; CHECK-NEXT: [[TMP3:%.*]] = xor i8 [[TMP1:%.*]], [[TMP0:%.*]]
; CHECK-NEXT: ret i8 [[TMP3]]
;
%3 = icmp eq i8 %1, %0
%4 = xor i8 %1, %0
%5 = select i1 %3, i8 0, i8 %4
ret i8 %5
}
define <2 x i8> @select_xor_cmp_vec(<2 x i8> %0, <2 x i8> %1) {
; CHECK-LABEL: @select_xor_cmp_vec(
; CHECK-NEXT: [[TMP3:%.*]] = xor <2 x i8> [[TMP1:%.*]], [[TMP0:%.*]]
; CHECK-NEXT: ret <2 x i8> [[TMP3]]
;
%3 = icmp eq <2 x i8> %1, %0
%4 = xor <2 x i8> %1, %0
%5 = select <2 x i1> %3, <2 x i8> <i8 0, i8 0>, <2 x i8> %4
ret <2 x i8> %5
}
define i8 @select_xor_cmp_swap(i8 %0, i8 %1) {
; CHECK-LABEL: @select_xor_cmp_swap(
; CHECK-NEXT: [[TMP3:%.*]] = xor i8 [[TMP0:%.*]], [[TMP1:%.*]]
; CHECK-NEXT: ret i8 [[TMP3]]
;
%3 = icmp eq i8 %1, %0
%4 = xor i8 %0, %1
%5 = select i1 %3, i8 0, i8 %4
ret i8 %5
}
define <2 x i8> @select_xor_cmp_vec_swap(<2 x i8> %0, <2 x i8> %1) {
; CHECK-LABEL: @select_xor_cmp_vec_swap(
; CHECK-NEXT: [[TMP3:%.*]] = xor <2 x i8> [[TMP0:%.*]], [[TMP1:%.*]]
; CHECK-NEXT: ret <2 x i8> [[TMP3]]
;
%3 = icmp eq <2 x i8> %1, %0
%4 = xor <2 x i8> %0, %1
%5 = select <2 x i1> %3, <2 x i8> <i8 0, i8 0>, <2 x i8> %4
ret <2 x i8> %5
}
; Negative test: the xor operands are not %0 and %1
define i8 @select_xor_cmp_unmatched_operands(i8 %0, i8 %1, i8 %c) {
; CHECK-LABEL: @select_xor_cmp_unmatched_operands(
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i8 [[TMP1:%.*]], [[TMP0:%.*]]
; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP1]], [[C:%.*]]
; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i8 0, i8 [[TMP4]]
; CHECK-NEXT: ret i8 [[TMP5]]
;
%3 = icmp eq i8 %1, %0
%4 = xor i8 %1, %c
%5 = select i1 %3, i8 0, i8 %4
ret i8 %5
}
define i8 @select_or_eq(i8 %x, i8 %y) {
; CHECK-LABEL: @select_or_eq(
; CHECK-NEXT: [[OR:%.*]] = or i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i8 [[OR]]
;
%cmp = icmp eq i8 %x, %y
%or = or i8 %x, %y
%sel = select i1 %cmp, i8 %x, i8 %or
ret i8 %sel
}
define i8 @select_or_disjoint_eq(i8 %x, i8 %y) {
; CHECK-LABEL: @select_or_disjoint_eq(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[OR:%.*]] = or disjoint i8 [[X]], [[Y]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[X]], i8 [[OR]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%cmp = icmp eq i8 %x, %y
%or = or disjoint i8 %x, %y
%sel = select i1 %cmp, i8 %x, i8 %or
ret i8 %sel
}
define <4 x i32> @select_vector_cmp_with_bitcasts(<2 x i64> %x, <4 x i32> %y) {
; CHECK-LABEL: @select_vector_cmp_with_bitcasts(
; CHECK-NEXT: [[X_BC:%.*]] = bitcast <2 x i64> [[X:%.*]] to <4 x i32>
; CHECK-NEXT: [[Y_BC:%.*]] = bitcast <4 x i32> [[Y:%.*]] to <2 x i64>
; CHECK-NEXT: [[SUB:%.*]] = sub <2 x i64> [[X]], [[Y_BC]]
; CHECK-NEXT: [[SUB_BC:%.*]] = bitcast <2 x i64> [[SUB]] to <4 x i32>
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <4 x i32> [[Y]], [[X_BC]]
; CHECK-NEXT: [[SEL:%.*]] = select <4 x i1> [[CMP]], <4 x i32> [[SUB_BC]], <4 x i32> zeroinitializer
; CHECK-NEXT: ret <4 x i32> [[SEL]]
;
%x.bc = bitcast <2 x i64> %x to <4 x i32>
%y.bc = bitcast <4 x i32> %y to <2 x i64>
%sub = sub <2 x i64> %x, %y.bc
%sub.bc = bitcast <2 x i64> %sub to <4 x i32>
%cmp = icmp eq <4 x i32> %y, %x.bc
%sel = select <4 x i1> %cmp, <4 x i32> %sub.bc, <4 x i32> zeroinitializer
ret <4 x i32> %sel
}