| ; 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 |
| } |
| |
| ; Basic aggregate tests to ensure this does not crash. |
| define nofpclass(nan) { float } @ret_nofpclass_struct_ty() { |
| ; CHECK-LABEL: define nofpclass(nan) { float } @ret_nofpclass_struct_ty() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: ret { float } zeroinitializer |
| ; |
| entry: |
| ret { float } zeroinitializer |
| } |
| |
| define nofpclass(nan) { float, float } @ret_nofpclass_multiple_elems_struct_ty() { |
| ; CHECK-LABEL: define nofpclass(nan) { float, float } @ret_nofpclass_multiple_elems_struct_ty() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: ret { float, float } zeroinitializer |
| ; |
| entry: |
| ret { float, float } zeroinitializer |
| } |
| |
| define nofpclass(nan) { <4 x float>, <4 x float> } @ret_nofpclass_vector_elems_struct_ty() { |
| ; CHECK-LABEL: define nofpclass(nan) { <4 x float>, <4 x float> } @ret_nofpclass_vector_elems_struct_ty() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: ret { <4 x float>, <4 x float> } zeroinitializer |
| ; |
| entry: |
| ret { <4 x float>, <4 x float> } zeroinitializer |
| } |
| |
| define nofpclass(nan) [ 5 x float ] @ret_nofpclass_array_ty() { |
| ; CHECK-LABEL: define nofpclass(nan) [5 x float] @ret_nofpclass_array_ty() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: ret [5 x float] zeroinitializer |
| ; |
| entry: |
| ret [ 5 x float ] zeroinitializer |
| } |
| |
| define nofpclass(nan) [ 2 x [ 5 x float ]] @ret_nofpclass_nested_array_ty() { |
| ; CHECK-LABEL: define nofpclass(nan) [2 x [5 x float]] @ret_nofpclass_nested_array_ty() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: ret [2 x [5 x float]] zeroinitializer |
| ; |
| entry: |
| ret [ 2 x [ 5 x float ]] zeroinitializer |
| } |
| |
| define nofpclass(pinf) { float } @ret_nofpclass_struct_ty_pinf__ninf() { |
| ; CHECK-LABEL: define nofpclass(pinf) { float } @ret_nofpclass_struct_ty_pinf__ninf() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: ret { float } { float 0xFFF0000000000000 } |
| ; |
| entry: |
| ret { float } { float 0xFFF0000000000000 } |
| } |
| |
| define nofpclass(pinf) { float, float } @ret_nofpclass_multiple_elems_struct_ty_pinf__ninf() { |
| ; CHECK-LABEL: define nofpclass(pinf) { float, float } @ret_nofpclass_multiple_elems_struct_ty_pinf__ninf() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: ret { float, float } { float 0xFFF0000000000000, float 0xFFF0000000000000 } |
| ; |
| entry: |
| ret { float, float } { float 0xFFF0000000000000, float 0xFFF0000000000000 } |
| } |
| |
| define nofpclass(pinf) { <2 x float> } @ret_nofpclass_vector_elems_struct_ty_pinf__ninf() { |
| ; CHECK-LABEL: define nofpclass(pinf) { <2 x float> } @ret_nofpclass_vector_elems_struct_ty_pinf__ninf() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: ret { <2 x float> } { <2 x float> splat (float 0xFFF0000000000000) } |
| ; |
| entry: |
| ret { <2 x float>} { <2 x float> <float 0xFFF0000000000000, float 0xFFF0000000000000> } |
| } |
| |
| ; UTC_ARGS: --disable |
| ; FileCheck does not like the nested square brackets. |
| define nofpclass(pinf) [ 1 x [ 1 x float ]] @ret_nofpclass_nested_array_ty_pinf__ninf() { |
| ; CHECK-LABEL: @ret_nofpclass_nested_array_ty_pinf__ninf() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: ret {{.*}}float 0xFFF0000000000000 |
| ; |
| entry: |
| ret [ 1 x [ 1 x float ]] [[ 1 x float ] [float 0xFFF0000000000000]] |
| } |
| ; UTC_ARGS: --enable |
| |
| define nofpclass(pzero) { float, float } @ret_nofpclass_multiple_elems_struct_ty_pzero__nzero() { |
| ; CHECK-LABEL: define nofpclass(pzero) { float, float } @ret_nofpclass_multiple_elems_struct_ty_pzero__nzero() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: ret { float, float } { float -0.000000e+00, float -0.000000e+00 } |
| ; |
| entry: |
| ret { float, float } { float -0.0, float -0.0 } |
| } |
| |
| define nofpclass(ninf) { float, float } @ret_nofpclass_multiple_elems_struct_ty_ninf__npinf() { |
| ; CHECK-LABEL: define nofpclass(ninf) { float, float } @ret_nofpclass_multiple_elems_struct_ty_ninf__npinf() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: ret { float, float } { float 0x7FF0000000000000, float 0x7FF0000000000000 } |
| ; |
| entry: |
| ret { float, float } { float 0x7FF0000000000000, float 0x7FF0000000000000 } |
| } |
| |
| ; FIXME (should be poison): Support computeKnownFPClass() for non-zero aggregates. |
| define nofpclass(inf) { float, float } @ret_nofpclass_multiple_elems_struct_ty_inf__npinf() { |
| ; CHECK-LABEL: define nofpclass(inf) { float, float } @ret_nofpclass_multiple_elems_struct_ty_inf__npinf() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: ret { float, float } { float 0x7FF0000000000000, float 0x7FF0000000000000 } |
| ; |
| entry: |
| ret { float, float } { float 0x7FF0000000000000, float 0x7FF0000000000000 } |
| } |
| |
| ; FIXME (should be poison): Support computeKnownFPClass() for non-zero aggregates. |
| define nofpclass(nzero) [ 1 x float ] @ret_nofpclass_multiple_elems_struct_ty_nzero_nzero() { |
| ; CHECK-LABEL: define nofpclass(nzero) [1 x float] @ret_nofpclass_multiple_elems_struct_ty_nzero_nzero() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: ret [1 x float] [float -0.000000e+00] |
| ; |
| entry: |
| ret [ 1 x float ] [ float -0.0 ] |
| } |
| |
| ; 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: [[TMP0:%.*]] = tail call nofpclass(nan sub norm) float @llvm.copysign.f32(float 0.000000e+00, float [[ARG]]) |
| ; CHECK-NEXT: [[I22:%.*]] = select i1 [[I11]], float [[TMP0]], float 0.000000e+00 |
| ; 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 |
| } |