llvm-project/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
Matt Arsenault 302ff8fd00
InstCombine: Use SimplifyDemandedFPClass on fmul (#177490)
Start trying to use SimplifyDemandedFPClass on instructions, starting
with fmul. This subsumes the old transform on multiply of 0. The
main change is the introduction of nnan/ninf. I do not think anywhere
was systematically trying to introduce fast math flags before, though
a few odd transforms would set them.

Previously we only called SimplifyDemandedFPClass on function returns
with nofpclass annotations. Start following the pattern of
SimplifyDemandedBits, where this will be called from relevant root
instructions.

I was wondering if this should go into InstCombineAggressive, but that
apparently does not make use of InstCombineInternal's worklist.
2026-02-10 09:49:31 +00:00

2693 lines
143 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)
declare float @llvm.minimumnum.f32(float, float)
declare float @llvm.maximumnum.f32(float, float)
declare nofpclass(inf norm sub zero) float @nan_only()
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
}
define nofpclass(all) float @ret_nofpclass_all_undef() {
; CHECK-LABEL: define nofpclass(all) float @ret_nofpclass_all_undef() {
; CHECK-NEXT: ret float poison
;
ret float undef
}
; Use + callsite implies no values, should fold undef to poison.
define nofpclass(nan) float @undef_folds_to_poison_arg() {
; CHECK-LABEL: define nofpclass(nan) float @undef_folds_to_poison_arg() {
; CHECK-NEXT: [[FENCE:%.*]] = call float @llvm.arithmetic.fence.f32(float nofpclass(inf zero sub norm) poison)
; CHECK-NEXT: ret float [[FENCE]]
;
%fence = call float @llvm.arithmetic.fence.f32(float nofpclass(inf sub norm zero) undef)
ret float %fence
}
; 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 %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 [[X]]
;
%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
}
define nofpclass(snan) float @fabs_src_known_positive(float nofpclass(nan ninf nnorm nsub nzero) %always.positive) {
; CHECK-LABEL: define nofpclass(snan) float @fabs_src_known_positive
; CHECK-SAME: (float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]]) {
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE]]
;
%fabs = call float @llvm.fabs.f32(float %always.positive)
ret float %fabs
}
define nofpclass(snan) float @fabs_src_known_positive_or_nan(float nofpclass(ninf nnorm nsub nzero) %always.positive.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @fabs_src_known_positive_or_nan
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ALWAYS_POSITIVE_OR_NAN:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_POSITIVE_OR_NAN]])
; CHECK-NEXT: ret float [[FABS]]
;
%fabs = call float @llvm.fabs.f32(float %always.positive.or.nan)
ret float %fabs
}
define nofpclass(snan) float @fabs_nnan_src_known_positive_or_nan(float nofpclass(ninf nnorm nsub nzero) %always.positive.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @fabs_nnan_src_known_positive_or_nan
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ALWAYS_POSITIVE_OR_NAN:%.*]]) {
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE_OR_NAN]]
;
%fabs = call nnan float @llvm.fabs.f32(float %always.positive.or.nan)
ret float %fabs
}
define nofpclass(nan) float @ret_nonan_fabs_src_known_positive_or_nan(float nofpclass(ninf nnorm nsub nzero) %always.positive.or.nan) {
; CHECK-LABEL: define nofpclass(nan) float @ret_nonan_fabs_src_known_positive_or_nan
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ALWAYS_POSITIVE_OR_NAN:%.*]]) {
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE_OR_NAN]]
;
%fabs = call float @llvm.fabs.f32(float %always.positive.or.nan)
ret float %fabs
}
define nofpclass(snan) float @fabs_src_known_positive_multiple_uses(float nofpclass(nan ninf nnorm nsub nzero) %always.positive, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fabs_src_known_positive_multiple_uses
; CHECK-SAME: (float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: store float [[ALWAYS_POSITIVE]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE]]
;
%fabs = call float @llvm.fabs.f32(float %always.positive)
store float %fabs, ptr %ptr
ret float %fabs
}
define nofpclass(snan) float @fabs_src_known_positive_except_negzero_multiple_uses(float nofpclass(nan ninf nnorm nsub) %always.positive.or.nzero, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fabs_src_known_positive_except_negzero_multiple_uses
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[ALWAYS_POSITIVE_OR_NZERO:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_POSITIVE_OR_NZERO]])
; CHECK-NEXT: store float [[FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[FABS]]
;
%fabs = call float @llvm.fabs.f32(float %always.positive.or.nzero)
store float %fabs, ptr %ptr
ret float %fabs
}
define nofpclass(snan) float @fabs_nsz_src_known_positive_except_negzero(float nofpclass(nan ninf nnorm nsub) %always.positive.or.nzero) {
; CHECK-LABEL: define nofpclass(snan) float @fabs_nsz_src_known_positive_except_negzero
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[ALWAYS_POSITIVE_OR_NZERO:%.*]]) {
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE_OR_NZERO]]
;
%fabs = call nsz float @llvm.fabs.f32(float %always.positive.or.nzero)
ret float %fabs
}
define nofpclass(snan) float @fabs_nsz_src_known_positive_except_negzero_multiple_uses(float nofpclass(nan ninf nnorm nsub) %always.positive.or.nzero, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fabs_nsz_src_known_positive_except_negzero_multiple_uses
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[ALWAYS_POSITIVE_OR_NZERO:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: store float [[ALWAYS_POSITIVE_OR_NZERO]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE_OR_NZERO]]
;
%fabs = call nsz float @llvm.fabs.f32(float %always.positive.or.nzero)
store float %fabs, ptr %ptr
ret float %fabs
}
define nofpclass(snan) float @fabs_src_known_positive_or_nan_multiple_uses(float nofpclass(ninf nnorm nsub nzero) %always.positive.or.nan, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fabs_src_known_positive_or_nan_multiple_uses
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ALWAYS_POSITIVE_OR_NAN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_POSITIVE_OR_NAN]])
; CHECK-NEXT: store float [[FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[FABS]]
;
%fabs = call float @llvm.fabs.f32(float %always.positive.or.nan)
store float %fabs, ptr %ptr
ret float %fabs
}
define nofpclass(nan) float @ret_nonan_fabs_src_known_positive_or_nan_multiple_uses(float nofpclass(ninf nnorm nsub nzero) %always.positive.or.nan, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan) float @ret_nonan_fabs_src_known_positive_or_nan_multiple_uses
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ALWAYS_POSITIVE_OR_NAN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_POSITIVE_OR_NAN]])
; CHECK-NEXT: store float [[FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE_OR_NAN]]
;
%fabs = call float @llvm.fabs.f32(float %always.positive.or.nan)
store float %fabs, ptr %ptr
ret float %fabs
}
; Take no-nan from flag
define nofpclass(nsub) float @ret_fabs_nnan_src_known_positive_or_nan_multiple_uses(float nofpclass(ninf nnorm nsub nzero) %always.positive.or.nan, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nsub) float @ret_fabs_nnan_src_known_positive_or_nan_multiple_uses
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ALWAYS_POSITIVE_OR_NAN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call nnan float @llvm.fabs.f32(float [[ALWAYS_POSITIVE_OR_NAN]])
; CHECK-NEXT: store float [[FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE_OR_NAN]]
;
%fabs = call nnan float @llvm.fabs.f32(float %always.positive.or.nan)
store float %fabs, ptr %ptr
ret float %fabs
}
; Take no-infs from flag, which will then imply no neg
define nofpclass(nsub) float @ret_fabs_ninf_src_known_positive_or_ninf_or_nan_multiple_uses(float nofpclass(nan nnorm nsub nzero) %always.positive.or.ninf, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nsub) float @ret_fabs_ninf_src_known_positive_or_ninf_or_nan_multiple_uses
; CHECK-SAME: (float nofpclass(nan nzero nsub nnorm) [[ALWAYS_POSITIVE_OR_NINF:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call ninf float @llvm.fabs.f32(float [[ALWAYS_POSITIVE_OR_NINF]])
; CHECK-NEXT: store float [[FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE_OR_NINF]]
;
%fabs = call ninf float @llvm.fabs.f32(float %always.positive.or.ninf)
store float %fabs, ptr %ptr
ret float %fabs
}
define nofpclass(snan) float @fabs_src_known_negative(float nofpclass(nan pinf pnorm psub pzero) %always.negative) {
; CHECK-LABEL: define nofpclass(snan) float @fabs_src_known_negative
; CHECK-SAME: (float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE]])
; CHECK-NEXT: ret float [[FABS]]
;
%fabs = call float @llvm.fabs.f32(float %always.negative)
ret float %fabs
}
define nofpclass(snan) float @fneg_fabs_src_known_negative_multiple_uses(float nofpclass(nan pinf pnorm psub pzero) %always.negative, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_src_known_negative_multiple_uses
; CHECK-SAME: (float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE]])
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: store float [[FNEG_FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE]]
;
%fabs = call float @llvm.fabs.f32(float %always.negative)
%fneg.fabs = fneg float %fabs
store float %fneg.fabs, ptr %ptr
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_fabs_src_known_positive_multiple_uses(float nofpclass(nan ninf nnorm nsub nzero) %always.positive, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_src_known_positive_multiple_uses
; CHECK-SAME: (float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[ALWAYS_POSITIVE]]
; CHECK-NEXT: store float [[FNEG_FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call float @llvm.fabs.f32(float %always.positive)
%fneg.fabs = fneg float %fabs
store float %fneg.fabs, ptr %ptr
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_fabs_src_known_negative_or_nan_multiple_uses(float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_src_known_negative_or_nan_multiple_uses
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_NAN]])
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: store float [[FNEG_FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call float @llvm.fabs.f32(float %always.negative.or.nan)
%fneg.fabs = fneg float %fabs
store float %fneg.fabs, ptr %ptr
ret float %fneg.fabs
}
define nofpclass(nan) float @ret_nonan_fneg_fabs_src_known_positive_or_nan_multiple_uses(float nofpclass(ninf nnorm nsub nzero) %always.positive.or.nan, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan) float @ret_nonan_fneg_fabs_src_known_positive_or_nan_multiple_uses
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ALWAYS_POSITIVE_OR_NAN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_POSITIVE_OR_NAN]])
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: store float [[FNEG_FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call float @llvm.fabs.f32(float %always.positive.or.nan)
%fneg.fabs = fneg float %fabs
store float %fneg.fabs, ptr %ptr
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_nnan_fabs_src_known_negative_or_nan_multiple_uses(float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_nnan_fabs_src_known_negative_or_nan_multiple_uses
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_NAN]])
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg nnan float [[FABS]]
; CHECK-NEXT: store float [[FNEG_FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE_OR_NAN]]
;
%fabs = call float @llvm.fabs.f32(float %always.negative.or.nan)
%fneg.fabs = fneg nnan float %fabs
store float %fneg.fabs, ptr %ptr
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_fabs_nnan_src_known_negative_or_nan_multiple_uses(float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_nnan_src_known_negative_or_nan_multiple_uses
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call nnan float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_NAN]])
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: store float [[FNEG_FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE_OR_NAN]]
;
%fabs = call nnan float @llvm.fabs.f32(float %always.negative.or.nan)
%fneg.fabs = fneg float %fabs
store float %fneg.fabs, ptr %ptr
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_fabs_nofpclass_nan_src__known_negative_or_nan_multiple_uses(float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_nofpclass_nan_src__known_negative_or_nan_multiple_uses
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float nofpclass(nan) [[ALWAYS_NEGATIVE_OR_NAN]])
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: store float [[FNEG_FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call float @llvm.fabs.f32(float nofpclass(nan) %always.negative.or.nan)
%fneg.fabs = fneg float %fabs
store float %fneg.fabs, ptr %ptr
ret float %fneg.fabs
}
; Take no-posinf from ninf flag
define nofpclass(snan) float @ret_fneg_ninf_fabs_src_known_negative_or_posinf_multiple_uses(float nofpclass(nan pnorm psub pzero) %negative.or.neginf, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @ret_fneg_ninf_fabs_src_known_negative_or_posinf_multiple_uses
; CHECK-SAME: (float nofpclass(nan pzero psub pnorm) [[NEGATIVE_OR_NEGINF:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[NEGATIVE_OR_NEGINF]])
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg ninf float [[FABS]]
; CHECK-NEXT: store float [[FNEG_FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[NEGATIVE_OR_NEGINF]]
;
%fabs = call float @llvm.fabs.f32(float %negative.or.neginf)
%fneg.fabs = fneg ninf float %fabs
store float %fneg.fabs, ptr %ptr
ret float %fneg.fabs
}
; Take no-posinf from ninf flag
define nofpclass(snan) float @ret_fneg_fabs_ninf_src_known_negative_or_posinf_multiple_uses(float nofpclass(nan pnorm psub pzero) %negative.or.neginf, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @ret_fneg_fabs_ninf_src_known_negative_or_posinf_multiple_uses
; CHECK-SAME: (float nofpclass(nan pzero psub pnorm) [[NEGATIVE_OR_NEGINF:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call ninf float @llvm.fabs.f32(float [[NEGATIVE_OR_NEGINF]])
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: store float [[FNEG_FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[NEGATIVE_OR_NEGINF]]
;
%fabs = call ninf float @llvm.fabs.f32(float %negative.or.neginf)
%fneg.fabs = fneg float %fabs
store float %fneg.fabs, ptr %ptr
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_fabs_src_known_negative_or_poszero_multiple_uses(float nofpclass(nan pinf pnorm psub) %always.negative.or.pzero, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_src_known_negative_or_poszero_multiple_uses
; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ALWAYS_NEGATIVE_OR_PZERO:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_PZERO]])
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: store float [[FNEG_FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call float @llvm.fabs.f32(float %always.negative.or.pzero)
%fneg.fabs = fneg float %fabs
store float %fneg.fabs, ptr %ptr
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_fabs_nsz_src_known_negative_or_poszero(float nofpclass(nan pinf pnorm psub) %always.negative.or.pzero) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_nsz_src_known_negative_or_poszero
; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ALWAYS_NEGATIVE_OR_PZERO:%.*]]) {
; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE_OR_PZERO]]
;
%fabs = call nsz float @llvm.fabs.f32(float %always.negative.or.pzero)
%fneg.fabs = fneg float %fabs
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_fabs_nsz_src_known_negative_or_poszero_multiple_uses(float nofpclass(nan pinf pnorm psub) %always.negative.or.pzero, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_nsz_src_known_negative_or_poszero_multiple_uses
; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ALWAYS_NEGATIVE_OR_PZERO:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call nsz float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_PZERO]])
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: store float [[FNEG_FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call nsz float @llvm.fabs.f32(float %always.negative.or.pzero)
%fneg.fabs = fneg float %fabs
store float %fneg.fabs, ptr %ptr
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_fabs_nsz_src_known_negative_or_poszero_multiple_uses_fabs(float nofpclass(nan pinf pnorm psub) %always.negative.or.pzero, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_nsz_src_known_negative_or_poszero_multiple_uses_fabs
; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ALWAYS_NEGATIVE_OR_PZERO:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call nsz float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_PZERO]])
; CHECK-NEXT: store float [[FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call nsz float @llvm.fabs.f32(float %always.negative.or.pzero)
store float %fabs, ptr %ptr
%fneg.fabs = fneg float %fabs
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_nsz_fabs_src_known_negative_or_poszero_multiple_uses_fabs(float nofpclass(nan pinf pnorm psub) %always.negative.or.pzero, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_nsz_fabs_src_known_negative_or_poszero_multiple_uses_fabs
; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ALWAYS_NEGATIVE_OR_PZERO:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_PZERO]])
; CHECK-NEXT: store float [[FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg nsz float [[FABS]]
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call float @llvm.fabs.f32(float %always.negative.or.pzero)
store float %fabs, ptr %ptr
%fneg.fabs = fneg nsz float %fabs
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_nsz_fabs_src_known_negative_or_poszero(float nofpclass(nan pinf pnorm psub) %always.negative.or.pzero) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_nsz_fabs_src_known_negative_or_poszero
; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ALWAYS_NEGATIVE_OR_PZERO:%.*]]) {
; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE_OR_PZERO]]
;
%fabs = call float @llvm.fabs.f32(float %always.negative.or.pzero)
%fneg.fabs = fneg nsz float %fabs
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_nsz_fabs_src_known_negative_or_poszero_multiple_uses(float nofpclass(nan pinf pnorm psub) %always.negative.or.pzero, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_nsz_fabs_src_known_negative_or_poszero_multiple_uses
; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ALWAYS_NEGATIVE_OR_PZERO:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_PZERO]])
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg nsz float [[FABS]]
; CHECK-NEXT: store float [[FNEG_FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call float @llvm.fabs.f32(float %always.negative.or.pzero)
%fneg.fabs = fneg nsz float %fabs
store float %fneg.fabs, ptr %ptr
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_fabs_src_known_negative_multiple_uses_fabs(float nofpclass(nan pinf pnorm psub pzero) %always.negative, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_src_known_negative_multiple_uses_fabs
; CHECK-SAME: (float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE]])
; CHECK-NEXT: store float [[FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call float @llvm.fabs.f32(float %always.negative)
store float %fabs, ptr %ptr
%fneg.fabs = fneg float %fabs
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_fabs_src_known_positive_multiple_uses_fabs(float nofpclass(nan ninf nnorm nsub nzero) %always.positive, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_src_known_positive_multiple_uses_fabs
; CHECK-SAME: (float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: store float [[ALWAYS_POSITIVE]], ptr [[PTR]], align 4
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[ALWAYS_POSITIVE]]
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call float @llvm.fabs.f32(float %always.positive)
store float %fabs, ptr %ptr
%fneg.fabs = fneg float %fabs
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_fabs_nnan__known_positive__sign_known_negative_or_nan(float nofpclass(ninf nzero nsub nnorm) %known.positive) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_nnan__known_positive__sign_known_negative_or_nan
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[KNOWN_POSITIVE:%.*]]) {
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg nnan float [[KNOWN_POSITIVE]]
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call nnan float @llvm.fabs.f32(float %known.positive)
%fneg.fabs = fneg nnan float %fabs
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_fabs_nnan__known_positive__sign_known_positive_or_negzero_or_nan(float nofpclass(ninf nsub nnorm) %known.positive.or.neg.zero) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_nnan__known_positive__sign_known_positive_or_negzero_or_nan
; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[KNOWN_POSITIVE_OR_NEG_ZERO:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[KNOWN_POSITIVE_OR_NEG_ZERO]])
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg nnan float [[FABS]]
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call float @llvm.fabs.f32(float %known.positive.or.neg.zero)
%fneg.fabs = fneg nnan float %fabs
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_fabs__known_positive__sign_known_positive_or_negzero_or_nan(float nofpclass(nan ninf nsub nnorm) %known.positive.or.neg.zero) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs__known_positive__sign_known_positive_or_negzero_or_nan
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[KNOWN_POSITIVE_OR_NEG_ZERO:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[KNOWN_POSITIVE_OR_NEG_ZERO]])
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call float @llvm.fabs.f32(float %known.positive.or.neg.zero)
%fneg.fabs = fneg float %fabs
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_nsz_fabs__known_positive__sign_known_positive_or_negzero_or_nan(float nofpclass(nan ninf nsub nnorm) %known.positive.or.neg.zero) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_nsz_fabs__known_positive__sign_known_positive_or_negzero_or_nan
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[KNOWN_POSITIVE_OR_NEG_ZERO:%.*]]) {
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg nsz float [[KNOWN_POSITIVE_OR_NEG_ZERO]]
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call float @llvm.fabs.f32(float %known.positive.or.neg.zero)
%fneg.fabs = fneg nsz float %fabs
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_nsz_fabs__known_positive__sign_known_positive_or_negzero_or_nan_multiple_use_fabs(float nofpclass(nan ninf nsub nnorm) %known.positive.or.neg.zero, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_nsz_fabs__known_positive__sign_known_positive_or_negzero_or_nan_multiple_use_fabs
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[KNOWN_POSITIVE_OR_NEG_ZERO:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[KNOWN_POSITIVE_OR_NEG_ZERO]])
; CHECK-NEXT: store float [[FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg nsz float [[FABS]]
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call float @llvm.fabs.f32(float %known.positive.or.neg.zero)
store float %fabs, ptr %ptr
%fneg.fabs = fneg nsz float %fabs
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_nsz_fabs_nsz__known_positive__sign_known_positive_or_negzero_or_nan_multiple_use_fabs(float nofpclass(nan ninf nsub nnorm) %known.positive.or.neg.zero, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_nsz_fabs_nsz__known_positive__sign_known_positive_or_negzero_or_nan_multiple_use_fabs
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[KNOWN_POSITIVE_OR_NEG_ZERO:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: store float [[KNOWN_POSITIVE_OR_NEG_ZERO]], ptr [[PTR]], align 4
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg nsz float [[KNOWN_POSITIVE_OR_NEG_ZERO]]
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call nsz float @llvm.fabs.f32(float %known.positive.or.neg.zero)
store float %fabs, ptr %ptr
%fneg.fabs = fneg nsz float %fabs
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_nsz_fabs_nsz__known_positive__sign_known_positive_or_negzero_or_nan_multiple_use_fneg(float nofpclass(nan ninf nsub nnorm) %known.positive.or.neg.zero, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_nsz_fabs_nsz__known_positive__sign_known_positive_or_negzero_or_nan_multiple_use_fneg
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[KNOWN_POSITIVE_OR_NEG_ZERO:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg nsz float [[KNOWN_POSITIVE_OR_NEG_ZERO]]
; CHECK-NEXT: store float [[FNEG_FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%fabs = call nsz float @llvm.fabs.f32(float %known.positive.or.neg.zero)
%fneg.fabs = fneg nsz float %fabs
store float %fneg.fabs, ptr %ptr
ret float %fneg.fabs
}
define nofpclass(snan) float @fneg_fabs_nsz__known_positive__sign_known_positive_or_negzero_or_nan(float nofpclass(nan ninf nsub nnorm) %known.positive.or.neg.zero) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_nsz__known_positive__sign_known_positive_or_negzero_or_nan
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[KNOWN_POSITIVE_OR_NEG_ZERO:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[KNOWN_POSITIVE_OR_NEG_ZERO]]
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%fabs = call nsz float @llvm.fabs.f32(float %known.positive.or.neg.zero)
%copysign = fneg float %fabs
ret float %copysign
}
define nofpclass(snan) float @fneg_fabs_nsz__known_positive__sign_known_positive_or_negzero_or_nan__multi_use_fabs(float nofpclass(nan ninf nsub nnorm) %known.positive.or.neg.zero, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_nsz__known_positive__sign_known_positive_or_negzero_or_nan__multi_use_fabs
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[KNOWN_POSITIVE_OR_NEG_ZERO:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: store float [[KNOWN_POSITIVE_OR_NEG_ZERO]], ptr [[PTR]], align 4
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[KNOWN_POSITIVE_OR_NEG_ZERO]]
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%fabs = call nsz float @llvm.fabs.f32(float %known.positive.or.neg.zero)
store float %fabs, ptr %ptr
%copysign = fneg float %fabs
ret float %copysign
}
define nofpclass(snan) float @fneg_fabs_nnan__known_positive__sign_known_negative_or_nan_multi_use_fabs(float nofpclass(ninf nzero nsub nnorm) %known.positive, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_nnan__known_positive__sign_known_negative_or_nan_multi_use_fabs
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[KNOWN_POSITIVE:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call nnan float @llvm.fabs.f32(float [[KNOWN_POSITIVE]])
; CHECK-NEXT: store float [[FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg nnan float [[KNOWN_POSITIVE]]
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%fabs = call nnan float @llvm.fabs.f32(float %known.positive)
store float %fabs, ptr %ptr
%copysign = fneg nnan float %fabs
ret float %copysign
}
; Known fabs source is positive due to ninf flag
define nofpclass(nan) float @no_nan__fneg_ninf_fabs__known_positive_or_ninf__sign_known_negative_or_nan(float nofpclass(nzero nsub nnorm) %known.positive.or.ninf) {
; CHECK-LABEL: define nofpclass(nan) float @no_nan__fneg_ninf_fabs__known_positive_or_ninf__sign_known_negative_or_nan
; CHECK-SAME: (float nofpclass(nzero nsub nnorm) [[KNOWN_POSITIVE_OR_NINF:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg ninf float [[KNOWN_POSITIVE_OR_NINF]]
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%fabs = call float @llvm.fabs.f32(float %known.positive.or.ninf)
%copysign = fneg ninf float %fabs
ret float %copysign
}
; Known fabs source is positive due to ninf flag
define nofpclass(nan) float @no_nan__fneg_fabs_ninf__known_positive_or_ninf__sign_known_negative_or_nan(float nofpclass(nzero nsub nnorm) %known.positive.or.ninf) {
; CHECK-LABEL: define nofpclass(nan) float @no_nan__fneg_fabs_ninf__known_positive_or_ninf__sign_known_negative_or_nan
; CHECK-SAME: (float nofpclass(nzero nsub nnorm) [[KNOWN_POSITIVE_OR_NINF:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[KNOWN_POSITIVE_OR_NINF]]
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%fabs = call ninf float @llvm.fabs.f32(float %known.positive.or.ninf)
%copysign = fneg float %fabs
ret float %copysign
}
; Can't tell fabs source is positive with no-pinf return
define nofpclass(nan pinf) float @no_nan_nopinf__fneg_ninf_fabs__known_positive_or_ninf__sign_known_negative_or_nan(float nofpclass(nzero nsub nnorm) %known.positive.or.ninf) {
; CHECK-LABEL: define nofpclass(nan pinf) float @no_nan_nopinf__fneg_ninf_fabs__known_positive_or_ninf__sign_known_negative_or_nan
; CHECK-SAME: (float nofpclass(nzero nsub nnorm) [[KNOWN_POSITIVE_OR_NINF:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[KNOWN_POSITIVE_OR_NINF]])
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%fabs = call float @llvm.fabs.f32(float %known.positive.or.ninf)
%copysign = fneg float %fabs
ret float %copysign
}
; Can't tell fabs source is positive with ninf return
define nofpclass(nan ninf) float @no_nan_noninf__fneg_ninf_fabs__known_positive_or_ninf__sign_known_negative_or_nan(float nofpclass(nzero nsub nnorm) %known.positive.or.ninf) {
; CHECK-LABEL: define nofpclass(nan ninf) float @no_nan_noninf__fneg_ninf_fabs__known_positive_or_ninf__sign_known_negative_or_nan
; CHECK-SAME: (float nofpclass(nzero nsub nnorm) [[KNOWN_POSITIVE_OR_NINF:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[KNOWN_POSITIVE_OR_NINF]])
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%fabs = call float @llvm.fabs.f32(float %known.positive.or.ninf)
%copysign = fneg float %fabs
ret float %copysign
}
; Can tell fabs source is positive with no inf return
define nofpclass(nan inf) float @no_nan_noinf__fneg_ninf_fabs__known_positive_or_ninf__sign_known_negative_or_nan(float nofpclass(nzero nsub nnorm) %known.positive.or.ninf) {
; CHECK-LABEL: define nofpclass(nan inf) float @no_nan_noinf__fneg_ninf_fabs__known_positive_or_ninf__sign_known_negative_or_nan
; CHECK-SAME: (float nofpclass(nzero nsub nnorm) [[KNOWN_POSITIVE_OR_NINF:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[KNOWN_POSITIVE_OR_NINF]]
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%fabs = call float @llvm.fabs.f32(float %known.positive.or.ninf)
%copysign = fneg float %fabs
ret float %copysign
}
define nofpclass(nan) float @fneg_fabs_multiple_uses_fabs(i1 %cond, float %x, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan) float @fneg_fabs_multiple_uses_fabs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[NAN:%.*]] = call float @nan_only()
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND]], float [[X]], float [[NAN]]
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SEL]])
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: store float [[FABS]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[FNEG_FABS]]
;
%nan = call float @nan_only()
%sel = select i1 %cond, float %x, float %nan
%fabs = call float @llvm.fabs.f32(float %sel)
%fneg.fabs = fneg float %fabs
store float %fabs, ptr %ptr ; external user on fabs
ret float %fneg.fabs
}
; 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't 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: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
; 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(pnorm psub pzero) float @ret_nofpclass_nopositive_finites_copysign_nnan_ninf_flag(float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(pzero psub pnorm) float @ret_nofpclass_nopositive_finites_copysign_nnan_ninf_flag
; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call nnan ninf float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg nnan ninf float [[TMP1]]
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call nnan ninf float @llvm.copysign.f32(float %x, float %unknown.sign)
ret float %copysign
}
; can't 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't 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.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
; 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.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
}
; 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: [[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
}
; 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: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[SELECT]], 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
}
; 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: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[SELECT]], 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
}
; 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
}
define nofpclass(snan) float @copysign_nnan_sign_known_positive_or_nan(float %x, float nofpclass(ninf nnorm nsub nzero) %always.positive.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @copysign_nnan_sign_known_positive_or_nan
; CHECK-SAME: (float [[X:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ALWAYS_POSITIVE_OR_NAN:%.*]]) {
; 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 %always.positive.or.nan)
ret float %copysign
}
define nofpclass(snan) float @copysign_nnan_sign_known_positive_or_nan__drop_ub_attrs(float %x, float nofpclass(ninf nnorm nsub nzero) %always.positive.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @copysign_nnan_sign_known_positive_or_nan__drop_ub_attrs
; CHECK-SAME: (float [[X:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ALWAYS_POSITIVE_OR_NAN:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call nnan float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call nnan noundef float @llvm.copysign.f32(float %x, float noundef nofpclass(zero) %always.positive.or.nan)
ret float %copysign
}
define nofpclass(snan) float @copysign_nnan_sign_known_negative_or_nan(float %x, float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @copysign_nnan_sign_known_negative_or_nan
; CHECK-SAME: (float [[X:%.*]], float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]]) {
; 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 %always.negative.or.nan)
ret float %copysign
}
define nofpclass(snan) float @copysign_nnan_sign_known_negative_or_nan__drop_ub_attrs(float %x, float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @copysign_nnan_sign_known_negative_or_nan__drop_ub_attrs
; CHECK-SAME: (float [[X:%.*]], float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]]) {
; 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 noundef float @llvm.copysign.f32(float %x, float noundef nofpclass(zero) %always.negative.or.nan)
ret float %copysign
}
; Fold out copysign
define nofpclass(snan) float @copysign_nnan__known_positive__sign_known_positive_or_nan(float nofpclass(ninf nnorm nsub nzero) %known.positive, float nofpclass(ninf nnorm nsub nzero) %always.positive.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @copysign_nnan__known_positive__sign_known_positive_or_nan
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[KNOWN_POSITIVE:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ALWAYS_POSITIVE_OR_NAN:%.*]]) {
; CHECK-NEXT: ret float [[KNOWN_POSITIVE]]
;
%copysign = call nnan float @llvm.copysign.f32(float %known.positive, float %always.positive.or.nan)
ret float %copysign
}
; Fold out copysign
define nofpclass(snan) float @copysign_nnan__known_negative__sign_known_negative_or_nan(float nofpclass(pinf pnorm psub pzero) %known.negative, float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @copysign_nnan__known_negative__sign_known_negative_or_nan
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[KNOWN_NEGATIVE:%.*]], float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]]) {
; CHECK-NEXT: ret float [[KNOWN_NEGATIVE]]
;
%copysign = call nnan float @llvm.copysign.f32(float %known.negative, float %always.negative.or.nan)
ret float %copysign
}
; Convert to fabs
define nofpclass(snan) float @copysign_nnan__known_negative__sign_known_positive_or_nan(float nofpclass(pinf pnorm psub pzero) %known.negative, float nofpclass(ninf nnorm nsub nzero) %always.positive.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @copysign_nnan__known_negative__sign_known_positive_or_nan
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[KNOWN_NEGATIVE:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ALWAYS_POSITIVE_OR_NAN:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call nnan float @llvm.fabs.f32(float [[KNOWN_NEGATIVE]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call nnan float @llvm.copysign.f32(float %known.negative, float %always.positive.or.nan)
ret float %copysign
}
; Convert to fneg(fabs)
define nofpclass(snan) float @copysign_nnan__known_positive__sign_known_negative_or_nan(float nofpclass(ninf nnorm nsub nzero) %known.positive, float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @copysign_nnan__known_positive__sign_known_negative_or_nan
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[KNOWN_POSITIVE:%.*]], float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg nnan float [[KNOWN_POSITIVE]]
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call nnan float @llvm.copysign.f32(float %known.positive, float %always.negative.or.nan)
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 noundef %x) {
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_nofpclass_nan_negatives__select_clamp_pos_to_zero
; CHECK-SAME: (float noundef [[X:%.*]]) {
; CHECK-NEXT: ret float 0.000000e+00
;
%is.gt.zero = fcmp ogt float %x, 0.0
%select = select i1 %is.gt.zero, float 0.0, float %x
ret float %select
}
; Cannot fold due to undef
define nofpclass(nan ninf nnorm nsub nzero) float @ret_nofpclass_nan_negatives__select_clamp_pos_to_zero__maybe_undef(float %x) {
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_nofpclass_nan_negatives__select_clamp_pos_to_zero__maybe_undef
; 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 nnan float @llvm.log2.f32(float [[I]])
; CHECK-NEXT: [[I2:%.*]] = fmul nnan float [[I1]], [[Y]]
; CHECK-NEXT: [[I3:%.*]] = tail call nnan 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: [[I3:%.*]] = tail call nnan float @llvm.log2.f32(float [[ARG]])
; CHECK-NEXT: [[I5:%.*]] = fmul nnan float [[ARG1]], [[I3]]
; CHECK-NEXT: [[I6:%.*]] = tail call nnan nofpclass(ninf nzero nsub nnorm) float @llvm.exp2.f32(float [[I5]])
; CHECK-NEXT: [[TMP0:%.*]] = fcmp oeq float [[ARG]], 0.000000e+00
; CHECK-NEXT: [[I12:%.*]] = select i1 [[TMP0]], 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 nnan float @llvm.log2.f32(float [[I]])
; CHECK-NEXT: [[I3:%.*]] = fmul nnan float [[I2]], [[ARG1]]
; CHECK-NEXT: [[I4:%.*]] = tail call nnan float @llvm.exp2.f32(float [[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 nnan 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: ret float [[Y]]
;
%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
}
define nofpclass(snan) float @arithmetic_fence__noinf_callsite_param_attr_select_pinf_rhs(i1 %cond, float %x) {
; CHECK-LABEL: define nofpclass(snan) float @arithmetic_fence__noinf_callsite_param_attr_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
; CHECK-NEXT: [[FENCE:%.*]] = call float @llvm.arithmetic.fence.f32(float nofpclass(inf) [[X]])
; CHECK-NEXT: ret float [[FENCE]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
%fence = call float @llvm.arithmetic.fence.f32(float nofpclass(inf) %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 nsz 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.minimumnum.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 nsz 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.maximumnum.f32(float %x, float 0x7FF0000000000000)
ret float %max
}
declare nofpclass(inf norm sub zero) float @returns_nan()
; %nan has multiple uses, but we should still know what class is is
; %allowing this to fold to a single select.
define nofpclass(nan) float @known_class_multiple_uses(i1 %cond0, i1 %cond1, i1 %cond2, float %unknown0, float %unknown1) {
; CHECK-LABEL: define nofpclass(nan) float @known_class_multiple_uses
; CHECK-SAME: (i1 [[COND0:%.*]], i1 [[COND1:%.*]], i1 [[COND2:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) {
; CHECK-NEXT: [[NAN:%.*]] = call float @returns_nan()
; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[COND2]], float [[UNKNOWN0]], float [[UNKNOWN1]]
; CHECK-NEXT: ret float [[SELECT2]]
;
%nan = call float @returns_nan()
%select0 = select i1 %cond0, float %unknown0, float %nan
%select1 = select i1 %cond1, float %nan, float %unknown1
%select2 = select i1 %cond2, float %select0, float %select1
ret float %select2
}
; Do not overdefine the poison element to inf.
define nofpclass(ninf) <2 x float> @single_class_constant_partially_poison_pinf() {
; CHECK-LABEL: define nofpclass(ninf) <2 x float> @single_class_constant_partially_poison_pinf() {
; CHECK-NEXT: ret <2 x float> <float 0x7FF0000000000000, float poison>
;
ret <2 x float> <float 0x7FF0000000000000, float poison>
}
define nofpclass(ninf) <2 x float> @single_class_constant_partially_undef_pinf() {
; CHECK-LABEL: define nofpclass(ninf) <2 x float> @single_class_constant_partially_undef_pinf() {
; CHECK-NEXT: ret <2 x float> <float 0x7FF0000000000000, float undef>
;
ret <2 x float> <float 0x7FF0000000000000, float undef>
}
define nofpclass(zero) <3 x float> @mixed_sign_zero_splat_to_poison() {
; CHECK-LABEL: define nofpclass(zero) <3 x float> @mixed_sign_zero_splat_to_poison() {
; CHECK-NEXT: ret <3 x float> poison
;
ret <3 x float> <float 0.0, float -0.0, float poison>
}
define nofpclass(zero) <3 x float> @partially_defined_0_splat_to_poison() {
; CHECK-LABEL: define nofpclass(zero) <3 x float> @partially_defined_0_splat_to_poison() {
; CHECK-NEXT: ret <3 x float> poison
;
ret <3 x float> <float 0.0, float 0.0, float poison>
}
; The select must be 0, so the exp should fold to 1. This requires
; analysis of the select condition.
define nofpclass(nan) float @exp_select_must_be_0(float noundef %arg, float nofpclass(inf sub norm) %zero.or.nan) {
; CHECK-LABEL: define nofpclass(nan) float @exp_select_must_be_0
; CHECK-SAME: (float noundef [[ARG:%.*]], float nofpclass(inf sub norm) [[ZERO_OR_NAN:%.*]]) {
; CHECK-NEXT: ret float 1.000000e+00
;
%not.zero = fcmp one float %arg, 0.0
%select = select i1 %not.zero, float %zero.or.nan, float %arg
%exp = call float @llvm.exp.f32(float %select)
ret float %exp
}
; The select must be 0, so the exp should fold to 1. This requires
; analysis of the select condition.
define nofpclass(nan) float @exp_select_must_be_0_commute(float noundef %arg, float nofpclass(inf sub norm) %zero.or.nan) {
; CHECK-LABEL: define nofpclass(nan) float @exp_select_must_be_0_commute
; CHECK-SAME: (float noundef [[ARG:%.*]], float nofpclass(inf sub norm) [[ZERO_OR_NAN:%.*]]) {
; CHECK-NEXT: ret float 1.000000e+00
;
%is.zero = fcmp oeq float %arg, 0.0
%select = select i1 %is.zero, float %arg, float %zero.or.nan
%exp = call float @llvm.exp.f32(float %select)
ret float %exp
}
; Select has multiple uses, with the same user
define nofpclass(nan) float @ret_nonan_fmul_select_fmul_select_nan_multiple_use(i1 %cond, float noundef %x) {
; CHECK-LABEL: define nofpclass(nan) float @ret_nonan_fmul_select_fmul_select_nan_multiple_use
; CHECK-SAME: (i1 [[COND:%.*]], float noundef [[X:%.*]]) {
; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[X]], [[X]]
; CHECK-NEXT: ret float [[FMUL]]
;
%select = select i1 %cond, float %x, float 0x7FF8000000000000
%fmul = fmul float %select, %select
ret float %fmul
}
define nofpclass(nan) float @ret_nonan_fmul_select_fmul_select_nan_multiple_use_commute(i1 %cond, float noundef %x) {
; CHECK-LABEL: define nofpclass(nan) float @ret_nonan_fmul_select_fmul_select_nan_multiple_use_commute
; CHECK-SAME: (i1 [[COND:%.*]], float noundef [[X:%.*]]) {
; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[X]], [[X]]
; CHECK-NEXT: ret float [[FMUL]]
;
%select = select i1 %cond, float 0x7FF8000000000000, float %x
%fmul = fmul float %select, %select
ret float %fmul
}
; Select has a second, unrelated use
define nofpclass(nan) float @ret_nonan_fmul_select_nan_other_use(i1 %cond, float noundef %x, float %y, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan) float @ret_nonan_fmul_select_nan_other_use
; CHECK-SAME: (i1 [[COND:%.*]], float noundef [[X:%.*]], float [[Y:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF8000000000000
; CHECK-NEXT: store float [[SELECT]], ptr [[PTR]], align 4
; CHECK-NEXT: [[NAN_USER:%.*]] = fmul nnan float [[X]], [[Y]]
; CHECK-NEXT: ret float [[NAN_USER]]
;
%select = select i1 %cond, float %x, float 0x7FF8000000000000
store float %select, ptr %ptr
%nan.user = fmul float %select, %y
ret float %nan.user
}
define nofpclass(nan) float @ret_nonan_fmul_select_nan_other_use_commute(i1 %cond, float noundef %x, float %y, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan) float @ret_nonan_fmul_select_nan_other_use_commute
; CHECK-SAME: (i1 [[COND:%.*]], float noundef [[X:%.*]], float [[Y:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float 0x7FF8000000000000, float [[X]]
; CHECK-NEXT: store float [[SELECT]], ptr [[PTR]], align 4
; CHECK-NEXT: [[NAN_USER:%.*]] = fmul nnan float [[X]], [[Y]]
; CHECK-NEXT: ret float [[NAN_USER]]
;
%select = select i1 %cond, float 0x7FF8000000000000, float %x
store float %select, ptr %ptr
%nan.user = fmul float %select, %y
ret float %nan.user
}
define nofpclass(snan) float @copysign_src_known_positive__sign_known_negative_multiple_use(float nofpclass(nan ninf nnorm nsub nzero) %always.positive, float nofpclass(nan pinf pnorm psub pzero) %always.negative, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @copysign_src_known_positive__sign_known_negative_multiple_use
; CHECK-SAME: (float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]], float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[ALWAYS_POSITIVE]]
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.positive, float %always.negative)
store float %copysign, ptr %ptr
ret float %copysign
}
define nofpclass(snan) float @copysign_src_known_negative__sign_known_negative_multiple_use(float nofpclass(nan pinf pnorm psub pzero) %always.negative0, float nofpclass(nan pinf pnorm psub pzero) %always.negative1, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @copysign_src_known_negative__sign_known_negative_multiple_use
; CHECK-SAME: (float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE0:%.*]], float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE1:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE0]])
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE0]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative0, float %always.negative1)
store float %copysign, ptr %ptr
ret float %copysign
}
define nofpclass(snan) float @copysign_src_known_positive__sign_known_positive_multiple_use(float nofpclass(nan ninf nnorm nsub nzero) %always.positive0, float nofpclass(nan ninf nnorm nsub nzero) %always.positive1, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @copysign_src_known_positive__sign_known_positive_multiple_use
; CHECK-SAME: (float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE0:%.*]], float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE1:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: store float [[ALWAYS_POSITIVE0]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE0]]
;
%copysign = call float @llvm.copysign.f32(float %always.positive0, float %always.positive1)
store float %copysign, ptr %ptr
ret float %copysign
}
define nofpclass(nan) float @ret_nonan__copysign_src_known_negative_or_nan__sign_known_negative_multiple_use(float nofpclass(pinf pnorm psub pzero) %always.negative0.or.nan, float nofpclass(nan pinf pnorm psub pzero) %always.negative1, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan) float @ret_nonan__copysign_src_known_negative_or_nan__sign_known_negative_multiple_use
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE0_OR_NAN:%.*]], float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE1:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE0_OR_NAN]])
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE0_OR_NAN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative0.or.nan, float %always.negative1)
store float %copysign, ptr %ptr
ret float %copysign
}
define nofpclass(nan ninf nnorm nsub nzero) float @ret_only_positive__copysign__sign_known_negative_multiple_use(float %unknown, float nofpclass(nan pinf pnorm psub pzero) %always.negative, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_only_positive__copysign__sign_known_negative_multiple_use
; CHECK-SAME: (float [[UNKNOWN:%.*]], float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[UNKNOWN]])
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float poison
;
%copysign = call float @llvm.copysign.f32(float %unknown, float %always.negative)
store float %copysign, ptr %ptr
ret float %copysign
}
define nofpclass(nan ninf nnorm nsub nzero) float @ret_only_positive__copysign__sign_known_positive_multiple_use(float %unknown, float nofpclass(nan ninf nnorm nsub nzero) %always.positive, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_only_positive__copysign__sign_known_positive_multiple_use
; CHECK-SAME: (float [[UNKNOWN:%.*]], float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[UNKNOWN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %unknown, float %always.positive)
store float %copysign, ptr %ptr
ret float %copysign
}
define nofpclass(nan pinf pnorm psub pzero) float @ret_only_negative__copysign__sign_known_negative_multiple_use(float %unknown, float nofpclass(nan pinf pnorm psub pzero) %always.negative, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_only_negative__copysign__sign_known_negative_multiple_use
; CHECK-SAME: (float [[UNKNOWN:%.*]], float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[UNKNOWN]])
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %unknown, float %always.negative)
store float %copysign, ptr %ptr
ret float %copysign
}
define nofpclass(nan pinf pnorm psub pzero) float @ret_only_negative__copysign__sign_known_positive_multiple_use(float %unknown, float nofpclass(nan ninf nnorm nsub nzero) %always.positive, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_only_negative__copysign__sign_known_positive_multiple_use
; CHECK-SAME: (float [[UNKNOWN:%.*]], float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[UNKNOWN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float poison
;
%copysign = call float @llvm.copysign.f32(float %unknown, float %always.positive)
store float %copysign, ptr %ptr
ret float %copysign
}
define nofpclass(nan ninf nnorm nsub nzero) float @ret_only_positive__copysign_multiple_use(float %unknown.mag, float %unknown.sign, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_only_positive__copysign_multiple_use
; CHECK-SAME: (float [[UNKNOWN_MAG:%.*]], float [[UNKNOWN_SIGN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[UNKNOWN_MAG]], float [[UNKNOWN_SIGN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %unknown.mag, float %unknown.sign)
store float %copysign, ptr %ptr
ret float %copysign
}
define nofpclass(nan pinf pnorm psub pzero) float @ret_only_negative__copysign_multiple_use(float %unknown.mag, float %unknown.sign, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_only_negative__copysign_multiple_use
; CHECK-SAME: (float [[UNKNOWN_MAG:%.*]], float [[UNKNOWN_SIGN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[UNKNOWN_MAG]], float [[UNKNOWN_SIGN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %unknown.mag, float %unknown.sign)
store float %copysign, ptr %ptr
ret float %copysign
}
; Fold to direct use of %always.positive
define nofpclass(nan ninf nnorm nsub nzero) float @ret_only_positive__copysign_src_known_positive__sign_unknown(float nofpclass(nan ninf nnorm nsub nzero) %always.positive, float %unknown) {
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_only_positive__copysign_src_known_positive__sign_unknown
; CHECK-SAME: (float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE]]
;
%copysign = call float @llvm.copysign.f32(float %always.positive, float %unknown)
ret float %copysign
}
; Fold to direct use of %always.positive
define nofpclass(nan ninf nnorm nsub nzero) float @ret_only_positive__copysign_src_known_positive__sign_unknown_multiple_use(float nofpclass(nan ninf nnorm nsub nzero) %always.positive, float %unknown, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_only_positive__copysign_src_known_positive__sign_unknown_multiple_use
; CHECK-SAME: (float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[ALWAYS_POSITIVE]], float [[UNKNOWN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE]]
;
%copysign = call float @llvm.copysign.f32(float %always.positive, float %unknown)
store float %copysign, ptr %ptr
ret float %copysign
}
; Fold to direct use of %always.negative
define nofpclass(nan pinf pnorm psub pzero) float @ret_only_negative__copysign_src_known_negative__sign_unknown(float nofpclass(nan pinf pnorm psub pzero) %always.negative, float %unknown) {
; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_only_negative__copysign_src_known_negative__sign_unknown
; CHECK-SAME: (float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative, float %unknown)
ret float %copysign
}
; Fold to direct use of %always.negative
define nofpclass(nan pinf pnorm psub pzero) float @ret_only_negative__copysign_src_known_negative__sign_unknown_multiple_use(float nofpclass(nan pinf pnorm psub pzero) %always.negative, float %unknown, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_only_negative__copysign_src_known_negative__sign_unknown_multiple_use
; CHECK-SAME: (float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[ALWAYS_NEGATIVE]], float [[UNKNOWN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative, float %unknown)
store float %copysign, ptr %ptr
ret float %copysign
}
; Negative test
define nofpclass(nan ninf nnorm nsub nzero) float @ret_only_positive__copysign_src_known_negative__sign_unknown(float nofpclass(nan pinf pnorm psub pzero) %always.negative, float %unknown) {
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_only_positive__copysign_src_known_negative__sign_unknown
; CHECK-SAME: (float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative, float %unknown)
ret float %copysign
}
; Negative test
define nofpclass(nan ninf nnorm nsub nzero) float @ret_only_positive__copysign_src_known_negative__sign_unknown_multiple_use(float nofpclass(nan pinf pnorm psub pzero) %always.negative, float %unknown, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_only_positive__copysign_src_known_negative__sign_unknown_multiple_use
; CHECK-SAME: (float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[ALWAYS_NEGATIVE]], float [[UNKNOWN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative, float %unknown)
store float %copysign, ptr %ptr
ret float %copysign
}
; Negative test
define nofpclass(nan pinf pnorm psub pzero) float @ret_only_negative__copysign_src_known_positive__sign_unknown(float nofpclass(nan ninf nnorm nsub nzero) %always.positive, float %unknown) {
; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_only_negative__copysign_src_known_positive__sign_unknown
; CHECK-SAME: (float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[ALWAYS_POSITIVE]]
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.positive, float %unknown)
ret float %copysign
}
; Could still be positive for +inf input
define nofpclass(nan nnorm nsub nzero) float @ret_only_positive_or_ninf__copysign_src_known_positive__sign_unknown(float nofpclass(nan ninf nnorm nsub nzero) %always.positive, float %unknown) {
; CHECK-LABEL: define nofpclass(nan nzero nsub nnorm) float @ret_only_positive_or_ninf__copysign_src_known_positive__sign_unknown
; CHECK-SAME: (float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[ALWAYS_POSITIVE]], float [[UNKNOWN]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.positive, float %unknown)
ret float %copysign
}
; The ninf flag gives the missing no-infs
define nofpclass(nan nnorm nsub nzero) float @ret_only_positive_or_ninf__copysign_ninf_src_known_positive__sign_unknown(float nofpclass(nan ninf nnorm nsub nzero) %always.positive, float %unknown) {
; CHECK-LABEL: define nofpclass(nan nzero nsub nnorm) float @ret_only_positive_or_ninf__copysign_ninf_src_known_positive__sign_unknown
; CHECK-SAME: (float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE]]
;
%copysign = call ninf float @llvm.copysign.f32(float %always.positive, float %unknown)
ret float %copysign
}
; The ninf flag gives the missing no-infs
define nofpclass(nan nnorm nsub nzero) float @ret_only_positive_or_ninf__copysign_ninf_src_known_positive__sign_unknown_multiple_use(float nofpclass(nan ninf nnorm nsub nzero) %always.positive, float %unknown, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan nzero nsub nnorm) float @ret_only_positive_or_ninf__copysign_ninf_src_known_positive__sign_unknown_multiple_use
; CHECK-SAME: (float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call ninf float @llvm.copysign.f32(float [[ALWAYS_POSITIVE]], float [[UNKNOWN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE]]
;
%copysign = call ninf float @llvm.copysign.f32(float %always.positive, float %unknown)
store float %copysign, ptr %ptr
ret float %copysign
}
; No pinf from argument
define nofpclass(nan nnorm nsub nzero) float @ret_only_positive_or_ninf__copysign_src_known_positive_no_inf__sign_unknown(float nofpclass(nan inf nnorm nsub nzero) %always.positive.no.inf, float %unknown) {
; CHECK-LABEL: define nofpclass(nan nzero nsub nnorm) float @ret_only_positive_or_ninf__copysign_src_known_positive_no_inf__sign_unknown
; CHECK-SAME: (float nofpclass(nan inf nzero nsub nnorm) [[ALWAYS_POSITIVE_NO_INF:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[ALWAYS_POSITIVE_NO_INF]], float [[UNKNOWN]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.positive.no.inf, float %unknown)
ret float %copysign
}
; No pinf from argument
define nofpclass(nan nnorm nsub nzero) float @ret_only_positive_or_ninf__copysign_src_known_positive_no_inf__sign_unknown_multiple_use(float nofpclass(nan inf nnorm nsub nzero) %always.positive.no.inf, float %unknown, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan nzero nsub nnorm) float @ret_only_positive_or_ninf__copysign_src_known_positive_no_inf__sign_unknown_multiple_use
; CHECK-SAME: (float nofpclass(nan inf nzero nsub nnorm) [[ALWAYS_POSITIVE_NO_INF:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[ALWAYS_POSITIVE_NO_INF]], float [[UNKNOWN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.positive.no.inf, float %unknown)
store float %copysign, ptr %ptr
ret float %copysign
}
define nofpclass(nan ninf nnorm nsub) float @ret_only_positive_or_zero__copysign_src_known_positive__sign_unknown(float nofpclass(nan ninf nnorm nsub) %always.positive.or.zero, float %unknown) {
; CHECK-LABEL: define nofpclass(nan ninf nsub nnorm) float @ret_only_positive_or_zero__copysign_src_known_positive__sign_unknown
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[ALWAYS_POSITIVE_OR_ZERO:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[ALWAYS_POSITIVE_OR_ZERO]], float [[UNKNOWN]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.positive.or.zero, float %unknown)
ret float %copysign
}
; Ignore 0 mismatch with nsz
define nofpclass(nan ninf nnorm nsub) float @ret_only_positive_or_zero__copysign_nsz_src_known_positive__sign_unknown(float nofpclass(nan ninf nnorm nsub) %always.positive.or.zero, float %unknown) {
; CHECK-LABEL: define nofpclass(nan ninf nsub nnorm) float @ret_only_positive_or_zero__copysign_nsz_src_known_positive__sign_unknown
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[ALWAYS_POSITIVE_OR_ZERO:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE_OR_ZERO]]
;
%copysign = call nsz float @llvm.copysign.f32(float %always.positive.or.zero, float %unknown)
ret float %copysign
}
; Do not use nsz with multiple uses
define nofpclass(nan ninf nnorm nsub) float @ret_only_positive_or_zero__copysign_nsz_src_known_positive__sign_unknown_multiple_use(float nofpclass(nan ninf nnorm nsub) %always.positive.or.zero, float %unknown, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan ninf nsub nnorm) float @ret_only_positive_or_zero__copysign_nsz_src_known_positive__sign_unknown_multiple_use
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[ALWAYS_POSITIVE_OR_ZERO:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call nsz float @llvm.copysign.f32(float [[ALWAYS_POSITIVE_OR_ZERO]], float [[UNKNOWN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call nsz float @llvm.copysign.f32(float %always.positive.or.zero, float %unknown)
store float %copysign, ptr %ptr
ret float %copysign
}
define nofpclass(nan pinf pnorm psub) float @ret_only_negative_or_pzero__copysign_src_known_negative__sign_unknown(float nofpclass(nan pinf pnorm psub) %always.negative.or.zero, float %unknown) {
; CHECK-LABEL: define nofpclass(nan pinf psub pnorm) float @ret_only_negative_or_pzero__copysign_src_known_negative__sign_unknown
; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ALWAYS_NEGATIVE_OR_ZERO:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[ALWAYS_NEGATIVE_OR_ZERO]], float [[UNKNOWN]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative.or.zero, float %unknown)
ret float %copysign
}
; Ignore 0 mismatch with nsz
define nofpclass(nan pinf pnorm psub) float @ret_only_negative_or_pzero__copysign_nsz_src_known_negative__sign_unknown(float nofpclass(nan pinf pnorm psub) %always.negative.or.zero, float %unknown) {
; CHECK-LABEL: define nofpclass(nan pinf psub pnorm) float @ret_only_negative_or_pzero__copysign_nsz_src_known_negative__sign_unknown
; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ALWAYS_NEGATIVE_OR_ZERO:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE_OR_ZERO]]
;
%copysign = call nsz float @llvm.copysign.f32(float %always.negative.or.zero, float %unknown)
ret float %copysign
}
; Do not use nsz with multiple uses
define nofpclass(nan pinf pnorm psub) float @ret_only_negative_or_pzero__copysign_nsz_src_known_negative__sign_unknown_multiple_use(float nofpclass(nan pinf pnorm psub) %always.negative.or.zero, float %unknown, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan pinf psub pnorm) float @ret_only_negative_or_pzero__copysign_nsz_src_known_negative__sign_unknown_multiple_use
; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ALWAYS_NEGATIVE_OR_ZERO:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call nsz float @llvm.copysign.f32(float [[ALWAYS_NEGATIVE_OR_ZERO]], float [[UNKNOWN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call nsz float @llvm.copysign.f32(float %always.negative.or.zero, float %unknown)
store float %copysign, ptr %ptr
ret float %copysign
}
define nofpclass(pinf pnorm psub pzero) float @ret_only_negative_or_nan__copysign_src_known_negative__sign_unknown(float nofpclass(nan pinf pnorm psub pzero) %always.negative, float %unknown) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_negative_or_nan__copysign_src_known_negative__sign_unknown
; CHECK-SAME: (float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[ALWAYS_NEGATIVE]], float [[UNKNOWN]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative, float %unknown)
ret float %copysign
}
define nofpclass(pinf pnorm psub pzero) float @ret_only_negative_or_nan__copysign_src_known_negative__sign_unknown_multiple_use(float nofpclass(nan pinf pnorm psub pzero) %always.negative, float %unknown, ptr %ptr) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_negative_or_nan__copysign_src_known_negative__sign_unknown_multiple_use
; CHECK-SAME: (float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[ALWAYS_NEGATIVE]], float [[UNKNOWN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative, float %unknown)
store float %copysign, ptr %ptr
ret float %copysign
}
define nofpclass(pinf pnorm psub pzero) float @ret_only_negative_or_nan__copysign_src_known_negative_or_nan__sign_unknown(float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan, float %unknown) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_negative_or_nan__copysign_src_known_negative_or_nan__sign_unknown
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[ALWAYS_NEGATIVE_OR_NAN]], float [[UNKNOWN]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative.or.nan, float %unknown)
ret float %copysign
}
define nofpclass(pinf pnorm psub pzero) float @ret_only_negative_or_nan__copysign_src_known_negative_or_nan__sign_unknown_multiple_use(float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan, float %unknown, ptr %ptr) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_negative_or_nan__copysign_src_known_negative_or_nan__sign_unknown_multiple_use
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[ALWAYS_NEGATIVE_OR_NAN]], float [[UNKNOWN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative.or.nan, float %unknown)
store float %copysign, ptr %ptr
ret float %copysign
}
; Take nnan from flag
define nofpclass(pinf pnorm psub pzero) float @ret_only_negative_or_nan__copysign_nnan_src_known_negative_or_nan__sign_unknown(float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan, float %unknown) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_negative_or_nan__copysign_nnan_src_known_negative_or_nan__sign_unknown
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE_OR_NAN]]
;
%copysign = call nnan float @llvm.copysign.f32(float %always.negative.or.nan, float %unknown)
ret float %copysign
}
; Take nnan from flag
define nofpclass(pinf pnorm psub pzero) float @ret_only_negative_or_nan__copysign_nnan_src_known_negative_or_nan__sign_unknown_multiple_use(float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan, float %unknown, ptr %ptr) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_negative_or_nan__copysign_nnan_src_known_negative_or_nan__sign_unknown_multiple_use
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call nnan float @llvm.copysign.f32(float [[ALWAYS_NEGATIVE_OR_NAN]], float [[UNKNOWN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE_OR_NAN]]
;
%copysign = call nnan float @llvm.copysign.f32(float %always.negative.or.nan, float %unknown)
store float %copysign, ptr %ptr
ret float %copysign
}
define nofpclass(pinf pnorm psub pzero) float @ret_only_positive_or_nan__copysign_src_known_positive__sign_unknown(float nofpclass(nan pinf pnorm psub pzero) %always.negative, float %unknown) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_positive_or_nan__copysign_src_known_positive__sign_unknown
; CHECK-SAME: (float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[ALWAYS_NEGATIVE]], float [[UNKNOWN]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative, float %unknown)
ret float %copysign
}
define nofpclass(pinf pnorm psub pzero) float @ret_only_positive_or_nan__copysign_src_known_positive__sign_unknown_multiple_use(float nofpclass(nan pinf pnorm psub pzero) %always.negative, float %unknown, ptr %ptr) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_positive_or_nan__copysign_src_known_positive__sign_unknown_multiple_use
; CHECK-SAME: (float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[ALWAYS_NEGATIVE]], float [[UNKNOWN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative, float %unknown)
store float %copysign, ptr %ptr
ret float %copysign
}
define nofpclass(pinf pnorm psub pzero) float @ret_only_positive_or_nan__copysign_src_known_positive_or_nan__sign_unknown(float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan, float %unknown) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_positive_or_nan__copysign_src_known_positive_or_nan__sign_unknown
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[ALWAYS_NEGATIVE_OR_NAN]], float [[UNKNOWN]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative.or.nan, float %unknown)
ret float %copysign
}
define nofpclass(pinf pnorm psub pzero) float @ret_only_positive_or_nan__copysign_src_known_positive_or_nan__sign_unknown_multiple_use(float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan, float %unknown, ptr %ptr) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_positive_or_nan__copysign_src_known_positive_or_nan__sign_unknown_multiple_use
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[ALWAYS_NEGATIVE_OR_NAN]], float [[UNKNOWN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative.or.nan, float %unknown)
store float %copysign, ptr %ptr
ret float %copysign
}
; Take nnan from flag
define nofpclass(pinf pnorm psub pzero) float @ret_only_positive_or_nan__copysign_nnan_src_known_positive_or_nan__sign_unknown(float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan, float %unknown) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_positive_or_nan__copysign_nnan_src_known_positive_or_nan__sign_unknown
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE_OR_NAN]]
;
%copysign = call nnan float @llvm.copysign.f32(float %always.negative.or.nan, float %unknown)
ret float %copysign
}
; Take nnan from flag
define nofpclass(pinf pnorm psub pzero) float @ret_only_positive_or_nan__copysign_nnan_src_known_positive_or_nan__sign_unknown_multiple_use(float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan, float %unknown, ptr %ptr) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_positive_or_nan__copysign_nnan_src_known_positive_or_nan__sign_unknown_multiple_use
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call nnan float @llvm.copysign.f32(float [[ALWAYS_NEGATIVE_OR_NAN]], float [[UNKNOWN]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE_OR_NAN]]
;
%copysign = call nnan float @llvm.copysign.f32(float %always.negative.or.nan, float %unknown)
store float %copysign, ptr %ptr
ret float %copysign
}
; We can only tell the sign bit is negative due to the ninf flag
define nofpclass(nan) float @ret_no_nan__copysign_ninf__src_known_negative_or_nan__sign_known_negative_or_pinf(float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan, float nofpclass(nan pnorm psub pzero) %always.negative.or.pinf) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__copysign_ninf__src_known_negative_or_nan__sign_known_negative_or_pinf
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]], float nofpclass(nan pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_PINF:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call ninf float @llvm.copysign.f32(float [[ALWAYS_NEGATIVE_OR_NAN]], float [[ALWAYS_NEGATIVE_OR_PINF]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call ninf float @llvm.copysign.f32(float %always.negative.or.nan, float %always.negative.or.pinf)
ret float %copysign
}
; We can only tell the sign bit is negative due to the ninf flag
define nofpclass(nan) float @ret_no_nan__copysign_ninf__src_known_negative_or_nan__sign_known_negative_or_pinf__multiple_use(float nofpclass(pinf pnorm psub pzero) %always.negative.or.nan, float nofpclass(nan pnorm psub pzero) %always.negative.or.pinf, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__copysign_ninf__src_known_negative_or_nan__sign_known_negative_or_pinf__multiple_use
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_NAN:%.*]], float nofpclass(nan pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_PINF:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call ninf float @llvm.copysign.f32(float [[ALWAYS_NEGATIVE_OR_NAN]], float [[ALWAYS_NEGATIVE_OR_PINF]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE_OR_NAN]]
;
%copysign = call ninf float @llvm.copysign.f32(float %always.negative.or.nan, float %always.negative.or.pinf)
store float %copysign, ptr %ptr
ret float %copysign
}
; We can only tell the sign bit is positive due to the ninf flag
define nofpclass(nan) float @ret_no_nan__copysign_ninf__src_known_negative_or_nan__sign_known_positive_or_ninf(float nofpclass(ninf nnorm nsub nzero) %always.positive.or.nan, float nofpclass(nan nnorm nsub nzero) %always.negative.or.pinf) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__copysign_ninf__src_known_negative_or_nan__sign_known_positive_or_ninf
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ALWAYS_POSITIVE_OR_NAN:%.*]], float nofpclass(nan nzero nsub nnorm) [[ALWAYS_NEGATIVE_OR_PINF:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call ninf float @llvm.copysign.f32(float [[ALWAYS_POSITIVE_OR_NAN]], float [[ALWAYS_NEGATIVE_OR_PINF]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call ninf float @llvm.copysign.f32(float %always.positive.or.nan, float %always.negative.or.pinf)
ret float %copysign
}
; We can only tell the sign bit is positive due to the ninf flag
define nofpclass(nan) float @ret_no_nan__copysign_ninf__src_known_negative_or_nan__sign_known_positive_or_ninf__multiple_use(float nofpclass(ninf nnorm nsub nzero) %always.positive.or.nan, float nofpclass(nan nnorm nsub nzero) %always.negative.or.pinf, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__copysign_ninf__src_known_negative_or_nan__sign_known_positive_or_ninf__multiple_use
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ALWAYS_POSITIVE_OR_NAN:%.*]], float nofpclass(nan nzero nsub nnorm) [[ALWAYS_NEGATIVE_OR_PINF:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call ninf float @llvm.copysign.f32(float [[ALWAYS_POSITIVE_OR_NAN]], float [[ALWAYS_NEGATIVE_OR_PINF]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE_OR_NAN]]
;
%copysign = call ninf float @llvm.copysign.f32(float %always.positive.or.nan, float %always.negative.or.pinf)
store float %copysign, ptr %ptr
ret float %copysign
}
; Can infer sign bit is negative due to no-inf return
define nofpclass(nan inf) float @ret_no_nan_no_inf__copysign__src_known_negative_or_nan__sign_known_negative_or_pinf__multiple_use(float nofpclass(nan pnorm psub pzero) %always.negative.or.pinf, float nofpclass(nan pinf pnorm psub pzero) %always.negative, float %unknown0, float %unknown1, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan inf) float @ret_no_nan_no_inf__copysign__src_known_negative_or_nan__sign_known_negative_or_pinf__multiple_use
; CHECK-SAME: (float nofpclass(nan pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_PINF:%.*]], float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_PINF]])
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE_OR_PINF]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative.or.pinf, float %always.negative)
store float %copysign, ptr %ptr
ret float %copysign
}
; No-pinf result not sufficient
define nofpclass(nan pinf) float @ret_no_nan_no_pinf__copysign__src_known_negative_or_nan__sign_known_negative_or_pinf__multiple_use(float nofpclass(nan pnorm psub pzero) %always.negative.or.pinf, float nofpclass(nan pinf pnorm psub pzero) %always.negative, float %unknown0, float %unknown1, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan pinf) float @ret_no_nan_no_pinf__copysign__src_known_negative_or_nan__sign_known_negative_or_pinf__multiple_use
; CHECK-SAME: (float nofpclass(nan pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_PINF:%.*]], float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_PINF]])
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative.or.pinf, float %always.negative)
store float %copysign, ptr %ptr
ret float %copysign
}
; No-ninf result not sufficient
define nofpclass(nan ninf) float @ret_no_nan_no_ninf__copysign__src_known_negative_or_nan__sign_known_negative_or_pinf__multiple_use(float nofpclass(nan pnorm psub pzero) %always.negative.or.pinf, float nofpclass(nan pinf pnorm psub pzero) %always.negative, float %unknown0, float %unknown1, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan ninf) float @ret_no_nan_no_ninf__copysign__src_known_negative_or_nan__sign_known_negative_or_pinf__multiple_use
; CHECK-SAME: (float nofpclass(nan pzero psub pnorm) [[ALWAYS_NEGATIVE_OR_PINF:%.*]], float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_PINF]])
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative.or.pinf, float %always.negative)
store float %copysign, ptr %ptr
ret float %copysign
}
; Can infer sign bit is negative due to no-norm return
define nofpclass(nan norm) float @ret_no_nan_no_sub__copysign__src_known_negative_or_nan__sign_known_negative_or_pnorm__multiple_use(float nofpclass(nan pinf psub pzero) %always.negative.or.pnorm, float nofpclass(nan pinf pnorm psub pzero) %always.negative, float %unknown0, float %unknown1, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan norm) float @ret_no_nan_no_sub__copysign__src_known_negative_or_nan__sign_known_negative_or_pnorm__multiple_use
; CHECK-SAME: (float nofpclass(nan pinf pzero psub) [[ALWAYS_NEGATIVE_OR_PNORM:%.*]], float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_PNORM]])
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative.or.pnorm, float %always.negative)
store float %copysign, ptr %ptr
ret float %copysign
}
; Can infer sign bit is negative due to no-sub return
define nofpclass(nan sub) float @ret_no_nan_no_sub__copysign__src_known_negative_or_nan__sign_known_negative_or_psub__multiple_use(float nofpclass(nan pinf pnorm pzero) %always.negative.or.psub, float nofpclass(nan pinf pnorm psub pzero) %always.negative, float %unknown0, float %unknown1, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan sub) float @ret_no_nan_no_sub__copysign__src_known_negative_or_nan__sign_known_negative_or_psub__multiple_use
; CHECK-SAME: (float nofpclass(nan pinf pzero pnorm) [[ALWAYS_NEGATIVE_OR_PSUB:%.*]], float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_PSUB]])
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative.or.psub, float %always.negative)
store float %copysign, ptr %ptr
ret float %copysign
}
; Can infer sign bit is negative due to no-zero return
define nofpclass(nan zero) float @ret_no_nan_no_zero__copysign__src_known_negative_or_nan__sign_known_negative_or_pzero__multiple_use(float nofpclass(nan pinf pnorm psub) %always.negative.or.pzero, float nofpclass(nan pinf pnorm psub pzero) %always.negative, float %unknown0, float %unknown1, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan zero) float @ret_no_nan_no_zero__copysign__src_known_negative_or_nan__sign_known_negative_or_pzero__multiple_use
; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ALWAYS_NEGATIVE_OR_PZERO:%.*]], float nofpclass(nan pinf pzero psub pnorm) [[ALWAYS_NEGATIVE:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_PZERO]])
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.negative.or.pzero, float %always.negative)
store float %copysign, ptr %ptr
ret float %copysign
}
; Can infer sign bit is positive due to no-inf return
define nofpclass(nan inf) float @ret_no_nan_no_inf__copysign__src_known_positive_or_nan__sign_known_positive_or_ninf__multiple_use(float nofpclass(nan nnorm nsub nzero) %always.positive.or.ninf, float nofpclass(nan ninf nnorm nsub nzero) %always.positive, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan inf) float @ret_no_nan_no_inf__copysign__src_known_positive_or_nan__sign_known_positive_or_ninf__multiple_use
; CHECK-SAME: (float nofpclass(nan nzero nsub nnorm) [[ALWAYS_POSITIVE_OR_NINF:%.*]], float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_POSITIVE_OR_NINF]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[ALWAYS_POSITIVE_OR_NINF]]
;
%copysign = call float @llvm.copysign.f32(float %always.positive.or.ninf, float %always.positive)
store float %copysign, ptr %ptr
ret float %copysign
}
; Can infer sign bit is positive due to no-norm return
define nofpclass(nan norm) float @ret_no_nan_no_norm__copysign__src_known_positive_or_nan__sign_known_positive_or_norm__multiple_use(float nofpclass(nan ninf nsub nzero) %always.positive.or.nnorm, float nofpclass(nan ninf nnorm nsub nzero) %always.positive, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan norm) float @ret_no_nan_no_norm__copysign__src_known_positive_or_nan__sign_known_positive_or_norm__multiple_use
; CHECK-SAME: (float nofpclass(nan ninf nzero nsub) [[ALWAYS_POSITIVE_OR_NNORM:%.*]], float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_POSITIVE_OR_NNORM]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.positive.or.nnorm, float %always.positive)
store float %copysign, ptr %ptr
ret float %copysign
}
; Can infer sign bit is positive due to no-sub return
define nofpclass(nan sub) float @ret_no_nan_no_sub__copysign__src_known_positive_or_nan__sign_known_positive_or_sub__multiple_use(float nofpclass(nan ninf nnorm nzero) %always.positive.or.nsub, float nofpclass(nan ninf nnorm nsub nzero) %always.positive, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan sub) float @ret_no_nan_no_sub__copysign__src_known_positive_or_nan__sign_known_positive_or_sub__multiple_use
; CHECK-SAME: (float nofpclass(nan ninf nzero nnorm) [[ALWAYS_POSITIVE_OR_NSUB:%.*]], float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_POSITIVE_OR_NSUB]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.positive.or.nsub, float %always.positive)
store float %copysign, ptr %ptr
ret float %copysign
}
; Can infer sign bit is positive due to no-zero return
define nofpclass(nan zero) float @ret_no_nan_no_zero__copysign__src_known_positive_or_nan__sign_known_positive_or_zero__multiple_use(float nofpclass(nan ninf nnorm nsub) %always.positive.or.nzero, float nofpclass(nan ninf nnorm nsub nzero) %always.positive, ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan zero) float @ret_no_nan_no_zero__copysign__src_known_positive_or_nan__sign_known_positive_or_zero__multiple_use
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[ALWAYS_POSITIVE_OR_NZERO:%.*]], float nofpclass(nan ninf nzero nsub nnorm) [[ALWAYS_POSITIVE:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_POSITIVE_OR_NZERO]])
; CHECK-NEXT: store float [[COPYSIGN]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %always.positive.or.nzero, float %always.positive)
store float %copysign, ptr %ptr
ret float %copysign
}