| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: opt -S -passes=instcombine < %s | FileCheck %s |
| |
| declare nofpclass(nan inf sub norm) float @returns_zero() |
| declare nofpclass(nan inf nzero sub norm) float @returns_pzero() |
| declare nofpclass(nan inf pzero sub norm) float @returns_nzero() |
| declare nofpclass(nan inf zero sub nnorm) float @returns_pnorm() |
| declare nofpclass(nan inf norm zero) float @returns_sub() |
| declare nofpclass(nan inf sub zero) float @returns_norm() |
| declare nofpclass(qnan inf norm sub zero) float @returns_snan() |
| declare void @use(float) |
| |
| ; No inf result implies no inf inputs. |
| ; |
| ; Does not require special handling of fmul. |
| define nofpclass(pinf) float @ret_nofpclass_pinf__fmul_unknown_or_pinf(i1 %cond, float %x, float %y) { |
| ; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__fmul_unknown_or_pinf( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float [[Y:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[X]], [[Y]] |
| ; CHECK-NEXT: ret float [[TMP1]] |
| ; |
| %x.or.pinf = select i1 %cond, float %x, float 0x7FF0000000000000 |
| %y.or.pinf = select i1 %cond, float %y, float 0x7FF0000000000000 |
| %mul = fmul float %x.or.pinf, %y.or.pinf |
| ret float %mul |
| } |
| |
| ; Does not require special handling of fmul. |
| define nofpclass(ninf) float @ret_nofpclass_pinf__fmul_unknown_or_ninf(i1 %cond, float %x, float %y) { |
| ; CHECK-LABEL: define nofpclass(ninf) float @ret_nofpclass_pinf__fmul_unknown_or_ninf( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float [[Y:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[X]], [[Y]] |
| ; CHECK-NEXT: [[MUL:%.*]] = select i1 [[COND]], float [[TMP1]], float 0x7FF0000000000000 |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %x.or.ninf = select i1 %cond, float %x, float 0xFFF0000000000000 |
| %y.or.ninf = select i1 %cond, float %y, float 0xFFF0000000000000 |
| %mul = fmul float %x.or.ninf, %y.or.ninf |
| ret float %mul |
| } |
| |
| define nofpclass(inf) float @ret_nofpclass_inf__fmul_unknown_or_pinf(i1 %cond, float %x, float %y) { |
| ; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__fmul_unknown_or_pinf( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float [[Y:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[X]], [[Y]] |
| ; CHECK-NEXT: ret float [[TMP1]] |
| ; |
| %x.or.pinf = select i1 %cond, float %x, float 0x7FF0000000000000 |
| %y.or.pinf = select i1 %cond, float %y, float 0x7FF0000000000000 |
| %mul = fmul float %x.or.pinf, %y.or.pinf |
| ret float %mul |
| } |
| |
| ; -> Only propagate nan %x |
| define nofpclass(pinf pnorm psub pzero) float @ret_only_negative_results_or_nan_square(float noundef %x) { |
| ; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_negative_results_or_nan_square( |
| ; CHECK-SAME: float noundef [[X:%.*]]) { |
| ; CHECK-NEXT: ret float 0x7FF8000000000000 |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| ; -> poison |
| define nofpclass(pinf pnorm psub pzero nan) float @ret_only_negative_results_square(float noundef %x) { |
| ; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_only_negative_results_square( |
| ; CHECK-SAME: float noundef [[X:%.*]]) { |
| ; CHECK-NEXT: ret float poison |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| ; Cannot fold if undef |
| define nofpclass(pinf pnorm psub pzero nan) float @ret_only_negative_results_square_maybe_undef(float %x) { |
| ; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_only_negative_results_square_maybe_undef( |
| ; CHECK-SAME: float [[X:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul nnan float [[X]], [[X]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| define nofpclass(inf norm sub) float @ret_only_zero_or_nan_results_square(float noundef %x) { |
| ; CHECK-LABEL: define nofpclass(inf sub norm) float @ret_only_zero_or_nan_results_square( |
| ; CHECK-SAME: float noundef [[X:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[X]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| define nofpclass(inf norm sub nan) float @ret_only_zero_results_square(float noundef %x) { |
| ; CHECK-LABEL: define nofpclass(nan inf sub norm) float @ret_only_zero_results_square( |
| ; CHECK-SAME: float noundef [[X:%.*]]) { |
| ; CHECK-NEXT: ret float 0.000000e+00 |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| define nofpclass(inf norm sub zero) float @ret_only_nan_results_square(float noundef %x) { |
| ; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_only_nan_results_square( |
| ; CHECK-SAME: float noundef [[X:%.*]]) { |
| ; CHECK-NEXT: ret float 0x7FF8000000000000 |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| define nofpclass(inf norm sub zero snan) float @ret_only_qnan_results_square(float noundef %x) { |
| ; CHECK-LABEL: define nofpclass(snan inf zero sub norm) float @ret_only_qnan_results_square( |
| ; CHECK-SAME: float noundef [[X:%.*]]) { |
| ; CHECK-NEXT: ret float 0x7FF8000000000000 |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| define nofpclass(inf norm sub zero qnan) float @ret_only_snan_results_square(float noundef %x) { |
| ; CHECK-LABEL: define nofpclass(qnan inf zero sub norm) float @ret_only_snan_results_square( |
| ; CHECK-SAME: float noundef [[X:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[X]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| define nofpclass(norm sub zero) float @ret_only_inf_or_nan_results_square(float noundef %x) { |
| ; CHECK-LABEL: define nofpclass(zero sub norm) float @ret_only_inf_or_nan_results_square( |
| ; CHECK-SAME: float noundef [[X:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[X]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| define nofpclass(norm sub zero nan) float @ret_only_inf_results_square(float noundef %x) { |
| ; CHECK-LABEL: define nofpclass(nan zero sub norm) float @ret_only_inf_results_square( |
| ; CHECK-SAME: float noundef [[X:%.*]]) { |
| ; CHECK-NEXT: ret float 0x7FF0000000000000 |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| define nofpclass(ninf norm sub zero) float @ret_only_pinf_or_nan_results_square(float noundef %x) { |
| ; CHECK-LABEL: define nofpclass(ninf zero sub norm) float @ret_only_pinf_or_nan_results_square( |
| ; CHECK-SAME: float noundef [[X:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[X]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| define nofpclass(ninf norm sub zero nan) float @ret_only_pinf_results_square(float noundef %x) { |
| ; CHECK-LABEL: define nofpclass(nan ninf zero sub norm) float @ret_only_pinf_results_square( |
| ; CHECK-SAME: float noundef [[X:%.*]]) { |
| ; CHECK-NEXT: ret float 0x7FF0000000000000 |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| ; -> poison |
| define nofpclass(pinf norm sub zero nan) float @ret_only_ninf_results_square(float noundef %x) { |
| ; CHECK-LABEL: define nofpclass(nan pinf zero sub norm) float @ret_only_ninf_results_square( |
| ; CHECK-SAME: float noundef [[X:%.*]]) { |
| ; CHECK-NEXT: ret float poison |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| define nofpclass(inf) float @ret_src_must_be_zero_square(float noundef nofpclass(nan inf norm sub) %x) { |
| ; CHECK-LABEL: define nofpclass(inf) float @ret_src_must_be_zero_square( |
| ; CHECK-SAME: float noundef nofpclass(nan inf sub norm) [[X:%.*]]) { |
| ; CHECK-NEXT: ret float 0.000000e+00 |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| define nofpclass(inf) float @ret_src_must_be_pzero(float noundef nofpclass(nan inf norm sub nzero) %x) { |
| ; CHECK-LABEL: define nofpclass(inf) float @ret_src_must_be_pzero( |
| ; CHECK-SAME: float noundef nofpclass(nan inf nzero sub norm) [[X:%.*]]) { |
| ; CHECK-NEXT: ret float 0.000000e+00 |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| define nofpclass(inf) float @ret_src_must_be_nzero(float noundef nofpclass(nan inf norm sub pzero) %x) { |
| ; CHECK-LABEL: define nofpclass(inf) float @ret_src_must_be_nzero( |
| ; CHECK-SAME: float noundef nofpclass(nan inf pzero sub norm) [[X:%.*]]) { |
| ; CHECK-NEXT: ret float 0.000000e+00 |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square(float noundef nofpclass(inf norm sub) %x) { |
| ; CHECK-LABEL: define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square( |
| ; CHECK-SAME: float noundef nofpclass(inf sub norm) [[X:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.fabs.f32(float [[X]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square__preserve_flags(float noundef nofpclass(inf norm sub) %x) { |
| ; CHECK-LABEL: define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square__preserve_flags( |
| ; CHECK-SAME: float noundef nofpclass(inf sub norm) [[X:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = call contract float @llvm.fabs.f32(float [[X]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul contract float %x, %x |
| ret float %mul |
| } |
| |
| define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square_other_use_input0(float noundef nofpclass(inf norm sub) %x) { |
| ; CHECK-LABEL: define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square_other_use_input0( |
| ; CHECK-SAME: float noundef nofpclass(inf sub norm) [[X:%.*]]) { |
| ; CHECK-NEXT: call void @use(float [[X]]) |
| ; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.fabs.f32(float [[X]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| call void @use(float %x) |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square_other_use_input1(float noundef nofpclass(inf norm sub) %x) { |
| ; CHECK-LABEL: define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square_other_use_input1( |
| ; CHECK-SAME: float noundef nofpclass(inf sub norm) [[X:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.fabs.f32(float [[X]]) |
| ; CHECK-NEXT: call void @use(float [[X]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %x, %x |
| call void @use(float %x) |
| ret float %mul |
| } |
| |
| define nofpclass(ninf norm sub zero) float @pinf_result_demands__square__pnorm_source(i1 %cond, float nofpclass(nan) %not.nan) { |
| ; CHECK-LABEL: define nofpclass(ninf zero sub norm) float @pinf_result_demands__square__pnorm_source( |
| ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) { |
| ; CHECK-NEXT: [[PNORM:%.*]] = call float @returns_pnorm() |
| ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[PNORM]], float [[NOT_NAN]] |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[SELECT]], [[SELECT]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %pnorm = call float @returns_pnorm() |
| %select = select i1 %cond, float %pnorm, float %not.nan |
| %mul = fmul float %select, %select |
| ret float %mul |
| } |
| |
| define nofpclass(pinf) float @ret_nofpclass_pinf__fmul_square_unknown_or_pinf(i1 %cond, float %x) { |
| ; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__fmul_square_unknown_or_pinf( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]]) { |
| ; CHECK-NEXT: [[X_OR_PINF:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000 |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X_OR_PINF]], [[X_OR_PINF]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %x.or.pinf = select i1 %cond, float %x, float 0x7FF0000000000000 |
| %mul = fmul float %x.or.pinf, %x.or.pinf |
| ret float %mul |
| } |
| |
| define nofpclass(pinf) float @ret_nofpclass_pinf__fmul_square_unknown_or_pinf__other_use0(i1 %cond, float %x) { |
| ; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__fmul_square_unknown_or_pinf__other_use0( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]]) { |
| ; CHECK-NEXT: [[X_OR_PINF:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000 |
| ; CHECK-NEXT: call void @use(float [[X_OR_PINF]]) |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X_OR_PINF]], [[X_OR_PINF]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %x.or.pinf = select i1 %cond, float %x, float 0x7FF0000000000000 |
| call void @use(float %x.or.pinf) |
| %mul = fmul float %x.or.pinf, %x.or.pinf |
| ret float %mul |
| } |
| |
| define nofpclass(pinf) float @ret_nofpclass_pinf__fmul_square_unknown_or_pinf__other_use1(i1 %cond, float %x) { |
| ; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__fmul_square_unknown_or_pinf__other_use1( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]]) { |
| ; CHECK-NEXT: [[X_OR_PINF:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000 |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X_OR_PINF]], [[X_OR_PINF]] |
| ; CHECK-NEXT: call void @use(float [[X_OR_PINF]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %x.or.pinf = select i1 %cond, float %x, float 0x7FF0000000000000 |
| %mul = fmul float %x.or.pinf, %x.or.pinf |
| call void @use(float %x.or.pinf) |
| ret float %mul |
| } |
| |
| ; -> qnan |
| define nofpclass(nzero) float @ret_src_must_be_nan_square(float noundef nofpclass(inf norm sub zero) %x) { |
| ; CHECK-LABEL: define nofpclass(nzero) float @ret_src_must_be_nan_square( |
| ; CHECK-SAME: float noundef nofpclass(inf zero sub norm) [[X:%.*]]) { |
| ; CHECK-NEXT: ret float 0x7FF8000000000000 |
| ; |
| %mul = fmul float %x, %x |
| ret float %mul |
| } |
| |
| ; -> qnan |
| define nofpclass(pinf pnorm psub pzero) float @ret_only_negative_results_or_nan_fabs_xy(float %x, float nofpclass(ninf nnorm nsub nzero) %y.pos.or.nan) { |
| ; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_negative_results_or_nan_fabs_xy( |
| ; CHECK-SAME: float [[X:%.*]], float nofpclass(ninf nzero nsub nnorm) [[Y_POS_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: ret float 0x7FF8000000000000 |
| ; |
| %x.fabs = call float @llvm.fabs.f32(float %x) |
| %mul = fmul float %x.fabs, %y.pos.or.nan |
| ret float %mul |
| } |
| |
| ; -> poison |
| define nofpclass(pinf pnorm psub pzero nan) float @ret_only_negative_results_fabs_xy(float %x,float nofpclass(ninf nnorm nsub nzero) %y.pos.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_only_negative_results_fabs_xy( |
| ; CHECK-SAME: float [[X:%.*]], float nofpclass(ninf nzero nsub nnorm) [[Y_POS_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: ret float poison |
| ; |
| %x.fabs = call float @llvm.fabs.f32(float %x) |
| %mul = fmul float %x.fabs, %y.pos.or.nan |
| ret float %mul |
| } |
| |
| define nofpclass(zero) float @ret_only_zero_results__rhs_non0_const(float %x) { |
| ; CHECK-LABEL: define nofpclass(zero) float @ret_only_zero_results__rhs_non0_const( |
| ; CHECK-SAME: float [[X:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], 2.000000e+00 |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %x, 2.0 |
| ret float %mul |
| } |
| |
| define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero_nonsub(float nofpclass(zero sub) %x, float %y) { |
| ; CHECK-LABEL: define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero_nonsub( |
| ; CHECK-SAME: float nofpclass(zero sub) [[X:%.*]], float [[Y:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[Y]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %x, %y |
| ret float %mul |
| } |
| |
| define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero_nonsub_daz(float nofpclass(zero sub) %x, float %y) #0 { |
| ; CHECK-LABEL: define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero_nonsub_daz( |
| ; CHECK-SAME: float nofpclass(zero sub) [[X:%.*]], float [[Y:%.*]]) #[[ATTR0:[0-9]+]] { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[Y]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %x, %y |
| ret float %mul |
| } |
| |
| define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero_nonsub_dynamic(float nofpclass(zero sub) %x, float %y) #1 { |
| ; CHECK-LABEL: define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero_nonsub_dynamic( |
| ; CHECK-SAME: float nofpclass(zero sub) [[X:%.*]], float [[Y:%.*]]) #[[ATTR1:[0-9]+]] { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[Y]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %x, %y |
| ret float %mul |
| } |
| |
| define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero(float nofpclass(zero) %x, float %y) { |
| ; CHECK-LABEL: define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero( |
| ; CHECK-SAME: float nofpclass(zero) [[X:%.*]], float [[Y:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[Y]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %x, %y |
| ret float %mul |
| } |
| |
| define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero_daz(float nofpclass(zero) %x, float %y) #1 { |
| ; CHECK-LABEL: define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero_daz( |
| ; CHECK-SAME: float nofpclass(zero) [[X:%.*]], float [[Y:%.*]]) #[[ATTR1]] { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[Y]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %x, %y |
| ret float %mul |
| } |
| |
| define nofpclass(inf) float @ret_only_inf_results__lhs_known_non_inf(i1 %cond, float %x, float nofpclass(inf) %y) { |
| ; CHECK-LABEL: define nofpclass(inf) float @ret_only_inf_results__lhs_known_non_inf( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(inf) [[Y:%.*]]) { |
| ; CHECK-NEXT: [[X_OR_PINF:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000 |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X_OR_PINF]], [[Y]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %x.or.pinf = select i1 %cond, float %x, float 0x7FF0000000000000 |
| %mul = fmul float %x.or.pinf, %y |
| ret float %mul |
| } |
| |
| define nofpclass(inf) float @ret_no_inf_results__rhs_known_non_inf(i1 %cond, float %x, float nofpclass(inf) %y) { |
| ; CHECK-LABEL: define nofpclass(inf) float @ret_no_inf_results__rhs_known_non_inf( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(inf) [[Y:%.*]]) { |
| ; CHECK-NEXT: [[Y_OR_PINF:%.*]] = select i1 [[COND]], float [[Y]], float 0x7FF0000000000000 |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[Y_OR_PINF]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %y.or.pinf = select i1 %cond, float %y, float 0x7FF0000000000000 |
| %mul = fmul float %x, %y.or.pinf |
| ret float %mul |
| } |
| |
| ; Do nothing, this could still be -inf |
| define nofpclass(ninf nan) float @ret_no_ninf_or_nan_results__lhs_known_non_inf(i1 %cond, float %x, float nofpclass(inf) %y) { |
| ; CHECK-LABEL: define nofpclass(nan ninf) float @ret_no_ninf_or_nan_results__lhs_known_non_inf( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(inf) [[Y:%.*]]) { |
| ; CHECK-NEXT: [[X_OR_PINF:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000 |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul nnan float [[X_OR_PINF]], [[Y]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %x.or.pinf = select i1 %cond, float %x, float 0x7FF0000000000000 |
| %mul = fmul float %x.or.pinf, %y |
| ret float %mul |
| } |
| |
| ; Do nothing, this could still be -inf |
| define nofpclass(pinf nan) float @ret_no_pinf_or_nan_results__lhs_known_non_inf(i1 %cond, float %x, float nofpclass(inf) %y) { |
| ; CHECK-LABEL: define nofpclass(nan pinf) float @ret_no_pinf_or_nan_results__lhs_known_non_inf( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(inf) [[Y:%.*]]) { |
| ; CHECK-NEXT: [[X_OR_PINF:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000 |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul nnan float [[X_OR_PINF]], [[Y]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %x.or.pinf = select i1 %cond, float %x, float 0x7FF0000000000000 |
| %mul = fmul float %x.or.pinf, %y |
| ret float %mul |
| } |
| |
| ; fold to fmul |
| define nofpclass(inf nan) float @ret_no_inf_or_nan_results__lhs_known_non_inf(i1 %cond, float %x, float nofpclass(inf) %y) { |
| ; CHECK-LABEL: define nofpclass(nan inf) float @ret_no_inf_or_nan_results__lhs_known_non_inf( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(inf) [[Y:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf float [[X]], [[Y]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %x.or.pinf = select i1 %cond, float %x, float 0x7FF0000000000000 |
| %mul = fmul float %x.or.pinf, %y |
| ret float %mul |
| } |
| |
| ; fold to fmul |
| define nofpclass(inf nan) float @ret_no_inf_or_nan_results__rhs_known_non_inf(i1 %cond, float %x, float nofpclass(inf) %y) { |
| ; CHECK-LABEL: define nofpclass(nan inf) float @ret_no_inf_or_nan_results__rhs_known_non_inf( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(inf) [[Y:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf float [[X]], [[Y]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %y.or.pinf = select i1 %cond, float %y, float 0x7FF0000000000000 |
| %mul = fmul float %x, %y.or.pinf |
| ret float %mul |
| } |
| |
| ; -> nan |
| define nofpclass(ninf nnorm nsub nzero) float @ret_only_positive_results_or_nan_known_negative_fmul(float nofpclass(ninf nnorm nsub nzero) %only.positive.or.nan, float nofpclass(pinf pnorm psub pzero) %only.negative.or.nan) { |
| ; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_only_positive_results_or_nan_known_negative_fmul( |
| ; CHECK-SAME: float nofpclass(ninf nzero nsub nnorm) [[ONLY_POSITIVE_OR_NAN:%.*]], float nofpclass(pinf pzero psub pnorm) [[ONLY_NEGATIVE_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: ret float 0x7FF8000000000000 |
| ; |
| %mul = fmul float %only.negative.or.nan, %only.positive.or.nan |
| ret float %mul |
| } |
| |
| ; -> poison |
| define nofpclass(ninf nnorm nsub nzero nan) float @ret_only_positive_results_known_negative_fmul(float nofpclass(ninf nnorm nsub nzero) %only.positive.or.nan, float nofpclass(pinf pnorm psub pzero) %only.negative.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_only_positive_results_known_negative_fmul( |
| ; CHECK-SAME: float nofpclass(ninf nzero nsub nnorm) [[ONLY_POSITIVE_OR_NAN:%.*]], float nofpclass(pinf pzero psub pnorm) [[ONLY_NEGATIVE_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: ret float poison |
| ; |
| %mul = fmul float %only.negative.or.nan, %only.positive.or.nan |
| ret float %mul |
| } |
| |
| ; missing nnan rhs |
| define nofpclass(nsub) float @ret__known_zero_or_nan__fmul__not_inf(float nofpclass(inf sub norm) %zero.or.nan, float nofpclass(inf) %not.inf) { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__known_zero_or_nan__fmul__not_inf( |
| ; CHECK-SAME: float nofpclass(inf sub norm) [[ZERO_OR_NAN:%.*]], float nofpclass(inf) [[NOT_INF:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[ZERO_OR_NAN]], [[NOT_INF]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %zero.or.nan, %not.inf |
| ret float %mul |
| } |
| |
| ; Needs to be pzero to replace with copysign |
| define nofpclass(nsub) float @ret__known_zero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm) %zero.or.nan, float nofpclass(inf nan) %not.inf.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__known_zero_or_nan__fmul__not_inf_or_nan( |
| ; CHECK-SAME: float nofpclass(inf sub norm) [[ZERO_OR_NAN:%.*]], float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[ZERO_OR_NAN]], [[NOT_INF_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %zero.or.nan, %not.inf.or.nan |
| ret float %mul |
| } |
| |
| ; Needs to be pzero to replace with copysign |
| define nofpclass(nsub) float @ret__not_inf_or_nan__fmul__known_zero_or_nan(float nofpclass(inf nan) %not.inf.or.nan, float nofpclass(inf sub norm) %zero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__not_inf_or_nan__fmul__known_zero_or_nan( |
| ; CHECK-SAME: float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]], float nofpclass(inf sub norm) [[ZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[NOT_INF_OR_NAN]], [[ZERO_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.inf.or.nan, %zero.or.nan |
| ret float %mul |
| } |
| |
| ; -> copysign |
| define nofpclass(nsub) float @ret__known_pzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float nofpclass(inf nan) %not.inf.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__known_pzero_or_nan__fmul__not_inf_or_nan( |
| ; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_INF_OR_NAN]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %pzero.or.nan, %not.inf.or.nan |
| ret float %mul |
| } |
| |
| define nofpclass(nsub) float @ret__known_pzero_or_nan__fmul__not_inf_or_nan__insert_point(float nofpclass(inf sub norm nzero) %pzero.or.nan, float nofpclass(inf nan) %not.inf.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__known_pzero_or_nan__fmul__not_inf_or_nan__insert_point( |
| ; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_INF_OR_NAN]]) |
| ; CHECK-NEXT: [[BARRIER:%.*]] = call float @llvm.arithmetic.fence.f32(float [[MUL]]) |
| ; CHECK-NEXT: ret float [[BARRIER]] |
| ; |
| %mul = fmul float %pzero.or.nan, %not.inf.or.nan |
| %barrier = call float @llvm.arithmetic.fence.f32(float %mul) |
| ret float %barrier |
| } |
| |
| ; missing nnan lhs |
| define nofpclass(nsub) float @ret__not_inf__fmul__known_pzero_or_nan(float nofpclass(inf) %not.inf, float nofpclass(inf sub norm nzero) %pzero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__not_inf__fmul__known_pzero_or_nan( |
| ; CHECK-SAME: float nofpclass(inf) [[NOT_INF:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[NOT_INF]], [[PZERO_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.inf, %pzero.or.nan |
| ret float %mul |
| } |
| |
| ; -> copysign |
| define nofpclass(nsub) float @ret__not_inf_or_nan__fmul__known_pzero_or_nan(float nofpclass(inf nan) %not.inf.or.nan, float nofpclass(inf sub norm nzero) %pzero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__not_inf_or_nan__fmul__known_pzero_or_nan( |
| ; CHECK-SAME: float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_INF_OR_NAN]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.inf.or.nan, %pzero.or.nan |
| ret float %mul |
| } |
| |
| define nofpclass(nsub) float @ret__not_inf_or_nan__fmul__known_pzero_or_nan__insert_point(float nofpclass(inf nan) %not.inf.or.nan, float nofpclass(inf sub norm nzero) %pzero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__not_inf_or_nan__fmul__known_pzero_or_nan__insert_point( |
| ; CHECK-SAME: float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_INF_OR_NAN]]) |
| ; CHECK-NEXT: [[BARRIER:%.*]] = call float @llvm.arithmetic.fence.f32(float [[MUL]]) |
| ; CHECK-NEXT: ret float [[BARRIER]] |
| ; |
| %mul = fmul float %not.inf.or.nan, %pzero.or.nan |
| %barrier = call float @llvm.arithmetic.fence.f32(float %mul) |
| ret float %barrier |
| } |
| |
| ; Missing no-nan on RHS to turn into fneg |
| define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0_or_nan(float nofpclass(zero sub norm) %inf.or.nan, float nofpclass(zero pinf pnorm psub) %negative.non0.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0_or_nan( |
| ; CHECK-SAME: float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]], float nofpclass(pinf zero psub pnorm) [[NEGATIVE_NON0_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[INF_OR_NAN]], [[NEGATIVE_NON0_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %inf.or.nan, %negative.non0.or.nan |
| ret float %mul |
| } |
| |
| ; Missing no-nan on LHS to turn into fneg |
| define nofpclass(nsub) float @ret__known_negative_non0_or_nan__fmul__known_inf_or_nan(float nofpclass(zero pinf pnorm psub) %negative.non0.or.nan, float nofpclass(zero sub norm) %inf.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__known_negative_non0_or_nan__fmul__known_inf_or_nan( |
| ; CHECK-SAME: float nofpclass(pinf zero psub pnorm) [[NEGATIVE_NON0_OR_NAN:%.*]], float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NEGATIVE_NON0_OR_NAN]], [[INF_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %negative.non0.or.nan, %inf.or.nan |
| ret float %mul |
| } |
| |
| ; -> fneg |
| define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0(float nofpclass(zero sub norm) %inf.or.nan, float nofpclass(nan zero pinf pnorm psub) %negative.non0) { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0( |
| ; CHECK-SAME: float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]], float nofpclass(nan pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fneg float [[INF_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %inf.or.nan, %negative.non0 |
| ret float %mul |
| } |
| |
| define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0__insert_point(float nofpclass(zero sub norm) %inf.or.nan, float nofpclass(nan zero pinf pnorm psub) %negative.non0) { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0__insert_point( |
| ; CHECK-SAME: float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]], float nofpclass(nan pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fneg float [[INF_OR_NAN]] |
| ; CHECK-NEXT: [[BARRIER:%.*]] = call float @llvm.arithmetic.fence.f32(float [[MUL]]) |
| ; CHECK-NEXT: ret float [[BARRIER]] |
| ; |
| %mul = fmul float %inf.or.nan, %negative.non0 |
| %barrier = call float @llvm.arithmetic.fence.f32(float %mul) |
| ret float %barrier |
| } |
| |
| ; -> fneg |
| define nofpclass(nsub) float @ret__known_negative_non0__fmul__known_inf_or_nan(float nofpclass(nan zero pinf pnorm psub) %negative.non0, float nofpclass(zero sub norm) %inf.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__known_negative_non0__fmul__known_inf_or_nan( |
| ; CHECK-SAME: float nofpclass(nan pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]], float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fneg float [[INF_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %negative.non0, %inf.or.nan |
| ret float %mul |
| } |
| |
| define nofpclass(nsub) float @ret__known_negative_non0__fmul__known_inf_or_nan__insert_pt(float nofpclass(nan zero pinf pnorm psub) %negative.non0, float nofpclass(zero sub norm) %inf.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__known_negative_non0__fmul__known_inf_or_nan__insert_pt( |
| ; CHECK-SAME: float nofpclass(nan pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]], float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fneg float [[INF_OR_NAN]] |
| ; CHECK-NEXT: [[BARRIER:%.*]] = call float @llvm.arithmetic.fence.f32(float [[MUL]]) |
| ; CHECK-NEXT: ret float [[BARRIER]] |
| ; |
| %mul = fmul float %negative.non0, %inf.or.nan |
| %barrier = call float @llvm.arithmetic.fence.f32(float %mul) |
| ret float %barrier |
| } |
| |
| ; Cannot fold to fneg due to possible nsub input |
| define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0__daz(float nofpclass(zero sub norm) %inf.or.nan, float nofpclass(nan zero pinf pnorm psub) %negative.non0) #1 { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0__daz( |
| ; CHECK-SAME: float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]], float nofpclass(nan pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]]) #[[ATTR1]] { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[INF_OR_NAN]], [[NEGATIVE_NON0]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %inf.or.nan, %negative.non0 |
| ret float %mul |
| } |
| |
| ; Cannot fold to fneg due to possible nsub input |
| define nofpclass(nsub) float @ret__known_negative_non0__fmul__known_inf_or_nan__daz(float nofpclass(nan zero pinf pnorm psub) %negative.non0, float nofpclass(zero sub norm) %inf.or.nan) #1 { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__known_negative_non0__fmul__known_inf_or_nan__daz( |
| ; CHECK-SAME: float nofpclass(nan pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]], float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]]) #[[ATTR1]] { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NEGATIVE_NON0]], [[INF_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %negative.non0, %inf.or.nan |
| ret float %mul |
| } |
| |
| ; -> fneg |
| define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_nonlogical0__daz(float nofpclass(zero sub norm) %inf.or.nan, float nofpclass(nan zero pinf pnorm sub) %negative.nonlogical0) #1 { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_nonlogical0__daz( |
| ; CHECK-SAME: float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]], float nofpclass(nan pinf zero sub pnorm) [[NEGATIVE_NONLOGICAL0:%.*]]) #[[ATTR1]] { |
| ; CHECK-NEXT: [[MUL:%.*]] = fneg float [[INF_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %inf.or.nan, %negative.nonlogical0 |
| ret float %mul |
| } |
| |
| ; -> fneg |
| define nofpclass(nsub) float @ret__known_negative_nonlogical0__fmul__known_inf_or_nan__daz(float nofpclass(nan zero pinf pnorm sub) %negative.nonlogical0, float nofpclass(zero sub norm) %inf.or.nan) #1 { |
| ; CHECK-LABEL: define nofpclass(nsub) float @ret__known_negative_nonlogical0__fmul__known_inf_or_nan__daz( |
| ; CHECK-SAME: float nofpclass(nan pinf zero sub pnorm) [[NEGATIVE_NONLOGICAL0:%.*]], float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]]) #[[ATTR1]] { |
| ; CHECK-NEXT: [[MUL:%.*]] = fneg float [[INF_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %negative.nonlogical0, %inf.or.nan |
| ret float %mul |
| } |
| |
| ; Should be able to fold to copysign, helped by the lack of nan results. |
| define nofpclass(nan) float @ret_no_nan_result__known_pzero__fmul__not_inf(float nofpclass(inf sub norm nzero) %pzero.or.nan, float nofpclass(inf nan) %not.inf.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan_result__known_pzero__fmul__not_inf( |
| ; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[NOT_INF_OR_NAN]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %pzero.or.nan, %not.inf.or.nan |
| ret float %mul |
| } |
| |
| ; Should be able to fold to copysign, helped by the lack of nan results. |
| define nofpclass(nan) float @ret_no_nan_result__not_inf_or_nan__fmul__known_pzero_or_nan(float nofpclass(inf) %not.inf.or.nan, float nofpclass(inf sub norm nzero) %pzero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan_result__not_inf_or_nan__fmul__known_pzero_or_nan( |
| ; CHECK-SAME: float nofpclass(inf) [[NOT_INF_OR_NAN:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = call ninf float @llvm.copysign.f32(float 0.000000e+00, float [[NOT_INF_OR_NAN]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.inf.or.nan, %pzero.or.nan |
| ret float %mul |
| } |
| |
| ; -> fneg, with help of no nan results |
| define nofpclass(nan) float @ret_no_nan_result__known_inf_or_nan__fmul__known_negative_non0(float nofpclass(zero sub norm) %inf.or.nan, float nofpclass(zero pinf pnorm psub) %negative.non0) { |
| ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan_result__known_inf_or_nan__fmul__known_negative_non0( |
| ; CHECK-SAME: float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]], float nofpclass(pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fneg float [[INF_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %inf.or.nan, %negative.non0 |
| ret float %mul |
| } |
| |
| ; -> fneg, with help of no nan results |
| define nofpclass(nan) float @ret_no_nan_result__known_negative_non0__fmul__known_inf_or_nan(float nofpclass(zero pinf pnorm psub) %negative.non0, float nofpclass(zero sub norm) %inf.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan_result__known_negative_non0__fmul__known_inf_or_nan( |
| ; CHECK-SAME: float nofpclass(pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]], float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fneg float [[INF_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %negative.non0, %inf.or.nan |
| ret float %mul |
| } |
| |
| ; -> copysign, take no-infs-no-nans from invalid return |
| define nofpclass(inf nan) float @ret_noinf_nonan__known_pzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float %unknown) { |
| ; CHECK-LABEL: define nofpclass(nan inf) float @ret_noinf_nonan__known_pzero_or_nan__fmul__not_inf_or_nan( |
| ; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[UNKNOWN]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %pzero.or.nan, %unknown |
| ret float %mul |
| } |
| |
| ; -> copysign, take no-infs-no-nans from invalid return, commuted |
| define nofpclass(inf nan) float @ret_noinf_nonan__not_inf_or_nan__fmul__known_pzero_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float %unknown) { |
| ; CHECK-LABEL: define nofpclass(nan inf) float @ret_noinf_nonan__not_inf_or_nan__fmul__known_pzero_or_nan( |
| ; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[UNKNOWN]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %pzero.or.nan, %unknown |
| ret float %mul |
| } |
| |
| ; -> copysign, take no-infs from invalid return |
| define nofpclass(inf) float @ret_noinf__known_zero_or_nan__fmul__not_nan(float nofpclass(nan sub norm nzero) %pzero.or.inf, float nofpclass(nan) %not.nan) { |
| ; CHECK-LABEL: define nofpclass(inf) float @ret_noinf__known_zero_or_nan__fmul__not_nan( |
| ; CHECK-SAME: float nofpclass(nan nzero sub norm) [[PZERO_OR_INF:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[PZERO_OR_INF]], [[NOT_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %pzero.or.inf, %not.nan |
| ret float %mul |
| } |
| |
| ; -> copysign, take no-infs from invalid return, commuted |
| define nofpclass(inf) float @ret_noinf__noinf_or_nan__fmul__known_pzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(nan sub norm nzero) %pzero.or.inf) { |
| ; CHECK-LABEL: define nofpclass(inf) float @ret_noinf__noinf_or_nan__fmul__known_pzero_or_nan( |
| ; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(nan nzero sub norm) [[PZERO_OR_INF:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN]], [[PZERO_OR_INF]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.nan, %pzero.or.inf |
| ret float %mul |
| } |
| |
| ; -> copysign, take no-nans from invalid return |
| define nofpclass(nan) float @ret_nonan__known_zero_or_nan__fmul__not_nan(float nofpclass(nan sub norm nzero) %pzero.or.inf, float nofpclass(nan) %not.nan) { |
| ; CHECK-LABEL: define nofpclass(nan) float @ret_nonan__known_zero_or_nan__fmul__not_nan( |
| ; CHECK-SAME: float nofpclass(nan nzero sub norm) [[PZERO_OR_INF:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul nnan float [[PZERO_OR_INF]], [[NOT_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %pzero.or.inf, %not.nan |
| ret float %mul |
| } |
| |
| ; -> copysign, take no-nans from invalid return, commuted |
| define nofpclass(nan) float @ret_nonan__noinf_or_nan__fmul__known_pzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(nan sub norm nzero) %pzero.or.inf) { |
| ; CHECK-LABEL: define nofpclass(nan) float @ret_nonan__noinf_or_nan__fmul__known_pzero_or_nan( |
| ; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(nan nzero sub norm) [[PZERO_OR_INF:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul nnan float [[NOT_NAN]], [[PZERO_OR_INF]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.nan, %pzero.or.inf |
| ret float %mul |
| } |
| |
| define nofpclass(pinf) float @ret_nopinf__known_pzero_or_nan__fmul__not_nan(float nofpclass(nan sub norm nzero) %pzero.or.inf, float nofpclass(nan) %not.nan) { |
| ; CHECK-LABEL: define nofpclass(pinf) float @ret_nopinf__known_pzero_or_nan__fmul__not_nan( |
| ; CHECK-SAME: float nofpclass(nan nzero sub norm) [[PZERO_OR_INF:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[PZERO_OR_INF]], [[NOT_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %pzero.or.inf, %not.nan |
| ret float %mul |
| } |
| |
| define nofpclass(pinf) float @ret_nopinf__not_nan__fmul__known_zero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(nan sub norm nzero) %pzero.or.inf) { |
| ; CHECK-LABEL: define nofpclass(pinf) float @ret_nopinf__not_nan__fmul__known_zero_or_nan( |
| ; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(nan nzero sub norm) [[PZERO_OR_INF:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN]], [[PZERO_OR_INF]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.nan, %pzero.or.inf |
| ret float %mul |
| } |
| |
| define nofpclass(ninf) float @ret_noninf__known_pzero_or_nan__fmul__not_nan(float nofpclass(nan sub norm nzero) %pzero.or.inf, float nofpclass(nan) %not.nan) { |
| ; CHECK-LABEL: define nofpclass(ninf) float @ret_noninf__known_pzero_or_nan__fmul__not_nan( |
| ; CHECK-SAME: float nofpclass(nan nzero sub norm) [[PZERO_OR_INF:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[PZERO_OR_INF]], [[NOT_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %pzero.or.inf, %not.nan |
| ret float %mul |
| } |
| |
| define nofpclass(ninf) float @ret_noninf__not_nan__fmul__known_zero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(nan sub norm nzero) %pzero.or.inf) { |
| ; CHECK-LABEL: define nofpclass(ninf) float @ret_noninf__not_nan__fmul__known_zero_or_nan( |
| ; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(nan nzero sub norm) [[PZERO_OR_INF:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN]], [[PZERO_OR_INF]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.nan, %pzero.or.inf |
| ret float %mul |
| } |
| |
| ; no pinf result implies no infs if the signs of each operand are the same, must be +0 |
| define nofpclass(pinf) float @ret_nopinf__known_zero_or_pos_nan__fmul__not_nan_pos(float nofpclass(nan ninf sub norm) %zero.or.not.neg, float nofpclass(nan ninf nzero nsub nnorm) %not.nan.not.neg) { |
| ; CHECK-LABEL: define nofpclass(pinf) float @ret_nopinf__known_zero_or_pos_nan__fmul__not_nan_pos( |
| ; CHECK-SAME: float nofpclass(nan ninf sub norm) [[ZERO_OR_NOT_NEG:%.*]], float nofpclass(nan ninf nzero nsub nnorm) [[NOT_NAN_NOT_NEG:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[ZERO_OR_NOT_NEG]], [[NOT_NAN_NOT_NEG]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %zero.or.not.neg, %not.nan.not.neg |
| ret float %mul |
| } |
| |
| define nofpclass(pinf) float @ret_nopinf__not_nan_pos__fmul__known_zero_or_pos_nan(float nofpclass(nan ninf nsub nnorm) %not.nan.not.neg, float nofpclass(nan ninf nzero sub norm) %zero.or.not.neg) { |
| ; CHECK-LABEL: define nofpclass(pinf) float @ret_nopinf__not_nan_pos__fmul__known_zero_or_pos_nan( |
| ; CHECK-SAME: float nofpclass(nan ninf nsub nnorm) [[NOT_NAN_NOT_NEG:%.*]], float nofpclass(nan ninf nzero sub norm) [[ZERO_OR_NOT_NEG:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN_NOT_NEG]], [[ZERO_OR_NOT_NEG]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.nan.not.neg, %zero.or.not.neg |
| ret float %mul |
| } |
| |
| define nofpclass(pinf) float @ret_nopinf__known_zero_or_neg_nan__fmul__not_nan_neg(float nofpclass(nan pinf sub norm) %zero.or.not.pos, float nofpclass(nan pinf pzero psub pnorm) %not.nan.not.pos) { |
| ; CHECK-LABEL: define nofpclass(pinf) float @ret_nopinf__known_zero_or_neg_nan__fmul__not_nan_neg( |
| ; CHECK-SAME: float nofpclass(nan pinf sub norm) [[ZERO_OR_NOT_POS:%.*]], float nofpclass(nan pinf pzero psub pnorm) [[NOT_NAN_NOT_POS:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[ZERO_OR_NOT_POS]], [[NOT_NAN_NOT_POS]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %zero.or.not.pos, %not.nan.not.pos |
| ret float %mul |
| } |
| |
| define nofpclass(pinf) float @ret_nopinf__not_nan_neg__fmul__known_zero_or_neg_nan(float nofpclass(nan pinf pzero psub pnorm) %not.nan.not.pos, float nofpclass(nan pinf sub norm) %zero.or.not.pos) { |
| ; CHECK-LABEL: define nofpclass(pinf) float @ret_nopinf__not_nan_neg__fmul__known_zero_or_neg_nan( |
| ; CHECK-SAME: float nofpclass(nan pinf pzero psub pnorm) [[NOT_NAN_NOT_POS:%.*]], float nofpclass(nan pinf sub norm) [[ZERO_OR_NOT_POS:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN_NOT_POS]], [[ZERO_OR_NOT_POS]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.nan.not.pos, %zero.or.not.pos |
| ret float %mul |
| } |
| |
| define nofpclass(ninf) float @ret_noninf__known_zero_or_pos_nan__fmul__not_nan_pos(float nofpclass(nan ninf sub norm) %zero.or.not.neg, float nofpclass(nan ninf nzero nsub nnorm) %not.nan.not.neg) { |
| ; CHECK-LABEL: define nofpclass(ninf) float @ret_noninf__known_zero_or_pos_nan__fmul__not_nan_pos( |
| ; CHECK-SAME: float nofpclass(nan ninf sub norm) [[ZERO_OR_NOT_NEG:%.*]], float nofpclass(nan ninf nzero nsub nnorm) [[NOT_NAN_NOT_NEG:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[ZERO_OR_NOT_NEG]], [[NOT_NAN_NOT_NEG]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %zero.or.not.neg, %not.nan.not.neg |
| ret float %mul |
| } |
| |
| define nofpclass(ninf) float @ret_noninf__not_nan_pos__fmul__known_zero_or_pos_nan(float nofpclass(nan ninf nzero nsub nnorm) %not.nan.not.neg, float nofpclass(nan ninf sub norm) %zero.or.not.neg) { |
| ; CHECK-LABEL: define nofpclass(ninf) float @ret_noninf__not_nan_pos__fmul__known_zero_or_pos_nan( |
| ; CHECK-SAME: float nofpclass(nan ninf nzero nsub nnorm) [[NOT_NAN_NOT_NEG:%.*]], float nofpclass(nan ninf sub norm) [[ZERO_OR_NOT_NEG:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN_NOT_NEG]], [[ZERO_OR_NOT_NEG]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.nan.not.neg, %zero.or.not.neg |
| ret float %mul |
| } |
| |
| define nofpclass(ninf) float @ret_noninf__known_zero_or_pos_nan__fmul__not_nan_neg(float nofpclass(nan ninf sub norm) %zero.or.not.neg, float nofpclass(nan pinf pzero psub pnorm) %not.nan.not.pos) { |
| ; CHECK-LABEL: define nofpclass(ninf) float @ret_noninf__known_zero_or_pos_nan__fmul__not_nan_neg( |
| ; CHECK-SAME: float nofpclass(nan ninf sub norm) [[ZERO_OR_NOT_NEG:%.*]], float nofpclass(nan pinf pzero psub pnorm) [[NOT_NAN_NOT_POS:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[ZERO_OR_NOT_NEG]], [[NOT_NAN_NOT_POS]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %zero.or.not.neg, %not.nan.not.pos |
| ret float %mul |
| } |
| |
| define nofpclass(ninf) float @ret_noninf__not_nan_neg__fmul__known_zero_or_pos_nan(float nofpclass(nan pinf pzero psub pnorm) %not.nan.not.pos, float nofpclass(nan ninf sub norm) %zero.or.not.neg) { |
| ; CHECK-LABEL: define nofpclass(ninf) float @ret_noninf__not_nan_neg__fmul__known_zero_or_pos_nan( |
| ; CHECK-SAME: float nofpclass(nan pinf pzero psub pnorm) [[NOT_NAN_NOT_POS:%.*]], float nofpclass(nan ninf sub norm) [[ZERO_OR_NOT_NEG:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN_NOT_POS]], [[ZERO_OR_NOT_NEG]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.nan.not.pos, %zero.or.not.neg |
| ret float %mul |
| } |
| |
| define nofpclass(inf norm sub zero) float @ret_only_nan_results_fmul(float %x, float %y) { |
| ; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_only_nan_results_fmul( |
| ; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) { |
| ; CHECK-NEXT: ret float 0x7FF8000000000000 |
| ; |
| %mul = fmul float %x, %y |
| ret float %mul |
| } |
| |
| define nofpclass(inf norm sub zero snan) float @ret_only_qnan_results_fmul(float %x, float %y) { |
| ; CHECK-LABEL: define nofpclass(snan inf zero sub norm) float @ret_only_qnan_results_fmul( |
| ; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) { |
| ; CHECK-NEXT: ret float 0x7FF8000000000000 |
| ; |
| %mul = fmul float %x, %y |
| ret float %mul |
| } |
| |
| define nofpclass(inf norm sub zero qnan) float @ret_only_snan_results_fmul(float %x, float %y) { |
| ; CHECK-LABEL: define nofpclass(qnan inf zero sub norm) float @ret_only_snan_results_fmul( |
| ; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[Y]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %x, %y |
| ret float %mul |
| } |
| |
| define nofpclass(nan inf) float @ret_no_nan_no_inf__fmul_nonan_noinf__nonan_noinf(float nofpclass(inf nan) %x, float nofpclass(inf nan) %y) { |
| ; CHECK-LABEL: define nofpclass(nan inf) float @ret_no_nan_no_inf__fmul_nonan_noinf__nonan_noinf( |
| ; CHECK-SAME: float nofpclass(nan inf) [[X:%.*]], float nofpclass(nan inf) [[Y:%.*]]) { |
| ; CHECK-NEXT: [[FMUL:%.*]] = fmul nnan ninf float [[X]], [[Y]] |
| ; CHECK-NEXT: ret float [[FMUL]] |
| ; |
| %fmul = fmul float %x, %y |
| ret float %fmul |
| } |
| |
| define nofpclass(nan inf) float @ret_no_nan_no_inf__fmul_no_nan__normal_constant(float nofpclass(inf nan) %x) { |
| ; CHECK-LABEL: define nofpclass(nan inf) float @ret_no_nan_no_inf__fmul_no_nan__normal_constant( |
| ; CHECK-SAME: float nofpclass(nan inf) [[X:%.*]]) { |
| ; CHECK-NEXT: [[FMUL:%.*]] = fmul nnan ninf float [[X]], 4.000000e+00 |
| ; CHECK-NEXT: ret float [[FMUL]] |
| ; |
| %fmul = fmul float %x, 4.0 |
| ret float %fmul |
| } |
| |
| define nofpclass(nan) float @ret_no_nan__fmul_zero__unknown(float %unknown) { |
| ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_zero__unknown( |
| ; CHECK-SAME: float [[UNKNOWN:%.*]]) { |
| ; CHECK-NEXT: [[ZERO:%.*]] = call float @returns_zero() |
| ; CHECK-NEXT: [[FMUL:%.*]] = fmul nnan float [[ZERO]], [[UNKNOWN]] |
| ; CHECK-NEXT: ret float [[FMUL]] |
| ; |
| %zero = call float @returns_zero() |
| %fmul = fmul float %zero, %unknown |
| ret float %fmul |
| } |
| |
| define nofpclass(nan) float @ret_no_nan__fmul_unknown__zero(float %unknown) { |
| ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_unknown__zero( |
| ; CHECK-SAME: float [[UNKNOWN:%.*]]) { |
| ; CHECK-NEXT: [[ZERO:%.*]] = call float @returns_zero() |
| ; CHECK-NEXT: [[FMUL:%.*]] = fmul nnan float [[UNKNOWN]], [[ZERO]] |
| ; CHECK-NEXT: ret float [[FMUL]] |
| ; |
| %zero = call float @returns_zero() |
| %fmul = fmul float %unknown, %zero |
| ret float %fmul |
| } |
| |
| define nofpclass(nan) float @ret_no_nan__fmul_pzero__unknown(float %unknown) { |
| ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_pzero__unknown( |
| ; CHECK-SAME: float [[UNKNOWN:%.*]]) { |
| ; CHECK-NEXT: [[PZERO:%.*]] = call float @returns_pzero() |
| ; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[UNKNOWN]]) |
| ; CHECK-NEXT: ret float [[FMUL]] |
| ; |
| %pzero = call float @returns_pzero() |
| %fmul = fmul float %pzero, %unknown |
| ret float %fmul |
| } |
| |
| define nofpclass(nan) float @ret_no_nan__fmul_unknown__pzero(float %unknown) { |
| ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_unknown__pzero( |
| ; CHECK-SAME: float [[UNKNOWN:%.*]]) { |
| ; CHECK-NEXT: [[PZERO:%.*]] = call float @returns_pzero() |
| ; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[UNKNOWN]]) |
| ; CHECK-NEXT: ret float [[FMUL]] |
| ; |
| %pzero = call float @returns_pzero() |
| %fmul = fmul float %unknown, %pzero |
| ret float %fmul |
| } |
| |
| define nofpclass(nan) float @ret_no_nan__fmul_nzero__unknown(float %unknown) { |
| ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_nzero__unknown( |
| ; CHECK-SAME: float [[UNKNOWN:%.*]]) { |
| ; CHECK-NEXT: [[NZERO:%.*]] = call float @returns_nzero() |
| ; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[UNKNOWN]] |
| ; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]]) |
| ; CHECK-NEXT: ret float [[FMUL]] |
| ; |
| %nzero = call float @returns_nzero() |
| %fmul = fmul float %nzero, %unknown |
| ret float %fmul |
| } |
| |
| define nofpclass(nan) float @ret_no_nan__fmul_nzero__unknown_insert_point(float %unknown) { |
| ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_nzero__unknown_insert_point( |
| ; CHECK-SAME: float [[UNKNOWN:%.*]]) { |
| ; CHECK-NEXT: [[NZERO:%.*]] = call float @returns_nzero() |
| ; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[UNKNOWN]] |
| ; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]]) |
| ; CHECK-NEXT: [[BARRIER:%.*]] = call float @llvm.arithmetic.fence.f32(float [[FMUL]]) |
| ; CHECK-NEXT: ret float [[BARRIER]] |
| ; |
| %nzero = call float @returns_nzero() |
| %fmul = fmul float %nzero, %unknown |
| %barrier =call float @llvm.arithmetic.fence.f32(float %fmul) |
| ret float %barrier |
| } |
| |
| define nofpclass(nan) float @ret_no_nan__fmul_unknown__nzero(float %unknown) { |
| ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_unknown__nzero( |
| ; CHECK-SAME: float [[UNKNOWN:%.*]]) { |
| ; CHECK-NEXT: [[NZERO:%.*]] = call float @returns_nzero() |
| ; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[UNKNOWN]] |
| ; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]]) |
| ; CHECK-NEXT: ret float [[FMUL]] |
| ; |
| %nzero = call float @returns_nzero() |
| %fmul = fmul float %unknown, %nzero |
| ret float %fmul |
| } |
| |
| define nofpclass(ninf) float @ret_ninf__fmul_nnan_zero__unknown(float %unknown) { |
| ; CHECK-LABEL: define nofpclass(ninf) float @ret_ninf__fmul_nnan_zero__unknown( |
| ; CHECK-SAME: float [[UNKNOWN:%.*]]) { |
| ; CHECK-NEXT: [[ZERO:%.*]] = call float @returns_zero() |
| ; CHECK-NEXT: [[FMUL:%.*]] = fmul nnan float [[ZERO]], [[UNKNOWN]] |
| ; CHECK-NEXT: ret float [[FMUL]] |
| ; |
| %zero = call float @returns_zero() |
| %fmul = fmul nnan float %zero, %unknown |
| ret float %fmul |
| } |
| |
| define nofpclass(ninf) float @ret_ninf__fmul_nnan_unknown__zero(float %unknown) { |
| ; CHECK-LABEL: define nofpclass(ninf) float @ret_ninf__fmul_nnan_unknown__zero( |
| ; CHECK-SAME: float [[UNKNOWN:%.*]]) { |
| ; CHECK-NEXT: [[ZERO:%.*]] = call float @returns_zero() |
| ; CHECK-NEXT: [[FMUL:%.*]] = fmul nnan float [[UNKNOWN]], [[ZERO]] |
| ; CHECK-NEXT: ret float [[FMUL]] |
| ; |
| %zero = call float @returns_zero() |
| %fmul = fmul nnan float %unknown, %zero |
| ret float %fmul |
| } |
| |
| ; -> copysign + fneg |
| define nofpclass(snan) float @known__nzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm pzero) %nzero.or.nan, float nofpclass(inf nan) %not.inf.or.nan) { |
| ; CHECK-LABEL: define nofpclass(snan) float @known__nzero_or_nan__fmul__not_inf_or_nan( |
| ; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = fneg contract float [[NOT_INF_OR_NAN]] |
| ; CHECK-NEXT: [[MUL:%.*]] = call contract float @llvm.copysign.f32(float [[NZERO_OR_NAN]], float [[TMP1]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul contract float %nzero.or.nan, %not.inf.or.nan |
| ret float %mul |
| } |
| |
| define nofpclass(snan) float @known__nzero_or_nan__fmul__not_inf_or_nan__insert_point(float nofpclass(inf sub norm pzero) %nzero.or.nan, float nofpclass(inf nan) %not.inf.or.nan) { |
| ; CHECK-LABEL: define nofpclass(snan) float @known__nzero_or_nan__fmul__not_inf_or_nan__insert_point( |
| ; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = fneg contract float [[NOT_INF_OR_NAN]] |
| ; CHECK-NEXT: [[MUL:%.*]] = call contract float @llvm.copysign.f32(float [[NZERO_OR_NAN]], float [[TMP1]]) |
| ; CHECK-NEXT: [[BARRIER:%.*]] = call float @llvm.arithmetic.fence.f32(float [[MUL]]) |
| ; CHECK-NEXT: ret float [[BARRIER]] |
| ; |
| %mul = fmul contract float %nzero.or.nan, %not.inf.or.nan |
| %barrier = call float @llvm.arithmetic.fence.f32(float %mul) |
| ret float %barrier |
| } |
| |
| ; -> copysign + fneg |
| define nofpclass(snan) float @known__not_inf_or_nan__fmul__nzero_or_nan(float nofpclass(inf nan) %not.inf.or.nan, float nofpclass(inf sub norm pzero) %nzero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(snan) float @known__not_inf_or_nan__fmul__nzero_or_nan( |
| ; CHECK-SAME: float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = fneg contract float [[NOT_INF_OR_NAN]] |
| ; CHECK-NEXT: [[MUL:%.*]] = call contract float @llvm.copysign.f32(float [[NZERO_OR_NAN]], float [[TMP1]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul contract float %not.inf.or.nan, %nzero.or.nan |
| ret float %mul |
| } |
| |
| ; cannot replace with copysign + fneg |
| define nofpclass(snan) float @known__nzero_or_nan__fmul__not_inf(float nofpclass(inf sub norm pzero) %nzero.or.nan, float nofpclass(inf) %not.inf) { |
| ; CHECK-LABEL: define nofpclass(snan) float @known__nzero_or_nan__fmul__not_inf( |
| ; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float nofpclass(inf) [[NOT_INF:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[NZERO_OR_NAN]], [[NOT_INF]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %nzero.or.nan, %not.inf |
| ret float %mul |
| } |
| |
| ; cannot replace with copysign + fneg |
| define nofpclass(snan) float @known__not_inf__fmul__nzero_or_nan(float nofpclass(inf) %not.inf, float nofpclass(inf sub norm pzero) %nzero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(snan) float @known__not_inf__fmul__nzero_or_nan( |
| ; CHECK-SAME: float nofpclass(inf) [[NOT_INF:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[NOT_INF]], [[NZERO_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.inf, %nzero.or.nan |
| ret float %mul |
| } |
| |
| ; cannot replace with copysign + fneg |
| define nofpclass(snan) float @known__nzero_or_nan__fmul__not_nan(float nofpclass(inf sub norm pzero) %nzero.or.nan, float nofpclass(nan) %not.nan) { |
| ; CHECK-LABEL: define nofpclass(snan) float @known__nzero_or_nan__fmul__not_nan( |
| ; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul contract float [[NZERO_OR_NAN]], [[NOT_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul contract float %nzero.or.nan, %not.nan |
| ret float %mul |
| } |
| |
| ; cannot replace with copysign + fneg |
| define nofpclass(snan) float @known__not_nan__fmul__nzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm pzero) %nzero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(snan) float @known__not_nan__fmul__nzero_or_nan( |
| ; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul contract float [[NOT_NAN]], [[NZERO_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul contract float %not.nan, %nzero.or.nan |
| ret float %mul |
| } |
| |
| ; -> copysign + fneg, no infinity from return |
| define nofpclass(inf) float @ret_noinf__nzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm pzero) %nzero.or.nan, float nofpclass(nan) %not.nan) { |
| ; CHECK-LABEL: define nofpclass(inf) float @ret_noinf__nzero_or_nan__fmul__not_inf_or_nan( |
| ; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NZERO_OR_NAN]], [[NOT_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %nzero.or.nan, %not.nan |
| ret float %mul |
| } |
| |
| ; -> copysign + fneg, no infinity from return |
| define nofpclass(inf) float @ret_noinf__not_inf_or_nan__fmul__nzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm pzero) %nzero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(inf) float @ret_noinf__not_inf_or_nan__fmul__nzero_or_nan( |
| ; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN]], [[NZERO_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.nan, %nzero.or.nan |
| ret float %mul |
| } |
| |
| ; -> copysign + fneg, no nans from return |
| define nofpclass(nan) float @ret_nonan__nzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm pzero) %nzero.or.nan, float nofpclass(nan) %not.nan) { |
| ; CHECK-LABEL: define nofpclass(nan) float @ret_nonan__nzero_or_nan__fmul__not_inf_or_nan( |
| ; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[NOT_NAN]] |
| ; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %nzero.or.nan, %not.nan |
| ret float %mul |
| } |
| |
| ; -> copysign + fneg, no nans from return |
| define nofpclass(nan) float @ret_nonan__not_inf_or_nan__fmul__nzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm pzero) %nzero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(nan) float @ret_nonan__not_inf_or_nan__fmul__nzero_or_nan( |
| ; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[NOT_NAN]] |
| ; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.nan, %nzero.or.nan |
| ret float %mul |
| } |
| |
| ; -> copysign + fneg, no infinity from flag |
| define nofpclass(snan) float @ret__nzero_or_nan__fmul_ninf__not_inf_or_nan(float nofpclass(inf sub norm pzero) %nzero.or.nan, float nofpclass(nan) %not.nan) { |
| ; CHECK-LABEL: define nofpclass(snan) float @ret__nzero_or_nan__fmul_ninf__not_inf_or_nan( |
| ; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = fneg ninf float [[NOT_NAN]] |
| ; CHECK-NEXT: [[MUL:%.*]] = call ninf float @llvm.copysign.f32(float [[NZERO_OR_NAN]], float [[TMP1]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul ninf float %nzero.or.nan, %not.nan |
| ret float %mul |
| } |
| |
| ; -> copysign + fneg, no infinity from flag |
| define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__nzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm pzero) %nzero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__nzero_or_nan( |
| ; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = fneg ninf float [[NOT_NAN]] |
| ; CHECK-NEXT: [[MUL:%.*]] = call ninf float @llvm.copysign.f32(float [[NZERO_OR_NAN]], float [[TMP1]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul ninf float %not.nan, %nzero.or.nan |
| ret float %mul |
| } |
| |
| ; -> copysign + fneg, no nan from flag |
| define nofpclass(snan) float @ret__nzero_or_nan__fmul_nnan__not_inf_or_nan(float nofpclass(inf sub norm pzero) %nzero.or.nan, float %unknown) { |
| ; CHECK-LABEL: define nofpclass(snan) float @ret__nzero_or_nan__fmul_nnan__not_inf_or_nan( |
| ; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = fneg nnan float [[UNKNOWN]] |
| ; CHECK-NEXT: [[MUL:%.*]] = call nnan float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul nnan float %nzero.or.nan, %unknown |
| ret float %mul |
| } |
| |
| ; -> copysign + fneg, no nan from flag |
| define nofpclass(snan) float @not_inf_or_nan__fmul_nnan__nzero_or_nan(float %unknown, float nofpclass(inf sub norm pzero) %nzero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(snan) float @not_inf_or_nan__fmul_nnan__nzero_or_nan( |
| ; CHECK-SAME: float [[UNKNOWN:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = fneg nnan float [[UNKNOWN]] |
| ; CHECK-NEXT: [[MUL:%.*]] = call nnan float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul nnan float %unknown, %nzero.or.nan |
| ret float %mul |
| } |
| |
| ; -> copysign |
| define nofpclass(snan) float @known__pzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float nofpclass(inf nan) %not.inf.or.nan) { |
| ; CHECK-LABEL: define nofpclass(snan) float @known__pzero_or_nan__fmul__not_inf_or_nan( |
| ; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = call contract float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_INF_OR_NAN]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul contract float %pzero.or.nan, %not.inf.or.nan |
| ret float %mul |
| } |
| |
| ; -> copysign |
| define nofpclass(snan) float @known__not_inf_or_nan__fmul__pzero_or_nan(float nofpclass(inf nan) %not.inf.or.nan, float nofpclass(inf sub norm nzero) %pzero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(snan) float @known__not_inf_or_nan__fmul__pzero_or_nan( |
| ; CHECK-SAME: float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = call contract float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_INF_OR_NAN]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul contract float %not.inf.or.nan, %pzero.or.nan |
| ret float %mul |
| } |
| |
| ; cannot replace with copysign |
| define nofpclass(snan) float @known__pzero_or_nan__fmul__not_inf(float nofpclass(inf sub norm nzero) %pzero.or.nan, float nofpclass(inf) %not.inf) { |
| ; CHECK-LABEL: define nofpclass(snan) float @known__pzero_or_nan__fmul__not_inf( |
| ; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float nofpclass(inf) [[NOT_INF:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[PZERO_OR_NAN]], [[NOT_INF]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %pzero.or.nan, %not.inf |
| ret float %mul |
| } |
| |
| ; cannot replace with copysign |
| define nofpclass(snan) float @known__not_inf__fmul__pzero_or_nan(float nofpclass(inf) %not.inf, float nofpclass(inf sub norm nzero) %pzero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(snan) float @known__not_inf__fmul__pzero_or_nan( |
| ; CHECK-SAME: float nofpclass(inf) [[NOT_INF:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[NOT_INF]], [[PZERO_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.inf, %pzero.or.nan |
| ret float %mul |
| } |
| |
| ; cannot replace with copysign |
| define nofpclass(snan) float @known__pzero_or_nan__fmul__not_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float nofpclass(nan) %not.nan) { |
| ; CHECK-LABEL: define nofpclass(snan) float @known__pzero_or_nan__fmul__not_nan( |
| ; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul contract float [[PZERO_OR_NAN]], [[NOT_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul contract float %pzero.or.nan, %not.nan |
| ret float %mul |
| } |
| |
| ; cannot replace with copysign |
| define nofpclass(snan) float @known__not_nan__fmul__pzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm nzero) %pzero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(snan) float @known__not_nan__fmul__pzero_or_nan( |
| ; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul contract float [[NOT_NAN]], [[PZERO_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul contract float %not.nan, %pzero.or.nan |
| ret float %mul |
| } |
| |
| ; -> copysign, no infinity from return |
| define nofpclass(inf) float @ret_noinf__pzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float nofpclass(nan) %not.nan) { |
| ; CHECK-LABEL: define nofpclass(inf) float @ret_noinf__pzero_or_nan__fmul__not_inf_or_nan( |
| ; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[PZERO_OR_NAN]], [[NOT_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %pzero.or.nan, %not.nan |
| ret float %mul |
| } |
| |
| ; -> copysign, no infinity from return |
| define nofpclass(inf) float @ret_noinf__not_inf_or_nan__fmul__pzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm nzero) %pzero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(inf) float @ret_noinf__not_inf_or_nan__fmul__pzero_or_nan( |
| ; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN]], [[PZERO_OR_NAN]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul float %not.nan, %pzero.or.nan |
| ret float %mul |
| } |
| |
| ; -> copysign, no infinity from flag |
| define nofpclass(snan) float @ret__pzero_or_nan__fmul_ninf__not_inf_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float nofpclass(nan) %not.nan) { |
| ; CHECK-LABEL: define nofpclass(snan) float @ret__pzero_or_nan__fmul_ninf__not_inf_or_nan( |
| ; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = call ninf float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_NAN]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul ninf float %pzero.or.nan, %not.nan |
| ret float %mul |
| } |
| |
| ; -> copysign, no infinity from flag |
| define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__pzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm nzero) %pzero.or.nan) { |
| ; CHECK-LABEL: define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__pzero_or_nan( |
| ; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = call ninf float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_NAN]]) |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %mul = fmul ninf float %not.nan, %pzero.or.nan |
| ret float %mul |
| } |
| |
| define nofpclass(nan inf norm sub) float @zero_result_demands_sub_source_lhs(i1 %cond, float %unknown0, float %unknown1) { |
| ; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_demands_sub_source_lhs( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) { |
| ; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub() |
| ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[SUB]], float [[UNKNOWN0]] |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf float [[SELECT]], [[UNKNOWN1]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %sub = call float @returns_sub() |
| %select = select i1 %cond, float %sub, float %unknown0 |
| %mul = fmul float %select, %unknown1 |
| ret float %mul |
| } |
| |
| define nofpclass(nan inf norm sub) float @zero_result_demands_sub_source_rhs(i1 %cond, float %unknown0, float %unknown1) { |
| ; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_demands_sub_source_rhs( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) { |
| ; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub() |
| ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[SUB]], float [[UNKNOWN0]] |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf float [[UNKNOWN1]], [[SELECT]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %sub = call float @returns_sub() |
| %select = select i1 %cond, float %sub, float %unknown0 |
| %mul = fmul float %unknown1, %select |
| ret float %mul |
| } |
| |
| define nofpclass(nan inf norm sub) float @zero_result_demands_norm_source_lhs(i1 %cond, float %unknown0, float %unknown1) { |
| ; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_demands_norm_source_lhs( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) { |
| ; CHECK-NEXT: [[NORM:%.*]] = call float @returns_norm() |
| ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[NORM]], float [[UNKNOWN0]] |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf float [[SELECT]], [[UNKNOWN1]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %norm = call float @returns_norm() |
| %select = select i1 %cond, float %norm, float %unknown0 |
| %mul = fmul float %select, %unknown1 |
| ret float %mul |
| } |
| |
| define nofpclass(nan inf norm sub) float @zero_result_demands_norm_source_rhs(i1 %cond, float %unknown0, float %unknown1) { |
| ; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_demands_norm_source_rhs( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) { |
| ; CHECK-NEXT: [[NORM:%.*]] = call float @returns_norm() |
| ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[NORM]], float [[UNKNOWN0]] |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf float [[UNKNOWN1]], [[SELECT]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %norm = call float @returns_norm() |
| %select = select i1 %cond, float %norm, float %unknown0 |
| %mul = fmul float %unknown1, %select |
| ret float %mul |
| } |
| |
| define nofpclass(nan inf norm zero) float @sub_result_demands_norm_source_lhs(i1 %cond, float %unknown0, float %unknown1) { |
| ; CHECK-LABEL: define nofpclass(nan inf zero norm) float @sub_result_demands_norm_source_lhs( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) { |
| ; CHECK-NEXT: [[NORM:%.*]] = call float @returns_norm() |
| ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[NORM]], float [[UNKNOWN0]] |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf float [[SELECT]], [[UNKNOWN1]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %norm = call float @returns_norm() |
| %select = select i1 %cond, float %norm, float %unknown0 |
| %mul = fmul float %select, %unknown1 |
| ret float %mul |
| } |
| |
| define nofpclass(nan inf norm zero) float @sub_result_demands_norm_source_rhs(i1 %cond, float %unknown0, float %unknown1) { |
| ; CHECK-LABEL: define nofpclass(nan inf zero norm) float @sub_result_demands_norm_source_rhs( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) { |
| ; CHECK-NEXT: [[NORM:%.*]] = call float @returns_norm() |
| ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[NORM]], float [[UNKNOWN0]] |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf float [[UNKNOWN1]], [[SELECT]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %norm = call float @returns_norm() |
| %select = select i1 %cond, float %norm, float %unknown0 |
| %mul = fmul float %unknown1, %select |
| ret float %mul |
| } |
| |
| define nofpclass(nan inf sub zero) float @norm_result_demands_sub_source_lhs(i1 %cond, float %unknown0, float %unknown1) { |
| ; CHECK-LABEL: define nofpclass(nan inf zero sub) float @norm_result_demands_sub_source_lhs( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) { |
| ; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub() |
| ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[SUB]], float [[UNKNOWN0]] |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf float [[SELECT]], [[UNKNOWN1]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %sub = call float @returns_sub() |
| %select = select i1 %cond, float %sub, float %unknown0 |
| %mul = fmul float %select, %unknown1 |
| ret float %mul |
| } |
| |
| define nofpclass(nan inf sub zero) float @norm_result_demands_sub_source_rhs(i1 %cond, float %unknown0, float %unknown1) { |
| ; CHECK-LABEL: define nofpclass(nan inf zero sub) float @norm_result_demands_sub_source_rhs( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) { |
| ; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub() |
| ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[SUB]], float [[UNKNOWN0]] |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf float [[UNKNOWN1]], [[SELECT]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %sub = call float @returns_sub() |
| %select = select i1 %cond, float %sub, float %unknown0 |
| %mul = fmul float %unknown1, %select |
| ret float %mul |
| } |
| |
| define nofpclass(snan) float @qnan_result_square_demands_snan(i1 noundef %cond, float noundef %unknown0) { |
| ; CHECK-LABEL: define nofpclass(snan) float @qnan_result_square_demands_snan( |
| ; CHECK-SAME: i1 noundef [[COND:%.*]], float noundef [[UNKNOWN0:%.*]]) { |
| ; CHECK-NEXT: [[SNAN:%.*]] = call noundef float @returns_snan() |
| ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[SNAN]], float [[UNKNOWN0]] |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[SELECT]], [[SELECT]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %snan = call noundef float @returns_snan() |
| %select = select i1 %cond, float %snan, float %unknown0 |
| %mul = fmul float %select, %select |
| ret float %mul |
| } |
| |
| define nofpclass(snan) float @qnan_result_demands_snan_lhs(i1 %cond, float %unknown0, float %unknown1) { |
| ; CHECK-LABEL: define nofpclass(snan) float @qnan_result_demands_snan_lhs( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) { |
| ; CHECK-NEXT: [[SNAN:%.*]] = call float @returns_snan() |
| ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[SNAN]], float [[UNKNOWN0]] |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[SELECT]], [[UNKNOWN1]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %snan = call float @returns_snan() |
| %select = select i1 %cond, float %snan, float %unknown0 |
| %mul = fmul float %select, %unknown1 |
| ret float %mul |
| } |
| |
| define nofpclass(snan) float @qnan_result_demands_snan_rhs(i1 %cond, float %unknown0, float %unknown1) { |
| ; CHECK-LABEL: define nofpclass(snan) float @qnan_result_demands_snan_rhs( |
| ; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) { |
| ; CHECK-NEXT: [[SNAN:%.*]] = call float @returns_snan() |
| ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[SNAN]], float [[UNKNOWN0]] |
| ; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN1]], [[SELECT]] |
| ; CHECK-NEXT: ret float [[MUL]] |
| ; |
| %snan = call float @returns_snan() |
| %select = select i1 %cond, float %snan, float %unknown0 |
| %mul = fmul float %unknown1, %select |
| ret float %mul |
| } |
| |
| attributes #0 = { denormal_fpenv(preservesign) } |
| attributes #1 = { denormal_fpenv(dynamic) } |