The idea behind this canonicalization is that it allows us to handle less patterns, because we know that some will be canonicalized away. This is indeed very useful to e.g. know that constants are always on the right. However, this is only useful if the canonicalization is actually reliable. This is the case for constants, but not for arguments: Moving these to the right makes it look like the "more complex" expression is guaranteed to be on the left, but this is not actually the case in practice. It fails as soon as you replace the argument with another instruction. The end result is that it looks like things correctly work in tests, while they actually don't. We use the "thwart complexity-based canonicalization" trick to handle this in tests, but it's often a challenge for new contributors to get this right, and based on the regressions this PR originally exposed, we clearly don't get this right in many cases. For this reason, I think that it's better to remove this complexity canonicalization. It will make it much easier to write tests for commuted cases and make sure that they are handled.
1209 lines
53 KiB
LLVM
1209 lines
53 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
|
|
; RUN: opt -S -passes=instcombine < %s | FileCheck %s
|
|
|
|
declare float @llvm.fabs.f32(float)
|
|
declare float @llvm.copysign.f32(float, float)
|
|
declare void @llvm.assume(i1 noundef)
|
|
declare float @llvm.log2.f32(float)
|
|
declare float @llvm.exp2.f32(float)
|
|
declare float @llvm.trunc.f32(float)
|
|
declare float @llvm.arithmetic.fence.f32(float)
|
|
declare float @llvm.minnum.f32(float, float)
|
|
declare float @llvm.maxnum.f32(float, float)
|
|
|
|
|
|
define float @ninf_user_select_inf(i1 %cond, float %x, float %y) {
|
|
; CHECK-LABEL: define float @ninf_user_select_inf
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
|
|
; CHECK-NEXT: [[NINF_USER:%.*]] = fmul ninf float [[Y]], [[SELECT]]
|
|
; CHECK-NEXT: ret float [[NINF_USER]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%ninf.user = fmul ninf float %y, %select
|
|
ret float %ninf.user
|
|
}
|
|
|
|
define nofpclass(inf) float @ret_nofpclass_inf_poison() {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf_poison() {
|
|
; CHECK-NEXT: ret float poison
|
|
;
|
|
ret float poison
|
|
}
|
|
|
|
define nofpclass(inf) float @ret_nofpclass_inf_undef() {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf_undef() {
|
|
; CHECK-NEXT: ret float undef
|
|
;
|
|
ret float undef
|
|
}
|
|
|
|
; Make sure there's no infinite loop
|
|
define nofpclass(all) float @ret_nofpclass_all_var(float %arg) {
|
|
; CHECK-LABEL: define nofpclass(all) float @ret_nofpclass_all_var
|
|
; CHECK-SAME: (float [[ARG:%.*]]) {
|
|
; CHECK-NEXT: ret float poison
|
|
;
|
|
ret float %arg
|
|
}
|
|
|
|
; Make sure there's no infinite loop
|
|
define nofpclass(all) <2 x float> @ret_nofpclass_all_var_vector(<2 x float> %arg) {
|
|
; CHECK-LABEL: define nofpclass(all) <2 x float> @ret_nofpclass_all_var_vector
|
|
; CHECK-SAME: (<2 x float> [[ARG:%.*]]) {
|
|
; CHECK-NEXT: ret <2 x float> poison
|
|
;
|
|
ret <2 x float> %arg
|
|
}
|
|
|
|
define nofpclass(inf) float @ret_nofpclass_inf__0() {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__0() {
|
|
; CHECK-NEXT: ret float 0.000000e+00
|
|
;
|
|
ret float 0.0
|
|
}
|
|
|
|
define nofpclass(inf) float @ret_nofpclass_inf__pinf() {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__pinf() {
|
|
; CHECK-NEXT: ret float poison
|
|
;
|
|
ret float 0x7FF0000000000000
|
|
}
|
|
|
|
define nofpclass(pinf) float @ret_nofpclass_pinf__pinf() {
|
|
; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__pinf() {
|
|
; CHECK-NEXT: ret float poison
|
|
;
|
|
ret float 0x7FF0000000000000
|
|
}
|
|
|
|
define nofpclass(pinf) float @ret_nofpclass_pinf__ninf() {
|
|
; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__ninf() {
|
|
; CHECK-NEXT: ret float 0xFFF0000000000000
|
|
;
|
|
ret float 0xFFF0000000000000
|
|
}
|
|
|
|
define nofpclass(inf) float @ret_nofpclass_inf__ninf() {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__ninf() {
|
|
; CHECK-NEXT: ret float poison
|
|
;
|
|
ret float 0xFFF0000000000000
|
|
}
|
|
|
|
; Negative test, do nothing
|
|
define nofpclass(inf) float @ret_nofpclass_inf__select_nofpclass_inf_lhs(i1 %cond, float nofpclass(inf) %x, float %y) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_nofpclass_inf_lhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float nofpclass(inf) [[X:%.*]], float [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[Y]]
|
|
; CHECK-NEXT: ret float [[SELECT]]
|
|
;
|
|
%select = select i1 %cond, float %x, float %y
|
|
ret float %select
|
|
}
|
|
|
|
; Make sure nofpclass from source argument is used, fold to %y
|
|
define nofpclass(inf) float @ret_nofpclass_inf__select_nofpclass_arg_only_inf_lhs(i1 %cond, float nofpclass(nan norm zero sub) %x, float %y) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_nofpclass_arg_only_inf_lhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float nofpclass(nan zero sub norm) [[X:%.*]], float [[Y:%.*]]) {
|
|
; CHECK-NEXT: ret float [[Y]]
|
|
;
|
|
%select = select i1 %cond, float %x, float %y
|
|
ret float %select
|
|
}
|
|
|
|
; Make sure nofpclass from source argument is used, fold to %x
|
|
define nofpclass(inf) float @ret_nofpclass_inf__select_nofpclass_arg_only_inf_rhs(i1 %cond, float %x, float nofpclass(nan norm zero sub) %y) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_nofpclass_arg_only_inf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(nan zero sub norm) [[Y:%.*]]) {
|
|
; CHECK-NEXT: ret float [[X]]
|
|
;
|
|
%select = select i1 %cond, float %x, float %y
|
|
ret float %select
|
|
}
|
|
|
|
; Fold to ret %y
|
|
define nofpclass(inf) [3 x [2 x float]] @ret_float_array(i1 %cond, [3 x [2 x float]] nofpclass(nan norm zero sub) %x, [3 x [2 x float]] %y) {
|
|
; CHECK-LABEL: define nofpclass(inf) [3 x [2 x float]] @ret_float_array
|
|
; CHECK-SAME: (i1 [[COND:%.*]], [3 x [2 x float]] nofpclass(nan zero sub norm) [[X:%.*]], [3 x [2 x float]] [[Y:%.*]]) {
|
|
; CHECK-NEXT: ret [3 x [2 x float]] [[Y]]
|
|
;
|
|
%select = select i1 %cond, [3 x [2 x float]] %x, [3 x [2 x float]] %y
|
|
ret [3 x [2 x float ]] %select
|
|
}
|
|
|
|
; Fold to ret %x
|
|
define nofpclass(inf) float @ret_nofpclass_inf__select_pinf_lhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_pinf_lhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float [[X]]
|
|
;
|
|
%select = select i1 %cond, float 0x7FF0000000000000, float %x
|
|
ret float %select
|
|
}
|
|
|
|
; Fold to ret %x
|
|
define nofpclass(inf) float @ret_nofpclass_inf__select_pinf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float [[X]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
ret float %select
|
|
}
|
|
|
|
; Fold to poison
|
|
define nofpclass(inf) float @ret_nofpclass_inf__select_pinf_or_ninf(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_pinf_or_ninf
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float poison
|
|
;
|
|
%select = select i1 %cond, float 0x7FF0000000000000, float 0xFFF0000000000000
|
|
ret float %select
|
|
}
|
|
|
|
; Fold to poison
|
|
define nofpclass(inf) float @ret_nofpclass_inf__select_ninf_or_pinf(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_ninf_or_pinf
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float poison
|
|
;
|
|
%select = select i1 %cond, float 0xFFF0000000000000, float 0x7FF0000000000000
|
|
ret float %select
|
|
}
|
|
|
|
; Fold to pos inf
|
|
define nofpclass(ninf) float @ret_nofpclass_ninf__select_ninf_or_pinf(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(ninf) float @ret_nofpclass_ninf__select_ninf_or_pinf
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float 0x7FF0000000000000
|
|
;
|
|
%select = select i1 %cond, float 0xFFF0000000000000, float 0x7FF0000000000000
|
|
ret float %select
|
|
}
|
|
|
|
; Fold to neg inf
|
|
define nofpclass(pinf) float @ret_nofpclass_pinf__select_ninf_or_pinf(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__select_ninf_or_pinf
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float 0xFFF0000000000000
|
|
;
|
|
%select = select i1 %cond, float 0xFFF0000000000000, float 0x7FF0000000000000
|
|
ret float %select
|
|
}
|
|
|
|
; Fold to poison
|
|
define nofpclass(zero) float @ret_nofpclass_zero__select_pzero_or_nzero(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(zero) float @ret_nofpclass_zero__select_pzero_or_nzero
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float poison
|
|
;
|
|
%select = select i1 %cond, float 0.0, float -0.0
|
|
ret float %select
|
|
}
|
|
|
|
; Fold to +0
|
|
define nofpclass(nzero) float @ret_nofpclass_nzero__select_pzero_or_nzero(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(nzero) float @ret_nofpclass_nzero__select_pzero_or_nzero
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float 0.000000e+00
|
|
;
|
|
%select = select i1 %cond, float 0.0, float -0.0
|
|
ret float %select
|
|
}
|
|
|
|
; Fold to -0
|
|
define nofpclass(pzero) float @ret_nofpclass_pzero__select_pzero_or_nzero(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(pzero) float @ret_nofpclass_pzero__select_pzero_or_nzero
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float -0.000000e+00
|
|
;
|
|
%select = select i1 %cond, float 0.0, float -0.0
|
|
ret float %select
|
|
}
|
|
|
|
; Fold to ret %x
|
|
define nofpclass(inf) <2 x float> @ret_nofpclass_inf__select_pinf_lhs_vector(<2 x i1> %cond, <2 x float> %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) <2 x float> @ret_nofpclass_inf__select_pinf_lhs_vector
|
|
; CHECK-SAME: (<2 x i1> [[COND:%.*]], <2 x float> [[X:%.*]]) {
|
|
; CHECK-NEXT: ret <2 x float> [[X]]
|
|
;
|
|
%select = select <2 x i1> %cond, <2 x float> <float 0x7FF0000000000000, float 0x7FF0000000000000>, <2 x float> %x
|
|
ret <2 x float> %select
|
|
}
|
|
|
|
; Fold to ret %x
|
|
define nofpclass(inf) <2 x float> @ret_nofpclass_inf__select_pinf_lhs_vector_undef(<2 x i1> %cond, <2 x float> %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) <2 x float> @ret_nofpclass_inf__select_pinf_lhs_vector_undef
|
|
; CHECK-SAME: (<2 x i1> [[COND:%.*]], <2 x float> [[X:%.*]]) {
|
|
; CHECK-NEXT: ret <2 x float> [[X]]
|
|
;
|
|
%select = select <2 x i1> %cond, <2 x float> <float 0x7FF0000000000000, float poison>, <2 x float> %x
|
|
ret <2 x float> %select
|
|
}
|
|
|
|
; Fold to ret %x
|
|
define nofpclass(inf) <2 x float> @ret_nofpclass_inf__select_mixed_inf_lhs_vector(<2 x i1> %cond, <2 x float> %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) <2 x float> @ret_nofpclass_inf__select_mixed_inf_lhs_vector
|
|
; CHECK-SAME: (<2 x i1> [[COND:%.*]], <2 x float> [[X:%.*]]) {
|
|
; CHECK-NEXT: ret <2 x float> [[X]]
|
|
;
|
|
%select = select <2 x i1> %cond, <2 x float> <float 0x7FF0000000000000, float 0xFFF0000000000000>, <2 x float> %x
|
|
ret <2 x float> %select
|
|
}
|
|
|
|
; Can't delete the select
|
|
define nofpclass(inf) float @ret_nofpclass_inf__select_multi_use_pinf_lhs(i1 %cond, float %x, ptr %ptr) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_multi_use_pinf_lhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], ptr [[PTR:%.*]]) {
|
|
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float [[X]]
|
|
; CHECK-NEXT: store float [[SELECT]], ptr [[PTR]], align 4
|
|
; CHECK-NEXT: ret float [[SELECT]]
|
|
;
|
|
%select = select i1 %cond, float 0x7FF0000000000000, float %x
|
|
store float %select, ptr %ptr
|
|
ret float %select
|
|
}
|
|
|
|
; Can't do anything
|
|
define nofpclass(inf) float @ret_nofpclass_inf__select_p0_lhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_p0_lhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float 0.000000e+00, float [[X]]
|
|
; CHECK-NEXT: ret float [[SELECT]]
|
|
;
|
|
%select = select i1 %cond, float 0.0, float %x
|
|
ret float %select
|
|
}
|
|
|
|
; Can't do anything
|
|
define nofpclass(inf) float @ret_nofpclass_inf__select_p0_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_p0_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0.000000e+00
|
|
; CHECK-NEXT: ret float [[SELECT]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0.0
|
|
ret float %select
|
|
}
|
|
|
|
; Can't do anything
|
|
define nofpclass(nan) float @ret_nofpclass_nan__select_pinf_lhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__select_pinf_lhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float [[X]]
|
|
; CHECK-NEXT: ret float [[SELECT]]
|
|
;
|
|
%select = select i1 %cond, float 0x7FF0000000000000, float %x
|
|
ret float %select
|
|
}
|
|
|
|
; Can't do anything
|
|
define nofpclass(nan) float @ret_nofpclass_nan__select_pinf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
|
|
; CHECK-NEXT: ret float [[SELECT]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
ret float %select
|
|
}
|
|
|
|
define nofpclass(inf nan) float @ret_nofpclass_inf_nan__select_chain_inf_nan_0(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(nan inf) float @ret_nofpclass_inf_nan__select_chain_inf_nan_0
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float [[X]]
|
|
;
|
|
%select0 = select i1 %cond, float 0x7FF8000000000000, float %x
|
|
%select1 = select i1 %cond, float 0x7FF0000000000000, float %select0
|
|
ret float %select1
|
|
}
|
|
|
|
define nofpclass(inf nan) float @ret_nofpclass_inf_nan__select_chain_inf_nan_1(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(nan inf) float @ret_nofpclass_inf_nan__select_chain_inf_nan_1
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float poison
|
|
;
|
|
%select0 = select i1 %cond, float %x, float 0x7FF8000000000000
|
|
%select1 = select i1 %cond, float 0x7FF0000000000000, float %select0
|
|
ret float %select1
|
|
}
|
|
|
|
define nofpclass(nan) float @ret_nofpclass_nan__select_chain_inf_nan(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__select_chain_inf_nan
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[SELECT1:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float [[X]]
|
|
; CHECK-NEXT: ret float [[SELECT1]]
|
|
;
|
|
%select0 = select i1 %cond, float 0x7FF8000000000000, float %x
|
|
%select1 = select i1 %cond, float 0x7FF0000000000000, float %select0
|
|
ret float %select1
|
|
}
|
|
|
|
define nofpclass(inf) float @ret_nofpclass_inf__select_chain_inf_nan_0(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_chain_inf_nan_0
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float [[X]]
|
|
;
|
|
%select0 = select i1 %cond, float 0x7FF8000000000000, float %x
|
|
%select1 = select i1 %cond, float 0x7FF0000000000000, float %select0
|
|
ret float %select1
|
|
}
|
|
|
|
define nofpclass(inf) float @ret_nofpclass_inf__select_chain_inf_nan_1(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_chain_inf_nan_1
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float 0x7FF8000000000000
|
|
;
|
|
%select0 = select i1 %cond, float 0x7FF8000000000000, float %x
|
|
%select1 = select i1 %cond, float %select0, float 0x7FF0000000000000
|
|
ret float %select1
|
|
}
|
|
|
|
; Simplify to fabs %x
|
|
define nofpclass(inf) float @ret_nofpclass_inf__fabs_select_ninf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__fabs_select_ninf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: ret float [[TMP1]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0xFFF0000000000000
|
|
%fabs = call float @llvm.fabs.f32(float %select)
|
|
ret float %fabs
|
|
}
|
|
|
|
; Simplify to fabs %x
|
|
define nofpclass(inf) float @ret_nofpclass_inf__fabs_select_pinf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__fabs_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: ret float [[TMP1]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%fabs = call float @llvm.fabs.f32(float %select)
|
|
ret float %fabs
|
|
}
|
|
|
|
define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives__fabs_select_pinf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_no_negatives__fabs_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[COND]], float [[TMP1]], float 0x7FF0000000000000
|
|
; CHECK-NEXT: ret float [[FABS]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%fabs = call float @llvm.fabs.f32(float %select)
|
|
ret float %fabs
|
|
}
|
|
|
|
; Fold to fabs(%x), preserving a possible nan's payload bits
|
|
define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_no_positives__fabs_select_pinf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_no_positives__fabs_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: ret float [[TMP1]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%fabs = call float @llvm.fabs.f32(float %select)
|
|
ret float %fabs
|
|
}
|
|
|
|
define nofpclass(nan ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives_nan__fabs_select_pinf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_nofpclass_no_negatives_nan__fabs_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[COND]], float [[TMP1]], float 0x7FF0000000000000
|
|
; CHECK-NEXT: ret float [[FABS]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%fabs = call float @llvm.fabs.f32(float %select)
|
|
ret float %fabs
|
|
}
|
|
|
|
; Can fold to poison
|
|
define nofpclass(nan pinf pnorm psub pzero) float @ret_nofpclass_no_positives_nan__fabs_select_pinf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_nofpclass_no_positives_nan__fabs_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float poison
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%fabs = call float @llvm.fabs.f32(float %select)
|
|
ret float %fabs
|
|
}
|
|
|
|
; Simplify to fneg %x
|
|
define nofpclass(inf) float @ret_nofpclass_inf__fneg_select_ninf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__fneg_select_ninf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[X_NEG:%.*]] = fneg float [[X]]
|
|
; CHECK-NEXT: ret float [[X_NEG]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0xFFF0000000000000
|
|
%fneg = fneg float %select
|
|
ret float %fneg
|
|
}
|
|
|
|
; Simplify to fneg %x
|
|
define nofpclass(inf nnorm nsub nzero) float @ret_nofpclass_nonegatives_noinf___fneg_select_pinf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_nofpclass_nonegatives_noinf___fneg_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[X_NEG:%.*]] = fneg float [[X]]
|
|
; CHECK-NEXT: ret float [[X_NEG]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%fneg = fneg float %select
|
|
ret float %fneg
|
|
}
|
|
|
|
; Simplify to fneg %x
|
|
define nofpclass(inf nnorm nsub nzero) float @ret_nofpclass_nonegatives_noinf___fneg_select_ninf_lhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_nofpclass_nonegatives_noinf___fneg_select_ninf_lhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[X_NEG:%.*]] = fneg float [[X]]
|
|
; CHECK-NEXT: ret float [[X_NEG]]
|
|
;
|
|
%select = select i1 %cond, float 0xFFF0000000000000, float %x
|
|
%fneg = fneg float %select
|
|
ret float %fneg
|
|
}
|
|
|
|
define nofpclass(pzero psub pnorm pinf) float @ret_nofpclass_nopositives___fneg_select_pinf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_nopositives___fneg_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[X_NEG:%.*]] = fneg float [[X]]
|
|
; CHECK-NEXT: [[FNEG:%.*]] = select i1 [[COND]], float [[X_NEG]], float 0xFFF0000000000000
|
|
; CHECK-NEXT: ret float [[FNEG]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%fneg = fneg float %select
|
|
ret float %fneg
|
|
}
|
|
|
|
; Fold to fneg fabs
|
|
define nofpclass(inf) float @ret_nofpclass_inf__fneg_fabs_select_pinf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__fneg_fabs_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: [[DOTNEG:%.*]] = fneg float [[TMP1]]
|
|
; CHECK-NEXT: ret float [[DOTNEG]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%fabs = call float @llvm.fabs.f32(float %select)
|
|
%fneg = fneg float %fabs
|
|
ret float %fneg
|
|
}
|
|
|
|
; Fold to fneg fabs, may need to preserve a nan payload
|
|
define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives__fneg_fabs_select_pinf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_nonegatives__fneg_fabs_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: [[DOTNEG:%.*]] = fneg float [[TMP1]]
|
|
; CHECK-NEXT: ret float [[DOTNEG]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%fabs = call float @llvm.fabs.f32(float %select)
|
|
%fneg = fneg float %fabs
|
|
ret float %fneg
|
|
}
|
|
|
|
|
|
; Fold to poison
|
|
define nofpclass(nan ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives_nonan__fneg_fabs_select_pinf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_nofpclass_nonegatives_nonan__fneg_fabs_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float poison
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%fabs = call float @llvm.fabs.f32(float %select)
|
|
%fneg = fneg float %fabs
|
|
ret float %fneg
|
|
}
|
|
|
|
; should fold to ret copysign(%x)
|
|
define nofpclass(inf) float @ret_nofpclass_inf__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__copysign_unknown_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
|
|
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
|
|
; CHECK-NEXT: ret float [[COPYSIGN]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%copysign = call float @llvm.copysign.f32(float %select, float %unknown.sign)
|
|
ret float %copysign
|
|
}
|
|
|
|
define nofpclass(inf) float @ret_nofpclass_inf__copysign_positive_select_pinf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__copysign_positive_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: ret float [[TMP1]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%copysign = call float @llvm.copysign.f32(float %select, float 1.0)
|
|
ret float %copysign
|
|
}
|
|
|
|
define nofpclass(inf) float @ret_nofpclass_inf__copysign_negative_select_pinf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__copysign_negative_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: [[DOTNEG:%.*]] = fneg float [[TMP1]]
|
|
; CHECK-NEXT: ret float [[DOTNEG]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%copysign = call float @llvm.copysign.f32(float %select, float -1.0)
|
|
ret float %copysign
|
|
}
|
|
|
|
; can fold to fneg(fabs(x))
|
|
define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_nopositives_copysign(float %x, float %unknown.sign) {
|
|
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_nopositives_copysign
|
|
; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
|
|
; CHECK-NEXT: ret float [[COPYSIGN]]
|
|
;
|
|
%copysign = call float @llvm.copysign.f32(float %x, float %unknown.sign)
|
|
ret float %copysign
|
|
}
|
|
|
|
; can fold to fneg(fabs(x))
|
|
define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_nopositives_copysign_nnan_flag(float %x, float %unknown.sign) {
|
|
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_nopositives_copysign_nnan_flag
|
|
; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call nnan float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg nnan float [[TMP1]]
|
|
; CHECK-NEXT: ret float [[COPYSIGN]]
|
|
;
|
|
%copysign = call nnan float @llvm.copysign.f32(float %x, float %unknown.sign)
|
|
ret float %copysign
|
|
}
|
|
|
|
; can fold to fneg(fabs(x))
|
|
define nofpclass(nan pinf pnorm psub pzero) float @ret_nofpclass_nopositives_nonan_copysign(float %x, float %unknown.sign) {
|
|
; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_nofpclass_nopositives_nonan_copysign
|
|
; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
|
|
; CHECK-NEXT: ret float [[COPYSIGN]]
|
|
;
|
|
%copysign = call float @llvm.copysign.f32(float %x, float %unknown.sign)
|
|
ret float %copysign
|
|
}
|
|
|
|
; can fold to fabs(x)
|
|
define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives_copysign(float %x, float %unknown.sign) {
|
|
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_nonegatives_copysign
|
|
; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
|
|
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: ret float [[COPYSIGN]]
|
|
;
|
|
%copysign = call float @llvm.copysign.f32(float %x, float %unknown.sign)
|
|
ret float %copysign
|
|
}
|
|
|
|
; can fold to fabs(x)
|
|
define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives_copysign_nnan_flag(float %x, float %unknown.sign) {
|
|
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_nonegatives_copysign_nnan_flag
|
|
; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
|
|
; CHECK-NEXT: [[COPYSIGN:%.*]] = call nnan float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: ret float [[COPYSIGN]]
|
|
;
|
|
%copysign = call nnan float @llvm.copysign.f32(float %x, float %unknown.sign)
|
|
ret float %copysign
|
|
}
|
|
|
|
; can fold to fabs(x)
|
|
define nofpclass(nan ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives_nonan_copysign(float %x, float %unknown.sign) {
|
|
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_nofpclass_nonegatives_nonan_copysign
|
|
; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
|
|
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: ret float [[COPYSIGN]]
|
|
;
|
|
%copysign = call float @llvm.copysign.f32(float %x, float %unknown.sign)
|
|
ret float %copysign
|
|
}
|
|
|
|
define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_nopositives__copysign_fabs_select_pinf_rhs(i1 %cond, float %x, float %sign) {
|
|
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_nopositives__copysign_fabs_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[SIGN:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: ret float [[TMP1]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%fabs.sign = call float @llvm.fabs.f32(float %sign)
|
|
%copysign = call float @llvm.copysign.f32(float %select, float %fabs.sign)
|
|
ret float %copysign
|
|
}
|
|
|
|
; Can fold to copysign %x
|
|
define nofpclass(inf nnorm nsub nzero) float @ret_nofpclass_no_negatives_noinf__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
|
|
; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_nofpclass_no_negatives_noinf__copysign_unknown_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
|
|
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: ret float [[COPYSIGN]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%copysign = call float @llvm.copysign.f32(float %select, float %unknown.sign)
|
|
ret float %copysign
|
|
}
|
|
|
|
; Can fold to copysign %x
|
|
define nofpclass(inf pnorm psub pzero) float @ret_nofpclass_no_positives_noinf__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
|
|
; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_nofpclass_no_positives_noinf__copysign_unknown_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
|
|
; CHECK-NEXT: ret float [[COPYSIGN]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%copysign = call float @llvm.copysign.f32(float %select, float %unknown.sign)
|
|
ret float %copysign
|
|
}
|
|
|
|
; Can't fold because it could have nan payload bits
|
|
define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
|
|
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_no_negatives__copysign_unknown_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: [[COPYSIGN:%.*]] = select i1 [[COND]], float [[TMP1]], float 0x7FF0000000000000
|
|
; CHECK-NEXT: ret float [[COPYSIGN]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%copysign = call float @llvm.copysign.f32(float %select, float %unknown.sign)
|
|
ret float %copysign
|
|
}
|
|
|
|
; Can't fold because it could be nan
|
|
define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_no_positives__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
|
|
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_no_positives__copysign_unknown_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: [[DOTNEG:%.*]] = fneg float [[TMP1]]
|
|
; CHECK-NEXT: [[COPYSIGN:%.*]] = select i1 [[COND]], float [[DOTNEG]], float 0xFFF0000000000000
|
|
; CHECK-NEXT: ret float [[COPYSIGN]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%copysign = call float @llvm.copysign.f32(float %select, float %unknown.sign)
|
|
ret float %copysign
|
|
}
|
|
|
|
; Could fold to copysign with constant
|
|
define nofpclass(nan ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives_nonan__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
|
|
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_nofpclass_no_negatives_nonan__copysign_unknown_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: [[COPYSIGN:%.*]] = select i1 [[COND]], float [[TMP1]], float 0x7FF0000000000000
|
|
; CHECK-NEXT: ret float [[COPYSIGN]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%copysign = call float @llvm.copysign.f32(float %select, float %unknown.sign)
|
|
ret float %copysign
|
|
}
|
|
|
|
; Could fold to copysign %x with constant
|
|
define nofpclass(nan pinf pnorm psub pzero) float @ret_nofpclass_no_positives_nonan__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
|
|
; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_nofpclass_no_positives_nonan__copysign_unknown_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: [[DOTNEG:%.*]] = fneg float [[TMP1]]
|
|
; CHECK-NEXT: [[COPYSIGN:%.*]] = select i1 [[COND]], float [[DOTNEG]], float 0xFFF0000000000000
|
|
; CHECK-NEXT: ret float [[COPYSIGN]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%copysign = call float @llvm.copysign.f32(float %select, float %unknown.sign)
|
|
ret float %copysign
|
|
}
|
|
|
|
; Do nothing
|
|
define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_negatives__select_clamp_neg_to_zero(float %x) {
|
|
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_negatives__select_clamp_neg_to_zero
|
|
; CHECK-SAME: (float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[IS_LT_ZERO:%.*]] = fcmp olt float [[X]], 0.000000e+00
|
|
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_LT_ZERO]], float 0.000000e+00, float [[X]]
|
|
; CHECK-NEXT: ret float [[SELECT]]
|
|
;
|
|
%is.lt.zero = fcmp olt float %x, 0.0
|
|
%select = select i1 %is.lt.zero, float 0.0, float %x
|
|
ret float %select
|
|
}
|
|
|
|
; Can fold to ret %x, assumed to be nan
|
|
define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_negatives__select_clamp_pos_to_zero(float %x) {
|
|
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_negatives__select_clamp_pos_to_zero
|
|
; CHECK-SAME: (float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[IS_GT_ZERO:%.*]] = fcmp ogt float [[X]], 0.000000e+00
|
|
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_GT_ZERO]], float 0.000000e+00, float [[X]]
|
|
; CHECK-NEXT: ret float [[SELECT]]
|
|
;
|
|
%is.gt.zero = fcmp ogt float %x, 0.0
|
|
%select = select i1 %is.gt.zero, float 0.0, float %x
|
|
ret float %select
|
|
}
|
|
|
|
; Can fold to ret +0
|
|
define nofpclass(nan ninf nnorm nsub nzero) float @ret_nofpclass_nan_negatives__select_clamp_pos_to_zero(float %x) {
|
|
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_nofpclass_nan_negatives__select_clamp_pos_to_zero
|
|
; CHECK-SAME: (float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[IS_GT_ZERO:%.*]] = fcmp ogt float [[X]], 0.000000e+00
|
|
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_GT_ZERO]], float 0.000000e+00, float [[X]]
|
|
; CHECK-NEXT: ret float [[SELECT]]
|
|
;
|
|
%is.gt.zero = fcmp ogt float %x, 0.0
|
|
%select = select i1 %is.gt.zero, float 0.0, float %x
|
|
ret float %select
|
|
}
|
|
|
|
; Can fold to ret poison
|
|
define nofpclass(nan ninf nnorm nsub zero) float @ret_nofpclass_nan_negatives_zero__select_clamp_pos_to_zero(float %x) {
|
|
; CHECK-LABEL: define nofpclass(nan ninf zero nsub nnorm) float @ret_nofpclass_nan_negatives_zero__select_clamp_pos_to_zero
|
|
; CHECK-SAME: (float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float [[X]]
|
|
;
|
|
%is.gt.zero = fcmp ogt float %x, 0.0
|
|
%select = select i1 %is.gt.zero, float 0.0, float %x
|
|
ret float %select
|
|
}
|
|
|
|
; Can fold to ret %x, assumed to be nan
|
|
define nofpclass(ninf nnorm nsub zero) float @ret_nofpclass_negatives_zero__select_clamp_pos_to_zero(float %x) {
|
|
; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @ret_nofpclass_negatives_zero__select_clamp_pos_to_zero
|
|
; CHECK-SAME: (float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float [[X]]
|
|
;
|
|
%is.gt.zero = fcmp ogt float %x, 0.0
|
|
%select = select i1 %is.gt.zero, float 0.0, float %x
|
|
ret float %select
|
|
}
|
|
|
|
; Assume should allow folding ret %y
|
|
define nofpclass(inf) float @ret_nofpclass_noinfs__assumed_isinf__select_pinf_lhs(i1 %cond, float %x, float %y) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_noinfs__assumed_isinf__select_pinf_lhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[FABS_X:%.*]] = call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: [[X_IS_INF:%.*]] = fcmp oeq float [[FABS_X]], 0x7FF0000000000000
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[X_IS_INF]])
|
|
; CHECK-NEXT: ret float [[Y]]
|
|
;
|
|
%fabs.x = call float @llvm.fabs.f32(float %x)
|
|
%x.is.inf = fcmp oeq float %fabs.x, 0x7FF0000000000000
|
|
call void @llvm.assume(i1 %x.is.inf)
|
|
%select = select i1 %cond, float %x, float %y
|
|
ret float %select
|
|
}
|
|
|
|
; Ideally should be able to fold out everything after the exp2 call.
|
|
define nofpclass(nan inf nzero nsub nnorm) float @powr_issue64870(float nofpclass(nan inf) %x, float nofpclass(nan inf) %y) {
|
|
; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @powr_issue64870
|
|
; CHECK-SAME: (float nofpclass(nan inf) [[X:%.*]], float nofpclass(nan inf) [[Y:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[I:%.*]] = tail call float @llvm.fabs.f32(float [[X]])
|
|
; CHECK-NEXT: [[I1:%.*]] = tail call float @llvm.log2.f32(float [[I]])
|
|
; CHECK-NEXT: [[I2:%.*]] = fmul float [[I1]], [[Y]]
|
|
; CHECK-NEXT: [[I3:%.*]] = tail call nofpclass(ninf nzero nsub nnorm) float @llvm.exp2.f32(float [[I2]])
|
|
; CHECK-NEXT: [[I6:%.*]] = fcmp oeq float [[X]], 0.000000e+00
|
|
; CHECK-NEXT: [[I7:%.*]] = select i1 [[I6]], float 0.000000e+00, float [[I3]]
|
|
; CHECK-NEXT: [[I8:%.*]] = fcmp oeq float [[Y]], 0.000000e+00
|
|
; CHECK-NEXT: [[I11:%.*]] = fcmp oeq float [[X]], 1.000000e+00
|
|
; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[I11]], i1 true, i1 [[I8]]
|
|
; CHECK-NEXT: [[I12:%.*]] = select i1 [[TMP0]], float 1.000000e+00, float [[I7]]
|
|
; CHECK-NEXT: ret float [[I12]]
|
|
;
|
|
entry:
|
|
%i = tail call float @llvm.fabs.f32(float %x)
|
|
%i1 = tail call float @llvm.log2.f32(float %i)
|
|
%i2 = fmul float %i1, %y
|
|
%i3 = tail call nofpclass(ninf nzero nsub nnorm) float @llvm.exp2.f32(float %i2)
|
|
%i4 = fcmp olt float %y, 0.000000e+00
|
|
%i5 = select i1 %i4, float 0x7FF0000000000000, float 0.000000e+00
|
|
%i6 = fcmp oeq float %x, 0.000000e+00
|
|
%i7 = select i1 %i6, float %i5, float %i3
|
|
%i8 = fcmp oeq float %y, 0.000000e+00
|
|
%i9 = select i1 %i6, float 0x7FF8000000000000, float 1.000000e+00
|
|
%i10 = select i1 %i8, float %i9, float %i7
|
|
%i11 = fcmp oeq float %x, 1.000000e+00
|
|
%i12 = select i1 %i11, float 1.000000e+00, float %i10
|
|
%i13 = fcmp olt float %x, 0.000000e+00
|
|
%i14 = select i1 %i13, float 0x7FF8000000000000, float %i12
|
|
ret float %i14
|
|
}
|
|
|
|
; Different implementation of powr
|
|
define nofpclass(nan inf nzero nsub nnorm) float @test_powr_issue64870_2(float nofpclass(nan inf) %arg, float nofpclass(nan inf) %arg1) #0 {
|
|
; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @test_powr_issue64870_2
|
|
; CHECK-SAME: (float nofpclass(nan inf) [[ARG:%.*]], float nofpclass(nan inf) [[ARG1:%.*]]) {
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[I:%.*]] = fcmp olt float [[ARG]], 0.000000e+00
|
|
; CHECK-NEXT: [[I2:%.*]] = select i1 [[I]], float 0x7FF8000000000000, float [[ARG]]
|
|
; CHECK-NEXT: [[I3:%.*]] = tail call float @llvm.log2.f32(float noundef [[I2]])
|
|
; CHECK-NEXT: [[I4:%.*]] = select i1 [[I]], float 0x7FF8000000000000, float [[ARG1]]
|
|
; CHECK-NEXT: [[I5:%.*]] = fmul float [[I4]], [[I3]]
|
|
; CHECK-NEXT: [[I6:%.*]] = tail call noundef nofpclass(ninf nzero nsub nnorm) float @llvm.exp2.f32(float noundef [[I5]])
|
|
; CHECK-NEXT: [[I10:%.*]] = fcmp oeq float [[I2]], 0.000000e+00
|
|
; CHECK-NEXT: [[I12:%.*]] = select i1 [[I10]], float 0.000000e+00, float [[I6]]
|
|
; CHECK-NEXT: ret float [[I12]]
|
|
;
|
|
bb:
|
|
%i = fcmp olt float %arg, 0.000000e+00
|
|
%i2 = select i1 %i, float 0x7FF8000000000000, float %arg
|
|
%i3 = tail call float @llvm.log2.f32(float noundef %i2) #2
|
|
%i4 = select i1 %i, float 0x7FF8000000000000, float %arg1
|
|
%i5 = fmul float %i4, %i3
|
|
%i6 = tail call noundef nofpclass(ninf nzero nsub nnorm) float @llvm.exp2.f32(float noundef %i5)
|
|
%i7 = fcmp olt float %i4, 0.000000e+00
|
|
%i8 = select i1 %i7, float 0x7FF0000000000000, float 0.000000e+00
|
|
%i9 = fcmp ueq float %i4, 0.000000e+00
|
|
%i10 = fcmp oeq float %i2, 0.000000e+00
|
|
%i11 = select i1 %i9, float 0x7FF8000000000000, float %i8
|
|
%i12 = select i1 %i10, float %i11, float %i6
|
|
ret float %i12
|
|
}
|
|
|
|
; implementation of pow with some prunable cases
|
|
define nofpclass(nan inf) float @pow_f32(float nofpclass(nan inf) %arg, float nofpclass(nan inf) %arg1) #0 {
|
|
; CHECK-LABEL: define nofpclass(nan inf) float @pow_f32
|
|
; CHECK-SAME: (float nofpclass(nan inf) [[ARG:%.*]], float nofpclass(nan inf) [[ARG1:%.*]]) {
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[I:%.*]] = tail call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float noundef [[ARG]])
|
|
; CHECK-NEXT: [[I2:%.*]] = tail call float @llvm.log2.f32(float noundef [[I]])
|
|
; CHECK-NEXT: [[I3:%.*]] = fmul float [[I2]], [[ARG1]]
|
|
; CHECK-NEXT: [[I4:%.*]] = tail call noundef float @llvm.exp2.f32(float noundef [[I3]])
|
|
; CHECK-NEXT: [[I5:%.*]] = tail call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float noundef [[ARG1]])
|
|
; CHECK-NEXT: [[I6:%.*]] = tail call float @llvm.trunc.f32(float noundef [[I5]])
|
|
; CHECK-NEXT: [[I7:%.*]] = fcmp oeq float [[I6]], [[I5]]
|
|
; CHECK-NEXT: [[I8:%.*]] = fmul float [[I5]], 5.000000e-01
|
|
; CHECK-NEXT: [[I9:%.*]] = tail call float @llvm.trunc.f32(float noundef [[I8]])
|
|
; CHECK-NEXT: [[I10:%.*]] = fcmp une float [[I9]], [[I8]]
|
|
; CHECK-NEXT: [[I11:%.*]] = and i1 [[I7]], [[I10]]
|
|
; CHECK-NEXT: [[I12:%.*]] = select i1 [[I11]], float [[ARG]], float 1.000000e+00
|
|
; CHECK-NEXT: [[I13:%.*]] = tail call noundef float @llvm.copysign.f32(float noundef [[I4]], float noundef [[I12]])
|
|
; CHECK-NEXT: [[I17:%.*]] = fcmp oeq float [[ARG]], 0.000000e+00
|
|
; CHECK-NEXT: [[I21:%.*]] = select i1 [[I11]], float [[ARG]], float 0.000000e+00
|
|
; CHECK-NEXT: [[I22:%.*]] = tail call noundef nofpclass(nan sub norm) float @llvm.copysign.f32(float noundef 0.000000e+00, float noundef [[I21]])
|
|
; CHECK-NEXT: [[I23:%.*]] = select i1 [[I17]], float [[I22]], float [[I13]]
|
|
; CHECK-NEXT: [[I24:%.*]] = fcmp oeq float [[ARG]], 1.000000e+00
|
|
; CHECK-NEXT: [[I25:%.*]] = fcmp oeq float [[ARG1]], 0.000000e+00
|
|
; CHECK-NEXT: [[I26:%.*]] = or i1 [[I24]], [[I25]]
|
|
; CHECK-NEXT: [[I27:%.*]] = select i1 [[I26]], float 1.000000e+00, float [[I23]]
|
|
; CHECK-NEXT: ret float [[I27]]
|
|
;
|
|
bb:
|
|
%i = tail call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float noundef %arg)
|
|
%i2 = tail call float @llvm.log2.f32(float noundef %i)
|
|
%i3 = fmul float %i2, %arg1
|
|
%i4 = tail call noundef float @llvm.exp2.f32(float noundef %i3)
|
|
%i5 = tail call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float noundef %arg1)
|
|
%i6 = tail call float @llvm.trunc.f32(float noundef %i5)
|
|
%i7 = fcmp oeq float %i6, %i5
|
|
%i8 = fmul float %i5, 5.000000e-01
|
|
%i9 = tail call float @llvm.trunc.f32(float noundef %i8)
|
|
%i10 = fcmp une float %i9, %i8
|
|
%i11 = and i1 %i7, %i10
|
|
%i12 = select i1 %i11, float %arg, float 1.000000e+00
|
|
%i13 = tail call noundef float @llvm.copysign.f32(float noundef %i4, float noundef %i12)
|
|
%i14 = fcmp olt float %arg, 0.000000e+00
|
|
%i15 = select i1 %i7, float %i13, float 0x7FF8000000000000
|
|
%i16 = select i1 %i14, float %i15, float %i13
|
|
%i17 = fcmp oeq float %arg, 0.000000e+00
|
|
%i18 = fcmp olt float %arg1, 0.000000e+00
|
|
%i19 = xor i1 %i17, %i18
|
|
%i20 = select i1 %i19, float 0.000000e+00, float 0x7FF0000000000000
|
|
%i21 = select i1 %i11, float %arg, float 0.000000e+00
|
|
%i22 = tail call noundef nofpclass(nan sub norm) float @llvm.copysign.f32(float noundef %i20, float noundef %i21)
|
|
%i23 = select i1 %i17, float %i22, float %i16
|
|
%i24 = fcmp oeq float %arg, 1.000000e+00
|
|
%i25 = fcmp oeq float %arg1, 0.000000e+00
|
|
%i26 = or i1 %i24, %i25
|
|
%i27 = select i1 %i26, float 1.000000e+00, float %i23
|
|
ret float %i27
|
|
}
|
|
|
|
declare float @extern()
|
|
|
|
; Make sure nofpclass from arbitrary callsite is used, fold to %y
|
|
define nofpclass(inf) float @ret_nofpclass_inf__select_nofpclass_call_only_inf(i1 %cond, float %y) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_nofpclass_call_only_inf
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[MUST_BE_INF:%.*]] = call nofpclass(nan zero sub norm) float @extern()
|
|
; CHECK-NEXT: ret float [[Y]]
|
|
;
|
|
%must.be.inf = call nofpclass(nan norm zero sub) float @extern()
|
|
%select = select i1 %cond, float %must.be.inf, float %y
|
|
ret float %select
|
|
}
|
|
|
|
define nofpclass(pinf) float @ret_nofpclass_pinf__nofpclass_call_only_inf(i1 %cond, float %y) {
|
|
; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__nofpclass_call_only_inf
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[MUST_BE_INF:%.*]] = call nofpclass(nan zero sub norm) float @extern()
|
|
; CHECK-NEXT: ret float 0xFFF0000000000000
|
|
;
|
|
%must.be.inf = call nofpclass(nan norm zero sub) float @extern()
|
|
ret float %must.be.inf
|
|
}
|
|
|
|
define nofpclass(ninf) float @ret_nofpclass_ninf__nofpclass_call_only_inf(i1 %cond, float %y) {
|
|
; CHECK-LABEL: define nofpclass(ninf) float @ret_nofpclass_ninf__nofpclass_call_only_inf
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[MUST_BE_INF:%.*]] = call nofpclass(nan zero sub norm) float @extern()
|
|
; CHECK-NEXT: ret float 0x7FF0000000000000
|
|
;
|
|
%must.be.inf = call nofpclass(nan norm zero sub) float @extern()
|
|
ret float %must.be.inf
|
|
}
|
|
|
|
define nofpclass(nzero) float @ret_nofpclass_nzero__nofpclass_call_only_zero(i1 %cond, float %y) {
|
|
; CHECK-LABEL: define nofpclass(nzero) float @ret_nofpclass_nzero__nofpclass_call_only_zero
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[MUST_BE_ZERO:%.*]] = call nofpclass(nan inf sub norm) float @extern()
|
|
; CHECK-NEXT: ret float 0.000000e+00
|
|
;
|
|
%must.be.zero = call nofpclass(nan sub norm inf) float @extern()
|
|
ret float %must.be.zero
|
|
}
|
|
|
|
define nofpclass(pzero) float @ret_nofpclass_pzero__nofpclass_call_only_zero(i1 %cond, float %y) {
|
|
; CHECK-LABEL: define nofpclass(pzero) float @ret_nofpclass_pzero__nofpclass_call_only_zero
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[MUST_BE_ZERO:%.*]] = call nofpclass(nan inf sub norm) float @extern()
|
|
; CHECK-NEXT: ret float -0.000000e+00
|
|
;
|
|
%must.be.zero = call nofpclass(nan sub norm inf) float @extern()
|
|
ret float %must.be.zero
|
|
}
|
|
|
|
; Should not fold this, should not assume payload/sign bits are canonical
|
|
define nofpclass(qnan) float @ret_nofpclass_qnan__nofpclass_call_only_nan(i1 %cond, float %y) {
|
|
; CHECK-LABEL: define nofpclass(qnan) float @ret_nofpclass_qnan__nofpclass_call_only_nan
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[MUST_BE_NAN:%.*]] = call nofpclass(inf zero sub norm) float @extern()
|
|
; CHECK-NEXT: ret float [[MUST_BE_NAN]]
|
|
;
|
|
%must.be.nan = call nofpclass(inf norm zero sub) float @extern()
|
|
ret float %must.be.nan
|
|
}
|
|
|
|
; Should not fold this, should not assume payload/sign bits are canonical
|
|
define nofpclass(snan) float @ret_nofpclass_snan__nofpclass_call_only_nan(i1 %cond, float %y) {
|
|
; CHECK-LABEL: define nofpclass(snan) float @ret_nofpclass_snan__nofpclass_call_only_nan
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[MUST_BE_NAN:%.*]] = call nofpclass(inf zero sub norm) float @extern()
|
|
; CHECK-NEXT: ret float [[MUST_BE_NAN]]
|
|
;
|
|
%must.be.nan = call nofpclass(inf norm zero sub) float @extern()
|
|
ret float %must.be.nan
|
|
}
|
|
|
|
; Assume call should allow folding this to %y
|
|
; TODO: Not working, multiple user problem.
|
|
define nofpclass(inf) float @ret_nofpclass_inf__select_assumed_call_result_only_inf(i1 %cond, float %y) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_assumed_call_result_only_inf
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[MUST_BE_INF:%.*]] = call float @extern()
|
|
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MUST_BE_INF]])
|
|
; CHECK-NEXT: [[IS_INF:%.*]] = fcmp oeq float [[FABS]], 0x7FF0000000000000
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[IS_INF]])
|
|
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[MUST_BE_INF]], float [[Y]]
|
|
; CHECK-NEXT: ret float [[SELECT]]
|
|
;
|
|
%must.be.inf = call float @extern()
|
|
%fabs = call float @llvm.fabs.f32(float %must.be.inf)
|
|
%is.inf = fcmp oeq float %fabs, 0x7FF0000000000000
|
|
call void @llvm.assume(i1 %is.inf)
|
|
%select = select i1 %cond, float %must.be.inf, float %y
|
|
ret float %select
|
|
}
|
|
|
|
define nofpclass(inf) float @ret_nofpclass_inf__simple_phi_inf_or_unknown(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__simple_phi_inf_or_unknown
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND]], label [[BB0:%.*]], label [[RET:%.*]]
|
|
; CHECK: bb0:
|
|
; CHECK-NEXT: br label [[RET]]
|
|
; CHECK: ret:
|
|
; CHECK-NEXT: [[PHI:%.*]] = phi float [ 0x7FF0000000000000, [[ENTRY:%.*]] ], [ [[X]], [[BB0]] ]
|
|
; CHECK-NEXT: ret float [[PHI]]
|
|
;
|
|
entry:
|
|
br i1 %cond, label %bb0, label %ret
|
|
|
|
bb0:
|
|
br label %ret
|
|
|
|
ret:
|
|
%phi = phi float [ 0x7FF0000000000000, %entry ], [ %x, %bb0 ]
|
|
ret float %phi
|
|
}
|
|
|
|
declare i1 @loop.cond()
|
|
|
|
declare float @loop.func()
|
|
|
|
|
|
; Should be able to fold inf initial value to poison
|
|
define nofpclass(inf) float @ret_nofpclass_inf__phi_0(i1 %cond0, float %unknown) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__phi_0
|
|
; CHECK-SAME: (i1 [[COND0:%.*]], float [[UNKNOWN:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND0]], label [[LOOP:%.*]], label [[RET:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[PHI_LOOP:%.*]] = phi float [ 0x7FF0000000000000, [[ENTRY:%.*]] ], [ [[LOOP_FUNC:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[LOOP_FUNC]] = call nofpclass(nan) float @loop.func()
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = call i1 @loop.cond()
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[RET]], label [[LOOP]]
|
|
; CHECK: ret:
|
|
; CHECK-NEXT: [[PHI_RET:%.*]] = phi float [ 0.000000e+00, [[ENTRY]] ], [ [[PHI_LOOP]], [[LOOP]] ]
|
|
; CHECK-NEXT: ret float [[PHI_RET]]
|
|
;
|
|
entry:
|
|
br i1 %cond0, label %loop, label %ret
|
|
|
|
loop:
|
|
%phi.loop = phi float [ 0x7FF0000000000000, %entry ], [ %loop.func, %loop ]
|
|
%loop.func = call nofpclass(nan) float @loop.func()
|
|
%loop.cond = call i1 @loop.cond()
|
|
br i1 %loop.cond, label %ret, label %loop
|
|
|
|
ret:
|
|
%phi.ret = phi float [ 0.0, %entry ], [ %phi.loop, %loop ]
|
|
ret float %phi.ret
|
|
}
|
|
|
|
; fold to ret 0
|
|
define nofpclass(inf) float @ret_nofpclass_inf__recursive_phi_0(i1 %cond0, float %unknown) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__recursive_phi_0
|
|
; CHECK-SAME: (i1 [[COND0:%.*]], float [[UNKNOWN:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND0]], label [[LOOP:%.*]], label [[RET:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = call i1 @loop.cond()
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[RET]], label [[LOOP]]
|
|
; CHECK: ret:
|
|
; CHECK-NEXT: ret float 0.000000e+00
|
|
;
|
|
entry:
|
|
br i1 %cond0, label %loop, label %ret
|
|
|
|
loop:
|
|
%phi.loop = phi float [ 0x7FF0000000000000, %entry ], [ %phi.loop, %loop ]
|
|
%loop.cond = call i1 @loop.cond()
|
|
br i1 %loop.cond, label %ret, label %loop
|
|
|
|
ret:
|
|
%phi.ret = phi float [ 0.0, %entry ], [ %phi.loop, %loop ]
|
|
ret float %phi.ret
|
|
}
|
|
|
|
; fold to ret poison
|
|
define nofpclass(inf) float @ret_nofpclass_inf__recursive_phi_1(i1 %cond0, float %unknown) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__recursive_phi_1
|
|
; CHECK-SAME: (i1 [[COND0:%.*]], float [[UNKNOWN:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND0]], label [[LOOP:%.*]], label [[RET:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = call i1 @loop.cond()
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[RET]], label [[LOOP]]
|
|
; CHECK: ret:
|
|
; CHECK-NEXT: ret float poison
|
|
;
|
|
entry:
|
|
br i1 %cond0, label %loop, label %ret
|
|
|
|
loop:
|
|
%phi.loop = phi float [ 0x7FF0000000000000, %entry ], [ %phi.loop, %loop ]
|
|
%loop.cond = call i1 @loop.cond()
|
|
br i1 %loop.cond, label %ret, label %loop
|
|
|
|
ret:
|
|
%phi.ret = phi float [ 0x7FF0000000000000, %entry ], [ %phi.loop, %loop ]
|
|
ret float %phi.ret
|
|
}
|
|
|
|
; Should be able to fold inf initial values to poison
|
|
define nofpclass(inf) float @ret_nofpclass_inf__phi_switch_repeated_predecessor(i32 %switch, float %unknown) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__phi_switch_repeated_predecessor
|
|
; CHECK-SAME: (i32 [[SWITCH:%.*]], float [[UNKNOWN:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: switch i32 [[SWITCH]], label [[RET:%.*]] [
|
|
; CHECK-NEXT: i32 0, label [[LOOP:%.*]]
|
|
; CHECK-NEXT: i32 1, label [[LOOP]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[PHI_LOOP:%.*]] = phi float [ 0x7FF0000000000000, [[ENTRY:%.*]] ], [ 0x7FF0000000000000, [[ENTRY]] ], [ [[UNKNOWN]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = call i1 @loop.cond()
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[RET]], label [[LOOP]]
|
|
; CHECK: ret:
|
|
; CHECK-NEXT: [[PHI_RET:%.*]] = phi float [ 0.000000e+00, [[ENTRY]] ], [ [[PHI_LOOP]], [[LOOP]] ]
|
|
; CHECK-NEXT: ret float [[PHI_RET]]
|
|
;
|
|
entry:
|
|
switch i32 %switch, label %ret [
|
|
i32 0, label %loop
|
|
i32 1, label %loop
|
|
]
|
|
|
|
loop:
|
|
%phi.loop = phi float [ 0x7FF0000000000000, %entry ], [ 0x7FF0000000000000, %entry ], [ %unknown, %loop ]
|
|
%loop.cond = call i1 @loop.cond()
|
|
br i1 %loop.cond, label %ret, label %loop
|
|
|
|
ret:
|
|
%phi.ret = phi float [ 0.0, %entry ], [ %phi.loop, %loop ]
|
|
ret float %phi.ret
|
|
}
|
|
|
|
; Simplify to arithmetic.fence %x
|
|
define nofpclass(inf) float @ret_nofpclass_inf__arithmetic_fence_select_pinf_rhs(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__arithmetic_fence_select_pinf_rhs
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[FENCE:%.*]] = call float @llvm.arithmetic.fence.f32(float [[X]])
|
|
; CHECK-NEXT: ret float [[FENCE]]
|
|
;
|
|
%select = select i1 %cond, float %x, float 0x7FF0000000000000
|
|
%fence = call float @llvm.arithmetic.fence.f32(float %select)
|
|
ret float %fence
|
|
}
|
|
|
|
; Can simplify to %x
|
|
define nofpclass(pinf) float @ret_nofpclass_pinf__minnum_pinf(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__minnum_pinf
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minnum.f32(float [[X]], float 0x7FF0000000000000)
|
|
; CHECK-NEXT: ret float [[MIN]]
|
|
;
|
|
%min = call float @llvm.minnum.f32(float %x, float 0x7FF0000000000000)
|
|
ret float %min
|
|
}
|
|
|
|
; Can fold to -inf
|
|
define nofpclass(pinf) float @ret_nofpclass_pinf__minnum_ninf(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__minnum_ninf
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float 0xFFF0000000000000
|
|
;
|
|
%min = call float @llvm.minnum.f32(float %x, float 0xFFF0000000000000)
|
|
ret float %min
|
|
}
|
|
|
|
; Can simplify to %x
|
|
define nofpclass(ninf) float @ret_nofpclass_ninf__maxnum_ninf(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(ninf) float @ret_nofpclass_ninf__maxnum_ninf
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maxnum.f32(float [[X]], float 0xFFF0000000000000)
|
|
; CHECK-NEXT: ret float [[MAX]]
|
|
;
|
|
%max = call float @llvm.maxnum.f32(float %x, float 0xFFF0000000000000)
|
|
ret float %max
|
|
}
|
|
|
|
; Can fold to +inf
|
|
define nofpclass(ninf) float @ret_nofpclass_ninf__maxnum_pinf(i1 %cond, float %x) {
|
|
; CHECK-LABEL: define nofpclass(ninf) float @ret_nofpclass_ninf__maxnum_pinf
|
|
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
|
|
; CHECK-NEXT: ret float 0x7FF0000000000000
|
|
;
|
|
%max = call float @llvm.maxnum.f32(float %x, float 0x7FF0000000000000)
|
|
ret float %max
|
|
}
|