mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 04:46:07 +00:00

In #88217 a large set of matchers was changed to only accept poison values in splats, but not undef values. This is because we now use poison for non-demanded vector elements, and allowing undef can cause correctness issues. This patch covers the remaining matchers by changing the AllowUndef parameter of getSplatValue() to AllowPoison instead. We also carry out corresponding renames in matchers. As a followup, we may want to change the default for things like m_APInt to m_APIntAllowPoison (as this is much less risky when only allowing poison), but this change doesn't do that. There is one caveat here: We have a single place (X86FixupVectorConstants) which does require handling of vector splats with undefs. This is because this works on backend constant pool entries, which currently still use undef instead of poison for non-demanded elements (because SDAG as a whole does not have an explicit poison representation). As it's just the single use, I've open-coded a getSplatValueAllowUndef() helper there, to discourage use in any other places.
4560 lines
144 KiB
LLVM
4560 lines
144 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
|
|
|
; PR1822
|
|
|
|
target datalayout = "e-p:64:64-p1:16:16-p2:32:32:32-p3:64:64:64"
|
|
|
|
define i1 @test5(i1 %C) {
|
|
; CHECK-LABEL: @test5(
|
|
; CHECK-NEXT: [[NOT_C:%.*]] = xor i1 [[C:%.*]], true
|
|
; CHECK-NEXT: ret i1 [[NOT_C]]
|
|
;
|
|
%V = select i1 %C, i1 false, i1 true
|
|
ret i1 %V
|
|
}
|
|
|
|
define i32 @test6(i1 %C) {
|
|
; CHECK-LABEL: @test6(
|
|
; CHECK-NEXT: [[V:%.*]] = zext i1 [[C:%.*]] to i32
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
%V = select i1 %C, i32 1, i32 0
|
|
ret i32 %V
|
|
}
|
|
|
|
define i1 @trueval_is_true(i1 %C, i1 %X) {
|
|
; CHECK-LABEL: @trueval_is_true(
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[X:%.*]]
|
|
; CHECK-NEXT: ret i1 [[R]]
|
|
;
|
|
%R = select i1 %C, i1 true, i1 %X
|
|
ret i1 %R
|
|
}
|
|
|
|
define <2 x i1> @trueval_is_true_vec(<2 x i1> %C, <2 x i1> %X) {
|
|
; CHECK-LABEL: @trueval_is_true_vec(
|
|
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[C:%.*]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i1> [[R]]
|
|
;
|
|
%R = select <2 x i1> %C, <2 x i1> <i1 true, i1 true>, <2 x i1> %X
|
|
ret <2 x i1> %R
|
|
}
|
|
|
|
define <2 x i1> @trueval_is_true_vec_poison_elt(<2 x i1> %C, <2 x i1> %X) {
|
|
; CHECK-LABEL: @trueval_is_true_vec_poison_elt(
|
|
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[C:%.*]], <2 x i1> <i1 poison, i1 true>, <2 x i1> [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i1> [[R]]
|
|
;
|
|
%R = select <2 x i1> %C, <2 x i1> <i1 poison, i1 true>, <2 x i1> %X
|
|
ret <2 x i1> %R
|
|
}
|
|
|
|
define i1 @test8(i1 %C, i1 %X) {
|
|
; CHECK-LABEL: @test8(
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[C:%.*]], i1 [[X:%.*]], i1 false
|
|
; CHECK-NEXT: ret i1 [[R]]
|
|
;
|
|
%R = select i1 %C, i1 %X, i1 false
|
|
ret i1 %R
|
|
}
|
|
|
|
define <2 x i1> @test8vec(<2 x i1> %C, <2 x i1> %X) {
|
|
; CHECK-LABEL: @test8vec(
|
|
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[C:%.*]], <2 x i1> [[X:%.*]], <2 x i1> zeroinitializer
|
|
; CHECK-NEXT: ret <2 x i1> [[R]]
|
|
;
|
|
%R = select <2 x i1> %C, <2 x i1> %X, <2 x i1> <i1 false, i1 false>
|
|
ret <2 x i1> %R
|
|
}
|
|
|
|
define <vscale x 2 x i1> @test8vvec(<vscale x 2 x i1> %C, <vscale x 2 x i1> %X) {
|
|
; CHECK-LABEL: @test8vvec(
|
|
; CHECK-NEXT: [[R:%.*]] = select <vscale x 2 x i1> [[C:%.*]], <vscale x 2 x i1> [[X:%.*]], <vscale x 2 x i1> zeroinitializer
|
|
; CHECK-NEXT: ret <vscale x 2 x i1> [[R]]
|
|
;
|
|
%R = select <vscale x 2 x i1> %C, <vscale x 2 x i1> %X, <vscale x 2 x i1> zeroinitializer
|
|
ret <vscale x 2 x i1> %R
|
|
}
|
|
|
|
define i1 @test9(i1 %C, i1 %X) {
|
|
; CHECK-LABEL: @test9(
|
|
; CHECK-NEXT: [[NOT_C:%.*]] = xor i1 [[C:%.*]], true
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[NOT_C]], i1 [[X:%.*]], i1 false
|
|
; CHECK-NEXT: ret i1 [[R]]
|
|
;
|
|
%R = select i1 %C, i1 false, i1 %X
|
|
ret i1 %R
|
|
}
|
|
|
|
define <2 x i1> @test9vec(<2 x i1> %C, <2 x i1> %X) {
|
|
; CHECK-LABEL: @test9vec(
|
|
; CHECK-NEXT: [[NOT_C:%.*]] = xor <2 x i1> [[C:%.*]], <i1 true, i1 true>
|
|
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[NOT_C]], <2 x i1> [[X:%.*]], <2 x i1> zeroinitializer
|
|
; CHECK-NEXT: ret <2 x i1> [[R]]
|
|
;
|
|
%R = select <2 x i1> %C, <2 x i1> <i1 false, i1 false>, <2 x i1> %X
|
|
ret <2 x i1> %R
|
|
}
|
|
|
|
define <vscale x 2 x i1> @test9vvec(<vscale x 2 x i1> %C, <vscale x 2 x i1> %X) {
|
|
; CHECK-LABEL: @test9vvec(
|
|
; CHECK-NEXT: [[NOT_C:%.*]] = xor <vscale x 2 x i1> [[C:%.*]], shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer)
|
|
; CHECK-NEXT: [[R:%.*]] = select <vscale x 2 x i1> [[NOT_C]], <vscale x 2 x i1> [[X:%.*]], <vscale x 2 x i1> zeroinitializer
|
|
; CHECK-NEXT: ret <vscale x 2 x i1> [[R]]
|
|
;
|
|
%R = select <vscale x 2 x i1> %C, <vscale x 2 x i1> zeroinitializer, <vscale x 2 x i1> %X
|
|
ret <vscale x 2 x i1> %R
|
|
}
|
|
|
|
define i1 @test10(i1 %C, i1 %X) {
|
|
; CHECK-LABEL: @test10(
|
|
; CHECK-NEXT: [[NOT_C:%.*]] = xor i1 [[C:%.*]], true
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[NOT_C]], i1 true, i1 [[X:%.*]]
|
|
; CHECK-NEXT: ret i1 [[R]]
|
|
;
|
|
%R = select i1 %C, i1 %X, i1 true
|
|
ret i1 %R
|
|
}
|
|
|
|
define <2 x i1> @test10vec(<2 x i1> %C, <2 x i1> %X) {
|
|
; CHECK-LABEL: @test10vec(
|
|
; CHECK-NEXT: [[NOT_C:%.*]] = xor <2 x i1> [[C:%.*]], <i1 true, i1 true>
|
|
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[NOT_C]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i1> [[R]]
|
|
;
|
|
%R = select <2 x i1> %C, <2 x i1> %X, <2 x i1> <i1 true, i1 true>
|
|
ret <2 x i1> %R
|
|
}
|
|
|
|
define i1 @test23(i1 %a, i1 %b) {
|
|
; CHECK-LABEL: @test23(
|
|
; CHECK-NEXT: [[C:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%c = select i1 %a, i1 %b, i1 %a
|
|
ret i1 %c
|
|
}
|
|
|
|
define <2 x i1> @test23vec(<2 x i1> %a, <2 x i1> %b) {
|
|
; CHECK-LABEL: @test23vec(
|
|
; CHECK-NEXT: [[C:%.*]] = select <2 x i1> [[A:%.*]], <2 x i1> [[B:%.*]], <2 x i1> zeroinitializer
|
|
; CHECK-NEXT: ret <2 x i1> [[C]]
|
|
;
|
|
%c = select <2 x i1> %a, <2 x i1> %b, <2 x i1> %a
|
|
ret <2 x i1> %c
|
|
}
|
|
|
|
define i1 @test24(i1 %a, i1 %b) {
|
|
; CHECK-LABEL: @test24(
|
|
; CHECK-NEXT: [[C:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]]
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%c = select i1 %a, i1 %a, i1 %b
|
|
ret i1 %c
|
|
}
|
|
|
|
define <2 x i1> @test24vec(<2 x i1> %a, <2 x i1> %b) {
|
|
; CHECK-LABEL: @test24vec(
|
|
; CHECK-NEXT: [[C:%.*]] = select <2 x i1> [[A:%.*]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[B:%.*]]
|
|
; CHECK-NEXT: ret <2 x i1> [[C]]
|
|
;
|
|
%c = select <2 x i1> %a, <2 x i1> %a, <2 x i1> %b
|
|
ret <2 x i1> %c
|
|
}
|
|
|
|
define i1 @test62(i1 %A, i1 %B) {
|
|
; CHECK-LABEL: @test62(
|
|
; CHECK-NEXT: [[NOT_A:%.*]] = xor i1 [[A:%.*]], true
|
|
; CHECK-NEXT: [[C:%.*]] = select i1 [[NOT_A]], i1 [[B:%.*]], i1 false
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%not = xor i1 %A, true
|
|
%C = select i1 %A, i1 %not, i1 %B
|
|
ret i1 %C
|
|
}
|
|
|
|
define <2 x i1> @test62vec(<2 x i1> %A, <2 x i1> %B) {
|
|
; CHECK-LABEL: @test62vec(
|
|
; CHECK-NEXT: [[NOT_A:%.*]] = xor <2 x i1> [[A:%.*]], <i1 true, i1 true>
|
|
; CHECK-NEXT: [[C:%.*]] = select <2 x i1> [[NOT_A]], <2 x i1> [[B:%.*]], <2 x i1> zeroinitializer
|
|
; CHECK-NEXT: ret <2 x i1> [[C]]
|
|
;
|
|
%not = xor <2 x i1> %A, <i1 true, i1 true>
|
|
%C = select <2 x i1> %A, <2 x i1> %not, <2 x i1> %B
|
|
ret <2 x i1> %C
|
|
}
|
|
|
|
define i1 @test63(i1 %A, i1 %B) {
|
|
; CHECK-LABEL: @test63(
|
|
; CHECK-NEXT: [[NOT_A:%.*]] = xor i1 [[A:%.*]], true
|
|
; CHECK-NEXT: [[C:%.*]] = select i1 [[NOT_A]], i1 true, i1 [[B:%.*]]
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%not = xor i1 %A, true
|
|
%C = select i1 %A, i1 %B, i1 %not
|
|
ret i1 %C
|
|
}
|
|
|
|
define <2 x i1> @test63vec(<2 x i1> %A, <2 x i1> %B) {
|
|
; CHECK-LABEL: @test63vec(
|
|
; CHECK-NEXT: [[NOT_A:%.*]] = xor <2 x i1> [[A:%.*]], <i1 true, i1 true>
|
|
; CHECK-NEXT: [[C:%.*]] = select <2 x i1> [[NOT_A]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[B:%.*]]
|
|
; CHECK-NEXT: ret <2 x i1> [[C]]
|
|
;
|
|
%not = xor <2 x i1> %A, <i1 true, i1 true>
|
|
%C = select <2 x i1> %A, <2 x i1> %B, <2 x i1> %not
|
|
ret <2 x i1> %C
|
|
}
|
|
|
|
define i32 @test11(i32 %a) {
|
|
; CHECK-LABEL: @test11(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[A:%.*]], 0
|
|
; CHECK-NEXT: [[R:%.*]] = zext i1 [[C]] to i32
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%C = icmp eq i32 %a, 0
|
|
%R = select i1 %C, i32 0, i32 1
|
|
ret i32 %R
|
|
}
|
|
|
|
define i32 @test12(i1 %cond, i32 %a) {
|
|
; CHECK-LABEL: @test12(
|
|
; CHECK-NEXT: [[B:%.*]] = zext i1 [[COND:%.*]] to i32
|
|
; CHECK-NEXT: [[C:%.*]] = or i32 [[B]], [[A:%.*]]
|
|
; CHECK-NEXT: ret i32 [[C]]
|
|
;
|
|
%b = or i32 %a, 1
|
|
%c = select i1 %cond, i32 %b, i32 %a
|
|
ret i32 %c
|
|
}
|
|
|
|
define <2 x i32> @test12vec(<2 x i1> %cond, <2 x i32> %a) {
|
|
; CHECK-LABEL: @test12vec(
|
|
; CHECK-NEXT: [[B:%.*]] = zext <2 x i1> [[COND:%.*]] to <2 x i32>
|
|
; CHECK-NEXT: [[C:%.*]] = or <2 x i32> [[B]], [[A:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[C]]
|
|
;
|
|
%b = or <2 x i32> %a, <i32 1, i32 1>
|
|
%c = select <2 x i1> %cond, <2 x i32> %b, <2 x i32> %a
|
|
ret <2 x i32> %c
|
|
}
|
|
|
|
define i32 @test12a(i1 %cond, i32 %a) {
|
|
; CHECK-LABEL: @test12a(
|
|
; CHECK-NEXT: [[B:%.*]] = zext i1 [[COND:%.*]] to i32
|
|
; CHECK-NEXT: [[C:%.*]] = ashr i32 [[A:%.*]], [[B]]
|
|
; CHECK-NEXT: ret i32 [[C]]
|
|
;
|
|
%b = ashr i32 %a, 1
|
|
%c = select i1 %cond, i32 %b, i32 %a
|
|
ret i32 %c
|
|
}
|
|
|
|
define <2 x i32> @test12avec(<2 x i1> %cond, <2 x i32> %a) {
|
|
; CHECK-LABEL: @test12avec(
|
|
; CHECK-NEXT: [[B:%.*]] = zext <2 x i1> [[COND:%.*]] to <2 x i32>
|
|
; CHECK-NEXT: [[C:%.*]] = ashr <2 x i32> [[A:%.*]], [[B]]
|
|
; CHECK-NEXT: ret <2 x i32> [[C]]
|
|
;
|
|
%b = ashr <2 x i32> %a, <i32 1, i32 1>
|
|
%c = select <2 x i1> %cond, <2 x i32> %b, <2 x i32> %a
|
|
ret <2 x i32> %c
|
|
}
|
|
|
|
define i32 @test12b(i1 %cond, i32 %a) {
|
|
; CHECK-LABEL: @test12b(
|
|
; CHECK-NEXT: [[NOT_COND:%.*]] = xor i1 [[COND:%.*]], true
|
|
; CHECK-NEXT: [[B:%.*]] = zext i1 [[NOT_COND]] to i32
|
|
; CHECK-NEXT: [[D:%.*]] = ashr i32 [[A:%.*]], [[B]]
|
|
; CHECK-NEXT: ret i32 [[D]]
|
|
;
|
|
%b = ashr i32 %a, 1
|
|
%d = select i1 %cond, i32 %a, i32 %b
|
|
ret i32 %d
|
|
}
|
|
|
|
define <2 x i32> @test12bvec(<2 x i1> %cond, <2 x i32> %a) {
|
|
; CHECK-LABEL: @test12bvec(
|
|
; CHECK-NEXT: [[NOT_COND:%.*]] = xor <2 x i1> [[COND:%.*]], <i1 true, i1 true>
|
|
; CHECK-NEXT: [[B:%.*]] = zext <2 x i1> [[NOT_COND]] to <2 x i32>
|
|
; CHECK-NEXT: [[D:%.*]] = ashr <2 x i32> [[A:%.*]], [[B]]
|
|
; CHECK-NEXT: ret <2 x i32> [[D]]
|
|
;
|
|
%b = ashr <2 x i32> %a, <i32 1, i32 1>
|
|
%d = select <2 x i1> %cond, <2 x i32> %a, <2 x i32> %b
|
|
ret <2 x i32> %d
|
|
}
|
|
|
|
define i32 @test13(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test13(
|
|
; CHECK-NEXT: ret i32 [[B:%.*]]
|
|
;
|
|
%C = icmp eq i32 %a, %b
|
|
%V = select i1 %C, i32 %a, i32 %b
|
|
ret i32 %V
|
|
}
|
|
|
|
define i32 @test13a(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test13a(
|
|
; CHECK-NEXT: ret i32 [[A:%.*]]
|
|
;
|
|
%C = icmp ne i32 %a, %b
|
|
%V = select i1 %C, i32 %a, i32 %b
|
|
ret i32 %V
|
|
}
|
|
|
|
define i32 @test13b(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test13b(
|
|
; CHECK-NEXT: ret i32 [[A:%.*]]
|
|
;
|
|
%C = icmp eq i32 %a, %b
|
|
%V = select i1 %C, i32 %b, i32 %a
|
|
ret i32 %V
|
|
}
|
|
|
|
define i1 @test14a(i1 %C, i32 %X) {
|
|
; CHECK-LABEL: @test14a(
|
|
; CHECK-NEXT: [[R1:%.*]] = icmp slt i32 [[X:%.*]], 1
|
|
; CHECK-NEXT: [[NOT_C:%.*]] = xor i1 [[C:%.*]], true
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[NOT_C]], i1 true, i1 [[R1]]
|
|
; CHECK-NEXT: ret i1 [[R]]
|
|
;
|
|
%V = select i1 %C, i32 %X, i32 0
|
|
; (X < 1) | !C
|
|
%R = icmp slt i32 %V, 1
|
|
ret i1 %R
|
|
}
|
|
|
|
define i1 @test14b(i1 %C, i32 %X) {
|
|
; CHECK-LABEL: @test14b(
|
|
; CHECK-NEXT: [[R1:%.*]] = icmp slt i32 [[X:%.*]], 1
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[R1]]
|
|
; CHECK-NEXT: ret i1 [[R]]
|
|
;
|
|
%V = select i1 %C, i32 0, i32 %X
|
|
; (X < 1) | C
|
|
%R = icmp slt i32 %V, 1
|
|
ret i1 %R
|
|
}
|
|
|
|
define i32 @test16(i1 %C, ptr %P) {
|
|
; CHECK-LABEL: @test16(
|
|
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
%P2 = select i1 %C, ptr %P, ptr null
|
|
%V = load i32, ptr %P2
|
|
ret i32 %V
|
|
}
|
|
|
|
;; It may be legal to load from a null address in a non-zero address space
|
|
define i32 @test16_neg(i1 %C, ptr addrspace(1) %P) {
|
|
; CHECK-LABEL: @test16_neg(
|
|
; CHECK-NEXT: [[P2:%.*]] = select i1 [[C:%.*]], ptr addrspace(1) [[P:%.*]], ptr addrspace(1) null
|
|
; CHECK-NEXT: [[V:%.*]] = load i32, ptr addrspace(1) [[P2]], align 4
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
%P2 = select i1 %C, ptr addrspace(1) %P, ptr addrspace(1) null
|
|
%V = load i32, ptr addrspace(1) %P2
|
|
ret i32 %V
|
|
}
|
|
|
|
define i32 @test16_neg2(i1 %C, ptr addrspace(1) %P) {
|
|
; CHECK-LABEL: @test16_neg2(
|
|
; CHECK-NEXT: [[P2:%.*]] = select i1 [[C:%.*]], ptr addrspace(1) null, ptr addrspace(1) [[P:%.*]]
|
|
; CHECK-NEXT: [[V:%.*]] = load i32, ptr addrspace(1) [[P2]], align 4
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
%P2 = select i1 %C, ptr addrspace(1) null, ptr addrspace(1) %P
|
|
%V = load i32, ptr addrspace(1) %P2
|
|
ret i32 %V
|
|
}
|
|
|
|
;; It may be legal to load from a null address with null pointer valid attribute.
|
|
define i32 @test16_no_null_opt(i1 %C, ptr %P) #0 {
|
|
; CHECK-LABEL: @test16_no_null_opt(
|
|
; CHECK-NEXT: [[P2:%.*]] = select i1 [[C:%.*]], ptr [[P:%.*]], ptr null
|
|
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P2]], align 4
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
%P2 = select i1 %C, ptr %P, ptr null
|
|
%V = load i32, ptr %P2
|
|
ret i32 %V
|
|
}
|
|
|
|
define i32 @test16_no_null_opt_2(i1 %C, ptr %P) #0 {
|
|
; CHECK-LABEL: @test16_no_null_opt_2(
|
|
; CHECK-NEXT: [[P2:%.*]] = select i1 [[C:%.*]], ptr null, ptr [[P:%.*]]
|
|
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P2]], align 4
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
%P2 = select i1 %C, ptr null, ptr %P
|
|
%V = load i32, ptr %P2
|
|
ret i32 %V
|
|
}
|
|
|
|
attributes #0 = { null_pointer_is_valid }
|
|
|
|
define i1 @test17(ptr %X, i1 %C) {
|
|
; CHECK-LABEL: @test17(
|
|
; CHECK-NEXT: [[RV1:%.*]] = icmp eq ptr [[X:%.*]], null
|
|
; CHECK-NEXT: [[NOT_C:%.*]] = xor i1 [[C:%.*]], true
|
|
; CHECK-NEXT: [[RV:%.*]] = select i1 [[NOT_C]], i1 true, i1 [[RV1]]
|
|
; CHECK-NEXT: ret i1 [[RV]]
|
|
;
|
|
%R = select i1 %C, ptr %X, ptr null
|
|
%RV = icmp eq ptr %R, null
|
|
ret i1 %RV
|
|
}
|
|
|
|
define i32 @test18(i32 %X, i32 %Y, i1 %C) {
|
|
; CHECK-LABEL: @test18(
|
|
; CHECK-NEXT: [[V:%.*]] = sdiv i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
%R = select i1 %C, i32 %X, i32 0
|
|
%V = sdiv i32 %Y, %R
|
|
ret i32 %V
|
|
}
|
|
|
|
define i32 @test19(i32 %x) {
|
|
; CHECK-LABEL: @test19(
|
|
; CHECK-NEXT: [[X_LOBIT:%.*]] = ashr i32 [[X:%.*]], 31
|
|
; CHECK-NEXT: ret i32 [[X_LOBIT]]
|
|
;
|
|
%t = icmp ugt i32 %x, 2147483647
|
|
%retval = select i1 %t, i32 -1, i32 0
|
|
ret i32 %retval
|
|
}
|
|
|
|
define i32 @test20(i32 %x) {
|
|
; CHECK-LABEL: @test20(
|
|
; CHECK-NEXT: [[X_LOBIT:%.*]] = ashr i32 [[X:%.*]], 31
|
|
; CHECK-NEXT: ret i32 [[X_LOBIT]]
|
|
;
|
|
%t = icmp slt i32 %x, 0
|
|
%retval = select i1 %t, i32 -1, i32 0
|
|
ret i32 %retval
|
|
}
|
|
|
|
define i64 @test21(i32 %x) {
|
|
; CHECK-LABEL: @test21(
|
|
; CHECK-NEXT: [[X_LOBIT:%.*]] = ashr i32 [[X:%.*]], 31
|
|
; CHECK-NEXT: [[RETVAL:%.*]] = sext i32 [[X_LOBIT]] to i64
|
|
; CHECK-NEXT: ret i64 [[RETVAL]]
|
|
;
|
|
%t = icmp slt i32 %x, 0
|
|
%retval = select i1 %t, i64 -1, i64 0
|
|
ret i64 %retval
|
|
}
|
|
|
|
define i16 @test22(i32 %x) {
|
|
; CHECK-LABEL: @test22(
|
|
; CHECK-NEXT: [[X_LOBIT:%.*]] = ashr i32 [[X:%.*]], 31
|
|
; CHECK-NEXT: [[RETVAL:%.*]] = trunc nsw i32 [[X_LOBIT]] to i16
|
|
; CHECK-NEXT: ret i16 [[RETVAL]]
|
|
;
|
|
%t = icmp slt i32 %x, 0
|
|
%retval = select i1 %t, i16 -1, i16 0
|
|
ret i16 %retval
|
|
}
|
|
|
|
define i32 @test25(i1 %c) {
|
|
; CHECK-LABEL: @test25(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[JUMP:%.*]], label [[RET:%.*]]
|
|
; CHECK: jump:
|
|
; CHECK-NEXT: br label [[RET]]
|
|
; CHECK: ret:
|
|
; CHECK-NEXT: [[B:%.*]] = phi i32 [ 10, [[JUMP]] ], [ 20, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: ret i32 [[B]]
|
|
;
|
|
entry:
|
|
br i1 %c, label %jump, label %ret
|
|
jump:
|
|
br label %ret
|
|
ret:
|
|
%a = phi i1 [true, %jump], [false, %entry]
|
|
%b = select i1 %a, i32 10, i32 20
|
|
ret i32 %b
|
|
}
|
|
|
|
define i32 @test26(i1 %cond) {
|
|
; CHECK-LABEL: @test26(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[JUMP:%.*]], label [[RET:%.*]]
|
|
; CHECK: jump:
|
|
; CHECK-NEXT: br label [[RET]]
|
|
; CHECK: ret:
|
|
; CHECK-NEXT: [[B:%.*]] = phi i32 [ 20, [[ENTRY:%.*]] ], [ 10, [[JUMP]] ]
|
|
; CHECK-NEXT: ret i32 [[B]]
|
|
;
|
|
entry:
|
|
br i1 %cond, label %jump, label %ret
|
|
jump:
|
|
%c = or i1 false, false
|
|
br label %ret
|
|
ret:
|
|
%a = phi i1 [true, %entry], [%c, %jump]
|
|
%b = select i1 %a, i32 20, i32 10
|
|
ret i32 %b
|
|
}
|
|
|
|
define i32 @test26_logical(i1 %cond) {
|
|
; CHECK-LABEL: @test26_logical(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[JUMP:%.*]], label [[RET:%.*]]
|
|
; CHECK: jump:
|
|
; CHECK-NEXT: br label [[RET]]
|
|
; CHECK: ret:
|
|
; CHECK-NEXT: [[B:%.*]] = phi i32 [ 20, [[ENTRY:%.*]] ], [ 10, [[JUMP]] ]
|
|
; CHECK-NEXT: ret i32 [[B]]
|
|
;
|
|
entry:
|
|
br i1 %cond, label %jump, label %ret
|
|
jump:
|
|
%c = select i1 false, i1 true, i1 false
|
|
br label %ret
|
|
ret:
|
|
%a = phi i1 [true, %entry], [%c, %jump]
|
|
%b = select i1 %a, i32 20, i32 10
|
|
ret i32 %b
|
|
}
|
|
|
|
define i32 @test27(i1 %c, i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test27(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[JUMP:%.*]], label [[RET:%.*]]
|
|
; CHECK: jump:
|
|
; CHECK-NEXT: br label [[RET]]
|
|
; CHECK: ret:
|
|
; CHECK-NEXT: [[S:%.*]] = phi i32 [ [[A:%.*]], [[JUMP]] ], [ [[B:%.*]], [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
;
|
|
entry:
|
|
br i1 %c, label %jump, label %ret
|
|
jump:
|
|
br label %ret
|
|
ret:
|
|
%p = phi i1 [true, %jump], [false, %entry]
|
|
%s = select i1 %p, i32 %A, i32 %B
|
|
ret i32 %s
|
|
}
|
|
|
|
define i32 @test28(i1 %cond, i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test28(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[JUMP:%.*]], label [[RET:%.*]]
|
|
; CHECK: jump:
|
|
; CHECK-NEXT: br label [[RET]]
|
|
; CHECK: ret:
|
|
; CHECK-NEXT: [[S:%.*]] = phi i32 [ [[A:%.*]], [[JUMP]] ], [ [[B:%.*]], [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
;
|
|
entry:
|
|
br i1 %cond, label %jump, label %ret
|
|
jump:
|
|
br label %ret
|
|
ret:
|
|
%c = phi i32 [%A, %jump], [%B, %entry]
|
|
%p = phi i1 [true, %jump], [false, %entry]
|
|
%s = select i1 %p, i32 %A, i32 %c
|
|
ret i32 %s
|
|
}
|
|
|
|
define i32 @test29(i1 %cond, i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test29(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[JUMP:%.*]], label [[RET:%.*]]
|
|
; CHECK: jump:
|
|
; CHECK-NEXT: br label [[RET]]
|
|
; CHECK: ret:
|
|
; CHECK-NEXT: [[S:%.*]] = phi i32 [ [[A:%.*]], [[JUMP]] ], [ [[B:%.*]], [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: br label [[NEXT:%.*]]
|
|
; CHECK: next:
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
;
|
|
entry:
|
|
br i1 %cond, label %jump, label %ret
|
|
jump:
|
|
br label %ret
|
|
ret:
|
|
%c = phi i32 [%A, %jump], [%B, %entry]
|
|
%p = phi i1 [true, %jump], [false, %entry]
|
|
br label %next
|
|
|
|
next:
|
|
%s = select i1 %p, i32 %A, i32 %c
|
|
ret i32 %s
|
|
}
|
|
|
|
; SMAX(SMAX(x, y), x) -> SMAX(x, y)
|
|
define i32 @test30(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test30(
|
|
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%cmp = icmp sgt i32 %x, %y
|
|
%cond = select i1 %cmp, i32 %x, i32 %y
|
|
%cmp5 = icmp sgt i32 %cond, %x
|
|
%retval = select i1 %cmp5, i32 %cond, i32 %x
|
|
ret i32 %retval
|
|
}
|
|
|
|
; UMAX(UMAX(x, y), x) -> UMAX(x, y)
|
|
define i32 @test31(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test31(
|
|
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%cmp = icmp ugt i32 %x, %y
|
|
%cond = select i1 %cmp, i32 %x, i32 %y
|
|
%cmp5 = icmp ugt i32 %cond, %x
|
|
%retval = select i1 %cmp5, i32 %cond, i32 %x
|
|
ret i32 %retval
|
|
}
|
|
|
|
; SMIN(SMIN(x, y), x) -> SMIN(x, y)
|
|
define i32 @test32(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test32(
|
|
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.smin.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%cmp = icmp sgt i32 %x, %y
|
|
%cond = select i1 %cmp, i32 %y, i32 %x
|
|
%cmp5 = icmp sgt i32 %cond, %x
|
|
%retval = select i1 %cmp5, i32 %x, i32 %cond
|
|
ret i32 %retval
|
|
}
|
|
|
|
; MAX(MIN(x, y), x) -> x
|
|
define i32 @test33(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test33(
|
|
; CHECK-NEXT: ret i32 [[X:%.*]]
|
|
;
|
|
%cmp = icmp sgt i32 %x, %y
|
|
%cond = select i1 %cmp, i32 %y, i32 %x
|
|
%cmp5 = icmp sgt i32 %cond, %x
|
|
%retval = select i1 %cmp5, i32 %cond, i32 %x
|
|
ret i32 %retval
|
|
}
|
|
|
|
; MIN(MAX(x, y), x) -> x
|
|
define i32 @test34(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test34(
|
|
; CHECK-NEXT: ret i32 [[X:%.*]]
|
|
;
|
|
%cmp = icmp sgt i32 %x, %y
|
|
%cond = select i1 %cmp, i32 %x, i32 %y
|
|
%cmp5 = icmp sgt i32 %cond, %x
|
|
%retval = select i1 %cmp5, i32 %x, i32 %cond
|
|
ret i32 %retval
|
|
}
|
|
|
|
define i1 @test38(i1 %cond) {
|
|
; CHECK-LABEL: @test38(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%zero = alloca i32
|
|
%one = alloca i32
|
|
%ptr = select i1 %cond, ptr %zero, ptr %one
|
|
%isnull = icmp eq ptr %ptr, null
|
|
ret i1 %isnull
|
|
}
|
|
|
|
define i1 @test39(i1 %cond, double %x) {
|
|
; CHECK-LABEL: @test39(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%s = select i1 %cond, double %x, double 0x7FF0000000000000 ; RHS = +infty
|
|
%cmp = fcmp ule double %x, %s
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @test40(i1 %cond) {
|
|
; CHECK-LABEL: @test40(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%a = alloca i32
|
|
%b = alloca i32
|
|
%c = alloca i32
|
|
%s = select i1 %cond, ptr %a, ptr %b
|
|
%r = icmp eq ptr %s, %c
|
|
ret i1 %r
|
|
}
|
|
|
|
define i32 @test41(i1 %cond, i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test41(
|
|
; CHECK-NEXT: [[R:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%z = and i32 %x, %y
|
|
%s = select i1 %cond, i32 %y, i32 %z
|
|
%r = and i32 %x, %s
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @test42(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test42(
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: [[B:%.*]] = sext i1 [[COND]] to i32
|
|
; CHECK-NEXT: [[C:%.*]] = add i32 [[B]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret i32 [[C]]
|
|
;
|
|
%b = add i32 %y, -1
|
|
%cond = icmp eq i32 %x, 0
|
|
%c = select i1 %cond, i32 %b, i32 %y
|
|
ret i32 %c
|
|
}
|
|
|
|
define <2 x i32> @test42vec(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @test42vec(
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp eq <2 x i32> [[X:%.*]], zeroinitializer
|
|
; CHECK-NEXT: [[B:%.*]] = sext <2 x i1> [[COND]] to <2 x i32>
|
|
; CHECK-NEXT: [[C:%.*]] = add <2 x i32> [[B]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[C]]
|
|
;
|
|
%b = add <2 x i32> %y, <i32 -1, i32 -1>
|
|
%cond = icmp eq <2 x i32> %x, zeroinitializer
|
|
%c = select <2 x i1> %cond, <2 x i32> %b, <2 x i32> %y
|
|
ret <2 x i32> %c
|
|
}
|
|
|
|
; PR8994
|
|
|
|
; This select instruction can't be eliminated because trying to do so would
|
|
; change the number of vector elements. This used to assert.
|
|
define i48 @test51(<3 x i1> %icmp, <3 x i16> %t) {
|
|
; CHECK-LABEL: @test51(
|
|
; CHECK-NEXT: [[SELECT:%.*]] = select <3 x i1> [[ICMP:%.*]], <3 x i16> zeroinitializer, <3 x i16> [[T:%.*]]
|
|
; CHECK-NEXT: [[T2:%.*]] = bitcast <3 x i16> [[SELECT]] to i48
|
|
; CHECK-NEXT: ret i48 [[T2]]
|
|
;
|
|
%select = select <3 x i1> %icmp, <3 x i16> zeroinitializer, <3 x i16> %t
|
|
%t2 = bitcast <3 x i16> %select to i48
|
|
ret i48 %t2
|
|
}
|
|
|
|
define <vscale x 4 x float> @bitcast_select_bitcast(<vscale x 4 x i1> %icmp, <vscale x 4 x i32> %a, <vscale x 4 x float> %b) {
|
|
; CHECK-LABEL: @bitcast_select_bitcast(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <vscale x 4 x i32> [[A:%.*]] to <vscale x 4 x float>
|
|
; CHECK-NEXT: [[BC2:%.*]] = select <vscale x 4 x i1> [[ICMP:%.*]], <vscale x 4 x float> [[B:%.*]], <vscale x 4 x float> [[TMP1]]
|
|
; CHECK-NEXT: ret <vscale x 4 x float> [[BC2]]
|
|
;
|
|
%bc1 = bitcast <vscale x 4 x float> %b to <vscale x 4 x i32>
|
|
%select = select <vscale x 4 x i1> %icmp, <vscale x 4 x i32> %bc1, <vscale x 4 x i32> %a
|
|
%bc2 = bitcast <vscale x 4 x i32> %select to <vscale x 4 x float>
|
|
ret <vscale x 4 x float> %bc2
|
|
}
|
|
|
|
define void @select_oneuse_bitcast(<vscale x 4 x float> %a, <vscale x 4 x float> %b, <vscale x 4 x i32> %c, <vscale x 4 x i32> %d, ptr %ptr1) {
|
|
; CHECK-LABEL: @select_oneuse_bitcast(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult <vscale x 4 x i32> [[C:%.*]], [[D:%.*]]
|
|
; CHECK-NEXT: [[SEL1_V:%.*]] = select <vscale x 4 x i1> [[CMP]], <vscale x 4 x float> [[A:%.*]], <vscale x 4 x float> [[B:%.*]]
|
|
; CHECK-NEXT: store <vscale x 4 x float> [[SEL1_V]], ptr [[PTR1:%.*]], align 16
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%cmp = icmp ult <vscale x 4 x i32> %c, %d
|
|
%bc1 = bitcast <vscale x 4 x float> %a to <vscale x 4 x i32>
|
|
%bc2 = bitcast <vscale x 4 x float> %b to <vscale x 4 x i32>
|
|
%sel1 = select <vscale x 4 x i1> %cmp, <vscale x 4 x i32> %bc1, <vscale x 4 x i32> %bc2
|
|
store <vscale x 4 x i32> %sel1, ptr %ptr1
|
|
ret void
|
|
}
|
|
|
|
; Allow select promotion even if there are multiple uses of bitcasted ops.
|
|
; Hoisting the selects allows later pattern matching to see that these are min/max ops.
|
|
|
|
define void @min_max_bitcast(<4 x float> %a, <4 x float> %b, ptr %ptr1, ptr %ptr2) {
|
|
; CHECK-LABEL: @min_max_bitcast(
|
|
; CHECK-NEXT: [[CMP:%.*]] = fcmp olt <4 x float> [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[SEL1_V:%.*]] = select <4 x i1> [[CMP]], <4 x float> [[A]], <4 x float> [[B]]
|
|
; CHECK-NEXT: [[SEL2_V:%.*]] = select <4 x i1> [[CMP]], <4 x float> [[B]], <4 x float> [[A]]
|
|
; CHECK-NEXT: store <4 x float> [[SEL1_V]], ptr [[PTR1:%.*]], align 16
|
|
; CHECK-NEXT: store <4 x float> [[SEL2_V]], ptr [[PTR2:%.*]], align 16
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%cmp = fcmp olt <4 x float> %a, %b
|
|
%bc1 = bitcast <4 x float> %a to <4 x i32>
|
|
%bc2 = bitcast <4 x float> %b to <4 x i32>
|
|
%sel1 = select <4 x i1> %cmp, <4 x i32> %bc1, <4 x i32> %bc2
|
|
%sel2 = select <4 x i1> %cmp, <4 x i32> %bc2, <4 x i32> %bc1
|
|
store <4 x i32> %sel1, ptr %ptr1
|
|
store <4 x i32> %sel2, ptr %ptr2
|
|
ret void
|
|
}
|
|
|
|
define void @min_max_bitcast1(<vscale x 4 x float> %a, <vscale x 4 x float> %b, ptr %ptr1, ptr %ptr2) {
|
|
; CHECK-LABEL: @min_max_bitcast1(
|
|
; CHECK-NEXT: [[CMP:%.*]] = fcmp olt <vscale x 4 x float> [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[SEL1_V:%.*]] = select <vscale x 4 x i1> [[CMP]], <vscale x 4 x float> [[A]], <vscale x 4 x float> [[B]]
|
|
; CHECK-NEXT: [[SEL2_V:%.*]] = select <vscale x 4 x i1> [[CMP]], <vscale x 4 x float> [[B]], <vscale x 4 x float> [[A]]
|
|
; CHECK-NEXT: store <vscale x 4 x float> [[SEL1_V]], ptr [[PTR1:%.*]], align 16
|
|
; CHECK-NEXT: store <vscale x 4 x float> [[SEL2_V]], ptr [[PTR2:%.*]], align 16
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%cmp = fcmp olt <vscale x 4 x float> %a, %b
|
|
%bc1 = bitcast <vscale x 4 x float> %a to <vscale x 4 x i32>
|
|
%bc2 = bitcast <vscale x 4 x float> %b to <vscale x 4 x i32>
|
|
%sel1 = select <vscale x 4 x i1> %cmp, <vscale x 4 x i32> %bc1, <vscale x 4 x i32> %bc2
|
|
%sel2 = select <vscale x 4 x i1> %cmp, <vscale x 4 x i32> %bc2, <vscale x 4 x i32> %bc1
|
|
store <vscale x 4 x i32> %sel1, ptr %ptr1
|
|
store <vscale x 4 x i32> %sel2, ptr %ptr2
|
|
ret void
|
|
}
|
|
|
|
; To avoid potential backend problems, we don't do the same transform for other casts.
|
|
|
|
define void @truncs_before_selects(<4 x float> %f1, <4 x float> %f2, <4 x i64> %a, <4 x i64> %b, ptr %ptr1, ptr %ptr2) {
|
|
; CHECK-LABEL: @truncs_before_selects(
|
|
; CHECK-NEXT: [[CMP:%.*]] = fcmp olt <4 x float> [[F1:%.*]], [[F2:%.*]]
|
|
; CHECK-NEXT: [[BC1:%.*]] = trunc <4 x i64> [[A:%.*]] to <4 x i32>
|
|
; CHECK-NEXT: [[BC2:%.*]] = trunc <4 x i64> [[B:%.*]] to <4 x i32>
|
|
; CHECK-NEXT: [[SEL1:%.*]] = select <4 x i1> [[CMP]], <4 x i32> [[BC1]], <4 x i32> [[BC2]]
|
|
; CHECK-NEXT: [[SEL2:%.*]] = select <4 x i1> [[CMP]], <4 x i32> [[BC2]], <4 x i32> [[BC1]]
|
|
; CHECK-NEXT: store <4 x i32> [[SEL1]], ptr [[PTR1:%.*]], align 16
|
|
; CHECK-NEXT: store <4 x i32> [[SEL2]], ptr [[PTR2:%.*]], align 16
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%cmp = fcmp olt <4 x float> %f1, %f2
|
|
%bc1 = trunc <4 x i64> %a to <4 x i32>
|
|
%bc2 = trunc <4 x i64> %b to <4 x i32>
|
|
%sel1 = select <4 x i1> %cmp, <4 x i32> %bc1, <4 x i32> %bc2
|
|
%sel2 = select <4 x i1> %cmp, <4 x i32> %bc2, <4 x i32> %bc1
|
|
store <4 x i32> %sel1, ptr %ptr1, align 16
|
|
store <4 x i32> %sel2, ptr %ptr2, align 16
|
|
ret void
|
|
}
|
|
|
|
; PR8575
|
|
|
|
define i32 @test52(i32 %n, i32 %m) {
|
|
; CHECK-LABEL: @test52(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N:%.*]], [[M:%.*]]
|
|
; CHECK-NEXT: [[STOREMERGE:%.*]] = select i1 [[CMP]], i32 1, i32 6
|
|
; CHECK-NEXT: ret i32 [[STOREMERGE]]
|
|
;
|
|
%cmp = icmp sgt i32 %n, %m
|
|
%. = select i1 %cmp, i32 1, i32 3
|
|
%add = add nsw i32 %., 3
|
|
%storemerge = select i1 %cmp, i32 %., i32 %add
|
|
ret i32 %storemerge
|
|
}
|
|
|
|
; PR9454
|
|
|
|
define i32 @test53(i32 %x) {
|
|
; CHECK-LABEL: @test53(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], -3
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 0
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 2, i32 1
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
%and = and i32 %x, 2
|
|
%cmp = icmp eq i32 %and, %x
|
|
%sel = select i1 %cmp, i32 2, i32 1
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i32 @test54(i32 %X, i32 %Y) {
|
|
; CHECK-LABEL: @test54(
|
|
; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: [[C:%.*]] = zext i1 [[B]] to i32
|
|
; CHECK-NEXT: ret i32 [[C]]
|
|
;
|
|
%A = ashr exact i32 %X, %Y
|
|
%B = icmp eq i32 %A, 0
|
|
%C = select i1 %B, i32 %A, i32 1
|
|
ret i32 %C
|
|
}
|
|
|
|
define i1 @test55(i1 %X, i32 %Y, i32 %Z) {
|
|
; CHECK-LABEL: @test55(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[Y:%.*]], 0
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%A = ashr exact i32 %Y, %Z
|
|
%B = select i1 %X, i32 %Y, i32 %A
|
|
%C = icmp eq i32 %B, 0
|
|
ret i1 %C
|
|
}
|
|
|
|
define i32 @test56(i16 %x) {
|
|
; CHECK-LABEL: @test56(
|
|
; CHECK-NEXT: [[CONV:%.*]] = zext i16 [[X:%.*]] to i32
|
|
; CHECK-NEXT: ret i32 [[CONV]]
|
|
;
|
|
%tobool = icmp eq i16 %x, 0
|
|
%conv = zext i16 %x to i32
|
|
%cond = select i1 %tobool, i32 0, i32 %conv
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @test57(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test57(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X]], 0
|
|
; CHECK-NEXT: [[DOTAND:%.*]] = select i1 [[TOBOOL]], i32 0, i32 [[AND]]
|
|
; CHECK-NEXT: ret i32 [[DOTAND]]
|
|
;
|
|
%and = and i32 %x, %y
|
|
%tobool = icmp eq i32 %x, 0
|
|
%.and = select i1 %tobool, i32 0, i32 %and
|
|
ret i32 %.and
|
|
}
|
|
|
|
define i32 @test58(i16 %x) {
|
|
; CHECK-LABEL: @test58(
|
|
; CHECK-NEXT: [[CONV:%.*]] = zext i16 [[X:%.*]] to i32
|
|
; CHECK-NEXT: ret i32 [[CONV]]
|
|
;
|
|
%tobool = icmp ne i16 %x, 1
|
|
%conv = zext i16 %x to i32
|
|
%cond = select i1 %tobool, i32 %conv, i32 1
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @test59(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test59(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret i32 [[AND]]
|
|
;
|
|
%and = and i32 %x, %y
|
|
%tobool = icmp ne i32 %x, %y
|
|
%.and = select i1 %tobool, i32 %and, i32 %y
|
|
ret i32 %.and
|
|
}
|
|
|
|
define i1 @test60(i32 %x, ptr %y) {
|
|
; CHECK-LABEL: @test60(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: [[LOAD:%.*]] = load i1, ptr [[Y:%.*]], align 1
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[X]], 1
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i1 [[LOAD]], i1 [[CMP1]]
|
|
; CHECK-NEXT: ret i1 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i32 %x, 0
|
|
%load = load i1, ptr %y, align 1
|
|
%cmp1 = icmp slt i32 %x, 1
|
|
%sel = select i1 %cmp, i1 %load, i1 %cmp1
|
|
ret i1 %sel
|
|
}
|
|
|
|
@glbl = constant i32 10
|
|
define i32 @test61(ptr %ptr) {
|
|
; CHECK-LABEL: @test61(
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
%A = load i32, ptr %ptr
|
|
%B = icmp eq ptr %ptr, @glbl
|
|
%C = select i1 %B, i32 %A, i32 10
|
|
ret i32 %C
|
|
}
|
|
|
|
; PR14131
|
|
define void @test64(i32 %p, i16 %b, i1 %c1) noreturn {
|
|
; CHECK-LABEL: @test64(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[C1:%.*]], label [[LOR_RHS:%.*]], label [[LOR_END:%.*]]
|
|
; CHECK: lor.rhs:
|
|
; CHECK-NEXT: br label [[LOR_END]]
|
|
; CHECK: lor.end:
|
|
; CHECK-NEXT: br i1 poison, label [[COND_END17:%.*]], label [[COND_FALSE16:%.*]]
|
|
; CHECK: cond.false16:
|
|
; CHECK-NEXT: br label [[COND_END17]]
|
|
; CHECK: cond.end17:
|
|
; CHECK-NEXT: br label [[WHILE_BODY:%.*]]
|
|
; CHECK: while.body:
|
|
; CHECK-NEXT: br label [[WHILE_BODY]]
|
|
;
|
|
entry:
|
|
%p.addr.0.insert.mask = and i32 %p, -65536
|
|
%conv2 = and i32 %p, 65535
|
|
br i1 %c1, label %lor.rhs, label %lor.end
|
|
|
|
lor.rhs:
|
|
%p.addr.0.extract.trunc = trunc i32 %p.addr.0.insert.mask to i16
|
|
%phitmp = zext i16 %p.addr.0.extract.trunc to i32
|
|
br label %lor.end
|
|
|
|
lor.end:
|
|
%t.1 = phi i32 [ 0, %entry ], [ %phitmp, %lor.rhs ]
|
|
%conv6 = zext i16 %b to i32
|
|
%div = udiv i32 %conv6, %t.1
|
|
%tobool8 = icmp eq i32 %div, 0
|
|
%cmp = icmp eq i32 %t.1, 0
|
|
%cmp12 = icmp ult i32 %conv2, 2
|
|
%cmp.sink = select i1 %tobool8, i1 %cmp12, i1 %cmp
|
|
br i1 %cmp.sink, label %cond.end17, label %cond.false16
|
|
|
|
cond.false16:
|
|
br label %cond.end17
|
|
|
|
cond.end17:
|
|
br label %while.body
|
|
|
|
while.body:
|
|
br label %while.body
|
|
}
|
|
|
|
@under_aligned = external global i32, align 1
|
|
|
|
; The load here must not be speculated around the select. One side of the
|
|
; select is trivially dereferenceable but may have a lower alignment than the
|
|
; load does.
|
|
define i32 @test76(i1 %flag, ptr %x) {
|
|
; CHECK-LABEL: @test76(
|
|
; CHECK-NEXT: store i32 0, ptr [[X:%.*]], align 4
|
|
; CHECK-NEXT: [[P:%.*]] = select i1 [[FLAG:%.*]], ptr @under_aligned, ptr [[X]]
|
|
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
store i32 0, ptr %x
|
|
%p = select i1 %flag, ptr @under_aligned, ptr %x
|
|
%v = load i32, ptr %p
|
|
ret i32 %v
|
|
}
|
|
|
|
declare void @scribble_on_i32(ptr)
|
|
|
|
; The load here must not be speculated around the select. One side of the
|
|
; select is trivially dereferenceable but may have a lower alignment than the
|
|
; load does.
|
|
|
|
define i32 @test77(i1 %flag, ptr %x) {
|
|
; CHECK-LABEL: @test77(
|
|
; CHECK-NEXT: [[UNDER_ALIGNED:%.*]] = alloca i32, align 1
|
|
; CHECK-NEXT: call void @scribble_on_i32(ptr nonnull [[UNDER_ALIGNED]])
|
|
; CHECK-NEXT: store i32 0, ptr [[X:%.*]], align 4
|
|
; CHECK-NEXT: [[P:%.*]] = select i1 [[FLAG:%.*]], ptr [[UNDER_ALIGNED]], ptr [[X]]
|
|
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
%under_aligned = alloca i32, align 1
|
|
call void @scribble_on_i32(ptr %under_aligned)
|
|
store i32 0, ptr %x
|
|
%p = select i1 %flag, ptr %under_aligned, ptr %x
|
|
%v = load i32, ptr %p
|
|
ret i32 %v
|
|
}
|
|
|
|
define i32 @test78(i1 %flag, ptr %x, ptr %y, ptr %z) {
|
|
; Test that we can speculate the loads around the select even when we can't
|
|
; fold the load completely away.
|
|
; CHECK-LABEL: @test78(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: store i32 0, ptr [[X:%.*]], align 4
|
|
; CHECK-NEXT: store i32 0, ptr [[Y:%.*]], align 4
|
|
; CHECK-NEXT: store i32 42, ptr [[Z:%.*]], align 4
|
|
; CHECK-NEXT: [[X_VAL:%.*]] = load i32, ptr [[X]], align 4
|
|
; CHECK-NEXT: [[Y_VAL:%.*]] = load i32, ptr [[Y]], align 4
|
|
; CHECK-NEXT: [[V:%.*]] = select i1 [[FLAG:%.*]], i32 [[X_VAL]], i32 [[Y_VAL]]
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
entry:
|
|
store i32 0, ptr %x
|
|
store i32 0, ptr %y
|
|
; Block forwarding by storing to %z which could alias either %x or %y.
|
|
store i32 42, ptr %z
|
|
%p = select i1 %flag, ptr %x, ptr %y
|
|
%v = load i32, ptr %p
|
|
ret i32 %v
|
|
}
|
|
|
|
; Test that we can speculate the loads around the select even when we can't
|
|
; fold the load completely away.
|
|
define i32 @test78_deref(i1 %flag, ptr dereferenceable(4) align 4 %x, ptr dereferenceable(4) align 4 %y, ptr %z) nofree nosync {
|
|
; CHECK-LABEL: @test78_deref(
|
|
; CHECK-NEXT: [[X_VAL:%.*]] = load i32, ptr [[X:%.*]], align 4
|
|
; CHECK-NEXT: [[Y_VAL:%.*]] = load i32, ptr [[Y:%.*]], align 4
|
|
; CHECK-NEXT: [[V:%.*]] = select i1 [[FLAG:%.*]], i32 [[X_VAL]], i32 [[Y_VAL]]
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
%p = select i1 %flag, ptr %x, ptr %y
|
|
%v = load i32, ptr %p
|
|
ret i32 %v
|
|
}
|
|
|
|
; The same as @test78 but we can't speculate the load because it can trap
|
|
; if under-aligned.
|
|
define i32 @test78_neg(i1 %flag, ptr %x, ptr %y, ptr %z) {
|
|
; CHECK-LABEL: @test78_neg(
|
|
; CHECK-NEXT: store i32 0, ptr [[X:%.*]], align 4
|
|
; CHECK-NEXT: store i32 0, ptr [[Y:%.*]], align 4
|
|
; CHECK-NEXT: store i32 42, ptr [[Z:%.*]], align 4
|
|
; CHECK-NEXT: [[P:%.*]] = select i1 [[FLAG:%.*]], ptr [[X]], ptr [[Y]]
|
|
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 16
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
store i32 0, ptr %x
|
|
store i32 0, ptr %y
|
|
; Block forwarding by storing to %z which could alias either %x or %y.
|
|
store i32 42, ptr %z
|
|
%p = select i1 %flag, ptr %x, ptr %y
|
|
%v = load i32, ptr %p, align 16
|
|
ret i32 %v
|
|
}
|
|
|
|
; The same as @test78_deref but we can't speculate the load because
|
|
; one of the arguments is not sufficiently dereferenceable.
|
|
define i32 @test78_deref_neg(i1 %flag, ptr dereferenceable(2) %x, ptr dereferenceable(4) %y, ptr %z) nofree nosync {
|
|
; CHECK-LABEL: @test78_deref_neg(
|
|
; CHECK-NEXT: [[P:%.*]] = select i1 [[FLAG:%.*]], ptr [[X:%.*]], ptr [[Y:%.*]]
|
|
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
%p = select i1 %flag, ptr %x, ptr %y
|
|
%v = load i32, ptr %p
|
|
ret i32 %v
|
|
}
|
|
|
|
; Test that we can speculate the loads around the select even when we can't
|
|
; fold the load completely away.
|
|
define float @test79(i1 %flag, ptr %x, ptr %y, ptr %z) {
|
|
; CHECK-LABEL: @test79(
|
|
; CHECK-NEXT: store i32 0, ptr [[X:%.*]], align 4
|
|
; CHECK-NEXT: store i32 0, ptr [[Y:%.*]], align 4
|
|
; CHECK-NEXT: store i32 42, ptr [[Z:%.*]], align 4
|
|
; CHECK-NEXT: [[X_VAL:%.*]] = load float, ptr [[X]], align 4
|
|
; CHECK-NEXT: [[Y_VAL:%.*]] = load float, ptr [[Y]], align 4
|
|
; CHECK-NEXT: [[V:%.*]] = select i1 [[FLAG:%.*]], float [[X_VAL]], float [[Y_VAL]]
|
|
; CHECK-NEXT: ret float [[V]]
|
|
;
|
|
store i32 0, ptr %x
|
|
store i32 0, ptr %y
|
|
; Block forwarding by storing to %z which could alias either %x or %y.
|
|
store i32 42, ptr %z
|
|
%p = select i1 %flag, ptr %x, ptr %y
|
|
%v = load float, ptr %p
|
|
ret float %v
|
|
}
|
|
|
|
; Test that when we speculate the loads around the select they fold throug
|
|
; load->load folding and load->store folding.
|
|
define i32 @test80(i1 %flag) {
|
|
; CHECK-LABEL: @test80(
|
|
; CHECK-NEXT: [[X:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: [[Y:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: call void @scribble_on_i32(ptr nonnull [[X]])
|
|
; CHECK-NEXT: call void @scribble_on_i32(ptr nonnull [[Y]])
|
|
; CHECK-NEXT: [[T:%.*]] = load i32, ptr [[X]], align 4
|
|
; CHECK-NEXT: store i32 [[T]], ptr [[Y]], align 4
|
|
; CHECK-NEXT: ret i32 [[T]]
|
|
;
|
|
%x = alloca i32
|
|
%y = alloca i32
|
|
call void @scribble_on_i32(ptr %x)
|
|
call void @scribble_on_i32(ptr %y)
|
|
%t = load i32, ptr %x
|
|
store i32 %t, ptr %y
|
|
%p = select i1 %flag, ptr %x, ptr %y
|
|
%v = load i32, ptr %p
|
|
ret i32 %v
|
|
}
|
|
|
|
; Test that we can speculate the load around the select even though they use
|
|
; differently typed pointers.
|
|
define float @test81(i1 %flag) {
|
|
; CHECK-LABEL: @test81(
|
|
; CHECK-NEXT: [[X:%.*]] = alloca float, align 4
|
|
; CHECK-NEXT: [[Y:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: call void @scribble_on_i32(ptr nonnull [[X]])
|
|
; CHECK-NEXT: call void @scribble_on_i32(ptr nonnull [[Y]])
|
|
; CHECK-NEXT: [[T:%.*]] = load i32, ptr [[X]], align 4
|
|
; CHECK-NEXT: store i32 [[T]], ptr [[Y]], align 4
|
|
; CHECK-NEXT: [[V:%.*]] = bitcast i32 [[T]] to float
|
|
; CHECK-NEXT: ret float [[V]]
|
|
;
|
|
%x = alloca float
|
|
%y = alloca i32
|
|
call void @scribble_on_i32(ptr %x)
|
|
call void @scribble_on_i32(ptr %y)
|
|
%t = load i32, ptr %x
|
|
store i32 %t, ptr %y
|
|
%p = select i1 %flag, ptr %x, ptr %y
|
|
%v = load float, ptr %p
|
|
ret float %v
|
|
}
|
|
|
|
; Test that we can speculate the load around the select even though they use
|
|
; differently typed pointers.
|
|
define i32 @test82(i1 %flag) {
|
|
; CHECK-LABEL: @test82(
|
|
; CHECK-NEXT: [[X:%.*]] = alloca float, align 4
|
|
; CHECK-NEXT: [[Y:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: call void @scribble_on_i32(ptr nonnull [[X]])
|
|
; CHECK-NEXT: call void @scribble_on_i32(ptr nonnull [[Y]])
|
|
; CHECK-NEXT: [[T:%.*]] = load float, ptr [[X]], align 4
|
|
; CHECK-NEXT: store float [[T]], ptr [[Y]], align 4
|
|
; CHECK-NEXT: [[V:%.*]] = bitcast float [[T]] to i32
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
%x = alloca float
|
|
%y = alloca i32
|
|
call void @scribble_on_i32(ptr %x)
|
|
call void @scribble_on_i32(ptr %y)
|
|
%t = load float, ptr %x
|
|
store float %t, ptr %y
|
|
%p = select i1 %flag, ptr %x, ptr %y
|
|
%v = load i32, ptr %p
|
|
ret i32 %v
|
|
}
|
|
|
|
declare void @scribble_on_i64(ptr)
|
|
declare void @scribble_on_i128(ptr)
|
|
|
|
; Test that we can speculate the load around the select even though they use
|
|
; differently typed pointers and requires inttoptr casts.
|
|
define ptr @test83(i1 %flag) {
|
|
; CHECK-LABEL: @test83(
|
|
; CHECK-NEXT: [[X:%.*]] = alloca ptr, align 8
|
|
; CHECK-NEXT: [[Y:%.*]] = alloca i64, align 8
|
|
; CHECK-NEXT: call void @scribble_on_i64(ptr nonnull [[X]])
|
|
; CHECK-NEXT: call void @scribble_on_i64(ptr nonnull [[Y]])
|
|
; CHECK-NEXT: [[T:%.*]] = load i64, ptr [[X]], align 4
|
|
; CHECK-NEXT: store i64 [[T]], ptr [[Y]], align 4
|
|
; CHECK-NEXT: [[V:%.*]] = inttoptr i64 [[T]] to ptr
|
|
; CHECK-NEXT: ret ptr [[V]]
|
|
;
|
|
%x = alloca ptr
|
|
%y = alloca i64
|
|
call void @scribble_on_i64(ptr %x)
|
|
call void @scribble_on_i64(ptr %y)
|
|
%t = load i64, ptr %x
|
|
store i64 %t, ptr %y
|
|
%p = select i1 %flag, ptr %x, ptr %y
|
|
%v = load ptr, ptr %p
|
|
ret ptr %v
|
|
}
|
|
|
|
; Test that we can speculate the load around the select even though they use
|
|
; differently typed pointers and requires a ptrtoint cast.
|
|
define i64 @test84(i1 %flag) {
|
|
; CHECK-LABEL: @test84(
|
|
; CHECK-NEXT: [[X:%.*]] = alloca ptr, align 8
|
|
; CHECK-NEXT: [[Y:%.*]] = alloca i64, align 8
|
|
; CHECK-NEXT: call void @scribble_on_i64(ptr nonnull [[X]])
|
|
; CHECK-NEXT: call void @scribble_on_i64(ptr nonnull [[Y]])
|
|
; CHECK-NEXT: [[T:%.*]] = load ptr, ptr [[X]], align 8
|
|
; CHECK-NEXT: store ptr [[T]], ptr [[Y]], align 8
|
|
; CHECK-NEXT: [[V:%.*]] = ptrtoint ptr [[T]] to i64
|
|
; CHECK-NEXT: ret i64 [[V]]
|
|
;
|
|
%x = alloca ptr
|
|
%y = alloca i64
|
|
call void @scribble_on_i64(ptr %x)
|
|
call void @scribble_on_i64(ptr %y)
|
|
%t = load ptr, ptr %x
|
|
store ptr %t, ptr %y
|
|
%p = select i1 %flag, ptr %x, ptr %y
|
|
%v = load i64, ptr %p
|
|
ret i64 %v
|
|
}
|
|
|
|
; Test that we can't speculate the load around the select. The load of the
|
|
; pointer doesn't load all of the stored integer bits. We could fix this, but it
|
|
; would require endianness checks and other nastiness.
|
|
define ptr @test85(i1 %flag) {
|
|
; CHECK-LABEL: @test85(
|
|
; CHECK-NEXT: [[X:%.*]] = alloca [2 x ptr], align 8
|
|
; CHECK-NEXT: [[Y:%.*]] = alloca i128, align 8
|
|
; CHECK-NEXT: call void @scribble_on_i128(ptr nonnull [[X]])
|
|
; CHECK-NEXT: call void @scribble_on_i128(ptr nonnull [[Y]])
|
|
; CHECK-NEXT: [[T:%.*]] = load i128, ptr [[X]], align 4
|
|
; CHECK-NEXT: store i128 [[T]], ptr [[Y]], align 4
|
|
; CHECK-NEXT: [[X_VAL:%.*]] = load ptr, ptr [[X]], align 8
|
|
; CHECK-NEXT: [[Y_VAL:%.*]] = load ptr, ptr [[Y]], align 8
|
|
; CHECK-NEXT: [[V:%.*]] = select i1 [[FLAG:%.*]], ptr [[X_VAL]], ptr [[Y_VAL]]
|
|
; CHECK-NEXT: ret ptr [[V]]
|
|
;
|
|
%x = alloca [2 x ptr]
|
|
%y = alloca i128
|
|
call void @scribble_on_i128(ptr %x)
|
|
call void @scribble_on_i128(ptr %y)
|
|
%t = load i128, ptr %x
|
|
store i128 %t, ptr %y
|
|
%p = select i1 %flag, ptr %x, ptr %y
|
|
%v = load ptr, ptr %p
|
|
ret ptr %v
|
|
}
|
|
|
|
; Test that we can't speculate the load around the select when the integer size
|
|
; is larger than the pointer size. The store of the pointer doesn't store to all
|
|
; the bits of the integer.
|
|
define i128 @test86(i1 %flag) {
|
|
; CHECK-LABEL: @test86(
|
|
; CHECK-NEXT: [[X:%.*]] = alloca [2 x ptr], align 8
|
|
; CHECK-NEXT: [[Y:%.*]] = alloca i128, align 8
|
|
; CHECK-NEXT: call void @scribble_on_i128(ptr nonnull [[X]])
|
|
; CHECK-NEXT: call void @scribble_on_i128(ptr nonnull [[Y]])
|
|
; CHECK-NEXT: [[T:%.*]] = load ptr, ptr [[X]], align 8
|
|
; CHECK-NEXT: store ptr [[T]], ptr [[Y]], align 8
|
|
; CHECK-NEXT: [[X_VAL:%.*]] = load i128, ptr [[X]], align 4
|
|
; CHECK-NEXT: [[Y_VAL:%.*]] = load i128, ptr [[Y]], align 4
|
|
; CHECK-NEXT: [[V:%.*]] = select i1 [[FLAG:%.*]], i128 [[X_VAL]], i128 [[Y_VAL]]
|
|
; CHECK-NEXT: ret i128 [[V]]
|
|
;
|
|
%x = alloca [2 x ptr]
|
|
%y = alloca i128
|
|
call void @scribble_on_i128(ptr %x)
|
|
call void @scribble_on_i128(ptr %y)
|
|
%t = load ptr, ptr %x
|
|
store ptr %t, ptr %y
|
|
%p = select i1 %flag, ptr %x, ptr %y
|
|
%v = load i128, ptr %p
|
|
ret i128 %v
|
|
}
|
|
|
|
define i32 @test_select_select0(i32 %a, i32 %r0, i32 %r1, i32 %v1, i32 %v2) {
|
|
; CHECK-LABEL: @test_select_select0(
|
|
; CHECK-NEXT: [[C0_NOT:%.*]] = icmp slt i32 [[A:%.*]], [[V1:%.*]]
|
|
; CHECK-NEXT: [[S0:%.*]] = select i1 [[C0_NOT]], i32 [[R1:%.*]], i32 [[R0:%.*]]
|
|
; CHECK-NEXT: [[C1:%.*]] = icmp slt i32 [[A]], [[V2:%.*]]
|
|
; CHECK-NEXT: [[S1:%.*]] = select i1 [[C1]], i32 [[S0]], i32 [[R1]]
|
|
; CHECK-NEXT: ret i32 [[S1]]
|
|
;
|
|
%c0 = icmp sge i32 %a, %v1
|
|
%s0 = select i1 %c0, i32 %r0, i32 %r1
|
|
%c1 = icmp slt i32 %a, %v2
|
|
%s1 = select i1 %c1, i32 %s0, i32 %r1
|
|
ret i32 %s1
|
|
}
|
|
|
|
define i32 @test_select_select1(i32 %a, i32 %r0, i32 %r1, i32 %v1, i32 %v2) {
|
|
; CHECK-LABEL: @test_select_select1(
|
|
; CHECK-NEXT: [[C0_NOT:%.*]] = icmp slt i32 [[A:%.*]], [[V1:%.*]]
|
|
; CHECK-NEXT: [[S0:%.*]] = select i1 [[C0_NOT]], i32 [[R1:%.*]], i32 [[R0:%.*]]
|
|
; CHECK-NEXT: [[C1:%.*]] = icmp slt i32 [[A]], [[V2:%.*]]
|
|
; CHECK-NEXT: [[S1:%.*]] = select i1 [[C1]], i32 [[R0]], i32 [[S0]]
|
|
; CHECK-NEXT: ret i32 [[S1]]
|
|
;
|
|
%c0 = icmp sge i32 %a, %v1
|
|
%s0 = select i1 %c0, i32 %r0, i32 %r1
|
|
%c1 = icmp slt i32 %a, %v2
|
|
%s1 = select i1 %c1, i32 %r0, i32 %s0
|
|
ret i32 %s1
|
|
}
|
|
|
|
define i32 @PR23757(i32 %x) {
|
|
; CHECK-LABEL: @PR23757(
|
|
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], 1
|
|
; CHECK-NEXT: ret i32 [[ADD]]
|
|
;
|
|
%cmp = icmp eq i32 %x, 2147483647
|
|
%add = add nsw i32 %x, 1
|
|
%sel = select i1 %cmp, i32 -2147483648, i32 %add
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i32 @PR23757_swapped(i32 %x) {
|
|
; CHECK-LABEL: @PR23757_swapped(
|
|
; CHECK-NEXT: ret i32 -2147483648
|
|
;
|
|
%cmp = icmp eq i32 %x, 2147483647
|
|
%add = add nsw i32 %x, 1
|
|
%sel = select i1 %cmp, i32 %add, i32 -2147483648
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i32 @PR23757_ne(i32 %x, ptr %p) {
|
|
; CHECK-LABEL: @PR23757_ne(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[X:%.*]], 2147483647
|
|
; CHECK-NEXT: store i1 [[CMP]], ptr [[P:%.*]], align 1
|
|
; CHECK-NEXT: ret i32 -2147483648
|
|
;
|
|
%cmp = icmp ne i32 %x, 2147483647
|
|
store i1 %cmp, ptr %p ; thwart predicate canonicalization
|
|
%add = add nsw i32 %x, 1
|
|
%sel = select i1 %cmp, i32 -2147483648, i32 %add
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i32 @PR23757_ne_swapped(i32 %x, ptr %p) {
|
|
; CHECK-LABEL: @PR23757_ne_swapped(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[X:%.*]], 2147483647
|
|
; CHECK-NEXT: store i1 [[CMP]], ptr [[P:%.*]], align 1
|
|
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X]], 1
|
|
; CHECK-NEXT: ret i32 [[ADD]]
|
|
;
|
|
%cmp = icmp ne i32 %x, 2147483647
|
|
store i1 %cmp, ptr %p ; thwart predicate canonicalization
|
|
%add = add nsw i32 %x, 1
|
|
%sel = select i1 %cmp, i32 %add, i32 -2147483648
|
|
ret i32 %sel
|
|
}
|
|
|
|
; max(max(~a, -1), -1) --> ~min(a, 0)
|
|
|
|
define i32 @PR27137(i32 %a) {
|
|
; CHECK-LABEL: @PR27137(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[A:%.*]], i32 0)
|
|
; CHECK-NEXT: [[S1:%.*]] = xor i32 [[TMP1]], -1
|
|
; CHECK-NEXT: ret i32 [[S1]]
|
|
;
|
|
%not_a = xor i32 %a, -1
|
|
%c0 = icmp slt i32 %a, 0
|
|
%s0 = select i1 %c0, i32 %not_a, i32 -1
|
|
%c1 = icmp sgt i32 %s0, -1
|
|
%s1 = select i1 %c1, i32 %s0, i32 -1
|
|
ret i32 %s1
|
|
}
|
|
|
|
; ub-safe negation pattern
|
|
define i32 @PR27817(i32 %x) {
|
|
; CHECK-LABEL: @PR27817(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i32 0, [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[SUB]]
|
|
;
|
|
%cmp = icmp eq i32 %x, -2147483648
|
|
%sub = sub i32 0, %x
|
|
%sel = select i1 %cmp, i32 -2147483648, i32 %sub
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i32 @PR27817_nsw(i32 %x) {
|
|
; CHECK-LABEL: @PR27817_nsw(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i32 0, [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[SUB]]
|
|
;
|
|
%cmp = icmp eq i32 %x, -2147483648
|
|
%sub = sub nsw i32 0, %x
|
|
%sel = select i1 %cmp, i32 -2147483648, i32 %sub
|
|
ret i32 %sel
|
|
}
|
|
|
|
define <2 x i32> @PR27817_nsw_vec(<2 x i32> %x) {
|
|
; CHECK-LABEL: @PR27817_nsw_vec(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub <2 x i32> zeroinitializer, [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[SUB]]
|
|
;
|
|
%cmp = icmp eq <2 x i32> %x, <i32 -2147483648, i32 -2147483648>
|
|
%sub = sub nsw <2 x i32> zeroinitializer, %x
|
|
%sel = select <2 x i1> %cmp, <2 x i32> <i32 -2147483648, i32 -2147483648>, <2 x i32> %sub
|
|
ret <2 x i32> %sel
|
|
}
|
|
|
|
define i32 @select_icmp_slt0_xor(i32 %x) {
|
|
; CHECK-LABEL: @select_icmp_slt0_xor(
|
|
; CHECK-NEXT: [[X_XOR:%.*]] = or i32 [[X:%.*]], -2147483648
|
|
; CHECK-NEXT: ret i32 [[X_XOR]]
|
|
;
|
|
%cmp = icmp slt i32 %x, zeroinitializer
|
|
%xor = xor i32 %x, 2147483648
|
|
%x.xor = select i1 %cmp, i32 %x, i32 %xor
|
|
ret i32 %x.xor
|
|
}
|
|
|
|
define <2 x i32> @select_icmp_slt0_xor_vec(<2 x i32> %x) {
|
|
; CHECK-LABEL: @select_icmp_slt0_xor_vec(
|
|
; CHECK-NEXT: [[X_XOR:%.*]] = or <2 x i32> [[X:%.*]], <i32 -2147483648, i32 -2147483648>
|
|
; CHECK-NEXT: ret <2 x i32> [[X_XOR]]
|
|
;
|
|
%cmp = icmp slt <2 x i32> %x, zeroinitializer
|
|
%xor = xor <2 x i32> %x, <i32 2147483648, i32 2147483648>
|
|
%x.xor = select <2 x i1> %cmp, <2 x i32> %x, <2 x i32> %xor
|
|
ret <2 x i32> %x.xor
|
|
}
|
|
|
|
define <4 x i32> @canonicalize_to_shuffle(<4 x i32> %a, <4 x i32> %b) {
|
|
; CHECK-LABEL: @canonicalize_to_shuffle(
|
|
; CHECK-NEXT: [[SEL:%.*]] = shufflevector <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]], <4 x i32> <i32 0, i32 5, i32 6, i32 3>
|
|
; CHECK-NEXT: ret <4 x i32> [[SEL]]
|
|
;
|
|
%sel = select <4 x i1> <i1 true, i1 false, i1 false, i1 true>, <4 x i32> %a, <4 x i32> %b
|
|
ret <4 x i32> %sel
|
|
}
|
|
|
|
; Undef elements of the select condition may not be translated into undef elements of a shuffle mask
|
|
; because undef in a shuffle mask means we can return anything, not just one of the selected values.
|
|
; https://bugs.llvm.org/show_bug.cgi?id=32486
|
|
|
|
define <4 x i32> @undef_elts_in_condition(<4 x i32> %a, <4 x i32> %b) {
|
|
; CHECK-LABEL: @undef_elts_in_condition(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select <4 x i1> <i1 true, i1 undef, i1 false, i1 undef>, <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]
|
|
; CHECK-NEXT: ret <4 x i32> [[SEL]]
|
|
;
|
|
%sel = select <4 x i1> <i1 true, i1 undef, i1 false, i1 undef>, <4 x i32> %a, <4 x i32> %b
|
|
ret <4 x i32> %sel
|
|
}
|
|
|
|
; Don't die or try if the condition mask is a constant expression or contains a constant expression.
|
|
|
|
@g = global i32 0
|
|
|
|
define <4 x i32> @cannot_canonicalize_to_shuffle1(<4 x i32> %a, <4 x i32> %b) {
|
|
; CHECK-LABEL: @cannot_canonicalize_to_shuffle1(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select <4 x i1> bitcast (i4 ptrtoint (ptr @g to i4) to <4 x i1>), <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]
|
|
; CHECK-NEXT: ret <4 x i32> [[SEL]]
|
|
;
|
|
%sel = select <4 x i1> bitcast (i4 ptrtoint (ptr @g to i4) to <4 x i1>), <4 x i32> %a, <4 x i32> %b
|
|
ret <4 x i32> %sel
|
|
}
|
|
|
|
define <4 x i32> @cannot_canonicalize_to_shuffle2(<4 x i32> %a, <4 x i32> %b) {
|
|
; CHECK-LABEL: @cannot_canonicalize_to_shuffle2(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select <4 x i1> <i1 true, i1 undef, i1 false, i1 icmp sle (i16 ptrtoint (ptr @g to i16), i16 4)>, <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]
|
|
; CHECK-NEXT: ret <4 x i32> [[SEL]]
|
|
;
|
|
%sel = select <4 x i1> <i1 true, i1 undef, i1 false, i1 icmp sle (i16 ptrtoint (ptr @g to i16), i16 4)>, <4 x i32> %a, <4 x i32> %b
|
|
ret <4 x i32> %sel
|
|
}
|
|
|
|
declare void @llvm.assume(i1)
|
|
|
|
define i8 @assume_cond_true(i1 %cond, i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @assume_cond_true(
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[COND:%.*]])
|
|
; CHECK-NEXT: ret i8 [[X:%.*]]
|
|
;
|
|
call void @llvm.assume(i1 %cond)
|
|
%sel = select i1 %cond, i8 %x, i8 %y
|
|
ret i8 %sel
|
|
}
|
|
|
|
; computeKnownBitsFromAssume() understands the 'not' of an assumed condition.
|
|
|
|
define i8 @assume_cond_false(i1 %cond, i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @assume_cond_false(
|
|
; CHECK-NEXT: [[NOTCOND:%.*]] = xor i1 [[COND:%.*]], true
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[NOTCOND]])
|
|
; CHECK-NEXT: ret i8 [[Y:%.*]]
|
|
;
|
|
%notcond = xor i1 %cond, true
|
|
call void @llvm.assume(i1 %notcond)
|
|
%sel = select i1 %cond, i8 %x, i8 %y
|
|
ret i8 %sel
|
|
}
|
|
|
|
; Test case to make sure we don't consider an all ones float values for converting the select into a sext.
|
|
define <4 x float> @PR33721(<4 x float> %w) {
|
|
; CHECK-LABEL: @PR33721(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = fcmp ole <4 x float> [[W:%.*]], zeroinitializer
|
|
; CHECK-NEXT: [[TMP1:%.*]] = select <4 x i1> [[TMP0]], <4 x float> <float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000>, <4 x float> zeroinitializer
|
|
; CHECK-NEXT: ret <4 x float> [[TMP1]]
|
|
;
|
|
entry:
|
|
%0 = fcmp ole <4 x float> %w, zeroinitializer
|
|
%1 = select <4 x i1> %0, <4 x float> <float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000>, <4 x float> zeroinitializer
|
|
ret <4 x float> %1
|
|
}
|
|
|
|
; select(C, binop(select(C, X, Y), W), Z) -> select(C, binop(X, W), Z)
|
|
define i8 @test87(i1 %cond, i8 %w, i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: @test87(
|
|
; CHECK-NEXT: [[B:%.*]] = add i8 [[X:%.*]], [[W:%.*]]
|
|
; CHECK-NEXT: [[C:%.*]] = select i1 [[COND:%.*]], i8 [[B]], i8 [[Z:%.*]]
|
|
; CHECK-NEXT: ret i8 [[C]]
|
|
;
|
|
%a = select i1 %cond, i8 %x, i8 %y
|
|
%b = add i8 %a, %w
|
|
%c = select i1 %cond, i8 %b, i8 %z
|
|
ret i8 %c
|
|
}
|
|
|
|
; select(C, binop(select(C, X, Y), W), Z) -> select(C, Z, binop(Y, W))
|
|
define i8 @test88(i1 %cond, i8 %w, i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: @test88(
|
|
; CHECK-NEXT: [[B:%.*]] = sub i8 [[Y:%.*]], [[W:%.*]]
|
|
; CHECK-NEXT: [[C:%.*]] = select i1 [[COND:%.*]], i8 [[Z:%.*]], i8 [[B]]
|
|
; CHECK-NEXT: ret i8 [[C]]
|
|
;
|
|
%a = select i1 %cond, i8 %x, i8 %y
|
|
%b = sub i8 %a, %w
|
|
%c = select i1 %cond, i8 %z, i8 %b
|
|
ret i8 %c
|
|
}
|
|
|
|
; select(C, Z, binop(W, select(C, X, Y))) -> select(C, binop(X, W), Z)
|
|
define i8 @test89(i1 %cond, i8 %w, i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: @test89(
|
|
; CHECK-NEXT: [[B:%.*]] = and i8 [[X:%.*]], [[W:%.*]]
|
|
; CHECK-NEXT: [[C:%.*]] = select i1 [[COND:%.*]], i8 [[B]], i8 [[Z:%.*]]
|
|
; CHECK-NEXT: ret i8 [[C]]
|
|
;
|
|
%a = select i1 %cond, i8 %x, i8 %y
|
|
%b = and i8 %w, %a
|
|
%c = select i1 %cond, i8 %b, i8 %z
|
|
ret i8 %c
|
|
}
|
|
|
|
; select(C, Z, binop(W, select(C, X, Y))) -> select(C, Z, binop(W, Y))
|
|
define i8 @test90(i1 %cond, i8 %w, i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: @test90(
|
|
; CHECK-NEXT: [[B:%.*]] = or i8 [[Y:%.*]], [[W:%.*]]
|
|
; CHECK-NEXT: [[C:%.*]] = select i1 [[COND:%.*]], i8 [[Z:%.*]], i8 [[B]]
|
|
; CHECK-NEXT: ret i8 [[C]]
|
|
;
|
|
%a = select i1 %cond, i8 %x, i8 %y
|
|
%b = or i8 %w, %a
|
|
%c = select i1 %cond, i8 %z, i8 %b
|
|
ret i8 %c
|
|
}
|
|
|
|
define i32 @test_shl_zext_bool(i1 %t) {
|
|
; CHECK-LABEL: @test_shl_zext_bool(
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[T:%.*]], i32 4, i32 0
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%r = select i1 %t, i32 4, i32 0
|
|
ret i32 %r
|
|
}
|
|
|
|
define <2 x i32> @test_shl_zext_bool_splat(<2 x i1> %t) {
|
|
; CHECK-LABEL: @test_shl_zext_bool_splat(
|
|
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T:%.*]], <2 x i32> <i32 8, i32 8>, <2 x i32> zeroinitializer
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%r = select <2 x i1> %t, <2 x i32> <i32 8, i32 8>, <2 x i32> zeroinitializer
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define <2 x i32> @test_shl_zext_bool_vec(<2 x i1> %t) {
|
|
; CHECK-LABEL: @test_shl_zext_bool_vec(
|
|
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T:%.*]], <2 x i32> <i32 4, i32 8>, <2 x i32> zeroinitializer
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%r = select <2 x i1> %t, <2 x i32> <i32 4, i32 8>, <2 x i32> zeroinitializer
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define float @copysign1(float %x) {
|
|
; CHECK-LABEL: @copysign1(
|
|
; CHECK-NEXT: [[R:%.*]] = call float @llvm.copysign.f32(float 1.000000e+00, float [[X:%.*]])
|
|
; CHECK-NEXT: ret float [[R]]
|
|
;
|
|
%i = bitcast float %x to i32
|
|
%ispos = icmp sgt i32 %i, -1
|
|
%r = select i1 %ispos, float 1.0, float -1.0
|
|
ret float %r
|
|
}
|
|
|
|
define float @copysign1_fmf(float %x) {
|
|
; CHECK-LABEL: @copysign1_fmf(
|
|
; CHECK-NEXT: [[R:%.*]] = call float @llvm.copysign.f32(float 1.000000e+00, float [[X:%.*]])
|
|
; CHECK-NEXT: ret float [[R]]
|
|
;
|
|
%i = bitcast float %x to i32
|
|
%ispos = icmp sgt i32 %i, -1
|
|
%r = select nsz ninf i1 %ispos, float 1.0, float -1.0
|
|
ret float %r
|
|
}
|
|
|
|
define <2 x float> @copysign2(<2 x float> %x) {
|
|
; CHECK-LABEL: @copysign2(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = fneg <2 x float> [[X:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = call <2 x float> @llvm.copysign.v2f32(<2 x float> <float 4.200000e+01, float 4.200000e+01>, <2 x float> [[TMP1]])
|
|
; CHECK-NEXT: ret <2 x float> [[R]]
|
|
;
|
|
%i = bitcast <2 x float> %x to <2 x i32>
|
|
%isneg = icmp slt <2 x i32> %i, zeroinitializer
|
|
%r = select nsz <2 x i1> %isneg, <2 x float> <float 42.0, float 42.0>, <2 x float> <float -42.0, float -42.0>
|
|
ret <2 x float> %r
|
|
}
|
|
|
|
define float @copysign3(float %x) {
|
|
; CHECK-LABEL: @copysign3(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[X:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = call float @llvm.copysign.f32(float 4.300000e+01, float [[TMP1]])
|
|
; CHECK-NEXT: ret float [[R]]
|
|
;
|
|
%i = bitcast float %x to i32
|
|
%ispos = icmp ult i32 %i, 2147483648
|
|
%r = select fast i1 %ispos, float -43.0, float 43.0
|
|
ret float %r
|
|
}
|
|
|
|
define <2 x float> @copysign_vec_poison(<2 x float> %x) {
|
|
; CHECK-LABEL: @copysign_vec_poison(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = fneg <2 x float> [[X:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = call <2 x float> @llvm.copysign.v2f32(<2 x float> <float 4.200000e+01, float 4.200000e+01>, <2 x float> [[TMP1]])
|
|
; CHECK-NEXT: ret <2 x float> [[R]]
|
|
;
|
|
%i = bitcast <2 x float> %x to <2 x i32>
|
|
%isneg = icmp ugt <2 x i32> %i, <i32 2147483647, i32 2147483647>
|
|
%r = select arcp nnan <2 x i1> %isneg, <2 x float> <float 42.0, float poison>, <2 x float> <float -42.0, float -42.0>
|
|
ret <2 x float> %r
|
|
}
|
|
|
|
define <2 x float> @copysign_vec_poison1(<2 x float> %x) {
|
|
; CHECK-LABEL: @copysign_vec_poison1(
|
|
; CHECK-NEXT: [[R:%.*]] = call <2 x float> @llvm.copysign.v2f32(<2 x float> <float 4.200000e+01, float 4.200000e+01>, <2 x float> [[X:%.*]])
|
|
; CHECK-NEXT: ret <2 x float> [[R]]
|
|
;
|
|
%i = bitcast <2 x float> %x to <2 x i32>
|
|
%isneg = icmp ult <2 x i32> %i, <i32 2147483648, i32 2147483648>
|
|
%r = select arcp nnan <2 x i1> %isneg, <2 x float> <float 42.0, float 42.0>, <2 x float> <float poison, float -42.0>
|
|
ret <2 x float> %r
|
|
}
|
|
|
|
define <2 x float> @copysign_vec_poison3(<2 x float> %x) {
|
|
; CHECK-LABEL: @copysign_vec_poison3(
|
|
; CHECK-NEXT: [[R:%.*]] = call <2 x float> @llvm.copysign.v2f32(<2 x float> <float 4.200000e+01, float 4.200000e+01>, <2 x float> [[X:%.*]])
|
|
; CHECK-NEXT: ret <2 x float> [[R]]
|
|
;
|
|
%i = bitcast <2 x float> %x to <2 x i32>
|
|
%isneg = icmp ugt <2 x i32> %i, <i32 2147483647, i32 2147483647>
|
|
%r = select arcp nnan <2 x i1> %isneg, <2 x float> <float -42.0, float poison>, <2 x float> <float +42.0, float poison>
|
|
ret <2 x float> %r
|
|
}
|
|
|
|
declare void @use1(i1)
|
|
|
|
; Negative test
|
|
|
|
define float @copysign_extra_use(float %x) {
|
|
; CHECK-LABEL: @copysign_extra_use(
|
|
; CHECK-NEXT: [[I:%.*]] = bitcast float [[X:%.*]] to i32
|
|
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[I]], 0
|
|
; CHECK-NEXT: call void @use1(i1 [[ISNEG]])
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[ISNEG]], float -4.400000e+01, float 4.400000e+01
|
|
; CHECK-NEXT: ret float [[R]]
|
|
;
|
|
%i = bitcast float %x to i32
|
|
%isneg = icmp ugt i32 %i, 2147483647
|
|
call void @use1(i1 %isneg)
|
|
%r = select i1 %isneg, float -44.0, float 44.0
|
|
ret float %r
|
|
}
|
|
|
|
; Negative test
|
|
|
|
define float @copysign_type_mismatch(double %x) {
|
|
; CHECK-LABEL: @copysign_type_mismatch(
|
|
; CHECK-NEXT: [[I:%.*]] = bitcast double [[X:%.*]] to i64
|
|
; CHECK-NEXT: [[ISPOS:%.*]] = icmp sgt i64 [[I]], -1
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[ISPOS]], float 1.000000e+00, float -1.000000e+00
|
|
; CHECK-NEXT: ret float [[R]]
|
|
;
|
|
%i = bitcast double %x to i64
|
|
%ispos = icmp sgt i64 %i, -1
|
|
%r = select i1 %ispos, float 1.0, float -1.0
|
|
ret float %r
|
|
}
|
|
|
|
; Negative test
|
|
|
|
define <2 x float> @copysign_type_mismatch2(<2 x float> %x) {
|
|
; CHECK-LABEL: @copysign_type_mismatch2(
|
|
; CHECK-NEXT: [[I:%.*]] = bitcast <2 x float> [[X:%.*]] to i64
|
|
; CHECK-NEXT: [[ISPOS:%.*]] = icmp sgt i64 [[I]], -1
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[ISPOS]], <2 x float> <float 1.000000e+00, float 1.000000e+00>, <2 x float> <float -1.000000e+00, float -1.000000e+00>
|
|
; CHECK-NEXT: ret <2 x float> [[R]]
|
|
;
|
|
%i = bitcast <2 x float> %x to i64
|
|
%ispos = icmp sgt i64 %i, -1
|
|
%r = select i1 %ispos, <2 x float> <float 1.0, float 1.0>, <2 x float> <float -1.0, float -1.0>
|
|
ret <2 x float> %r
|
|
}
|
|
|
|
; Negative test
|
|
|
|
define float @copysign_wrong_cmp(float %x) {
|
|
; CHECK-LABEL: @copysign_wrong_cmp(
|
|
; CHECK-NEXT: [[I:%.*]] = bitcast float [[X:%.*]] to i32
|
|
; CHECK-NEXT: [[ISPOS:%.*]] = icmp sgt i32 [[I]], 0
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[ISPOS]], float 1.000000e+00, float -1.000000e+00
|
|
; CHECK-NEXT: ret float [[R]]
|
|
;
|
|
%i = bitcast float %x to i32
|
|
%ispos = icmp sgt i32 %i, 0
|
|
%r = select i1 %ispos, float 1.0, float -1.0
|
|
ret float %r
|
|
}
|
|
|
|
; Negative test
|
|
|
|
define float @copysign_wrong_const(float %x) {
|
|
; CHECK-LABEL: @copysign_wrong_const(
|
|
; CHECK-NEXT: [[I:%.*]] = bitcast float [[X:%.*]] to i32
|
|
; CHECK-NEXT: [[ISPOS:%.*]] = icmp sgt i32 [[I]], -1
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[ISPOS]], float 2.000000e+00, float -1.000000e+00
|
|
; CHECK-NEXT: ret float [[R]]
|
|
;
|
|
%i = bitcast float %x to i32
|
|
%ispos = icmp sgt i32 %i, -1
|
|
%r = select i1 %ispos, float 2.0, float -1.0
|
|
ret float %r
|
|
}
|
|
|
|
; TODO: we can replace select with a Phi.
|
|
define i32 @select_dominating_cond(i1 %cond, i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @select_dominating_cond(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[S:%.*]] = phi i32 [ [[Y:%.*]], [[IF_FALSE]] ], [ [[X:%.*]], [[IF_TRUE]] ]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
;
|
|
entry:
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
br label %merge
|
|
|
|
if.false:
|
|
br label %merge
|
|
|
|
merge:
|
|
%s = select i1 %cond, i32 %x, i32 %y
|
|
ret i32 %s
|
|
}
|
|
|
|
define i32 @select_dominating_inverted(i1 %cond, i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @select_dominating_inverted(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_FALSE:%.*]], label [[IF_TRUE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[S:%.*]] = phi i32 [ [[X:%.*]], [[IF_FALSE]] ], [ [[Y:%.*]], [[IF_TRUE]] ]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
;
|
|
entry:
|
|
%inverted = xor i1 %cond, 1
|
|
br i1 %inverted, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
br label %merge
|
|
|
|
if.false:
|
|
br label %merge
|
|
|
|
merge:
|
|
%s = select i1 %cond, i32 %x, i32 %y
|
|
ret i32 %s
|
|
}
|
|
|
|
; More complex CFG: the block with select has multiple predecessors.
|
|
define i32 @select_dominating_cond_multiple_preds(i1 %cond, i1 %cond2, i1 %cond3, i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @select_dominating_cond_multiple_preds(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: br i1 [[COND2:%.*]], label [[IF_TRUE_1:%.*]], label [[IF_TRUE_2:%.*]]
|
|
; CHECK: if.true.1:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.true.2:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br i1 [[COND3:%.*]], label [[IF_FALSE_1:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: if.false.1:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[S:%.*]] = phi i32 [ [[Y:%.*]], [[IF_FALSE_1]] ], [ [[X:%.*]], [[IF_TRUE_2]] ], [ [[X]], [[IF_TRUE_1]] ]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
br i1 %cond2, label %if.true.1, label %if.true.2
|
|
|
|
if.true.1:
|
|
br label %merge
|
|
|
|
if.true.2:
|
|
br label %merge
|
|
|
|
if.false:
|
|
br i1 %cond3, label %if.false.1, label %exit
|
|
|
|
if.false.1:
|
|
br label %merge
|
|
|
|
merge:
|
|
%s = select i1 %cond, i32 %x, i32 %y
|
|
ret i32 %s
|
|
|
|
exit:
|
|
ret i32 0
|
|
}
|
|
|
|
; More complex CFG for inverted case: the block with select has multiple predecessors.
|
|
define i32 @select_dominating_cond_inverted_multiple_preds(i1 %cond, i1 %cond2, i1 %cond3, i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @select_dominating_cond_inverted_multiple_preds(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_FALSE:%.*]], label [[IF_TRUE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: br i1 [[COND2:%.*]], label [[IF_TRUE_1:%.*]], label [[IF_TRUE_2:%.*]]
|
|
; CHECK: if.true.1:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.true.2:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br i1 [[COND3:%.*]], label [[IF_FALSE_1:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: if.false.1:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[S:%.*]] = phi i32 [ [[X:%.*]], [[IF_FALSE_1]] ], [ [[Y:%.*]], [[IF_TRUE_2]] ], [ [[Y]], [[IF_TRUE_1]] ]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
%inverted = xor i1 %cond, 1
|
|
br i1 %inverted, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
br i1 %cond2, label %if.true.1, label %if.true.2
|
|
|
|
if.true.1:
|
|
br label %merge
|
|
|
|
if.true.2:
|
|
br label %merge
|
|
|
|
if.false:
|
|
br i1 %cond3, label %if.false.1, label %exit
|
|
|
|
if.false.1:
|
|
br label %merge
|
|
|
|
merge:
|
|
%s = select i1 %cond, i32 %x, i32 %y
|
|
ret i32 %s
|
|
|
|
exit:
|
|
ret i32 0
|
|
}
|
|
|
|
; More complex CFG for inverted case: the block with select has multiple predecessors that can duplicate.
|
|
define i32 @select_dominating_cond_inverted_multiple_duplicating_preds(i1 %cond, i32 %cond2, i1 %cond3, i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @select_dominating_cond_inverted_multiple_duplicating_preds(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_FALSE:%.*]], label [[IF_TRUE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: switch i32 [[COND2:%.*]], label [[SWITCH_CASE_1:%.*]] [
|
|
; CHECK-NEXT: i32 1, label [[MERGE:%.*]]
|
|
; CHECK-NEXT: i32 2, label [[MERGE]]
|
|
; CHECK-NEXT: i32 3, label [[MERGE]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: switch.case.1:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br i1 [[COND3:%.*]], label [[IF_FALSE_1:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: if.false.1:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[S:%.*]] = phi i32 [ [[X:%.*]], [[IF_FALSE_1]] ], [ [[Y:%.*]], [[SWITCH_CASE_1]] ], [ [[Y]], [[IF_TRUE]] ], [ [[Y]], [[IF_TRUE]] ], [ [[Y]], [[IF_TRUE]] ]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
%inverted = xor i1 %cond, 1
|
|
br i1 %inverted, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
switch i32 %cond2, label %switch.case.1 [
|
|
i32 1, label %merge
|
|
i32 2, label %merge
|
|
i32 3, label %merge
|
|
]
|
|
|
|
switch.case.1:
|
|
br label %merge
|
|
|
|
if.false:
|
|
br i1 %cond3, label %if.false.1, label %exit
|
|
|
|
if.false.1:
|
|
br label %merge
|
|
|
|
merge:
|
|
%s = select i1 %cond, i32 %x, i32 %y
|
|
ret i32 %s
|
|
|
|
exit:
|
|
ret i32 0
|
|
}
|
|
|
|
; Negative test: currently we take condition from IDom, but might be willing to expand it in the future.
|
|
define i32 @select_not_imm_dominating_cond_neg(i1 %cond, i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @select_not_imm_dominating_cond_neg(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[S:%.*]] = select i1 [[COND]], i32 [[X:%.*]], i32 [[Y:%.*]]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
;
|
|
entry:
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
br label %merge
|
|
|
|
if.false:
|
|
br label %merge
|
|
|
|
merge:
|
|
br label %exit
|
|
|
|
exit:
|
|
%s = select i1 %cond, i32 %x, i32 %y
|
|
ret i32 %s
|
|
}
|
|
|
|
; Shows how we can leverage dominance to eliminate duplicating selects.
|
|
define i32 @select_dominance_chain(i1 %cond, i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @select_dominance_chain(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE_1:%.*]], label [[IF_FALSE_1:%.*]]
|
|
; CHECK: if.true.1:
|
|
; CHECK-NEXT: br label [[MERGE_1:%.*]]
|
|
; CHECK: if.false.1:
|
|
; CHECK-NEXT: br label [[MERGE_1]]
|
|
; CHECK: merge.1:
|
|
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE_2:%.*]], label [[IF_FALSE_2:%.*]]
|
|
; CHECK: if.true.2:
|
|
; CHECK-NEXT: br label [[MERGE_2:%.*]]
|
|
; CHECK: if.false.2:
|
|
; CHECK-NEXT: br label [[MERGE_2]]
|
|
; CHECK: merge.2:
|
|
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE_3:%.*]], label [[IF_FALSE_3:%.*]]
|
|
; CHECK: if.true.3:
|
|
; CHECK-NEXT: br label [[MERGE_3:%.*]]
|
|
; CHECK: if.false.3:
|
|
; CHECK-NEXT: br label [[MERGE_3]]
|
|
; CHECK: merge.3:
|
|
; CHECK-NEXT: [[S_1:%.*]] = phi i32 [ [[Y:%.*]], [[IF_FALSE_3]] ], [ [[X:%.*]], [[IF_TRUE_3]] ]
|
|
; CHECK-NEXT: [[SUM_2:%.*]] = mul i32 [[S_1]], 3
|
|
; CHECK-NEXT: ret i32 [[SUM_2]]
|
|
;
|
|
entry:
|
|
br i1 %cond, label %if.true.1, label %if.false.1
|
|
|
|
if.true.1:
|
|
br label %merge.1
|
|
|
|
if.false.1:
|
|
br label %merge.1
|
|
|
|
merge.1:
|
|
%s.1 = select i1 %cond, i32 %x, i32 %y
|
|
br i1 %cond, label %if.true.2, label %if.false.2
|
|
|
|
if.true.2:
|
|
br label %merge.2
|
|
|
|
if.false.2:
|
|
br label %merge.2
|
|
|
|
merge.2:
|
|
%s.2 = select i1 %cond, i32 %x, i32 %y
|
|
br i1 %cond, label %if.true.3, label %if.false.3
|
|
|
|
if.true.3:
|
|
br label %merge.3
|
|
|
|
if.false.3:
|
|
br label %merge.3
|
|
|
|
merge.3:
|
|
%s.3 = select i1 %cond, i32 %x, i32 %y
|
|
%sum.1 = add i32 %s.1, %s.2
|
|
%sum.2 = add i32 %sum.1, %s.3
|
|
ret i32 %sum.2
|
|
}
|
|
|
|
; TODO: We can replace select with a Phi and then sink a and b to respective
|
|
; branches.
|
|
define i32 @select_dominating_cond_and_sink(i1 %cond, i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @select_dominating_cond_and_sink(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[B:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[S:%.*]] = select i1 [[COND]], i32 [[A]], i32 [[B]]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
;
|
|
entry:
|
|
%a = add i32 %x, %y
|
|
%b = mul i32 %x, %y
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
br label %merge
|
|
|
|
if.false:
|
|
br label %merge
|
|
|
|
merge:
|
|
%s = select i1 %cond, i32 %a, i32 %b
|
|
ret i32 %s
|
|
}
|
|
|
|
define i32 @select_dominating_cond_same_labels(i1 %cond) {
|
|
; CHECK-LABEL: @select_dominating_cond_same_labels(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 false, label [[EXIT:%.*]], label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[RESULT:%.*]] = select i1 [[COND:%.*]], i32 123, i32 456
|
|
; CHECK-NEXT: ret i32 [[RESULT]]
|
|
;
|
|
entry:
|
|
%result = select i1 %cond, i32 123, i32 456
|
|
br i1 %cond, label %exit, label %exit
|
|
exit:
|
|
ret i32 %result
|
|
}
|
|
|
|
define i32 @select_phi_same_condition(i1 %cond, i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @select_phi_same_condition(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[S:%.*]] = phi i32 [ [[X:%.*]], [[IF_TRUE]] ], [ [[Z:%.*]], [[IF_FALSE]] ]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
;
|
|
entry:
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
br label %merge
|
|
|
|
if.false:
|
|
br label %merge
|
|
|
|
merge:
|
|
%phi = phi i32 [0, %if.true], [%z, %if.false]
|
|
%s = select i1 %cond, i32 %x, i32 %phi
|
|
ret i32 %s
|
|
}
|
|
|
|
|
|
; TODO: Replace with phi[a, c] and sink them to respective branches.
|
|
define i32 @select_phi_same_condition_sink(i1 %cond, i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @select_phi_same_condition_sink(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: [[B:%.*]] = mul i32 [[X:%.*]], [[Z:%.*]]
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, [[IF_TRUE]] ], [ [[B]], [[IF_FALSE]] ]
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[X]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[S:%.*]] = select i1 [[COND]], i32 [[A]], i32 [[PHI]]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
;
|
|
entry:
|
|
%a = add i32 %x, %y
|
|
%b = mul i32 %x, %z
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
br label %merge
|
|
|
|
if.false:
|
|
br label %merge
|
|
|
|
merge:
|
|
%phi = phi i32 [0, %if.true], [%b, %if.false]
|
|
%s = select i1 %cond, i32 %a, i32 %phi
|
|
ret i32 %s
|
|
}
|
|
|
|
declare i32 @__gxx_personality_v0(...)
|
|
declare i1 @foo()
|
|
|
|
define i32 @test_invoke_neg(i32 %x, i32 %y) nounwind uwtable ssp personality ptr @__gxx_personality_v0 {
|
|
; CHECK-LABEL: @test_invoke_neg(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COND:%.*]] = invoke i1 @foo()
|
|
; CHECK-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
; CHECK: invoke.cont:
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND]], i32 [[X:%.*]], i32 [[Y:%.*]]
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
; CHECK: lpad:
|
|
; CHECK-NEXT: [[LP:%.*]] = landingpad { i1, i32 }
|
|
; CHECK-NEXT: filter [0 x i1] zeroinitializer
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
entry:
|
|
%cond = invoke i1 @foo()
|
|
to label %invoke.cont unwind label %lpad
|
|
|
|
invoke.cont:
|
|
%sel = select i1 %cond, i32 %x, i32 %y
|
|
ret i32 %sel
|
|
|
|
lpad:
|
|
%lp = landingpad { i1, i32 }
|
|
filter [0 x i1] zeroinitializer
|
|
unreachable
|
|
}
|
|
|
|
declare i32 @bar()
|
|
|
|
define i32 @test_invoke_2_neg(i1 %cond, i32 %x, i32 %y) nounwind uwtable ssp personality ptr @__gxx_personality_v0 {
|
|
; CHECK-LABEL: @test_invoke_2_neg(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: [[RESULT:%.*]] = invoke i32 @bar()
|
|
; CHECK-NEXT: to label [[MERGE]] unwind label [[LPAD:%.*]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, [[IF_TRUE]] ], [ [[RESULT]], [[IF_FALSE]] ]
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND]], i32 1, i32 [[PHI]]
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
; CHECK: lpad:
|
|
; CHECK-NEXT: [[LP:%.*]] = landingpad { i1, i32 }
|
|
; CHECK-NEXT: filter [0 x i1] zeroinitializer
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
entry:
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
br label %merge
|
|
|
|
if.false:
|
|
%result = invoke i32 @bar()
|
|
to label %merge unwind label %lpad
|
|
|
|
merge:
|
|
%phi = phi i32 [ 0, %if.true ], [ %result, %if.false ]
|
|
%sel = select i1 %cond, i32 1, i32 %phi
|
|
ret i32 %sel
|
|
|
|
lpad:
|
|
%lp = landingpad { i1, i32 }
|
|
filter [0 x i1] zeroinitializer
|
|
unreachable
|
|
}
|
|
|
|
define i32 @select_phi_same_condition_switch(i1 %cond, i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @select_phi_same_condition_switch(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: switch i32 [[X:%.*]], label [[EXIT:%.*]] [
|
|
; CHECK-NEXT: i32 1, label [[MERGE:%.*]]
|
|
; CHECK-NEXT: i32 2, label [[MERGE]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 0
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[S:%.*]] = phi i32 [ [[X]], [[IF_TRUE]] ], [ [[X]], [[IF_TRUE]] ], [ [[Y:%.*]], [[IF_FALSE]] ]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
;
|
|
entry:
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
switch i32 %x, label %exit [
|
|
i32 1, label %merge
|
|
i32 2, label %merge
|
|
]
|
|
|
|
exit:
|
|
ret i32 0
|
|
|
|
if.false:
|
|
br label %merge
|
|
|
|
merge:
|
|
%phi = phi i32 [0, %if.true], [0, %if.true], [%y, %if.false]
|
|
%s = select i1 %cond, i32 %x, i32 %phi
|
|
ret i32 %s
|
|
}
|
|
|
|
define i32 @transit_different_values_through_phi(i1 %cond, i1 %cond2) {
|
|
; CHECK-LABEL: @transit_different_values_through_phi(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: br i1 [[COND2:%.*]], label [[IF_TRUE_1:%.*]], label [[IF_TRUE_2:%.*]]
|
|
; CHECK: if.true.1:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.true.2:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[S:%.*]] = phi i32 [ 1, [[IF_TRUE_1]] ], [ 2, [[IF_TRUE_2]] ], [ 3, [[IF_FALSE]] ]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
br i1 %cond2, label %if.true.1, label %if.true.2
|
|
|
|
if.true.1:
|
|
br label %merge
|
|
|
|
if.true.2:
|
|
br label %merge
|
|
|
|
if.false:
|
|
br label %merge
|
|
|
|
merge:
|
|
%p = phi i32 [ 1, %if.true.1 ], [ 2, %if.true.2 ], [ 4, %if.false ]
|
|
%s = select i1 %cond, i32 %p, i32 3
|
|
ret i32 %s
|
|
|
|
exit:
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @select_phi_degenerate(i1 %cond, i1 %cond2) {
|
|
; CHECK-LABEL: @select_phi_degenerate(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[LOOP:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[SELECT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_INC:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_INC]] = add i32 [[SELECT]], 1
|
|
; CHECK-NEXT: br i1 [[COND2:%.*]], label [[LOOP]], label [[EXIT2:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 0
|
|
; CHECK: exit2:
|
|
; CHECK-NEXT: ret i32 [[IV_INC]]
|
|
;
|
|
entry:
|
|
br i1 %cond, label %loop, label %exit
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
|
%select = select i1 %cond, i32 %iv, i32 -1
|
|
%iv.inc = add i32 %select, 1
|
|
br i1 %cond2, label %loop, label %exit2
|
|
|
|
exit:
|
|
ret i32 0
|
|
|
|
exit2:
|
|
ret i32 %iv.inc
|
|
}
|
|
|
|
define i32 @test_select_into_phi_not_idom(i1 %cond, i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test_select_into_phi_not_idom(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 [[A:%.*]]
|
|
;
|
|
entry:
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
br label %merge
|
|
|
|
if.false:
|
|
br label %merge
|
|
|
|
merge:
|
|
%phi = phi i32 [%A, %if.true], [%B, %if.false]
|
|
br label %exit
|
|
|
|
exit:
|
|
%sel = select i1 %cond, i32 %phi, i32 %A
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i32 @test_select_into_phi_not_idom_2(i1 %cond, i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test_select_into_phi_not_idom_2(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 [[B:%.*]]
|
|
;
|
|
entry:
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
br label %merge
|
|
|
|
if.false:
|
|
br label %merge
|
|
|
|
merge:
|
|
%phi = phi i32 [%A, %if.true], [%B, %if.false]
|
|
br label %exit
|
|
|
|
exit:
|
|
%sel = select i1 %cond, i32 %B, i32 %phi
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i32 @test_select_into_phi_not_idom_inverted(i1 %cond, i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test_select_into_phi_not_idom_inverted(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_FALSE:%.*]], label [[IF_TRUE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[SEL:%.*]] = phi i32 [ [[A:%.*]], [[IF_TRUE]] ], [ [[B:%.*]], [[IF_FALSE]] ]
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
entry:
|
|
%inverted = xor i1 %cond, 1
|
|
br i1 %inverted, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
br label %merge
|
|
|
|
if.false:
|
|
br label %merge
|
|
|
|
merge:
|
|
%phi = phi i32 [%A, %if.true], [%B, %if.false]
|
|
br label %exit
|
|
|
|
exit:
|
|
%sel = select i1 %cond, i32 %phi, i32 %A
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i32 @test_select_into_phi_not_idom_inverted_2(i1 %cond, i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test_select_into_phi_not_idom_inverted_2(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_FALSE:%.*]], label [[IF_TRUE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[SEL:%.*]] = phi i32 [ [[A:%.*]], [[IF_TRUE]] ], [ [[B:%.*]], [[IF_FALSE]] ]
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
entry:
|
|
%inverted = xor i1 %cond, 1
|
|
br i1 %inverted, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
br label %merge
|
|
|
|
if.false:
|
|
br label %merge
|
|
|
|
merge:
|
|
%phi = phi i32 [%A, %if.true], [%B, %if.false]
|
|
br label %exit
|
|
|
|
exit:
|
|
%sel = select i1 %cond, i32 %B, i32 %phi
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i32 @test_select_into_phi_not_idom_no_dom_input_1(i1 %cond, i32 %A, i32 %B, ptr %p) {
|
|
; CHECK-LABEL: @test_select_into_phi_not_idom_no_dom_input_1(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[SEL:%.*]] = phi i32 [ [[C]], [[IF_TRUE]] ], [ [[A:%.*]], [[IF_FALSE]] ]
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
entry:
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
%C = load i32, ptr %p
|
|
br label %merge
|
|
|
|
if.false:
|
|
br label %merge
|
|
|
|
merge:
|
|
%phi = phi i32 [%C, %if.true], [%B, %if.false]
|
|
br label %exit
|
|
|
|
exit:
|
|
%sel = select i1 %cond, i32 %phi, i32 %A
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i32 @test_select_into_phi_not_idom_no_dom_input_2(i1 %cond, i32 %A, i32 %B, ptr %p) {
|
|
; CHECK-LABEL: @test_select_into_phi_not_idom_no_dom_input_2(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[SEL:%.*]] = phi i32 [ [[B:%.*]], [[IF_TRUE]] ], [ [[C]], [[IF_FALSE]] ]
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
entry:
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
br label %merge
|
|
|
|
if.false:
|
|
%C = load i32, ptr %p
|
|
br label %merge
|
|
|
|
merge:
|
|
%phi = phi i32 [%A, %if.true], [%C, %if.false]
|
|
br label %exit
|
|
|
|
exit:
|
|
%sel = select i1 %cond, i32 %B, i32 %phi
|
|
ret i32 %sel
|
|
}
|
|
|
|
; 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
|
|
}
|
|
|
|
define i8 @cond_freeze(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @cond_freeze(
|
|
; CHECK-NEXT: ret i8 [[Y:%.*]]
|
|
;
|
|
%cond.fr = freeze i1 undef
|
|
%s = select i1 %cond.fr, i8 %x, i8 %y
|
|
ret i8 %s
|
|
}
|
|
|
|
define i8 @cond_freeze_constant_false_val(i8 %x) {
|
|
; CHECK-LABEL: @cond_freeze_constant_false_val(
|
|
; CHECK-NEXT: ret i8 1
|
|
;
|
|
%cond.fr = freeze i1 undef
|
|
%s = select i1 %cond.fr, i8 %x, i8 1
|
|
ret i8 %s
|
|
}
|
|
|
|
define i8 @cond_freeze_constant_true_val(i8 %x) {
|
|
; CHECK-LABEL: @cond_freeze_constant_true_val(
|
|
; CHECK-NEXT: ret i8 1
|
|
;
|
|
%cond.fr = freeze i1 undef
|
|
%s = select i1 %cond.fr, i8 1, i8 %x
|
|
ret i8 %s
|
|
}
|
|
|
|
define i8 @cond_freeze_both_arms_constant() {
|
|
; CHECK-LABEL: @cond_freeze_both_arms_constant(
|
|
; CHECK-NEXT: ret i8 42
|
|
;
|
|
%cond.fr = freeze i1 undef
|
|
%s = select i1 %cond.fr, i8 42, i8 3
|
|
ret i8 %s
|
|
}
|
|
|
|
define <2 x i8> @cond_freeze_constant_true_val_vec(<2 x i8> %x) {
|
|
; CHECK-LABEL: @cond_freeze_constant_true_val_vec(
|
|
; CHECK-NEXT: ret <2 x i8> <i8 1, i8 2>
|
|
;
|
|
%cond.fr = freeze <2 x i1> <i1 undef, i1 undef>
|
|
%s = select <2 x i1> %cond.fr, <2 x i8> <i8 1, i8 2>, <2 x i8> %x
|
|
ret <2 x i8> %s
|
|
}
|
|
|
|
define <2 x i8> @partial_cond_freeze_constant_true_val_vec(<2 x i8> %x) {
|
|
; CHECK-LABEL: @partial_cond_freeze_constant_true_val_vec(
|
|
; CHECK-NEXT: ret <2 x i8> <i8 1, i8 2>
|
|
;
|
|
%cond.fr = freeze <2 x i1> <i1 true, i1 undef>
|
|
%s = select <2 x i1> %cond.fr, <2 x i8> <i8 1, i8 2>, <2 x i8> %x
|
|
ret <2 x i8> %s
|
|
}
|
|
|
|
define <2 x i8> @partial_cond_freeze_constant_false_val_vec(<2 x i8> %x) {
|
|
; CHECK-LABEL: @partial_cond_freeze_constant_false_val_vec(
|
|
; CHECK-NEXT: [[S1:%.*]] = insertelement <2 x i8> [[X:%.*]], i8 2, i64 1
|
|
; CHECK-NEXT: ret <2 x i8> [[S1]]
|
|
;
|
|
%cond.fr = freeze <2 x i1> <i1 true, i1 undef>
|
|
%s = select <2 x i1> %cond.fr, <2 x i8> %x, <2 x i8> <i8 1, i8 2>
|
|
ret <2 x i8> %s
|
|
}
|
|
|
|
define <2 x i8> @partial_cond_freeze_both_arms_constant_vec() {
|
|
; CHECK-LABEL: @partial_cond_freeze_both_arms_constant_vec(
|
|
; CHECK-NEXT: ret <2 x i8> <i8 42, i8 2>
|
|
;
|
|
%cond.fr = freeze <2 x i1> <i1 false, i1 undef>
|
|
%s = select <2 x i1> %cond.fr, <2 x i8> <i8 1, i8 2>, <2 x i8> <i8 42, i8 43>
|
|
ret <2 x i8> %s
|
|
}
|
|
|
|
declare void @foo2(i8, i8)
|
|
|
|
define void @cond_freeze_multipleuses(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @cond_freeze_multipleuses(
|
|
; CHECK-NEXT: call void @foo2(i8 [[Y:%.*]], i8 [[X:%.*]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%cond.fr = freeze i1 undef
|
|
%s = select i1 %cond.fr, i8 %x, i8 %y
|
|
%s2 = select i1 %cond.fr, i8 %y, i8 %x
|
|
call void @foo2(i8 %s, i8 %s2)
|
|
ret void
|
|
}
|
|
|
|
define i32 @select_freeze_icmp_eq(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @select_freeze_icmp_eq(
|
|
; CHECK-NEXT: ret i32 [[Y:%.*]]
|
|
;
|
|
%c = icmp eq i32 %x, %y
|
|
%c.fr = freeze i1 %c
|
|
%v = select i1 %c.fr, i32 %x, i32 %y
|
|
ret i32 %v
|
|
}
|
|
|
|
define i32 @select_freeze_icmp_ne(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @select_freeze_icmp_ne(
|
|
; CHECK-NEXT: ret i32 [[X:%.*]]
|
|
;
|
|
%c = icmp ne i32 %x, %y
|
|
%c.fr = freeze i1 %c
|
|
%v = select i1 %c.fr, i32 %x, i32 %y
|
|
ret i32 %v
|
|
}
|
|
|
|
define i32 @select_freeze_icmp_else(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @select_freeze_icmp_else(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[C_FR:%.*]] = freeze i1 [[C]]
|
|
; CHECK-NEXT: [[V:%.*]] = select i1 [[C_FR]], i32 [[X]], i32 [[Y]]
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
%c = icmp ult i32 %x, %y
|
|
%c.fr = freeze i1 %c
|
|
%v = select i1 %c.fr, i32 %x, i32 %y
|
|
ret i32 %v
|
|
}
|
|
|
|
declare void @use_i1_i32(i1, i32)
|
|
|
|
define void @select_freeze_icmp_multuses(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @select_freeze_icmp_multuses(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[C_FR:%.*]] = freeze i1 [[C]]
|
|
; CHECK-NEXT: [[V:%.*]] = select i1 [[C_FR]], i32 [[X]], i32 [[Y]]
|
|
; CHECK-NEXT: call void @use_i1_i32(i1 [[C_FR]], i32 [[V]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%c = icmp ne i32 %x, %y
|
|
%c.fr = freeze i1 %c
|
|
%v = select i1 %c.fr, i32 %x, i32 %y
|
|
call void @use_i1_i32(i1 %c.fr, i32 %v)
|
|
ret void
|
|
}
|
|
|
|
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 immarg true), !range [[RNG0:![0-9]+]]
|
|
; 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 immarg true)
|
|
%shifted = lshr i32 %arg, %trailing
|
|
%r1.sroa.0.1 = select i1 %cmp, i32 0, i32 %shifted
|
|
ret i32 %r1.sroa.0.1
|
|
}
|
|
|
|
define i8 @select_replacement_add_eq(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @select_replacement_add_eq(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 1
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 2, i8 [[Y:%.*]]
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i8 %x, 1
|
|
%add = add i8 %x, 1
|
|
%sel = select i1 %cmp, i8 %add, i8 %y
|
|
ret i8 %sel
|
|
}
|
|
|
|
define <2 x i8> @select_replacement_add_eq_vec(<2 x i8> %x, <2 x i8> %y) {
|
|
; CHECK-LABEL: @select_replacement_add_eq_vec(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 1, i8 1>
|
|
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i8> <i8 2, i8 2>, <2 x i8> [[Y:%.*]]
|
|
; CHECK-NEXT: ret <2 x i8> [[SEL]]
|
|
;
|
|
%cmp = icmp eq <2 x i8> %x, <i8 1, i8 1>
|
|
%add = add <2 x i8> %x, <i8 1, i8 1>
|
|
%sel = select <2 x i1> %cmp, <2 x i8> %add, <2 x i8> %y
|
|
ret <2 x i8> %sel
|
|
}
|
|
|
|
define <2 x i8> @select_replacement_add_eq_vec_nonuniform(<2 x i8> %x, <2 x i8> %y) {
|
|
; CHECK-LABEL: @select_replacement_add_eq_vec_nonuniform(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 1, i8 2>
|
|
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i8> <i8 4, i8 6>, <2 x i8> [[Y:%.*]]
|
|
; CHECK-NEXT: ret <2 x i8> [[SEL]]
|
|
;
|
|
%cmp = icmp eq <2 x i8> %x, <i8 1, i8 2>
|
|
%add = add <2 x i8> %x, <i8 3, i8 4>
|
|
%sel = select <2 x i1> %cmp, <2 x i8> %add, <2 x i8> %y
|
|
ret <2 x i8> %sel
|
|
}
|
|
|
|
define <2 x i8> @select_replacement_add_eq_vec_poison(<2 x i8> %x, <2 x i8> %y) {
|
|
; CHECK-LABEL: @select_replacement_add_eq_vec_poison(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 1, i8 poison>
|
|
; CHECK-NEXT: [[ADD:%.*]] = add <2 x i8> [[X]], <i8 1, i8 1>
|
|
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[ADD]], <2 x i8> [[Y:%.*]]
|
|
; CHECK-NEXT: ret <2 x i8> [[SEL]]
|
|
;
|
|
%cmp = icmp eq <2 x i8> %x, <i8 1, i8 poison>
|
|
%add = add <2 x i8> %x, <i8 1, i8 1>
|
|
%sel = select <2 x i1> %cmp, <2 x i8> %add, <2 x i8> %y
|
|
ret <2 x i8> %sel
|
|
}
|
|
|
|
define i8 @select_replacement_add_ne(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @select_replacement_add_ne(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[X:%.*]], 1
|
|
; CHECK-NEXT: call void @use(i1 [[CMP]])
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[Y:%.*]], i8 2
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%cmp = icmp ne i8 %x, 1
|
|
call void @use(i1 %cmp)
|
|
%add = add i8 %x, 1
|
|
%sel = select i1 %cmp, i8 %y, i8 %add
|
|
ret i8 %sel
|
|
}
|
|
|
|
define i8 @select_replacement_add_nuw(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @select_replacement_add_nuw(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 1
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 2, i8 [[Y:%.*]]
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i8 %x, 1
|
|
%add = add nuw i8 %x, 1
|
|
%sel = select i1 %cmp, i8 %add, i8 %y
|
|
ret i8 %sel
|
|
}
|
|
|
|
define i8 @select_replacement_sub_noundef(i8 %x, i8 noundef %y, i8 %z) {
|
|
; CHECK-LABEL: @select_replacement_sub_noundef(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 0, i8 [[Z:%.*]]
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i8 %x, %y
|
|
%sub = sub i8 %x, %y
|
|
%sel = select i1 %cmp, i8 %sub, i8 %z
|
|
ret i8 %sel
|
|
}
|
|
|
|
; TODO: The transform is also safe without noundef.
|
|
define i8 @select_replacement_sub(i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: @select_replacement_sub(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[SUB]], i8 [[Z:%.*]]
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i8 %x, %y
|
|
%sub = sub i8 %x, %y
|
|
%sel = select i1 %cmp, i8 %sub, i8 %z
|
|
ret i8 %sel
|
|
}
|
|
|
|
; FIXME: This is safe to fold.
|
|
define i8 @select_replacement_shift_noundef(i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: @select_replacement_shift_noundef(
|
|
; CHECK-NEXT: [[SHR:%.*]] = lshr exact i8 [[X:%.*]], 1
|
|
; CHECK-NEXT: call void @use_i8(i8 noundef [[SHR]])
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[SHR]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SHL:%.*]] = shl i8 [[Y]], 1
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[SHL]], i8 [[Z:%.*]]
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%shr = lshr exact i8 %x, 1
|
|
call void @use_i8(i8 noundef %shr)
|
|
%cmp = icmp eq i8 %shr, %y
|
|
%shl = shl i8 %y, 1
|
|
%sel = select i1 %cmp, i8 %shl, i8 %z
|
|
ret i8 %sel
|
|
}
|
|
|
|
; TODO: The transform is also safe without noundef.
|
|
define i8 @select_replacement_shift(i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: @select_replacement_shift(
|
|
; CHECK-NEXT: [[SHR:%.*]] = lshr exact i8 [[X:%.*]], 1
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[SHR]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SHL:%.*]] = shl i8 [[Y]], 1
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[SHL]], i8 [[Z:%.*]]
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%shr = lshr exact i8 %x, 1
|
|
%cmp = icmp eq i8 %shr, %y
|
|
%shl = shl i8 %y, 1
|
|
%sel = select i1 %cmp, i8 %shl, i8 %z
|
|
ret i8 %sel
|
|
}
|
|
|
|
define i8 @select_replacement_loop(i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: @select_replacement_loop(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[X]], i8 [[Z:%.*]]
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i8 %x, %y
|
|
%sel = select i1 %cmp, i8 %x, i8 %z
|
|
ret i8 %sel
|
|
}
|
|
|
|
define i32 @select_replacement_loop2(i32 %arg, i32 %arg2) {
|
|
; CHECK-LABEL: @select_replacement_loop2(
|
|
; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[ARG:%.*]], [[ARG2:%.*]]
|
|
; CHECK-NEXT: ret i32 [[DIV]]
|
|
;
|
|
%div = udiv i32 %arg, %arg2
|
|
%mul = mul nsw i32 %div, %arg2
|
|
%cmp = icmp eq i32 %mul, %arg
|
|
%sel = select i1 %cmp, i32 %div, i32 undef
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i8 @select_replacement_loop3(i32 noundef %x) {
|
|
; CHECK-LABEL: @select_replacement_loop3(
|
|
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 [[X:%.*]] to i8
|
|
; CHECK-NEXT: [[REV:%.*]] = call i8 @llvm.bitreverse.i8(i8 [[TRUNC]])
|
|
; CHECK-NEXT: [[EXT:%.*]] = zext i8 [[REV]] to i32
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[EXT]], [[X]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[TRUNC]], i8 0
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%trunc = trunc i32 %x to i8
|
|
%rev = call i8 @llvm.bitreverse.i8(i8 %trunc)
|
|
%ext = zext i8 %rev to i32
|
|
%cmp = icmp eq i32 %ext, %x
|
|
%sel = select i1 %cmp, i8 %trunc, i8 0
|
|
ret i8 %sel
|
|
}
|
|
|
|
define i16 @select_replacement_loop4(i16 noundef %p_12) {
|
|
; CHECK-LABEL: @select_replacement_loop4(
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i16 [[P_12:%.*]], 1
|
|
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i16 [[P_12]], 2
|
|
; CHECK-NEXT: [[AND3:%.*]] = select i1 [[CMP2]], i16 [[AND1]], i16 0
|
|
; CHECK-NEXT: ret i16 [[AND3]]
|
|
;
|
|
%cmp1 = icmp ult i16 %p_12, 2
|
|
%and1 = and i16 %p_12, 1
|
|
%and2 = select i1 %cmp1, i16 %and1, i16 0
|
|
%cmp2 = icmp eq i16 %and2, %p_12
|
|
%and3 = select i1 %cmp2, i16 %and1, i16 0
|
|
ret i16 %and3
|
|
}
|
|
|
|
define ptr @select_replacement_gep_inbounds(ptr %base, i64 %offset) {
|
|
; CHECK-LABEL: @select_replacement_gep_inbounds(
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[BASE:%.*]], i64 [[OFFSET:%.*]]
|
|
; CHECK-NEXT: ret ptr [[GEP]]
|
|
;
|
|
%cmp = icmp eq i64 %offset, 0
|
|
%gep = getelementptr inbounds i8, ptr %base, i64 %offset
|
|
%sel = select i1 %cmp, ptr %base, ptr %gep
|
|
ret ptr %sel
|
|
}
|
|
|
|
define i8 @replace_false_op_eq_shl_or_disjoint(i8 %x) {
|
|
; CHECK-LABEL: @replace_false_op_eq_shl_or_disjoint(
|
|
; CHECK-NEXT: [[SHL:%.*]] = shl i8 [[X:%.*]], 3
|
|
; CHECK-NEXT: [[OR:%.*]] = or i8 [[SHL]], [[X]]
|
|
; CHECK-NEXT: ret i8 [[OR]]
|
|
;
|
|
%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
|
|
}
|
|
|
|
define i8 @select_or_disjoint_eq(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @select_or_disjoint_eq(
|
|
; CHECK-NEXT: [[OR:%.*]] = or i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret i8 [[OR]]
|
|
;
|
|
%cmp = icmp eq i8 %x, %y
|
|
%or = or disjoint i8 %x, %y
|
|
%sel = select i1 %cmp, i8 %x, i8 %or
|
|
ret i8 %sel
|
|
}
|
|
|
|
define <2 x i1> @partial_true_undef_condval(<2 x i1> %x) {
|
|
; CHECK-LABEL: @partial_true_undef_condval(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 poison>
|
|
;
|
|
%r = select <2 x i1> <i1 true, i1 poison>, <2 x i1> <i1 true, i1 poison>, <2 x i1> %x
|
|
ret <2 x i1> %r
|
|
}
|
|
|
|
define <2 x i1> @partial_false_undef_condval(<2 x i1> %x) {
|
|
; CHECK-LABEL: @partial_false_undef_condval(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 false, i1 poison>
|
|
;
|
|
%r = select <2 x i1> <i1 false, i1 poison>, <2 x i1> %x, <2 x i1> <i1 false, i1 poison>
|
|
ret <2 x i1> %r
|
|
}
|
|
|
|
; select (x == 0), 0, x * y --> freeze(y) * x
|
|
define i32 @mul_select_eq_zero(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @mul_select_eq_zero(
|
|
; CHECK-NEXT: [[Y_FR:%.*]] = freeze i32 [[Y:%.*]]
|
|
; CHECK-NEXT: [[M:%.*]] = mul i32 [[Y_FR]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[M]]
|
|
;
|
|
%c = icmp eq i32 %x, 0
|
|
%m = mul i32 %x, %y
|
|
%r = select i1 %c, i32 0, i32 %m
|
|
ret i32 %r
|
|
}
|
|
|
|
; select (y == 0), 0, x * y --> freeze(x) * y
|
|
define i32 @mul_select_eq_zero_commute(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @mul_select_eq_zero_commute(
|
|
; CHECK-NEXT: [[X_FR:%.*]] = freeze i32 [[X:%.*]]
|
|
; CHECK-NEXT: [[M:%.*]] = mul i32 [[X_FR]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret i32 [[M]]
|
|
;
|
|
%c = icmp eq i32 %y, 0
|
|
%m = mul i32 %x, %y
|
|
%r = select i1 %c, i32 0, i32 %m
|
|
ret i32 %r
|
|
}
|
|
|
|
; Check that mul's flags preserved during the transformation.
|
|
define i32 @mul_select_eq_zero_copy_flags(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @mul_select_eq_zero_copy_flags(
|
|
; CHECK-NEXT: [[Y_FR:%.*]] = freeze i32 [[Y:%.*]]
|
|
; CHECK-NEXT: [[M:%.*]] = mul nuw nsw i32 [[Y_FR]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[M]]
|
|
;
|
|
%c = icmp eq i32 %x, 0
|
|
%m = mul nuw nsw i32 %x, %y
|
|
%r = select i1 %c, i32 0, i32 %m
|
|
ret i32 %r
|
|
}
|
|
|
|
; Check that the transformation could be applied after condition's inversion.
|
|
; select (x != 0), x * y, 0 --> freeze(y) * x
|
|
define i32 @mul_select_ne_zero(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @mul_select_ne_zero(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: [[Y_FR:%.*]] = freeze i32 [[Y:%.*]]
|
|
; CHECK-NEXT: [[M:%.*]] = mul i32 [[Y_FR]], [[X]]
|
|
; CHECK-NEXT: call void @use(i1 [[C]])
|
|
; CHECK-NEXT: ret i32 [[M]]
|
|
;
|
|
%c = icmp ne i32 %x, 0
|
|
%m = mul i32 %x, %y
|
|
%r = select i1 %c, i32 %m, i32 0
|
|
call void @use(i1 %c)
|
|
ret i32 %r
|
|
}
|
|
|
|
; Check that if one of a select's branches returns undef then
|
|
; an expression could be folded into mul as if there was a 0 instead of undef.
|
|
; select (x == 0), undef, x * y --> freeze(y) * x
|
|
define i32 @mul_select_eq_zero_sel_undef(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @mul_select_eq_zero_sel_undef(
|
|
; CHECK-NEXT: [[Y_FR:%.*]] = freeze i32 [[Y:%.*]]
|
|
; CHECK-NEXT: [[M:%.*]] = mul i32 [[Y_FR]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[M]]
|
|
;
|
|
%c = icmp eq i32 %x, 0
|
|
%m = mul i32 %x, %y
|
|
%r = select i1 %c, i32 undef, i32 %m
|
|
ret i32 %r
|
|
}
|
|
|
|
; Check that the transformation is applied disregard to a number
|
|
; of expression's users.
|
|
define i32 @mul_select_eq_zero_multiple_users(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @mul_select_eq_zero_multiple_users(
|
|
; CHECK-NEXT: [[Y_FR:%.*]] = freeze i32 [[Y:%.*]]
|
|
; CHECK-NEXT: [[M:%.*]] = mul i32 [[Y_FR]], [[X:%.*]]
|
|
; CHECK-NEXT: call void @use_i32(i32 [[M]])
|
|
; CHECK-NEXT: call void @use_i32(i32 [[M]])
|
|
; CHECK-NEXT: call void @use_i32(i32 [[M]])
|
|
; CHECK-NEXT: ret i32 [[M]]
|
|
;
|
|
%m = mul i32 %x, %y
|
|
call void @use_i32(i32 %m)
|
|
%c = icmp eq i32 %x, 0
|
|
%r = select i1 %c, i32 0, i32 %m
|
|
call void @use_i32(i32 %m)
|
|
call void @use_i32(i32 %r)
|
|
ret i32 %r
|
|
}
|
|
|
|
; Negative test: select's condition is unrelated to multiplied values,
|
|
; so the transformation should not be applied.
|
|
define i32 @mul_select_eq_zero_unrelated_condition(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @mul_select_eq_zero_unrelated_condition(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[Z:%.*]], 0
|
|
; CHECK-NEXT: [[M:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[C]], i32 0, i32 [[M]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%c = icmp eq i32 %z, 0
|
|
%m = mul i32 %x, %y
|
|
%r = select i1 %c, i32 0, i32 %m
|
|
ret i32 %r
|
|
}
|
|
|
|
; select (<k x elt> x == 0), <k x elt> 0, <k x elt> x * y --> freeze(y) * x
|
|
define <4 x i32> @mul_select_eq_zero_vector(<4 x i32> %x, <4 x i32> %y) {
|
|
; CHECK-LABEL: @mul_select_eq_zero_vector(
|
|
; CHECK-NEXT: [[Y_FR:%.*]] = freeze <4 x i32> [[Y:%.*]]
|
|
; CHECK-NEXT: [[M:%.*]] = mul <4 x i32> [[Y_FR]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <4 x i32> [[M]]
|
|
;
|
|
%c = icmp eq <4 x i32> %x, zeroinitializer
|
|
%m = mul <4 x i32> %x, %y
|
|
%r = select <4 x i1> %c, <4 x i32> zeroinitializer, <4 x i32> %m
|
|
ret <4 x i32> %r
|
|
}
|
|
|
|
; Check that a select is folded into multiplication if condition's operand
|
|
; is a vector consisting of zeros and poisons.
|
|
; select (<k x elt> x == {0, poison, ...}), <k x elt> 0, <k x elt> x * y --> freeze(y) * x
|
|
define <2 x i32> @mul_select_eq_poison_vector(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @mul_select_eq_poison_vector(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i32> [[Y_FR:%.*]], <i32 0, i32 poison>
|
|
; CHECK-NEXT: [[M:%.*]] = mul <2 x i32> [[Y_FR]], [[X:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[C]], <2 x i32> <i32 0, i32 42>, <2 x i32> [[M]]
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%c = icmp eq <2 x i32> %x, <i32 0, i32 poison>
|
|
%m = mul <2 x i32> %x, %y
|
|
%r = select <2 x i1> %c, <2 x i32> <i32 0, i32 42>, <2 x i32> %m
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
; Check that a select is folded into multiplication if other select's operand
|
|
; is a vector consisting of zeros and poisons.
|
|
; select (<k x elt> x == 0), <k x elt> {0, poison, ...}, <k x elt> x * y --> freeze(y) * x
|
|
define <2 x i32> @mul_select_eq_zero_sel_poison_vector(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @mul_select_eq_zero_sel_poison_vector(
|
|
; CHECK-NEXT: [[Y_FR:%.*]] = freeze <2 x i32> [[Y:%.*]]
|
|
; CHECK-NEXT: [[M:%.*]] = mul <2 x i32> [[Y_FR]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[M]]
|
|
;
|
|
%c = icmp eq <2 x i32> %x, zeroinitializer
|
|
%m = mul <2 x i32> %x, %y
|
|
%r = select <2 x i1> %c, <2 x i32> <i32 0, i32 poison>, <2 x i32> %m
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
; Negative test: select should not be folded into mul because
|
|
; condition's operand and select's operand do not merge into zero vector.
|
|
define <2 x i32> @mul_select_eq_poison_vector_not_merging_to_zero(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @mul_select_eq_poison_vector_not_merging_to_zero(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i32> [[X:%.*]], <i32 0, i32 poison>
|
|
; CHECK-NEXT: [[M:%.*]] = mul <2 x i32> [[X]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[C]], <2 x i32> <i32 1, i32 0>, <2 x i32> [[M]]
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%c = icmp eq <2 x i32> %x, <i32 0, i32 poison>
|
|
%m = mul <2 x i32> %x, %y
|
|
%r = select <2 x i1> %c, <2 x i32> <i32 1, i32 0>, <2 x i32> %m
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define i8 @ne0_is_all_ones(i8 %x) {
|
|
; CHECK-LABEL: @ne0_is_all_ones(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i8 [[X:%.*]], 0
|
|
; CHECK-NEXT: [[R:%.*]] = sext i1 [[TMP1]] to i8
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%negx = sub i8 0, %x
|
|
%ugt1 = icmp ugt i8 %x, 1
|
|
%r = select i1 %ugt1, i8 -1, i8 %negx
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @ne0_is_all_ones_use1(i8 %x) {
|
|
; CHECK-LABEL: @ne0_is_all_ones_use1(
|
|
; CHECK-NEXT: [[NEGX:%.*]] = sub i8 0, [[X:%.*]]
|
|
; CHECK-NEXT: call void @use_i8(i8 [[NEGX]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i8 [[X]], 0
|
|
; CHECK-NEXT: [[R:%.*]] = sext i1 [[TMP1]] to i8
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%negx = sub i8 0, %x
|
|
call void @use_i8(i8 %negx)
|
|
%ugt1 = icmp ugt i8 %x, 1
|
|
%r = select i1 %ugt1, i8 -1, i8 %negx
|
|
ret i8 %r
|
|
}
|
|
|
|
; negative test
|
|
|
|
define i8 @ne0_is_all_ones_use2(i8 %x) {
|
|
; CHECK-LABEL: @ne0_is_all_ones_use2(
|
|
; CHECK-NEXT: [[NEGX:%.*]] = sub i8 0, [[X:%.*]]
|
|
; CHECK-NEXT: [[UGT1:%.*]] = icmp ugt i8 [[X]], 1
|
|
; CHECK-NEXT: call void @use(i1 [[UGT1]])
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[UGT1]], i8 -1, i8 [[NEGX]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%negx = sub i8 0, %x
|
|
%ugt1 = icmp ugt i8 %x, 1
|
|
call void @use(i1 %ugt1)
|
|
%r = select i1 %ugt1, i8 -1, i8 %negx
|
|
ret i8 %r
|
|
}
|
|
|
|
; negative test
|
|
|
|
define i8 @ne0_is_all_ones_wrong_pred(i8 %x) {
|
|
; CHECK-LABEL: @ne0_is_all_ones_wrong_pred(
|
|
; CHECK-NEXT: [[NEGX:%.*]] = sub i8 0, [[X:%.*]]
|
|
; CHECK-NEXT: [[UGT1:%.*]] = icmp sgt i8 [[X]], 2
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[UGT1]], i8 -1, i8 [[NEGX]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%negx = sub i8 0, %x
|
|
%ugt1 = icmp sgt i8 %x, 2
|
|
%r = select i1 %ugt1, i8 -1, i8 %negx
|
|
ret i8 %r
|
|
}
|
|
|
|
; negative test
|
|
|
|
define i8 @ne0_is_all_ones_wrong_cmp(i8 %x) {
|
|
; CHECK-LABEL: @ne0_is_all_ones_wrong_cmp(
|
|
; CHECK-NEXT: [[NEGX:%.*]] = sub i8 0, [[X:%.*]]
|
|
; CHECK-NEXT: [[UGT1:%.*]] = icmp ugt i8 [[X]], 2
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[UGT1]], i8 -1, i8 [[NEGX]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%negx = sub i8 0, %x
|
|
%ugt1 = icmp ugt i8 %x, 2
|
|
%r = select i1 %ugt1, i8 -1, i8 %negx
|
|
ret i8 %r
|
|
}
|
|
|
|
; negative test
|
|
|
|
define i8 @ne0_is_all_ones_wrong_sel(i8 %x) {
|
|
; CHECK-LABEL: @ne0_is_all_ones_wrong_sel(
|
|
; CHECK-NEXT: [[NEGX:%.*]] = sub i8 0, [[X:%.*]]
|
|
; CHECK-NEXT: [[UGT1:%.*]] = icmp ugt i8 [[X]], 2
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[UGT1]], i8 1, i8 [[NEGX]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%negx = sub i8 0, %x
|
|
%ugt1 = icmp ugt i8 %x, 2
|
|
%r = select i1 %ugt1, i8 1, i8 %negx
|
|
ret i8 %r
|
|
}
|
|
|
|
define <2 x i8> @ne0_is_all_ones_swap_vec(<2 x i8> %x) {
|
|
; CHECK-LABEL: @ne0_is_all_ones_swap_vec(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <2 x i8> [[X:%.*]], zeroinitializer
|
|
; CHECK-NEXT: [[R:%.*]] = sext <2 x i1> [[TMP1]] to <2 x i8>
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%negx = sub <2 x i8> zeroinitializer, %x
|
|
%ult2 = icmp ult <2 x i8> %x, <i8 2, i8 2>
|
|
%r = select <2 x i1> %ult2, <2 x i8> %negx, <2 x i8> <i8 -1, i8 -1>
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
define <2 x i8> @ne0_is_all_ones_swap_vec_poison(<2 x i8> %x) {
|
|
; CHECK-LABEL: @ne0_is_all_ones_swap_vec_poison(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <2 x i8> [[X:%.*]], zeroinitializer
|
|
; CHECK-NEXT: [[R:%.*]] = sext <2 x i1> [[TMP1]] to <2 x i8>
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%negx = sub <2 x i8> <i8 0, i8 poison>, %x
|
|
%ult2 = icmp ult <2 x i8> %x, <i8 2, i8 poison>
|
|
%r = select <2 x i1> %ult2, <2 x i8> %negx, <2 x i8> <i8 -1, i8 poison>
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
define i64 @udiv_of_select_constexpr(i1 %c, i64 %x) {
|
|
; CHECK-LABEL: @udiv_of_select_constexpr(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i64 [[X:%.*]], i64 ptrtoint (ptr @glbl to i64)
|
|
; CHECK-NEXT: [[OP:%.*]] = udiv i64 [[SEL]], 3
|
|
; CHECK-NEXT: ret i64 [[OP]]
|
|
;
|
|
%sel = select i1 %c, i64 %x, i64 ptrtoint (ptr @glbl to i64)
|
|
%op = udiv i64 %sel, 3
|
|
ret i64 %op
|
|
}
|
|
|
|
define i64 @udiv_of_select_constexpr_commuted(i1 %c, i64 %x) {
|
|
; CHECK-LABEL: @udiv_of_select_constexpr_commuted(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i64 ptrtoint (ptr @glbl to i64), i64 [[X:%.*]]
|
|
; CHECK-NEXT: [[OP:%.*]] = udiv i64 [[SEL]], 3
|
|
; CHECK-NEXT: ret i64 [[OP]]
|
|
;
|
|
%sel = select i1 %c, i64 ptrtoint (ptr @glbl to i64), i64 %x
|
|
%op = udiv i64 %sel, 3
|
|
ret i64 %op
|
|
}
|
|
|
|
declare void @use(i1)
|
|
declare void @use_i8(i8)
|
|
declare void @use_i32(i32)
|
|
declare i32 @llvm.cttz.i32(i32, i1 immarg)
|
|
|
|
define i32 @select_cond_zext_cond(i1 %cond, i32 %b) {
|
|
; CHECK-LABEL: @select_cond_zext_cond(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], i32 1, i32 [[B:%.*]]
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
%zext = zext i1 %cond to i32
|
|
%sel = select i1 %cond, i32 %zext, i32 %b
|
|
ret i32 %sel
|
|
}
|
|
|
|
define <2 x i32> @select_cond_zext_cond_vec(<2 x i1> %cond, <2 x i32> %b) {
|
|
; CHECK-LABEL: @select_cond_zext_cond_vec(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[COND:%.*]], <2 x i32> <i32 1, i32 1>, <2 x i32> [[B:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[SEL]]
|
|
;
|
|
%zext = zext <2 x i1> %cond to <2 x i32>
|
|
%sel = select <2 x i1> %cond, <2 x i32> %zext, <2 x i32> %b
|
|
ret <2 x i32> %sel
|
|
}
|
|
|
|
define i32 @select_cond_sext_cond(i1 %cond, i32 %b) {
|
|
; CHECK-LABEL: @select_cond_sext_cond(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], i32 -1, i32 [[B:%.*]]
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
%sext = sext i1 %cond to i32
|
|
%sel = select i1 %cond, i32 %sext, i32 %b
|
|
ret i32 %sel
|
|
}
|
|
|
|
define <2 x i32> @select_cond_sext_cond_vec(<2 x i1> %cond, <2 x i32> %b) {
|
|
; CHECK-LABEL: @select_cond_sext_cond_vec(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[COND:%.*]], <2 x i32> <i32 -1, i32 -1>, <2 x i32> [[B:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[SEL]]
|
|
;
|
|
%sext = sext <2 x i1> %cond to <2 x i32>
|
|
%sel = select <2 x i1> %cond, <2 x i32> %sext, <2 x i32> %b
|
|
ret <2 x i32> %sel
|
|
}
|
|
|
|
define i32 @select_cond_val_zext_cond(i1 %cond, i32 %b) {
|
|
; CHECK-LABEL: @select_cond_val_zext_cond(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], i32 [[B:%.*]], i32 0
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
%zext = zext i1 %cond to i32
|
|
%sel = select i1 %cond, i32 %b, i32 %zext
|
|
ret i32 %sel
|
|
}
|
|
|
|
define <2 x i32> @select_cond_val_zext_cond_vec(<2 x i1> %cond, <2 x i32> %b) {
|
|
; CHECK-LABEL: @select_cond_val_zext_cond_vec(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[COND:%.*]], <2 x i32> [[B:%.*]], <2 x i32> zeroinitializer
|
|
; CHECK-NEXT: ret <2 x i32> [[SEL]]
|
|
;
|
|
%zext = zext <2 x i1> %cond to <2 x i32>
|
|
%sel = select <2 x i1> %cond, <2 x i32> %b, <2 x i32> %zext
|
|
ret <2 x i32> %sel
|
|
}
|
|
|
|
define i32 @select_cond_val_sext_cond(i1 %cond, i32 %b) {
|
|
; CHECK-LABEL: @select_cond_val_sext_cond(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], i32 [[B:%.*]], i32 0
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
%sext = sext i1 %cond to i32
|
|
%sel = select i1 %cond, i32 %b, i32 %sext
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i32 @select_cond_zext_not_cond_val(i1 %cond, i32 %b) {
|
|
; CHECK-LABEL: @select_cond_zext_not_cond_val(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], i32 0, i32 [[B:%.*]]
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
%not_cond = xor i1 %cond, true
|
|
%zext = zext i1 %not_cond to i32
|
|
%sel = select i1 %cond, i32 %zext, i32 %b
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i32 @select_cond_sext_not_cond_val(i1 %cond, i32 %b) {
|
|
; CHECK-LABEL: @select_cond_sext_not_cond_val(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], i32 0, i32 [[B:%.*]]
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
%not_cond = xor i1 %cond, true
|
|
%sext = sext i1 %not_cond to i32
|
|
%sel = select i1 %cond, i32 %sext, i32 %b
|
|
ret i32 %sel
|
|
}
|
|
|
|
|
|
define i32 @select_cond_val_zext_not_cond(i1 %cond, i32 %b) {
|
|
; CHECK-LABEL: @select_cond_val_zext_not_cond(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], i32 [[B:%.*]], i32 1
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
%not_cond = xor i1 %cond, true
|
|
%zext = zext i1 %not_cond to i32
|
|
%sel = select i1 %cond, i32 %b, i32 %zext
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i32 @select_cond_val_sext_not_cond(i1 %cond, i32 %b) {
|
|
; CHECK-LABEL: @select_cond_val_sext_not_cond(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], i32 [[B:%.*]], i32 -1
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
%not_cond = xor i1 %cond, true
|
|
%sext = sext i1 %not_cond to i32
|
|
%sel = select i1 %cond, i32 %b, i32 %sext
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i32 @select_cond_not_cond_cond1(i1 %cond) {
|
|
; CHECK-LABEL: @select_cond_not_cond_cond1(
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
%z = zext i1 %cond to i32
|
|
%not_cond = xor i1 %cond, true
|
|
%s = sext i1 %not_cond to i32
|
|
%v = select i1 %cond, i32 %s, i32 %z
|
|
ret i32 %v
|
|
}
|
|
|
|
define i32 @select_cond_not_cond_cond2(i1 %cond) {
|
|
; CHECK-LABEL: @select_cond_not_cond_cond2(
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
%z = sext i1 %cond to i32
|
|
%not_cond = xor i1 %cond, true
|
|
%s = zext i1 %not_cond to i32
|
|
%v = select i1 %cond, i32 %s, i32 %z
|
|
ret i32 %v
|
|
}
|
|
|
|
; This previously crashed due to Constant::getUniqueInteger not handling
|
|
; scalable vector splat ConstantExprs.
|
|
define <vscale x 2 x i32> @and_constant_select_svec(<vscale x 2 x i32> %x, <vscale x 2 x i1> %cond) {
|
|
; CHECK-LABEL: @and_constant_select_svec(
|
|
; CHECK-NEXT: [[A:%.*]] = and <vscale x 2 x i32> [[X:%.*]], shufflevector (<vscale x 2 x i32> insertelement (<vscale x 2 x i32> poison, i32 1, i64 0), <vscale x 2 x i32> poison, <vscale x 2 x i32> zeroinitializer)
|
|
; CHECK-NEXT: [[B:%.*]] = select <vscale x 2 x i1> [[COND:%.*]], <vscale x 2 x i32> [[A]], <vscale x 2 x i32> [[X]]
|
|
; CHECK-NEXT: ret <vscale x 2 x i32> [[B]]
|
|
;
|
|
%a = and <vscale x 2 x i32> %x, splat (i32 1)
|
|
%b = select <vscale x 2 x i1> %cond, <vscale x 2 x i32> %a, <vscale x 2 x i32> %x
|
|
ret <vscale x 2 x i32> %b
|
|
}
|
|
|
|
define <vscale x 2 x i32> @scalable_sign_bits(<vscale x 2 x i8> %x) {
|
|
; CHECK-LABEL: @scalable_sign_bits(
|
|
; CHECK-NEXT: [[A:%.*]] = sext <vscale x 2 x i8> [[X:%.*]] to <vscale x 2 x i32>
|
|
; CHECK-NEXT: [[B:%.*]] = shl nsw <vscale x 2 x i32> [[A]], shufflevector (<vscale x 2 x i32> insertelement (<vscale x 2 x i32> poison, i32 16, i64 0), <vscale x 2 x i32> poison, <vscale x 2 x i32> zeroinitializer)
|
|
; CHECK-NEXT: ret <vscale x 2 x i32> [[B]]
|
|
;
|
|
%a = sext <vscale x 2 x i8> %x to <vscale x 2 x i32>
|
|
%b = shl <vscale x 2 x i32> %a, splat (i32 16)
|
|
ret <vscale x 2 x i32> %b
|
|
}
|
|
|
|
define <vscale x 2 x i1> @scalable_non_zero(<vscale x 2 x i32> %x) {
|
|
; CHECK-LABEL: @scalable_non_zero(
|
|
; CHECK-NEXT: [[A:%.*]] = or <vscale x 2 x i32> [[X:%.*]], shufflevector (<vscale x 2 x i32> insertelement (<vscale x 2 x i32> poison, i32 1, i64 0), <vscale x 2 x i32> poison, <vscale x 2 x i32> zeroinitializer)
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult <vscale x 2 x i32> [[A]], shufflevector (<vscale x 2 x i32> insertelement (<vscale x 2 x i32> poison, i32 57, i64 0), <vscale x 2 x i32> poison, <vscale x 2 x i32> zeroinitializer)
|
|
; CHECK-NEXT: ret <vscale x 2 x i1> [[CMP]]
|
|
;
|
|
%a = or <vscale x 2 x i32> %x, splat (i32 1)
|
|
%b = add <vscale x 2 x i32> %a, splat (i32 -1)
|
|
%cmp = icmp ult <vscale x 2 x i32> %b, splat (i32 56)
|
|
ret <vscale x 2 x i1> %cmp
|
|
}
|
|
|
|
define i32 @clamp_umin(i32 %x) {
|
|
; CHECK-LABEL: @clamp_umin(
|
|
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 1)
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i32 %x, 0
|
|
%sel = select i1 %cmp, i32 1, i32 %x
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i32 @clamp_umin_use(i32 %x) {
|
|
; CHECK-LABEL: @clamp_umin_use(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: call void @use1(i1 [[CMP]])
|
|
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.umax.i32(i32 [[X]], i32 1)
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i32 %x, 0
|
|
call void @use1(i1 %cmp)
|
|
%sel = select i1 %cmp, i32 1, i32 %x
|
|
ret i32 %sel
|
|
}
|
|
|
|
; negative test - wrong cmp constant
|
|
|
|
define i32 @not_clamp_umin1(i32 %x) {
|
|
; CHECK-LABEL: @not_clamp_umin1(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 2
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 1, i32 [[X]]
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i32 %x, 2
|
|
%sel = select i1 %cmp, i32 1, i32 %x
|
|
ret i32 %sel
|
|
}
|
|
|
|
; negative test - wrong select constant
|
|
|
|
define i32 @not_clamp_umin2(i32 %x) {
|
|
; CHECK-LABEL: @not_clamp_umin2(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 -1, i32 [[X]]
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i32 %x, 0
|
|
%sel = select i1 %cmp, i32 -1, i32 %x
|
|
ret i32 %sel
|
|
}
|
|
|
|
define <2 x i8> @clamp_umaxval(<2 x i8> %x) {
|
|
; CHECK-LABEL: @clamp_umaxval(
|
|
; CHECK-NEXT: [[SEL:%.*]] = call <2 x i8> @llvm.umin.v2i8(<2 x i8> [[X:%.*]], <2 x i8> <i8 -2, i8 -2>)
|
|
; CHECK-NEXT: ret <2 x i8> [[SEL]]
|
|
;
|
|
%cmp = icmp eq <2 x i8> %x, <i8 255, i8 255>
|
|
%sel = select <2 x i1> %cmp, <2 x i8> <i8 254, i8 254>, <2 x i8> %x
|
|
ret <2 x i8> %sel
|
|
}
|
|
|
|
; negative test - wrong cmp constant
|
|
|
|
define i8 @not_clamp_umax1(i8 %x) {
|
|
; CHECK-LABEL: @not_clamp_umax1(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], -3
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 -2, i8 [[X]]
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i8 %x, 253
|
|
%sel = select i1 %cmp, i8 254, i8 %x
|
|
ret i8 %sel
|
|
}
|
|
|
|
; negative test - wrong select constant
|
|
|
|
define i8 @not_clamp_umax2(i8 %x) {
|
|
; CHECK-LABEL: @not_clamp_umax2(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], -1
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 1, i8 [[X]]
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i8 %x, 255
|
|
%sel = select i1 %cmp, i8 1, i8 %x
|
|
ret i8 %sel
|
|
}
|
|
|
|
define i8 @clamp_smin(i8 %x) {
|
|
; CHECK-LABEL: @clamp_smin(
|
|
; CHECK-NEXT: [[SEL:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 -127)
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i8 %x, -128
|
|
%sel = select i1 %cmp, i8 -127, i8 %x
|
|
ret i8 %sel
|
|
}
|
|
|
|
define i8 @clamp_smin_use(i8 %x) {
|
|
; CHECK-LABEL: @clamp_smin_use(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], -128
|
|
; CHECK-NEXT: call void @use1(i1 [[CMP]])
|
|
; CHECK-NEXT: [[SEL:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 -127)
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i8 %x, -128
|
|
call void @use1(i1 %cmp)
|
|
%sel = select i1 %cmp, i8 -127, i8 %x
|
|
ret i8 %sel
|
|
}
|
|
|
|
; negative test - wrong cmp constant
|
|
|
|
define i8 @not_clamp_smin1(i8 %x) {
|
|
; CHECK-LABEL: @not_clamp_smin1(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 127
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 -127, i8 [[X]]
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i8 %x, 127
|
|
%sel = select i1 %cmp, i8 -127, i8 %x
|
|
ret i8 %sel
|
|
}
|
|
|
|
; negative test - wrong select constant
|
|
|
|
define i8 @not_clamp_smin2(i8 %x) {
|
|
; CHECK-LABEL: @not_clamp_smin2(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], -128
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 -1, i8 [[X]]
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i8 %x, -128
|
|
%sel = select i1 %cmp, i8 -1, i8 %x
|
|
ret i8 %sel
|
|
}
|
|
|
|
define <2 x i8> @clamp_smaxval(<2 x i8> %x) {
|
|
; CHECK-LABEL: @clamp_smaxval(
|
|
; CHECK-NEXT: [[SEL:%.*]] = call <2 x i8> @llvm.smin.v2i8(<2 x i8> [[X:%.*]], <2 x i8> <i8 126, i8 126>)
|
|
; CHECK-NEXT: ret <2 x i8> [[SEL]]
|
|
;
|
|
%cmp = icmp eq <2 x i8> %x, <i8 127, i8 127>
|
|
%sel = select <2 x i1> %cmp, <2 x i8> <i8 126, i8 126>, <2 x i8> %x
|
|
ret <2 x i8> %sel
|
|
}
|
|
|
|
; negative test - wrong cmp constant
|
|
|
|
define i8 @not_clamp_smax1(i8 %x) {
|
|
; CHECK-LABEL: @not_clamp_smax1(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], -128
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 126, i8 [[X]]
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i8 %x, -128
|
|
%sel = select i1 %cmp, i8 126, i8 %x
|
|
ret i8 %sel
|
|
}
|
|
|
|
; negative test - wrong select constant
|
|
|
|
define i8 @not_clamp_smax2(i8 %x) {
|
|
; CHECK-LABEL: @not_clamp_smax2(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 127
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 125, i8 [[X]]
|
|
; CHECK-NEXT: ret i8 [[SEL]]
|
|
;
|
|
%cmp = icmp eq i8 %x, 127
|
|
%sel = select i1 %cmp, i8 125, i8 %x
|
|
ret i8 %sel
|
|
}
|
|
|
|
; Used to infinite loop.
|
|
define i32 @pr61361(i32 %arg) {
|
|
; CHECK-LABEL: @pr61361(
|
|
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[ARG:%.*]], 0
|
|
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i32 16777215, i32 0
|
|
; CHECK-NEXT: ret i32 [[SEL2]]
|
|
;
|
|
%cmp1 = icmp eq i32 %arg, 1
|
|
%sel1 = select i1 %cmp1, i32 0, i32 33554431
|
|
%cmp2 = icmp eq i32 %arg, 0
|
|
%sel2 = select i1 %cmp2, i32 %sel1, i32 0
|
|
%ashr = ashr i32 %sel2, 1
|
|
ret i32 %ashr
|
|
}
|
|
|
|
define i32 @pr62088() {
|
|
; CHECK-LABEL: @pr62088(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[NOT2:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ -2, [[LOOP]] ]
|
|
; CHECK-NEXT: [[H_0:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ 1, [[LOOP]] ]
|
|
; CHECK-NEXT: [[XOR:%.*]] = or disjoint i32 [[H_0]], [[NOT2]]
|
|
; CHECK-NEXT: [[SUB5:%.*]] = sub i32 -1824888657, [[XOR]]
|
|
; CHECK-NEXT: [[XOR6:%.*]] = xor i32 [[SUB5]], -1260914025
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[XOR6]], 824855120
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 [[H_0]]
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%not2 = phi i32 [ 0, %entry ], [ -2, %loop ]
|
|
%i.0 = phi i32 [ 0, %entry ], [ %shr, %loop ]
|
|
%h.0 = phi i32 [ 0, %entry ], [ 1, %loop ]
|
|
%i.0.fr = freeze i32 %i.0
|
|
%sext = shl i32 %i.0.fr, 16
|
|
%conv = ashr exact i32 %sext, 16
|
|
%not = xor i32 %conv, -1
|
|
%and = and i32 %h.0, 1
|
|
%rem.urem = sub nsw i32 %and, %conv
|
|
%rem.cmp = icmp ult i32 %and, %conv
|
|
%rem = select i1 %rem.cmp, i32 %not, i32 %rem.urem
|
|
%xor = xor i32 %rem, %not2
|
|
%sub = sub nsw i32 0, %xor
|
|
%sub5 = sub i32 -1824888657, %xor
|
|
%xor6 = xor i32 %sub5, -1260914025
|
|
%cmp = icmp slt i32 %xor6, 824855120
|
|
%shr = ashr i32 %xor6, 40
|
|
br i1 %cmp, label %loop, label %exit
|
|
|
|
exit:
|
|
ret i32 %rem
|
|
}
|
|
|
|
; Select icmp and/or/xor
|
|
; https://alive2.llvm.org/ce/z/QXQDwF
|
|
; X&Y==C?X|Y:X^Y, X&Y==C?X^Y:X|Y
|
|
; TODO: X&Y==0 could imply no_common_bit to TrueValue
|
|
define i32 @src_and_eq_0_or_xor(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_and_eq_0_or_xor(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[OR]], i32 [[XOR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
entry:
|
|
%and = and i32 %y, %x
|
|
%cmp = icmp eq i32 %and, 0
|
|
%or = or i32 %y, %x
|
|
%xor = xor i32 %y, %x
|
|
%cond = select i1 %cmp, i32 %or, i32 %xor
|
|
ret i32 %cond
|
|
}
|
|
|
|
; TODO: X&Y==0 could imply no_common_bit to TrueValue
|
|
define i32 @src_and_eq_0_xor_or(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_and_eq_0_xor_or(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 [[OR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
entry:
|
|
%and = and i32 %y, %x
|
|
%cmp = icmp eq i32 %and, 0
|
|
%xor = xor i32 %y, %x
|
|
%or = or i32 %y, %x
|
|
%cond = select i1 %cmp, i32 %xor, i32 %or
|
|
ret i32 %cond
|
|
}
|
|
|
|
; TODO: X&Y==-1 could imply all_common_bit to TrueValue
|
|
define i32 @src_and_eq_neg1_or_xor(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_and_eq_neg1_or_xor(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], -1
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[OR]], i32 [[XOR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
entry:
|
|
%and = and i32 %y, %x
|
|
%cmp = icmp eq i32 %and, -1
|
|
%or = or i32 %y, %x
|
|
%xor = xor i32 %y, %x
|
|
%cond = select i1 %cmp, i32 %or, i32 %xor
|
|
ret i32 %cond
|
|
}
|
|
|
|
; TODO: X&Y==-1 could imply all_common_bit to TrueValue
|
|
define i32 @src_and_eq_neg1_xor_or(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_and_eq_neg1_xor_or(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], -1
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 [[OR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
entry:
|
|
%and = and i32 %y, %x
|
|
%cmp = icmp eq i32 %and, -1
|
|
%xor = xor i32 %y, %x
|
|
%or = or i32 %y, %x
|
|
%cond = select i1 %cmp, i32 %xor, i32 %or
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_and_eq_C_or_xororC(i32 %x, i32 %y, i32 %c) {
|
|
; CHECK-LABEL: @src_and_eq_C_or_xororC(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[XOR]], [[C:%.*]]
|
|
; CHECK-NEXT: ret i32 [[OR1]]
|
|
;
|
|
entry:
|
|
%and = and i32 %y, %x
|
|
%cmp = icmp eq i32 %and, %c
|
|
%or = or i32 %y, %x
|
|
%xor = xor i32 %y, %x
|
|
%or1 = or i32 %xor, %c
|
|
%cond = select i1 %cmp, i32 %or, i32 %or1
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_and_eq_C_or_xorxorC(i32 %x, i32 %y, i32 %c) {
|
|
; CHECK-LABEL: @src_and_eq_C_or_xorxorC(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[XOR]], [[C:%.*]]
|
|
; CHECK-NEXT: ret i32 [[XOR1]]
|
|
;
|
|
entry:
|
|
%and = and i32 %y, %x
|
|
%cmp = icmp eq i32 %and, %c
|
|
%or = or i32 %y, %x
|
|
%xor = xor i32 %y, %x
|
|
%xor1 = xor i32 %xor, %c
|
|
%cond = select i1 %cmp, i32 %or, i32 %xor1
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_and_eq_C_xor_OrAndNotC(i32 %x, i32 %y, i32 %c) {
|
|
; CHECK-LABEL: @src_and_eq_C_xor_OrAndNotC(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[C:%.*]], -1
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[OR]], [[NOT]]
|
|
; CHECK-NEXT: ret i32 [[AND1]]
|
|
;
|
|
entry:
|
|
%and = and i32 %y, %x
|
|
%cmp = icmp eq i32 %and, %c
|
|
%xor = xor i32 %y, %x
|
|
%or = or i32 %y, %x
|
|
%not = xor i32 %c, -1
|
|
%and1 = and i32 %or, %not
|
|
%cond = select i1 %cmp, i32 %xor, i32 %and1
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_and_eq_C_xor_orxorC(i32 %x, i32 %y, i32 %c) {
|
|
; CHECK-LABEL: @src_and_eq_C_xor_orxorC(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[OR]], [[C:%.*]]
|
|
; CHECK-NEXT: ret i32 [[XOR1]]
|
|
;
|
|
entry:
|
|
%and = and i32 %y, %x
|
|
%cmp = icmp eq i32 %and, %c
|
|
%xor = xor i32 %y, %x
|
|
%or = or i32 %y, %x
|
|
%xor1 = xor i32 %or, %c
|
|
%cond = select i1 %cmp, i32 %xor, i32 %xor1
|
|
ret i32 %cond
|
|
}
|
|
|
|
; https://alive2.llvm.org/ce/z/9RPwfN
|
|
; X|Y==C?X&Y:X^Y, X|Y==C?X^Y:X&Y
|
|
; TODO: X|Y==0 could imply no_common_bit to TrueValue
|
|
define i32 @src_or_eq_0_and_xor(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_or_eq_0_and_xor(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR]], 0
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[AND]], i32 [[XOR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
entry:
|
|
%or = or i32 %y, %x
|
|
%cmp = icmp eq i32 %or, 0
|
|
%and = and i32 %y, %x
|
|
%xor = xor i32 %y, %x
|
|
%cond = select i1 %cmp, i32 %and, i32 %xor
|
|
ret i32 %cond
|
|
}
|
|
|
|
; TODO: X|Y==0 could imply no_common_bit to TrueValue
|
|
define i32 @src_or_eq_0_xor_and(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_or_eq_0_xor_and(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR]], 0
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 [[AND]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
entry:
|
|
%or = or i32 %y, %x
|
|
%cmp = icmp eq i32 %or, 0
|
|
%xor = xor i32 %y, %x
|
|
%and = and i32 %y, %x
|
|
%cond = select i1 %cmp, i32 %xor, i32 %and
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_or_eq_neg1_and_xor(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_or_eq_neg1_and_xor(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[TMP0]], -1
|
|
; CHECK-NEXT: ret i32 [[NOT]]
|
|
;
|
|
entry:
|
|
%or = or i32 %y, %x
|
|
%cmp = icmp eq i32 %or, -1
|
|
%and = and i32 %y, %x
|
|
%0 = xor i32 %x, %y
|
|
%not = xor i32 %0, -1
|
|
%cond = select i1 %cmp, i32 %and, i32 %not
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_or_eq_neg1_xor_and(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_or_eq_neg1_xor_and(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[AND]], -1
|
|
; CHECK-NEXT: ret i32 [[NOT]]
|
|
;
|
|
entry:
|
|
%or = or i32 %y, %x
|
|
%cmp = icmp eq i32 %or, -1
|
|
%xor = xor i32 %y, %x
|
|
%and = and i32 %y, %x
|
|
%not = xor i32 %and, -1
|
|
%cond = select i1 %cmp, i32 %xor, i32 %not
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_or_eq_C_and_xorC(i32 %x, i32 %y, i32 %c) {
|
|
; CHECK-LABEL: @src_or_eq_C_and_xorC(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[XOR]], [[C:%.*]]
|
|
; CHECK-NEXT: ret i32 [[XOR1]]
|
|
;
|
|
entry:
|
|
%or = or i32 %y, %x
|
|
%cmp = icmp eq i32 %or, %c
|
|
%and = and i32 %y, %x
|
|
%xor = xor i32 %y, %x
|
|
%xor1 = xor i32 %xor, %c
|
|
%cond = select i1 %cmp, i32 %and, i32 %xor1
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_or_eq_C_and_andnotxorC(i32 %x, i32 %y, i32 %c) {
|
|
; CHECK-LABEL: @src_or_eq_C_and_andnotxorC(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[TMP0]], -1
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT]], [[C:%.*]]
|
|
; CHECK-NEXT: ret i32 [[AND1]]
|
|
;
|
|
entry:
|
|
%or = or i32 %y, %x
|
|
%cmp = icmp eq i32 %or, %c
|
|
%and = and i32 %y, %x
|
|
%0 = xor i32 %x, %y
|
|
%not = xor i32 %0, -1
|
|
%and1 = and i32 %not, %c
|
|
%cond = select i1 %cmp, i32 %and, i32 %and1
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_or_eq_C_xor_xorandC(i32 %x, i32 %y, i32 %c) {
|
|
; CHECK-LABEL: @src_or_eq_C_xor_xorandC(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[AND]], [[C:%.*]]
|
|
; CHECK-NEXT: ret i32 [[XOR1]]
|
|
;
|
|
entry:
|
|
%or = or i32 %y, %x
|
|
%cmp = icmp eq i32 %or, %c
|
|
%xor = xor i32 %y, %x
|
|
%and = and i32 %y, %x
|
|
%xor1 = xor i32 %and, %c
|
|
%cond = select i1 %cmp, i32 %xor, i32 %xor1
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_or_eq_C_xor_andnotandC(i32 %x, i32 %y, i32 %c) {
|
|
; CHECK-LABEL: @src_or_eq_C_xor_andnotandC(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[AND]], -1
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT]], [[C:%.*]]
|
|
; CHECK-NEXT: ret i32 [[AND1]]
|
|
;
|
|
entry:
|
|
%or = or i32 %y, %x
|
|
%cmp = icmp eq i32 %or, %c
|
|
%xor = xor i32 %y, %x
|
|
%and = and i32 %y, %x
|
|
%not = xor i32 %and, -1
|
|
%and1 = and i32 %not, %c
|
|
%cond = select i1 %cmp, i32 %xor, i32 %and1
|
|
ret i32 %cond
|
|
}
|
|
|
|
; https://alive2.llvm.org/ce/z/c6oXi4
|
|
; X^Y==C?X&Y:X|Y, X^Y==C?X|Y:X&Y
|
|
define i32 @src_xor_eq_neg1_and(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_xor_eq_neg1_and(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[OR]], -1
|
|
; CHECK-NEXT: ret i32 [[NOT]]
|
|
;
|
|
entry:
|
|
%xor = xor i32 %y, %x
|
|
%cmp = icmp eq i32 %xor, -1
|
|
%and = and i32 %y, %x
|
|
%or = or i32 %y, %x
|
|
%not = xor i32 %or, -1
|
|
%cond = select i1 %cmp, i32 %and, i32 %not
|
|
ret i32 %cond
|
|
}
|
|
|
|
; TODO: X^Y==-1 could imply no_common_bit to TrueValue
|
|
define i32 @src_xor_eq_neg1_or(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_xor_eq_neg1_or(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[XOR]], -1
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[OR]], i32 -1
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
entry:
|
|
%xor = xor i32 %y, %x
|
|
%cmp = icmp eq i32 %xor, -1
|
|
%or = or i32 %y, %x
|
|
%cond = select i1 %cmp, i32 %or, i32 -1
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_xor_eq_C_and_xororC(i32 %x, i32 %y, i32 %c) {
|
|
; CHECK-LABEL: @src_xor_eq_C_and_xororC(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[OR]], [[C:%.*]]
|
|
; CHECK-NEXT: ret i32 [[XOR1]]
|
|
;
|
|
entry:
|
|
%xor = xor i32 %y, %x
|
|
%cmp = icmp eq i32 %xor, %c
|
|
%and = and i32 %y, %x
|
|
%or = or i32 %y, %x
|
|
%xor1 = xor i32 %or, %c
|
|
%cond = select i1 %cmp, i32 %and, i32 %xor1
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_xor_eq_C_and_andornotC(i32 %x, i32 %y, i32 %c) {
|
|
; CHECK-LABEL: @src_xor_eq_C_and_andornotC(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[C:%.*]], -1
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[OR]], [[NOT]]
|
|
; CHECK-NEXT: ret i32 [[AND1]]
|
|
;
|
|
entry:
|
|
%xor = xor i32 %y, %x
|
|
%cmp = icmp eq i32 %xor, %c
|
|
%and = and i32 %y, %x
|
|
%or = or i32 %y, %x
|
|
%not = xor i32 %c, -1
|
|
%and1 = and i32 %or, %not
|
|
%cond = select i1 %cmp, i32 %and, i32 %and1
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_xor_eq_C_or_xorandC(i32 %x, i32 %y, i32 %c) {
|
|
; CHECK-LABEL: @src_xor_eq_C_or_xorandC(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[AND]], [[C:%.*]]
|
|
; CHECK-NEXT: ret i32 [[XOR1]]
|
|
;
|
|
entry:
|
|
%xor = xor i32 %y, %x
|
|
%cmp = icmp eq i32 %xor, %c
|
|
%or = or i32 %y, %x
|
|
%and = and i32 %y, %x
|
|
%xor1 = xor i32 %and, %c
|
|
%cond = select i1 %cmp, i32 %or, i32 %xor1
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_xor_eq_C_or_orandC(i32 %x, i32 %y, i32 %c) {
|
|
; CHECK-LABEL: @src_xor_eq_C_or_orandC(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[AND]], [[C:%.*]]
|
|
; CHECK-NEXT: ret i32 [[OR1]]
|
|
;
|
|
entry:
|
|
%xor = xor i32 %y, %x
|
|
%cmp = icmp eq i32 %xor, %c
|
|
%or = or i32 %y, %x
|
|
%and = and i32 %y, %x
|
|
%or1 = or i32 %and, %c
|
|
%cond = select i1 %cmp, i32 %or, i32 %or1
|
|
ret i32 %cond
|
|
}
|
|
|
|
; Select icmp and/or/xor
|
|
; NO TRANSFORMED - select condition is compare with not 0
|
|
define i32 @src_select_and_min_positive_int(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_select_and_min_positive_int(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[AND0:%.*]] = icmp eq i32 [[AND]], 1
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[AND0]], i32 [[OR]], i32 [[XOR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%and = and i32 %x, %y
|
|
%and0 = icmp eq i32 %and, 1
|
|
%xor = xor i32 %x, %y
|
|
%or = or i32 %x, %y
|
|
%cond = select i1 %and0, i32 %or, i32 %xor
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_select_and_max_positive_int(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_select_and_max_positive_int(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[AND0:%.*]] = icmp eq i32 [[AND]], 2147483647
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[AND0]], i32 [[OR]], i32 [[XOR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%and = and i32 %x, %y
|
|
%and0 = icmp eq i32 %and, 2147483647
|
|
%xor = xor i32 %x, %y
|
|
%or = or i32 %x, %y
|
|
%cond = select i1 %and0, i32 %or, i32 %xor
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_select_and_min_negative_int(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_select_and_min_negative_int(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[AND0:%.*]] = icmp eq i32 [[AND]], -2147483648
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[AND0]], i32 [[OR]], i32 [[XOR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%and = and i32 %x, %y
|
|
%and0 = icmp eq i32 %and, -2147483648
|
|
%xor = xor i32 %x, %y
|
|
%or = or i32 %x, %y
|
|
%cond = select i1 %and0, i32 %or, i32 %xor
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_select_or_min_positive_int(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_select_or_min_positive_int(
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], 1
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 [[AND]], i32 [[XOR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%or = or i32 %x, %y
|
|
%or0 = icmp eq i32 %or, 1
|
|
%and = and i32 %x, %y
|
|
%xor = xor i32 %x, %y
|
|
%cond = select i1 %or0, i32 %and, i32 %xor
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_select_or_max_positive_int(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_select_or_max_positive_int(
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], 2147483647
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 [[AND]], i32 [[XOR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%or = or i32 %x, %y
|
|
%or0 = icmp eq i32 %or, 2147483647
|
|
%and = and i32 %x, %y
|
|
%xor = xor i32 %x, %y
|
|
%cond = select i1 %or0, i32 %and, i32 %xor
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_select_or_min_negative_int(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_select_or_min_negative_int(
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], -2147483648
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 [[AND]], i32 [[XOR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%or = or i32 %x, %y
|
|
%or0 = icmp eq i32 %or, -2147483648
|
|
%and = and i32 %x, %y
|
|
%xor = xor i32 %x, %y
|
|
%cond = select i1 %or0, i32 %and, i32 %xor
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_select_or_max_negative_int(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_select_or_max_negative_int(
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], -1
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 [[AND]], i32 [[XOR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%or = or i32 %x, %y
|
|
%or0 = icmp eq i32 %or, -1
|
|
%and = and i32 %x, %y
|
|
%xor = xor i32 %x, %y
|
|
%cond = select i1 %or0, i32 %and, i32 %xor
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_select_xor_min_positive_int(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_select_xor_min_positive_int(
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], 1
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[AND]], i32 [[OR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%xor = xor i32 %x, %y
|
|
%xor0 = icmp eq i32 %xor, 1
|
|
%and = and i32 %x, %y
|
|
%or = or i32 %x, %y
|
|
%cond = select i1 %xor0, i32 %and, i32 %or
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_select_xor_max_positive_int(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_select_xor_max_positive_int(
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], 2147483647
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[AND]], i32 [[OR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%xor = xor i32 %x, %y
|
|
%xor0 = icmp eq i32 %xor, 2147483647
|
|
%and = and i32 %x, %y
|
|
%or = or i32 %x, %y
|
|
%cond = select i1 %xor0, i32 %and, i32 %or
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_select_xor_min_negative_int(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_select_xor_min_negative_int(
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], -2147483648
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[AND]], i32 [[OR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%xor = xor i32 %x, %y
|
|
%xor0 = icmp eq i32 %xor, -2147483648
|
|
%and = and i32 %x, %y
|
|
%or = or i32 %x, %y
|
|
%cond = select i1 %xor0, i32 %and, i32 %or
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_select_xor_max_negative_int(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_select_xor_max_negative_int(
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], -1
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[AND]], i32 [[OR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%xor = xor i32 %x, %y
|
|
%xor0 = icmp eq i32 %xor, -1
|
|
%and = and i32 %x, %y
|
|
%or = or i32 %x, %y
|
|
%cond = select i1 %xor0, i32 %and, i32 %or
|
|
ret i32 %cond
|
|
}
|
|
|
|
; Select icmp and/or/xor
|
|
; https://alive2.llvm.org/ce/z/BVgrJ-
|
|
; NO TRANSFORMED - not supported
|
|
define i32 @src_no_trans_select_and_eq0_and_or(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_no_trans_select_and_eq0_and_or(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[AND0:%.*]] = icmp eq i32 [[AND]], 0
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[AND0]], i32 0, i32 [[OR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%and = and i32 %x, %y
|
|
%and0 = icmp eq i32 %and, 0
|
|
%or = or i32 %x, %y
|
|
%cond = select i1 %and0, i32 %and, i32 %or
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_no_trans_select_and_eq0_and_xor(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_no_trans_select_and_eq0_and_xor(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[AND0:%.*]] = icmp eq i32 [[AND]], 0
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[AND0]], i32 0, i32 [[XOR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%and = and i32 %x, %y
|
|
%and0 = icmp eq i32 %and, 0
|
|
%xor = xor i32 %x, %y
|
|
%cond = select i1 %and0, i32 %and, i32 %xor
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_no_trans_select_and_eq0_or_and(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_no_trans_select_and_eq0_or_and(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[AND0:%.*]] = icmp eq i32 [[AND]], 0
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[AND0]], i32 [[OR]], i32 [[AND]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%and = and i32 %x, %y
|
|
%and0 = icmp eq i32 %and, 0
|
|
%or = or i32 %x, %y
|
|
%cond = select i1 %and0, i32 %or, i32 %and
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_no_trans_select_and_eq0_xor_and(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_no_trans_select_and_eq0_xor_and(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[AND0:%.*]] = icmp eq i32 [[AND]], 0
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[AND0]], i32 [[XOR]], i32 [[AND]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%and = and i32 %x, %y
|
|
%and0 = icmp eq i32 %and, 0
|
|
%xor = xor i32 %x, %y
|
|
%cond = select i1 %and0, i32 %xor, i32 %and
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_no_trans_select_or_eq0_or_and(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_no_trans_select_or_eq0_or_and(
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], 0
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 0, i32 [[AND]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%or = or i32 %x, %y
|
|
%or0 = icmp eq i32 %or, 0
|
|
%and = and i32 %x, %y
|
|
%cond = select i1 %or0, i32 %or, i32 %and
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_no_trans_select_or_eq0_or_xor(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_no_trans_select_or_eq0_or_xor(
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], 0
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 0, i32 [[XOR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%or = or i32 %x, %y
|
|
%or0 = icmp eq i32 %or, 0
|
|
%xor = xor i32 %x, %y
|
|
%cond = select i1 %or0, i32 %or, i32 %xor
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_no_trans_select_or_eq0_and_or(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_no_trans_select_or_eq0_and_or(
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], 0
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 [[AND]], i32 [[OR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%or = or i32 %x, %y
|
|
%or0 = icmp eq i32 %or, 0
|
|
%and = and i32 %x, %y
|
|
%cond = select i1 %or0, i32 %and, i32 %or
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_no_trans_select_or_eq0_xor_or(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_no_trans_select_or_eq0_xor_or(
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], 0
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 [[XOR]], i32 [[OR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%or = or i32 %x, %y
|
|
%or0 = icmp eq i32 %or, 0
|
|
%xor = xor i32 %x, %y
|
|
%cond = select i1 %or0, i32 %xor, i32 %or
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_no_trans_select_and_ne0_xor_or(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_no_trans_select_and_ne0_xor_or(
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[OR0_NOT:%.*]] = icmp eq i32 [[OR]], 0
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0_NOT]], i32 0, i32 [[XOR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%or = or i32 %x, %y
|
|
%or0 = icmp ne i32 %or, 0
|
|
%xor = xor i32 %x, %y
|
|
%cond = select i1 %or0, i32 %xor, i32 %or
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_no_trans_select_xor_eq0_xor_and(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_no_trans_select_xor_eq0_xor_and(
|
|
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 0, i32 [[AND]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%xor = xor i32 %x, %y
|
|
%xor0 = icmp eq i32 %xor, 0
|
|
%and = and i32 %x, %y
|
|
%cond = select i1 %xor0, i32 %xor, i32 %and
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_no_trans_select_xor_eq0_xor_or(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_no_trans_select_xor_eq0_xor_or(
|
|
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 0, i32 [[OR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%xor = xor i32 %x, %y
|
|
%xor0 = icmp eq i32 %xor, 0
|
|
%or = or i32 %x, %y
|
|
%cond = select i1 %xor0, i32 %xor, i32 %or
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @src_no_trans_select_xor_eq0_and_xor(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_no_trans_select_xor_eq0_and_xor(
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], 0
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[AND]], i32 [[XOR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%xor = xor i32 %x, %y
|
|
%xor0 = icmp eq i32 %xor, 0
|
|
%and = and i32 %x, %y
|
|
%cond = select i1 %xor0, i32 %and, i32 %xor
|
|
ret i32 %cond
|
|
}
|
|
|
|
; https://alive2.llvm.org/ce/z/SBe8ei
|
|
define i32 @src_no_trans_select_xor_eq0_or_xor(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_no_trans_select_xor_eq0_or_xor(
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], 0
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[OR]], i32 [[XOR]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%xor = xor i32 %x, %y
|
|
%xor0 = icmp eq i32 %xor, 0
|
|
%or = or i32 %x, %y
|
|
%cond = select i1 %xor0, i32 %or, i32 %xor
|
|
ret i32 %cond
|
|
}
|
|
|
|
; (X == C) ? X : Y -> (X == C) ? C : Y
|
|
; Fixed #77553
|
|
define i32 @src_select_xxory_eq0_xorxy_y(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_select_xxory_eq0_xorxy_y(
|
|
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 0, i32 [[Y]]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
;
|
|
%xor = xor i32 %x, %y
|
|
%xor0 = icmp eq i32 %xor, 0
|
|
%cond = select i1 %xor0, i32 %xor, i32 %y
|
|
ret i32 %cond
|
|
}
|
|
|
|
define i32 @sequence_select_with_same_cond_false(i1 %c1, i1 %c2){
|
|
; CHECK-LABEL: @sequence_select_with_same_cond_false(
|
|
; CHECK-NEXT: [[S1:%.*]] = select i1 [[C1:%.*]], i32 23, i32 45
|
|
; CHECK-NEXT: [[S2:%.*]] = select i1 [[C2:%.*]], i32 666, i32 [[S1]]
|
|
; CHECK-NEXT: [[S3:%.*]] = select i1 [[C1]], i32 789, i32 [[S2]]
|
|
; CHECK-NEXT: ret i32 [[S3]]
|
|
;
|
|
%s1 = select i1 %c1, i32 23, i32 45
|
|
%s2 = select i1 %c2, i32 666, i32 %s1
|
|
%s3 = select i1 %c1, i32 789, i32 %s2
|
|
ret i32 %s3
|
|
}
|
|
|
|
define i32 @sequence_select_with_same_cond_true(i1 %c1, i1 %c2){
|
|
; CHECK-LABEL: @sequence_select_with_same_cond_true(
|
|
; CHECK-NEXT: [[S1:%.*]] = select i1 [[C1:%.*]], i32 45, i32 23
|
|
; CHECK-NEXT: [[S2:%.*]] = select i1 [[C2:%.*]], i32 [[S1]], i32 666
|
|
; CHECK-NEXT: [[S3:%.*]] = select i1 [[C1]], i32 [[S2]], i32 789
|
|
; CHECK-NEXT: ret i32 [[S3]]
|
|
;
|
|
%s1 = select i1 %c1, i32 45, i32 23
|
|
%s2 = select i1 %c2, i32 %s1, i32 666
|
|
%s3 = select i1 %c1, i32 %s2, i32 789
|
|
ret i32 %s3
|
|
}
|
|
|
|
define double @sequence_select_with_same_cond_double(double %a, i1 %c1, i1 %c2, double %r1, double %r2){
|
|
; CHECK-LABEL: @sequence_select_with_same_cond_double(
|
|
; CHECK-NEXT: [[S1:%.*]] = select i1 [[C1:%.*]], double 1.000000e+00, double 0.000000e+00
|
|
; CHECK-NEXT: [[S2:%.*]] = select i1 [[C2:%.*]], double [[S1]], double 2.000000e+00
|
|
; CHECK-NEXT: [[S3:%.*]] = select i1 [[C1]], double [[S2]], double 3.000000e+00
|
|
; CHECK-NEXT: ret double [[S3]]
|
|
;
|
|
%s1 = select i1 %c1, double 1.0, double 0.0
|
|
%s2 = select i1 %c2, double %s1, double 2.0
|
|
%s3 = select i1 %c1, double %s2, double 3.0
|
|
ret double %s3
|
|
}
|
|
|
|
declare void @use32(i32)
|
|
|
|
define i32 @sequence_select_with_same_cond_extra_use(i1 %c1, i1 %c2){
|
|
; CHECK-LABEL: @sequence_select_with_same_cond_extra_use(
|
|
; CHECK-NEXT: [[S1:%.*]] = select i1 [[C1:%.*]], i32 23, i32 45
|
|
; CHECK-NEXT: call void @use32(i32 [[S1]])
|
|
; CHECK-NEXT: [[S2:%.*]] = select i1 [[C2:%.*]], i32 666, i32 [[S1]]
|
|
; CHECK-NEXT: [[S3:%.*]] = select i1 [[C1]], i32 789, i32 [[S2]]
|
|
; CHECK-NEXT: ret i32 [[S3]]
|
|
;
|
|
%s1 = select i1 %c1, i32 23, i32 45
|
|
call void @use32(i32 %s1)
|
|
%s2 = select i1 %c2, i32 666, i32 %s1
|
|
%s3 = select i1 %c1, i32 789, i32 %s2
|
|
ret i32 %s3
|
|
}
|