| ; 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 |
| |
| 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 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 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 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 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 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 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 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 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 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 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 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> <float 0x7ff8000000000000, float poison>) |
| ret <2 x float> %exp |
| } |
| |
| !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"} |
| ;. |