:p
atchew
Login
Fixes for scalbn and muladd. r~ Richard Henderson (12): fpu: Return struct from parts{64,128}_scalbn fpu: Reorganize partsN(muladd) fpu: Return struct from parts{64,128}_muladd fpu: Hoist nan check in partsN_addsub fpu: Simplify 0 +/- N case in parts_addsub fpu: Use parts64_round_to_int in parts_s390_divide_to_integer target/s390x: Move float{32,64}_s390_divide_to_integer target/arm: Use FloatParts64 in bfdotadd_ebf target/arm: Drop oddstatus from is_ebf and bfdotadd_ebf target/arm: Use FloatParts64 in f16_dotadd fpu: Saturate the exponent in uncanon_normal fpu: Introduce exp_scalbn include/fpu/softfloat-parts.h | 12 ++ include/fpu/softfloat.h | 11 -- target/arm/tcg/vec_internal.h | 12 +- fpu/softfloat.c | 236 ++++++++-------------------------- target/arm/tcg/sme_helper.c | 102 +++++++-------- target/arm/tcg/vec_helper.c | 127 +++++++++--------- target/s390x/tcg/fpu_helper.c | 135 +++++++++++++++++++ fpu/softfloat-parts.c.inc | 236 ++++++++++++++++------------------ 8 files changed, 424 insertions(+), 447 deletions(-) -- 2.43.0
At the same time, export. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 3 +++ fpu/softfloat.c | 18 +++++++++--------- fpu/softfloat-parts.c.inc | 14 ++++++++------ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/include/fpu/softfloat-parts.h b/include/fpu/softfloat-parts.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-parts.h +++ b/include/fpu/softfloat-parts.h @@ -XXX,XX +XXX,XX @@ FloatParts128 parts128_round_to_int(const FloatParts128 *a, FloatParts64 parts64_round_to_fmt(const FloatParts64 *p, float_status *s, const FloatFmt *fmt); +FloatParts64 parts64_scalbn(const FloatParts64 *a, int n, float_status *s); +FloatParts128 parts128_scalbn(const FloatParts128 *a, int n, float_status *s); + #endif diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ float16 float16_muladd_scalbn(float16 a, float16 b, float16 c, /* Before rounding, scale. */ if (scale) { - parts64_scalbn(pr, scale, status); + *pr = parts64_scalbn(pr, scale, status); } parts64_uncanon(pr, status, &float16_params, false); /* After rounding, apply negate result, especially for -0.0. */ @@ -XXX,XX +XXX,XX @@ float32_muladd_scalbn(float32 a, float32 b, float32 c, /* Before rounding, scale. */ if (scale) { - parts64_scalbn(pr, scale, status); + *pr = parts64_scalbn(pr, scale, status); } parts64_uncanon(pr, status, &float32_params, false); /* After rounding, apply negate result, especially for -0.0. */ @@ -XXX,XX +XXX,XX @@ float64_muladd_scalbn(float64 a, float64 b, float64 c, /* Before rounding, scale. */ if (scale) { - parts64_scalbn(pr, scale, status); + *pr = parts64_scalbn(pr, scale, status); } parts64_uncanon(pr, status, &float64_params, false); /* After rounding, apply negate result, especially for -0.0. */ @@ -XXX,XX +XXX,XX @@ float16 float16_scalbn(float16 a, int n, float_status *status) { FloatParts64 p = float16_unpack_canonical(a, status); - parts64_scalbn(&p, n, status); + p = parts64_scalbn(&p, n, status); return float16_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float32 float32_scalbn(float32 a, int n, float_status *status) { FloatParts64 p = float32_unpack_canonical(a, status); - parts64_scalbn(&p, n, status); + p = parts64_scalbn(&p, n, status); return float32_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float64 float64_scalbn(float64 a, int n, float_status *status) { FloatParts64 p = float64_unpack_canonical(a, status); - parts64_scalbn(&p, n, status); + p = parts64_scalbn(&p, n, status); return float64_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_scalbn(bfloat16 a, int n, float_status *status) { FloatParts64 p = bfloat16_unpack_canonical(a, status); - parts64_scalbn(&p, n, status); + p = parts64_scalbn(&p, n, status); return bfloat16_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float128 float128_scalbn(float128 a, int n, float_status *status) { FloatParts128 p = float128_unpack_canonical(a, status); - parts128_scalbn(&p, n, status); + p = parts128_scalbn(&p, n, status); return float128_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_scalbn(floatx80 a, int n, float_status *status) if (!floatx80_unpack_canonical(&p, a, status)) { return floatx80_default_nan(status); } - parts128_scalbn(&p, n, status); + p = parts128_scalbn(&p, n, status); return floatx80_round_pack_canonical(&p, status); } diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ FloatRelation partsN(compare)(const FloatPartsN *a, const FloatPartsN *b, /* * Multiply A by 2 raised to the power N. */ -static void partsN(scalbn)(FloatPartsN *a, int n, float_status *s) +FloatPartsN partsN(scalbn)(const FloatPartsN *a, int n, float_status *s) { switch (a->cls) { case float_class_snan: case float_class_qnan: - *a = partsN(return_nan)(a, s); - break; + return partsN(return_nan)(a, s); case float_class_zero: case float_class_inf: - break; + return *a; case float_class_denormal: float_raise(float_flag_input_denormal_used, s); /* fall through */ case float_class_normal: - a->exp += MIN(MAX(n, -0x10000), 0x10000); - break; + { + FloatPartsN r = *a; + r.exp += MIN(MAX(n, -0x10000), 0x10000); + return r; + } default: g_assert_not_reached(); } -- 2.43.0
Check the likely case of normal product and normal or zero addend first; shift NaN and infinity detection down; end with zero product + addend. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 156 +++++++++++++++++--------------------- 1 file changed, 71 insertions(+), 85 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, FloatPartsN *c, int flags, float_status *s) { - int ab_mask, abc_mask; - FloatPartsW p_widen, c_widen; + int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); + int c_mask = float_cmask(c->cls); + int abc_mask = ab_mask | c_mask; + bool c_sign = c->sign ^ !!(flags & float_muladd_negate_c); + bool p_sign = a->sign ^ b->sign ^ !!(flags & float_muladd_negate_product); - ab_mask = float_cmask(a->cls) | float_cmask(b->cls); - abc_mask = float_cmask(c->cls) | ab_mask; + /* + * The "likely" case is A and B normal, so that the product is normal, + * and C normal or zero so that the result is normal. + */ + int likely_mask = ab_mask | (c_mask & ~float_cmask_zero); + if (likely(cmask_is_only_normals(likely_mask))) { + record_denormals_used(abc_mask, s); + + /* Perform the multiplication step. */ + FloatPartsW p_widen = { .sign = p_sign, .exp = a->exp + b->exp + 1 }; + fracN(mulw)(&p_widen, a, b); + if (!(p_widen.frac_hi & DECOMPOSED_IMPLICIT_BIT)) { + fracW(add)(&p_widen, &p_widen, &p_widen); + p_widen.exp -= 1; + } + + /* Perform the addition step. */ + if (!(c_mask & float_cmask_zero)) { + /* Zero-extend C to less significant bits. */ + FloatPartsW c_widen = { .sign = c_sign, .exp = c->exp }; + fracN(widen)(&c_widen, c); + + if (p_sign == c_sign) { + partsW(add_normal)(&p_widen, &c_widen); + } else if (!partsW(sub_normal)(&p_widen, &c_widen)) { + goto return_sub_zero; + } + } + + /* Narrow with sticky bit, for proper rounding later. */ + fracN(truncjam)(a, &p_widen); + a->sign = p_widen.sign; + a->exp = p_widen.exp; + return a; + } /* * It is implementation-defined whether the cases of (0,inf,qnan) @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, return a; } - if (flags & float_muladd_negate_c) { - c->sign ^= 1; + if (unlikely(ab_mask == float_cmask_infzero)) { + /* Inf * Zero == NaN */ + float_raise(float_flag_invalid | float_flag_invalid_imz, s); + goto d_nan; } - /* Compute the sign of the product into A. */ - a->sign ^= b->sign; - if (flags & float_muladd_negate_product) { - a->sign ^= 1; - } - - if (unlikely(!cmask_is_only_normals(ab_mask))) { - if (unlikely(ab_mask == float_cmask_infzero)) { - float_raise(float_flag_invalid | float_flag_invalid_imz, s); + if (unlikely(ab_mask & float_cmask_inf)) { + if ((c_mask & float_cmask_inf) && p_sign != c_sign) { + /* Inf - Inf == NaN */ + float_raise(float_flag_invalid | float_flag_invalid_isi, s); goto d_nan; } - - if (ab_mask & float_cmask_inf) { - if (c->cls == float_class_inf && a->sign != c->sign) { - float_raise(float_flag_invalid | float_flag_invalid_isi, s); - goto d_nan; - } - goto return_inf; - } - - g_assert(ab_mask & float_cmask_zero); - if (is_anynorm(c->cls)) { - *a = *c; - goto finish_sign; - } - if (c->cls == float_class_zero) { - if (flags & float_muladd_suppress_add_product_zero) { - a->sign = c->sign; - } else if (a->sign != c->sign) { - goto return_sub_zero; - } - goto return_zero; - } - g_assert(c->cls == float_class_inf); + /* Inf + C == Inf */ + record_denormals_used(abc_mask, s); + a->sign = p_sign; + a->cls = float_class_inf; + return a; } - - if (unlikely(c->cls == float_class_inf)) { - a->sign = c->sign; - goto return_inf; - } - - /* Perform the multiplication step. */ - p_widen.sign = a->sign; - p_widen.exp = a->exp + b->exp + 1; - fracN(mulw)(&p_widen, a, b); - if (!(p_widen.frac_hi & DECOMPOSED_IMPLICIT_BIT)) { - fracW(add)(&p_widen, &p_widen, &p_widen); - p_widen.exp -= 1; - } - - /* Perform the addition step. */ - if (c->cls != float_class_zero) { - /* Zero-extend C to less significant bits. */ - fracN(widen)(&c_widen, c); - c_widen.exp = c->exp; - - if (a->sign == c->sign) { - partsW(add_normal)(&p_widen, &c_widen); - } else if (!partsW(sub_normal)(&p_widen, &c_widen)) { - goto return_sub_zero; - } - } - - /* Narrow with sticky bit, for proper rounding later. */ - fracN(truncjam)(a, &p_widen); - a->sign = p_widen.sign; - a->exp = p_widen.exp; - - finish_sign: - /* - * All result types except for "return the default NaN - * because this is an Invalid Operation" go through here; - * this matches the set of cases where we consumed a - * denormal input. - */ record_denormals_used(abc_mask, s); - return a; + + /* Only remaining cases are zero product or inf addend. */ + assert((ab_mask & float_cmask_zero) | (c_mask & float_cmask_inf)); + + /* + * P + Inf == Inf, or + * 0 + C == C, + * except for 0 - 0, which needs special rounding, + * except for when we want to suppress this addition step. + */ + if (!(c_mask & float_cmask_zero) + || p_sign == c_sign + || (flags & float_muladd_suppress_add_product_zero)) { + c->sign = c_sign; + return c; + } return_sub_zero: + /* 0 - 0 == -0 for round_down, +0 otherwise. */ a->sign = s->float_rounding_mode == float_round_down; - return_zero: a->cls = float_class_zero; - goto finish_sign; - - return_inf: - a->cls = float_class_inf; - goto finish_sign; + return a; d_nan: *a = partsN(default_nan)(s); -- 2.43.0
At the same time, export. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 9 ++++ fpu/softfloat.c | 83 +++++++++++++++++------------------ fpu/softfloat-parts.c.inc | 38 ++++++++-------- 3 files changed, 69 insertions(+), 61 deletions(-) diff --git a/include/fpu/softfloat-parts.h b/include/fpu/softfloat-parts.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-parts.h +++ b/include/fpu/softfloat-parts.h @@ -XXX,XX +XXX,XX @@ FloatParts64 parts64_mul(const FloatParts64 *a, const FloatParts64 *b, FloatParts128 parts128_mul(const FloatParts128 *a, const FloatParts128 *b, float_status *s); +FloatParts64 parts64_muladd(const FloatParts64 *a, + const FloatParts64 *b, + const FloatParts64 *c, + int flags, float_status *s); +FloatParts128 parts128_muladd(const FloatParts128 *a, + const FloatParts128 *b, + const FloatParts128 *c, + int flags, float_status *s); + FloatParts64 parts64_round_to_int(const FloatParts64 *a, FloatRoundMode rmode, int scale, float_status *s, diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ float16 float16_muladd_scalbn(float16 a, float16 b, float16 c, FloatParts64 pa = float16_unpack_canonical(a, status); FloatParts64 pb = float16_unpack_canonical(b, status); FloatParts64 pc = float16_unpack_canonical(c, status); - FloatParts64 *pr = parts64_muladd(&pa, &pb, &pc, flags, status); + FloatParts64 pr = parts64_muladd(&pa, &pb, &pc, flags, status); /* Before rounding, scale. */ if (scale) { - *pr = parts64_scalbn(pr, scale, status); + pr = parts64_scalbn(&pr, scale, status); } - parts64_uncanon(pr, status, &float16_params, false); + parts64_uncanon(&pr, status, &float16_params, false); /* After rounding, apply negate result, especially for -0.0. */ - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return pack_raw64(pr, &float16_params); + return pack_raw64(&pr, &float16_params); } float16 float16_muladd(float16 a, float16 b, float16 c, @@ -XXX,XX +XXX,XX @@ float32_muladd_scalbn(float32 a, float32 b, float32 c, FloatParts64 pa = float32_unpack_canonical(a, status); FloatParts64 pb = float32_unpack_canonical(b, status); FloatParts64 pc = float32_unpack_canonical(c, status); - FloatParts64 *pr = parts64_muladd(&pa, &pb, &pc, flags, status); + FloatParts64 pr = parts64_muladd(&pa, &pb, &pc, flags, status); /* Before rounding, scale. */ if (scale) { - *pr = parts64_scalbn(pr, scale, status); + pr = parts64_scalbn(&pr, scale, status); } - parts64_uncanon(pr, status, &float32_params, false); + parts64_uncanon(&pr, status, &float32_params, false); /* After rounding, apply negate result, especially for -0.0. */ - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return pack_raw64(pr, &float32_params); + return pack_raw64(&pr, &float32_params); } float64 QEMU_SOFTFLOAT_ATTR @@ -XXX,XX +XXX,XX @@ float64_muladd_scalbn(float64 a, float64 b, float64 c, FloatParts64 pa = float64_unpack_canonical(a, status); FloatParts64 pb = float64_unpack_canonical(b, status); FloatParts64 pc = float64_unpack_canonical(c, status); - FloatParts64 *pr = parts64_muladd(&pa, &pb, &pc, flags, status); + FloatParts64 pr = parts64_muladd(&pa, &pb, &pc, flags, status); /* Before rounding, scale. */ if (scale) { - *pr = parts64_scalbn(pr, scale, status); + pr = parts64_scalbn(&pr, scale, status); } - parts64_uncanon(pr, status, &float64_params, false); + parts64_uncanon(&pr, status, &float64_params, false); /* After rounding, apply negate result, especially for -0.0. */ - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return pack_raw64(pr, &float64_params); + return pack_raw64(&pr, &float64_params); } static bool force_soft_fma; @@ -XXX,XX +XXX,XX @@ float64 float64r32_muladd(float64 a, float64 b, float64 c, FloatParts64 pa = float64_unpack_canonical(a, status); FloatParts64 pb = float64_unpack_canonical(b, status); FloatParts64 pc = float64_unpack_canonical(c, status); - FloatParts64 *pr = parts64_muladd(&pa, &pb, &pc, flags, status); + FloatParts64 pr = parts64_muladd(&pa, &pb, &pc, flags, status); /* Round before applying negate result. */ - parts64_uncanon(pr, status, &float32_params, false); - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + parts64_uncanon(&pr, status, &float32_params, false); + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return float64r32_pack_raw(pr); + return float64r32_pack_raw(&pr); } bfloat16 bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, FloatParts64 pa = bfloat16_unpack_canonical(a, status); FloatParts64 pb = bfloat16_unpack_canonical(b, status); FloatParts64 pc = bfloat16_unpack_canonical(c, status); - FloatParts64 *pr = parts64_muladd(&pa, &pb, &pc, flags, status); + FloatParts64 pr = parts64_muladd(&pa, &pb, &pc, flags, status); /* Round before applying negate result. */ - parts64_uncanon(pr, status, &bfloat16_params, false); - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + parts64_uncanon(&pr, status, &bfloat16_params, false); + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return pack_raw64(pr, &bfloat16_params); + return pack_raw64(&pr, &bfloat16_params); } float128 float128_muladd(float128 a, float128 b, float128 c, @@ -XXX,XX +XXX,XX @@ float128 float128_muladd(float128 a, float128 b, float128 c, FloatParts128 pa = float128_unpack_canonical(a, status); FloatParts128 pb = float128_unpack_canonical(b, status); FloatParts128 pc = float128_unpack_canonical(c, status); - FloatParts128 *pr = parts128_muladd(&pa, &pb, &pc, flags, status); + FloatParts128 pr = parts128_muladd(&pa, &pb, &pc, flags, status); /* Round before applying negate result. */ - parts128_uncanon(pr, status, &float128_params, false); - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + parts128_uncanon(&pr, status, &float128_params, false); + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return float128_pack_raw(pr); + return float128_pack_raw(&pr); } /* @@ -XXX,XX +XXX,XX @@ float32 float32_exp2(float32 a, float_status *status) rp = float64_unpack_canonical(float64_one, status); for (int i = 0; i < 15; i++) { tp = float64_unpack_canonical(float32_exp2_coefficients[i], status); - rp = *parts64_muladd(&tp, &xnp, &rp, 0, status); + rp = parts64_muladd(&tp, &xnp, &rp, 0, status); xnp = parts64_mul(&xnp, &xp, status); } @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, n->sign = a->sign ^ b->sign; *cc = 0; } else { - FloatParts64 *q, q_buf, *r_precise, r_precise_buf; + FloatParts64 *q, q_buf, r_precise; int float_exception_flags = 0; bool is_q_smallish; uint32_t r_flags; @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, 0, fmt->frac_size); /* Compute precise remainder */ - r_precise_buf = *b; - r_precise = parts64_muladd(&r_precise_buf, n, a, + r_precise = parts64_muladd(b, n, a, float_muladd_negate_product, status); /* Round remainder to the target format */ - *r = *r_precise; + *r = r_precise; status->float_exception_flags = 0; *r = parts64_round_to_fmt(r, status, fmt); r_flags = status->float_exception_flags; @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, * toward zero) or incremented. */ saved_r_sign = r->sign; - saved_r_precise_sign = r_precise->sign; + saved_r_precise_sign = r_precise.sign; r->sign = false; - r_precise->sign = false; - if (parts64_compare(r, r_precise, status, true) < + r_precise.sign = false; + if (parts64_compare(r, &r_precise, status, true) < float_relation_equal) { *dxc = 0x8; } else { *dxc = 0xc; } r->sign = saved_r_sign; - r_precise->sign = saved_r_precise_sign; + r_precise.sign = saved_r_precise_sign; } } } diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(mul)(const FloatPartsN *a, const FloatPartsN *b, * Requires A and C extracted into a double-sized structure to provide the * extra space for the widening multiply. */ -static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, - FloatPartsN *c, - int flags, float_status *s) +FloatPartsN partsN(muladd)(const FloatPartsN *a, const FloatPartsN *b, + const FloatPartsN *c, int flags, float_status *s) { int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); int c_mask = float_cmask(c->cls); @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, } /* Narrow with sticky bit, for proper rounding later. */ - fracN(truncjam)(a, &p_widen); - a->sign = p_widen.sign; - a->exp = p_widen.exp; - return a; + FloatPartsN r = { + .sign = p_widen.sign, + .exp = p_widen.exp, + .cls = float_class_normal, + }; + fracN(truncjam)(&r, &p_widen); + return r; } /* @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, * off to the target-specific pick-a-NaN routine. */ if (unlikely(abc_mask & float_cmask_anynan)) { - *a = partsN(pick_nan_muladd)(a, b, c, s, ab_mask, abc_mask); - return a; + return partsN(pick_nan_muladd)(a, b, c, s, ab_mask, abc_mask); } if (unlikely(ab_mask == float_cmask_infzero)) { @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, } /* Inf + C == Inf */ record_denormals_used(abc_mask, s); - a->sign = p_sign; - a->cls = float_class_inf; - return a; + return (FloatPartsN){ .sign = p_sign, .cls = float_class_inf }; } record_denormals_used(abc_mask, s); @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, if (!(c_mask & float_cmask_zero) || p_sign == c_sign || (flags & float_muladd_suppress_add_product_zero)) { - c->sign = c_sign; - return c; + FloatPartsN r = *c; + r.sign = c_sign; + return r; } return_sub_zero: /* 0 - 0 == -0 for round_down, +0 otherwise. */ - a->sign = s->float_rounding_mode == float_round_down; - a->cls = float_class_zero; - return a; + return (FloatPartsN){ + .sign = s->float_rounding_mode == float_round_down, + .cls = float_class_zero + }; d_nan: - *a = partsN(default_nan)(s); - return a; + return partsN(default_nan)(s); } /* -- 2.43.0
The nan test had been down below because it was unlikely. But if we have to have one anyway because of denormals, we might as well take care of them right away. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, { int ab_mask = float_cmask(a_orig->cls) | float_cmask(b_orig->cls); + if (unlikely(ab_mask & float_cmask_anynan)) { + return partsN(pick_nan)(a_orig, b_orig, s); + } + /* * For addition and subtraction, we will consume an * input denormal unless the other input is a NaN. */ - if (!(ab_mask & float_cmask_anynan)) { - record_denormals_used(ab_mask, s); - } + record_denormals_used(ab_mask, s); FloatPartsN a = *a_orig; FloatPartsN b = *b_orig; @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, return a; } - if (unlikely(ab_mask & float_cmask_anynan)) { - goto p_nan; - } - if (ab_mask & float_cmask_inf) { if (a.cls != float_class_inf) { /* N - Inf */ @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, return a; } - if (unlikely(ab_mask & float_cmask_anynan)) { - goto p_nan; - } - if (ab_mask & float_cmask_inf) { a.cls = float_class_inf; return a; @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, g_assert(a.cls == float_class_zero); g_assert(is_anynorm(b.cls)); return b; - - p_nan: - return partsN(pick_nan)(a_orig, b_orig, s); } /* -- 2.43.0
Consolidate the tests for zero and anynorm. Add comments for a few cases. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, } if (ab_mask == float_cmask_zero) { + /* 0 - 0 */ a.sign = s->float_rounding_mode == float_round_down; return a; } @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, } if (ab_mask == float_cmask_zero) { + /* 0 + 0 */ return a; } if (ab_mask & float_cmask_inf) { + /* N + Inf or Inf + N */ a.cls = float_class_inf; return a; } } - if (b.cls == float_class_zero) { - g_assert(is_anynorm(a.cls)); - return a; - } - - g_assert(a.cls == float_class_zero); - g_assert(is_anynorm(b.cls)); - return b; + /* 0 +/- N or N +/- 0 */ + assert((ab_mask & float_cmask_zero) && (ab_mask & float_cmask_anynorm)); + return b.cls == float_class_zero ? a : b; } /* -- 2.43.0
We will not expose parts_round_to_int_normal. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, * Rounding of partial quotient may be inexact. This is the whole point * of distinguishing partial quotients, so ignore the exception. */ - *n = *q; - parts64_round_to_int_normal(n, - is_q_smallish - ? final_quotient_rounding_mode - : float_round_to_zero, - 0, fmt->frac_size); + *n = parts64_round_to_int(q, + is_q_smallish + ? final_quotient_rounding_mode + : float_round_to_zero, + 0, status, fmt); /* Compute precise remainder */ r_precise = parts64_muladd(b, n, a, -- 2.43.0
Now that we've exposed enough infrastructure, this can be implemented in the backend that needs it. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Ilya Leoshkevich <iii@linux.ibm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat.h | 11 --- fpu/softfloat.c | 137 ---------------------------------- target/s390x/tcg/fpu_helper.c | 135 +++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 148 deletions(-) diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -XXX,XX +XXX,XX @@ static inline bool float128_unordered_quiet(float128 a, float128 b, *----------------------------------------------------------------------------*/ float128 float128_default_nan(float_status *status); -#define DECLARE_S390_DIVIDE_TO_INTEGER(floatN) \ -void floatN ## _s390_divide_to_integer(floatN a, floatN b, \ - int final_quotient_rounding_mode, \ - bool mask_underflow, bool mask_inexact, \ - floatN *r, floatN *n, \ - uint32_t *cc, int *dxc, \ - float_status *status) -DECLARE_S390_DIVIDE_TO_INTEGER(float32); -DECLARE_S390_DIVIDE_TO_INTEGER(float64); - - #endif /* SOFTFLOAT_H */ diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_round(floatx80 a, float_status *status) return floatx80_round_pack_canonical(&p, status); } -static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, - int final_quotient_rounding_mode, - bool mask_underflow, bool mask_inexact, - const FloatFmt *fmt, - FloatParts64 *r, FloatParts64 *n, - uint32_t *cc, int *dxc, - float_status *status) -{ - /* POp table "Results: DIVIDE TO INTEGER (Part 1 of 2)" */ - if ((float_cmask(a->cls) | float_cmask(b->cls)) & float_cmask_anynan) { - *r = parts64_pick_nan(a, b, status); - *n = *r; - *cc = 1; - } else if (a->cls == float_class_inf || b->cls == float_class_zero) { - *r = parts64_default_nan(status); - *n = *r; - *cc = 1; - status->float_exception_flags |= float_flag_invalid; - } else if (b->cls == float_class_inf) { - *r = *a; - n->cls = float_class_zero; - n->sign = a->sign ^ b->sign; - *cc = 0; - } else { - FloatParts64 *q, q_buf, r_precise; - int float_exception_flags = 0; - bool is_q_smallish; - uint32_t r_flags; - - /* Compute precise quotient */ - q_buf = parts64_div(a, b, status); - q = &q_buf; - - /* - * Check whether two closest integers can be precisely represented, - * i.e., all their bits fit into the fractional part. - */ - is_q_smallish = q->exp < (fmt->frac_size + 1); - - /* - * Final quotient is rounded using final-quotient-rounding method, and - * partial quotient is rounded toward zero. - * - * Rounding of partial quotient may be inexact. This is the whole point - * of distinguishing partial quotients, so ignore the exception. - */ - *n = parts64_round_to_int(q, - is_q_smallish - ? final_quotient_rounding_mode - : float_round_to_zero, - 0, status, fmt); - - /* Compute precise remainder */ - r_precise = parts64_muladd(b, n, a, - float_muladd_negate_product, status); - - /* Round remainder to the target format */ - *r = r_precise; - status->float_exception_flags = 0; - *r = parts64_round_to_fmt(r, status, fmt); - r_flags = status->float_exception_flags; - - /* POp table "Results: DIVIDE TO INTEGER (Part 2 of 2)" */ - if (is_q_smallish) { - if (r->cls != float_class_zero) { - if (r->exp < 2 - (1 << (fmt->exp_size - 1))) { - if (mask_underflow) { - float_exception_flags |= float_flag_underflow; - *dxc = 0x10; - r->exp += fmt->exp_re_bias; - } - } else if (r_flags & float_flag_inexact) { - float_exception_flags |= float_flag_inexact; - if (mask_inexact) { - bool saved_r_sign, saved_r_precise_sign; - - /* - * Check whether remainder was truncated (rounded - * toward zero) or incremented. - */ - saved_r_sign = r->sign; - saved_r_precise_sign = r_precise.sign; - r->sign = false; - r_precise.sign = false; - if (parts64_compare(r, &r_precise, status, true) < - float_relation_equal) { - *dxc = 0x8; - } else { - *dxc = 0xc; - } - r->sign = saved_r_sign; - r_precise.sign = saved_r_precise_sign; - } - } - } - *cc = 0; - } else if (n->exp > (1 << (fmt->exp_size - 1)) - 1) { - n->exp -= fmt->exp_re_bias; - *cc = r->cls == float_class_zero ? 1 : 3; - } else { - *cc = r->cls == float_class_zero ? 0 : 2; - } - - /* Adjust signs of zero results */ - if (r->cls == float_class_zero) { - r->sign = a->sign; - } - if (n->cls == float_class_zero) { - n->sign = a->sign ^ b->sign; - } - - status->float_exception_flags = float_exception_flags; - } -} - -#define DEFINE_S390_DIVIDE_TO_INTEGER(floatN) \ -void floatN ## _s390_divide_to_integer(floatN a, floatN b, \ - int final_quotient_rounding_mode, \ - bool mask_underflow, bool mask_inexact, \ - floatN *r, floatN *n, \ - uint32_t *cc, int *dxc, \ - float_status *status) \ -{ \ - FloatParts64 pa = floatN ## _unpack_canonical(a, status); \ - FloatParts64 pb = floatN ## _unpack_canonical(b, status); \ - FloatParts64 pr, pn; \ - parts_s390_divide_to_integer(&pa, &pb, final_quotient_rounding_mode, \ - mask_underflow, mask_inexact, \ - &floatN ## _params, \ - &pr, &pn, cc, dxc, status); \ - *r = floatN ## _round_pack_canonical(&pr, status); \ - *n = floatN ## _round_pack_canonical(&pn, status); \ -} - -DEFINE_S390_DIVIDE_TO_INTEGER(float32) -DEFINE_S390_DIVIDE_TO_INTEGER(float64) - static void __attribute__((constructor)) softfloat_init(void) { union_float64 ua, ub, uc, ur; diff --git a/target/s390x/tcg/fpu_helper.c b/target/s390x/tcg/fpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/s390x/tcg/fpu_helper.c +++ b/target/s390x/tcg/fpu_helper.c @@ -XXX,XX +XXX,XX @@ #include "tcg_s390x.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" +#include "fpu/softfloat-parts.h" /* #define DEBUG_HELPER */ #ifdef DEBUG_HELPER @@ -XXX,XX +XXX,XX @@ Int128 HELPER(dxb)(CPUS390XState *env, Int128 a, Int128 b) return RET128(ret); } +static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, + int final_quotient_rounding_mode, + bool mask_underflow, bool mask_inexact, + const FloatFmt *fmt, + FloatParts64 *r, FloatParts64 *n, + uint32_t *cc, int *dxc, + float_status *status) +{ + /* POp table "Results: DIVIDE TO INTEGER (Part 1 of 2)" */ + if ((float_cmask(a->cls) | float_cmask(b->cls)) & float_cmask_anynan) { + *r = parts64_pick_nan(a, b, status); + *n = *r; + *cc = 1; + } else if (a->cls == float_class_inf || b->cls == float_class_zero) { + *r = parts64_default_nan(status); + *n = *r; + *cc = 1; + status->float_exception_flags |= float_flag_invalid; + } else if (b->cls == float_class_inf) { + *r = *a; + n->cls = float_class_zero; + n->sign = a->sign ^ b->sign; + *cc = 0; + } else { + FloatParts64 *q, q_buf, r_precise; + int float_exception_flags = 0; + bool is_q_smallish; + uint32_t r_flags; + + /* Compute precise quotient */ + q_buf = parts64_div(a, b, status); + q = &q_buf; + + /* + * Check whether two closest integers can be precisely represented, + * i.e., all their bits fit into the fractional part. + */ + is_q_smallish = q->exp < (fmt->frac_size + 1); + + /* + * Final quotient is rounded using final-quotient-rounding method, and + * partial quotient is rounded toward zero. + * + * Rounding of partial quotient may be inexact. This is the whole point + * of distinguishing partial quotients, so ignore the exception. + */ + *n = parts64_round_to_int(q, + is_q_smallish + ? final_quotient_rounding_mode + : float_round_to_zero, + 0, status, fmt); + + /* Compute precise remainder */ + r_precise = parts64_muladd(b, n, a, + float_muladd_negate_product, status); + + /* Round remainder to the target format */ + *r = r_precise; + status->float_exception_flags = 0; + *r = parts64_round_to_fmt(r, status, fmt); + r_flags = status->float_exception_flags; + + /* POp table "Results: DIVIDE TO INTEGER (Part 2 of 2)" */ + if (is_q_smallish) { + if (r->cls != float_class_zero) { + if (r->exp < 2 - (1 << (fmt->exp_size - 1))) { + if (mask_underflow) { + float_exception_flags |= float_flag_underflow; + *dxc = 0x10; + r->exp += fmt->exp_re_bias; + } + } else if (r_flags & float_flag_inexact) { + float_exception_flags |= float_flag_inexact; + if (mask_inexact) { + bool saved_r_sign, saved_r_precise_sign; + + /* + * Check whether remainder was truncated (rounded + * toward zero) or incremented. + */ + saved_r_sign = r->sign; + saved_r_precise_sign = r_precise.sign; + r->sign = false; + r_precise.sign = false; + if (parts64_compare(r, &r_precise, status, true) < + float_relation_equal) { + *dxc = 0x8; + } else { + *dxc = 0xc; + } + r->sign = saved_r_sign; + r_precise.sign = saved_r_precise_sign; + } + } + } + *cc = 0; + } else if (n->exp > (1 << (fmt->exp_size - 1)) - 1) { + n->exp -= fmt->exp_re_bias; + *cc = r->cls == float_class_zero ? 1 : 3; + } else { + *cc = r->cls == float_class_zero ? 0 : 2; + } + + /* Adjust signs of zero results */ + if (r->cls == float_class_zero) { + r->sign = a->sign; + } + if (n->cls == float_class_zero) { + n->sign = a->sign ^ b->sign; + } + + status->float_exception_flags = float_exception_flags; + } +} + +#define DEFINE_S390_DIVIDE_TO_INTEGER(floatN) \ +static void floatN ## _s390_divide_to_integer(floatN a, floatN b, \ + int final_quotient_rounding_mode, bool mask_underflow, bool mask_inexact, \ + floatN *r, floatN *n, uint32_t *cc, int *dxc, float_status *status) \ +{ \ + FloatParts64 pa = floatN ## _unpack_canonical(a, status); \ + FloatParts64 pb = floatN ## _unpack_canonical(b, status); \ + FloatParts64 pr, pn; \ + parts_s390_divide_to_integer(&pa, &pb, final_quotient_rounding_mode, \ + mask_underflow, mask_inexact, \ + &floatN ## _params, \ + &pr, &pn, cc, dxc, status); \ + *r = floatN ## _round_pack_canonical(&pr, status); \ + *n = floatN ## _round_pack_canonical(&pn, status); \ +} + +DEFINE_S390_DIVIDE_TO_INTEGER(float32) +DEFINE_S390_DIVIDE_TO_INTEGER(float64) + void HELPER(dib)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3, uint32_t m4, uint32_t bits) { -- 2.43.0
Use softfloat-parts.h so that we can more naturally perform the required operations witha single rounding step. This happens to also simplify the NaN detection step. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/arm/tcg/vec_helper.c | 77 +++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vec_helper.c +++ b/target/arm/tcg/vec_helper.c @@ -XXX,XX +XXX,XX @@ #include "helper.h" #include "tcg/tcg-gvec-desc.h" #include "fpu/softfloat.h" +#include "fpu/softfloat-parts.h" #include "qemu/int128.h" #include "crypto/clmul.h" #include "vec_internal.h" @@ -XXX,XX +XXX,XX @@ float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst) float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst, float_status *fpst_odd) { + /* Unpack two BFloat16 into two Float32, trivially. */ float32 s1r = e1 << 16; float32 s1c = e1 & 0xffff0000u; float32 s2r = e2 << 16; float32 s2c = e2 & 0xffff0000u; float32 t32; + /* + * Compare f16_dotadd() in sme_helper.c, but here we have + * bfloat16 inputs. In particular that means that we do not + * want the FPCR.FZ16 flush semantics, so we use the normal + * float_status for the input handling here. + */ + FloatParts64 p1r = float32_unpack_canonical(s1r, fpst); + FloatParts64 p1c = float32_unpack_canonical(s1c, fpst); + FloatParts64 p2r = float32_unpack_canonical(s2r, fpst); + FloatParts64 p2c = float32_unpack_canonical(s2c, fpst); + + int all_mask = (float_cmask(p1r.cls) | float_cmask(p1c.cls) | + float_cmask(p1r.cls) | float_cmask(p1c.cls)); + /* C.f. FPProcessNaNs4 */ - if (float32_is_any_nan(s1r) || float32_is_any_nan(s1c) || - float32_is_any_nan(s2r) || float32_is_any_nan(s2c)) { - if (float32_is_signaling_nan(s1r, fpst)) { - t32 = s1r; - } else if (float32_is_signaling_nan(s1c, fpst)) { - t32 = s1c; - } else if (float32_is_signaling_nan(s2r, fpst)) { - t32 = s2r; - } else if (float32_is_signaling_nan(s2c, fpst)) { - t32 = s2c; - } else if (float32_is_any_nan(s1r)) { - t32 = s1r; - } else if (float32_is_any_nan(s1c)) { - t32 = s1c; - } else if (float32_is_any_nan(s2r)) { - t32 = s2r; + if (unlikely(all_mask & float_cmask_anynan)) { + if (unlikely(all_mask & float_cmask_snan)) { + if (p1r.cls == float_class_snan) { + t32 = s1r; + } else if (p1c.cls == float_class_snan) { + t32 = s1c; + } else if (p2r.cls == float_class_snan) { + t32 = s2r; + } else { + t32 = s2c; + } } else { - t32 = s2c; + if (p1r.cls == float_class_qnan) { + t32 = s1r; + } else if (p1c.cls == float_class_qnan) { + t32 = s1c; + } else if (p2r.cls == float_class_qnan) { + t32 = s2r; + } else { + t32 = s2c; + } } /* * FPConvertNaN(FPProcessNaN(t32)) will be done as part * of the final addition below. */ } else { - /* - * Compare f16_dotadd() in sme_helper.c, but here we have - * bfloat16 inputs. In particular that means that we do not - * want the FPCR.FZ16 flush semantics, so we use the normal - * float_status for the input handling here. - */ - float64 e1r = float32_to_float64(s1r, fpst); - float64 e1c = float32_to_float64(s1c, fpst); - float64 e2r = float32_to_float64(s2r, fpst); - float64 e2c = float32_to_float64(s2c, fpst); - float64 t64; - /* * The ARM pseudocode function FPDot performs both multiplies - * and the add with a single rounding operation. Emulate this - * by performing the first multiply in round-to-odd, then doing - * the second multiply as fused multiply-add, and rounding to - * float32 all in one step. + * and the add with a single rounding operation. */ - t64 = float64_mul(e1r, e2r, fpst_odd); - t64 = float64r32_muladd(e1c, e2c, t64, 0, fpst); + FloatParts64 tmp = parts64_mul(&p1r, &p2r, fpst); + tmp = parts64_muladd(&p1c, &p2c, &tmp, 0, fpst); - /* This conversion is exact, because we've already rounded. */ - t32 = float64_to_float32(t64, fpst); + t32 = float32_round_pack_canonical(&tmp, fpst); } /* The final accumulation step is not fused. */ -- 2.43.0
This argument is no longer used. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/arm/tcg/vec_internal.h | 12 +++------ target/arm/tcg/sme_helper.c | 6 ++--- target/arm/tcg/vec_helper.c | 50 +++++++++++++++-------------------- 3 files changed, 29 insertions(+), 39 deletions(-) diff --git a/target/arm/tcg/vec_internal.h b/target/arm/tcg/vec_internal.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vec_internal.h +++ b/target/arm/tcg/vec_internal.h @@ -XXX,XX +XXX,XX @@ float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst); * @sum: addend * @e1, @e2: multiplicand vectors * @fpst: floating-point status to use - * @fpst_odd: floating-point status to use for round-to-odd operations * * BFloat16 2-way dot product of @e1 & @e2, accumulating with @sum. * The @e1 and @e2 operands correspond to the 32-bit source vector @@ -XXX,XX +XXX,XX @@ float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst); * Corresponds to the ARM pseudocode function BFDotAdd, specialized * for the FPCR.EBF == 1 case. */ -float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2, - float_status *fpst, float_status *fpst_odd); +float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst); /** * is_ebf: * @env: CPU state * @statusp: pointer to floating point status to fill in - * @oddstatusp: pointer to floating point status to fill in for round-to-odd * * Determine whether a BFDotAdd operation should use FPCR.EBF = 0 - * or FPCR.EBF = 1 semantics. On return, has initialized *statusp - * and *oddstatusp to suitable float_status arguments to use with either - * bfdotadd() or bfdotadd_ebf(). + * or FPCR.EBF = 1 semantics. On return, has initialized *statusp as suitable + * for float_status arguments to either bfdotadd() or bfdotadd_ebf(). * Returns true for EBF = 1, false for EBF = 0. (The caller should use this * to decide whether to call bfdotadd() or bfdotadd_ebf().) */ -bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp); +bool is_ebf(CPUARMState *env, float_status *statusp); /* * Negate as for FPCR.AH=1 -- do not negate NaNs. diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ static void do_bfmopa_w(void *vza, void *vzn, void *vzm, uint32_t desc, uint32_t negx, bool ah_neg) { intptr_t row, col, oprsz = simd_maxsz(desc); - float_status fpst, fpst_odd; + float_status fpst; - if (is_ebf(env, &fpst, &fpst_odd)) { + if (is_ebf(env, &fpst)) { for (row = 0; row < oprsz; ) { uint16_t prow = pn[H2(row >> 4)]; do { @@ -XXX,XX +XXX,XX @@ static void do_bfmopa_w(void *vza, void *vzn, void *vzm, uint32_t m = *(uint32_t *)(vzm + H1_4(col)); m = f16mop_adj_pair(m, pcol, 0); - *a = bfdotadd_ebf(*a, n, m, &fpst, &fpst_odd); + *a = bfdotadd_ebf(*a, n, m, &fpst); } col += 4; pcol >>= 4; diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vec_helper.c +++ b/target/arm/tcg/vec_helper.c @@ -XXX,XX +XXX,XX @@ DO_MMLA_B(gvec_usmmla_b, do_usmmla_b) * BFloat16 Dot Product */ -bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp) +bool is_ebf(CPUARMState *env, float_status *statusp) { /* * For BFDOT, BFMMLA, etc, the behaviour depends on FPCR.EBF. @@ -XXX,XX +XXX,XX @@ bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp) *statusp = env->vfp.fp_status[is_a64(env) ? FPST_A64 : FPST_A32]; set_default_nan_mode(true, statusp); - if (ebf) { - /* EBF=1 needs to do a step with round-to-odd semantics */ - *oddstatusp = *statusp; - set_float_rounding_mode(float_round_to_odd, oddstatusp); - } else { + if (!ebf) { set_flush_to_zero(true, statusp); set_flush_inputs_to_zero(true, statusp); set_float_rounding_mode(float_round_to_odd_inf, statusp); @@ -XXX,XX +XXX,XX @@ float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst) return t1; } -float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2, - float_status *fpst, float_status *fpst_odd) +float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst) { /* Unpack two BFloat16 into two Float32, trivially. */ float32 s1r = e1 << 16; @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_bfdot)(void *vd, void *vn, void *vm, void *va, intptr_t i, opr_sz = simd_oprsz(desc); float32 *d = vd, *a = va; uint32_t *n = vn, *m = vm; - float_status fpst, fpst_odd; + float_status fpst; - if (is_ebf(env, &fpst, &fpst_odd)) { + if (is_ebf(env, &fpst)) { for (i = 0; i < opr_sz / 4; ++i) { - d[i] = bfdotadd_ebf(a[i], n[i], m[i], &fpst, &fpst_odd); + d[i] = bfdotadd_ebf(a[i], n[i], m[i], &fpst); } } else { for (i = 0; i < opr_sz / 4; ++i) { @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_bfdot_idx)(void *vd, void *vn, void *vm, intptr_t eltspersegment = MIN(16 / 4, elements); float32 *d = vd, *a = va; uint32_t *n = vn, *m = vm; - float_status fpst, fpst_odd; + float_status fpst; - if (is_ebf(env, &fpst, &fpst_odd)) { + if (is_ebf(env, &fpst)) { for (i = 0; i < elements; i += eltspersegment) { uint32_t m_idx = m[i + H4(index)]; for (j = i; j < i + eltspersegment; j++) { - d[j] = bfdotadd_ebf(a[j], n[j], m_idx, &fpst, &fpst_odd); + d[j] = bfdotadd_ebf(a[j], n[j], m_idx, &fpst); } } } else { @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_bfvdot_idx)(void *vd, void *vn, void *vm, uint16_t *n0 = vn; uint16_t *n1 = vn + sizeof(ARMVectorReg); uint32_t *m = vm; - float_status fpst, fpst_odd; + float_status fpst; - if (is_ebf(env, &fpst, &fpst_odd)) { + if (is_ebf(env, &fpst)) { for (i = 0; i < elements; i += eltspersegment) { uint32_t m_idx = m[i + H4(idx)]; for (j = 0; j < eltspersegment; j++) { uint32_t nn = (n0[H2(2 * (i + j) + sel)]) | (n1[H2(2 * (i + j) + sel)] << 16); - d[i + H4(j)] = bfdotadd_ebf(a[i + H4(j)], nn, m_idx, - &fpst, &fpst_odd); + d[i + H4(j)] = bfdotadd_ebf(a[i + H4(j)], nn, m_idx, &fpst); } } } else { @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_bfmmla)(void *vd, void *vn, void *vm, void *va, intptr_t s, opr_sz = simd_oprsz(desc); float32 *d = vd, *a = va; uint32_t *n = vn, *m = vm; - float_status fpst, fpst_odd; + float_status fpst; - if (is_ebf(env, &fpst, &fpst_odd)) { + if (is_ebf(env, &fpst)) { for (s = 0; s < opr_sz / 4; s += 4) { float32 sum00, sum01, sum10, sum11; @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_bfmmla)(void *vd, void *vn, void *vm, void *va, * i j i k j k */ sum00 = a[s + H4(0 + 0)]; - sum00 = bfdotadd_ebf(sum00, n[s + H4(0 + 0)], m[s + H4(0 + 0)], &fpst, &fpst_odd); - sum00 = bfdotadd_ebf(sum00, n[s + H4(0 + 1)], m[s + H4(0 + 1)], &fpst, &fpst_odd); + sum00 = bfdotadd_ebf(sum00, n[s + H4(0 + 0)], m[s + H4(0 + 0)], &fpst); + sum00 = bfdotadd_ebf(sum00, n[s + H4(0 + 1)], m[s + H4(0 + 1)], &fpst); sum01 = a[s + H4(0 + 1)]; - sum01 = bfdotadd_ebf(sum01, n[s + H4(0 + 0)], m[s + H4(2 + 0)], &fpst, &fpst_odd); - sum01 = bfdotadd_ebf(sum01, n[s + H4(0 + 1)], m[s + H4(2 + 1)], &fpst, &fpst_odd); + sum01 = bfdotadd_ebf(sum01, n[s + H4(0 + 0)], m[s + H4(2 + 0)], &fpst); + sum01 = bfdotadd_ebf(sum01, n[s + H4(0 + 1)], m[s + H4(2 + 1)], &fpst); sum10 = a[s + H4(2 + 0)]; - sum10 = bfdotadd_ebf(sum10, n[s + H4(2 + 0)], m[s + H4(0 + 0)], &fpst, &fpst_odd); - sum10 = bfdotadd_ebf(sum10, n[s + H4(2 + 1)], m[s + H4(0 + 1)], &fpst, &fpst_odd); + sum10 = bfdotadd_ebf(sum10, n[s + H4(2 + 0)], m[s + H4(0 + 0)], &fpst); + sum10 = bfdotadd_ebf(sum10, n[s + H4(2 + 1)], m[s + H4(0 + 1)], &fpst); sum11 = a[s + H4(2 + 1)]; - sum11 = bfdotadd_ebf(sum11, n[s + H4(2 + 0)], m[s + H4(2 + 0)], &fpst, &fpst_odd); - sum11 = bfdotadd_ebf(sum11, n[s + H4(2 + 1)], m[s + H4(2 + 1)], &fpst, &fpst_odd); + sum11 = bfdotadd_ebf(sum11, n[s + H4(2 + 0)], m[s + H4(2 + 0)], &fpst); + sum11 = bfdotadd_ebf(sum11, n[s + H4(2 + 1)], m[s + H4(2 + 1)], &fpst); d[s + H4(0 + 0)] = sum00; d[s + H4(0 + 1)] = sum01; -- 2.43.0
Use softfloat-parts.h so that we can more naturally perform the required operations witha single rounding step. This happens to also simplify the NaN detection step. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/arm/tcg/sme_helper.c | 96 ++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 56 deletions(-) diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ #include "accel/tcg/helper-retaddr.h" #include "qemu/int128.h" #include "fpu/softfloat.h" +#include "fpu/softfloat-parts.h" #include "vec_internal.h" #include "sve_ldst_internal.h" @@ -XXX,XX +XXX,XX @@ static inline uint32_t bf16mop_ah_neg_adj_pair(uint32_t pair, uint32_t pg) } static float32 f16_dotadd(float32 sum, uint32_t e1, uint32_t e2, - float_status *s_f16, float_status *s_std, - float_status *s_odd) + float_status *s_f16, float_status *s_std) { /* - * We need three different float_status for different parts of this + * We need two different float_status for different parts of this * operation: * - the input conversion of the float16 values must use the * f16-specific float_status, so that the FPCR.FZ16 control is applied * - operations on float32 including the final accumulation must use * the normal float_status, so that FPCR.FZ is applied - * - we have pre-set-up copy of s_std which is set to round-to-odd, - * for the multiply (see below) */ float16 h1r = e1 & 0xffff; float16 h1c = e1 >> 16; @@ -XXX,XX +XXX,XX @@ static float32 f16_dotadd(float32 sum, uint32_t e1, uint32_t e2, float16 h2c = e2 >> 16; float32 t32; + FloatParts64 p1r = float16_unpack_canonical(h1r, s_f16); + FloatParts64 p1c = float16_unpack_canonical(h1c, s_f16); + FloatParts64 p2r = float16_unpack_canonical(h2r, s_f16); + FloatParts64 p2c = float16_unpack_canonical(h2c, s_f16); + + int all_mask = (float_cmask(p1r.cls) | float_cmask(p1c.cls) | + float_cmask(p1r.cls) | float_cmask(p1c.cls)); + /* C.f. FPProcessNaNs4 */ - if (float16_is_any_nan(h1r) || float16_is_any_nan(h1c) || - float16_is_any_nan(h2r) || float16_is_any_nan(h2c)) { + if (unlikely(all_mask & float_cmask_anynan)) { float16 t16; - if (float16_is_signaling_nan(h1r, s_f16)) { - t16 = h1r; - } else if (float16_is_signaling_nan(h1c, s_f16)) { - t16 = h1c; - } else if (float16_is_signaling_nan(h2r, s_f16)) { - t16 = h2r; - } else if (float16_is_signaling_nan(h2c, s_f16)) { - t16 = h2c; - } else if (float16_is_any_nan(h1r)) { - t16 = h1r; - } else if (float16_is_any_nan(h1c)) { - t16 = h1c; - } else if (float16_is_any_nan(h2r)) { - t16 = h2r; + if (unlikely(all_mask & float_cmask_snan)) { + if (p1r.cls == float_class_snan) { + t16 = h1r; + } else if (p1c.cls == float_class_snan) { + t16 = h1c; + } else if (p2r.cls == float_class_snan) { + t16 = h2r; + } else { + t16 = h2c; + } } else { - t16 = h2c; + if (p1r.cls == float_class_qnan) { + t16 = h1r; + } else if (p1c.cls == float_class_qnan) { + t16 = h1c; + } else if (p2r.cls == float_class_qnan) { + t16 = h2r; + } else { + t16 = h2c; + } } t32 = float16_to_float32(t16, true, s_f16); } else { - float64 e1r = float16_to_float64(h1r, true, s_f16); - float64 e1c = float16_to_float64(h1c, true, s_f16); - float64 e2r = float16_to_float64(h2r, true, s_f16); - float64 e2c = float16_to_float64(h2c, true, s_f16); - float64 t64; - /* * The ARM pseudocode function FPDot performs both multiplies - * and the add with a single rounding operation. Emulate this - * by performing the first multiply in round-to-odd, then doing - * the second multiply as fused multiply-add, and rounding to - * float32 all in one step. + * and the add with a single rounding operation. */ - t64 = float64_mul(e1r, e2r, s_odd); - t64 = float64r32_muladd(e1c, e2c, t64, 0, s_std); + FloatParts64 tmp = parts64_mul(&p1r, &p2r, s_std); + tmp = parts64_muladd(&p1c, &p2c, &tmp, 0, s_std); - /* This conversion is exact, because we've already rounded. */ - t32 = float64_to_float32(t64, s_std); + t32 = float32_round_pack_canonical(&tmp, s_std); } /* The final accumulation step is not fused. */ @@ -XXX,XX +XXX,XX @@ static void do_fmopa_w_h(void *vza, void *vzn, void *vzm, uint16_t *pn, uint32_t negx, bool ah_neg) { intptr_t row, col, oprsz = simd_maxsz(desc); - float_status fpst_odd = env->vfp.fp_status[FPST_ZA]; - - set_float_rounding_mode(float_round_to_odd, &fpst_odd); for (row = 0; row < oprsz; ) { uint16_t prow = pn[H2(row >> 4)]; @@ -XXX,XX +XXX,XX @@ static void do_fmopa_w_h(void *vza, void *vzn, void *vzm, uint16_t *pn, m = f16mop_adj_pair(m, pcol, 0); *a = f16_dotadd(*a, n, m, &env->vfp.fp_status[FPST_ZA_F16], - &env->vfp.fp_status[FPST_ZA], - &fpst_odd); + &env->vfp.fp_status[FPST_ZA]); } col += 4; pcol >>= 4; @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_fdot_h)(void *vd, void *vn, void *vm, void *va, bool za = extract32(desc, SIMD_DATA_SHIFT, 1); float_status *fpst_std = &env->vfp.fp_status[za ? FPST_ZA : FPST_A64]; float_status *fpst_f16 = &env->vfp.fp_status[za ? FPST_ZA_F16 : FPST_A64_F16]; - float_status fpst_odd = *fpst_std; float32 *d = vd, *a = va; uint32_t *n = vn, *m = vm; - set_float_rounding_mode(float_round_to_odd, &fpst_odd); - for (i = 0; i < oprsz / sizeof(float32); ++i) { d[H4(i)] = f16_dotadd(a[H4(i)], n[H4(i)], m[H4(i)], - fpst_f16, fpst_std, &fpst_odd); + fpst_f16, fpst_std); } } @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_fdot_idx_h)(void *vd, void *vn, void *vm, void *va, bool za = extract32(desc, SIMD_DATA_SHIFT + 2, 1); float_status *fpst_std = &env->vfp.fp_status[za ? FPST_ZA : FPST_A64]; float_status *fpst_f16 = &env->vfp.fp_status[za ? FPST_ZA_F16 : FPST_A64_F16]; - float_status fpst_odd = *fpst_std; float32 *d = vd, *a = va; uint32_t *n = vn, *m = (uint32_t *)vm + H4(idx); - set_float_rounding_mode(float_round_to_odd, &fpst_odd); - for (i = 0; i < elements; i += eltspersegment) { uint32_t mm = m[i]; for (j = 0; j < eltspersegment; ++j) { d[H4(i + j)] = f16_dotadd(a[H4(i + j)], n[H4(i + j)], mm, - fpst_f16, fpst_std, &fpst_odd); + fpst_f16, fpst_std); } } } @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_fvdot_idx_h)(void *vd, void *vn, void *vm, void *va, intptr_t eltspersegment = MIN(4, elements); int idx = extract32(desc, SIMD_DATA_SHIFT, 2); int sel = extract32(desc, SIMD_DATA_SHIFT + 2, 1); - float_status fpst_odd, *fpst_std, *fpst_f16; float32 *d = vd, *a = va; uint16_t *n0 = vn; uint16_t *n1 = vn + sizeof(ARMVectorReg); uint32_t *m = (uint32_t *)vm + H4(idx); - fpst_std = &env->vfp.fp_status[FPST_ZA]; - fpst_f16 = &env->vfp.fp_status[FPST_ZA_F16]; - fpst_odd = *fpst_std; - set_float_rounding_mode(float_round_to_odd, &fpst_odd); - for (i = 0; i < elements; i += eltspersegment) { uint32_t mm = m[i]; for (j = 0; j < eltspersegment; ++j) { uint32_t nn = (n0[H2(2 * (i + j) + sel)]) | (n1[H2(2 * (i + j) + sel)] << 16); d[i + H4(j)] = f16_dotadd(a[i + H4(j)], nn, mm, - fpst_f16, fpst_std, &fpst_odd); + &env->vfp.fp_status[FPST_ZA_F16], + &env->vfp.fp_status[FPST_ZA]); } } } -- 2.43.0
Notice the conflict between saturation and rebias_overflow, which should never happen. Otherwise, saturate to INT32_MAX and allow the usual overflow to max, infinity, or dnan. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, g_assert_not_reached(); } - exp = p->exp + fmt->exp_bias; + /* Because exp_bias is positive, we can only overflow past INT_MAX. */ + if (sadd32_overflow(p->exp, fmt->exp_bias, &exp)) { + /* + * rebias_overflow wants to compute a modulo exponent, which + * conflicts with saturation. That said, saturation can only + * happen with scalbn, which is not a PowerPC operation. + */ + assert(!s->rebias_overflow); + exp = INT32_MAX; + } + if (likely(exp > 0)) { if (p->frac_lo & round_mask) { flags |= float_flag_inexact; -- 2.43.0
Avoid exponent overflow as well as checking that we don't lose information with opposing scaling. Use it in partsN(scalbn) and partsN(round_to_int_normal). Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 17 +++++++++++++++++ fpu/softfloat-parts.c.inc | 5 ++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ static float128 QEMU_FLATTEN float128_pack_raw(const FloatParts128 *p) *----------------------------------------------------------------------------*/ #include "softfloat-specialize.c.inc" +static int32_t exp_scalbn(int32_t exp, int32_t scale) +{ + /* + * Catch chains of scaling which lose information. + * In particular, if the exponent has been saturated, + * do not allow it to become unsaturated. + */ + if (unlikely(exp == INT32_MAX)) { + assert(scale >= 0); + } else if (unlikely(exp == INT32_MIN)) { + assert(scale <= 0); + } else { + exp = sadd32_saturate(exp, scale); + } + return exp; +} + /* * Helper functions for softfloat-parts.c.inc, per-size operations. */ diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode, uint64_t frac_lsb, frac_lsbm1, rnd_even_mask, rnd_mask, inc; int shift_adj; - scale = MIN(MAX(scale, -0x10000), 0x10000); - a->exp += scale; + a->exp = exp_scalbn(a->exp, scale); if (a->exp < 0) { bool one; @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(scalbn)(const FloatPartsN *a, int n, float_status *s) case float_class_normal: { FloatPartsN r = *a; - r.exp += MIN(MAX(n, -0x10000), 0x10000); + r.exp = exp_scalbn(r.exp, n); return r; } default: -- 2.43.0
Changes for v5: - Drop target/arm changes as non-essential; will be moved to another patch set. - Incorporate "Export floatN_minmax" from the FEAT_FP8 patch set. - Incorporate "fpu: Compress float_status", to avoid conflicts with... - Introduce float_status.e4m3_nan_is_snan - Fix NaN encoding for E4M3 in parts64_uncanon r~ Richard Henderson (30): fpu: Return struct from parts{64,128}_scalbn fpu: Reorganize partsN(muladd) fpu: Return struct from parts{64,128}_muladd fpu: Hoist nan check in partsN_addsub fpu: Simplify 0 +/- N case in parts_addsub fpu: Use parts64_round_to_int in parts_s390_divide_to_integer target/s390x: Move float{32,64}_s390_divide_to_integer fpu: Introduce exp_scalbn target/alpha: Remove CONFIG_SOFTFLOAT_INLINE fpu: Introduce FloatExceptionFlags target/alpha: Use FloatExceptionFlags fpu: Introduce frac_msb_is_snan fpu: Introduce FloatSNaNRule fpu: Use {get,set}_float_rounding_mode everywhere fpu: Use of {get,set}_floatx80_rounding_precision everywhere fpu: Use get_floatx80_behaviour everywhere fpu: Use get_float_2nan_prop_rule in partsN_pick_nan fpu: Use get_float_3nan_prop_rule in partsN_pick_nan_muladd fpu: Use get_float_infzeronan_rule in partsN_pick_nan_muladd fpu: Use accessors for tininess_before_rounding fpu: Use {get,set}_flush_to_zero everywhere fpu: Use accessors for ftz_before_rounding fpu: Use {get,set}_flush_inputs_to_zero everywhere fpu: Use get_default_nan_mode everywhere fpu: Use get_float_default_nan_pattern in partsN_default_nan fpu: Add accessors for rebias_{underflow,overflow} fpu: Reorg float_status fpu: Introduce float_status.e4m3_nan_is_snan fpu: Fix NaN encoding for E4M3 in parts64_uncanon fpu: Export floatN_minmax include/fpu/softfloat-helpers.h | 37 +-- include/fpu/softfloat-parts.h | 12 + include/fpu/softfloat-types.h | 89 ++++--- include/fpu/softfloat.h | 112 +++++---- target/i386/ops_sse.h | 24 +- target/mips/fpu_helper.h | 3 +- fpu/softfloat.c | 422 +++++++++++--------------------- target/alpha/fpu_helper.c | 8 +- target/alpha/helper.c | 3 +- target/alpha/translate.c | 18 +- target/arm/tcg/helper-a64.c | 12 +- target/arm/tcg/vfp_helper.c | 38 +-- target/hexagon/fma_emu.c | 6 +- target/hppa/fpu_helper.c | 2 +- target/i386/tcg/fpu_helper.c | 65 ++--- target/m68k/softfloat.c | 380 ++++++++++++++-------------- target/mips/msa.c | 4 +- target/ppc/cpu.c | 4 +- target/ppc/fpu_helper.c | 14 +- target/riscv/vector_helper.c | 6 +- target/s390x/tcg/fpu_helper.c | 139 ++++++++++- target/sh4/cpu.c | 2 +- target/xtensa/cpu.c | 3 +- tests/fp/fp-bench.c | 6 +- tests/fp/fp-test.c | 6 +- fpu/softfloat-parts.c.inc | 313 ++++++++++++----------- fpu/softfloat-specialize.c.inc | 117 +++++---- tests/fp/wrap.c.inc | 12 +- 28 files changed, 936 insertions(+), 921 deletions(-) -- 2.43.0
At the same time, export. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 3 +++ fpu/softfloat.c | 18 +++++++++--------- fpu/softfloat-parts.c.inc | 14 ++++++++------ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/include/fpu/softfloat-parts.h b/include/fpu/softfloat-parts.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-parts.h +++ b/include/fpu/softfloat-parts.h @@ -XXX,XX +XXX,XX @@ FloatParts128 parts128_round_to_int(const FloatParts128 *a, FloatParts64 parts64_round_to_fmt(const FloatParts64 *p, float_status *s, const FloatFmt *fmt); +FloatParts64 parts64_scalbn(const FloatParts64 *a, int n, float_status *s); +FloatParts128 parts128_scalbn(const FloatParts128 *a, int n, float_status *s); + #endif diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ float16 float16_muladd_scalbn(float16 a, float16 b, float16 c, /* Before rounding, scale. */ if (scale) { - parts64_scalbn(pr, scale, status); + *pr = parts64_scalbn(pr, scale, status); } parts64_uncanon(pr, status, &float16_params, false); /* After rounding, apply negate result, especially for -0.0. */ @@ -XXX,XX +XXX,XX @@ float32_muladd_scalbn(float32 a, float32 b, float32 c, /* Before rounding, scale. */ if (scale) { - parts64_scalbn(pr, scale, status); + *pr = parts64_scalbn(pr, scale, status); } parts64_uncanon(pr, status, &float32_params, false); /* After rounding, apply negate result, especially for -0.0. */ @@ -XXX,XX +XXX,XX @@ float64_muladd_scalbn(float64 a, float64 b, float64 c, /* Before rounding, scale. */ if (scale) { - parts64_scalbn(pr, scale, status); + *pr = parts64_scalbn(pr, scale, status); } parts64_uncanon(pr, status, &float64_params, false); /* After rounding, apply negate result, especially for -0.0. */ @@ -XXX,XX +XXX,XX @@ float16 float16_scalbn(float16 a, int n, float_status *status) { FloatParts64 p = float16_unpack_canonical(a, status); - parts64_scalbn(&p, n, status); + p = parts64_scalbn(&p, n, status); return float16_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float32 float32_scalbn(float32 a, int n, float_status *status) { FloatParts64 p = float32_unpack_canonical(a, status); - parts64_scalbn(&p, n, status); + p = parts64_scalbn(&p, n, status); return float32_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float64 float64_scalbn(float64 a, int n, float_status *status) { FloatParts64 p = float64_unpack_canonical(a, status); - parts64_scalbn(&p, n, status); + p = parts64_scalbn(&p, n, status); return float64_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_scalbn(bfloat16 a, int n, float_status *status) { FloatParts64 p = bfloat16_unpack_canonical(a, status); - parts64_scalbn(&p, n, status); + p = parts64_scalbn(&p, n, status); return bfloat16_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float128 float128_scalbn(float128 a, int n, float_status *status) { FloatParts128 p = float128_unpack_canonical(a, status); - parts128_scalbn(&p, n, status); + p = parts128_scalbn(&p, n, status); return float128_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_scalbn(floatx80 a, int n, float_status *status) if (!floatx80_unpack_canonical(&p, a, status)) { return floatx80_default_nan(status); } - parts128_scalbn(&p, n, status); + p = parts128_scalbn(&p, n, status); return floatx80_round_pack_canonical(&p, status); } diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ FloatRelation partsN(compare)(const FloatPartsN *a, const FloatPartsN *b, /* * Multiply A by 2 raised to the power N. */ -static void partsN(scalbn)(FloatPartsN *a, int n, float_status *s) +FloatPartsN partsN(scalbn)(const FloatPartsN *a, int n, float_status *s) { switch (a->cls) { case float_class_snan: case float_class_qnan: - *a = partsN(return_nan)(a, s); - break; + return partsN(return_nan)(a, s); case float_class_zero: case float_class_inf: - break; + return *a; case float_class_denormal: float_raise(float_flag_input_denormal_used, s); /* fall through */ case float_class_normal: - a->exp += MIN(MAX(n, -0x10000), 0x10000); - break; + { + FloatPartsN r = *a; + r.exp += MIN(MAX(n, -0x10000), 0x10000); + return r; + } default: g_assert_not_reached(); } -- 2.43.0
Check the likely case of normal product and normal or zero addend first; shift NaN and infinity detection down; end with zero product + addend. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 156 +++++++++++++++++--------------------- 1 file changed, 71 insertions(+), 85 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, FloatPartsN *c, int flags, float_status *s) { - int ab_mask, abc_mask; - FloatPartsW p_widen, c_widen; + int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); + int c_mask = float_cmask(c->cls); + int abc_mask = ab_mask | c_mask; + bool c_sign = c->sign ^ !!(flags & float_muladd_negate_c); + bool p_sign = a->sign ^ b->sign ^ !!(flags & float_muladd_negate_product); - ab_mask = float_cmask(a->cls) | float_cmask(b->cls); - abc_mask = float_cmask(c->cls) | ab_mask; + /* + * The "likely" case is A and B normal, so that the product is normal, + * and C normal or zero so that the result is normal. + */ + int likely_mask = ab_mask | (c_mask & ~float_cmask_zero); + if (likely(cmask_is_only_normals(likely_mask))) { + record_denormals_used(abc_mask, s); + + /* Perform the multiplication step. */ + FloatPartsW p_widen = { .sign = p_sign, .exp = a->exp + b->exp + 1 }; + fracN(mulw)(&p_widen, a, b); + if (!(p_widen.frac_hi & DECOMPOSED_IMPLICIT_BIT)) { + fracW(add)(&p_widen, &p_widen, &p_widen); + p_widen.exp -= 1; + } + + /* Perform the addition step. */ + if (!(c_mask & float_cmask_zero)) { + /* Zero-extend C to less significant bits. */ + FloatPartsW c_widen = { .sign = c_sign, .exp = c->exp }; + fracN(widen)(&c_widen, c); + + if (p_sign == c_sign) { + partsW(add_normal)(&p_widen, &c_widen); + } else if (!partsW(sub_normal)(&p_widen, &c_widen)) { + goto return_sub_zero; + } + } + + /* Narrow with sticky bit, for proper rounding later. */ + fracN(truncjam)(a, &p_widen); + a->sign = p_widen.sign; + a->exp = p_widen.exp; + return a; + } /* * It is implementation-defined whether the cases of (0,inf,qnan) @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, return a; } - if (flags & float_muladd_negate_c) { - c->sign ^= 1; + if (unlikely(ab_mask == float_cmask_infzero)) { + /* Inf * Zero == NaN */ + float_raise(float_flag_invalid | float_flag_invalid_imz, s); + goto d_nan; } - /* Compute the sign of the product into A. */ - a->sign ^= b->sign; - if (flags & float_muladd_negate_product) { - a->sign ^= 1; - } - - if (unlikely(!cmask_is_only_normals(ab_mask))) { - if (unlikely(ab_mask == float_cmask_infzero)) { - float_raise(float_flag_invalid | float_flag_invalid_imz, s); + if (unlikely(ab_mask & float_cmask_inf)) { + if ((c_mask & float_cmask_inf) && p_sign != c_sign) { + /* Inf - Inf == NaN */ + float_raise(float_flag_invalid | float_flag_invalid_isi, s); goto d_nan; } - - if (ab_mask & float_cmask_inf) { - if (c->cls == float_class_inf && a->sign != c->sign) { - float_raise(float_flag_invalid | float_flag_invalid_isi, s); - goto d_nan; - } - goto return_inf; - } - - g_assert(ab_mask & float_cmask_zero); - if (is_anynorm(c->cls)) { - *a = *c; - goto finish_sign; - } - if (c->cls == float_class_zero) { - if (flags & float_muladd_suppress_add_product_zero) { - a->sign = c->sign; - } else if (a->sign != c->sign) { - goto return_sub_zero; - } - goto return_zero; - } - g_assert(c->cls == float_class_inf); + /* Inf + C == Inf */ + record_denormals_used(abc_mask, s); + a->sign = p_sign; + a->cls = float_class_inf; + return a; } - - if (unlikely(c->cls == float_class_inf)) { - a->sign = c->sign; - goto return_inf; - } - - /* Perform the multiplication step. */ - p_widen.sign = a->sign; - p_widen.exp = a->exp + b->exp + 1; - fracN(mulw)(&p_widen, a, b); - if (!(p_widen.frac_hi & DECOMPOSED_IMPLICIT_BIT)) { - fracW(add)(&p_widen, &p_widen, &p_widen); - p_widen.exp -= 1; - } - - /* Perform the addition step. */ - if (c->cls != float_class_zero) { - /* Zero-extend C to less significant bits. */ - fracN(widen)(&c_widen, c); - c_widen.exp = c->exp; - - if (a->sign == c->sign) { - partsW(add_normal)(&p_widen, &c_widen); - } else if (!partsW(sub_normal)(&p_widen, &c_widen)) { - goto return_sub_zero; - } - } - - /* Narrow with sticky bit, for proper rounding later. */ - fracN(truncjam)(a, &p_widen); - a->sign = p_widen.sign; - a->exp = p_widen.exp; - - finish_sign: - /* - * All result types except for "return the default NaN - * because this is an Invalid Operation" go through here; - * this matches the set of cases where we consumed a - * denormal input. - */ record_denormals_used(abc_mask, s); - return a; + + /* Only remaining cases are zero product or inf addend. */ + assert((ab_mask & float_cmask_zero) | (c_mask & float_cmask_inf)); + + /* + * P + Inf == Inf, or + * 0 + C == C, + * except for 0 - 0, which needs special rounding, + * except for when we want to suppress this addition step. + */ + if (!(c_mask & float_cmask_zero) + || p_sign == c_sign + || (flags & float_muladd_suppress_add_product_zero)) { + c->sign = c_sign; + return c; + } return_sub_zero: + /* 0 - 0 == -0 for round_down, +0 otherwise. */ a->sign = s->float_rounding_mode == float_round_down; - return_zero: a->cls = float_class_zero; - goto finish_sign; - - return_inf: - a->cls = float_class_inf; - goto finish_sign; + return a; d_nan: *a = partsN(default_nan)(s); -- 2.43.0
At the same time, export. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 9 ++++ fpu/softfloat.c | 83 +++++++++++++++++------------------ fpu/softfloat-parts.c.inc | 38 ++++++++-------- 3 files changed, 69 insertions(+), 61 deletions(-) diff --git a/include/fpu/softfloat-parts.h b/include/fpu/softfloat-parts.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-parts.h +++ b/include/fpu/softfloat-parts.h @@ -XXX,XX +XXX,XX @@ FloatParts64 parts64_mul(const FloatParts64 *a, const FloatParts64 *b, FloatParts128 parts128_mul(const FloatParts128 *a, const FloatParts128 *b, float_status *s); +FloatParts64 parts64_muladd(const FloatParts64 *a, + const FloatParts64 *b, + const FloatParts64 *c, + int flags, float_status *s); +FloatParts128 parts128_muladd(const FloatParts128 *a, + const FloatParts128 *b, + const FloatParts128 *c, + int flags, float_status *s); + FloatParts64 parts64_round_to_int(const FloatParts64 *a, FloatRoundMode rmode, int scale, float_status *s, diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ float16 float16_muladd_scalbn(float16 a, float16 b, float16 c, FloatParts64 pa = float16_unpack_canonical(a, status); FloatParts64 pb = float16_unpack_canonical(b, status); FloatParts64 pc = float16_unpack_canonical(c, status); - FloatParts64 *pr = parts64_muladd(&pa, &pb, &pc, flags, status); + FloatParts64 pr = parts64_muladd(&pa, &pb, &pc, flags, status); /* Before rounding, scale. */ if (scale) { - *pr = parts64_scalbn(pr, scale, status); + pr = parts64_scalbn(&pr, scale, status); } - parts64_uncanon(pr, status, &float16_params, false); + parts64_uncanon(&pr, status, &float16_params, false); /* After rounding, apply negate result, especially for -0.0. */ - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return pack_raw64(pr, &float16_params); + return pack_raw64(&pr, &float16_params); } float16 float16_muladd(float16 a, float16 b, float16 c, @@ -XXX,XX +XXX,XX @@ float32_muladd_scalbn(float32 a, float32 b, float32 c, FloatParts64 pa = float32_unpack_canonical(a, status); FloatParts64 pb = float32_unpack_canonical(b, status); FloatParts64 pc = float32_unpack_canonical(c, status); - FloatParts64 *pr = parts64_muladd(&pa, &pb, &pc, flags, status); + FloatParts64 pr = parts64_muladd(&pa, &pb, &pc, flags, status); /* Before rounding, scale. */ if (scale) { - *pr = parts64_scalbn(pr, scale, status); + pr = parts64_scalbn(&pr, scale, status); } - parts64_uncanon(pr, status, &float32_params, false); + parts64_uncanon(&pr, status, &float32_params, false); /* After rounding, apply negate result, especially for -0.0. */ - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return pack_raw64(pr, &float32_params); + return pack_raw64(&pr, &float32_params); } float64 QEMU_SOFTFLOAT_ATTR @@ -XXX,XX +XXX,XX @@ float64_muladd_scalbn(float64 a, float64 b, float64 c, FloatParts64 pa = float64_unpack_canonical(a, status); FloatParts64 pb = float64_unpack_canonical(b, status); FloatParts64 pc = float64_unpack_canonical(c, status); - FloatParts64 *pr = parts64_muladd(&pa, &pb, &pc, flags, status); + FloatParts64 pr = parts64_muladd(&pa, &pb, &pc, flags, status); /* Before rounding, scale. */ if (scale) { - *pr = parts64_scalbn(pr, scale, status); + pr = parts64_scalbn(&pr, scale, status); } - parts64_uncanon(pr, status, &float64_params, false); + parts64_uncanon(&pr, status, &float64_params, false); /* After rounding, apply negate result, especially for -0.0. */ - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return pack_raw64(pr, &float64_params); + return pack_raw64(&pr, &float64_params); } static bool force_soft_fma; @@ -XXX,XX +XXX,XX @@ float64 float64r32_muladd(float64 a, float64 b, float64 c, FloatParts64 pa = float64_unpack_canonical(a, status); FloatParts64 pb = float64_unpack_canonical(b, status); FloatParts64 pc = float64_unpack_canonical(c, status); - FloatParts64 *pr = parts64_muladd(&pa, &pb, &pc, flags, status); + FloatParts64 pr = parts64_muladd(&pa, &pb, &pc, flags, status); /* Round before applying negate result. */ - parts64_uncanon(pr, status, &float32_params, false); - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + parts64_uncanon(&pr, status, &float32_params, false); + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return float64r32_pack_raw(pr); + return float64r32_pack_raw(&pr); } bfloat16 bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, FloatParts64 pa = bfloat16_unpack_canonical(a, status); FloatParts64 pb = bfloat16_unpack_canonical(b, status); FloatParts64 pc = bfloat16_unpack_canonical(c, status); - FloatParts64 *pr = parts64_muladd(&pa, &pb, &pc, flags, status); + FloatParts64 pr = parts64_muladd(&pa, &pb, &pc, flags, status); /* Round before applying negate result. */ - parts64_uncanon(pr, status, &bfloat16_params, false); - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + parts64_uncanon(&pr, status, &bfloat16_params, false); + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return pack_raw64(pr, &bfloat16_params); + return pack_raw64(&pr, &bfloat16_params); } float128 float128_muladd(float128 a, float128 b, float128 c, @@ -XXX,XX +XXX,XX @@ float128 float128_muladd(float128 a, float128 b, float128 c, FloatParts128 pa = float128_unpack_canonical(a, status); FloatParts128 pb = float128_unpack_canonical(b, status); FloatParts128 pc = float128_unpack_canonical(c, status); - FloatParts128 *pr = parts128_muladd(&pa, &pb, &pc, flags, status); + FloatParts128 pr = parts128_muladd(&pa, &pb, &pc, flags, status); /* Round before applying negate result. */ - parts128_uncanon(pr, status, &float128_params, false); - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + parts128_uncanon(&pr, status, &float128_params, false); + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return float128_pack_raw(pr); + return float128_pack_raw(&pr); } /* @@ -XXX,XX +XXX,XX @@ float32 float32_exp2(float32 a, float_status *status) rp = float64_unpack_canonical(float64_one, status); for (int i = 0; i < 15; i++) { tp = float64_unpack_canonical(float32_exp2_coefficients[i], status); - rp = *parts64_muladd(&tp, &xnp, &rp, 0, status); + rp = parts64_muladd(&tp, &xnp, &rp, 0, status); xnp = parts64_mul(&xnp, &xp, status); } @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, n->sign = a->sign ^ b->sign; *cc = 0; } else { - FloatParts64 *q, q_buf, *r_precise, r_precise_buf; + FloatParts64 *q, q_buf, r_precise; int float_exception_flags = 0; bool is_q_smallish; uint32_t r_flags; @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, 0, fmt->frac_size); /* Compute precise remainder */ - r_precise_buf = *b; - r_precise = parts64_muladd(&r_precise_buf, n, a, + r_precise = parts64_muladd(b, n, a, float_muladd_negate_product, status); /* Round remainder to the target format */ - *r = *r_precise; + *r = r_precise; status->float_exception_flags = 0; *r = parts64_round_to_fmt(r, status, fmt); r_flags = status->float_exception_flags; @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, * toward zero) or incremented. */ saved_r_sign = r->sign; - saved_r_precise_sign = r_precise->sign; + saved_r_precise_sign = r_precise.sign; r->sign = false; - r_precise->sign = false; - if (parts64_compare(r, r_precise, status, true) < + r_precise.sign = false; + if (parts64_compare(r, &r_precise, status, true) < float_relation_equal) { *dxc = 0x8; } else { *dxc = 0xc; } r->sign = saved_r_sign; - r_precise->sign = saved_r_precise_sign; + r_precise.sign = saved_r_precise_sign; } } } diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(mul)(const FloatPartsN *a, const FloatPartsN *b, * Requires A and C extracted into a double-sized structure to provide the * extra space for the widening multiply. */ -static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, - FloatPartsN *c, - int flags, float_status *s) +FloatPartsN partsN(muladd)(const FloatPartsN *a, const FloatPartsN *b, + const FloatPartsN *c, int flags, float_status *s) { int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); int c_mask = float_cmask(c->cls); @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, } /* Narrow with sticky bit, for proper rounding later. */ - fracN(truncjam)(a, &p_widen); - a->sign = p_widen.sign; - a->exp = p_widen.exp; - return a; + FloatPartsN r = { + .sign = p_widen.sign, + .exp = p_widen.exp, + .cls = float_class_normal, + }; + fracN(truncjam)(&r, &p_widen); + return r; } /* @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, * off to the target-specific pick-a-NaN routine. */ if (unlikely(abc_mask & float_cmask_anynan)) { - *a = partsN(pick_nan_muladd)(a, b, c, s, ab_mask, abc_mask); - return a; + return partsN(pick_nan_muladd)(a, b, c, s, ab_mask, abc_mask); } if (unlikely(ab_mask == float_cmask_infzero)) { @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, } /* Inf + C == Inf */ record_denormals_used(abc_mask, s); - a->sign = p_sign; - a->cls = float_class_inf; - return a; + return (FloatPartsN){ .sign = p_sign, .cls = float_class_inf }; } record_denormals_used(abc_mask, s); @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, if (!(c_mask & float_cmask_zero) || p_sign == c_sign || (flags & float_muladd_suppress_add_product_zero)) { - c->sign = c_sign; - return c; + FloatPartsN r = *c; + r.sign = c_sign; + return r; } return_sub_zero: /* 0 - 0 == -0 for round_down, +0 otherwise. */ - a->sign = s->float_rounding_mode == float_round_down; - a->cls = float_class_zero; - return a; + return (FloatPartsN){ + .sign = s->float_rounding_mode == float_round_down, + .cls = float_class_zero + }; d_nan: - *a = partsN(default_nan)(s); - return a; + return partsN(default_nan)(s); } /* -- 2.43.0
The nan test had been down below because it was unlikely. But if we have to have one anyway because of denormals, we might as well take care of them right away. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, { int ab_mask = float_cmask(a_orig->cls) | float_cmask(b_orig->cls); + if (unlikely(ab_mask & float_cmask_anynan)) { + return partsN(pick_nan)(a_orig, b_orig, s); + } + /* * For addition and subtraction, we will consume an * input denormal unless the other input is a NaN. */ - if (!(ab_mask & float_cmask_anynan)) { - record_denormals_used(ab_mask, s); - } + record_denormals_used(ab_mask, s); FloatPartsN a = *a_orig; FloatPartsN b = *b_orig; @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, return a; } - if (unlikely(ab_mask & float_cmask_anynan)) { - goto p_nan; - } - if (ab_mask & float_cmask_inf) { if (a.cls != float_class_inf) { /* N - Inf */ @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, return a; } - if (unlikely(ab_mask & float_cmask_anynan)) { - goto p_nan; - } - if (ab_mask & float_cmask_inf) { a.cls = float_class_inf; return a; @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, g_assert(a.cls == float_class_zero); g_assert(is_anynorm(b.cls)); return b; - - p_nan: - return partsN(pick_nan)(a_orig, b_orig, s); } /* -- 2.43.0
Consolidate the tests for zero and anynorm. Add comments for a few cases. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, } if (ab_mask == float_cmask_zero) { + /* 0 - 0 */ a.sign = s->float_rounding_mode == float_round_down; return a; } @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, } if (ab_mask == float_cmask_zero) { + /* 0 + 0 */ return a; } if (ab_mask & float_cmask_inf) { + /* N + Inf or Inf + N */ a.cls = float_class_inf; return a; } } - if (b.cls == float_class_zero) { - g_assert(is_anynorm(a.cls)); - return a; - } - - g_assert(a.cls == float_class_zero); - g_assert(is_anynorm(b.cls)); - return b; + /* 0 +/- N or N +/- 0 */ + assert((ab_mask & float_cmask_zero) && (ab_mask & float_cmask_anynorm)); + return b.cls == float_class_zero ? a : b; } /* -- 2.43.0
We will not expose parts_round_to_int_normal. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, * Rounding of partial quotient may be inexact. This is the whole point * of distinguishing partial quotients, so ignore the exception. */ - *n = *q; - parts64_round_to_int_normal(n, - is_q_smallish - ? final_quotient_rounding_mode - : float_round_to_zero, - 0, fmt->frac_size); + *n = parts64_round_to_int(q, + is_q_smallish + ? final_quotient_rounding_mode + : float_round_to_zero, + 0, status, fmt); /* Compute precise remainder */ r_precise = parts64_muladd(b, n, a, -- 2.43.0
Now that we've exposed enough infrastructure, this can be implemented in the backend that needs it. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Ilya Leoshkevich <iii@linux.ibm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat.h | 11 --- fpu/softfloat.c | 137 ---------------------------------- target/s390x/tcg/fpu_helper.c | 135 +++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 148 deletions(-) diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -XXX,XX +XXX,XX @@ static inline bool float128_unordered_quiet(float128 a, float128 b, *----------------------------------------------------------------------------*/ float128 float128_default_nan(float_status *status); -#define DECLARE_S390_DIVIDE_TO_INTEGER(floatN) \ -void floatN ## _s390_divide_to_integer(floatN a, floatN b, \ - int final_quotient_rounding_mode, \ - bool mask_underflow, bool mask_inexact, \ - floatN *r, floatN *n, \ - uint32_t *cc, int *dxc, \ - float_status *status) -DECLARE_S390_DIVIDE_TO_INTEGER(float32); -DECLARE_S390_DIVIDE_TO_INTEGER(float64); - - #endif /* SOFTFLOAT_H */ diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_round(floatx80 a, float_status *status) return floatx80_round_pack_canonical(&p, status); } -static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, - int final_quotient_rounding_mode, - bool mask_underflow, bool mask_inexact, - const FloatFmt *fmt, - FloatParts64 *r, FloatParts64 *n, - uint32_t *cc, int *dxc, - float_status *status) -{ - /* POp table "Results: DIVIDE TO INTEGER (Part 1 of 2)" */ - if ((float_cmask(a->cls) | float_cmask(b->cls)) & float_cmask_anynan) { - *r = parts64_pick_nan(a, b, status); - *n = *r; - *cc = 1; - } else if (a->cls == float_class_inf || b->cls == float_class_zero) { - *r = parts64_default_nan(status); - *n = *r; - *cc = 1; - status->float_exception_flags |= float_flag_invalid; - } else if (b->cls == float_class_inf) { - *r = *a; - n->cls = float_class_zero; - n->sign = a->sign ^ b->sign; - *cc = 0; - } else { - FloatParts64 *q, q_buf, r_precise; - int float_exception_flags = 0; - bool is_q_smallish; - uint32_t r_flags; - - /* Compute precise quotient */ - q_buf = parts64_div(a, b, status); - q = &q_buf; - - /* - * Check whether two closest integers can be precisely represented, - * i.e., all their bits fit into the fractional part. - */ - is_q_smallish = q->exp < (fmt->frac_size + 1); - - /* - * Final quotient is rounded using final-quotient-rounding method, and - * partial quotient is rounded toward zero. - * - * Rounding of partial quotient may be inexact. This is the whole point - * of distinguishing partial quotients, so ignore the exception. - */ - *n = parts64_round_to_int(q, - is_q_smallish - ? final_quotient_rounding_mode - : float_round_to_zero, - 0, status, fmt); - - /* Compute precise remainder */ - r_precise = parts64_muladd(b, n, a, - float_muladd_negate_product, status); - - /* Round remainder to the target format */ - *r = r_precise; - status->float_exception_flags = 0; - *r = parts64_round_to_fmt(r, status, fmt); - r_flags = status->float_exception_flags; - - /* POp table "Results: DIVIDE TO INTEGER (Part 2 of 2)" */ - if (is_q_smallish) { - if (r->cls != float_class_zero) { - if (r->exp < 2 - (1 << (fmt->exp_size - 1))) { - if (mask_underflow) { - float_exception_flags |= float_flag_underflow; - *dxc = 0x10; - r->exp += fmt->exp_re_bias; - } - } else if (r_flags & float_flag_inexact) { - float_exception_flags |= float_flag_inexact; - if (mask_inexact) { - bool saved_r_sign, saved_r_precise_sign; - - /* - * Check whether remainder was truncated (rounded - * toward zero) or incremented. - */ - saved_r_sign = r->sign; - saved_r_precise_sign = r_precise.sign; - r->sign = false; - r_precise.sign = false; - if (parts64_compare(r, &r_precise, status, true) < - float_relation_equal) { - *dxc = 0x8; - } else { - *dxc = 0xc; - } - r->sign = saved_r_sign; - r_precise.sign = saved_r_precise_sign; - } - } - } - *cc = 0; - } else if (n->exp > (1 << (fmt->exp_size - 1)) - 1) { - n->exp -= fmt->exp_re_bias; - *cc = r->cls == float_class_zero ? 1 : 3; - } else { - *cc = r->cls == float_class_zero ? 0 : 2; - } - - /* Adjust signs of zero results */ - if (r->cls == float_class_zero) { - r->sign = a->sign; - } - if (n->cls == float_class_zero) { - n->sign = a->sign ^ b->sign; - } - - status->float_exception_flags = float_exception_flags; - } -} - -#define DEFINE_S390_DIVIDE_TO_INTEGER(floatN) \ -void floatN ## _s390_divide_to_integer(floatN a, floatN b, \ - int final_quotient_rounding_mode, \ - bool mask_underflow, bool mask_inexact, \ - floatN *r, floatN *n, \ - uint32_t *cc, int *dxc, \ - float_status *status) \ -{ \ - FloatParts64 pa = floatN ## _unpack_canonical(a, status); \ - FloatParts64 pb = floatN ## _unpack_canonical(b, status); \ - FloatParts64 pr, pn; \ - parts_s390_divide_to_integer(&pa, &pb, final_quotient_rounding_mode, \ - mask_underflow, mask_inexact, \ - &floatN ## _params, \ - &pr, &pn, cc, dxc, status); \ - *r = floatN ## _round_pack_canonical(&pr, status); \ - *n = floatN ## _round_pack_canonical(&pn, status); \ -} - -DEFINE_S390_DIVIDE_TO_INTEGER(float32) -DEFINE_S390_DIVIDE_TO_INTEGER(float64) - static void __attribute__((constructor)) softfloat_init(void) { union_float64 ua, ub, uc, ur; diff --git a/target/s390x/tcg/fpu_helper.c b/target/s390x/tcg/fpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/s390x/tcg/fpu_helper.c +++ b/target/s390x/tcg/fpu_helper.c @@ -XXX,XX +XXX,XX @@ #include "tcg_s390x.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" +#include "fpu/softfloat-parts.h" /* #define DEBUG_HELPER */ #ifdef DEBUG_HELPER @@ -XXX,XX +XXX,XX @@ Int128 HELPER(dxb)(CPUS390XState *env, Int128 a, Int128 b) return RET128(ret); } +static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, + int final_quotient_rounding_mode, + bool mask_underflow, bool mask_inexact, + const FloatFmt *fmt, + FloatParts64 *r, FloatParts64 *n, + uint32_t *cc, int *dxc, + float_status *status) +{ + /* POp table "Results: DIVIDE TO INTEGER (Part 1 of 2)" */ + if ((float_cmask(a->cls) | float_cmask(b->cls)) & float_cmask_anynan) { + *r = parts64_pick_nan(a, b, status); + *n = *r; + *cc = 1; + } else if (a->cls == float_class_inf || b->cls == float_class_zero) { + *r = parts64_default_nan(status); + *n = *r; + *cc = 1; + status->float_exception_flags |= float_flag_invalid; + } else if (b->cls == float_class_inf) { + *r = *a; + n->cls = float_class_zero; + n->sign = a->sign ^ b->sign; + *cc = 0; + } else { + FloatParts64 *q, q_buf, r_precise; + int float_exception_flags = 0; + bool is_q_smallish; + uint32_t r_flags; + + /* Compute precise quotient */ + q_buf = parts64_div(a, b, status); + q = &q_buf; + + /* + * Check whether two closest integers can be precisely represented, + * i.e., all their bits fit into the fractional part. + */ + is_q_smallish = q->exp < (fmt->frac_size + 1); + + /* + * Final quotient is rounded using final-quotient-rounding method, and + * partial quotient is rounded toward zero. + * + * Rounding of partial quotient may be inexact. This is the whole point + * of distinguishing partial quotients, so ignore the exception. + */ + *n = parts64_round_to_int(q, + is_q_smallish + ? final_quotient_rounding_mode + : float_round_to_zero, + 0, status, fmt); + + /* Compute precise remainder */ + r_precise = parts64_muladd(b, n, a, + float_muladd_negate_product, status); + + /* Round remainder to the target format */ + *r = r_precise; + status->float_exception_flags = 0; + *r = parts64_round_to_fmt(r, status, fmt); + r_flags = status->float_exception_flags; + + /* POp table "Results: DIVIDE TO INTEGER (Part 2 of 2)" */ + if (is_q_smallish) { + if (r->cls != float_class_zero) { + if (r->exp < 2 - (1 << (fmt->exp_size - 1))) { + if (mask_underflow) { + float_exception_flags |= float_flag_underflow; + *dxc = 0x10; + r->exp += fmt->exp_re_bias; + } + } else if (r_flags & float_flag_inexact) { + float_exception_flags |= float_flag_inexact; + if (mask_inexact) { + bool saved_r_sign, saved_r_precise_sign; + + /* + * Check whether remainder was truncated (rounded + * toward zero) or incremented. + */ + saved_r_sign = r->sign; + saved_r_precise_sign = r_precise.sign; + r->sign = false; + r_precise.sign = false; + if (parts64_compare(r, &r_precise, status, true) < + float_relation_equal) { + *dxc = 0x8; + } else { + *dxc = 0xc; + } + r->sign = saved_r_sign; + r_precise.sign = saved_r_precise_sign; + } + } + } + *cc = 0; + } else if (n->exp > (1 << (fmt->exp_size - 1)) - 1) { + n->exp -= fmt->exp_re_bias; + *cc = r->cls == float_class_zero ? 1 : 3; + } else { + *cc = r->cls == float_class_zero ? 0 : 2; + } + + /* Adjust signs of zero results */ + if (r->cls == float_class_zero) { + r->sign = a->sign; + } + if (n->cls == float_class_zero) { + n->sign = a->sign ^ b->sign; + } + + status->float_exception_flags = float_exception_flags; + } +} + +#define DEFINE_S390_DIVIDE_TO_INTEGER(floatN) \ +static void floatN ## _s390_divide_to_integer(floatN a, floatN b, \ + int final_quotient_rounding_mode, bool mask_underflow, bool mask_inexact, \ + floatN *r, floatN *n, uint32_t *cc, int *dxc, float_status *status) \ +{ \ + FloatParts64 pa = floatN ## _unpack_canonical(a, status); \ + FloatParts64 pb = floatN ## _unpack_canonical(b, status); \ + FloatParts64 pr, pn; \ + parts_s390_divide_to_integer(&pa, &pb, final_quotient_rounding_mode, \ + mask_underflow, mask_inexact, \ + &floatN ## _params, \ + &pr, &pn, cc, dxc, status); \ + *r = floatN ## _round_pack_canonical(&pr, status); \ + *n = floatN ## _round_pack_canonical(&pn, status); \ +} + +DEFINE_S390_DIVIDE_TO_INTEGER(float32) +DEFINE_S390_DIVIDE_TO_INTEGER(float64) + void HELPER(dib)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3, uint32_t m4, uint32_t bits) { -- 2.43.0
Avoid exponent overflow as well as checking that we don't lose information with opposing scaling. Use it in partsN(scalbn) and partsN(round_to_int_normal). Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 29 +++++++++++++++++++++++++++++ fpu/softfloat-parts.c.inc | 5 ++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ typedef struct { uint64_t frac_lo; } FloatParts256; +/* + * Minimum and maximum exponent for scalbn. + * These are chosen to be much larger than the true exponent for any input format, + * but also not at the bounds of INT32_{MIN,MAX} so that we can perform other + * arithmetic on the exponent without overflowing, particularly during uncanon. + */ +#define SCALBN_EXP_MAX 0x0fffffff +#define SCALBN_EXP_MIN (-SCALBN_EXP_MAX) + /* These apply to the most significant word of each FloatPartsN. */ #define DECOMPOSED_BINARY_POINT 63 #define DECOMPOSED_IMPLICIT_BIT (1ull << DECOMPOSED_BINARY_POINT) @@ -XXX,XX +XXX,XX @@ static float128 QEMU_FLATTEN float128_pack_raw(const FloatParts128 *p) *----------------------------------------------------------------------------*/ #include "softfloat-specialize.c.inc" +static int32_t exp_scalbn(int32_t exp, int32_t scale) +{ + /* + * Catch chains of scaling which lose information. + * In particular, if the exponent has been saturated, + * do not allow it to become unsaturated. + */ + if (exp >= SCALBN_EXP_MAX) { + assert(scale >= 0); + } else if (exp <= SCALBN_EXP_MIN) { + assert(scale <= 0); + } + if (sadd32_overflow(exp, scale, &exp)) { + exp = scale < 0 ? SCALBN_EXP_MIN : SCALBN_EXP_MAX; + } else { + exp = MIN(MAX(exp, SCALBN_EXP_MIN), SCALBN_EXP_MAX); + } + return exp; +} + /* * Helper functions for softfloat-parts.c.inc, per-size operations. */ diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode, uint64_t frac_lsb, frac_lsbm1, rnd_even_mask, rnd_mask, inc; int shift_adj; - scale = MIN(MAX(scale, -0x10000), 0x10000); - a->exp += scale; + a->exp = exp_scalbn(a->exp, scale); if (a->exp < 0) { bool one; @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(scalbn)(const FloatPartsN *a, int n, float_status *s) case float_class_normal: { FloatPartsN r = *a; - r.exp += MIN(MAX(n, -0x10000), 0x10000); + r.exp = exp_scalbn(r.exp, n); return r; } default: -- 2.43.0
Don't peek into float_status internals. Fix the helper calls that were missing an argument. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/alpha/translate.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/target/alpha/translate.c b/target/alpha/translate.c index XXXXXXX..XXXXXXX 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -XXX,XX +XXX,XX @@ #undef HELPER_H #undef ALPHA_DEBUG_DISAS -#define CONFIG_SOFTFLOAT_INLINE #ifdef ALPHA_DEBUG_DISAS # define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) @@ -XXX,XX +XXX,XX @@ static void gen_qual_roundmode(DisasContext *ctx, int fn11) break; } -#if defined(CONFIG_SOFTFLOAT_INLINE) - /* ??? The "fpu/softfloat.h" interface is to call set_float_rounding_mode. - With CONFIG_SOFTFLOAT that expands to an out-of-line call that just - sets the one field. */ - tcg_gen_st8_i32(tmp, tcg_env, - offsetof(CPUAlphaState, fp_status.float_rounding_mode)); -#else - gen_helper_setroundmode(tmp); -#endif + gen_helper_setroundmode(tcg_env, tmp); } static void gen_qual_flushzero(DisasContext *ctx, int fn11) @@ -XXX,XX +XXX,XX @@ static void gen_qual_flushzero(DisasContext *ctx, int fn11) tcg_gen_movi_i32(tmp, 1); } -#if defined(CONFIG_SOFTFLOAT_INLINE) - tcg_gen_st8_i32(tmp, tcg_env, - offsetof(CPUAlphaState, fp_status.flush_to_zero)); -#else - gen_helper_setflushzero(tmp); -#endif + gen_helper_setflushzero(tcg_env, tmp); } static TCGv_i64 gen_ieee_input(DisasContext *ctx, int reg, int fn11, int is_cmp) -- 2.43.0
We have, in the past, used any of uint8_t, uint16_t or int to hold the set of exception flags. Use a typedef instead. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-helpers.h | 6 ++++-- include/fpu/softfloat-types.h | 4 +++- include/fpu/softfloat.h | 2 +- fpu/softfloat.c | 2 +- fpu/softfloat-parts.c.inc | 7 ++++--- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-helpers.h +++ b/include/fpu/softfloat-helpers.h @@ -XXX,XX +XXX,XX @@ static inline void set_float_rounding_mode(FloatRoundMode val, status->float_rounding_mode = val; } -static inline void set_float_exception_flags(int val, float_status *status) +static inline void +set_float_exception_flags(FloatExceptionFlags val, float_status *status) { status->float_exception_flags = val; } @@ -XXX,XX +XXX,XX @@ static inline FloatRoundMode get_float_rounding_mode(const float_status *status) return status->float_rounding_mode; } -static inline int get_float_exception_flags(const float_status *status) +static inline FloatExceptionFlags +get_float_exception_flags(const float_status *status) { return status->float_exception_flags; } diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-types.h +++ b/include/fpu/softfloat-types.h @@ -XXX,XX +XXX,XX @@ enum { float_flag_input_denormal_used = 0x4000, }; +typedef uint16_t FloatExceptionFlags; + /* * Rounding precision for floatx80. */ @@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) { */ typedef struct float_status { - uint16_t float_exception_flags; + FloatExceptionFlags float_exception_flags; FloatRoundMode float_rounding_mode; FloatX80RoundPrec floatx80_rounding_precision; FloatX80Behaviour floatx80_behaviour; diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -XXX,XX +XXX,XX @@ typedef enum { | Routine to raise any or all of the software IEC/IEEE floating-point | exception flags. *----------------------------------------------------------------------------*/ -static inline void float_raise(uint16_t flags, float_status *status) +static inline void float_raise(FloatExceptionFlags flags, float_status *status) { status->float_exception_flags |= flags; } diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ static int64_t float128_to_int64_scalbn(float128 a, FloatRoundMode rmode, static Int128 float128_to_int128_scalbn(float128 a, FloatRoundMode rmode, int scale, float_status *s) { - int flags = 0; + FloatExceptionFlags flags = 0; Int128 r; FloatParts128 p = float128_unpack_canonical(a, s); diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, const uint64_t roundeven_mask = round_mask | frac_lsb; uint64_t inc; bool overflow_norm = saturate; - int exp, flags = 0; + int exp; + FloatExceptionFlags flags = 0; switch (s->float_rounding_mode) { case float_round_nearest_even_max: @@ -XXX,XX +XXX,XX @@ static int64_t partsN(float_to_sint)(FloatPartsN *p, FloatRoundMode rmode, int scale, int64_t min, int64_t max, float_status *s) { - int flags = 0; + FloatExceptionFlags flags = 0; uint64_t r; switch (p->cls) { @@ -XXX,XX +XXX,XX @@ static int64_t partsN(float_to_sint)(FloatPartsN *p, FloatRoundMode rmode, static uint64_t partsN(float_to_uint)(FloatPartsN *p, FloatRoundMode rmode, int scale, uint64_t max, float_status *s) { - int flags = 0; + FloatExceptionFlags flags = 0; uint64_t r; switch (p->cls) { -- 2.43.0
Fixes a bug in which we were still using uint8_t. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/alpha/fpu_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/alpha/fpu_helper.c b/target/alpha/fpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/alpha/fpu_helper.c +++ b/target/alpha/fpu_helper.c @@ -XXX,XX +XXX,XX @@ void helper_setflushzero(CPUAlphaState *env, uint32_t val) static uint32_t soft_to_fpcr_exc(CPUAlphaState *env) { - uint8_t exc = get_float_exception_flags(&FP_STATUS); + FloatExceptionFlags exc = get_float_exception_flags(&FP_STATUS); uint32_t ret = 0; if (unlikely(exc)) { @@ -XXX,XX +XXX,XX @@ static uint64_t do_cvttq(CPUAlphaState *env, uint64_t a, int roundmode) float64 fa; int64_t ret; uint32_t exc = 0; - int flags; + FloatExceptionFlags flags; fa = t_to_float64(a); ret = float64_to_int64_modulo(fa, roundmode, &FP_STATUS); -- 2.43.0
Unify handling of the two snan parameters, letting the caller simply extract the msb. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-specialize.c.inc | 45 ++++++++++------------------------ 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -XXX,XX +XXX,XX @@ static inline bool snan_bit_is_one(float_status *status) | if the fraction represents a signalling NaN; otherwise false. *----------------------------------------------------------------------------*/ -static bool parts_is_snan_frac(uint64_t frac, float_status *status) +static bool frac_msb_is_snan(bool msb, float_status *status) { if (no_signaling_nans(status)) { return false; } else { - bool msb = extract64(frac, DECOMPOSED_BINARY_POINT - 1, 1); return msb == snan_bit_is_one(status); } } +static bool parts_is_snan_frac(uint64_t frac, float_status *status) +{ + bool msb = extract64(frac, DECOMPOSED_BINARY_POINT - 1, 1); + return frac_msb_is_snan(msb, status); +} + /*---------------------------------------------------------------------------- | The pattern for a default generated deconstructed floating-point NaN. *----------------------------------------------------------------------------*/ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_default_inf(bool zSign, float_status *status) static bool float16_nan_is_snan(float16 a, float_status *status) { - if (no_signaling_nans(status)) { - return false; - } - bool frac_msb_is_one = (a >> 9) & 1; - return frac_msb_is_one == snan_bit_is_one(status); + return frac_msb_is_snan((a >> 9) & 1, status); } /*---------------------------------------------------------------------------- @@ -XXX,XX +XXX,XX @@ bool float16_is_signaling_nan(float16 a_, float_status *status) static bool bfloat16_nan_is_snan(bfloat16 a, float_status *status) { - if (no_signaling_nans(status)) { - return false; - } - bool frac_msb_is_one = (a >> 6) & 1; - return frac_msb_is_one == snan_bit_is_one(status); + return frac_msb_is_snan((a >> 6) & 1, status); } /*---------------------------------------------------------------------------- @@ -XXX,XX +XXX,XX @@ bool bfloat16_is_signaling_nan(bfloat16 a_, float_status *status) static bool float32_nan_is_snan(float32 a, float_status *status) { - if (no_signaling_nans(status)) { - return false; - } - bool frac_msb_is_one = (a >> 22) & 1; - return frac_msb_is_one == snan_bit_is_one(status); + return frac_msb_is_snan((a >> 22) & 1, status); } /*---------------------------------------------------------------------------- @@ -XXX,XX +XXX,XX @@ bool float32_is_signaling_nan(float32 a_, float_status *status) static bool float64_nan_is_snan(float64 a, float_status *status) { - if (no_signaling_nans(status)) { - return false; - } - bool frac_msb_is_one = (a >> 51) & 1; - return frac_msb_is_one == snan_bit_is_one(status); + return frac_msb_is_snan((a >> 51) & 1, status); } /*---------------------------------------------------------------------------- @@ -XXX,XX +XXX,XX @@ bool float64_is_signaling_nan(float64 a_, float_status *status) static bool floatx80_nan_is_snan(floatx80 a, float_status *status) { - if (no_signaling_nans(status)) { - return false; - } - bool frac_msb_is_one = (a.low >> 62) & 1; - return frac_msb_is_one == snan_bit_is_one(status); + return frac_msb_is_snan((a.low >> 62) & 1, status); } /*---------------------------------------------------------------------------- @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_silence_nan(floatx80 a, float_status *status) static bool float128_nan_is_snan(float128 a, float_status *status) { - if (no_signaling_nans(status)) { - return false; - } - bool frac_msb_is_one = (a.high >> 47) & 1; - return frac_msb_is_one == snan_bit_is_one(status); + return frac_msb_is_snan((a.high >> 47) & 1, status); } /*---------------------------------------------------------------------------- -- 2.43.0
Merge snan_bit_is_one and no_signaling_nans into one control. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-helpers.h | 14 +++++----- include/fpu/softfloat-types.h | 25 ++++++++++++----- target/mips/fpu_helper.h | 3 ++- target/hppa/fpu_helper.c | 2 +- target/mips/msa.c | 4 +-- target/sh4/cpu.c | 2 +- target/xtensa/cpu.c | 3 ++- fpu/softfloat-specialize.c.inc | 48 +++++++++++++-------------------- 8 files changed, 51 insertions(+), 50 deletions(-) diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-helpers.h +++ b/include/fpu/softfloat-helpers.h @@ -XXX,XX +XXX,XX @@ static inline void set_default_nan_mode(bool val, float_status *status) status->default_nan_mode = val; } -static inline void set_snan_bit_is_one(bool val, float_status *status) +static inline void set_snan_rule(FloatSNaNRule val, float_status *status) { - status->snan_bit_is_one = val; -} - -static inline void set_no_signaling_nans(bool val, float_status *status) -{ - status->no_signaling_nans = val; + status->float_snan_rule = val; } static inline bool get_float_detect_tininess(const float_status *status) @@ -XXX,XX +XXX,XX @@ static inline bool get_default_nan_mode(const float_status *status) return status->default_nan_mode; } +static inline FloatSNaNRule get_snan_rule(float_status *status) +{ + return status->float_snan_rule; +} + static inline FloatFTZDetection get_float_ftz_detection(const float_status *status) { return status->ftz_detection; diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-types.h +++ b/include/fpu/softfloat-types.h @@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) { floatx80_precision_s, } FloatX80RoundPrec; +/* + * Define how the architecture discriminates signaling NaNs. + * This done with the most significant bit of the fraction. + * + * In IEEE 754-1985 this was implementation defined, but in IEEE 754-2008 + * the msb must be 0. But setting the msb to 1 got baked into HPPA, SH4, + * and pre-2008 MIPS. + * + * Further, some architectures (or modes of architectures) do not detect + * signaling NaNs at all. + */ +typedef enum __attribute__((__packed__)) { + float_snan_bit_is_zero, + float_snan_bit_is_one, + float_snan_never, +} FloatSNaNRule; + /* * 2-input NaN propagation rule. Individual architectures have * different rules for which input NaN is propagated to the output @@ -XXX,XX +XXX,XX @@ typedef struct float_status { Float2NaNPropRule float_2nan_prop_rule; Float3NaNPropRule float_3nan_prop_rule; FloatInfZeroNaNRule float_infzeronan_rule; + FloatSNaNRule float_snan_rule; bool tininess_before_rounding; /* should denormalised results go to zero and set output_denormal_flushed? */ bool flush_to_zero; @@ -XXX,XX +XXX,XX @@ typedef struct float_status { * create a default NaN. */ uint8_t default_nan_pattern; - /* - * The flags below are not used on all specializations and may - * constant fold away (see snan_bit_is_one()/no_signalling_nans() in - * softfloat-specialize.inc.c) - */ - bool snan_bit_is_one; - bool no_signaling_nans; /* should overflowed results subtract re_bias to its exponent? */ bool rebias_overflow; /* should underflowed results add re_bias to its exponent? */ diff --git a/target/mips/fpu_helper.h b/target/mips/fpu_helper.h index XXXXXXX..XXXXXXX 100644 --- a/target/mips/fpu_helper.h +++ b/target/mips/fpu_helper.h @@ -XXX,XX +XXX,XX @@ static inline void restore_snan_bit_mode(CPUMIPSState *env) * With nan2008, SNaNs are silenced in the usual way. * Before that, SNaNs are not silenced; default nans are produced. */ - set_snan_bit_is_one(!nan2008, &env->active_fpu.fp_status); + set_snan_rule(nan2008 ? float_snan_bit_is_zero : float_snan_bit_is_one, + &env->active_fpu.fp_status); set_default_nan_mode(!nan2008, &env->active_fpu.fp_status); /* * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan) diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/hppa/fpu_helper.c +++ b/target/hppa/fpu_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(loaded_fr0)(CPUHPPAState *env) set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status); /* Default NaN: sign bit clear, msb-1 frac bit set */ set_float_default_nan_pattern(0b00100000, &env->fp_status); - set_snan_bit_is_one(true, &env->fp_status); + set_snan_rule(float_snan_bit_is_one, &env->fp_status); /* * "PA-RISC 2.0 Architecture" says it is IMPDEF whether the flushing * enabled by FPSR.D happens before or after rounding. We pick "before" diff --git a/target/mips/msa.c b/target/mips/msa.c index XXXXXXX..XXXXXXX 100644 --- a/target/mips/msa.c +++ b/target/mips/msa.c @@ -XXX,XX +XXX,XX @@ void msa_reset(CPUMIPSState *env) /* clear float_status nan mode */ set_default_nan_mode(0, &env->active_tc.msa_fp_status); - /* set proper signanling bit meaning ("1" means "quiet") */ - set_snan_bit_is_one(0, &env->active_tc.msa_fp_status); + /* set proper signanling bit meaning */ + set_snan_rule(float_snan_bit_is_zero, &env->active_tc.msa_fp_status); /* Inf * 0 + NaN returns the input NaN */ set_float_infzeronan_rule(float_infzeronan_dnan_never, diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -XXX,XX +XXX,XX @@ static void superh_cpu_reset_hold(Object *obj, ResetType type) set_flush_to_zero(1, &env->fp_status); #endif set_default_nan_mode(1, &env->fp_status); - set_snan_bit_is_one(true, &env->fp_status); + set_snan_rule(float_snan_bit_is_one, &env->fp_status); /* sign bit clear, set all frac bits other than msb */ set_float_default_nan_pattern(0b00111111, &env->fp_status); /* diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -XXX,XX +XXX,XX @@ static void xtensa_cpu_reset_hold(Object *obj, ResetType type) #endif /* For inf * 0 + NaN, return the input NaN */ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status); - set_no_signaling_nans(!dfpu, &env->fp_status); + set_snan_rule(dfpu ? float_snan_bit_is_zero : float_snan_never, + &env->fp_status); /* Default NaN value: sign bit clear, set frac msb */ set_float_default_nan_pattern(0b01000000, &env->fp_status); xtensa_use_first_nan(env, !dfpu); diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -XXX,XX +XXX,XX @@ this code that are retained. * version 2 or later. See the COPYING file in the top-level directory. */ -/* - * Define whether architecture deviates from IEEE in not supporting - * signaling NaNs (so all NaNs are treated as quiet). - */ -static inline bool no_signaling_nans(float_status *status) -{ - return status->no_signaling_nans; -} - -/* Define how the architecture discriminates signaling NaNs. - * This done with the most significant bit of the fraction. - * In IEEE 754-1985 this was implementation defined, but in IEEE 754-2008 - * the msb must be zero. MIPS is (so far) unique in supporting both the - * 2008 revision and backward compatibility with their original choice. - */ -static inline bool snan_bit_is_one(float_status *status) -{ - return status->snan_bit_is_one; -} - /*---------------------------------------------------------------------------- | For the deconstructed floating-point with fraction FRAC, return true | if the fraction represents a signalling NaN; otherwise false. @@ -XXX,XX +XXX,XX @@ static inline bool snan_bit_is_one(float_status *status) static bool frac_msb_is_snan(bool msb, float_status *status) { - if (no_signaling_nans(status)) { + switch (get_snan_rule(status)) { + case float_snan_never: return false; - } else { - return msb == snan_bit_is_one(status); + case float_snan_bit_is_one: + return msb; + case float_snan_bit_is_zero: + return !msb; } + g_assert_not_reached(); } static bool parts_is_snan_frac(uint64_t frac, float_status *status) @@ -XXX,XX +XXX,XX @@ FloatParts128 parts128_default_nan(float_status *status) static uint64_t parts_silence_nan_frac(uint64_t frac, float_status *status) { - g_assert(!no_signaling_nans(status)); - - /* The only snan_bit_is_one target without default_nan_mode is HPPA. */ - if (snan_bit_is_one(status)) { + switch (get_snan_rule(status)) { + case float_snan_bit_is_zero: + frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 1); + break; + case float_snan_bit_is_one: + /* The only snan_bit_is_one target without default_nan_mode is HPPA. */ frac &= ~(1ULL << (DECOMPOSED_BINARY_POINT - 1)); frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 2); - } else { - frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 1); + break; + case float_snan_never: + default: + g_assert_not_reached(); } return frac; } @@ -XXX,XX +XXX,XX @@ bool floatx80_is_signaling_nan(floatx80 a, float_status *status) floatx80 floatx80_silence_nan(floatx80 a, float_status *status) { /* None of the targets that have snan_bit_is_one use floatx80. */ - assert(!snan_bit_is_one(status)); + assert(get_snan_rule(status) == float_snan_bit_is_zero); a.low |= UINT64_C(0xC000000000000000); return a; } -- 2.43.0
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/i386/ops_sse.h | 24 ++--- fpu/softfloat.c | 88 +++++++++--------- target/alpha/fpu_helper.c | 2 +- target/arm/tcg/vfp_helper.c | 8 +- target/hexagon/fma_emu.c | 6 +- target/i386/tcg/fpu_helper.c | 28 +++--- target/m68k/softfloat.c | 170 +++++++++++++++++----------------- target/ppc/fpu_helper.c | 14 +-- target/riscv/vector_helper.c | 6 +- target/s390x/tcg/fpu_helper.c | 4 +- tests/fp/fp-bench.c | 2 +- tests/fp/fp-test.c | 2 +- fpu/softfloat-parts.c.inc | 8 +- tests/fp/wrap.c.inc | 12 +-- 14 files changed, 185 insertions(+), 189 deletions(-) diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h index XXXXXXX..XXXXXXX 100644 --- a/target/i386/ops_sse.h +++ b/target/i386/ops_sse.h @@ -XXX,XX +XXX,XX @@ void glue(helper_cvtph2ps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) void glue(helper_cvtps2ph, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, int mode) { int i; - FloatRoundMode prev_rounding_mode = env->sse_status.float_rounding_mode; + FloatRoundMode prev_rounding_mode = get_float_rounding_mode(&env->sse_status); if (!(mode & (1 << 2))) { set_x86_rounding_mode(mode & 3, &env->sse_status); } @@ -XXX,XX +XXX,XX @@ void glue(helper_cvtps2ph, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, int mode) d->Q(i) = 0; } - env->sse_status.float_rounding_mode = prev_rounding_mode; + set_float_rounding_mode(prev_rounding_mode, &env->sse_status); } #endif @@ -XXX,XX +XXX,XX @@ void glue(helper_roundps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mode) { int old_flags = get_float_exception_flags(&env->sse_status); - signed char prev_rounding_mode; + FloatRoundMode prev_rounding_mode = get_float_rounding_mode(&env->sse_status); int i; - prev_rounding_mode = env->sse_status.float_rounding_mode; if (!(mode & (1 << 2))) { set_x86_rounding_mode(mode & 3, &env->sse_status); } @@ -XXX,XX +XXX,XX @@ void glue(helper_roundps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, ~float_flag_inexact, &env->sse_status); } - env->sse_status.float_rounding_mode = prev_rounding_mode; + set_float_rounding_mode(prev_rounding_mode, &env->sse_status); } void glue(helper_roundpd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mode) { int old_flags = get_float_exception_flags(&env->sse_status); - signed char prev_rounding_mode; + FloatRoundMode prev_rounding_mode = get_float_rounding_mode(&env->sse_status); int i; - prev_rounding_mode = env->sse_status.float_rounding_mode; if (!(mode & (1 << 2))) { set_x86_rounding_mode(mode & 3, &env->sse_status); } @@ -XXX,XX +XXX,XX @@ void glue(helper_roundpd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, ~float_flag_inexact, &env->sse_status); } - env->sse_status.float_rounding_mode = prev_rounding_mode; + set_float_rounding_mode(prev_rounding_mode, &env->sse_status); } #if SHIFT == 1 @@ -XXX,XX +XXX,XX @@ void glue(helper_roundss, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s, uint32_t mode) { int old_flags = get_float_exception_flags(&env->sse_status); - signed char prev_rounding_mode; + FloatRoundMode prev_rounding_mode = get_float_rounding_mode(&env->sse_status); int i; - prev_rounding_mode = env->sse_status.float_rounding_mode; if (!(mode & (1 << 2))) { set_x86_rounding_mode(mode & 3, &env->sse_status); } @@ -XXX,XX +XXX,XX @@ void glue(helper_roundss, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s, ~float_flag_inexact, &env->sse_status); } - env->sse_status.float_rounding_mode = prev_rounding_mode; + set_float_rounding_mode(prev_rounding_mode, &env->sse_status); } void glue(helper_roundsd, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s, uint32_t mode) { int old_flags = get_float_exception_flags(&env->sse_status); - signed char prev_rounding_mode; + FloatRoundMode prev_rounding_mode = get_float_rounding_mode(&env->sse_status); int i; - prev_rounding_mode = env->sse_status.float_rounding_mode; if (!(mode & (1 << 2))) { set_x86_rounding_mode(mode & 3, &env->sse_status); } @@ -XXX,XX +XXX,XX @@ void glue(helper_roundsd, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s, ~float_flag_inexact, &env->sse_status); } - env->sse_status.float_rounding_mode = prev_rounding_mode; + set_float_rounding_mode(prev_rounding_mode, &env->sse_status); } #endif diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ static inline bool can_use_fpu(const float_status *s) return false; } return likely(s->float_exception_flags & float_flag_inexact && - s->float_rounding_mode == float_round_nearest_even); + get_float_rounding_mode(s) == float_round_nearest_even); } /* @@ -XXX,XX +XXX,XX @@ float16 float16_round_to_int(float16 a, float_status *s) { FloatParts64 p = float16_unpack_canonical(a, s); - p = parts64_round_to_int(&p, s->float_rounding_mode, 0, s, + p = parts64_round_to_int(&p, get_float_rounding_mode(s), 0, s, &float16_params); return float16_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ float32 float32_round_to_int(float32 a, float_status *s) { FloatParts64 p = float32_unpack_canonical(a, s); - p = parts64_round_to_int(&p, s->float_rounding_mode, 0, s, + p = parts64_round_to_int(&p, get_float_rounding_mode(s), 0, s, &float32_params); return float32_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ float64 float64_round_to_int(float64 a, float_status *s) { FloatParts64 p = float64_unpack_canonical(a, s); - p = parts64_round_to_int(&p, s->float_rounding_mode, 0, s, + p = parts64_round_to_int(&p, get_float_rounding_mode(s), 0, s, &float64_params); return float64_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_round_to_int(bfloat16 a, float_status *s) { FloatParts64 p = bfloat16_unpack_canonical(a, s); - p = parts64_round_to_int(&p, s->float_rounding_mode, 0, s, + p = parts64_round_to_int(&p, get_float_rounding_mode(s), 0, s, &bfloat16_params); return bfloat16_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ float128 float128_round_to_int(float128 a, float_status *s) { FloatParts128 p = float128_unpack_canonical(a, s); - p = parts128_round_to_int(&p, s->float_rounding_mode, 0, s, + p = parts128_round_to_int(&p, get_float_rounding_mode(s), 0, s, &float128_params); return float128_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status) return floatx80_default_nan(status); } - p = parts128_round_to_int(&p, status->float_rounding_mode, 0, status, + p = parts128_round_to_int(&p, get_float_rounding_mode(status), 0, status, &floatx80_params[status->floatx80_rounding_precision]); return floatx80_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ static int64_t floatx80_to_int64_scalbn(floatx80 a, FloatRoundMode rmode, int8_t float16_to_int8(float16 a, float_status *s) { - return float16_to_int8_scalbn(a, s->float_rounding_mode, 0, s); + return float16_to_int8_scalbn(a, get_float_rounding_mode(s), 0, s); } int16_t float16_to_int16(float16 a, float_status *s) { - return float16_to_int16_scalbn(a, s->float_rounding_mode, 0, s); + return float16_to_int16_scalbn(a, get_float_rounding_mode(s), 0, s); } int32_t float16_to_int32(float16 a, float_status *s) { - return float16_to_int32_scalbn(a, s->float_rounding_mode, 0, s); + return float16_to_int32_scalbn(a, get_float_rounding_mode(s), 0, s); } int64_t float16_to_int64(float16 a, float_status *s) { - return float16_to_int64_scalbn(a, s->float_rounding_mode, 0, s); + return float16_to_int64_scalbn(a, get_float_rounding_mode(s), 0, s); } int16_t float32_to_int16(float32 a, float_status *s) { - return float32_to_int16_scalbn(a, s->float_rounding_mode, 0, s); + return float32_to_int16_scalbn(a, get_float_rounding_mode(s), 0, s); } int32_t float32_to_int32(float32 a, float_status *s) { - return float32_to_int32_scalbn(a, s->float_rounding_mode, 0, s); + return float32_to_int32_scalbn(a, get_float_rounding_mode(s), 0, s); } int64_t float32_to_int64(float32 a, float_status *s) { - return float32_to_int64_scalbn(a, s->float_rounding_mode, 0, s); + return float32_to_int64_scalbn(a, get_float_rounding_mode(s), 0, s); } int16_t float64_to_int16(float64 a, float_status *s) { - return float64_to_int16_scalbn(a, s->float_rounding_mode, 0, s); + return float64_to_int16_scalbn(a, get_float_rounding_mode(s), 0, s); } int32_t float64_to_int32(float64 a, float_status *s) { - return float64_to_int32_scalbn(a, s->float_rounding_mode, 0, s); + return float64_to_int32_scalbn(a, get_float_rounding_mode(s), 0, s); } int64_t float64_to_int64(float64 a, float_status *s) { - return float64_to_int64_scalbn(a, s->float_rounding_mode, 0, s); + return float64_to_int64_scalbn(a, get_float_rounding_mode(s), 0, s); } int32_t float128_to_int32(float128 a, float_status *s) { - return float128_to_int32_scalbn(a, s->float_rounding_mode, 0, s); + return float128_to_int32_scalbn(a, get_float_rounding_mode(s), 0, s); } int64_t float128_to_int64(float128 a, float_status *s) { - return float128_to_int64_scalbn(a, s->float_rounding_mode, 0, s); + return float128_to_int64_scalbn(a, get_float_rounding_mode(s), 0, s); } Int128 float128_to_int128(float128 a, float_status *s) { - return float128_to_int128_scalbn(a, s->float_rounding_mode, 0, s); + return float128_to_int128_scalbn(a, get_float_rounding_mode(s), 0, s); } int32_t floatx80_to_int32(floatx80 a, float_status *s) { - return floatx80_to_int32_scalbn(a, s->float_rounding_mode, 0, s); + return floatx80_to_int32_scalbn(a, get_float_rounding_mode(s), 0, s); } int64_t floatx80_to_int64(floatx80 a, float_status *s) { - return floatx80_to_int64_scalbn(a, s->float_rounding_mode, 0, s); + return floatx80_to_int64_scalbn(a, get_float_rounding_mode(s), 0, s); } int16_t float16_to_int16_round_to_zero(float16 a, float_status *s) @@ -XXX,XX +XXX,XX @@ int64_t floatx80_to_int64_round_to_zero(floatx80 a, float_status *s) int8_t bfloat16_to_int8(bfloat16 a, float_status *s) { - return bfloat16_to_int8_scalbn(a, s->float_rounding_mode, 0, s); + return bfloat16_to_int8_scalbn(a, get_float_rounding_mode(s), 0, s); } int16_t bfloat16_to_int16(bfloat16 a, float_status *s) { - return bfloat16_to_int16_scalbn(a, s->float_rounding_mode, 0, s); + return bfloat16_to_int16_scalbn(a, get_float_rounding_mode(s), 0, s); } int32_t bfloat16_to_int32(bfloat16 a, float_status *s) { - return bfloat16_to_int32_scalbn(a, s->float_rounding_mode, 0, s); + return bfloat16_to_int32_scalbn(a, get_float_rounding_mode(s), 0, s); } int64_t bfloat16_to_int64(bfloat16 a, float_status *s) { - return bfloat16_to_int64_scalbn(a, s->float_rounding_mode, 0, s); + return bfloat16_to_int64_scalbn(a, get_float_rounding_mode(s), 0, s); } int8_t bfloat16_to_int8_round_to_zero(bfloat16 a, float_status *s) @@ -XXX,XX +XXX,XX @@ static Int128 float128_to_uint128_scalbn(float128 a, FloatRoundMode rmode, uint8_t float16_to_uint8(float16 a, float_status *s) { - return float16_to_uint8_scalbn(a, s->float_rounding_mode, 0, s); + return float16_to_uint8_scalbn(a, get_float_rounding_mode(s), 0, s); } uint16_t float16_to_uint16(float16 a, float_status *s) { - return float16_to_uint16_scalbn(a, s->float_rounding_mode, 0, s); + return float16_to_uint16_scalbn(a, get_float_rounding_mode(s), 0, s); } uint32_t float16_to_uint32(float16 a, float_status *s) { - return float16_to_uint32_scalbn(a, s->float_rounding_mode, 0, s); + return float16_to_uint32_scalbn(a, get_float_rounding_mode(s), 0, s); } uint64_t float16_to_uint64(float16 a, float_status *s) { - return float16_to_uint64_scalbn(a, s->float_rounding_mode, 0, s); + return float16_to_uint64_scalbn(a, get_float_rounding_mode(s), 0, s); } uint16_t float32_to_uint16(float32 a, float_status *s) { - return float32_to_uint16_scalbn(a, s->float_rounding_mode, 0, s); + return float32_to_uint16_scalbn(a, get_float_rounding_mode(s), 0, s); } uint32_t float32_to_uint32(float32 a, float_status *s) { - return float32_to_uint32_scalbn(a, s->float_rounding_mode, 0, s); + return float32_to_uint32_scalbn(a, get_float_rounding_mode(s), 0, s); } uint64_t float32_to_uint64(float32 a, float_status *s) { - return float32_to_uint64_scalbn(a, s->float_rounding_mode, 0, s); + return float32_to_uint64_scalbn(a, get_float_rounding_mode(s), 0, s); } uint16_t float64_to_uint16(float64 a, float_status *s) { - return float64_to_uint16_scalbn(a, s->float_rounding_mode, 0, s); + return float64_to_uint16_scalbn(a, get_float_rounding_mode(s), 0, s); } uint32_t float64_to_uint32(float64 a, float_status *s) { - return float64_to_uint32_scalbn(a, s->float_rounding_mode, 0, s); + return float64_to_uint32_scalbn(a, get_float_rounding_mode(s), 0, s); } uint64_t float64_to_uint64(float64 a, float_status *s) { - return float64_to_uint64_scalbn(a, s->float_rounding_mode, 0, s); + return float64_to_uint64_scalbn(a, get_float_rounding_mode(s), 0, s); } uint32_t float128_to_uint32(float128 a, float_status *s) { - return float128_to_uint32_scalbn(a, s->float_rounding_mode, 0, s); + return float128_to_uint32_scalbn(a, get_float_rounding_mode(s), 0, s); } uint64_t float128_to_uint64(float128 a, float_status *s) { - return float128_to_uint64_scalbn(a, s->float_rounding_mode, 0, s); + return float128_to_uint64_scalbn(a, get_float_rounding_mode(s), 0, s); } Int128 float128_to_uint128(float128 a, float_status *s) { - return float128_to_uint128_scalbn(a, s->float_rounding_mode, 0, s); + return float128_to_uint128_scalbn(a, get_float_rounding_mode(s), 0, s); } uint16_t float16_to_uint16_round_to_zero(float16 a, float_status *s) @@ -XXX,XX +XXX,XX @@ Int128 float128_to_uint128_round_to_zero(float128 a, float_status *s) uint8_t bfloat16_to_uint8(bfloat16 a, float_status *s) { - return bfloat16_to_uint8_scalbn(a, s->float_rounding_mode, 0, s); + return bfloat16_to_uint8_scalbn(a, get_float_rounding_mode(s), 0, s); } uint16_t bfloat16_to_uint16(bfloat16 a, float_status *s) { - return bfloat16_to_uint16_scalbn(a, s->float_rounding_mode, 0, s); + return bfloat16_to_uint16_scalbn(a, get_float_rounding_mode(s), 0, s); } uint32_t bfloat16_to_uint32(bfloat16 a, float_status *s) { - return bfloat16_to_uint32_scalbn(a, s->float_rounding_mode, 0, s); + return bfloat16_to_uint32_scalbn(a, get_float_rounding_mode(s), 0, s); } uint64_t bfloat16_to_uint64(bfloat16 a, float_status *s) { - return bfloat16_to_uint64_scalbn(a, s->float_rounding_mode, 0, s); + return bfloat16_to_uint64_scalbn(a, get_float_rounding_mode(s), 0, s); } uint8_t bfloat16_to_uint8_round_to_zero(bfloat16 a, float_status *s) @@ -XXX,XX +XXX,XX @@ floatx80 roundAndPackFloatx80(FloatX80RoundPrec roundingPrecision, bool zSign, bool roundNearestEven, increment, isTiny; int64_t roundIncrement, roundMask, roundBits; - roundingMode = status->float_rounding_mode; + roundingMode = get_float_rounding_mode(status); roundNearestEven = ( roundingMode == float_round_nearest_even ); switch (roundingPrecision) { case floatx80_precision_x: diff --git a/target/alpha/fpu_helper.c b/target/alpha/fpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/alpha/fpu_helper.c +++ b/target/alpha/fpu_helper.c @@ -XXX,XX +XXX,XX @@ static uint64_t do_cvttq(CPUAlphaState *env, uint64_t a, int roundmode) uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a) { - return do_cvttq(env, a, FP_STATUS.float_rounding_mode); + return do_cvttq(env, a, get_float_rounding_mode(&FP_STATUS)); } uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a) diff --git a/target/arm/tcg/vfp_helper.c b/target/arm/tcg/vfp_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vfp_helper.c +++ b/target/arm/tcg/vfp_helper.c @@ -XXX,XX +XXX,XX @@ ftype HELPER(vfp_##name##to##p)(uint##isz##_t x, uint32_t shift, \ float_status *fpst) \ { \ ftype ret; \ - FloatRoundMode oldmode = fpst->float_rounding_mode; \ - fpst->float_rounding_mode = float_round_nearest_even; \ + FloatRoundMode oldmode = get_float_rounding_mode(fpst); \ + set_float_rounding_mode(float_round_nearest_even, fpst); \ ret = itype##_to_##float##fsz##_scalbn(x, -shift, fpst); \ - fpst->float_rounding_mode = oldmode; \ + set_float_rounding_mode(oldmode, fpst); \ return ret; \ } @@ -XXX,XX +XXX,XX @@ static uint64_t call_recip_estimate(int *exp, int exp_off, uint64_t frac, static bool round_to_inf(float_status *fpst, bool sign_bit) { - switch (fpst->float_rounding_mode) { + switch (get_float_rounding_mode(fpst)) { case float_round_nearest_even: /* Round to Nearest */ return true; case float_round_up: /* Round to +Inf */ diff --git a/target/hexagon/fma_emu.c b/target/hexagon/fma_emu.c index XXXXXXX..XXXXXXX 100644 --- a/target/hexagon/fma_emu.c +++ b/target/hexagon/fma_emu.c @@ -XXX,XX +XXX,XX @@ static float64 accum_round_float64(Accum a, float_status *fp_status) if ((int128_gethi(a.mant) == 0) && (int128_getlo(a.mant) == 0) && ((a.guard | a.round | a.sticky) == 0)) { /* result zero */ - switch (fp_status->float_rounding_mode) { + switch (get_float_rounding_mode(fp_status)) { case float_round_down: return zero_float64(1); default: @@ -XXX,XX +XXX,XX @@ static float64 accum_round_float64(Accum a, float_status *fp_status) /* OK, we're relatively canonical... now we need to round */ if (a.guard || a.round || a.sticky) { float_raise(float_flag_inexact, fp_status); - switch (fp_status->float_rounding_mode) { + switch (get_float_rounding_mode(fp_status)) { case float_round_to_zero: /* Chop and we're done */ break; @@ -XXX,XX +XXX,XX @@ static float64 accum_round_float64(Accum a, float_status *fp_status) /* Yep, inf result */ float_raise(float_flag_overflow, fp_status); float_raise(float_flag_inexact, fp_status); - switch (fp_status->float_rounding_mode) { + switch (get_float_rounding_mode(fp_status)) { case float_round_to_zero: return maxfinite_float64(a.sign); case float_round_up: diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -XXX,XX +XXX,XX @@ void helper_f2xm1(CPUX86State *env) bool asign, bsign; int32_t n, aexp, bexp; uint64_t asig0, asig1, asig2, bsig0, bsig1; - FloatRoundMode save_mode = env->fp_status.float_rounding_mode; + FloatRoundMode save_mode = get_float_rounding_mode(&env->fp_status); FloatX80RoundPrec save_prec = env->fp_status.floatx80_rounding_precision; - env->fp_status.float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); env->fp_status.floatx80_rounding_precision = floatx80_precision_x; /* Find the nearest multiple of 1/32 to the argument. */ @@ -XXX,XX +XXX,XX @@ void helper_f2xm1(CPUX86State *env) */ ST0 = f2xm1_table[n].t; set_float_exception_flags(float_flag_inexact, &env->fp_status); - env->fp_status.float_rounding_mode = save_mode; + set_float_rounding_mode(save_mode, &env->fp_status); } else { /* * Compute the lower parts of a polynomial expansion for @@ -XXX,XX +XXX,XX @@ void helper_f2xm1(CPUX86State *env) asign = bsign; } } - env->fp_status.float_rounding_mode = save_mode; + set_float_rounding_mode(save_mode, &env->fp_status); /* This result is inexact. */ asig1 |= 1; ST0 = normalizeRoundAndPackFloatx80(floatx80_precision_x, @@ -XXX,XX +XXX,XX @@ void helper_fpatan(CPUX86State *env) uint64_t azsig0, azsig1; uint64_t azsig2, azsig3, axsig0, axsig1; floatx80 x8; - FloatRoundMode save_mode = env->fp_status.float_rounding_mode; + FloatRoundMode save_mode = get_float_rounding_mode(&env->fp_status); FloatX80RoundPrec save_prec = env->fp_status.floatx80_rounding_precision; - env->fp_status.float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); env->fp_status.floatx80_rounding_precision = floatx80_precision_x; if (arg0_exp == 0) { @@ -XXX,XX +XXX,XX @@ void helper_fpatan(CPUX86State *env) } } - env->fp_status.float_rounding_mode = save_mode; + set_float_rounding_mode(save_mode, &env->fp_status); env->fp_status.floatx80_rounding_precision = save_prec; } /* This result is inexact. */ @@ -XXX,XX +XXX,XX @@ void helper_fyl2xp1(CPUX86State *env) } else { int32_t aexp; uint64_t asig0, asig1, asig2; - FloatRoundMode save_mode = env->fp_status.float_rounding_mode; + FloatRoundMode save_mode = get_float_rounding_mode(&env->fp_status); FloatX80RoundPrec save_prec = env->fp_status.floatx80_rounding_precision; - env->fp_status.float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); env->fp_status.floatx80_rounding_precision = floatx80_precision_x; helper_fyl2x_common(env, ST0, &aexp, &asig0, &asig1); @@ -XXX,XX +XXX,XX @@ void helper_fyl2xp1(CPUX86State *env) aexp += arg1_exp - 0x3ffe; /* This result is inexact. */ asig1 |= 1; - env->fp_status.float_rounding_mode = save_mode; + set_float_rounding_mode(save_mode, &env->fp_status); ST1 = normalizeRoundAndPackFloatx80(floatx80_precision_x, arg0_sign ^ arg1_sign, aexp, asig0, asig1, &env->fp_status); @@ -XXX,XX +XXX,XX @@ void helper_fyl2x(CPUX86State *env) } else { int32_t int_exp; floatx80 arg0_m1; - FloatRoundMode save_mode = env->fp_status.float_rounding_mode; + FloatRoundMode save_mode = get_float_rounding_mode(&env->fp_status); FloatX80RoundPrec save_prec = env->fp_status.floatx80_rounding_precision; - env->fp_status.float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); env->fp_status.floatx80_rounding_precision = floatx80_precision_x; if (arg0_exp == 0) { @@ -XXX,XX +XXX,XX @@ void helper_fyl2x(CPUX86State *env) floatx80_one, &env->fp_status); if (floatx80_is_zero(arg0_m1)) { /* Exact power of 2; multiply by ST1. */ - env->fp_status.float_rounding_mode = save_mode; + set_float_rounding_mode(save_mode, &env->fp_status); ST1 = floatx80_mul(int32_to_floatx80(int_exp, &env->fp_status), ST1, &env->fp_status); } else { @@ -XXX,XX +XXX,XX @@ void helper_fyl2x(CPUX86State *env) aexp += arg1_exp - 0x3ffe; /* This result is inexact. */ asig1 |= 1; - env->fp_status.float_rounding_mode = save_mode; + set_float_rounding_mode(save_mode, &env->fp_status); ST1 = normalizeRoundAndPackFloatx80(floatx80_precision_x, asign ^ arg1_sign, aexp, asig0, asig1, &env->fp_status); diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/target/m68k/softfloat.c +++ b/target/m68k/softfloat.c @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_lognp1(floatx80 a, float_status *status) return floatx80_move(a, status); } - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; compact = floatx80_make_compact(aExp, aSig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_lognp1(floatx80 a, float_status *status) status); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */ fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS LOG(F) + LOG(1+U) */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, klog2, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_lognp1(floatx80 a, float_status *status) fp0 = floatx80_mul(fp0, fp1, status); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, saveu, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_logn(floatx80 a, float_status *status) return floatx80_default_nan(status); } - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; compact = floatx80_make_compact(aExp, aSig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_logn(floatx80 a, float_status *status) status); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */ fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS LOG(F) + LOG(1+U) */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, klog2, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_logn(floatx80 a, float_status *status) fp0 = floatx80_mul(fp0, fp1, status); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, saveu, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_log10(floatx80 a, float_status *status) return floatx80_default_nan(status); } - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; fp0 = floatx80_logn(a, status); fp1 = packFloatx80(0, 0x3FFD, UINT64_C(0xDE5BD8A937287195)); /* INV_L10 */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_mul(fp0, fp1, status); /* LOGN(X)*INV_L10 */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_log2(floatx80 a, float_status *status) return floatx80_default_nan(status); } - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; if (aSig == one_sig) { /* X is 2^k */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = int32_to_floatx80(aExp - 0x3FFF, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_log2(floatx80 a, float_status *status) fp0 = floatx80_logn(a, status); fp1 = packFloatx80(0, 0x3FFF, UINT64_C(0xB8AA3B295C17F0BC)); /* INV_L2 */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_mul(fp0, fp1, status); /* LOGN(X)*INV_L2 */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etox(floatx80 a, float_status *status) return packFloatx80(0, one_exp, one_sig); } - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; adjflag = 0; @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etox(floatx80 a, float_status *status) fp0 = floatx80_mul(fp0, adjscale, status); } - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_mul(fp0, scale, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etox(floatx80 a, float_status *status) return a; } else { /* |X| >= 16380 log2 */ if (compact > 0x400CB27C) { /* |X| >= 16480 log2 */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; if (aSign) { a = roundAndPackFloatx80( @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etox(floatx80 a, float_status *status) } } } else { /* |X| < 2^(-65) */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(a, float32_to_floatx80(make_float32(0x3F800000), @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_twotox(floatx80 a, float_status *status) return packFloatx80(0, one_exp, one_sig); } - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; fp0 = a; @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_twotox(floatx80 a, float_status *status) if (compact < 0x3FB98000 || compact > 0x400D80C0) { /* |X| > 16480 or |X| < 2^(-70) */ if (compact > 0x3FFF8000) { /* |X| > 16480 */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; if (aSign) { @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_twotox(floatx80 a, float_status *status) 0, 0x8000, aSig, 0, status); } } else { /* |X| < 2^(-70) */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, float32_to_floatx80( @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_twotox(floatx80 a, float_status *status) fp0 = floatx80_add(fp0, fact2, status); fp0 = floatx80_add(fp0, fact1, status); - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_mul(fp0, adjfact, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tentox(floatx80 a, float_status *status) return packFloatx80(0, one_exp, one_sig); } - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; fp0 = a; @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tentox(floatx80 a, float_status *status) if (compact < 0x3FB98000 || compact > 0x400B9B07) { /* |X| > 16480 LOG2/LOG10 or |X| < 2^(-70) */ if (compact > 0x3FFF8000) { /* |X| > 16480 */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; if (aSign) { @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tentox(floatx80 a, float_status *status) 0, 0x8000, aSig, 0, status); } } else { /* |X| < 2^(-70) */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, float32_to_floatx80( @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tentox(floatx80 a, float_status *status) fp0 = floatx80_add(fp0, fact2, status); fp0 = floatx80_add(fp0, fact1, status); - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_mul(fp0, adjfact, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tan(floatx80 a, float_status *status) return packFloatx80(aSign, 0, 0); } - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; compact = floatx80_make_compact(aExp, aSig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tan(floatx80 a, float_status *status) fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */ goto loop; } else { - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_move(a, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tan(floatx80 a, float_status *status) xSign ^= 1; fp1 = packFloatx80(xSign, xExp, xSig); - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_div(fp0, fp1, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tan(floatx80 a, float_status *status) make_float32(0x3F800000), status), status); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_div(fp0, fp1, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sin(floatx80 a, float_status *status) return packFloatx80(aSign, 0, 0); } - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; compact = floatx80_make_compact(aExp, aSig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sin(floatx80 a, float_status *status) fp0 = float32_to_floatx80(make_float32(0x3F800000), status); /* 1 */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; /* SINTINY */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sin(floatx80 a, float_status *status) x = packFloatx80(xSign, xExp, xSig); fp0 = floatx80_mul(fp0, x, status); - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, float32_to_floatx80(posneg1, status), status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sin(floatx80 a, float_status *status) fp0 = floatx80_mul(fp0, x, status); /* R'*S */ fp0 = floatx80_mul(fp0, fp1, status); /* SIN(R')-R' */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, x, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_cos(floatx80 a, float_status *status) return packFloatx80(0, one_exp, one_sig); } - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; compact = floatx80_make_compact(aExp, aSig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_cos(floatx80 a, float_status *status) /* SINSM */ fp0 = float32_to_floatx80(make_float32(0x3F800000), status); /* 1 */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; /* COSTINY */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_cos(floatx80 a, float_status *status) x = packFloatx80(xSign, xExp, xSig); fp0 = floatx80_mul(fp0, x, status); - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, float32_to_floatx80(posneg1, status), status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_cos(floatx80 a, float_status *status) fp0 = floatx80_mul(fp0, x, status); /* R'*S */ fp0 = floatx80_mul(fp0, fp1, status); /* SIN(R')-R' */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, x, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atan(floatx80 a, float_status *status) compact = floatx80_make_compact(aExp, aSig); - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; if (compact < 0x3FFB8000 || compact > 0x4002FFFF) { @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atan(floatx80 a, float_status *status) fp0 = packFloatx80(aSign, piby2_exp, pi_sig); fp1 = packFloatx80(aSign, 0x0001, one_sig); - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_sub(fp0, fp1, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atan(floatx80 a, float_status *status) fp0 = floatx80_add(fp0, xsave, status); fp1 = packFloatx80(aSign, piby2_exp, pi_sig); - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, fp1, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atan(floatx80 a, float_status *status) } } else { /* |X| < 1/16 */ if (compact < 0x3FD78000) { /* |X| < 2^(-40) */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_move(a, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atan(floatx80 a, float_status *status) /* X*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) */ fp0 = floatx80_mul(fp0, fp1, status); - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, xsave, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atan(floatx80 a, float_status *status) fp1 = floatx80_mul(fp1, fp2, status); /* A1*U*V*(A2+V*(A3+V)) */ fp0 = floatx80_add(fp0, fp1, status); /* ATAN(U) */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, fp3, status); /* ATAN(X) */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_asin(floatx80 a, float_status *status) } /* |X| < 1 */ - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; one = packFloatx80(0, one_exp, one_sig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_asin(floatx80 a, float_status *status) fp1 = floatx80_sqrt(fp1, status); /* SQRT((1+X)*(1-X)) */ fp0 = floatx80_div(fp0, fp1, status); /* X/SQRT((1+X)*(1-X)) */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_atan(fp0, status); /* ATAN(X/SQRT((1+X)*(1-X))) */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_acos(floatx80 a, float_status *status) } } /* |X| < 1 */ - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; one = packFloatx80(0, one_exp, one_sig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_acos(floatx80 a, float_status *status) fp0 = floatx80_sqrt(fp0, status); /* SQRT((1-X)/(1+X)) */ fp0 = floatx80_atan(fp0, status); /* ATAN(SQRT((1-X)/(1+X))) */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, fp0, status); /* 2 * ATAN(SQRT((1-X)/(1+X))) */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atanh(floatx80 a, float_status *status) } } /* |X| < 1 */ - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; one = packFloatx80(0, one_exp, one_sig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atanh(floatx80 a, float_status *status) fp0 = floatx80_div(fp0, fp1, status); /* Z = 2Y/(1-Y) */ fp0 = floatx80_lognp1(fp0, status); /* LOG1P(Z) */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_mul(fp0, fp2, @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etoxm1(floatx80 a, float_status *status) return packFloatx80(aSign, 0, 0); } - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; if (aExp >= 0x3FFD) { /* |X| >= 1/4 */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etoxm1(floatx80 a, float_status *status) sc = packFloatx80(0, m + 0x3FFF, one_sig); - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_mul(fp0, sc, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etoxm1(floatx80 a, float_status *status) fp0 = float32_to_floatx80(make_float32(0xBF800000), status); /* -1 */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, float32_to_floatx80( @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etoxm1(floatx80 a, float_status *status) return a; } else { - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; return floatx80_etox(a, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etoxm1(floatx80 a, float_status *status) fp1 = floatx80_add(fp1, fp2, status); /* Q */ fp0 = floatx80_add(fp0, fp1, status); /* S*B1+Q */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, a, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etoxm1(floatx80 a, float_status *status) status); fp0 = floatx80_add(fp0, sc, status); - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_mul(fp0, float64_to_floatx80( make_float64(0x3730000000000000), status), status); } else { - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, sc, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tanh(floatx80 a, float_status *status) return packFloatx80(aSign, 0, 0); } - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; compact = floatx80_make_compact(aExp, aSig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tanh(floatx80 a, float_status *status) /* TANHBORS */ if (compact < 0x3FFF8000) { /* TANHSM */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_move(a, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tanh(floatx80 a, float_status *status) sign &= 0x80000000; sign ^= 0x80800000; /* -SIGN(X)*EPS */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, float32_to_floatx80(make_float32(sign), @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tanh(floatx80 a, float_status *status) fp0 = float32_to_floatx80(make_float32(sign | 0x3F800000), status); /* SIGN */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp1, fp0, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tanh(floatx80 a, float_status *status) fp1 = packFloatx80(vSign ^ aSign, vExp, vSig); - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_div(fp0, fp1, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sinh(floatx80 a, float_status *status) return packFloatx80(aSign, 0, 0); } - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; compact = floatx80_make_compact(aExp, aSig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sinh(floatx80 a, float_status *status) if (compact > 0x400CB167) { /* SINHBIG */ if (compact > 0x400CB2B3) { - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; return roundAndPackFloatx80(status->floatx80_rounding_precision, @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sinh(floatx80 a, float_status *status) fp0 = floatx80_etox(fp0, status); fp2 = packFloatx80(aSign, 0x7FFB, one_sig); - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_mul(fp0, fp2, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sinh(floatx80 a, float_status *status) fact = packFloat32(aSign, 0x7E, 0); - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_mul(fp0, float32_to_floatx80(fact, status), status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_cosh(floatx80 a, float_status *status) return packFloatx80(0, one_exp, one_sig); } - user_rnd_mode = status->float_rounding_mode; + user_rnd_mode = get_float_rounding_mode(status); user_rnd_prec = status->floatx80_rounding_precision; - status->float_rounding_mode = float_round_nearest_even; + set_float_rounding_mode(float_round_nearest_even, status); status->floatx80_rounding_precision = floatx80_precision_x; compact = floatx80_make_compact(aExp, aSig); if (compact > 0x400CB167) { if (compact > 0x400CB2B3) { - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; return roundAndPackFloatx80(status->floatx80_rounding_precision, 0, 0x8000, one_sig, 0, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_cosh(floatx80 a, float_status *status) fp0 = floatx80_etox(fp0, status); fp1 = packFloatx80(0, 0x7FFB, one_sig); - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_mul(fp0, fp1, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_cosh(floatx80 a, float_status *status) fp1 = float32_to_floatx80(make_float32(0x3E800000), status); /* 1/4 */ fp1 = floatx80_div(fp1, fp0, status); /* 1/(2*EXP(|X|)) */ - status->float_rounding_mode = user_rnd_mode; + set_float_rounding_mode(user_rnd_mode, status); status->floatx80_rounding_precision = user_rnd_prec; a = floatx80_add(fp0, fp1, status); diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -XXX,XX +XXX,XX @@ void helper_xsaddqp(CPUPPCState *env, uint32_t opcode, tstat = env->fp_status; if (unlikely(Rc(opcode) != 0)) { - tstat.float_rounding_mode = float_round_to_odd; + set_float_rounding_mode(float_round_to_odd, &tstat); } set_float_exception_flags(0, &tstat); @@ -XXX,XX +XXX,XX @@ void helper_xsmulqp(CPUPPCState *env, uint32_t opcode, helper_reset_fpstatus(env); tstat = env->fp_status; if (unlikely(Rc(opcode) != 0)) { - tstat.float_rounding_mode = float_round_to_odd; + set_float_rounding_mode(float_round_to_odd, &tstat); } set_float_exception_flags(0, &tstat); @@ -XXX,XX +XXX,XX @@ void helper_xsdivqp(CPUPPCState *env, uint32_t opcode, helper_reset_fpstatus(env); tstat = env->fp_status; if (unlikely(Rc(opcode) != 0)) { - tstat.float_rounding_mode = float_round_to_odd; + set_float_rounding_mode(float_round_to_odd, &tstat); } set_float_exception_flags(0, &tstat); @@ -XXX,XX +XXX,XX @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *s1, ppc_vsr_t *s2,\ float_status tstat = env->fp_status; \ set_float_exception_flags(0, &tstat); \ if (ro) { \ - tstat.float_rounding_mode = float_round_to_odd; \ + set_float_rounding_mode(float_round_to_odd, &tstat); \ } \ t.f128 = float128_muladd(s1->f128, s3->f128, s2->f128, maddflgs, &tstat); \ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ @@ -XXX,XX +XXX,XX @@ void helper_XSCVQPDP(CPUPPCState *env, uint32_t ro, ppc_vsr_t *xt, tstat = env->fp_status; if (ro != 0) { - tstat.float_rounding_mode = float_round_to_odd; + set_float_rounding_mode(float_round_to_odd, &tstat); } t.VsrD(0) = float128_to_float64(xb->f128, &tstat); @@ -XXX,XX +XXX,XX @@ void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode, tstat = env->fp_status; if (unlikely(Rc(opcode) != 0)) { - tstat.float_rounding_mode = float_round_to_odd; + set_float_rounding_mode(float_round_to_odd, &tstat); } set_float_exception_flags(0, &tstat); @@ -XXX,XX +XXX,XX @@ void helper_xssubqp(CPUPPCState *env, uint32_t opcode, tstat = env->fp_status; if (unlikely(Rc(opcode) != 0)) { - tstat.float_rounding_mode = float_round_to_odd; + set_float_rounding_mode(float_round_to_odd, &tstat); } set_float_exception_flags(0, &tstat); diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -XXX,XX +XXX,XX @@ static uint64_t frec7(uint64_t f, int exp_size, int frac_size, s->float_exception_flags |= (float_flag_inexact | float_flag_overflow); - if ((s->float_rounding_mode == float_round_to_zero) || - ((s->float_rounding_mode == float_round_down) && !sign) || - ((s->float_rounding_mode == float_round_up) && sign)) { + if ((get_float_rounding_mode(s) == float_round_to_zero) || + ((get_float_rounding_mode(s) == float_round_down) && !sign) || + ((get_float_rounding_mode(s) == float_round_up) && sign)) { /* Return greatest/negative finite value. */ return (sign << (exp_size + frac_size)) | (MAKE_64BIT_MASK(frac_size, exp_size) - 1); diff --git a/target/s390x/tcg/fpu_helper.c b/target/s390x/tcg/fpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/s390x/tcg/fpu_helper.c +++ b/target/s390x/tcg/fpu_helper.c @@ -XXX,XX +XXX,XX @@ static int s390_get_bfp_rounding_mode(CPUS390XState *env, int m3) switch (m3) { case 0: /* current mode */ - return env->fpu_status.float_rounding_mode; + return get_float_rounding_mode(&env->fpu_status); case 1: /* round to nearest with ties away from 0 */ return float_round_ties_away; @@ -XXX,XX +XXX,XX @@ uint32_t HELPER(cxb)(CPUS390XState *env, Int128 a, Int128 b) int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3) { - int ret = env->fpu_status.float_rounding_mode; + int ret = get_float_rounding_mode(&env->fpu_status); set_float_rounding_mode(s390_get_bfp_rounding_mode(env, m3), &env->fpu_status); diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c index XXXXXXX..XXXXXXX 100644 --- a/tests/fp/fp-bench.c +++ b/tests/fp/fp-bench.c @@ -XXX,XX +XXX,XX @@ static void set_soft_precision(enum rounding rounding) default: g_assert_not_reached(); } - soft_status.float_rounding_mode = mode; + set_float_rounding_mode(mode, &soft_status); } static void parse_args(int argc, char *argv[]) diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/fp/fp-test.c +++ b/tests/fp/fp-test.c @@ -XXX,XX +XXX,XX @@ void run_test(void) verCases_roundingCode = 0; slowfloat_roundingMode = rmode; - qsf.float_rounding_mode = sf_rounding_to_qemu(rmode); + set_float_rounding_mode(sf_rounding_to_qemu(rmode), &qsf); if (attrs & (FUNC_ARG_ROUNDINGMODE | FUNC_EFF_ROUNDINGMODE)) { /* print rounding mode if the op is affected by it */ diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, int exp; FloatExceptionFlags flags = 0; - switch (s->float_rounding_mode) { + switch (get_float_rounding_mode(s)) { case float_round_nearest_even_max: overflow_norm = true; /* fall through */ @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, if (p->frac_lo & round_mask) { /* Need to recompute round-to-even/round-to-odd. */ - switch (s->float_rounding_mode) { + switch (get_float_rounding_mode(s)) { case float_round_nearest_even: if (N > 64 && frac_lsb == 0) { inc = ((p->frac_hi & 1) || @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, if (ab_mask == float_cmask_zero) { /* 0 - 0 */ - a.sign = s->float_rounding_mode == float_round_down; + a.sign = get_float_rounding_mode(s) == float_round_down; return a; } @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(muladd)(const FloatPartsN *a, const FloatPartsN *b, return_sub_zero: /* 0 - 0 == -0 for round_down, +0 otherwise. */ return (FloatPartsN){ - .sign = s->float_rounding_mode == float_round_down, + .sign = get_float_rounding_mode(s) == float_round_down, .cls = float_class_zero }; diff --git a/tests/fp/wrap.c.inc b/tests/fp/wrap.c.inc index XXXXXXX..XXXXXXX 100644 --- a/tests/fp/wrap.c.inc +++ b/tests/fp/wrap.c.inc @@ -XXX,XX +XXX,XX @@ WRAP_SF_TO_128(qemu_f64_to_f128M, float64_to_float128, float64) { \ type *ap = (type *)&a; \ \ - qsf.float_rounding_mode = sf_rounding_to_qemu(round); \ + set_float_rounding_mode(sf_rounding_to_qemu(round), &qsf); \ return func(*ap, &qsf); \ } @@ -XXX,XX +XXX,XX @@ WRAP_INT_TO_80(qemu_i64_to_extF80M, int64_to_floatx80, int64_t) floatx80 a; \ \ a = soft_to_qemu80(*ap); \ - qsf.float_rounding_mode = sf_rounding_to_qemu(round); \ + set_float_rounding_mode(sf_rounding_to_qemu(round), &qsf); \ return func(a, &qsf); \ } @@ -XXX,XX +XXX,XX @@ WRAP_80_TO_INT_MINMAG(qemu_extF80M_to_i64_r_minMag, float128 a; \ \ a = soft_to_qemu128(*ap); \ - qsf.float_rounding_mode = sf_rounding_to_qemu(round); \ + set_float_rounding_mode(sf_rounding_to_qemu(round), &qsf); \ return func(a, &qsf); \ } @@ -XXX,XX +XXX,XX @@ WRAP_INT_TO_128(qemu_i64_to_f128M, int64_to_float128, int64_t) type *ap = (type *)&a; \ type ret; \ \ - qsf.float_rounding_mode = sf_rounding_to_qemu(round); \ + set_float_rounding_mode(sf_rounding_to_qemu(round), &qsf); \ ret = func(*ap, &qsf); \ return *(type##_t *)&ret; \ } @@ -XXX,XX +XXX,XX @@ static void qemu_extF80M_roundToInt(const extFloat80_t *ap, uint_fast8_t round, floatx80 ret; a = soft_to_qemu80(*ap); - qsf.float_rounding_mode = sf_rounding_to_qemu(round); + set_float_rounding_mode(sf_rounding_to_qemu(round), &qsf); ret = floatx80_round_to_int(a, &qsf); *res = qemu_to_soft80(ret); } @@ -XXX,XX +XXX,XX @@ static void qemu_f128M_roundToInt(const float128_t *ap, uint_fast8_t round, float128 ret; a = soft_to_qemu128(*ap); - qsf.float_rounding_mode = sf_rounding_to_qemu(round); + set_float_rounding_mode(sf_rounding_to_qemu(round), &qsf); ret = float128_round_to_int(a, &qsf); *res = qemu_to_soft128(ret); } -- 2.43.0
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 10 +- target/i386/tcg/fpu_helper.c | 37 ++++--- target/m68k/softfloat.c | 208 ++++++++++++++++++----------------- tests/fp/fp-test.c | 2 +- 4 files changed, 130 insertions(+), 127 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ float128 float128_round_pack_canonical(FloatParts128 *p, float_status *s) bool floatx80_unpack_canonical(FloatParts128 *p, floatx80 f, float_status *s) { /* Ensure rounding precision is set before beginning. */ - switch (s->floatx80_rounding_precision) { + switch (get_floatx80_rounding_precision(s)) { case floatx80_precision_x: case floatx80_precision_d: case floatx80_precision_s: @@ -XXX,XX +XXX,XX @@ bool floatx80_unpack_canonical(FloatParts128 *p, floatx80 f, float_status *s) floatx80 floatx80_round_pack_canonical(FloatParts128 *p, float_status *s) { - const FloatFmt *fmt = &floatx80_params[s->floatx80_rounding_precision]; + const FloatFmt *fmt = &floatx80_params[get_floatx80_rounding_precision(s)]; uint64_t frac; int exp; switch (p->cls) { case float_class_normal: case float_class_denormal: - if (s->floatx80_rounding_precision == floatx80_precision_x) { + if (get_floatx80_rounding_precision(s) == floatx80_precision_x) { parts128_uncanon_normal(p, s, fmt, false); frac = p->frac_hi; exp = p->exp; @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status) } p = parts128_round_to_int(&p, get_float_rounding_mode(status), 0, status, - &floatx80_params[status->floatx80_rounding_precision]); + &floatx80_params[get_floatx80_rounding_precision(status)]); return floatx80_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sqrt(floatx80 a, float_status *s) if (!floatx80_unpack_canonical(&p, a, s)) { return floatx80_default_nan(s); } - parts128_sqrt(&p, s, &floatx80_params[s->floatx80_rounding_precision]); + parts128_sqrt(&p, s, &floatx80_params[get_floatx80_rounding_precision(s)]); return floatx80_round_pack_canonical(&p, s); } diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -XXX,XX +XXX,XX @@ void helper_f2xm1(CPUX86State *env) uint64_t asig0, asig1, asig2, bsig0, bsig1; FloatRoundMode save_mode = get_float_rounding_mode(&env->fp_status); FloatX80RoundPrec save_prec = - env->fp_status.floatx80_rounding_precision; + get_floatx80_rounding_precision(&env->fp_status); set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - env->fp_status.floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, &env->fp_status); /* Find the nearest multiple of 1/32 to the argument. */ tmp = floatx80_scalbn(ST0, 5, &env->fp_status); @@ -XXX,XX +XXX,XX @@ void helper_f2xm1(CPUX86State *env) &env->fp_status); } - env->fp_status.floatx80_rounding_precision = save_prec; + set_floatx80_rounding_precision(save_prec, &env->fp_status); } merge_exception_flags(env, old_flags); } @@ -XXX,XX +XXX,XX @@ void helper_fpatan(CPUX86State *env) * (and underflowing where appropriate). */ FloatX80RoundPrec save_prec = - env->fp_status.floatx80_rounding_precision; - env->fp_status.floatx80_rounding_precision = floatx80_precision_x; + get_floatx80_rounding_precision(&env->fp_status); + set_floatx80_rounding_precision(floatx80_precision_x, &env->fp_status); ST1 = floatx80_div(ST1, ST0, &env->fp_status); - env->fp_status.floatx80_rounding_precision = save_prec; + set_floatx80_rounding_precision(save_prec, &env->fp_status); if (!floatx80_is_zero(ST1) && !(get_float_exception_flags(&env->fp_status) & float_flag_inexact)) { @@ -XXX,XX +XXX,XX @@ void helper_fpatan(CPUX86State *env) floatx80 x8; FloatRoundMode save_mode = get_float_rounding_mode(&env->fp_status); FloatX80RoundPrec save_prec = - env->fp_status.floatx80_rounding_precision; + get_floatx80_rounding_precision(&env->fp_status); set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - env->fp_status.floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, + &env->fp_status); if (arg0_exp == 0) { normalizeFloatx80Subnormal(arg0_sig, &arg0_exp, &arg0_sig); @@ -XXX,XX +XXX,XX @@ void helper_fpatan(CPUX86State *env) } set_float_rounding_mode(save_mode, &env->fp_status); - env->fp_status.floatx80_rounding_precision = save_prec; + set_floatx80_rounding_precision(save_prec, &env->fp_status); } /* This result is inexact. */ rsig1 |= 1; @@ -XXX,XX +XXX,XX @@ void helper_fyl2xp1(CPUX86State *env) uint64_t asig0, asig1, asig2; FloatRoundMode save_mode = get_float_rounding_mode(&env->fp_status); FloatX80RoundPrec save_prec = - env->fp_status.floatx80_rounding_precision; + get_floatx80_rounding_precision(&env->fp_status); set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - env->fp_status.floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, &env->fp_status); helper_fyl2x_common(env, ST0, &aexp, &asig0, &asig1); /* @@ -XXX,XX +XXX,XX @@ void helper_fyl2xp1(CPUX86State *env) ST1 = normalizeRoundAndPackFloatx80(floatx80_precision_x, arg0_sign ^ arg1_sign, aexp, asig0, asig1, &env->fp_status); - env->fp_status.floatx80_rounding_precision = save_prec; + set_floatx80_rounding_precision(save_prec, &env->fp_status); } fpop(env); merge_exception_flags(env, old_flags); @@ -XXX,XX +XXX,XX @@ void helper_fyl2x(CPUX86State *env) floatx80 arg0_m1; FloatRoundMode save_mode = get_float_rounding_mode(&env->fp_status); FloatX80RoundPrec save_prec = - env->fp_status.floatx80_rounding_precision; + get_floatx80_rounding_precision(&env->fp_status); set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - env->fp_status.floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, &env->fp_status); if (arg0_exp == 0) { normalizeFloatx80Subnormal(arg0_sig, &arg0_exp, &arg0_sig); @@ -XXX,XX +XXX,XX @@ void helper_fyl2x(CPUX86State *env) asig0, asig1, &env->fp_status); } - env->fp_status.floatx80_rounding_precision = save_prec; + set_floatx80_rounding_precision(save_prec, &env->fp_status); } fpop(env); merge_exception_flags(env, old_flags); @@ -XXX,XX +XXX,XX @@ void helper_fscale(CPUX86State *env) } } else { int n; - FloatX80RoundPrec save = env->fp_status.floatx80_rounding_precision; + FloatX80RoundPrec save = get_floatx80_rounding_precision(&env->fp_status); int save_flags = get_float_exception_flags(&env->fp_status); set_float_exception_flags(0, &env->fp_status); n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status); set_float_exception_flags(save_flags, &env->fp_status); - env->fp_status.floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, &env->fp_status); ST0 = floatx80_scalbn(ST0, n, &env->fp_status); - env->fp_status.floatx80_rounding_precision = save; + set_floatx80_rounding_precision(save, &env->fp_status); } merge_exception_flags(env, old_flags); } diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/target/m68k/softfloat.c +++ b/target/m68k/softfloat.c @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_getman(floatx80 a, float_status *status) normalizeFloatx80Subnormal(aSig, &aExp, &aSig); } - return roundAndPackFloatx80(status->floatx80_rounding_precision, aSign, + return roundAndPackFloatx80(get_floatx80_rounding_precision(status), + aSign, 0x3FFF, aSig, 0, status); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status) if (0x400F < bExp) { aExp = bSign ? -0x6001 : 0xE000; - return roundAndPackFloatx80(status->floatx80_rounding_precision, + return roundAndPackFloatx80(get_floatx80_rounding_precision(status), aSign, aExp, aSig, 0, status); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status) bSig >>= shiftCount; aExp = bSign ? (aExp - bSig) : (aExp + bSig); - return roundAndPackFloatx80(status->floatx80_rounding_precision, + return roundAndPackFloatx80(get_floatx80_rounding_precision(status), aSign, aExp, aSig, 0, status); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_move(floatx80 a, float_status *status) if (aSig == 0) { return a; } - normalizeRoundAndPackFloatx80(status->floatx80_rounding_precision, + normalizeRoundAndPackFloatx80(get_floatx80_rounding_precision(status), aSign, aExp, aSig, 0, status); } - return roundAndPackFloatx80(status->floatx80_rounding_precision, aSign, + return roundAndPackFloatx80(get_floatx80_rounding_precision(status), + aSign, aExp, aSig, 0, status); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_lognp1(floatx80 a, float_status *status) } user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); compact = floatx80_make_compact(aExp, aSig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_lognp1(floatx80 a, float_status *status) fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS LOG(F) + LOG(1+U) */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, klog2, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_lognp1(floatx80 a, float_status *status) status); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, saveu, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_logn(floatx80 a, float_status *status) } user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); compact = floatx80_make_compact(aExp, aSig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_logn(floatx80 a, float_status *status) fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS LOG(F) + LOG(1+U) */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, klog2, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_logn(floatx80 a, float_status *status) status); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, saveu, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_log10(floatx80 a, float_status *status) } user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); fp0 = floatx80_logn(a, status); fp1 = packFloatx80(0, 0x3FFD, UINT64_C(0xDE5BD8A937287195)); /* INV_L10 */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_mul(fp0, fp1, status); /* LOGN(X)*INV_L10 */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_log2(floatx80 a, float_status *status) } user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); if (aSig == one_sig) { /* X is 2^k */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = int32_to_floatx80(aExp - 0x3FFF, status); } else { @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_log2(floatx80 a, float_status *status) fp1 = packFloatx80(0, 0x3FFF, UINT64_C(0xB8AA3B295C17F0BC)); /* INV_L2 */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_mul(fp0, fp1, status); /* LOGN(X)*INV_L2 */ } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etox(floatx80 a, float_status *status) } user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); adjflag = 0; @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etox(floatx80 a, float_status *status) } set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_mul(fp0, scale, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etox(floatx80 a, float_status *status) } else { /* |X| >= 16380 log2 */ if (compact > 0x400CB27C) { /* |X| >= 16480 log2 */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); if (aSign) { - a = roundAndPackFloatx80( - status->floatx80_rounding_precision, - 0, -0x1000, aSig, 0, status); + a = roundAndPackFloatx80(get_floatx80_rounding_precision(status), + 0, -0x1000, aSig, 0, status); } else { - a = roundAndPackFloatx80( - status->floatx80_rounding_precision, - 0, 0x8000, aSig, 0, status); + a = roundAndPackFloatx80(get_floatx80_rounding_precision(status), + 0, 0x8000, aSig, 0, status); } float_raise(float_flag_inexact, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etox(floatx80 a, float_status *status) } } else { /* |X| < 2^(-65) */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(a, float32_to_floatx80(make_float32(0x3F800000), status), status); /* 1 + X */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_twotox(floatx80 a, float_status *status) } user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); fp0 = a; @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_twotox(floatx80 a, float_status *status) /* |X| > 16480 or |X| < 2^(-70) */ if (compact > 0x3FFF8000) { /* |X| > 16480 */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); if (aSign) { - return roundAndPackFloatx80(status->floatx80_rounding_precision, + return roundAndPackFloatx80(get_floatx80_rounding_precision(status), 0, -0x1000, aSig, 0, status); } else { - return roundAndPackFloatx80(status->floatx80_rounding_precision, + return roundAndPackFloatx80(get_floatx80_rounding_precision(status), 0, 0x8000, aSig, 0, status); } } else { /* |X| < 2^(-70) */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, float32_to_floatx80( make_float32(0x3F800000), status), @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_twotox(floatx80 a, float_status *status) fp0 = floatx80_add(fp0, fact1, status); set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_mul(fp0, adjfact, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tentox(floatx80 a, float_status *status) } user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); fp0 = a; @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tentox(floatx80 a, float_status *status) /* |X| > 16480 LOG2/LOG10 or |X| < 2^(-70) */ if (compact > 0x3FFF8000) { /* |X| > 16480 */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); if (aSign) { - return roundAndPackFloatx80(status->floatx80_rounding_precision, + return roundAndPackFloatx80(get_floatx80_rounding_precision(status), 0, -0x1000, aSig, 0, status); } else { - return roundAndPackFloatx80(status->floatx80_rounding_precision, + return roundAndPackFloatx80(get_floatx80_rounding_precision(status), 0, 0x8000, aSig, 0, status); } } else { /* |X| < 2^(-70) */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, float32_to_floatx80( make_float32(0x3F800000), status), @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tentox(floatx80 a, float_status *status) fp0 = floatx80_add(fp0, fact1, status); set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_mul(fp0, adjfact, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tan(floatx80 a, float_status *status) } user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); compact = floatx80_make_compact(aExp, aSig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tan(floatx80 a, float_status *status) goto loop; } else { set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_move(a, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tan(floatx80 a, float_status *status) fp1 = packFloatx80(xSign, xExp, xSig); set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_div(fp0, fp1, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tan(floatx80 a, float_status *status) status); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_div(fp0, fp1, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sin(floatx80 a, float_status *status) } user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); compact = floatx80_make_compact(aExp, aSig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sin(floatx80 a, float_status *status) status); /* 1 */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); /* SINTINY */ a = floatx80_move(a, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sin(floatx80 a, float_status *status) fp0 = floatx80_mul(fp0, x, status); set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, float32_to_floatx80(posneg1, status), status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sin(floatx80 a, float_status *status) fp0 = floatx80_mul(fp0, fp1, status); /* SIN(R')-R' */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, x, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_cos(floatx80 a, float_status *status) } user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); compact = floatx80_make_compact(aExp, aSig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_cos(floatx80 a, float_status *status) fp0 = float32_to_floatx80(make_float32(0x3F800000), status); /* 1 */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); /* COSTINY */ a = floatx80_sub(fp0, float32_to_floatx80( @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_cos(floatx80 a, float_status *status) fp0 = floatx80_mul(fp0, x, status); set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, float32_to_floatx80(posneg1, status), status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_cos(floatx80 a, float_status *status) fp0 = floatx80_mul(fp0, fp1, status); /* SIN(R')-R' */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, x, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atan(floatx80 a, float_status *status) compact = floatx80_make_compact(aExp, aSig); user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); if (compact < 0x3FFB8000 || compact > 0x4002FFFF) { /* |X| >= 16 or |X| < 1/16 */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atan(floatx80 a, float_status *status) fp1 = packFloatx80(aSign, 0x0001, one_sig); set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_sub(fp0, fp1, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atan(floatx80 a, float_status *status) fp1 = packFloatx80(aSign, piby2_exp, pi_sig); set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, fp1, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atan(floatx80 a, float_status *status) } else { /* |X| < 1/16 */ if (compact < 0x3FD78000) { /* |X| < 2^(-40) */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_move(a, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atan(floatx80 a, float_status *status) fp0 = floatx80_mul(fp0, fp1, status); set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, xsave, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atan(floatx80 a, float_status *status) fp0 = floatx80_add(fp0, fp1, status); /* ATAN(U) */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, fp3, status); /* ATAN(X) */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_asin(floatx80 a, float_status *status) } /* |X| < 1 */ user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); one = packFloatx80(0, one_exp, one_sig); fp0 = a; @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_asin(floatx80 a, float_status *status) fp0 = floatx80_div(fp0, fp1, status); /* X/SQRT((1+X)*(1-X)) */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_atan(fp0, status); /* ATAN(X/SQRT((1+X)*(1-X))) */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_acos(floatx80 a, float_status *status) } if (aExp == 0 && aSig == 0) { float_raise(float_flag_inexact, status); - return roundAndPackFloatx80(status->floatx80_rounding_precision, 0, + return roundAndPackFloatx80(get_floatx80_rounding_precision(status), + 0, piby2_exp, pi_sig, 0, status); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_acos(floatx80 a, float_status *status) } /* |X| < 1 */ user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); one = packFloatx80(0, one_exp, one_sig); fp0 = a; @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_acos(floatx80 a, float_status *status) fp0 = floatx80_atan(fp0, status); /* ATAN(SQRT((1-X)/(1+X))) */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, fp0, status); /* 2 * ATAN(SQRT((1-X)/(1+X))) */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atanh(floatx80 a, float_status *status) } /* |X| < 1 */ user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); one = packFloatx80(0, one_exp, one_sig); fp2 = packFloatx80(aSign, 0x3FFE, one_sig); /* SIGN(X) * (1/2) */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atanh(floatx80 a, float_status *status) fp0 = floatx80_lognp1(fp0, status); /* LOG1P(Z) */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_mul(fp0, fp2, status); /* ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z) */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etoxm1(floatx80 a, float_status *status) } user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); if (aExp >= 0x3FFD) { /* |X| >= 1/4 */ compact = floatx80_make_compact(aExp, aSig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etoxm1(floatx80 a, float_status *status) sc = packFloatx80(0, m + 0x3FFF, one_sig); set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_mul(fp0, sc, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etoxm1(floatx80 a, float_status *status) status); /* -1 */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, float32_to_floatx80( make_float32(0x00800000), status), @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etoxm1(floatx80 a, float_status *status) return a; } else { set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); return floatx80_etox(a, status); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etoxm1(floatx80 a, float_status *status) fp0 = floatx80_add(fp0, fp1, status); /* S*B1+Q */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, a, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etoxm1(floatx80 a, float_status *status) fp0 = floatx80_add(fp0, sc, status); set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_mul(fp0, float64_to_floatx80( make_float64(0x3730000000000000), status), status); } else { set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, sc, status); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tanh(floatx80 a, float_status *status) } user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); compact = floatx80_make_compact(aExp, aSig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tanh(floatx80 a, float_status *status) if (compact < 0x3FFF8000) { /* TANHSM */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_move(a, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tanh(floatx80 a, float_status *status) sign ^= 0x80800000; /* -SIGN(X)*EPS */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, float32_to_floatx80(make_float32(sign), status), status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tanh(floatx80 a, float_status *status) status); /* SIGN */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp1, fp0, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tanh(floatx80 a, float_status *status) fp1 = packFloatx80(vSign ^ aSign, vExp, vSig); set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_div(fp0, fp1, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sinh(floatx80 a, float_status *status) } user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); compact = floatx80_make_compact(aExp, aSig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sinh(floatx80 a, float_status *status) /* SINHBIG */ if (compact > 0x400CB2B3) { set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); - return roundAndPackFloatx80(status->floatx80_rounding_precision, + return roundAndPackFloatx80(get_floatx80_rounding_precision(status), aSign, 0x8000, aSig, 0, status); } else { fp0 = floatx80_abs(a); /* Y = |X| */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sinh(floatx80 a, float_status *status) fp2 = packFloatx80(aSign, 0x7FFB, one_sig); set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_mul(fp0, fp2, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sinh(floatx80 a, float_status *status) fact = packFloat32(aSign, 0x7E, 0); set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_mul(fp0, float32_to_floatx80(fact, status), status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_cosh(floatx80 a, float_status *status) } user_rnd_mode = get_float_rounding_mode(status); - user_rnd_prec = status->floatx80_rounding_precision; + user_rnd_prec = get_floatx80_rounding_precision(status); set_float_rounding_mode(float_round_nearest_even, status); - status->floatx80_rounding_precision = floatx80_precision_x; + set_floatx80_rounding_precision(floatx80_precision_x, status); compact = floatx80_make_compact(aExp, aSig); if (compact > 0x400CB167) { if (compact > 0x400CB2B3) { set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; - return roundAndPackFloatx80(status->floatx80_rounding_precision, 0, + set_floatx80_rounding_precision(user_rnd_prec, status); + return roundAndPackFloatx80(get_floatx80_rounding_precision(status), + 0, 0x8000, one_sig, 0, status); } else { fp0 = packFloatx80(0, aExp, aSig); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_cosh(floatx80 a, float_status *status) fp1 = packFloatx80(0, 0x7FFB, one_sig); set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_mul(fp0, fp1, status); @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_cosh(floatx80 a, float_status *status) fp1 = floatx80_div(fp1, fp0, status); /* 1/(2*EXP(|X|)) */ set_float_rounding_mode(user_rnd_mode, status); - status->floatx80_rounding_precision = user_rnd_prec; + set_floatx80_rounding_precision(user_rnd_prec, status); a = floatx80_add(fp0, fp1, status); diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/fp/fp-test.c +++ b/tests/fp/fp-test.c @@ -XXX,XX +XXX,XX @@ void run_test(void) verCases_roundingPrecision = 0; slow_extF80_roundingPrecision = prec80; - qsf.floatx80_rounding_precision = qsf_prec80; + set_floatx80_rounding_precision(qsf_prec80, &qsf); if (attrs & FUNC_EFF_ROUNDINGPRECISION) { verCases_roundingPrecision = prec80; -- 2.43.0
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat.h | 10 ++++++---- fpu/softfloat.c | 2 +- fpu/softfloat-parts.c.inc | 4 ++-- fpu/softfloat-specialize.c.inc | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -XXX,XX +XXX,XX @@ static inline bool floatx80_is_infinity(floatx80 a, float_status *status) bool intbit = a.low >> 63; if (!intbit && - !(status->floatx80_behaviour & floatx80_pseudo_inf_valid)) { + !(get_floatx80_behaviour(status) & floatx80_pseudo_inf_valid)) { return false; } return (a.high & 0x7fff) == 0x7fff && !(a.low << 1); @@ -XXX,XX +XXX,XX @@ static inline bool floatx80_unordered_quiet(floatx80 a, floatx80 b, *----------------------------------------------------------------------------*/ static inline bool floatx80_invalid_encoding(floatx80 a, float_status *s) { + FloatX80Behaviour rule = get_floatx80_behaviour(s); + if ((a.low >> 63) || (a.high & 0x7fff) == 0) { /* Anything with the Integer bit set or the exponent 0 is valid */ return false; @@ -XXX,XX +XXX,XX @@ static inline bool floatx80_invalid_encoding(floatx80 a, float_status *s) if ((a.high & 0x7fff) == 0x7fff) { if (a.low) { - return !(s->floatx80_behaviour & floatx80_pseudo_nan_valid); + return !(rule & floatx80_pseudo_nan_valid); } else { - return !(s->floatx80_behaviour & floatx80_pseudo_inf_valid); + return !(rule & floatx80_pseudo_inf_valid); } } else { - return !(s->floatx80_behaviour & floatx80_unnormal_valid); + return !(rule & floatx80_unnormal_valid); } } diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_round_pack_canonical(FloatParts128 *p, float_status *s) case float_class_inf: /* x86 and m68k differ in the setting of the integer bit. */ - frac = s->floatx80_behaviour & floatx80_default_inf_int_bit_is_zero ? + frac = get_floatx80_behaviour(s) & floatx80_default_inf_int_bit_is_zero ? 0 : (1ULL << 63); exp = fmt->exp_max; break; diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static void partsN(canonicalize)(FloatPartsN *p, float_status *status, * how we uncanonicalize results. */ bool has_pseudo_denormals = fmt->has_explicit_bit && - (status->floatx80_behaviour & floatx80_pseudo_denormal_valid); + (get_floatx80_behaviour(status) & floatx80_pseudo_denormal_valid); if (unlikely(p->exp == 0)) { if (likely(fracN(eqz)(p))) { @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, } else { bool is_tiny = s->tininess_before_rounding || exp < 0; bool has_pseudo_denormals = fmt->has_explicit_bit && - (s->floatx80_behaviour & floatx80_pseudo_denormal_valid); + (get_floatx80_behaviour(s) & floatx80_pseudo_denormal_valid); if (!is_tiny) { FloatPartsN discard; diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_default_inf(bool zSign, float_status *status) * Whether the Integer bit is set in the default Infinity is * target dependent. */ - bool z = status->floatx80_behaviour & floatx80_default_inf_int_bit_is_zero; + bool z = get_floatx80_behaviour(status) & floatx80_default_inf_int_bit_is_zero; return packFloatx80(zSign, 0x7fff, z ? 0 : (1ULL << 63)); } -- 2.43.0
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(pick_nan)(const FloatPartsN *a, const FloatPartsN *b, return partsN(default_nan)(s); } - switch (s->float_2nan_prop_rule) { + switch (get_float_2nan_prop_rule(s)) { case float_2nan_prop_s_ab: if (have_snan) { ret = is_snan(a->cls) ? a : b; -- 2.43.0
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static FloatPartsN partsN(pick_nan_muladd)(const FloatPartsN *a, ret = c; } else { const FloatPartsN *val[R_3NAN_1ST_MASK + 1] = { a, b, c }; - Float3NaNPropRule rule = s->float_3nan_prop_rule; + Float3NaNPropRule rule = get_float_3nan_prop_rule(s); assert(rule != float_3nan_prop_none); if (have_snan && (rule & R_3NAN_SNAN_MASK)) { -- 2.43.0
Deduplicate the uses to a local variable. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static FloatPartsN partsN(pick_nan_muladd)(const FloatPartsN *a, { bool infzero = (ab_mask == float_cmask_infzero); bool have_snan = (abc_mask & float_cmask_snan); + FloatInfZeroNaNRule izn_rule = get_float_infzeronan_rule(s); const FloatPartsN *ret; if (unlikely(have_snan)) { float_raise(float_flag_invalid | float_flag_invalid_snan, s); } - if (infzero && - !(s->float_infzeronan_rule & float_infzeronan_suppress_invalid)) { + if (infzero && !(izn_rule & float_infzeronan_suppress_invalid)) { /* This is (0 * inf) + NaN or (inf * 0) + NaN */ float_raise(float_flag_invalid | float_flag_invalid_imz, s); } @@ -XXX,XX +XXX,XX @@ static FloatPartsN partsN(pick_nan_muladd)(const FloatPartsN *a, * Inf * 0 + NaN -- some implementations return the * default NaN here, and some return the input NaN. */ - switch (s->float_infzeronan_rule & ~float_infzeronan_suppress_invalid) { + switch (izn_rule & ~float_infzeronan_suppress_invalid) { case float_infzeronan_dnan_never: break; case float_infzeronan_dnan_always: -- 2.43.0
Rename get_float_detect_tininess to get_tininess_before_rounding and move to softfloat.c, as there are no external users. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-helpers.h | 5 ----- fpu/softfloat.c | 4 ++-- tests/fp/fp-test.c | 2 +- fpu/softfloat-parts.c.inc | 2 +- fpu/softfloat-specialize.c.inc | 5 +++++ 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-helpers.h +++ b/include/fpu/softfloat-helpers.h @@ -XXX,XX +XXX,XX @@ static inline void set_snan_rule(FloatSNaNRule val, float_status *status) status->float_snan_rule = val; } -static inline bool get_float_detect_tininess(const float_status *status) -{ - return status->tininess_before_rounding; -} - static inline FloatRoundMode get_float_rounding_mode(const float_status *status) { return status->float_rounding_mode; diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ floatx80 roundAndPackFloatx80(FloatX80RoundPrec roundingPrecision, bool zSign, float_raise(float_flag_output_denormal_flushed, status); return packFloatx80(zSign, 0, 0); } - isTiny = status->tininess_before_rounding + isTiny = get_tininess_before_rounding(status) || (zExp < 0 ) || (zSig0 <= zSig0 + roundIncrement); shift64RightJamming( zSig0, 1 - zExp, &zSig0 ); @@ -XXX,XX +XXX,XX @@ floatx80 roundAndPackFloatx80(FloatX80RoundPrec roundingPrecision, bool zSign, return floatx80_default_inf(zSign, status); } if ( zExp <= 0 ) { - isTiny = status->tininess_before_rounding + isTiny = get_tininess_before_rounding(status) || (zExp < 0) || !increment || (zSig0 < UINT64_C(0xFFFFFFFFFFFFFFFF)); diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/fp/fp-test.c +++ b/tests/fp/fp-test.c @@ -XXX,XX +XXX,XX @@ void run_test(void) verCases_tininessCode = 0; slowfloat_detectTininess = tmode; - qsf.tininess_before_rounding = sf_tininess_to_qemu(tmode); + set_float_detect_tininess(sf_tininess_to_qemu(tmode), &qsf); if (attrs & FUNC_EFF_TININESSMODE || ((attrs & FUNC_EFF_TININESSMODE_REDUCEDPREC) && diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, exp = 0; fracN(clear)(p); } else { - bool is_tiny = s->tininess_before_rounding || exp < 0; + bool is_tiny = get_tininess_before_rounding(s) || exp < 0; bool has_pseudo_denormals = fmt->has_explicit_bit && (get_floatx80_behaviour(s) & floatx80_pseudo_denormal_valid); diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -XXX,XX +XXX,XX @@ this code that are retained. * version 2 or later. See the COPYING file in the top-level directory. */ +static inline bool get_tininess_before_rounding(const float_status *status) +{ + return status->tininess_before_rounding; +} + /*---------------------------------------------------------------------------- | For the deconstructed floating-point with fraction FRAC, return true | if the fraction represents a signalling NaN; otherwise false. -- 2.43.0
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 2 +- target/arm/tcg/vfp_helper.c | 6 +++--- tests/fp/fp-bench.c | 2 +- fpu/softfloat-parts.c.inc | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ floatx80 roundAndPackFloatx80(FloatX80RoundPrec roundingPrecision, bool zSign, goto overflow; } if ( zExp <= 0 ) { - if (status->flush_to_zero) { + if (get_flush_to_zero(status)) { float_raise(float_flag_output_denormal_flushed, status); return packFloatx80(zSign, 0, 0); } diff --git a/target/arm/tcg/vfp_helper.c b/target/arm/tcg/vfp_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vfp_helper.c +++ b/target/arm/tcg/vfp_helper.c @@ -XXX,XX +XXX,XX @@ uint32_t HELPER(recpe_f16)(uint32_t input, float_status *fpst) } else { return float16_set_sign(float16_maxnorm, f16_sign); } - } else if (f16_exp >= 29 && fpst->flush_to_zero) { + } else if (f16_exp >= 29 && get_flush_to_zero(fpst)) { float_raise(float_flag_underflow, fpst); return float16_set_sign(float16_zero, float16_is_neg(f16)); } @@ -XXX,XX +XXX,XX @@ static float32 do_recpe_f32(float32 input, float_status *fpst, bool rpres) } else { return float32_set_sign(float32_maxnorm, f32_sign); } - } else if (f32_exp >= 253 && fpst->flush_to_zero) { + } else if (f32_exp >= 253 && get_flush_to_zero(fpst)) { float_raise(float_flag_underflow, fpst); return float32_set_sign(float32_zero, float32_is_neg(f32)); } @@ -XXX,XX +XXX,XX @@ float64 HELPER(recpe_f64)(float64 input, float_status *fpst) } else { return float64_set_sign(float64_maxnorm, f64_sign); } - } else if (f64_exp >= 2045 && fpst->flush_to_zero) { + } else if (f64_exp >= 2045 && get_flush_to_zero(fpst)) { float_raise(float_flag_underflow, fpst); return float64_set_sign(float64_zero, float64_is_neg(f64)); } diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c index XXXXXXX..XXXXXXX 100644 --- a/tests/fp/fp-bench.c +++ b/tests/fp/fp-bench.c @@ -XXX,XX +XXX,XX @@ static void parse_args(int argc, char *argv[]) soft_status.flush_inputs_to_zero = 1; break; case 'Z': - soft_status.flush_to_zero = 1; + set_flush_to_zero(true, &soft_status); break; } } diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, p->frac_lo &= ~round_mask; } fracN(shr)(p, frac_shift); - } else if (s->flush_to_zero && + } else if (get_flush_to_zero(s) && s->ftz_detection == float_ftz_before_rounding) { flags |= float_flag_output_denormal_flushed; p->cls = float_class_zero; @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, fracN(shr)(p, frac_shift); if (is_tiny) { - if (s->flush_to_zero) { + if (get_flush_to_zero(s)) { assert(s->ftz_detection == float_ftz_after_rounding); flags |= float_flag_output_denormal_flushed; p->cls = float_class_zero; -- 2.43.0
Drop FloatFTZDetection and use #defines, like we do for tininess_before_rounding. Rename get_float_ftz_detection to get_ftz_before_rounding and move to softfloat.c, as there are no external users. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-helpers.h | 10 ++-------- include/fpu/softfloat-types.h | 8 +++----- fpu/softfloat-parts.c.inc | 5 ++--- fpu/softfloat-specialize.c.inc | 5 +++++ 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-helpers.h +++ b/include/fpu/softfloat-helpers.h @@ -XXX,XX +XXX,XX @@ static inline void set_flush_inputs_to_zero(bool val, float_status *status) status->flush_inputs_to_zero = val; } -static inline void set_float_ftz_detection(FloatFTZDetection d, - float_status *status) +static inline void set_float_ftz_detection(bool val, float_status *status) { - status->ftz_detection = d; + status->ftz_before_rounding = val; } static inline void set_default_nan_mode(bool val, float_status *status) @@ -XXX,XX +XXX,XX @@ static inline FloatSNaNRule get_snan_rule(float_status *status) return status->float_snan_rule; } -static inline FloatFTZDetection get_float_ftz_detection(const float_status *status) -{ - return status->ftz_detection; -} - #endif /* SOFTFLOAT_HELPERS_H */ diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-types.h +++ b/include/fpu/softfloat-types.h @@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) { * configure it matches the default for tininess_before_rounding * (i.e. "after rounding"). */ -typedef enum __attribute__((__packed__)) { - float_ftz_after_rounding = 0, - float_ftz_before_rounding = 1, -} FloatFTZDetection; +#define float_ftz_after_rounding false +#define float_ftz_before_rounding true /* * floatx80 is primarily used by x86 and m68k, and there are @@ -XXX,XX +XXX,XX @@ typedef struct float_status { /* should denormalised results go to zero and set output_denormal_flushed? */ bool flush_to_zero; /* do we detect and flush denormal results before or after rounding? */ - FloatFTZDetection ftz_detection; + bool ftz_before_rounding; /* should denormalised inputs go to zero and set input_denormal_flushed? */ bool flush_inputs_to_zero; bool default_nan_mode; diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, p->frac_lo &= ~round_mask; } fracN(shr)(p, frac_shift); - } else if (get_flush_to_zero(s) && - s->ftz_detection == float_ftz_before_rounding) { + } else if (get_flush_to_zero(s) && get_ftz_before_rounding(s)) { flags |= float_flag_output_denormal_flushed; p->cls = float_class_zero; exp = 0; @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, if (is_tiny) { if (get_flush_to_zero(s)) { - assert(s->ftz_detection == float_ftz_after_rounding); + assert(!get_ftz_before_rounding(s)); flags |= float_flag_output_denormal_flushed; p->cls = float_class_zero; exp = 0; diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -XXX,XX +XXX,XX @@ static inline bool get_tininess_before_rounding(const float_status *status) return status->tininess_before_rounding; } +static inline bool get_ftz_before_rounding(const float_status *status) +{ + return status->ftz_before_rounding; +} + /*---------------------------------------------------------------------------- | For the deconstructed floating-point with fraction FRAC, return true | if the fraction represents a signalling NaN; otherwise false. -- 2.43.0
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 14 +++++++------- target/alpha/fpu_helper.c | 2 +- target/alpha/helper.c | 3 ++- tests/fp/fp-bench.c | 2 +- fpu/softfloat-parts.c.inc | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ GEN_INPUT_FLUSH__NOCHECK(float64_input_flush__nocheck, float64) #define GEN_INPUT_FLUSH1(name, soft_t) \ static inline void name(soft_t *a, float_status *s) \ { \ - if (likely(!s->flush_inputs_to_zero)) { \ + if (likely(!get_flush_inputs_to_zero(s))) { \ return; \ } \ soft_t ## _input_flush__nocheck(a, s); \ @@ -XXX,XX +XXX,XX @@ GEN_INPUT_FLUSH1(float64_input_flush1, float64) #define GEN_INPUT_FLUSH2(name, soft_t) \ static inline void name(soft_t *a, soft_t *b, float_status *s) \ { \ - if (likely(!s->flush_inputs_to_zero)) { \ + if (likely(!get_flush_inputs_to_zero(s))) { \ return; \ } \ soft_t ## _input_flush__nocheck(a, s); \ @@ -XXX,XX +XXX,XX @@ GEN_INPUT_FLUSH2(float64_input_flush2, float64) #define GEN_INPUT_FLUSH3(name, soft_t) \ static inline void name(soft_t *a, soft_t *b, soft_t *c, float_status *s) \ { \ - if (likely(!s->flush_inputs_to_zero)) { \ + if (likely(!get_flush_inputs_to_zero(s))) { \ return; \ } \ soft_t ## _input_flush__nocheck(a, s); \ @@ -XXX,XX +XXX,XX @@ static bool parts_squash_denormal(FloatParts64 p, float_status *status) float16 float16_squash_input_denormal(float16 a, float_status *status) { - if (status->flush_inputs_to_zero) { + if (get_flush_inputs_to_zero(status)) { FloatParts64 p = unpack_raw64(&float16_params, a); if (parts_squash_denormal(p, status)) { @@ -XXX,XX +XXX,XX @@ float16 float16_squash_input_denormal(float16 a, float_status *status) float32 float32_squash_input_denormal(float32 a, float_status *status) { - if (status->flush_inputs_to_zero) { + if (get_flush_inputs_to_zero(status)) { FloatParts64 p = unpack_raw64(&float32_params, a); if (parts_squash_denormal(p, status)) { @@ -XXX,XX +XXX,XX @@ float32 float32_squash_input_denormal(float32 a, float_status *status) float64 float64_squash_input_denormal(float64 a, float_status *status) { - if (status->flush_inputs_to_zero) { + if (get_flush_inputs_to_zero(status)) { FloatParts64 p = unpack_raw64(&float64_params, a); if (parts_squash_denormal(p, status)) { @@ -XXX,XX +XXX,XX @@ float64 float64_squash_input_denormal(float64 a, float_status *status) bfloat16 bfloat16_squash_input_denormal(bfloat16 a, float_status *status) { - if (status->flush_inputs_to_zero) { + if (get_flush_inputs_to_zero(status)) { FloatParts64 p = unpack_raw64(&bfloat16_params, a); if (parts_squash_denormal(p, status)) { diff --git a/target/alpha/fpu_helper.c b/target/alpha/fpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/alpha/fpu_helper.c +++ b/target/alpha/fpu_helper.c @@ -XXX,XX +XXX,XX @@ void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val) void helper_ieee_input_s(CPUAlphaState *env, uint64_t val) { if (unlikely(2 * val - 1 < 0x1fffffffffffffull) - && !env->fp_status.flush_inputs_to_zero) { + && !get_flush_inputs_to_zero(&env->fp_status)) { arith_excp(env, GETPC(), EXC_M_INV | EXC_M_SWC, 0); } } diff --git a/target/alpha/helper.c b/target/alpha/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/alpha/helper.c +++ b/target/alpha/helper.c @@ -XXX,XX +XXX,XX @@ #include "exec/page-protection.h" #include "exec/target_page.h" #include "fpu/softfloat-types.h" +#include "fpu/softfloat-helpers.h" #include "exec/helper-proto.h" #include "qemu/qemu-print.h" #include "system/memory.h" @@ -XXX,XX +XXX,XX @@ void cpu_alpha_store_fpcr(CPUAlphaState *env, uint64_t val) env->fpcr_exc_enable = ~t & FPCR_STATUS_MASK; env->fpcr_dyn_round = rm_map[(fpcr & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT]; - env->fp_status.flush_inputs_to_zero = (fpcr & FPCR_DNZ) != 0; + set_flush_inputs_to_zero(fpcr & FPCR_DNZ, &env->fp_status); t = (fpcr & FPCR_UNFD) && (fpcr & FPCR_UNDZ); #ifdef CONFIG_USER_ONLY diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c index XXXXXXX..XXXXXXX 100644 --- a/tests/fp/fp-bench.c +++ b/tests/fp/fp-bench.c @@ -XXX,XX +XXX,XX @@ static void parse_args(int argc, char *argv[]) tester = val; break; case 'z': - soft_status.flush_inputs_to_zero = 1; + set_flush_inputs_to_zero(true, &soft_status); break; case 'Z': set_flush_to_zero(true, &soft_status); diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static void partsN(canonicalize)(FloatPartsN *p, float_status *status, if (unlikely(p->exp == 0)) { if (likely(fracN(eqz)(p))) { p->cls = float_class_zero; - } else if (status->flush_inputs_to_zero) { + } else if (get_flush_inputs_to_zero(status)) { float_raise(float_flag_input_denormal_flushed, status); p->cls = float_class_zero; fracN(clear)(p); -- 2.43.0
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/arm/tcg/helper-a64.c | 12 ++++++------ target/arm/tcg/vfp_helper.c | 24 ++++++++++++------------ target/m68k/softfloat.c | 2 +- fpu/softfloat-parts.c.inc | 8 ++++---- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -XXX,XX +XXX,XX @@ uint32_t HELPER(frecpx_f16)(uint32_t a, float_status *fpst) float16 nan = a; if (float16_is_signaling_nan(a, fpst)) { float_raise(float_flag_invalid, fpst); - if (!fpst->default_nan_mode) { + if (!get_default_nan_mode(fpst)) { nan = float16_silence_nan(a, fpst); } } - if (fpst->default_nan_mode) { + if (get_default_nan_mode(fpst)) { nan = float16_default_nan(fpst); } return nan; @@ -XXX,XX +XXX,XX @@ float32 HELPER(frecpx_f32)(float32 a, float_status *fpst) float32 nan = a; if (float32_is_signaling_nan(a, fpst)) { float_raise(float_flag_invalid, fpst); - if (!fpst->default_nan_mode) { + if (!get_default_nan_mode(fpst)) { nan = float32_silence_nan(a, fpst); } } - if (fpst->default_nan_mode) { + if (get_default_nan_mode(fpst)) { nan = float32_default_nan(fpst); } return nan; @@ -XXX,XX +XXX,XX @@ float64 HELPER(frecpx_f64)(float64 a, float_status *fpst) float64 nan = a; if (float64_is_signaling_nan(a, fpst)) { float_raise(float_flag_invalid, fpst); - if (!fpst->default_nan_mode) { + if (!get_default_nan_mode(fpst)) { nan = float64_silence_nan(a, fpst); } } - if (fpst->default_nan_mode) { + if (get_default_nan_mode(fpst)) { nan = float64_default_nan(fpst); } return nan; diff --git a/target/arm/tcg/vfp_helper.c b/target/arm/tcg/vfp_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vfp_helper.c +++ b/target/arm/tcg/vfp_helper.c @@ -XXX,XX +XXX,XX @@ uint32_t HELPER(recpe_f16)(uint32_t input, float_status *fpst) float16 nan = f16; if (float16_is_signaling_nan(f16, fpst)) { float_raise(float_flag_invalid, fpst); - if (!fpst->default_nan_mode) { + if (!get_default_nan_mode(fpst)) { nan = float16_silence_nan(f16, fpst); } } - if (fpst->default_nan_mode) { + if (get_default_nan_mode(fpst)) { nan = float16_default_nan(fpst); } return nan; @@ -XXX,XX +XXX,XX @@ static float32 do_recpe_f32(float32 input, float_status *fpst, bool rpres) float32 nan = f32; if (float32_is_signaling_nan(f32, fpst)) { float_raise(float_flag_invalid, fpst); - if (!fpst->default_nan_mode) { + if (!get_default_nan_mode(fpst)) { nan = float32_silence_nan(f32, fpst); } } - if (fpst->default_nan_mode) { + if (get_default_nan_mode(fpst)) { nan = float32_default_nan(fpst); } return nan; @@ -XXX,XX +XXX,XX @@ float64 HELPER(recpe_f64)(float64 input, float_status *fpst) float64 nan = f64; if (float64_is_signaling_nan(f64, fpst)) { float_raise(float_flag_invalid, fpst); - if (!fpst->default_nan_mode) { + if (!get_default_nan_mode(fpst)) { nan = float64_silence_nan(f64, fpst); } } - if (fpst->default_nan_mode) { + if (get_default_nan_mode(fpst)) { nan = float64_default_nan(fpst); } return nan; @@ -XXX,XX +XXX,XX @@ uint32_t HELPER(rsqrte_f16)(uint32_t input, float_status *s) float16 nan = f16; if (float16_is_signaling_nan(f16, s)) { float_raise(float_flag_invalid, s); - if (!s->default_nan_mode) { + if (!get_default_nan_mode(s)) { nan = float16_silence_nan(f16, s); } } - if (s->default_nan_mode) { + if (get_default_nan_mode(s)) { nan = float16_default_nan(s); } return nan; @@ -XXX,XX +XXX,XX @@ static float32 do_rsqrte_f32(float32 input, float_status *s, bool rpres) float32 nan = f32; if (float32_is_signaling_nan(f32, s)) { float_raise(float_flag_invalid, s); - if (!s->default_nan_mode) { + if (!get_default_nan_mode(s)) { nan = float32_silence_nan(f32, s); } } - if (s->default_nan_mode) { + if (get_default_nan_mode(s)) { nan = float32_default_nan(s); } return nan; @@ -XXX,XX +XXX,XX @@ float64 HELPER(rsqrte_f64)(float64 input, float_status *s) float64 nan = f64; if (float64_is_signaling_nan(f64, s)) { float_raise(float_flag_invalid, s); - if (!s->default_nan_mode) { + if (!get_default_nan_mode(s)) { nan = float64_silence_nan(f64, s); } } - if (s->default_nan_mode) { + if (get_default_nan_mode(s)) { nan = float64_default_nan(s); } return nan; diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/target/m68k/softfloat.c +++ b/target/m68k/softfloat.c @@ -XXX,XX +XXX,XX @@ static floatx80 propagateFloatx80NaNOneArg(floatx80 a, float_status *status) a = floatx80_silence_nan(a, status); } - if (status->default_nan_mode) { + if (get_default_nan_mode(status)) { return floatx80_default_nan(status); } diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(return_nan)(const FloatPartsN *a, float_status *s) switch (a->cls) { case float_class_snan: float_raise(float_flag_invalid | float_flag_invalid_snan, s); - if (s->default_nan_mode) { + if (get_default_nan_mode(s)) { return partsN(default_nan)(s); } else { return partsN(silence_nan)(a, s); } break; case float_class_qnan: - if (s->default_nan_mode) { + if (get_default_nan_mode(s)) { return partsN(default_nan)(s); } break; @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(pick_nan)(const FloatPartsN *a, const FloatPartsN *b, have_snan = true; } - if (s->default_nan_mode) { + if (get_default_nan_mode(s)) { return partsN(default_nan)(s); } @@ -XXX,XX +XXX,XX @@ static FloatPartsN partsN(pick_nan_muladd)(const FloatPartsN *a, float_raise(float_flag_invalid | float_flag_invalid_imz, s); } - if (s->default_nan_mode) { + if (get_default_nan_mode(s)) { /* * We guarantee not to require the target to tell us how to * pick a NaN if we're always returning the default NaN. -- 2.43.0
Move get_float_default_nan_pattern to softfloat-specialize.c.inc, since there are no external users. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-helpers.h | 5 ----- fpu/softfloat-specialize.c.inc | 7 ++++++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-helpers.h +++ b/include/fpu/softfloat-helpers.h @@ -XXX,XX +XXX,XX @@ get_float_infzeronan_rule(const float_status *status) return status->float_infzeronan_rule; } -static inline uint8_t get_float_default_nan_pattern(const float_status *status) -{ - return status->default_nan_pattern; -} - static inline bool get_flush_to_zero(const float_status *status) { return status->flush_to_zero; diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -XXX,XX +XXX,XX @@ static inline bool get_ftz_before_rounding(const float_status *status) return status->ftz_before_rounding; } +static inline uint8_t get_float_default_nan_pattern(const float_status *status) +{ + return status->default_nan_pattern; +} + /*---------------------------------------------------------------------------- | For the deconstructed floating-point with fraction FRAC, return true | if the fraction represents a signalling NaN; otherwise false. @@ -XXX,XX +XXX,XX @@ FloatParts64 parts64_default_nan(float_status *status) { bool sign = 0; uint64_t frac; - uint8_t dnan_pattern = status->default_nan_pattern; + uint8_t dnan_pattern = get_float_default_nan_pattern(status); assert(dnan_pattern != 0); -- 2.43.0
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-helpers.h | 10 ++++++++++ target/ppc/cpu.c | 4 ++-- fpu/softfloat-parts.c.inc | 4 ++-- fpu/softfloat-specialize.c.inc | 10 ++++++++++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-helpers.h +++ b/include/fpu/softfloat-helpers.h @@ -XXX,XX +XXX,XX @@ static inline void set_snan_rule(FloatSNaNRule val, float_status *status) status->float_snan_rule = val; } +static inline void set_float_rebias_overflow(bool val, float_status *status) +{ + status->rebias_overflow = val; +} + +static inline void set_float_rebias_underflow(bool val, float_status *status) +{ + status->rebias_underflow = val; +} + static inline FloatRoundMode get_float_rounding_mode(const float_status *status) { return status->float_rounding_mode; diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/ppc/cpu.c +++ b/target/ppc/cpu.c @@ -XXX,XX +XXX,XX @@ void ppc_store_fpscr(CPUPPCState *env, target_ulong val) val |= FP_FEX; } env->fpscr = val; - env->fp_status.rebias_overflow = (FP_OE & env->fpscr) ? true : false; - env->fp_status.rebias_underflow = (FP_UE & env->fpscr) ? true : false; + set_float_rebias_overflow(FP_OE & env->fpscr, &env->fp_status); + set_float_rebias_underflow(FP_UE & env->fpscr, &env->fp_status); if (tcg_enabled()) { fpscr_set_rounding_mode(env); } diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, switch (fmt->exp_max_kind) { case float_expmax_ieee: flags |= float_flag_overflow; - if (s->rebias_overflow) { + if (get_float_rebias_overflow(s)) { exp -= fmt->exp_re_bias; } else if (overflow_norm) { flags |= float_flag_inexact; @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, } } fracN(shr)(p, frac_shift); - } else if (unlikely(s->rebias_underflow)) { + } else if (unlikely(get_float_rebias_underflow(s))) { flags |= float_flag_underflow; exp += fmt->exp_re_bias; if (p->frac_lo & round_mask) { diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -XXX,XX +XXX,XX @@ static inline uint8_t get_float_default_nan_pattern(const float_status *status) return status->default_nan_pattern; } +static inline bool get_float_rebias_overflow(const float_status *status) +{ + return status->rebias_overflow; +} + +static inline bool get_float_rebias_underflow(const float_status *status) +{ + return status->rebias_underflow; +} + /*---------------------------------------------------------------------------- | For the deconstructed floating-point with fraction FRAC, return true | if the fraction represents a signalling NaN; otherwise false. -- 2.43.0
Use bitfields to compress float_status from 18 bytes down to 8 bytes. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-types.h | 53 ++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-types.h +++ b/include/fpu/softfloat-types.h @@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) { * This is a flag which can be ORed in with any of the above * DNaN behaviour options. */ - float_infzeronan_suppress_invalid = (1 << 7), + float_infzeronan_suppress_invalid = (1 << 2), } FloatInfZeroNaNRule; /* @@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) { */ typedef struct float_status { - FloatExceptionFlags float_exception_flags; - FloatRoundMode float_rounding_mode; - FloatX80RoundPrec floatx80_rounding_precision; - FloatX80Behaviour floatx80_behaviour; - Float2NaNPropRule float_2nan_prop_rule; - Float3NaNPropRule float_3nan_prop_rule; - FloatInfZeroNaNRule float_infzeronan_rule; - FloatSNaNRule float_snan_rule; - bool tininess_before_rounding; + FloatExceptionFlags float_exception_flags : 16; + + /* + * Floating point status controls. + * Items that, in general, may be updated by writes to an architectural + * floating point control register. + */ + FloatRoundMode float_rounding_mode : 3; + FloatX80RoundPrec floatx80_rounding_precision : 2; /* should denormalised results go to zero and set output_denormal_flushed? */ - bool flush_to_zero; - /* do we detect and flush denormal results before or after rounding? */ - bool ftz_before_rounding; + bool flush_to_zero : 1; /* should denormalised inputs go to zero and set input_denormal_flushed? */ - bool flush_inputs_to_zero; - bool default_nan_mode; + bool flush_inputs_to_zero : 1; + /* should default nans be produced instead of propagating an input nan? */ + bool default_nan_mode : 1; + /* should overflowed results subtract re_bias to its exponent? */ + bool rebias_overflow : 1; + /* should underflowed results add re_bias to its exponent? */ + bool rebias_underflow : 1; + + /* + * Floating point behaviour controls. + * Items that, in general, will be set at cpu realization because + * the behaviour is baked into the specific hardware implementation. + */ + bool tininess_before_rounding : 1; + /* do we detect and flush denormal results before or after rounding? */ + bool ftz_before_rounding : 1; + FloatSNaNRule float_snan_rule : 2; + Float2NaNPropRule float_2nan_prop_rule : 3; + Float3NaNPropRule float_3nan_prop_rule : 7; + FloatInfZeroNaNRule float_infzeronan_rule: 3; + FloatX80Behaviour floatx80_behaviour : 5; /* * The pattern to use for the default NaN. Here the high bit specifies * the default NaN's sign bit, and bits 6..0 specify the high bits of the @@ -XXX,XX +XXX,XX @@ typedef struct float_status { * this to the correct non-zero value, or we will assert when trying to * create a default NaN. */ - uint8_t default_nan_pattern; - /* should overflowed results subtract re_bias to its exponent? */ - bool rebias_overflow; - /* should underflowed results add re_bias to its exponent? */ - bool rebias_underflow; + unsigned default_nan_pattern : 8; } float_status; #endif /* SOFTFLOAT_TYPES_H */ -- 2.43.0
Introduce a separate control from float_snan_rule that applies only to the OCP E4M3 format. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-helpers.h | 5 +++++ include/fpu/softfloat-types.h | 5 +++++ fpu/softfloat-parts.c.inc | 2 +- fpu/softfloat-specialize.c.inc | 5 +++++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-helpers.h +++ b/include/fpu/softfloat-helpers.h @@ -XXX,XX +XXX,XX @@ static inline void set_snan_rule(FloatSNaNRule val, float_status *status) status->float_snan_rule = val; } +static inline void set_float_e4m3_nan_is_snan(bool val, float_status *status) +{ + status->e4m3_nan_is_snan = val; +} + static inline void set_float_rebias_overflow(bool val, float_status *status) { status->rebias_overflow = val; diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-types.h +++ b/include/fpu/softfloat-types.h @@ -XXX,XX +XXX,XX @@ typedef struct float_status { /* do we detect and flush denormal results before or after rounding? */ bool ftz_before_rounding : 1; FloatSNaNRule float_snan_rule : 2; + /* + * Overriding float_snan_rule, is the single NaN representation for + * the OCP E4M3 format an SNaN or QNaN? + */ + bool e4m3_nan_is_snan : 1; Float2NaNPropRule float_2nan_prop_rule : 3; Float3NaNPropRule float_3nan_prop_rule : 7; FloatInfZeroNaNRule float_infzeronan_rule: 3; diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static void partsN(canonicalize)(FloatPartsN *p, float_status *status, case float_expmax_e4m3: if (p->frac_hi == 0b111) { fracN(shl)(p, fmt->frac_shift); - p->cls = (parts_is_snan_frac(p->frac_hi, status) + p->cls = (get_float_e4m3_nan_is_snan(status) ? float_class_snan : float_class_qnan); return; } diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -XXX,XX +XXX,XX @@ static inline bool get_float_rebias_underflow(const float_status *status) return status->rebias_underflow; } +static inline bool get_float_e4m3_nan_is_snan(const float_status *status) +{ + return status->e4m3_nan_is_snan; +} + /*---------------------------------------------------------------------------- | For the deconstructed floating-point with fraction FRAC, return true | if the fraction represents a signalling NaN; otherwise false. -- 2.43.0
There is only one NaN fractional encoding for E4M3. Retain the incoming sign, but force the outgoing fraction to the unique value. Reported-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 2 ++ fpu/softfloat-parts.c.inc | 29 ++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ const FloatFmt float8_e4m3_params = { /* 110 << frac_shift, with the implicit bit set */ #define E4M3_NORMAL_FRAC_MAX 0xe000000000000000ull +/* 111 << frac_shift, no implicit bit */ +#define E4M3_NAN_FRAC 0x7000000000000000ull const FloatFmt float8_e5m2_params = { FLOAT_PARAMS(5, 2) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_e4m3_overflow)(FloatPartsN *p, float_status *s, const FloatFmt *fmt, bool saturate) { assert(N == 64); + p->exp = fmt->exp_max; if (saturate) { - p->exp = fmt->exp_max; p->frac_hi = E4M3_NORMAL_FRAC_MAX; } else { - *p = partsN(default_nan)(s); + /* + * The class isn't actually used after this point in uncanon, + * but for clarity while debugging, don't leave it set to normal. + */ + p->cls = float_class_qnan; + p->frac_hi = E4M3_NAN_FRAC; } } @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon)(FloatPartsN *p, float_status *s, return; case float_class_qnan: case float_class_snan: - assert(fmt->exp_max_kind != float_expmax_normal); p->exp = fmt->exp_max; - fracN(shr)(p, fmt->frac_shift); - return; + switch (fmt->exp_max_kind) { + case float_expmax_e4m3: + /* + * There is only one NaN encoding for E4M3, and with a + * conversion from another format, the input NaN fraction + * may not apply. + */ + assert(N == 64); + p->frac_hi = E4M3_NAN_FRAC; + /* fall through */ + case float_expmax_ieee: + fracN(shr)(p, fmt->frac_shift); + return; + case float_expmax_normal: + break; + } + g_assert_not_reached(); default: break; } -- 2.43.0
Allow target access to routines using the minmax flags. Make the existing min/max wrappers inline. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat.h | 93 ++++++++++++++++++++++----------------- fpu/softfloat.c | 50 +++------------------ fpu/softfloat-parts.c.inc | 8 ++-- 3 files changed, 62 insertions(+), 89 deletions(-) diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -XXX,XX +XXX,XX @@ enum { float_muladd_suppress_add_product_zero = 8, }; +/*---------------------------------------------------------------------------- +| Options to indicate which negations to perform in float*_minmax() +*----------------------------------------------------------------------------*/ + +/* Flags for parts_minmax. */ +enum { + /* Set for minimum; clear for maximum. */ + float_minmax_ismin = 1, + /* Set for the IEEE 754-2008 minNum() and maxNum() operations. */ + float_minmax_isnum = 2, + /* Set for the IEEE 754-2008 minNumMag() and minNumMag() operations. */ + float_minmax_ismag = 4, + /* + * Set for the IEEE 754-2019 minimumNumber() and maximumNumber() + * operations. + */ + float_minmax_isnumber = 8, +}; + /*---------------------------------------------------------------------------- | Software IEC/IEEE integer-to-floating-point conversion routines. *----------------------------------------------------------------------------*/ @@ -XXX,XX +XXX,XX @@ float16 float16_muladd_scalbn(float16, float16, float16, int, int, float_status *status); float16 float16_div(float16, float16, float_status *status); float16 float16_scalbn(float16, int, float_status *status); -float16 float16_min(float16, float16, float_status *status); -float16 float16_max(float16, float16, float_status *status); -float16 float16_minnum(float16, float16, float_status *status); -float16 float16_maxnum(float16, float16, float_status *status); -float16 float16_minnummag(float16, float16, float_status *status); -float16 float16_maxnummag(float16, float16, float_status *status); -float16 float16_minimum_number(float16, float16, float_status *status); -float16 float16_maximum_number(float16, float16, float_status *status); +float16 float16_minmax(float16, float16, float_status *status, int flags); float16 float16_sqrt(float16, float_status *status); FloatRelation float16_compare(float16, float16, float_status *status); FloatRelation float16_compare_quiet(float16, float16, float_status *status); @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_div(bfloat16, bfloat16, float_status *status); bfloat16 bfloat16_muladd(bfloat16, bfloat16, bfloat16, int, float_status *status); float16 bfloat16_scalbn(bfloat16, int, float_status *status); -bfloat16 bfloat16_min(bfloat16, bfloat16, float_status *status); -bfloat16 bfloat16_max(bfloat16, bfloat16, float_status *status); -bfloat16 bfloat16_minnum(bfloat16, bfloat16, float_status *status); -bfloat16 bfloat16_maxnum(bfloat16, bfloat16, float_status *status); -bfloat16 bfloat16_minnummag(bfloat16, bfloat16, float_status *status); -bfloat16 bfloat16_maxnummag(bfloat16, bfloat16, float_status *status); -bfloat16 bfloat16_minimum_number(bfloat16, bfloat16, float_status *status); -bfloat16 bfloat16_maximum_number(bfloat16, bfloat16, float_status *status); +bfloat16 bfloat16_minmax(bfloat16, bfloat16, float_status *status, int flags); bfloat16 bfloat16_sqrt(bfloat16, float_status *status); FloatRelation bfloat16_compare(bfloat16, bfloat16, float_status *status); FloatRelation bfloat16_compare_quiet(bfloat16, bfloat16, float_status *status); @@ -XXX,XX +XXX,XX @@ float32 float32_exp2(float32, float_status *status); float32 float32_log2(float32, float_status *status); FloatRelation float32_compare(float32, float32, float_status *status); FloatRelation float32_compare_quiet(float32, float32, float_status *status); -float32 float32_min(float32, float32, float_status *status); -float32 float32_max(float32, float32, float_status *status); -float32 float32_minnum(float32, float32, float_status *status); -float32 float32_maxnum(float32, float32, float_status *status); -float32 float32_minnummag(float32, float32, float_status *status); -float32 float32_maxnummag(float32, float32, float_status *status); -float32 float32_minimum_number(float32, float32, float_status *status); -float32 float32_maximum_number(float32, float32, float_status *status); +float32 float32_minmax(float32, float32, float_status *status, int flags); bool float32_is_quiet_nan(float32, float_status *status); bool float32_is_signaling_nan(float32, float_status *status); float32 float32_silence_nan(float32, float_status *status); @@ -XXX,XX +XXX,XX @@ float64 float64_sqrt(float64, float_status *status); float64 float64_log2(float64, float_status *status); FloatRelation float64_compare(float64, float64, float_status *status); FloatRelation float64_compare_quiet(float64, float64, float_status *status); -float64 float64_min(float64, float64, float_status *status); -float64 float64_max(float64, float64, float_status *status); -float64 float64_minnum(float64, float64, float_status *status); -float64 float64_maxnum(float64, float64, float_status *status); -float64 float64_minnummag(float64, float64, float_status *status); -float64 float64_maxnummag(float64, float64, float_status *status); -float64 float64_minimum_number(float64, float64, float_status *status); -float64 float64_maximum_number(float64, float64, float_status *status); +float64 float64_minmax(float64, float64, float_status *status, int flags); bool float64_is_quiet_nan(float64 a, float_status *status); bool float64_is_signaling_nan(float64, float_status *status); float64 float64_silence_nan(float64, float_status *status); @@ -XXX,XX +XXX,XX @@ float128 float128_rem(float128, float128, float_status *status); float128 float128_sqrt(float128, float_status *status); FloatRelation float128_compare(float128, float128, float_status *status); FloatRelation float128_compare_quiet(float128, float128, float_status *status); -float128 float128_min(float128, float128, float_status *status); -float128 float128_max(float128, float128, float_status *status); -float128 float128_minnum(float128, float128, float_status *status); -float128 float128_maxnum(float128, float128, float_status *status); -float128 float128_minnummag(float128, float128, float_status *status); -float128 float128_maxnummag(float128, float128, float_status *status); -float128 float128_minimum_number(float128, float128, float_status *status); -float128 float128_maximum_number(float128, float128, float_status *status); +float128 float128_minmax(float128, float128, float_status *status, int flags); bool float128_is_quiet_nan(float128, float_status *status); bool float128_is_signaling_nan(float128, float_status *status); float128 float128_silence_nan(float128, float_status *status); @@ -XXX,XX +XXX,XX @@ static inline bool float128_unordered_quiet(float128 a, float128 b, *----------------------------------------------------------------------------*/ float128 float128_default_nan(float_status *status); +/*---------------------------------------------------------------------------- +| Minumum and maximum functions. +*----------------------------------------------------------------------------*/ + +#define MINMAX_1(type, name, flags) \ + static inline type type##_##name(type a, type b, float_status *s) \ + { return type##_minmax(a, b, s, flags); } + +#define MINMAX_2(type) \ + MINMAX_1(type, max, 0) \ + MINMAX_1(type, maxnum, float_minmax_isnum) \ + MINMAX_1(type, maxnummag, float_minmax_isnum | float_minmax_ismag) \ + MINMAX_1(type, maximum_number, float_minmax_isnumber) \ + MINMAX_1(type, min, float_minmax_ismin) \ + MINMAX_1(type, minnum, float_minmax_ismin | float_minmax_isnum) \ + MINMAX_1(type, minnummag, \ + float_minmax_ismin | float_minmax_isnum | float_minmax_ismag) \ + MINMAX_1(type, minimum_number, \ + float_minmax_ismin | float_minmax_isnumber) + +MINMAX_2(float16) +MINMAX_2(bfloat16) +MINMAX_2(float32) +MINMAX_2(float64) +MINMAX_2(float128) + +#undef MINMAX_1 +#undef MINMAX_2 + #endif /* SOFTFLOAT_H */ diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ float64_gen2(float64 xa, float64 xb, float_status *s, return soft(ua.s, ub.s, s); } -/* Flags for parts_minmax. */ -enum { - /* Set for minimum; clear for maximum. */ - minmax_ismin = 1, - /* Set for the IEEE 754-2008 minNum() and maxNum() operations. */ - minmax_isnum = 2, - /* Set for the IEEE 754-2008 minNumMag() and minNumMag() operations. */ - minmax_ismag = 4, - /* - * Set for the IEEE 754-2019 minimumNumber() and maximumNumber() - * operations. - */ - minmax_isnumber = 8, -}; - /* Simple helpers for checking if, or what kind of, NaN we have */ static inline __attribute__((unused)) bool is_nan(FloatClass c) { @@ -XXX,XX +XXX,XX @@ float128 uint128_to_float128(Int128 a, float_status *status) * Minimum and maximum */ -static float16 float16_minmax(float16 a, float16 b, float_status *s, int flags) +float16 float16_minmax(float16 a, float16 b, float_status *s, int flags) { FloatParts64 pa = float16_unpack_canonical(a, s); FloatParts64 pb = float16_unpack_canonical(b, s); @@ -XXX,XX +XXX,XX @@ static float16 float16_minmax(float16 a, float16 b, float_status *s, int flags) return float16_round_pack_canonical(pr, s); } -static bfloat16 bfloat16_minmax(bfloat16 a, bfloat16 b, - float_status *s, int flags) +bfloat16 bfloat16_minmax(bfloat16 a, bfloat16 b, float_status *s, int flags) { FloatParts64 pa = bfloat16_unpack_canonical(a, s); FloatParts64 pb = bfloat16_unpack_canonical(b, s); @@ -XXX,XX +XXX,XX @@ static bfloat16 bfloat16_minmax(bfloat16 a, bfloat16 b, return bfloat16_round_pack_canonical(pr, s); } -static float32 float32_minmax(float32 a, float32 b, float_status *s, int flags) +float32 float32_minmax(float32 a, float32 b, float_status *s, int flags) { FloatParts64 pa = float32_unpack_canonical(a, s); FloatParts64 pb = float32_unpack_canonical(b, s); @@ -XXX,XX +XXX,XX @@ static float32 float32_minmax(float32 a, float32 b, float_status *s, int flags) return float32_round_pack_canonical(pr, s); } -static float64 float64_minmax(float64 a, float64 b, float_status *s, int flags) +float64 float64_minmax(float64 a, float64 b, float_status *s, int flags) { FloatParts64 pa = float64_unpack_canonical(a, s); FloatParts64 pb = float64_unpack_canonical(b, s); @@ -XXX,XX +XXX,XX @@ static float64 float64_minmax(float64 a, float64 b, float_status *s, int flags) return float64_round_pack_canonical(pr, s); } -static float128 float128_minmax(float128 a, float128 b, - float_status *s, int flags) +float128 float128_minmax(float128 a, float128 b, float_status *s, int flags) { FloatParts128 pa = float128_unpack_canonical(a, s); FloatParts128 pb = float128_unpack_canonical(b, s); @@ -XXX,XX +XXX,XX @@ static float128 float128_minmax(float128 a, float128 b, return float128_round_pack_canonical(pr, s); } -#define MINMAX_1(type, name, flags) \ - type type##_##name(type a, type b, float_status *s) \ - { return type##_minmax(a, b, s, flags); } - -#define MINMAX_2(type) \ - MINMAX_1(type, max, 0) \ - MINMAX_1(type, maxnum, minmax_isnum) \ - MINMAX_1(type, maxnummag, minmax_isnum | minmax_ismag) \ - MINMAX_1(type, maximum_number, minmax_isnumber) \ - MINMAX_1(type, min, minmax_ismin) \ - MINMAX_1(type, minnum, minmax_ismin | minmax_isnum) \ - MINMAX_1(type, minnummag, minmax_ismin | minmax_isnum | minmax_ismag) \ - MINMAX_1(type, minimum_number, minmax_ismin | minmax_isnumber) \ - -MINMAX_2(float16) -MINMAX_2(bfloat16) -MINMAX_2(float32) -MINMAX_2(float64) -MINMAX_2(float128) - -#undef MINMAX_1 -#undef MINMAX_2 - /* * Floating point compare */ diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b, * if one operand is a QNaN, and the other * operand is numerical, then return numerical argument. */ - if ((flags & (minmax_isnum | minmax_isnumber)) + if ((flags & (float_minmax_isnum | float_minmax_isnumber)) && !(ab_mask & float_cmask_snan) && (ab_mask & ~float_cmask_qnan)) { record_denormals_used(ab_mask, s); @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b, * but unless both operands are NaNs, * the SNaN is otherwise ignored and not converted to a QNaN. */ - if ((flags & minmax_isnumber) + if ((flags & float_minmax_isnumber) && (ab_mask & float_cmask_snan) && (ab_mask & ~float_cmask_anynan)) { float_raise(float_flag_invalid, s); @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b, * Take the sign into account. * For ismag, only do this if the magnitudes are equal. */ - if (!(flags & minmax_ismag) || cmp == 0) { + if (!(flags & float_minmax_ismag) || cmp == 0) { if (a->sign != b->sign) { /* For differing signs, the negative operand is less. */ cmp = a->sign ? -1 : 1; @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b, } } - if (flags & minmax_ismin) { + if (flags & float_minmax_ismin) { cmp = -cmp; } return cmp < 0 ? b : a; -- 2.43.0