; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6 ; RUN: opt -S -passes=instcombine < %s | FileCheck %s declare nofpclass(qnan inf norm sub zero) float @returns_snan() define nofpclass(pinf) float @ret_nofpclass_pinf__exp2_select_maybe_inf_or_not_pinf(i1 %cond, float %maybe.inf, float nofpclass(pinf) %not.pinf) { ; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__exp2_select_maybe_inf_or_not_pinf( ; CHECK-SAME: i1 [[COND:%.*]], float [[MAYBE_INF:%.*]], float nofpclass(pinf) [[NOT_PINF:%.*]]) { ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[MAYBE_INF]], float [[NOT_PINF]] ; CHECK-NEXT: [[EXP:%.*]] = call float @llvm.exp2.f32(float [[SELECT]]) ; CHECK-NEXT: ret float [[EXP]] ; %select = select i1 %cond, float %maybe.inf, float %not.pinf %exp = call float @llvm.exp2.f32(float %select) ret float %exp } define nofpclass(ninf) float @ret_nofpclass_ninf__exp2_select_maybe_inf_or_not_pinf(i1 %cond, float %maybe.inf, float nofpclass(pinf) %not.pinf) { ; CHECK-LABEL: define nofpclass(ninf) float @ret_nofpclass_ninf__exp2_select_maybe_inf_or_not_pinf( ; CHECK-SAME: i1 [[COND:%.*]], float [[MAYBE_INF:%.*]], float nofpclass(pinf) [[NOT_PINF:%.*]]) { ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[MAYBE_INF]], float [[NOT_PINF]] ; CHECK-NEXT: [[EXP:%.*]] = call float @llvm.exp2.f32(float [[SELECT]]) ; CHECK-NEXT: ret float [[EXP]] ; %select = select i1 %cond, float %maybe.inf, float %not.pinf %exp = call float @llvm.exp2.f32(float %select) ret float %exp } define nofpclass(ninf) float @ret_nofpclass_ninf__exp2_select_maybe_inf_or_not_ninf(i1 %cond, float %maybe.inf, float nofpclass(ninf) %not.ninf) { ; CHECK-LABEL: define nofpclass(ninf) float @ret_nofpclass_ninf__exp2_select_maybe_inf_or_not_ninf( ; CHECK-SAME: i1 [[COND:%.*]], float [[MAYBE_INF:%.*]], float nofpclass(ninf) [[NOT_NINF:%.*]]) { ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[MAYBE_INF]], float [[NOT_NINF]] ; CHECK-NEXT: [[EXP:%.*]] = call float @llvm.exp2.f32(float [[SELECT]]) ; CHECK-NEXT: ret float [[EXP]] ; %select = select i1 %cond, float %maybe.inf, float %not.ninf %exp = call float @llvm.exp2.f32(float %select) ret float %exp } ; Negative test define nofpclass(nan) float @ret_nofpclass_nan__exp2_select_maybe_inf_or_not_nan(i1 %cond, float %maybe.nan, float nofpclass(nan) %not.nan) { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__exp2_select_maybe_inf_or_not_nan( ; CHECK-SAME: i1 [[COND:%.*]], float [[MAYBE_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) { ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[MAYBE_NAN]], float [[NOT_NAN]] ; CHECK-NEXT: [[EXP:%.*]] = call nnan float @llvm.exp2.f32(float [[SELECT]]) ; CHECK-NEXT: ret float [[EXP]] ; %select = select i1 %cond, float %maybe.nan, float %not.nan %exp = call float @llvm.exp2.f32(float %select) ret float %exp } ; Fold to only exp2 define nofpclass(nan) float @ret_nofpclass_nan__exp2_select_maybe_inf_or_nan(i1 %cond, float %maybe.nan, float nofpclass(inf zero sub norm) %only.nan) { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__exp2_select_maybe_inf_or_nan( ; CHECK-SAME: i1 [[COND:%.*]], float [[MAYBE_NAN:%.*]], float nofpclass(inf zero sub norm) [[ONLY_NAN:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = call nnan float @llvm.exp2.f32(float [[MAYBE_NAN]]) ; CHECK-NEXT: ret float [[EXP]] ; %select = select i1 %cond, float %maybe.nan, float %only.nan %exp = call float @llvm.exp2.f32(float %select) ret float %exp } ; Only need to propagate nan inputs, so fold to ret %x define nofpclass(pinf zero psub pnorm) float @ret_nofpclass_no_positives__exp2(float %x) { ; CHECK-LABEL: define nofpclass(pinf zero psub pnorm) float @ret_nofpclass_no_positives__exp2( ; CHECK-SAME: float [[X:%.*]]) { ; CHECK-NEXT: ret float [[X]] ; %exp = call float @llvm.exp2.f32(float %x) ret float %exp } ; No positive results or nans, so fold to poison. define nofpclass(nan pinf zero psub pnorm) float @ret_nofpclass_no_positives_no_nan__exp2(float %x) { ; CHECK-LABEL: define nofpclass(nan pinf zero psub pnorm) float @ret_nofpclass_no_positives_no_nan__exp2( ; CHECK-SAME: float [[X:%.*]]) { ; CHECK-NEXT: ret float poison ; %exp = call float @llvm.exp2.f32(float %x) ret float %exp } ; Can fold this for nan propagation, don't need -0 define nofpclass(pzero pinf psub pnorm) float @ret_nofpclass_no_positives_except_neg0__exp2(float %x) { ; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_no_positives_except_neg0__exp2( ; CHECK-SAME: float [[X:%.*]]) { ; CHECK-NEXT: ret float [[X]] ; %exp = call float @llvm.exp2.f32(float %x) ret float %exp } ; -0 isn't returnable, fold to poison define nofpclass(pzero pinf psub pnorm nan) float @ret_nofpclass_no_positives_except_neg0_no_nan__exp2(float %x) { ; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_nofpclass_no_positives_except_neg0_no_nan__exp2( ; CHECK-SAME: float [[X:%.*]]) { ; CHECK-NEXT: ret float poison ; %exp = call float @llvm.exp2.f32(float %x) ret float %exp } ; Can't fold this, values near 0 return 1. define nofpclass(nzero pinf psub pnorm) float @ret_nofpclass_no_positives_except_pos0__exp2(float %x) { ; CHECK-LABEL: define nofpclass(pinf nzero psub pnorm) float @ret_nofpclass_no_positives_except_pos0__exp2( ; CHECK-SAME: float [[X:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = call float @llvm.exp2.f32(float [[X]]) ; CHECK-NEXT: ret float [[EXP]] ; %exp = call float @llvm.exp2.f32(float %x) ret float %exp } ; Can't fold this, values near 0 return 1. define nofpclass(pinf psub pnorm) float @ret_nofpclass_no_positives_except_0__exp2(float %x) { ; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @ret_nofpclass_no_positives_except_0__exp2( ; CHECK-SAME: float [[X:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = call float @llvm.exp2.f32(float [[X]]) ; CHECK-NEXT: ret float [[EXP]] ; %exp = call float @llvm.exp2.f32(float %x) ret float %exp } ; check exp intrinsic is handled define nofpclass(nan) float @handle_exp(i1 %cond, float %maybe.nan, float nofpclass(inf zero sub norm) %only.nan) { ; CHECK-LABEL: define nofpclass(nan) float @handle_exp( ; CHECK-SAME: i1 [[COND:%.*]], float [[MAYBE_NAN:%.*]], float nofpclass(inf zero sub norm) [[ONLY_NAN:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = call nnan float @llvm.exp.f32(float [[MAYBE_NAN]]) ; CHECK-NEXT: ret float [[EXP]] ; %select = select i1 %cond, float %maybe.nan, float %only.nan %exp = call float @llvm.exp.f32(float %select) ret float %exp } ; check exp10 intrinsic is handled define nofpclass(nan) float @handle_exp10(i1 %cond, float %maybe.nan, float nofpclass(inf zero sub norm) %only.nan) { ; CHECK-LABEL: define nofpclass(nan) float @handle_exp10( ; CHECK-SAME: i1 [[COND:%.*]], float [[MAYBE_NAN:%.*]], float nofpclass(inf zero sub norm) [[ONLY_NAN:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = call nnan float @llvm.exp10.f32(float [[MAYBE_NAN]]) ; CHECK-NEXT: ret float [[EXP]] ; %select = select i1 %cond, float %maybe.nan, float %only.nan %exp = call float @llvm.exp10.f32(float %select) ret float %exp } ; zero or sub result implies the input must be normal, so excludes the ; second select source. define nofpclass(inf norm nan) float @ret_nofpclass_only_subzero__exp2_select_unknown_or_not_norm(i1 %cond, float %unknown, float nofpclass(norm) %not.norm) { ; CHECK-LABEL: define nofpclass(nan inf norm) float @ret_nofpclass_only_subzero__exp2_select_unknown_or_not_norm( ; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN:%.*]], float nofpclass(norm) [[NOT_NORM:%.*]]) { ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[UNKNOWN]], float 0xFFF0000000000000 ; CHECK-NEXT: [[EXP:%.*]] = call nnan float @llvm.exp2.f32(float [[SELECT]]) ; CHECK-NEXT: ret float [[EXP]] ; %select = select i1 %cond, float %unknown, float %not.norm %exp = call float @llvm.exp2.f32(float %select) ret float %exp } define nofpclass(inf norm nan zero) float @ret_nofpclass_only_sub__exp2_select_unknown_or_not_norm(i1 %cond, float %unknown, float nofpclass(norm) %not.norm) { ; CHECK-LABEL: define nofpclass(nan inf zero norm) float @ret_nofpclass_only_sub__exp2_select_unknown_or_not_norm( ; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN:%.*]], float nofpclass(norm) [[NOT_NORM:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = call nnan ninf float @llvm.exp2.f32(float [[UNKNOWN]]) ; CHECK-NEXT: ret float [[EXP]] ; %select = select i1 %cond, float %unknown, float %not.norm %exp = call float @llvm.exp2.f32(float %select) ret float %exp } define nofpclass(inf norm nan sub) float @ret_nofpclass_only_zero__exp2_select_unknown_or_not_norm(i1 %cond, float %unknown, float nofpclass(norm) %not.norm) { ; CHECK-LABEL: define nofpclass(nan inf sub norm) float @ret_nofpclass_only_zero__exp2_select_unknown_or_not_norm( ; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN:%.*]], float nofpclass(norm) [[NOT_NORM:%.*]]) { ; CHECK-NEXT: ret float 0.000000e+00 ; %select = select i1 %cond, float %unknown, float %not.norm %exp = call float @llvm.exp2.f32(float %select) ret float %exp } ; Result only permits +inf or nan. The source value forbids pinf, but ; the possible pnorm value could overflow, so this should not fold to ; return poison. define nofpclass(ninf norm zero sub) float @pinf_result_implies_pnorm_source(float nofpclass(pinf nan) %maybe.pnorm) { ; CHECK-LABEL: define nofpclass(ninf zero sub norm) float @pinf_result_implies_pnorm_source( ; CHECK-SAME: float nofpclass(nan pinf) [[MAYBE_PNORM:%.*]]) { ; CHECK-NEXT: ret float 0x7FF0000000000000 ; %exp = call float @llvm.exp2.f32(float %maybe.pnorm) ret float %exp } define nofpclass(ninf norm zero sub) float @pinf_result_implies_pnorm_source_nan(float nofpclass(pinf) %maybe.pnorm.or.nan) { ; CHECK-LABEL: define nofpclass(ninf zero sub norm) float @pinf_result_implies_pnorm_source_nan( ; CHECK-SAME: float nofpclass(pinf) [[MAYBE_PNORM_OR_NAN:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = call float @llvm.exp2.f32(float [[MAYBE_PNORM_OR_NAN]]) ; CHECK-NEXT: ret float [[EXP]] ; %exp = call float @llvm.exp2.f32(float %maybe.pnorm.or.nan) ret float %exp } define nofpclass(pinf norm zero sub) float @ninf_result_implies_poison(float nofpclass(ninf nan) %maybe.nnorm) { ; CHECK-LABEL: define nofpclass(pinf zero sub norm) float @ninf_result_implies_poison( ; CHECK-SAME: float nofpclass(nan ninf) [[MAYBE_NNORM:%.*]]) { ; CHECK-NEXT: ret float poison ; %exp = call float @llvm.exp2.f32(float %maybe.nnorm) ret float %exp } ; Cannot fold to poison define nofpclass(inf norm nan sub) float @zero_result_implies_nnorm_source_valid(float nofpclass(pnorm sub nan) %maybe.nnorm) { ; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_implies_nnorm_source_valid( ; CHECK-SAME: float nofpclass(nan sub pnorm) [[MAYBE_NNORM:%.*]]) { ; CHECK-NEXT: ret float 0.000000e+00 ; %exp = call float @llvm.exp2.f32(float %maybe.nnorm) ret float %exp } define nofpclass(inf norm nan sub) float @zero_result_implies_nnorm_source_valid_nan(float nofpclass(pnorm sub) %maybe.nnorm.or.nan) { ; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_implies_nnorm_source_valid_nan( ; CHECK-SAME: float nofpclass(sub pnorm) [[MAYBE_NNORM_OR_NAN:%.*]]) { ; CHECK-NEXT: ret float 0.000000e+00 ; %exp = call float @llvm.exp2.f32(float %maybe.nnorm.or.nan) ret float %exp } ; Cannot fold to poison define nofpclass(inf norm nan sub) float @zero_result_implies_nsub_source_valid(float nofpclass(norm psub nan) %maybe.nsub) { ; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_implies_nsub_source_valid( ; CHECK-SAME: float nofpclass(nan psub norm) [[MAYBE_NSUB:%.*]]) { ; CHECK-NEXT: ret float 0.000000e+00 ; %exp = call float @llvm.exp2.f32(float %maybe.nsub) ret float %exp } define nofpclass(inf norm nan sub) float @zero_result_implies_nsub_source_valid_nan(float nofpclass(norm psub) %maybe.nsub.or.nan) { ; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_implies_nsub_source_valid_nan( ; CHECK-SAME: float nofpclass(psub norm) [[MAYBE_NSUB_OR_NAN:%.*]]) { ; CHECK-NEXT: ret float 0.000000e+00 ; %exp = call float @llvm.exp2.f32(float %maybe.nsub.or.nan) ret float %exp } ; Cannot fold to poison define nofpclass(inf norm nan zero) float @sub_result_implies_nnorm_source_valid(float nofpclass(pnorm sub nan) %maybe.nnorm) { ; CHECK-LABEL: define nofpclass(nan inf zero norm) float @sub_result_implies_nnorm_source_valid( ; CHECK-SAME: float nofpclass(nan sub pnorm) [[MAYBE_NNORM:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = call nnan ninf float @llvm.exp2.f32(float [[MAYBE_NNORM]]) ; CHECK-NEXT: ret float [[EXP]] ; %exp = call float @llvm.exp2.f32(float %maybe.nnorm) ret float %exp } ; Cannot fold to poison define nofpclass(inf norm nan zero) float @sub_result_implies_nsub_source_valid(float nofpclass(norm psub nan) %maybe.nsub) { ; CHECK-LABEL: define nofpclass(nan inf zero norm) float @sub_result_implies_nsub_source_valid( ; CHECK-SAME: float nofpclass(nan psub norm) [[MAYBE_NSUB:%.*]]) { ; CHECK-NEXT: ret float poison ; %exp = call float @llvm.exp2.f32(float %maybe.nsub) ret float %exp } define nofpclass(inf norm nan sub) float @zero_result_implies_pnorm_source_valid(float nofpclass(nnorm sub nan) %maybe.pnorm) { ; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_implies_pnorm_source_valid( ; CHECK-SAME: float nofpclass(nan sub nnorm) [[MAYBE_PNORM:%.*]]) { ; CHECK-NEXT: ret float 0.000000e+00 ; %exp = call float @llvm.exp2.f32(float %maybe.pnorm) ret float %exp } define nofpclass(inf norm nan sub) float @zero_result_implies_pnorm_source_valid_nan(float nofpclass(nnorm sub) %maybe.pnorm.or.nan) { ; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_implies_pnorm_source_valid_nan( ; CHECK-SAME: float nofpclass(sub nnorm) [[MAYBE_PNORM_OR_NAN:%.*]]) { ; CHECK-NEXT: ret float 0.000000e+00 ; %exp = call float @llvm.exp2.f32(float %maybe.pnorm.or.nan) ret float %exp } define nofpclass(inf norm nan zero) float @sub_result_implies_pnorm_source_valid(float nofpclass(pnorm sub nan) %maybe.pnorm) { ; CHECK-LABEL: define nofpclass(nan inf zero norm) float @sub_result_implies_pnorm_source_valid( ; CHECK-SAME: float nofpclass(nan sub pnorm) [[MAYBE_PNORM:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = call nnan ninf float @llvm.exp2.f32(float [[MAYBE_PNORM]]) ; CHECK-NEXT: ret float [[EXP]] ; %exp = call float @llvm.exp2.f32(float %maybe.pnorm) ret float %exp } define nofpclass(inf nnorm nan zero) float @pnorm_result_implies_possible_0_source(float nofpclass(pnorm sub) %maybe.zero.or.nan) { ; CHECK-LABEL: define nofpclass(nan inf zero nnorm) float @pnorm_result_implies_possible_0_source( ; CHECK-SAME: float nofpclass(sub pnorm) [[MAYBE_ZERO_OR_NAN:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = call nnan ninf float @llvm.exp2.f32(float [[MAYBE_ZERO_OR_NAN]]) ; CHECK-NEXT: ret float [[EXP]] ; %exp = call float @llvm.exp2.f32(float %maybe.zero.or.nan) ret float %exp } define nofpclass(inf nnorm nan zero sub) float @pnorm_result_implies_possible_0_source_no_inf(float nofpclass(inf norm sub) %maybe.zero.or.nan) { ; CHECK-LABEL: define nofpclass(nan inf zero sub nnorm) float @pnorm_result_implies_possible_0_source_no_inf( ; CHECK-SAME: float nofpclass(inf sub norm) [[MAYBE_ZERO_OR_NAN:%.*]]) { ; CHECK-NEXT: ret float 1.000000e+00 ; %exp = call float @llvm.exp2.f32(float %maybe.zero.or.nan) ret float %exp } define nofpclass(inf nnorm nan zero sub) float @pnorm_result_implies_possible_sub_source(float nofpclass(inf norm zero) %maybe.sub.or.nan) { ; CHECK-LABEL: define nofpclass(nan inf zero sub nnorm) float @pnorm_result_implies_possible_sub_source( ; CHECK-SAME: float nofpclass(inf zero norm) [[MAYBE_SUB_OR_NAN:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = call nnan ninf float @llvm.exp2.f32(float [[MAYBE_SUB_OR_NAN]]) ; CHECK-NEXT: ret float [[EXP]] ; %exp = call float @llvm.exp2.f32(float %maybe.sub.or.nan) ret float %exp } ; FIXME: Does not happen unless nofpclass set on return value. define nofpclass(pzero) float @source_is_known_zero(float nofpclass(nan inf norm sub) %must.be.zero) { ; CHECK-LABEL: define nofpclass(pzero) float @source_is_known_zero( ; CHECK-SAME: float nofpclass(nan inf sub norm) [[MUST_BE_ZERO:%.*]]) { ; CHECK-NEXT: ret float 1.000000e+00 ; %exp = call float @llvm.exp2.f32(float %must.be.zero) ret float %exp } define nofpclass(pzero) <2 x float> @source_is_known_zero_vec(<2 x float> nofpclass(nan inf norm sub) %must.be.zero) { ; CHECK-LABEL: define nofpclass(pzero) <2 x float> @source_is_known_zero_vec( ; CHECK-SAME: <2 x float> nofpclass(nan inf sub norm) [[MUST_BE_ZERO:%.*]]) { ; CHECK-NEXT: ret <2 x float> splat (float 1.000000e+00) ; %exp = call <2 x float> @llvm.exp2.v2f32(<2 x float> %must.be.zero) ret <2 x float> %exp } define nofpclass(pzero) float @source_is_known_pzero(float nofpclass(nan inf norm sub nzero) %must.be.pzero) { ; CHECK-LABEL: define nofpclass(pzero) float @source_is_known_pzero( ; CHECK-SAME: float nofpclass(nan inf nzero sub norm) [[MUST_BE_PZERO:%.*]]) { ; CHECK-NEXT: ret float 1.000000e+00 ; %exp = call float @llvm.exp2.f32(float %must.be.pzero) ret float %exp } define nofpclass(pzero) float @source_is_known_nzero(float nofpclass(nan inf norm sub pzero) %must.be.nzero) { ; CHECK-LABEL: define nofpclass(pzero) float @source_is_known_nzero( ; CHECK-SAME: float nofpclass(nan inf pzero sub norm) [[MUST_BE_NZERO:%.*]]) { ; CHECK-NEXT: ret float 1.000000e+00 ; %exp = call float @llvm.exp2.f32(float %must.be.nzero) ret float %exp } define nofpclass(nzero) float @source_is_known_inf(float nofpclass(nan norm sub zero) %must.be.inf) !prof !0 { ; CHECK-LABEL: define nofpclass(nzero) float @source_is_known_inf( ; CHECK-SAME: float nofpclass(nan zero sub norm) [[MUST_BE_INF:%.*]]) !prof [[PROF0:![0-9]+]] { ; CHECK-NEXT: [[TMP1:%.*]] = fcmp ueq float [[MUST_BE_INF]], 0x7FF0000000000000 ; CHECK-NEXT: [[EXP:%.*]] = select i1 [[TMP1]], float [[MUST_BE_INF]], float 0.000000e+00, !prof [[PROF1:![0-9]+]] ; CHECK-NEXT: ret float [[EXP]] ; %exp = call float @llvm.exp2.f32(float %must.be.inf) ret float %exp } define nofpclass(nzero) <2 x float> @source_is_known_inf_vec(<2 x float> nofpclass(nan norm sub zero) %must.be.inf) { ; CHECK-LABEL: define nofpclass(nzero) <2 x float> @source_is_known_inf_vec( ; CHECK-SAME: <2 x float> nofpclass(nan zero sub norm) [[MUST_BE_INF:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = fcmp ueq <2 x float> [[MUST_BE_INF]], splat (float 0x7FF0000000000000) ; CHECK-NEXT: [[EXP:%.*]] = select <2 x i1> [[TMP1]], <2 x float> [[MUST_BE_INF]], <2 x float> zeroinitializer ; CHECK-NEXT: ret <2 x float> [[EXP]] ; %exp = call <2 x float> @llvm.exp2.v2f32(<2 x float> %must.be.inf) ret <2 x float> %exp } define nofpclass(nzero) float @source_is_known_pinf(float nofpclass(ninf nan norm sub zero) %must.be.pinf) { ; CHECK-LABEL: define nofpclass(nzero) float @source_is_known_pinf( ; CHECK-SAME: float nofpclass(nan ninf zero sub norm) [[MUST_BE_PINF:%.*]]) { ; CHECK-NEXT: ret float 0x7FF0000000000000 ; %exp = call float @llvm.exp2.f32(float %must.be.pinf) ret float %exp } define nofpclass(nzero) float @source_is_known_ninf(float nofpclass(pinf nan norm sub zero) %must.be.ninf) { ; CHECK-LABEL: define nofpclass(nzero) float @source_is_known_ninf( ; CHECK-SAME: float nofpclass(nan pinf zero sub norm) [[MUST_BE_NINF:%.*]]) { ; CHECK-NEXT: ret float 0.000000e+00 ; %exp = call float @llvm.exp2.f32(float %must.be.ninf) ret float %exp } define nofpclass(nzero) float @source_is_known_nan(float nofpclass(inf norm sub zero) %must.be.nan) { ; CHECK-LABEL: define nofpclass(nzero) float @source_is_known_nan( ; CHECK-SAME: float nofpclass(inf zero sub norm) [[MUST_BE_NAN:%.*]]) { ; CHECK-NEXT: ret float [[MUST_BE_NAN]] ; %exp = call float @llvm.exp2.f32(float %must.be.nan) ret float %exp } define nofpclass(nzero) float @source_is_known_nan_preserve_flags(float nofpclass(inf norm sub zero) %must.be.nan) { ; CHECK-LABEL: define nofpclass(nzero) float @source_is_known_nan_preserve_flags( ; CHECK-SAME: float nofpclass(inf zero sub norm) [[MUST_BE_NAN:%.*]]) { ; CHECK-NEXT: ret float [[MUST_BE_NAN]] ; %exp = call contract nsz float @llvm.exp2.f32(float %must.be.nan) ret float %exp } define nofpclass(nzero) float @source_is_known_inf_or_nan(float nofpclass(norm sub zero) %must.be.inf.or.nan) { ; CHECK-LABEL: define nofpclass(nzero) float @source_is_known_inf_or_nan( ; CHECK-SAME: float nofpclass(zero sub norm) [[MUST_BE_INF_OR_NAN:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = fcmp ueq float [[MUST_BE_INF_OR_NAN]], 0x7FF0000000000000 ; CHECK-NEXT: [[EXP:%.*]] = select i1 [[TMP1]], float [[MUST_BE_INF_OR_NAN]], float 0.000000e+00 ; CHECK-NEXT: ret float [[EXP]] ; %exp = call float @llvm.exp2.f32(float %must.be.inf.or.nan) ret float %exp } define nofpclass(nzero) float @source_is_known_inf_or_nan_preserve_flags(float nofpclass(norm sub zero) %must.be.inf.or.nan) { ; CHECK-LABEL: define nofpclass(nzero) float @source_is_known_inf_or_nan_preserve_flags( ; CHECK-SAME: float nofpclass(zero sub norm) [[MUST_BE_INF_OR_NAN:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = fcmp nsz contract ueq float [[MUST_BE_INF_OR_NAN]], 0x7FF0000000000000 ; CHECK-NEXT: [[TMP2:%.*]] = select nsz contract i1 [[TMP1]], float [[MUST_BE_INF_OR_NAN]], float 0.000000e+00 ; CHECK-NEXT: ret float [[TMP2]] ; %exp = call contract nsz float @llvm.exp2.f32(float %must.be.inf.or.nan) ret float %exp } define nofpclass(nzero nan) float @source_is_known_inf_or_nan__nnan_result(float nofpclass(norm sub zero) %must.be.inf.or.nan) { ; CHECK-LABEL: define nofpclass(nan nzero) float @source_is_known_inf_or_nan__nnan_result( ; CHECK-SAME: float nofpclass(zero sub norm) [[MUST_BE_INF_OR_NAN:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = fcmp ueq float [[MUST_BE_INF_OR_NAN]], 0x7FF0000000000000 ; CHECK-NEXT: [[EXP:%.*]] = select i1 [[TMP1]], float [[MUST_BE_INF_OR_NAN]], float 0.000000e+00 ; CHECK-NEXT: ret float [[EXP]] ; %exp = call float @llvm.exp2.f32(float %must.be.inf.or.nan) ret float %exp } define nofpclass(pzero) float @source_is_known_zero_or_nan(float nofpclass(inf norm sub) %must.be.zero.or.nan) { ; CHECK-LABEL: define nofpclass(pzero) float @source_is_known_zero_or_nan( ; CHECK-SAME: float nofpclass(inf sub norm) [[MUST_BE_ZERO_OR_NAN:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = fadd float [[MUST_BE_ZERO_OR_NAN]], 1.000000e+00 ; CHECK-NEXT: ret float [[EXP]] ; %exp = call float @llvm.exp2.f32(float %must.be.zero.or.nan) ret float %exp } define nofpclass(pzero) <2 x float> @source_is_known_zero_or_nan_vec(<2 x float> nofpclass(inf norm sub) %must.be.zero.or.nan) { ; CHECK-LABEL: define nofpclass(pzero) <2 x float> @source_is_known_zero_or_nan_vec( ; CHECK-SAME: <2 x float> nofpclass(inf sub norm) [[MUST_BE_ZERO_OR_NAN:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = fadd <2 x float> [[MUST_BE_ZERO_OR_NAN]], splat (float 1.000000e+00) ; CHECK-NEXT: ret <2 x float> [[EXP]] ; %exp = call <2 x float> @llvm.exp2.v2f32(<2 x float> %must.be.zero.or.nan) ret <2 x float> %exp } define nofpclass(nzero) float @source_is_known_snan(float nofpclass(inf norm sub zero qnan) %must.be.snan) { ; CHECK-LABEL: define nofpclass(nzero) float @source_is_known_snan( ; CHECK-SAME: float nofpclass(qnan inf zero sub norm) [[MUST_BE_SNAN:%.*]]) { ; CHECK-NEXT: ret float [[MUST_BE_SNAN]] ; %exp = call float @llvm.exp2.f32(float %must.be.snan) ret float %exp } define nofpclass(nzero) float @source_is_known_qnan(float nofpclass(inf norm sub zero snan) %must.be.qnan) { ; CHECK-LABEL: define nofpclass(nzero) float @source_is_known_qnan( ; CHECK-SAME: float nofpclass(snan inf zero sub norm) [[MUST_BE_QNAN:%.*]]) { ; CHECK-NEXT: ret float [[MUST_BE_QNAN]] ; %exp = call float @llvm.exp2.f32(float %must.be.qnan) ret float %exp } define nofpclass(pzero nan) float @source_is_known_zero_or_nan__nnan_result(float nofpclass(inf norm sub) %must.be.zero.or.nan) { ; CHECK-LABEL: define nofpclass(nan pzero) float @source_is_known_zero_or_nan__nnan_result( ; CHECK-SAME: float nofpclass(inf sub norm) [[MUST_BE_ZERO_OR_NAN:%.*]]) { ; CHECK-NEXT: ret float 1.000000e+00 ; %exp = call float @llvm.exp2.f32(float %must.be.zero.or.nan) ret float %exp } ; Cannot eliminate the select define nofpclass(nan inf nnorm sub zero) float @posnormal_result_demands_negnormal_source(i1 %cond, float nofpclass(inf nan pnorm sub zero) %neg.normal, float %unknown) { ; CHECK-LABEL: define nofpclass(nan inf zero sub nnorm) float @posnormal_result_demands_negnormal_source( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(nan inf zero sub pnorm) [[NEG_NORMAL:%.*]], float [[UNKNOWN:%.*]]) { ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[UNKNOWN]], float [[NEG_NORMAL]] ; CHECK-NEXT: [[EXP:%.*]] = call nnan ninf float @llvm.exp2.f32(float [[SELECT]]) ; CHECK-NEXT: ret float [[EXP]] ; %select = select i1 %cond, float %unknown, float %neg.normal %exp = call float @llvm.exp2.f32(float %select) ret float %exp } define nofpclass(inf zero sub norm) float @ret_only_nan__exp2(float %x) { ; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_only_nan__exp2( ; CHECK-SAME: float [[X:%.*]]) { ; CHECK-NEXT: ret float 0x7FF8000000000000 ; %exp = call float @llvm.exp2.f32(float %x) ret float %exp } define nofpclass(qnan inf zero sub norm) float @ret_only_snan__exp2(float %x) { ; CHECK-LABEL: define nofpclass(qnan inf zero sub norm) float @ret_only_snan__exp2( ; CHECK-SAME: float [[X:%.*]]) { ; CHECK-NEXT: ret float poison ; %exp = call float @llvm.exp2.f32(float %x) ret float %exp } define nofpclass(snan inf zero sub norm) float @ret_only_qnan__exp2(float %x) { ; CHECK-LABEL: define nofpclass(snan inf zero sub norm) float @ret_only_qnan__exp2( ; CHECK-SAME: float [[X:%.*]]) { ; CHECK-NEXT: ret float 0x7FF8000000000000 ; %exp = call float @llvm.exp2.f32(float %x) ret float %exp } define nofpclass(inf zero sub norm) <2 x float> @ret_only_nan__exp2_vec(<2 x float> %x) { ; CHECK-LABEL: define nofpclass(inf zero sub norm) <2 x float> @ret_only_nan__exp2_vec( ; CHECK-SAME: <2 x float> [[X:%.*]]) { ; CHECK-NEXT: ret <2 x float> splat (float 0x7FF8000000000000) ; %exp = call <2 x float> @llvm.exp2.v2f32(<2 x float> %x) ret <2 x float> %exp } define nofpclass(inf zero sub norm) <2 x float> @ret_only_nan__exp2_vec_partially_defined(<2 x float> %x) { ; CHECK-LABEL: define nofpclass(inf zero sub norm) <2 x float> @ret_only_nan__exp2_vec_partially_defined( ; CHECK-SAME: <2 x float> [[X:%.*]]) { ; CHECK-NEXT: ret <2 x float> splat (float 0x7FF8000000000000) ; %exp = call <2 x float> @llvm.exp2.v2f32(<2 x float> ) ret <2 x float> %exp } define nofpclass(snan) float @ret_no_snan__exp__no_inf(float nofpclass(inf) %x) { ; CHECK-LABEL: define nofpclass(snan) float @ret_no_snan__exp__no_inf( ; CHECK-SAME: float nofpclass(inf) [[X:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = call float @llvm.exp.f32(float [[X]]) ; CHECK-NEXT: ret float [[EXP]] ; %exp = call float @llvm.exp.f32(float %x) ret float %exp } define nofpclass(inf) float @ret_no_inf__exp__no_inf(float nofpclass(inf) %x) { ; CHECK-LABEL: define nofpclass(inf) float @ret_no_inf__exp__no_inf( ; CHECK-SAME: float nofpclass(inf) [[X:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = call ninf float @llvm.exp.f32(float [[X]]) ; CHECK-NEXT: ret float [[EXP]] ; %exp = call float @llvm.exp.f32(float %x) ret float %exp } define nofpclass(pinf) float @ret_no_pinf__exp__no_pinf(float nofpclass(pinf) %x) { ; CHECK-LABEL: define nofpclass(pinf) float @ret_no_pinf__exp__no_pinf( ; CHECK-SAME: float nofpclass(pinf) [[X:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = call float @llvm.exp.f32(float [[X]]) ; CHECK-NEXT: ret float [[EXP]] ; %exp = call float @llvm.exp.f32(float %x) ret float %exp } define nofpclass(nan inf) float @ret_no_inf_no_nan__exp__no_inf(float nofpclass(inf) %x) { ; CHECK-LABEL: define nofpclass(nan inf) float @ret_no_inf_no_nan__exp__no_inf( ; CHECK-SAME: float nofpclass(inf) [[X:%.*]]) { ; CHECK-NEXT: [[EXP:%.*]] = call nnan ninf float @llvm.exp.f32(float [[X]]) ; CHECK-NEXT: ret float [[EXP]] ; %exp = call noundef float @llvm.exp.f32(float %x) ret float %exp } define nofpclass(snan) float @qnan_result_demands_snan_src(i1 %cond, float %unknown) { ; CHECK-LABEL: define nofpclass(snan) float @qnan_result_demands_snan_src( ; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN:%.*]]) { ; CHECK-NEXT: [[SNAN:%.*]] = call float @returns_snan() ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[SNAN]], float [[UNKNOWN]] ; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.exp.f32(float [[SELECT]]) ; CHECK-NEXT: ret float [[RESULT]] ; %snan = call float @returns_snan() %select = select i1 %cond, float %snan, float %unknown %result = call float @llvm.exp.f32(float %select) ret float %result } !0 = !{!"function_entry_count", i64 1000} ;. ; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nocreateundeforpoison nofree nosync nounwind speculatable willreturn memory(none) } ;. ; CHECK: [[PROF0]] = !{!"function_entry_count", i64 1000} ; CHECK: [[PROF1]] = !{!"unknown", !"instcombine"} ;.