:p
atchew
Login
Expose enough softfloat infrastructure so that we can move the s390_divide_to_integer code back into target/s390x/, and to perform the Arm FPDotAdd operation without using either float64 intermediates and round-to-odd. The motivation is the Arm FP8DotAdd operation, which has up to 8 multiplies, 9 additions, and 1 scaling operation before rounding. Rather than export the code as-is, with functions that sometimes (but not always) return a pointer to one of the inputs, and may or may not modify one or all of them as scratch space, return a new structure instead. This turns out to improve code as well, because we compile with -ftrivial-auto-var-init=zero. A pattern such as FloatParts t; foo(&t, ...); will zero t before calling foo, whereas FloatParts t = foo(...); will not. I have not converted everything, only enough to do the testing of the target/ patches at the end. Comments? r~ Richard Henderson (84): fpu: Drop parts_canonicalize fpu: Drop parts_uncanon fpu: Drop parts_uncanon_normal fpu: Drop parts_default_nan fpu: Drop parts_silence_nan fpu: Drop parts_return_nan fpu: Drop parts_pick_nan fpu: Drop parts_pick_nan_muladd fpu: Reverse the order of softfloat-parts* inclusions fpu: Drop parts_{add,sub}_normal fpu: Drop parts_addsub fpu: Drop parts_mul fpu: Drop parts_muladd_scalbn fpu: Drop parts_div fpu: Drop parts_modrem fpu: Drop parts_sqrt fpu: Drop parts_round_to_int_normal fpu: Drop parts_round_to_int fpu: Drop parts_float_to_sint fpu: Drop parts_float_to_uint fpu: Drop parts_float_to_sint_modulo fpu: Drop parts_sint_to_float fpu: Drop parts_uint_to_float fpu: Drop parts_minmax fpu: Drop parts_compare fpu: Drop parts_scalbn fpu: Drop parts_log2 fpu: Drop parts_float_to_float fpu: Drop PARTS_GENERIC_64_128{_256} fpu: Drop FRAC_GENERIC_64_128{_256} fpu: Constify frac{64,128,256}_* inputs fpu: Return structure from unpack_raw64 fpu: Return struct from float4_e2m1_unpack_canonical fpu: Return struct from float8_e4m3_unpack_canonical fpu: Return struct from float8_e5m2_unpack_canonical fpu: Inline float16_unpack_raw into callers fpu: Return struct from float16a_unpack_canonical fpu: Return struct from float16_unpack_canonical fpu: Inline bfloat16_unpack_raw into callers fpu: Return struct from bfloat16_unpack_canonical fpu: Inline float32_unpack_raw into callers fpu: Inline float64_unpack_raw into callers fpu: Return struct from float{32,64}_unpack_canonical fpu: Inline floatx80_unpack_raw into only caller fpu: Return struct from float128_unpack_raw fpu: Return struct from float128_unpack_canonical fpu: Change parts_float_to_float_narrow to parts128_to_parts64 fpu: Change parts_float_to_float_widen to parts64_to_parts128 fpu: Inline float8_e4m3_pack_raw to single caller fpu: Inline float8_e5m2_pack_raw into single caller fpu: Inline float16_pack_raw into callers fpu: Inline bfloat16_pack_raw into callers fpu: Inline float32_pack_raw into callers fpu: Inline float64_pack_raw into callers fpu: Mark unpack_raw64 QEMU_ALWAYS_INLINE fpu: Mark pack_raw64 QEMU_ALWAYS_INLINE fpu: Split FloatParts{64,128} to softfloat-parts.h fpu: Export FloatFmt structures fpu: Export unpack_canonical and round_pack_canonical routines fpu: Return struct from parts{64,128}_default_nan fpu: Return struct from parts{64,128}_silence_nan fpu: Return struct from parts{64,128}_return_nan fpu: Sink exp_bias adjustment in float64r32_pack_raw fpu: Return struct from parts{64,128}_pick_nan fpu: Return struct from parts{64,128}_div fpu: Return struct from parts{64,128}_round_to_int fpu: Use parts64_round_to_int in parts_s390_divide_to_integer fpu: Export default_nan and pick_nan routines fpu: Introduce parts64_round_canonical fpu: Export parts{64,128}_div fpu: Export parts{64,128}_round_to_int fpu: Return struct from parts{64,128}_pick_nan_muladd fpu: Introduce record_denormals_used fpu: Return struct from parts{64,128}_muladd_scalbn fpu: Drop QEMU_FLATTEN from muladd routines fpu: Export parts{64,128}_compare fpu: Return struct from parts{64,128}_mul fpu: Hoist nan check in partsN_addsub fpu: Return struct from parts{64,128}_addsub fpu: Simplify 0 +/- N case in parts_addsub 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 include/fpu/softfloat-parts.h | 223 ++++ include/fpu/softfloat.h | 11 - target/arm/tcg/vec_internal.h | 12 +- fpu/softfloat.c | 2124 +++++++++++------------------- target/arm/tcg/sme_helper.c | 102 +- target/arm/tcg/vec_helper.c | 127 +- target/s390x/tcg/fpu_helper.c | 135 ++ fpu/softfloat-parts-addsub.c.inc | 22 +- fpu/softfloat-parts.c.inc | 723 ++++------ fpu/softfloat-specialize.c.inc | 42 +- 10 files changed, 1529 insertions(+), 1992 deletions(-) create mode 100644 include/fpu/softfloat-parts.h -- 2.43.0
Use the specific parts{64,12}_canonicalize at each site. Drop the forward declarations. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 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 FloatParts128 *parts128_pick_nan_muladd(FloatParts128 *a, #define parts_pick_nan_muladd(A, B, C, S, ABM, ABCM) \ PARTS_GENERIC_64_128(pick_nan_muladd, A)(A, B, C, S, ABM, ABCM) -static void parts64_canonicalize(FloatParts64 *p, float_status *status, - const FloatFmt *fmt); -static void parts128_canonicalize(FloatParts128 *p, float_status *status, - const FloatFmt *fmt); - -#define parts_canonicalize(A, S, F) \ - PARTS_GENERIC_64_128(canonicalize, A)(A, S, F) - static void parts64_uncanon_normal(FloatParts64 *p, float_status *status, const FloatFmt *fmt, bool saturate); static void parts128_uncanon_normal(FloatParts128 *p, float_status *status, @@ -XXX,XX +XXX,XX @@ static void float4_e2m1_unpack_canonical(FloatParts64 *p, float4_e2m1 f, float_status *s) { float4_e2m1_unpack_raw(p, f); - parts_canonicalize(p, s, &float4_e2m1_params); + parts64_canonicalize(p, s, &float4_e2m1_params); } static void float8_e4m3_unpack_canonical(FloatParts64 *p, float8_e4m3 f, float_status *s) { float8_e4m3_unpack_raw(p, f); - parts_canonicalize(p, s, &float8_e4m3_params); + parts64_canonicalize(p, s, &float8_e4m3_params); } static void float8_e5m2_unpack_canonical(FloatParts64 *p, float8_e5m2 f, float_status *s) { float8_e5m2_unpack_raw(p, f); - parts_canonicalize(p, s, &float8_e5m2_params); + parts64_canonicalize(p, s, &float8_e5m2_params); } static void float16a_unpack_canonical(FloatParts64 *p, float16 f, float_status *s, const FloatFmt *params) { float16_unpack_raw(p, f); - parts_canonicalize(p, s, params); + parts64_canonicalize(p, s, params); } static void float16_unpack_canonical(FloatParts64 *p, float16 f, @@ -XXX,XX +XXX,XX @@ static void bfloat16_unpack_canonical(FloatParts64 *p, bfloat16 f, float_status *s) { bfloat16_unpack_raw(p, f); - parts_canonicalize(p, s, &bfloat16_params); + parts64_canonicalize(p, s, &bfloat16_params); } static float8_e4m3 float8_e4m3_round_pack_canonical(FloatParts64 *p, @@ -XXX,XX +XXX,XX @@ static void float32_unpack_canonical(FloatParts64 *p, float32 f, float_status *s) { float32_unpack_raw(p, f); - parts_canonicalize(p, s, &float32_params); + parts64_canonicalize(p, s, &float32_params); } static float32 float32_round_pack_canonical(FloatParts64 *p, @@ -XXX,XX +XXX,XX @@ static void float64_unpack_canonical(FloatParts64 *p, float64 f, float_status *s) { float64_unpack_raw(p, f); - parts_canonicalize(p, s, &float64_params); + parts64_canonicalize(p, s, &float64_params); } static float64 float64_round_pack_canonical(FloatParts64 *p, @@ -XXX,XX +XXX,XX @@ static void float128_unpack_canonical(FloatParts128 *p, float128 f, float_status *s) { float128_unpack_raw(p, f); - parts_canonicalize(p, s, &float128_params); + parts128_canonicalize(p, s, &float128_params); } static float128 float128_round_pack_canonical(FloatParts128 *p, @@ -XXX,XX +XXX,XX @@ static bool floatx80_unpack_canonical(FloatParts128 *p, floatx80 f, floatx80_unpack_raw(p, f); if (likely(p->exp != floatx80_params[floatx80_precision_x].exp_max)) { - parts_canonicalize(p, s, &floatx80_params[floatx80_precision_x]); + parts128_canonicalize(p, s, &floatx80_params[floatx80_precision_x]); } else { /* The explicit integer bit is ignored, after invalid checks. */ p->frac_hi &= MAKE_64BIT_MASK(0, 63); @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, parts_uncanon(r, status, fmt, false); r_flags = status->float_exception_flags; r->frac &= (1ULL << fmt->frac_size) - 1; - parts_canonicalize(r, status, fmt); + parts64_canonicalize(r, status, fmt); /* POp table "Results: DIVIDE TO INTEGER (Part 2 of 2)" */ if (is_q_smallish) { -- 2.43.0
Use parts{64,128}_uncanon at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 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 parts128_uncanon_normal(FloatParts128 *p, float_status *status, #define parts_uncanon_normal(A, S, F, X) \ PARTS_GENERIC_64_128(uncanon_normal, A)(A, S, F, X) -static void parts64_uncanon(FloatParts64 *p, float_status *status, - const FloatFmt *fmt, bool saturate); -static void parts128_uncanon(FloatParts128 *p, float_status *status, - const FloatFmt *fmt, bool saturate); - -#define parts_uncanon(A, S, F, X) \ - PARTS_GENERIC_64_128(uncanon, A)(A, S, F, X) - static void parts64_add_normal(FloatParts64 *a, FloatParts64 *b); static void parts128_add_normal(FloatParts128 *a, FloatParts128 *b); static void parts256_add_normal(FloatParts256 *a, FloatParts256 *b); @@ -XXX,XX +XXX,XX @@ static float8_e4m3 float8_e4m3_round_pack_canonical(FloatParts64 *p, float_status *s, bool saturate) { - parts_uncanon(p, s, &float8_e4m3_params, saturate); + parts64_uncanon(p, s, &float8_e4m3_params, saturate); return float8_e4m3_pack_raw(p); } @@ -XXX,XX +XXX,XX @@ static float8_e5m2 float8_e5m2_round_pack_canonical(FloatParts64 *p, float_status *s, bool saturate) { - parts_uncanon(p, s, &float8_e5m2_params, saturate); + parts64_uncanon(p, s, &float8_e5m2_params, saturate); return float8_e5m2_pack_raw(p); } @@ -XXX,XX +XXX,XX @@ static float16 float16a_round_pack_canonical(FloatParts64 *p, float_status *s, const FloatFmt *params) { - parts_uncanon(p, s, params, false); + parts64_uncanon(p, s, params, false); return float16_pack_raw(p); } @@ -XXX,XX +XXX,XX @@ static float16 float16_round_pack_canonical(FloatParts64 *p, static bfloat16 bfloat16_round_pack_canonical(FloatParts64 *p, float_status *s) { - parts_uncanon(p, s, &bfloat16_params, false); + parts64_uncanon(p, s, &bfloat16_params, false); return bfloat16_pack_raw(p); } @@ -XXX,XX +XXX,XX @@ static void float32_unpack_canonical(FloatParts64 *p, float32 f, static float32 float32_round_pack_canonical(FloatParts64 *p, float_status *s) { - parts_uncanon(p, s, &float32_params, false); + parts64_uncanon(p, s, &float32_params, false); return float32_pack_raw(p); } @@ -XXX,XX +XXX,XX @@ static void float64_unpack_canonical(FloatParts64 *p, float64 f, static float64 float64_round_pack_canonical(FloatParts64 *p, float_status *s) { - parts_uncanon(p, s, &float64_params, false); + parts64_uncanon(p, s, &float64_params, false); return float64_pack_raw(p); } static float64 float64r32_pack_raw(FloatParts64 *p) { /* - * In parts_uncanon, we placed the fraction for float32 at the lsb. + * In parts64_uncanon, we placed the fraction for float32 at the lsb. * We need to adjust the fraction higher so that the least N bits are * zero, and the fraction is adjacent to the float64 implicit bit. */ @@ -XXX,XX +XXX,XX @@ static float64 float64r32_pack_raw(FloatParts64 *p) static float64 float64r32_round_pack_canonical(FloatParts64 *p, float_status *s) { - parts_uncanon(p, s, &float32_params, false); + parts64_uncanon(p, s, &float32_params, false); return float64r32_pack_raw(p); } @@ -XXX,XX +XXX,XX @@ static void float128_unpack_canonical(FloatParts128 *p, float128 f, static float128 float128_round_pack_canonical(FloatParts128 *p, float_status *s) { - parts_uncanon(p, s, &float128_params, false); + parts128_uncanon(p, s, &float128_params, false); return float128_pack_raw(p); } @@ -XXX,XX +XXX,XX @@ static floatx80 floatx80_round_pack_canonical(FloatParts128 *p, case float_class_normal: case float_class_denormal: if (s->floatx80_rounding_precision == floatx80_precision_x) { - parts_uncanon_normal(p, s, fmt, false); + parts128_uncanon_normal(p, s, fmt, false); frac = p->frac_hi; exp = p->exp; } else { @@ -XXX,XX +XXX,XX @@ static floatx80 floatx80_round_pack_canonical(FloatParts128 *p, p64.sign = p->sign; p64.exp = p->exp; frac_truncjam(&p64, p); - parts_uncanon_normal(&p64, s, fmt, false); + parts64_uncanon_normal(&p64, s, fmt, false); frac = p64.frac; exp = p64.exp; } @@ -XXX,XX +XXX,XX @@ float16_muladd_scalbn(float16 a, float16 b, float16 c, pr = parts_muladd_scalbn(&pa, &pb, &pc, scale, flags, status); /* Round before applying negate result. */ - parts_uncanon(pr, status, &float16_params, false); + parts64_uncanon(pr, status, &float16_params, false); if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { pr->sign ^= 1; } @@ -XXX,XX +XXX,XX @@ float32_muladd_scalbn(float32 a, float32 b, float32 c, pr = parts_muladd_scalbn(&pa, &pb, &pc, scale, flags, status); /* Round before applying negate result. */ - parts_uncanon(pr, status, &float32_params, false); + parts64_uncanon(pr, status, &float32_params, false); if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { pr->sign ^= 1; } @@ -XXX,XX +XXX,XX @@ float64_muladd_scalbn(float64 a, float64 b, float64 c, pr = parts_muladd_scalbn(&pa, &pb, &pc, scale, flags, status); /* Round before applying negate result. */ - parts_uncanon(pr, status, &float64_params, false); + parts64_uncanon(pr, status, &float64_params, false); if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { pr->sign ^= 1; } @@ -XXX,XX +XXX,XX @@ float64 float64r32_muladd(float64 a, float64 b, float64 c, pr = parts_muladd_scalbn(&pa, &pb, &pc, 0, flags, status); /* Round before applying negate result. */ - parts_uncanon(pr, status, &float32_params, false); + parts64_uncanon(pr, status, &float32_params, false); if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { pr->sign ^= 1; } @@ -XXX,XX +XXX,XX @@ bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, pr = parts_muladd_scalbn(&pa, &pb, &pc, 0, flags, status); /* Round before applying negate result. */ - parts_uncanon(pr, status, &bfloat16_params, false); + parts64_uncanon(pr, status, &bfloat16_params, false); if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { pr->sign ^= 1; } @@ -XXX,XX +XXX,XX @@ float128 QEMU_FLATTEN float128_muladd(float128 a, float128 b, float128 c, pr = parts_muladd_scalbn(&pa, &pb, &pc, 0, flags, status); /* Round before applying negate result. */ - parts_uncanon(pr, status, &float128_params, false); + parts128_uncanon(pr, status, &float128_params, false); if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { pr->sign ^= 1; } @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, /* Round remainder to the target format */ *r = *r_precise; status->float_exception_flags = 0; - parts_uncanon(r, status, fmt, false); + parts64_uncanon(r, status, fmt, false); r_flags = status->float_exception_flags; r->frac &= (1ULL << fmt->frac_size) - 1; parts64_canonicalize(r, status, fmt); -- 2.43.0
Use partsN(uncanon_normal) and the single call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 8 -------- fpu/softfloat-parts.c.inc | 2 +- 2 files changed, 1 insertion(+), 9 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 FloatParts128 *parts128_pick_nan_muladd(FloatParts128 *a, #define parts_pick_nan_muladd(A, B, C, S, ABM, ABCM) \ PARTS_GENERIC_64_128(pick_nan_muladd, A)(A, B, C, S, ABM, ABCM) -static void parts64_uncanon_normal(FloatParts64 *p, float_status *status, - const FloatFmt *fmt, bool saturate); -static void parts128_uncanon_normal(FloatParts128 *p, float_status *status, - const FloatFmt *fmt, bool saturate); - -#define parts_uncanon_normal(A, S, F, X) \ - PARTS_GENERIC_64_128(uncanon_normal, A)(A, S, F, X) - static void parts64_add_normal(FloatParts64 *a, FloatParts64 *b); static void parts128_add_normal(FloatParts128 *a, FloatParts128 *b); static void parts256_add_normal(FloatParts256 *a, FloatParts256 *b); 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)(FloatPartsN *p, float_status *s, const FloatFmt *fmt, bool saturate) { if (likely(is_anynorm(p->cls))) { - parts_uncanon_normal(p, s, fmt, saturate); + partsN(uncanon_normal)(p, s, fmt, saturate); } else { switch (p->cls) { case float_class_zero: -- 2.43.0
Use parts{64,128}_default_nan at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 23 +++++++++++------------ fpu/softfloat-parts.c.inc | 24 ++++++++++++------------ 2 files changed, 23 insertions(+), 24 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -#define parts_default_nan(P, S) PARTS_GENERIC_64_128(default_nan, P)(P, S) #define parts_silence_nan(P, S) PARTS_GENERIC_64_128(silence_nan, P)(P, S) static void parts64_return_nan(FloatParts64 *a, float_status *s); @@ -XXX,XX +XXX,XX @@ float32 floatx80_to_float32(floatx80 a, float_status *s) if (floatx80_unpack_canonical(&p128, a, s)) { parts_float_to_float_narrow(&p64, &p128, s); } else { - parts_default_nan(&p64, s); + parts64_default_nan(&p64, s); } return float32_round_pack_canonical(&p64, s); } @@ -XXX,XX +XXX,XX @@ float64 floatx80_to_float64(floatx80 a, float_status *s) if (floatx80_unpack_canonical(&p128, a, s)) { parts_float_to_float_narrow(&p64, &p128, s); } else { - parts_default_nan(&p64, s); + parts64_default_nan(&p64, s); } return float64_round_pack_canonical(&p64, s); } @@ -XXX,XX +XXX,XX @@ float128 floatx80_to_float128(floatx80 a, float_status *s) if (floatx80_unpack_canonical(&p, a, s)) { parts_float_to_float(&p, s); } else { - parts_default_nan(&p, s); + parts128_default_nan(&p, s); } return float128_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ static int32_t floatx80_to_int32_scalbn(floatx80 a, FloatRoundMode rmode, FloatParts128 p; if (!floatx80_unpack_canonical(&p, a, s)) { - parts_default_nan(&p, s); + parts128_default_nan(&p, s); } return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); } @@ -XXX,XX +XXX,XX @@ static int64_t floatx80_to_int64_scalbn(floatx80 a, FloatRoundMode rmode, FloatParts128 p; if (!floatx80_unpack_canonical(&p, a, s)) { - parts_default_nan(&p, s); + parts128_default_nan(&p, s); } return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } @@ -XXX,XX +XXX,XX @@ float16 float16_default_nan(float_status *status) { FloatParts64 p; - parts_default_nan(&p, status); + parts64_default_nan(&p, status); p.frac >>= float16_params.frac_shift; return float16_pack_raw(&p); } @@ -XXX,XX +XXX,XX @@ float32 float32_default_nan(float_status *status) { FloatParts64 p; - parts_default_nan(&p, status); + parts64_default_nan(&p, status); p.frac >>= float32_params.frac_shift; return float32_pack_raw(&p); } @@ -XXX,XX +XXX,XX @@ float64 float64_default_nan(float_status *status) { FloatParts64 p; - parts_default_nan(&p, status); + parts64_default_nan(&p, status); p.frac >>= float64_params.frac_shift; return float64_pack_raw(&p); } @@ -XXX,XX +XXX,XX @@ float128 float128_default_nan(float_status *status) { FloatParts128 p; - parts_default_nan(&p, status); + parts128_default_nan(&p, status); frac_shr(&p, float128_params.frac_shift); return float128_pack_raw(&p); } @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_default_nan(float_status *status) { FloatParts64 p; - parts_default_nan(&p, status); + parts64_default_nan(&p, status); p.frac >>= bfloat16_params.frac_shift; return bfloat16_pack_raw(&p); } @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, *n = *r; *cc = 1; } else if (a->cls == float_class_inf || b->cls == float_class_zero) { - parts_default_nan(r, status); + parts64_default_nan(r, status); *n = *r; *cc = 1; status->float_exception_flags |= float_flag_invalid; 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(return_nan)(FloatPartsN *a, float_status *s) case float_class_snan: float_raise(float_flag_invalid | float_flag_invalid_snan, s); if (s->default_nan_mode) { - parts_default_nan(a, s); + partsN(default_nan)(a, s); } else { parts_silence_nan(a, s); } break; case float_class_qnan: if (s->default_nan_mode) { - parts_default_nan(a, s); + partsN(default_nan)(a, s); } break; default: @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, } if (s->default_nan_mode) { - parts_default_nan(a, s); + partsN(default_nan)(a, s); return a; } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, return ret; default_nan: - parts_default_nan(a, s); + partsN(default_nan)(a, s); return a; } @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_e4m3_overflow)(FloatPartsN *p, float_status *s, p->exp = fmt->exp_max; p->frac_hi = E4M3_NORMAL_FRAC_MAX; } else { - parts_default_nan(p, s); + partsN(default_nan)(p, s); } } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b, } /* Inf - Inf */ float_raise(float_flag_invalid | float_flag_invalid_isi, s); - parts_default_nan(a, s); + partsN(default_nan)(a, s); return a; } } else { @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(mul)(FloatPartsN *a, FloatPartsN *b, /* Inf * Zero == NaN */ if (unlikely(ab_mask == float_cmask_infzero)) { float_raise(float_flag_invalid | float_flag_invalid_imz, s); - parts_default_nan(a, s); + partsN(default_nan)(a, s); return a; } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd_scalbn)(FloatPartsN *a, FloatPartsN *b, goto finish_sign; d_nan: - parts_default_nan(a, s); + partsN(default_nan)(a, s); return a; } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(div)(FloatPartsN *a, FloatPartsN *b, return a; d_nan: - parts_default_nan(a, s); + partsN(default_nan)(a, s); return a; } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(modrem)(FloatPartsN *a, FloatPartsN *b, /* Inf % N; N % 0 */ if (a->cls == float_class_inf || b->cls == float_class_zero) { float_raise(float_flag_invalid, s); - parts_default_nan(a, s); + partsN(default_nan)(a, s); return a; } @@ -XXX,XX +XXX,XX @@ static void partsN(sqrt)(FloatPartsN *a, float_status *status, d_nan: float_raise(float_flag_invalid | float_flag_invalid_sqrt, status); - parts_default_nan(a, status); + partsN(default_nan)(a, status); } /* @@ -XXX,XX +XXX,XX @@ static void partsN(log2)(FloatPartsN *a, float_status *s, const FloatFmt *fmt) d_nan: float_raise(float_flag_invalid, s); - parts_default_nan(a, s); + partsN(default_nan)(a, s); } -- 2.43.0
Use parts{64,128}_silence_nan at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 12 +++++------- fpu/softfloat-parts.c.inc | 6 +++--- 2 files changed, 8 insertions(+), 10 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -#define parts_silence_nan(P, S) PARTS_GENERIC_64_128(silence_nan, P)(P, S) - static void parts64_return_nan(FloatParts64 *a, float_status *s); static void parts128_return_nan(FloatParts128 *a, float_status *s); @@ -XXX,XX +XXX,XX @@ float16 float16_silence_nan(float16 a, float_status *status) float16_unpack_raw(&p, a); p.frac <<= float16_params.frac_shift; - parts_silence_nan(&p, status); + parts64_silence_nan(&p, status); p.frac >>= float16_params.frac_shift; return float16_pack_raw(&p); } @@ -XXX,XX +XXX,XX @@ float32 float32_silence_nan(float32 a, float_status *status) float32_unpack_raw(&p, a); p.frac <<= float32_params.frac_shift; - parts_silence_nan(&p, status); + parts64_silence_nan(&p, status); p.frac >>= float32_params.frac_shift; return float32_pack_raw(&p); } @@ -XXX,XX +XXX,XX @@ float64 float64_silence_nan(float64 a, float_status *status) float64_unpack_raw(&p, a); p.frac <<= float64_params.frac_shift; - parts_silence_nan(&p, status); + parts64_silence_nan(&p, status); p.frac >>= float64_params.frac_shift; return float64_pack_raw(&p); } @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_silence_nan(bfloat16 a, float_status *status) bfloat16_unpack_raw(&p, a); p.frac <<= bfloat16_params.frac_shift; - parts_silence_nan(&p, status); + parts64_silence_nan(&p, status); p.frac >>= bfloat16_params.frac_shift; return bfloat16_pack_raw(&p); } @@ -XXX,XX +XXX,XX @@ float128 float128_silence_nan(float128 a, float_status *status) float128_unpack_raw(&p, a); frac_shl(&p, float128_params.frac_shift); - parts_silence_nan(&p, status); + parts128_silence_nan(&p, status); frac_shr(&p, float128_params.frac_shift); return float128_pack_raw(&p); } 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(return_nan)(FloatPartsN *a, float_status *s) if (s->default_nan_mode) { partsN(default_nan)(a, s); } else { - parts_silence_nan(a, s); + partsN(silence_nan)(a, s); } break; case float_class_qnan: @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, } if (is_snan(ret->cls)) { - parts_silence_nan(ret, s); + partsN(silence_nan)(ret, s); } return ret; } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, } if (is_snan(ret->cls)) { - parts_silence_nan(ret, s); + partsN(silence_nan)(ret, s); } return ret; -- 2.43.0
Use parts{64,128}_return_nan at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 17 ++++++----------- fpu/softfloat-parts.c.inc | 8 ++++---- 2 files changed, 10 insertions(+), 15 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static void parts64_return_nan(FloatParts64 *a, float_status *s); -static void parts128_return_nan(FloatParts128 *a, float_status *s); - -#define parts_return_nan(P, S) PARTS_GENERIC_64_128(return_nan, P)(P, S) - static FloatParts64 *parts64_pick_nan(FloatParts64 *a, FloatParts64 *b, float_status *s); static FloatParts128 *parts128_pick_nan(FloatParts128 *a, FloatParts128 *b, @@ -XXX,XX +XXX,XX @@ static void parts_float_to_e5m2(FloatParts64 *a, float_status *s, bool saturate) switch (a->cls) { case float_class_snan: case float_class_qnan: - parts_return_nan(a, s); + parts64_return_nan(a, s); break; case float_class_inf: @@ -XXX,XX +XXX,XX @@ static void parts_float_to_e5m2(FloatParts64 *a, float_status *s, bool saturate) static void parts64_float_to_float(FloatParts64 *a, float_status *s) { if (is_nan(a->cls)) { - parts_return_nan(a, s); + parts64_return_nan(a, s); } if (a->cls == float_class_denormal) { float_raise(float_flag_input_denormal_used, s); @@ -XXX,XX +XXX,XX @@ static void parts64_float_to_float(FloatParts64 *a, float_status *s) static void parts128_float_to_float(FloatParts128 *a, float_status *s) { if (is_nan(a->cls)) { - parts_return_nan(a, s); + parts128_return_nan(a, s); } if (a->cls == float_class_denormal) { float_raise(float_flag_input_denormal_used, s); @@ -XXX,XX +XXX,XX @@ static void parts_float_to_float_narrow(FloatParts64 *a, FloatParts128 *b, case float_class_qnan: /* Discard the low bits of the NaN. */ a->frac = b->frac_hi; - parts_return_nan(a, s); + parts64_return_nan(a, s); break; default: break; @@ -XXX,XX +XXX,XX @@ static void parts_float_to_float_widen(FloatParts128 *a, FloatParts64 *b, frac_widen(a, b); if (is_nan(a->cls)) { - parts_return_nan(a, s); + parts128_return_nan(a, s); } if (a->cls == float_class_denormal) { float_raise(float_flag_input_denormal_used, s); @@ -XXX,XX +XXX,XX @@ float32 float32_exp2(float32 a, float_status *status) break; case float_class_snan: case float_class_qnan: - parts_return_nan(&xp, status); + parts64_return_nan(&xp, status); return float32_round_pack_canonical(&xp, status); case float_class_inf: return xp.sign ? float32_zero : a; 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(sqrt)(FloatPartsN *a, float_status *status, break; case float_class_snan: case float_class_qnan: - parts_return_nan(a, status); + partsN(return_nan)(a, status); return; case float_class_zero: return; @@ -XXX,XX +XXX,XX @@ static void partsN(round_to_int)(FloatPartsN *a, FloatRoundMode rmode, switch (a->cls) { case float_class_qnan: case float_class_snan: - parts_return_nan(a, s); + partsN(return_nan)(a, s); break; case float_class_zero: case float_class_inf: @@ -XXX,XX +XXX,XX @@ static void partsN(scalbn)(FloatPartsN *a, int n, float_status *s) switch (a->cls) { case float_class_snan: case float_class_qnan: - parts_return_nan(a, s); + partsN(return_nan)(a, s); break; case float_class_zero: case float_class_inf: @@ -XXX,XX +XXX,XX @@ static void partsN(log2)(FloatPartsN *a, float_status *s, const FloatFmt *fmt) break; case float_class_snan: case float_class_qnan: - parts_return_nan(a, s); + partsN(return_nan)(a, s); return; case float_class_zero: float_raise(float_flag_divbyzero, s); -- 2.43.0
Use parts{64,128}_pick_nan at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 11 ++--------- fpu/softfloat-parts.c.inc | 10 +++++----- 2 files changed, 7 insertions(+), 14 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static FloatParts64 *parts64_pick_nan(FloatParts64 *a, FloatParts64 *b, - float_status *s); -static FloatParts128 *parts128_pick_nan(FloatParts128 *a, FloatParts128 *b, - float_status *s); - -#define parts_pick_nan(A, B, S) PARTS_GENERIC_64_128(pick_nan, A)(A, B, S) - static FloatParts64 *parts64_pick_nan_muladd(FloatParts64 *a, FloatParts64 *b, FloatParts64 *c, float_status *s, int ab_mask, int abc_mask); @@ -XXX,XX +XXX,XX @@ floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status) return floatx80_default_nan(status); } - pr = parts_pick_nan(&pa, &pb, status); + pr = parts128_pick_nan(&pa, &pb, status); return floatx80_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, { /* POp table "Results: DIVIDE TO INTEGER (Part 1 of 2)" */ if ((float_cmask(a->cls) | float_cmask(b->cls)) & float_cmask_anynan) { - *r = *parts_pick_nan(a, b, status); + *r = *parts64_pick_nan(a, b, status); *n = *r; *cc = 1; } else if (a->cls == float_class_inf || b->cls == float_class_zero) { 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(addsub)(FloatPartsN *a, FloatPartsN *b, return b; p_nan: - return parts_pick_nan(a, b, s); + return partsN(pick_nan)(a, b, s); } /* @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(mul)(FloatPartsN *a, FloatPartsN *b, } if (unlikely(ab_mask & float_cmask_anynan)) { - return parts_pick_nan(a, b, s); + return partsN(pick_nan)(a, b, s); } /* Multiply by 0 or Inf */ @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(div)(FloatPartsN *a, FloatPartsN *b, /* All the NaN cases */ if (unlikely(ab_mask & float_cmask_anynan)) { - return parts_pick_nan(a, b, s); + return partsN(pick_nan)(a, b, s); } if ((ab_mask & float_cmask_denormal) && b->cls != float_class_zero) { @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(modrem)(FloatPartsN *a, FloatPartsN *b, /* All the NaN cases */ if (unlikely(ab_mask & float_cmask_anynan)) { - return parts_pick_nan(a, b, s); + return partsN(pick_nan)(a, b, s); } /* Inf % N; N % 0 */ @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b, return is_nan(a->cls) ? b : a; } - return parts_pick_nan(a, b, s); + return partsN(pick_nan)(a, b, s); } if (ab_mask & float_cmask_denormal) { -- 2.43.0
Use partsN() at the only call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 12 ------------ fpu/softfloat-parts.c.inc | 2 +- 2 files changed, 1 insertion(+), 13 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static FloatParts64 *parts64_pick_nan_muladd(FloatParts64 *a, FloatParts64 *b, - FloatParts64 *c, float_status *s, - int ab_mask, int abc_mask); -static FloatParts128 *parts128_pick_nan_muladd(FloatParts128 *a, - FloatParts128 *b, - FloatParts128 *c, - float_status *s, - int ab_mask, int abc_mask); - -#define parts_pick_nan_muladd(A, B, C, S, ABM, ABCM) \ - PARTS_GENERIC_64_128(pick_nan_muladd, A)(A, B, C, S, ABM, ABCM) - static void parts64_add_normal(FloatParts64 *a, FloatParts64 *b); static void parts128_add_normal(FloatParts128 *a, FloatParts128 *b); static void parts256_add_normal(FloatParts256 *a, FloatParts256 *b); 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_scalbn)(FloatPartsN *a, FloatPartsN *b, * off to the target-specific pick-a-NaN routine. */ if (unlikely(abc_mask & float_cmask_anynan)) { - return parts_pick_nan_muladd(a, b, c, s, ab_mask, abc_mask); + return partsN(pick_nan_muladd)(a, b, c, s, ab_mask, abc_mask); } if (flags & float_muladd_negate_c) { -- 2.43.0
Define the widest addition primitives first, so that they're already defined before being used by the narrower muladd primitive. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 9 ++++----- 1 file changed, 4 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 @@ static const uint16_t rsqrt_tab[128] = { #define FloatPartsN glue(FloatParts,N) #define FloatPartsW glue(FloatParts,W) -#define N 64 -#define W 128 +#define N 256 #include "softfloat-parts-addsub.c.inc" -#include "softfloat-parts.c.inc" #undef N -#undef W #define N 128 #define W 256 @@ -XXX,XX +XXX,XX @@ static const uint16_t rsqrt_tab[128] = { #undef N #undef W -#define N 256 +#define N 64 +#define W 128 #include "softfloat-parts-addsub.c.inc" +#include "softfloat-parts.c.inc" #undef N #undef W -- 2.43.0
Drop the forward declarations and the _Generic macros. Add partsW() for use by muladd_scalbn. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 16 ++-------------- fpu/softfloat-parts.c.inc | 12 ++++++------ 2 files changed, 8 insertions(+), 20 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static void parts64_add_normal(FloatParts64 *a, FloatParts64 *b); -static void parts128_add_normal(FloatParts128 *a, FloatParts128 *b); -static void parts256_add_normal(FloatParts256 *a, FloatParts256 *b); - -#define parts_add_normal(A, B) \ - PARTS_GENERIC_64_128_256(add_normal, A)(A, B) - -static bool parts64_sub_normal(FloatParts64 *a, FloatParts64 *b); -static bool parts128_sub_normal(FloatParts128 *a, FloatParts128 *b); -static bool parts256_sub_normal(FloatParts256 *a, FloatParts256 *b); - -#define parts_sub_normal(A, B) \ - PARTS_GENERIC_64_128_256(sub_normal, A)(A, B) - static FloatParts64 *parts64_addsub(FloatParts64 *a, FloatParts64 *b, float_status *s, bool subtract); static FloatParts128 *parts128_addsub(FloatParts128 *a, FloatParts128 *b, @@ -XXX,XX +XXX,XX @@ static const uint16_t rsqrt_tab[128] = { }; #define partsN(NAME) glue(glue(glue(parts,N),_),NAME) +#define partsW(NAME) glue(glue(glue(parts,W),_),NAME) #define FloatPartsN glue(FloatParts,N) #define FloatPartsW glue(FloatParts,W) @@ -XXX,XX +XXX,XX @@ static const uint16_t rsqrt_tab[128] = { #undef N #undef W #undef partsN +#undef partsW #undef FloatPartsN #undef FloatPartsW 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(addsub)(FloatPartsN *a, FloatPartsN *b, if (a->sign != b_sign) { /* Subtraction */ if (likely(cmask_is_only_normals(ab_mask))) { - if (parts_sub_normal(a, b)) { + if (partsN(sub_normal)(a, b)) { return a; } /* Subtract was exact, fall through to set sign. */ @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b, } else { /* Addition */ if (likely(cmask_is_only_normals(ab_mask))) { - parts_add_normal(a, b); + partsN(add_normal)(a, b); return a; } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd_scalbn)(FloatPartsN *a, FloatPartsN *b, c_widen.exp = c->exp; if (a->sign == c->sign) { - parts_add_normal(&p_widen, &c_widen); - } else if (!parts_sub_normal(&p_widen, &c_widen)) { + partsW(add_normal)(&p_widen, &c_widen); + } else if (!partsW(sub_normal)(&p_widen, &c_widen)) { goto return_sub_zero; } } @@ -XXX,XX +XXX,XX @@ static void partsN(log2)(FloatPartsN *a, float_status *s, const FloatFmt *fmt) f.exp = f_exp - frac_normalize(&f); if (a_exp < 0) { - parts_sub_normal(a, &f); + partsN(sub_normal)(a, &f); } else if (a_exp > 0) { - parts_add_normal(a, &f); + partsN(add_normal)(a, &f); } else { *a = f; } -- 2.43.0
Use parts{64,128}_addsub at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static FloatParts64 *parts64_addsub(FloatParts64 *a, FloatParts64 *b, - float_status *s, bool subtract); -static FloatParts128 *parts128_addsub(FloatParts128 *a, FloatParts128 *b, - float_status *s, bool subtract); - -#define parts_addsub(A, B, S, Z) \ - PARTS_GENERIC_64_128(addsub, A)(A, B, S, Z) - static FloatParts64 *parts64_mul(FloatParts64 *a, FloatParts64 *b, float_status *s); static FloatParts128 *parts128_mul(FloatParts128 *a, FloatParts128 *b, @@ -XXX,XX +XXX,XX @@ float16_addsub(float16 a, float16 b, float_status *status, bool subtract) float16_unpack_canonical(&pa, a, status); float16_unpack_canonical(&pb, b, status); - pr = parts_addsub(&pa, &pb, status, subtract); + pr = parts64_addsub(&pa, &pb, status, subtract); return float16_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ soft_f32_addsub(float32 a, float32 b, float_status *status, bool subtract) float32_unpack_canonical(&pa, a, status); float32_unpack_canonical(&pb, b, status); - pr = parts_addsub(&pa, &pb, status, subtract); + pr = parts64_addsub(&pa, &pb, status, subtract); return float32_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ soft_f64_addsub(float64 a, float64 b, float_status *status, bool subtract) float64_unpack_canonical(&pa, a, status); float64_unpack_canonical(&pb, b, status); - pr = parts_addsub(&pa, &pb, status, subtract); + pr = parts64_addsub(&pa, &pb, status, subtract); return float64_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ static float64 float64r32_addsub(float64 a, float64 b, float_status *status, float64_unpack_canonical(&pa, a, status); float64_unpack_canonical(&pb, b, status); - pr = parts_addsub(&pa, &pb, status, subtract); + pr = parts64_addsub(&pa, &pb, status, subtract); return float64r32_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ bfloat16_addsub(bfloat16 a, bfloat16 b, float_status *status, bool subtract) bfloat16_unpack_canonical(&pa, a, status); bfloat16_unpack_canonical(&pb, b, status); - pr = parts_addsub(&pa, &pb, status, subtract); + pr = parts64_addsub(&pa, &pb, status, subtract); return bfloat16_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float128_addsub(float128 a, float128 b, float_status *status, bool subtract) float128_unpack_canonical(&pa, a, status); float128_unpack_canonical(&pb, b, status); - pr = parts_addsub(&pa, &pb, status, subtract); + pr = parts128_addsub(&pa, &pb, status, subtract); return float128_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ floatx80_addsub(floatx80 a, floatx80 b, float_status *status, bool subtract) return floatx80_default_nan(status); } - pr = parts_addsub(&pa, &pb, status, subtract); + pr = parts128_addsub(&pa, &pb, status, subtract); return floatx80_round_pack_canonical(pr, status); } -- 2.43.0
Use parts{64,128}_mul at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static FloatParts64 *parts64_mul(FloatParts64 *a, FloatParts64 *b, - float_status *s); -static FloatParts128 *parts128_mul(FloatParts128 *a, FloatParts128 *b, - float_status *s); - -#define parts_mul(A, B, S) \ - PARTS_GENERIC_64_128(mul, A)(A, B, S) - static FloatParts64 *parts64_muladd_scalbn(FloatParts64 *a, FloatParts64 *b, FloatParts64 *c, int scale, int flags, float_status *s); @@ -XXX,XX +XXX,XX @@ float16 QEMU_FLATTEN float16_mul(float16 a, float16 b, float_status *status) float16_unpack_canonical(&pa, a, status); float16_unpack_canonical(&pb, b, status); - pr = parts_mul(&pa, &pb, status); + pr = parts64_mul(&pa, &pb, status); return float16_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ soft_f32_mul(float32 a, float32 b, float_status *status) float32_unpack_canonical(&pa, a, status); float32_unpack_canonical(&pb, b, status); - pr = parts_mul(&pa, &pb, status); + pr = parts64_mul(&pa, &pb, status); return float32_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ soft_f64_mul(float64 a, float64 b, float_status *status) float64_unpack_canonical(&pa, a, status); float64_unpack_canonical(&pb, b, status); - pr = parts_mul(&pa, &pb, status); + pr = parts64_mul(&pa, &pb, status); return float64_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float64 float64r32_mul(float64 a, float64 b, float_status *status) float64_unpack_canonical(&pa, a, status); float64_unpack_canonical(&pb, b, status); - pr = parts_mul(&pa, &pb, status); + pr = parts64_mul(&pa, &pb, status); return float64r32_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ bfloat16_mul(bfloat16 a, bfloat16 b, float_status *status) bfloat16_unpack_canonical(&pa, a, status); bfloat16_unpack_canonical(&pb, b, status); - pr = parts_mul(&pa, &pb, status); + pr = parts64_mul(&pa, &pb, status); return bfloat16_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float128_mul(float128 a, float128 b, float_status *status) float128_unpack_canonical(&pa, a, status); float128_unpack_canonical(&pb, b, status); - pr = parts_mul(&pa, &pb, status); + pr = parts128_mul(&pa, &pb, status); return float128_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ floatx80_mul(floatx80 a, floatx80 b, float_status *status) return floatx80_default_nan(status); } - pr = parts_mul(&pa, &pb, status); + pr = parts128_mul(&pa, &pb, status); return floatx80_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float32 float32_exp2(float32 a, float_status *status) float_raise(float_flag_inexact, status); float64_unpack_canonical(&tp, float64_ln2, status); - xp = *parts_mul(&xp, &tp, status); + xp = *parts64_mul(&xp, &tp, status); xnp = xp; float64_unpack_canonical(&rp, float64_one, status); @@ -XXX,XX +XXX,XX @@ float32 float32_exp2(float32 a, float_status *status) float64_unpack_canonical(&tp, float32_exp2_coefficients[i], status); rp = *parts_muladd_scalbn(&tp, &xnp, &rp, 0, 0, status); - xnp = *parts_mul(&xnp, &xp, status); + xnp = *parts64_mul(&xnp, &xp, status); } return float32_round_pack_canonical(&rp, status); -- 2.43.0
Use parts{64,128}_muladd_scalbn at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static FloatParts64 *parts64_muladd_scalbn(FloatParts64 *a, FloatParts64 *b, - FloatParts64 *c, int scale, - int flags, float_status *s); -static FloatParts128 *parts128_muladd_scalbn(FloatParts128 *a, FloatParts128 *b, - FloatParts128 *c, int scale, - int flags, float_status *s); - -#define parts_muladd_scalbn(A, B, C, Z, Y, S) \ - PARTS_GENERIC_64_128(muladd_scalbn, A)(A, B, C, Z, Y, S) - static FloatParts64 *parts64_div(FloatParts64 *a, FloatParts64 *b, float_status *s); static FloatParts128 *parts128_div(FloatParts128 *a, FloatParts128 *b, @@ -XXX,XX +XXX,XX @@ float16_muladd_scalbn(float16 a, float16 b, float16 c, float16_unpack_canonical(&pa, a, status); float16_unpack_canonical(&pb, b, status); float16_unpack_canonical(&pc, c, status); - pr = parts_muladd_scalbn(&pa, &pb, &pc, scale, flags, status); + pr = parts64_muladd_scalbn(&pa, &pb, &pc, scale, flags, status); /* Round before applying negate result. */ parts64_uncanon(pr, status, &float16_params, false); @@ -XXX,XX +XXX,XX @@ float32_muladd_scalbn(float32 a, float32 b, float32 c, float32_unpack_canonical(&pa, a, status); float32_unpack_canonical(&pb, b, status); float32_unpack_canonical(&pc, c, status); - pr = parts_muladd_scalbn(&pa, &pb, &pc, scale, flags, status); + pr = parts64_muladd_scalbn(&pa, &pb, &pc, scale, flags, status); /* Round before applying negate result. */ parts64_uncanon(pr, status, &float32_params, false); @@ -XXX,XX +XXX,XX @@ float64_muladd_scalbn(float64 a, float64 b, float64 c, float64_unpack_canonical(&pa, a, status); float64_unpack_canonical(&pb, b, status); float64_unpack_canonical(&pc, c, status); - pr = parts_muladd_scalbn(&pa, &pb, &pc, scale, flags, status); + pr = parts64_muladd_scalbn(&pa, &pb, &pc, scale, flags, status); /* Round before applying negate result. */ parts64_uncanon(pr, status, &float64_params, false); @@ -XXX,XX +XXX,XX @@ float64 float64r32_muladd(float64 a, float64 b, float64 c, float64_unpack_canonical(&pa, a, status); float64_unpack_canonical(&pb, b, status); float64_unpack_canonical(&pc, c, status); - pr = parts_muladd_scalbn(&pa, &pb, &pc, 0, flags, status); + pr = parts64_muladd_scalbn(&pa, &pb, &pc, 0, flags, status); /* Round before applying negate result. */ parts64_uncanon(pr, status, &float32_params, false); @@ -XXX,XX +XXX,XX @@ bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, bfloat16_unpack_canonical(&pa, a, status); bfloat16_unpack_canonical(&pb, b, status); bfloat16_unpack_canonical(&pc, c, status); - pr = parts_muladd_scalbn(&pa, &pb, &pc, 0, flags, status); + pr = parts64_muladd_scalbn(&pa, &pb, &pc, 0, flags, status); /* Round before applying negate result. */ parts64_uncanon(pr, status, &bfloat16_params, false); @@ -XXX,XX +XXX,XX @@ float128 QEMU_FLATTEN float128_muladd(float128 a, float128 b, float128 c, float128_unpack_canonical(&pa, a, status); float128_unpack_canonical(&pb, b, status); float128_unpack_canonical(&pc, c, status); - pr = parts_muladd_scalbn(&pa, &pb, &pc, 0, flags, status); + pr = parts128_muladd_scalbn(&pa, &pb, &pc, 0, flags, status); /* Round before applying negate result. */ parts128_uncanon(pr, status, &float128_params, false); @@ -XXX,XX +XXX,XX @@ float32 float32_exp2(float32 a, float_status *status) for (i = 0 ; i < 15 ; i++) { float64_unpack_canonical(&tp, float32_exp2_coefficients[i], status); - rp = *parts_muladd_scalbn(&tp, &xnp, &rp, 0, 0, status); + rp = *parts64_muladd_scalbn(&tp, &xnp, &rp, 0, 0, status); xnp = *parts64_mul(&xnp, &xp, status); } @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, /* Compute precise remainder */ r_precise_buf = *b; - r_precise = parts_muladd_scalbn(&r_precise_buf, n, a, 0, - float_muladd_negate_product, status); + r_precise = parts64_muladd_scalbn(&r_precise_buf, n, a, 0, + float_muladd_negate_product, status); /* Round remainder to the target format */ *r = *r_precise; -- 2.43.0
Use parts{64,128}_div at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static FloatParts64 *parts64_div(FloatParts64 *a, FloatParts64 *b, - float_status *s); -static FloatParts128 *parts128_div(FloatParts128 *a, FloatParts128 *b, - float_status *s); - -#define parts_div(A, B, S) \ - PARTS_GENERIC_64_128(div, A)(A, B, S) - static FloatParts64 *parts64_modrem(FloatParts64 *a, FloatParts64 *b, uint64_t *mod_quot, float_status *s); static FloatParts128 *parts128_modrem(FloatParts128 *a, FloatParts128 *b, @@ -XXX,XX +XXX,XX @@ float16 float16_div(float16 a, float16 b, float_status *status) float16_unpack_canonical(&pa, a, status); float16_unpack_canonical(&pb, b, status); - pr = parts_div(&pa, &pb, status); + pr = parts64_div(&pa, &pb, status); return float16_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ soft_f32_div(float32 a, float32 b, float_status *status) float32_unpack_canonical(&pa, a, status); float32_unpack_canonical(&pb, b, status); - pr = parts_div(&pa, &pb, status); + pr = parts64_div(&pa, &pb, status); return float32_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ soft_f64_div(float64 a, float64 b, float_status *status) float64_unpack_canonical(&pa, a, status); float64_unpack_canonical(&pb, b, status); - pr = parts_div(&pa, &pb, status); + pr = parts64_div(&pa, &pb, status); return float64_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float64 float64r32_div(float64 a, float64 b, float_status *status) float64_unpack_canonical(&pa, a, status); float64_unpack_canonical(&pb, b, status); - pr = parts_div(&pa, &pb, status); + pr = parts64_div(&pa, &pb, status); return float64r32_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ bfloat16_div(bfloat16 a, bfloat16 b, float_status *status) bfloat16_unpack_canonical(&pa, a, status); bfloat16_unpack_canonical(&pb, b, status); - pr = parts_div(&pa, &pb, status); + pr = parts64_div(&pa, &pb, status); return bfloat16_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float128_div(float128 a, float128 b, float_status *status) float128_unpack_canonical(&pa, a, status); float128_unpack_canonical(&pb, b, status); - pr = parts_div(&pa, &pb, status); + pr = parts128_div(&pa, &pb, status); return float128_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status) return floatx80_default_nan(status); } - pr = parts_div(&pa, &pb, status); + pr = parts128_div(&pa, &pb, status); return floatx80_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, /* Compute precise quotient */ q_buf = *a; - q = parts_div(&q_buf, b, status); + q = parts64_div(&q_buf, b, status); /* * Check whether two closest integers can be precisely represented, -- 2.43.0
Use parts{64,128}_modrem at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static FloatParts64 *parts64_modrem(FloatParts64 *a, FloatParts64 *b, - uint64_t *mod_quot, float_status *s); -static FloatParts128 *parts128_modrem(FloatParts128 *a, FloatParts128 *b, - uint64_t *mod_quot, float_status *s); - -#define parts_modrem(A, B, Q, S) \ - PARTS_GENERIC_64_128(modrem, A)(A, B, Q, S) - static void parts64_sqrt(FloatParts64 *a, float_status *s, const FloatFmt *f); static void parts128_sqrt(FloatParts128 *a, float_status *s, const FloatFmt *f); @@ -XXX,XX +XXX,XX @@ float32 float32_rem(float32 a, float32 b, float_status *status) float32_unpack_canonical(&pa, a, status); float32_unpack_canonical(&pb, b, status); - pr = parts_modrem(&pa, &pb, NULL, status); + pr = parts64_modrem(&pa, &pb, NULL, status); return float32_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float64 float64_rem(float64 a, float64 b, float_status *status) float64_unpack_canonical(&pa, a, status); float64_unpack_canonical(&pb, b, status); - pr = parts_modrem(&pa, &pb, NULL, status); + pr = parts64_modrem(&pa, &pb, NULL, status); return float64_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float128 float128_rem(float128 a, float128 b, float_status *status) float128_unpack_canonical(&pa, a, status); float128_unpack_canonical(&pb, b, status); - pr = parts_modrem(&pa, &pb, NULL, status); + pr = parts128_modrem(&pa, &pb, NULL, status); return float128_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod, !floatx80_unpack_canonical(&pb, b, status)) { return floatx80_default_nan(status); } - pr = parts_modrem(&pa, &pb, mod ? quotient : NULL, status); + pr = parts128_modrem(&pa, &pb, mod ? quotient : NULL, status); return floatx80_round_pack_canonical(pr, status); } -- 2.43.0
Use parts{64,128}_sqrt at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static void parts64_sqrt(FloatParts64 *a, float_status *s, const FloatFmt *f); -static void parts128_sqrt(FloatParts128 *a, float_status *s, const FloatFmt *f); - -#define parts_sqrt(A, S, F) \ - PARTS_GENERIC_64_128(sqrt, A)(A, S, F) - static bool parts64_round_to_int_normal(FloatParts64 *a, FloatRoundMode rm, int scale, int frac_size); static bool parts128_round_to_int_normal(FloatParts128 *a, FloatRoundMode r, @@ -XXX,XX +XXX,XX @@ float16 QEMU_FLATTEN float16_sqrt(float16 a, float_status *status) FloatParts64 p; float16_unpack_canonical(&p, a, status); - parts_sqrt(&p, status, &float16_params); + parts64_sqrt(&p, status, &float16_params); return float16_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ soft_f32_sqrt(float32 a, float_status *status) FloatParts64 p; float32_unpack_canonical(&p, a, status); - parts_sqrt(&p, status, &float32_params); + parts64_sqrt(&p, status, &float32_params); return float32_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ soft_f64_sqrt(float64 a, float_status *status) FloatParts64 p; float64_unpack_canonical(&p, a, status); - parts_sqrt(&p, status, &float64_params); + parts64_sqrt(&p, status, &float64_params); return float64_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float64 float64r32_sqrt(float64 a, float_status *status) FloatParts64 p; float64_unpack_canonical(&p, a, status); - parts_sqrt(&p, status, &float64_params); + parts64_sqrt(&p, status, &float64_params); return float64r32_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ bfloat16 QEMU_FLATTEN bfloat16_sqrt(bfloat16 a, float_status *status) FloatParts64 p; bfloat16_unpack_canonical(&p, a, status); - parts_sqrt(&p, status, &bfloat16_params); + parts64_sqrt(&p, status, &bfloat16_params); return bfloat16_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float128 QEMU_FLATTEN float128_sqrt(float128 a, float_status *status) FloatParts128 p; float128_unpack_canonical(&p, a, status); - parts_sqrt(&p, status, &float128_params); + parts128_sqrt(&p, status, &float128_params); return float128_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); } - parts_sqrt(&p, s, &floatx80_params[s->floatx80_rounding_precision]); + parts128_sqrt(&p, s, &floatx80_params[s->floatx80_rounding_precision]); return floatx80_round_pack_canonical(&p, s); } -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 22 +++++++--------------- fpu/softfloat-parts.c.inc | 10 +++++----- 2 files changed, 12 insertions(+), 20 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static bool parts64_round_to_int_normal(FloatParts64 *a, FloatRoundMode rm, - int scale, int frac_size); -static bool parts128_round_to_int_normal(FloatParts128 *a, FloatRoundMode r, - int scale, int frac_size); - -#define parts_round_to_int_normal(A, R, C, F) \ - PARTS_GENERIC_64_128(round_to_int_normal, A)(A, R, C, F) - static void parts64_round_to_int(FloatParts64 *a, FloatRoundMode rm, int scale, float_status *s, const FloatFmt *fmt); @@ -XXX,XX +XXX,XX @@ static Int128 float128_to_int128_scalbn(float128 a, FloatRoundMode rmode, case float_class_normal: case float_class_denormal: - if (parts_round_to_int_normal(&p, rmode, scale, 128 - 2)) { + if (parts128_round_to_int_normal(&p, rmode, scale, 128 - 2)) { flags = float_flag_inexact; } @@ -XXX,XX +XXX,XX @@ static Int128 float128_to_uint128_scalbn(float128 a, FloatRoundMode rmode, case float_class_normal: case float_class_denormal: - if (parts_round_to_int_normal(&p, rmode, scale, 128 - 2)) { + if (parts128_round_to_int_normal(&p, rmode, scale, 128 - 2)) { flags = float_flag_inexact; if (p.cls == float_class_zero) { r = int128_zero(); @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, * of distinguishing partial quotients, so ignore the exception. */ *n = *q; - parts_round_to_int_normal(n, - is_q_smallish ? - final_quotient_rounding_mode : - float_round_to_zero, - 0, fmt->frac_size); + parts64_round_to_int_normal(n, + is_q_smallish + ? final_quotient_rounding_mode + : float_round_to_zero, + 0, fmt->frac_size); /* Compute precise remainder */ r_precise_buf = *b; 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(sqrt)(FloatPartsN *a, float_status *status, * according to the IEC/IEEE Standard for Binary Floating-Point * Arithmetic. * - * parts_round_to_int_normal is an internal helper function for + * partsN(round_to_int_normal) is an internal helper function for * normal numbers only, returning true for inexact but not directly * raising float_flag_inexact. */ @@ -XXX,XX +XXX,XX @@ static void partsN(round_to_int)(FloatPartsN *a, FloatRoundMode rmode, break; case float_class_normal: case float_class_denormal: - if (parts_round_to_int_normal(a, rmode, scale, fmt->frac_size)) { + if (partsN(round_to_int_normal)(a, rmode, scale, fmt->frac_size)) { float_raise(float_flag_inexact, s); } break; @@ -XXX,XX +XXX,XX @@ static int64_t partsN(float_to_sint)(FloatPartsN *p, FloatRoundMode rmode, case float_class_normal: case float_class_denormal: /* TODO: N - 2 is frac_size for rounding; could use input fmt. */ - if (parts_round_to_int_normal(p, rmode, scale, N - 2)) { + if (partsN(round_to_int_normal)(p, rmode, scale, N - 2)) { flags = float_flag_inexact; } @@ -XXX,XX +XXX,XX @@ static uint64_t partsN(float_to_uint)(FloatPartsN *p, FloatRoundMode rmode, case float_class_normal: case float_class_denormal: /* TODO: N - 2 is frac_size for rounding; could use input fmt. */ - if (parts_round_to_int_normal(p, rmode, scale, N - 2)) { + if (partsN(round_to_int_normal)(p, rmode, scale, N - 2)) { flags = float_flag_inexact; if (p->cls == float_class_zero) { r = 0; @@ -XXX,XX +XXX,XX @@ static int64_t partsN(float_to_sint_modulo)(FloatPartsN *p, case float_class_normal: case float_class_denormal: /* TODO: N - 2 is frac_size for rounding; could use input fmt. */ - if (parts_round_to_int_normal(p, rmode, 0, N - 2)) { + if (partsN(round_to_int_normal)(p, rmode, 0, N - 2)) { flags = float_flag_inexact; } -- 2.43.0
Use parts{64,128}_round_to_int at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static void parts64_round_to_int(FloatParts64 *a, FloatRoundMode rm, - int scale, float_status *s, - const FloatFmt *fmt); -static void parts128_round_to_int(FloatParts128 *a, FloatRoundMode r, - int scale, float_status *s, - const FloatFmt *fmt); - -#define parts_round_to_int(A, R, C, S, F) \ - PARTS_GENERIC_64_128(round_to_int, A)(A, R, C, S, F) - static int64_t parts64_float_to_sint(FloatParts64 *p, FloatRoundMode rmode, int scale, int64_t min, int64_t max, float_status *s); @@ -XXX,XX +XXX,XX @@ float16 float16_round_to_int(float16 a, float_status *s) FloatParts64 p; float16_unpack_canonical(&p, a, s); - parts_round_to_int(&p, s->float_rounding_mode, 0, s, &float16_params); + parts64_round_to_int(&p, s->float_rounding_mode, 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(&p, a, s); - parts_round_to_int(&p, s->float_rounding_mode, 0, s, &float32_params); + parts64_round_to_int(&p, s->float_rounding_mode, 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(&p, a, s); - parts_round_to_int(&p, s->float_rounding_mode, 0, s, &float64_params); + parts64_round_to_int(&p, s->float_rounding_mode, 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(&p, a, s); - parts_round_to_int(&p, s->float_rounding_mode, 0, s, &bfloat16_params); + parts64_round_to_int(&p, s->float_rounding_mode, 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(&p, a, s); - parts_round_to_int(&p, s->float_rounding_mode, 0, s, &float128_params); + parts128_round_to_int(&p, s->float_rounding_mode, 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); } - parts_round_to_int(&p, status->float_rounding_mode, 0, status, + parts128_round_to_int(&p, status->float_rounding_mode, 0, status, &floatx80_params[status->floatx80_rounding_precision]); return floatx80_round_pack_canonical(&p, status); } -- 2.43.0
Use parts{64,128}_float_to_sint at each call site. Note that there was a duplicate macro redefinition. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 49 ++++++++++++++++++------------------------------- 1 file changed, 18 insertions(+), 31 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static int64_t parts64_float_to_sint(FloatParts64 *p, FloatRoundMode rmode, - int scale, int64_t min, int64_t max, - float_status *s); -static int64_t parts128_float_to_sint(FloatParts128 *p, FloatRoundMode rmode, - int scale, int64_t min, int64_t max, - float_status *s); - -#define parts_float_to_sint(P, R, Z, MN, MX, S) \ - PARTS_GENERIC_64_128(float_to_sint, P)(P, R, Z, MN, MX, S) - static uint64_t parts64_float_to_uint(FloatParts64 *p, FloatRoundMode rmode, int scale, uint64_t max, float_status *s); @@ -XXX,XX +XXX,XX @@ static void parts64_sint_to_float(FloatParts64 *p, int64_t a, static void parts128_sint_to_float(FloatParts128 *p, int64_t a, int scale, float_status *s); -#define parts_float_to_sint(P, R, Z, MN, MX, S) \ - PARTS_GENERIC_64_128(float_to_sint, P)(P, R, Z, MN, MX, S) - #define parts_sint_to_float(P, I, Z, S) \ PARTS_GENERIC_64_128(sint_to_float, P)(P, I, Z, S) @@ -XXX,XX +XXX,XX @@ int8_t float16_to_int8_scalbn(float16 a, FloatRoundMode rmode, int scale, FloatParts64 p; float16_unpack_canonical(&p, a, s); - return parts_float_to_sint(&p, rmode, scale, INT8_MIN, INT8_MAX, s); + return parts64_float_to_sint(&p, rmode, scale, INT8_MIN, INT8_MAX, s); } int16_t float16_to_int16_scalbn(float16 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ int16_t float16_to_int16_scalbn(float16 a, FloatRoundMode rmode, int scale, FloatParts64 p; float16_unpack_canonical(&p, a, s); - return parts_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s); + return parts64_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s); } int32_t float16_to_int32_scalbn(float16 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ int32_t float16_to_int32_scalbn(float16 a, FloatRoundMode rmode, int scale, FloatParts64 p; float16_unpack_canonical(&p, a, s); - return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); + return parts64_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); } int64_t float16_to_int64_scalbn(float16 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ int64_t float16_to_int64_scalbn(float16 a, FloatRoundMode rmode, int scale, FloatParts64 p; float16_unpack_canonical(&p, a, s); - return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); + return parts64_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } int16_t float32_to_int16_scalbn(float32 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ int16_t float32_to_int16_scalbn(float32 a, FloatRoundMode rmode, int scale, FloatParts64 p; float32_unpack_canonical(&p, a, s); - return parts_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s); + return parts64_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s); } int32_t float32_to_int32_scalbn(float32 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ int32_t float32_to_int32_scalbn(float32 a, FloatRoundMode rmode, int scale, FloatParts64 p; float32_unpack_canonical(&p, a, s); - return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); + return parts64_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); } int64_t float32_to_int64_scalbn(float32 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ int64_t float32_to_int64_scalbn(float32 a, FloatRoundMode rmode, int scale, FloatParts64 p; float32_unpack_canonical(&p, a, s); - return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); + return parts64_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } int16_t float64_to_int16_scalbn(float64 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ int16_t float64_to_int16_scalbn(float64 a, FloatRoundMode rmode, int scale, FloatParts64 p; float64_unpack_canonical(&p, a, s); - return parts_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s); + return parts64_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s); } int32_t float64_to_int32_scalbn(float64 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ int32_t float64_to_int32_scalbn(float64 a, FloatRoundMode rmode, int scale, FloatParts64 p; float64_unpack_canonical(&p, a, s); - return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); + return parts64_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); } int64_t float64_to_int64_scalbn(float64 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ int64_t float64_to_int64_scalbn(float64 a, FloatRoundMode rmode, int scale, FloatParts64 p; float64_unpack_canonical(&p, a, s); - return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); + return parts64_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } int8_t bfloat16_to_int8_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ int8_t bfloat16_to_int8_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, FloatParts64 p; bfloat16_unpack_canonical(&p, a, s); - return parts_float_to_sint(&p, rmode, scale, INT8_MIN, INT8_MAX, s); + return parts64_float_to_sint(&p, rmode, scale, INT8_MIN, INT8_MAX, s); } int16_t bfloat16_to_int16_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ int16_t bfloat16_to_int16_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, FloatParts64 p; bfloat16_unpack_canonical(&p, a, s); - return parts_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s); + return parts64_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s); } int32_t bfloat16_to_int32_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ int32_t bfloat16_to_int32_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, FloatParts64 p; bfloat16_unpack_canonical(&p, a, s); - return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); + return parts64_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); } int64_t bfloat16_to_int64_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ int64_t bfloat16_to_int64_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, FloatParts64 p; bfloat16_unpack_canonical(&p, a, s); - return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); + return parts64_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } static int32_t float128_to_int32_scalbn(float128 a, FloatRoundMode rmode, @@ -XXX,XX +XXX,XX @@ static int32_t float128_to_int32_scalbn(float128 a, FloatRoundMode rmode, FloatParts128 p; float128_unpack_canonical(&p, a, s); - return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); + return parts128_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); } static int64_t float128_to_int64_scalbn(float128 a, FloatRoundMode rmode, @@ -XXX,XX +XXX,XX @@ static int64_t float128_to_int64_scalbn(float128 a, FloatRoundMode rmode, FloatParts128 p; float128_unpack_canonical(&p, a, s); - return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); + return parts128_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } static Int128 float128_to_int128_scalbn(float128 a, FloatRoundMode rmode, @@ -XXX,XX +XXX,XX @@ static int32_t floatx80_to_int32_scalbn(floatx80 a, FloatRoundMode rmode, if (!floatx80_unpack_canonical(&p, a, s)) { parts128_default_nan(&p, s); } - return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); + return parts128_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); } static int64_t floatx80_to_int64_scalbn(floatx80 a, FloatRoundMode rmode, @@ -XXX,XX +XXX,XX @@ static int64_t floatx80_to_int64_scalbn(floatx80 a, FloatRoundMode rmode, if (!floatx80_unpack_canonical(&p, a, s)) { parts128_default_nan(&p, s); } - return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); + return parts128_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } int8_t float16_to_int8(float16 a, float_status *s) -- 2.43.0
Use parts{64,128}_float_to_uint at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static uint64_t parts64_float_to_uint(FloatParts64 *p, FloatRoundMode rmode, - int scale, uint64_t max, - float_status *s); -static uint64_t parts128_float_to_uint(FloatParts128 *p, FloatRoundMode rmode, - int scale, uint64_t max, - float_status *s); - -#define parts_float_to_uint(P, R, Z, M, S) \ - PARTS_GENERIC_64_128(float_to_uint, P)(P, R, Z, M, S) - static int64_t parts64_float_to_sint_modulo(FloatParts64 *p, FloatRoundMode rmode, int bitsm1, float_status *s); @@ -XXX,XX +XXX,XX @@ uint8_t float16_to_uint8_scalbn(float16 a, FloatRoundMode rmode, int scale, FloatParts64 p; float16_unpack_canonical(&p, a, s); - return parts_float_to_uint(&p, rmode, scale, UINT8_MAX, s); + return parts64_float_to_uint(&p, rmode, scale, UINT8_MAX, s); } uint16_t float16_to_uint16_scalbn(float16 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ uint16_t float16_to_uint16_scalbn(float16 a, FloatRoundMode rmode, int scale, FloatParts64 p; float16_unpack_canonical(&p, a, s); - return parts_float_to_uint(&p, rmode, scale, UINT16_MAX, s); + return parts64_float_to_uint(&p, rmode, scale, UINT16_MAX, s); } uint32_t float16_to_uint32_scalbn(float16 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ uint32_t float16_to_uint32_scalbn(float16 a, FloatRoundMode rmode, int scale, FloatParts64 p; float16_unpack_canonical(&p, a, s); - return parts_float_to_uint(&p, rmode, scale, UINT32_MAX, s); + return parts64_float_to_uint(&p, rmode, scale, UINT32_MAX, s); } uint64_t float16_to_uint64_scalbn(float16 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ uint64_t float16_to_uint64_scalbn(float16 a, FloatRoundMode rmode, int scale, FloatParts64 p; float16_unpack_canonical(&p, a, s); - return parts_float_to_uint(&p, rmode, scale, UINT64_MAX, s); + return parts64_float_to_uint(&p, rmode, scale, UINT64_MAX, s); } uint16_t float32_to_uint16_scalbn(float32 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ uint16_t float32_to_uint16_scalbn(float32 a, FloatRoundMode rmode, int scale, FloatParts64 p; float32_unpack_canonical(&p, a, s); - return parts_float_to_uint(&p, rmode, scale, UINT16_MAX, s); + return parts64_float_to_uint(&p, rmode, scale, UINT16_MAX, s); } uint32_t float32_to_uint32_scalbn(float32 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ uint32_t float32_to_uint32_scalbn(float32 a, FloatRoundMode rmode, int scale, FloatParts64 p; float32_unpack_canonical(&p, a, s); - return parts_float_to_uint(&p, rmode, scale, UINT32_MAX, s); + return parts64_float_to_uint(&p, rmode, scale, UINT32_MAX, s); } uint64_t float32_to_uint64_scalbn(float32 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ uint64_t float32_to_uint64_scalbn(float32 a, FloatRoundMode rmode, int scale, FloatParts64 p; float32_unpack_canonical(&p, a, s); - return parts_float_to_uint(&p, rmode, scale, UINT64_MAX, s); + return parts64_float_to_uint(&p, rmode, scale, UINT64_MAX, s); } uint16_t float64_to_uint16_scalbn(float64 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ uint16_t float64_to_uint16_scalbn(float64 a, FloatRoundMode rmode, int scale, FloatParts64 p; float64_unpack_canonical(&p, a, s); - return parts_float_to_uint(&p, rmode, scale, UINT16_MAX, s); + return parts64_float_to_uint(&p, rmode, scale, UINT16_MAX, s); } uint32_t float64_to_uint32_scalbn(float64 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ uint32_t float64_to_uint32_scalbn(float64 a, FloatRoundMode rmode, int scale, FloatParts64 p; float64_unpack_canonical(&p, a, s); - return parts_float_to_uint(&p, rmode, scale, UINT32_MAX, s); + return parts64_float_to_uint(&p, rmode, scale, UINT32_MAX, s); } uint64_t float64_to_uint64_scalbn(float64 a, FloatRoundMode rmode, int scale, @@ -XXX,XX +XXX,XX @@ uint64_t float64_to_uint64_scalbn(float64 a, FloatRoundMode rmode, int scale, FloatParts64 p; float64_unpack_canonical(&p, a, s); - return parts_float_to_uint(&p, rmode, scale, UINT64_MAX, s); + return parts64_float_to_uint(&p, rmode, scale, UINT64_MAX, s); } uint8_t bfloat16_to_uint8_scalbn(bfloat16 a, FloatRoundMode rmode, @@ -XXX,XX +XXX,XX @@ uint8_t bfloat16_to_uint8_scalbn(bfloat16 a, FloatRoundMode rmode, FloatParts64 p; bfloat16_unpack_canonical(&p, a, s); - return parts_float_to_uint(&p, rmode, scale, UINT8_MAX, s); + return parts64_float_to_uint(&p, rmode, scale, UINT8_MAX, s); } uint16_t bfloat16_to_uint16_scalbn(bfloat16 a, FloatRoundMode rmode, @@ -XXX,XX +XXX,XX @@ uint16_t bfloat16_to_uint16_scalbn(bfloat16 a, FloatRoundMode rmode, FloatParts64 p; bfloat16_unpack_canonical(&p, a, s); - return parts_float_to_uint(&p, rmode, scale, UINT16_MAX, s); + return parts64_float_to_uint(&p, rmode, scale, UINT16_MAX, s); } uint32_t bfloat16_to_uint32_scalbn(bfloat16 a, FloatRoundMode rmode, @@ -XXX,XX +XXX,XX @@ uint32_t bfloat16_to_uint32_scalbn(bfloat16 a, FloatRoundMode rmode, FloatParts64 p; bfloat16_unpack_canonical(&p, a, s); - return parts_float_to_uint(&p, rmode, scale, UINT32_MAX, s); + return parts64_float_to_uint(&p, rmode, scale, UINT32_MAX, s); } uint64_t bfloat16_to_uint64_scalbn(bfloat16 a, FloatRoundMode rmode, @@ -XXX,XX +XXX,XX @@ uint64_t bfloat16_to_uint64_scalbn(bfloat16 a, FloatRoundMode rmode, FloatParts64 p; bfloat16_unpack_canonical(&p, a, s); - return parts_float_to_uint(&p, rmode, scale, UINT64_MAX, s); + return parts64_float_to_uint(&p, rmode, scale, UINT64_MAX, s); } static uint32_t float128_to_uint32_scalbn(float128 a, FloatRoundMode rmode, @@ -XXX,XX +XXX,XX @@ static uint32_t float128_to_uint32_scalbn(float128 a, FloatRoundMode rmode, FloatParts128 p; float128_unpack_canonical(&p, a, s); - return parts_float_to_uint(&p, rmode, scale, UINT32_MAX, s); + return parts128_float_to_uint(&p, rmode, scale, UINT32_MAX, s); } static uint64_t float128_to_uint64_scalbn(float128 a, FloatRoundMode rmode, @@ -XXX,XX +XXX,XX @@ static uint64_t float128_to_uint64_scalbn(float128 a, FloatRoundMode rmode, FloatParts128 p; float128_unpack_canonical(&p, a, s); - return parts_float_to_uint(&p, rmode, scale, UINT64_MAX, s); + return parts128_float_to_uint(&p, rmode, scale, UINT64_MAX, s); } static Int128 float128_to_uint128_scalbn(float128 a, FloatRoundMode rmode, -- 2.43.0
Use parts64_float_to_sint_modulo at each call site. That leaves parts128_float_to_sint_modulo unused, so move the whole function back to softfloat.c and specialize for FloatParts64. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 84 +++++++++++++++++++++++++++++++++------ fpu/softfloat-parts.c.inc | 79 ------------------------------------ 2 files changed, 72 insertions(+), 91 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static int64_t parts64_float_to_sint_modulo(FloatParts64 *p, - FloatRoundMode rmode, - int bitsm1, float_status *s); -static int64_t parts128_float_to_sint_modulo(FloatParts128 *p, - FloatRoundMode rmode, - int bitsm1, float_status *s); - -#define parts_float_to_sint_modulo(P, R, M, S) \ - PARTS_GENERIC_64_128(float_to_sint_modulo, P)(P, R, M, S) - static void parts64_sint_to_float(FloatParts64 *p, int64_t a, int scale, float_status *s); static void parts128_sint_to_float(FloatParts128 *p, int64_t a, @@ -XXX,XX +XXX,XX @@ int64_t bfloat16_to_int64_round_to_zero(bfloat16 a, float_status *s) return bfloat16_to_int64_scalbn(a, float_round_to_zero, 0, s); } +/* + * Like partsN(float_to_sint), except do not saturate the result. + * Instead, return the rounded unbounded precision two's compliment result, + * modulo 2**(bitsm1 + 1). + */ +static int64_t parts64_float_to_sint_modulo(FloatParts64 *p, + FloatRoundMode rmode, + int bitsm1, float_status *s) +{ + int flags = 0; + uint64_t r; + bool overflow = false; + + switch (p->cls) { + case float_class_snan: + flags |= float_flag_invalid_snan; + /* fall through */ + case float_class_qnan: + flags |= float_flag_invalid; + r = 0; + break; + + case float_class_inf: + overflow = true; + r = 0; + break; + + case float_class_zero: + return 0; + + case float_class_normal: + case float_class_denormal: + /* TODO: 64 - 2 is frac_size for rounding; could use input fmt. */ + if (parts64_round_to_int_normal(p, rmode, 0, 64 - 2)) { + flags = float_flag_inexact; + } + + if (p->exp <= DECOMPOSED_BINARY_POINT) { + r = p->frac >> (DECOMPOSED_BINARY_POINT - p->exp); + if (p->exp < bitsm1) { + /* Result in range. */ + } else if (p->exp == bitsm1) { + /* The only in-range value is INT_MIN. */ + overflow = !p->sign || p->frac != DECOMPOSED_IMPLICIT_BIT; + } else { + overflow = true; + } + } else { + /* Overflow, but there might still be bits to return. */ + int shl = p->exp - DECOMPOSED_BINARY_POINT; + r = (shl < 64 ? p->frac << shl : 0); + overflow = true; + } + + if (p->sign) { + r = -r; + } + break; + + default: + g_assert_not_reached(); + } + + if (overflow) { + flags = float_flag_invalid | float_flag_invalid_cvti; + } + float_raise(flags, s); + return r; +} + int32_t float64_to_int32_modulo(float64 a, FloatRoundMode rmode, float_status *s) { FloatParts64 p; float64_unpack_canonical(&p, a, s); - return parts_float_to_sint_modulo(&p, rmode, 31, s); + return parts64_float_to_sint_modulo(&p, rmode, 31, s); } int64_t float64_to_int64_modulo(float64 a, FloatRoundMode rmode, @@ -XXX,XX +XXX,XX @@ int64_t float64_to_int64_modulo(float64 a, FloatRoundMode rmode, FloatParts64 p; float64_unpack_canonical(&p, a, s); - return parts_float_to_sint_modulo(&p, rmode, 63, s); + return parts64_float_to_sint_modulo(&p, rmode, 63, 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 uint64_t partsN(float_to_uint)(FloatPartsN *p, FloatRoundMode rmode, return r; } -/* - * Like partsN(float_to_sint), except do not saturate the result. - * Instead, return the rounded unbounded precision two's compliment result, - * modulo 2**(bitsm1 + 1). - */ -static int64_t partsN(float_to_sint_modulo)(FloatPartsN *p, - FloatRoundMode rmode, - int bitsm1, float_status *s) -{ - int flags = 0; - uint64_t r; - bool overflow = false; - - switch (p->cls) { - case float_class_snan: - flags |= float_flag_invalid_snan; - /* fall through */ - case float_class_qnan: - flags |= float_flag_invalid; - r = 0; - break; - - case float_class_inf: - overflow = true; - r = 0; - break; - - case float_class_zero: - return 0; - - case float_class_normal: - case float_class_denormal: - /* TODO: N - 2 is frac_size for rounding; could use input fmt. */ - if (partsN(round_to_int_normal)(p, rmode, 0, N - 2)) { - flags = float_flag_inexact; - } - - if (p->exp <= DECOMPOSED_BINARY_POINT) { - /* - * Because we rounded to integral, and exp < 64, - * we know frac_low is zero. - */ - r = p->frac_hi >> (DECOMPOSED_BINARY_POINT - p->exp); - if (p->exp < bitsm1) { - /* Result in range. */ - } else if (p->exp == bitsm1) { - /* The only in-range value is INT_MIN. */ - overflow = !p->sign || p->frac_hi != DECOMPOSED_IMPLICIT_BIT; - } else { - overflow = true; - } - } else { - /* Overflow, but there might still be bits to return. */ - int shl = p->exp - DECOMPOSED_BINARY_POINT; - if (shl < N) { - frac_shl(p, shl); - r = p->frac_hi; - } else { - r = 0; - } - overflow = true; - } - - if (p->sign) { - r = -r; - } - break; - - default: - g_assert_not_reached(); - } - - if (overflow) { - flags = float_flag_invalid | float_flag_invalid_cvti; - } - float_raise(flags, s); - return r; -} - /* * Integer to float conversions * -- 2.43.0
Use parts{64,128}_sint_to_float at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 18 +++++------------- fpu/softfloat-parts.c.inc | 2 +- 2 files changed, 6 insertions(+), 14 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static void parts64_sint_to_float(FloatParts64 *p, int64_t a, - int scale, float_status *s); -static void parts128_sint_to_float(FloatParts128 *p, int64_t a, - int scale, float_status *s); - -#define parts_sint_to_float(P, I, Z, S) \ - PARTS_GENERIC_64_128(sint_to_float, P)(P, I, Z, S) - static void parts64_uint_to_float(FloatParts64 *p, uint64_t a, int scale, float_status *s); static void parts128_uint_to_float(FloatParts128 *p, uint64_t a, @@ -XXX,XX +XXX,XX @@ float16 int64_to_float16_scalbn(int64_t a, int scale, float_status *status) { FloatParts64 p; - parts_sint_to_float(&p, a, scale, status); + parts64_sint_to_float(&p, a, scale, status); return float16_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float64 int64_to_float64_scalbn(int64_t a, int scale, float_status *status) return ur.s; } - parts_sint_to_float(&p, a, scale, status); + parts64_sint_to_float(&p, a, scale, status); return float64_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ bfloat16 int64_to_bfloat16_scalbn(int64_t a, int scale, float_status *status) { FloatParts64 p; - parts_sint_to_float(&p, a, scale, status); + parts64_sint_to_float(&p, a, scale, status); return bfloat16_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float128 int64_to_float128(int64_t a, float_status *status) { FloatParts128 p; - parts_sint_to_float(&p, a, 0, status); + parts128_sint_to_float(&p, a, 0, status); return float128_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ floatx80 int64_to_floatx80(int64_t a, float_status *status) { FloatParts128 p; - parts_sint_to_float(&p, a, 0, status); + parts128_sint_to_float(&p, a, 0, 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 @@ static void partsN(log2)(FloatPartsN *a, float_status *s, const FloatFmt *fmt) r |= (a1 || a0 & ~DECOMPOSED_IMPLICIT_BIT); exact: - parts_sint_to_float(a, a_exp, 0, s); + partsN(sint_to_float)(a, a_exp, 0, s); if (r == 0) { return; } -- 2.43.0
Use parts{64,128}_uint_to_float at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static void parts64_uint_to_float(FloatParts64 *p, uint64_t a, - int scale, float_status *s); -static void parts128_uint_to_float(FloatParts128 *p, uint64_t a, - int scale, float_status *s); - -#define parts_uint_to_float(P, I, Z, S) \ - PARTS_GENERIC_64_128(uint_to_float, P)(P, I, Z, S) - static FloatParts64 *parts64_minmax(FloatParts64 *a, FloatParts64 *b, float_status *s, int flags); static FloatParts128 *parts128_minmax(FloatParts128 *a, FloatParts128 *b, @@ -XXX,XX +XXX,XX @@ float16 uint64_to_float16_scalbn(uint64_t a, int scale, float_status *status) { FloatParts64 p; - parts_uint_to_float(&p, a, scale, status); + parts64_uint_to_float(&p, a, scale, status); return float16_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float32 uint64_to_float32_scalbn(uint64_t a, int scale, float_status *status) return ur.s; } - parts_uint_to_float(&p, a, scale, status); + parts64_uint_to_float(&p, a, scale, status); return float32_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float64 uint64_to_float64_scalbn(uint64_t a, int scale, float_status *status) return ur.s; } - parts_uint_to_float(&p, a, scale, status); + parts64_uint_to_float(&p, a, scale, status); return float64_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ bfloat16 uint64_to_bfloat16_scalbn(uint64_t a, int scale, float_status *status) { FloatParts64 p; - parts_uint_to_float(&p, a, scale, status); + parts64_uint_to_float(&p, a, scale, status); return bfloat16_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float128 uint64_to_float128(uint64_t a, float_status *status) { FloatParts128 p; - parts_uint_to_float(&p, a, 0, status); + parts128_uint_to_float(&p, a, 0, status); return float128_round_pack_canonical(&p, status); } -- 2.43.0
Use parts{64,128}_minmax at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static FloatParts64 *parts64_minmax(FloatParts64 *a, FloatParts64 *b, - float_status *s, int flags); -static FloatParts128 *parts128_minmax(FloatParts128 *a, FloatParts128 *b, - float_status *s, int flags); - -#define parts_minmax(A, B, S, F) \ - PARTS_GENERIC_64_128(minmax, A)(A, B, S, F) - static FloatRelation parts64_compare(FloatParts64 *a, FloatParts64 *b, float_status *s, bool q); static FloatRelation parts128_compare(FloatParts128 *a, FloatParts128 *b, @@ -XXX,XX +XXX,XX @@ static float16 float16_minmax(float16 a, float16 b, float_status *s, int flags) float16_unpack_canonical(&pa, a, s); float16_unpack_canonical(&pb, b, s); - pr = parts_minmax(&pa, &pb, s, flags); + pr = parts64_minmax(&pa, &pb, s, flags); return float16_round_pack_canonical(pr, s); } @@ -XXX,XX +XXX,XX @@ static bfloat16 bfloat16_minmax(bfloat16 a, bfloat16 b, bfloat16_unpack_canonical(&pa, a, s); bfloat16_unpack_canonical(&pb, b, s); - pr = parts_minmax(&pa, &pb, s, flags); + pr = parts64_minmax(&pa, &pb, s, flags); return bfloat16_round_pack_canonical(pr, s); } @@ -XXX,XX +XXX,XX @@ static float32 float32_minmax(float32 a, float32 b, float_status *s, int flags) float32_unpack_canonical(&pa, a, s); float32_unpack_canonical(&pb, b, s); - pr = parts_minmax(&pa, &pb, s, flags); + pr = parts64_minmax(&pa, &pb, s, flags); return float32_round_pack_canonical(pr, s); } @@ -XXX,XX +XXX,XX @@ static float64 float64_minmax(float64 a, float64 b, float_status *s, int flags) float64_unpack_canonical(&pa, a, s); float64_unpack_canonical(&pb, b, s); - pr = parts_minmax(&pa, &pb, s, flags); + pr = parts64_minmax(&pa, &pb, s, flags); return float64_round_pack_canonical(pr, s); } @@ -XXX,XX +XXX,XX @@ static float128 float128_minmax(float128 a, float128 b, float128_unpack_canonical(&pa, a, s); float128_unpack_canonical(&pb, b, s); - pr = parts_minmax(&pa, &pb, s, flags); + pr = parts128_minmax(&pa, &pb, s, flags); return float128_round_pack_canonical(pr, s); } -- 2.43.0
Use parts{64,128}_compare at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static FloatRelation parts64_compare(FloatParts64 *a, FloatParts64 *b, - float_status *s, bool q); -static FloatRelation parts128_compare(FloatParts128 *a, FloatParts128 *b, - float_status *s, bool q); - -#define parts_compare(A, B, S, Q) \ - PARTS_GENERIC_64_128(compare, A)(A, B, S, Q) - static void parts64_scalbn(FloatParts64 *a, int n, float_status *s); static void parts128_scalbn(FloatParts128 *a, int n, float_status *s); @@ -XXX,XX +XXX,XX @@ float16_do_compare(float16 a, float16 b, float_status *s, bool is_quiet) float16_unpack_canonical(&pa, a, s); float16_unpack_canonical(&pb, b, s); - return parts_compare(&pa, &pb, s, is_quiet); + return parts64_compare(&pa, &pb, s, is_quiet); } FloatRelation float16_compare(float16 a, float16 b, float_status *s) @@ -XXX,XX +XXX,XX @@ float32_do_compare(float32 a, float32 b, float_status *s, bool is_quiet) float32_unpack_canonical(&pa, a, s); float32_unpack_canonical(&pb, b, s); - return parts_compare(&pa, &pb, s, is_quiet); + return parts64_compare(&pa, &pb, s, is_quiet); } static FloatRelation QEMU_FLATTEN @@ -XXX,XX +XXX,XX @@ float64_do_compare(float64 a, float64 b, float_status *s, bool is_quiet) float64_unpack_canonical(&pa, a, s); float64_unpack_canonical(&pb, b, s); - return parts_compare(&pa, &pb, s, is_quiet); + return parts64_compare(&pa, &pb, s, is_quiet); } static FloatRelation QEMU_FLATTEN @@ -XXX,XX +XXX,XX @@ bfloat16_do_compare(bfloat16 a, bfloat16 b, float_status *s, bool is_quiet) bfloat16_unpack_canonical(&pa, a, s); bfloat16_unpack_canonical(&pb, b, s); - return parts_compare(&pa, &pb, s, is_quiet); + return parts64_compare(&pa, &pb, s, is_quiet); } FloatRelation bfloat16_compare(bfloat16 a, bfloat16 b, float_status *s) @@ -XXX,XX +XXX,XX @@ float128_do_compare(float128 a, float128 b, float_status *s, bool is_quiet) float128_unpack_canonical(&pa, a, s); float128_unpack_canonical(&pb, b, s); - return parts_compare(&pa, &pb, s, is_quiet); + return parts128_compare(&pa, &pb, s, is_quiet); } FloatRelation float128_compare(float128 a, float128 b, float_status *s) @@ -XXX,XX +XXX,XX @@ floatx80_do_compare(floatx80 a, floatx80 b, float_status *s, bool is_quiet) !floatx80_unpack_canonical(&pb, b, s)) { return float_relation_unordered; } - return parts_compare(&pa, &pb, s, is_quiet); + return parts128_compare(&pa, &pb, s, is_quiet); } FloatRelation floatx80_compare(floatx80 a, floatx80 b, float_status *s) @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, saved_r_precise_sign = r_precise->sign; r->sign = false; r_precise->sign = false; - if (parts_compare(r, r_precise, status, true) < + if (parts64_compare(r, r_precise, status, true) < float_relation_equal) { *dxc = 0x8; } else { -- 2.43.0
Use parts{64,128}_scalbn at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static void parts64_scalbn(FloatParts64 *a, int n, float_status *s); -static void parts128_scalbn(FloatParts128 *a, int n, float_status *s); - -#define parts_scalbn(A, N, S) \ - PARTS_GENERIC_64_128(scalbn, A)(A, N, S) - static void parts64_log2(FloatParts64 *a, float_status *s, const FloatFmt *f); static void parts128_log2(FloatParts128 *a, float_status *s, const FloatFmt *f); @@ -XXX,XX +XXX,XX @@ float16 float16_scalbn(float16 a, int n, float_status *status) FloatParts64 p; float16_unpack_canonical(&p, a, status); - parts_scalbn(&p, n, status); + 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(&p, a, status); - parts_scalbn(&p, n, status); + 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(&p, a, status); - parts_scalbn(&p, n, status); + 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(&p, a, status); - parts_scalbn(&p, n, status); + 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(&p, a, status); - parts_scalbn(&p, n, status); + 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); } - parts_scalbn(&p, n, status); + parts128_scalbn(&p, n, status); return floatx80_round_pack_canonical(&p, status); } -- 2.43.0
Use parts64_log2 at each call site. That leaves parts128_log2 unused, so move the whole function back to softfloat.c and specialize for FloatParts64. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 133 +++++++++++++++++++++++++++++++++++--- fpu/softfloat-parts.c.inc | 131 ------------------------------------- 2 files changed, 125 insertions(+), 139 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) FloatParts128 *: parts128_##NAME, \ FloatParts256 *: parts256_##NAME) -static void parts64_log2(FloatParts64 *a, float_status *s, const FloatFmt *f); -static void parts128_log2(FloatParts128 *a, float_status *s, const FloatFmt *f); - -#define parts_log2(A, S, F) \ - PARTS_GENERIC_64_128(log2, A)(A, S, F) - /* * Helper functions for softfloat-parts.c.inc, per-size operations. */ @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sqrt(floatx80 a, float_status *s) /* * log2 */ + +static void parts64_log2(FloatParts64 *a, float_status *s, const FloatFmt *fmt) +{ + uint64_t a0, a1, r, t, ign; + int i, n, a_exp, f_exp; + + if (unlikely(a->cls != float_class_normal)) { + switch (a->cls) { + case float_class_denormal: + if (!a->sign) { + /* -ve denormal will be InvalidOperation */ + float_raise(float_flag_input_denormal_used, s); + } + break; + case float_class_snan: + case float_class_qnan: + parts64_return_nan(a, s); + return; + case float_class_zero: + float_raise(float_flag_divbyzero, s); + /* log2(0) = -inf */ + a->cls = float_class_inf; + a->sign = 1; + return; + case float_class_inf: + if (unlikely(a->sign)) { + goto d_nan; + } + return; + default: + g_assert_not_reached(); + } + } + if (unlikely(a->sign)) { + goto d_nan; + } + + a_exp = a->exp; + f_exp = -1; + + r = 0; + t = DECOMPOSED_IMPLICIT_BIT; + a0 = a->frac_hi; + a1 = 0; + + n = fmt->frac_size + 2; + if (unlikely(a_exp == -1)) { + /* + * When a_exp == -1, we're computing the log2 of a value [0.5,1.0). + * When the value is very close to 1.0, there are lots of 1's in + * the msb parts of the fraction. At the end, when we subtract + * this value from -1.0, we can see a catastrophic loss of precision, + * as 0x800..000 - 0x7ff..ffx becomes 0x000..00y, leaving only the + * bits of y in the final result. To minimize this, compute as many + * digits as we can. + * ??? This case needs another algorithm to avoid this. + */ + n = fmt->frac_size * 2 + 2; + /* Don't compute a value overlapping the sticky bit */ + n = MIN(n, 62); + } + + for (i = 0; i < n; i++) { + if (a1) { + mul128To256(a0, a1, a0, a1, &a0, &a1, &ign, &ign); + } else if (a0 & 0xffffffffull) { + mul64To128(a0, a0, &a0, &a1); + } else if (a0 & ~DECOMPOSED_IMPLICIT_BIT) { + a0 >>= 32; + a0 *= a0; + } else { + goto exact; + } + + if (a0 & DECOMPOSED_IMPLICIT_BIT) { + if (unlikely(a_exp == 0 && r == 0)) { + /* + * When a_exp == 0, we're computing the log2 of a value + * [1.0,2.0). When the value is very close to 1.0, there + * are lots of 0's in the msb parts of the fraction. + * We need to compute more digits to produce a correct + * result -- restart at the top of the fraction. + * ??? This is likely to lose precision quickly, as for + * float128; we may need another method. + */ + f_exp -= i; + t = r = DECOMPOSED_IMPLICIT_BIT; + i = 0; + } else { + r |= t; + } + } else { + add128(a0, a1, a0, a1, &a0, &a1); + } + t >>= 1; + } + + /* Set sticky for inexact. */ + r |= (a1 || a0 & ~DECOMPOSED_IMPLICIT_BIT); + + exact: + parts64_sint_to_float(a, a_exp, 0, s); + if (r != 0) { + FloatParts64 f = { + .cls = float_class_normal, .frac = r + }; + f.exp = f_exp - frac_normalize(&f); + + if (a_exp < 0) { + parts64_sub_normal(a, &f); + } else if (a_exp > 0) { + parts64_add_normal(a, &f); + } else { + *a = f; + } + } + return; + + d_nan: + float_raise(float_flag_invalid, s); + parts64_default_nan(a, s); +} + float32 float32_log2(float32 a, float_status *status) { FloatParts64 p; float32_unpack_canonical(&p, a, status); - parts_log2(&p, status, &float32_params); + parts64_log2(&p, status, &float32_params); return float32_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float64 float64_log2(float64 a, float_status *status) FloatParts64 p; float64_unpack_canonical(&p, a, status); - parts_log2(&p, status, &float64_params); + parts64_log2(&p, status, &float64_params); return float64_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 @@ static void partsN(scalbn)(FloatPartsN *a, int n, float_status *s) g_assert_not_reached(); } } - -/* - * Return log2(A) - */ -static void partsN(log2)(FloatPartsN *a, float_status *s, const FloatFmt *fmt) -{ - uint64_t a0, a1, r, t, ign; - FloatPartsN f; - int i, n, a_exp, f_exp; - - if (unlikely(a->cls != float_class_normal)) { - switch (a->cls) { - case float_class_denormal: - if (!a->sign) { - /* -ve denormal will be InvalidOperation */ - float_raise(float_flag_input_denormal_used, s); - } - break; - case float_class_snan: - case float_class_qnan: - partsN(return_nan)(a, s); - return; - case float_class_zero: - float_raise(float_flag_divbyzero, s); - /* log2(0) = -inf */ - a->cls = float_class_inf; - a->sign = 1; - return; - case float_class_inf: - if (unlikely(a->sign)) { - goto d_nan; - } - return; - default: - g_assert_not_reached(); - } - } - if (unlikely(a->sign)) { - goto d_nan; - } - - /* TODO: This algorithm looses bits too quickly for float128. */ - g_assert(N == 64); - - a_exp = a->exp; - f_exp = -1; - - r = 0; - t = DECOMPOSED_IMPLICIT_BIT; - a0 = a->frac_hi; - a1 = 0; - - n = fmt->frac_size + 2; - if (unlikely(a_exp == -1)) { - /* - * When a_exp == -1, we're computing the log2 of a value [0.5,1.0). - * When the value is very close to 1.0, there are lots of 1's in - * the msb parts of the fraction. At the end, when we subtract - * this value from -1.0, we can see a catastrophic loss of precision, - * as 0x800..000 - 0x7ff..ffx becomes 0x000..00y, leaving only the - * bits of y in the final result. To minimize this, compute as many - * digits as we can. - * ??? This case needs another algorithm to avoid this. - */ - n = fmt->frac_size * 2 + 2; - /* Don't compute a value overlapping the sticky bit */ - n = MIN(n, 62); - } - - for (i = 0; i < n; i++) { - if (a1) { - mul128To256(a0, a1, a0, a1, &a0, &a1, &ign, &ign); - } else if (a0 & 0xffffffffull) { - mul64To128(a0, a0, &a0, &a1); - } else if (a0 & ~DECOMPOSED_IMPLICIT_BIT) { - a0 >>= 32; - a0 *= a0; - } else { - goto exact; - } - - if (a0 & DECOMPOSED_IMPLICIT_BIT) { - if (unlikely(a_exp == 0 && r == 0)) { - /* - * When a_exp == 0, we're computing the log2 of a value - * [1.0,2.0). When the value is very close to 1.0, there - * are lots of 0's in the msb parts of the fraction. - * We need to compute more digits to produce a correct - * result -- restart at the top of the fraction. - * ??? This is likely to lose precision quickly, as for - * float128; we may need another method. - */ - f_exp -= i; - t = r = DECOMPOSED_IMPLICIT_BIT; - i = 0; - } else { - r |= t; - } - } else { - add128(a0, a1, a0, a1, &a0, &a1); - } - t >>= 1; - } - - /* Set sticky for inexact. */ - r |= (a1 || a0 & ~DECOMPOSED_IMPLICIT_BIT); - - exact: - partsN(sint_to_float)(a, a_exp, 0, s); - if (r == 0) { - return; - } - - memset(&f, 0, sizeof(f)); - f.cls = float_class_normal; - f.frac_hi = r; - f.exp = f_exp - frac_normalize(&f); - - if (a_exp < 0) { - partsN(sub_normal)(a, &f); - } else if (a_exp > 0) { - partsN(add_normal)(a, &f); - } else { - *a = f; - } - return; - - d_nan: - float_raise(float_flag_invalid, s); - partsN(default_nan)(a, s); -} -- 2.43.0
Use parts{64,128}_float_to_float at each call site. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 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 parts128_float_to_float(FloatParts128 *a, float_status *s) } } -#define parts_float_to_float(P, S) \ - PARTS_GENERIC_64_128(float_to_float, P)(P, S) - static void parts_float_to_float_narrow(FloatParts64 *a, FloatParts128 *b, float_status *s) { @@ -XXX,XX +XXX,XX @@ float8_e4m3 float4_e2m1_to_float8_e4m3(float4_e2m1 a, float_status *s) FloatParts64 p; float4_e2m1_unpack_canonical(&p, a, s); - parts_float_to_float(&p, s); + parts64_float_to_float(&p, s); return float8_e4m3_round_pack_canonical(&p, s, false); } @@ -XXX,XX +XXX,XX @@ bfloat16 float8_e4m3_to_bfloat16(float8_e4m3 a, float_status *s) FloatParts64 p; float8_e4m3_unpack_canonical(&p, a, s); - parts_float_to_float(&p, s); + parts64_float_to_float(&p, s); return bfloat16_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ bfloat16 float8_e5m2_to_bfloat16(float8_e5m2 a, float_status *s) FloatParts64 p; float8_e5m2_unpack_canonical(&p, a, s); - parts_float_to_float(&p, s); + parts64_float_to_float(&p, s); return bfloat16_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ float32 float16_to_float32(float16 a, bool ieee, float_status *s) FloatParts64 p; float16a_unpack_canonical(&p, a, s, fmt16); - parts_float_to_float(&p, s); + parts64_float_to_float(&p, s); return float32_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ float64 float16_to_float64(float16 a, bool ieee, float_status *s) FloatParts64 p; float16a_unpack_canonical(&p, a, s, fmt16); - parts_float_to_float(&p, s); + parts64_float_to_float(&p, s); return float64_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ float8_e4m3 float32_to_float8_e4m3(float32 a, bool saturate, float_status *s) FloatParts64 p; float32_unpack_canonical(&p, a, s); - parts_float_to_float(&p, s); + parts64_float_to_float(&p, s); return float8_e4m3_round_pack_canonical(&p, s, saturate); } @@ -XXX,XX +XXX,XX @@ float16 float32_to_float16(float32 a, bool ieee, float_status *s) float32_unpack_canonical(&p, a, s); if (ieee) { - parts_float_to_float(&p, s); + parts64_float_to_float(&p, s); fmt = &float16_params; } else { parts_float_to_ahp(&p, s); @@ -XXX,XX +XXX,XX @@ soft_float32_to_float64(float32 a, float_status *s) FloatParts64 p; float32_unpack_canonical(&p, a, s); - parts_float_to_float(&p, s); + parts64_float_to_float(&p, s); return float64_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ float16 float64_to_float16(float64 a, bool ieee, float_status *s) float64_unpack_canonical(&p, a, s); if (ieee) { - parts_float_to_float(&p, s); + parts64_float_to_float(&p, s); fmt = &float16_params; } else { parts_float_to_ahp(&p, s); @@ -XXX,XX +XXX,XX @@ float32 float64_to_float32(float64 a, float_status *s) FloatParts64 p; float64_unpack_canonical(&p, a, s); - parts_float_to_float(&p, s); + parts64_float_to_float(&p, s); return float32_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ float8_e4m3 bfloat16_to_float8_e4m3(bfloat16 a, bool saturate, float_status *s) FloatParts64 p; bfloat16_unpack_canonical(&p, a, s); - parts_float_to_float(&p, s); + parts64_float_to_float(&p, s); return float8_e4m3_round_pack_canonical(&p, s, saturate); } @@ -XXX,XX +XXX,XX @@ float32 bfloat16_to_float32(bfloat16 a, float_status *s) FloatParts64 p; bfloat16_unpack_canonical(&p, a, s); - parts_float_to_float(&p, s); + parts64_float_to_float(&p, s); return float32_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ float64 bfloat16_to_float64(bfloat16 a, float_status *s) FloatParts64 p; bfloat16_unpack_canonical(&p, a, s); - parts_float_to_float(&p, s); + parts64_float_to_float(&p, s); return float64_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ bfloat16 float32_to_bfloat16(float32 a, float_status *s) FloatParts64 p; float32_unpack_canonical(&p, a, s); - parts_float_to_float(&p, s); + parts64_float_to_float(&p, s); return bfloat16_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ bfloat16 float64_to_bfloat16(float64 a, float_status *s) FloatParts64 p; float64_unpack_canonical(&p, a, s); - parts_float_to_float(&p, s); + parts64_float_to_float(&p, s); return bfloat16_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ float128 floatx80_to_float128(floatx80 a, float_status *s) FloatParts128 p; if (floatx80_unpack_canonical(&p, a, s)) { - parts_float_to_float(&p, s); + parts128_float_to_float(&p, s); } else { parts128_default_nan(&p, s); } @@ -XXX,XX +XXX,XX @@ floatx80 float128_to_floatx80(float128 a, float_status *s) FloatParts128 p; float128_unpack_canonical(&p, a, s); - parts_float_to_float(&p, s); + parts128_float_to_float(&p, s); return floatx80_round_pack_canonical(&p, s); } -- 2.43.0
These macros are no longer used. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 9 --------- 1 file changed, 9 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" -#define PARTS_GENERIC_64_128(NAME, P) \ - _Generic((P), FloatParts64 *: parts64_##NAME, \ - FloatParts128 *: parts128_##NAME) - -#define PARTS_GENERIC_64_128_256(NAME, P) \ - _Generic((P), FloatParts64 *: parts64_##NAME, \ - FloatParts128 *: parts128_##NAME, \ - FloatParts256 *: parts256_##NAME) - /* * Helper functions for softfloat-parts.c.inc, per-size operations. */ -- 2.43.0
This requires more complexity to handle const selectors, and an indirection macro for each function. Easier to just use the preprocessor. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 69 +++++---------------- fpu/softfloat-parts-addsub.c.inc | 22 +++---- fpu/softfloat-parts.c.inc | 102 +++++++++++++++---------------- 3 files changed, 77 insertions(+), 116 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) * Helper functions for softfloat-parts.c.inc, per-size operations. */ -#define FRAC_GENERIC_64_128(NAME, P) \ - _Generic((P), FloatParts64 *: frac64_##NAME, \ - FloatParts128 *: frac128_##NAME) - -#define FRAC_GENERIC_64_128_256(NAME, P) \ - _Generic((P), FloatParts64 *: frac64_##NAME, \ - FloatParts128 *: frac128_##NAME, \ - FloatParts256 *: frac256_##NAME) - static bool frac64_add(FloatParts64 *r, FloatParts64 *a, FloatParts64 *b) { return uadd64_overflow(a->frac, b->frac, &r->frac); @@ -XXX,XX +XXX,XX @@ static bool frac256_add(FloatParts256 *r, FloatParts256 *a, FloatParts256 *b) return c; } -#define frac_add(R, A, B) FRAC_GENERIC_64_128_256(add, R)(R, A, B) - static bool frac64_addi(FloatParts64 *r, FloatParts64 *a, uint64_t c) { return uadd64_overflow(a->frac, c, &r->frac); @@ -XXX,XX +XXX,XX @@ static bool frac128_addi(FloatParts128 *r, FloatParts128 *a, uint64_t c) return uadd64_overflow(a->frac_hi, c, &r->frac_hi); } -#define frac_addi(R, A, C) FRAC_GENERIC_64_128(addi, R)(R, A, C) - static void frac64_allones(FloatParts64 *a) { a->frac = -1; @@ -XXX,XX +XXX,XX @@ static void frac128_allones(FloatParts128 *a) a->frac_hi = a->frac_lo = -1; } -#define frac_allones(A) FRAC_GENERIC_64_128(allones, A)(A) - static FloatRelation frac64_cmp(FloatParts64 *a, FloatParts64 *b) { return (a->frac == b->frac ? float_relation_equal @@ -XXX,XX +XXX,XX @@ static FloatRelation frac128_cmp(FloatParts128 *a, FloatParts128 *b) return ta < tb ? float_relation_less : float_relation_greater; } -#define frac_cmp(A, B) FRAC_GENERIC_64_128(cmp, A)(A, B) - static void frac64_clear(FloatParts64 *a) { a->frac = 0; @@ -XXX,XX +XXX,XX @@ static void frac128_clear(FloatParts128 *a) a->frac_hi = a->frac_lo = 0; } -#define frac_clear(A) FRAC_GENERIC_64_128(clear, A)(A) - static bool frac64_div(FloatParts64 *a, FloatParts64 *b) { uint64_t n1, n0, r, q; @@ -XXX,XX +XXX,XX @@ static bool frac128_div(FloatParts128 *a, FloatParts128 *b) return ret; } -#define frac_div(A, B) FRAC_GENERIC_64_128(div, A)(A, B) - static bool frac64_eqz(FloatParts64 *a) { return a->frac == 0; @@ -XXX,XX +XXX,XX @@ static bool frac128_eqz(FloatParts128 *a) return (a->frac_hi | a->frac_lo) == 0; } -#define frac_eqz(A) FRAC_GENERIC_64_128(eqz, A)(A) - static void frac64_mulw(FloatParts128 *r, FloatParts64 *a, FloatParts64 *b) { mulu64(&r->frac_lo, &r->frac_hi, a->frac, b->frac); @@ -XXX,XX +XXX,XX @@ static void frac128_mulw(FloatParts256 *r, FloatParts128 *a, FloatParts128 *b) &r->frac_hi, &r->frac_hm, &r->frac_lm, &r->frac_lo); } -#define frac_mulw(R, A, B) FRAC_GENERIC_64_128(mulw, A)(R, A, B) - static void frac64_neg(FloatParts64 *a) { a->frac = -a->frac; @@ -XXX,XX +XXX,XX @@ static void frac256_neg(FloatParts256 *a) a->frac_hi = usub64_borrow(0, a->frac_hi, &c); } -#define frac_neg(A) FRAC_GENERIC_64_128_256(neg, A)(A) - static int frac64_normalize(FloatParts64 *a) { if (a->frac) { @@ -XXX,XX +XXX,XX @@ static int frac256_normalize(FloatParts256 *a) return ret; } -#define frac_normalize(A) FRAC_GENERIC_64_128_256(normalize, A)(A) - static void frac64_modrem(FloatParts64 *a, FloatParts64 *b, uint64_t *mod_quot) { uint64_t a0, a1, b0, t0, t1, q, quot; @@ -XXX,XX +XXX,XX @@ static void frac128_modrem(FloatParts128 *a, FloatParts128 *b, a->frac_lo = a1 | (a2 != 0); } -#define frac_modrem(A, B, Q) FRAC_GENERIC_64_128(modrem, A)(A, B, Q) - static void frac64_shl(FloatParts64 *a, int c) { a->frac <<= c; @@ -XXX,XX +XXX,XX @@ static void frac128_shl(FloatParts128 *a, int c) a->frac_lo = a1; } -#define frac_shl(A, C) FRAC_GENERIC_64_128(shl, A)(A, C) - static void frac64_shr(FloatParts64 *a, int c) { a->frac >>= c; @@ -XXX,XX +XXX,XX @@ static void frac128_shr(FloatParts128 *a, int c) a->frac_lo = a1; } -#define frac_shr(A, C) FRAC_GENERIC_64_128(shr, A)(A, C) - static void frac64_shrjam(FloatParts64 *a, int c) { uint64_t a0 = a->frac; @@ -XXX,XX +XXX,XX @@ static void frac256_shrjam(FloatParts256 *a, int c) a->frac_hi = a0; } -#define frac_shrjam(A, C) FRAC_GENERIC_64_128_256(shrjam, A)(A, C) - static bool frac64_sub(FloatParts64 *r, FloatParts64 *a, FloatParts64 *b) { return usub64_overflow(a->frac, b->frac, &r->frac); @@ -XXX,XX +XXX,XX @@ static bool frac256_sub(FloatParts256 *r, FloatParts256 *a, FloatParts256 *b) return c; } -#define frac_sub(R, A, B) FRAC_GENERIC_64_128_256(sub, R)(R, A, B) - static void frac64_truncjam(FloatParts64 *r, FloatParts128 *a) { r->frac = a->frac_hi | (a->frac_lo != 0); @@ -XXX,XX +XXX,XX @@ static void frac128_truncjam(FloatParts128 *r, FloatParts256 *a) r->frac_lo = a->frac_hm | ((a->frac_lm | a->frac_lo) != 0); } -#define frac_truncjam(R, A) FRAC_GENERIC_64_128(truncjam, R)(R, A) - static void frac64_widen(FloatParts128 *r, FloatParts64 *a) { r->frac_hi = a->frac; @@ -XXX,XX +XXX,XX @@ static void frac128_widen(FloatParts256 *r, FloatParts128 *a) r->frac_lo = 0; } -#define frac_widen(A, B) FRAC_GENERIC_64_128(widen, B)(A, B) - /* * Reciprocal sqrt table. 1 bit of exponent, 6-bits of mantessa. * From https://git.musl-libc.org/cgit/musl/tree/src/math/sqrt_data.c @@ -XXX,XX +XXX,XX @@ static const uint16_t rsqrt_tab[128] = { 0xba91, 0xb9cc, 0xb90a, 0xb84a, 0xb78c, 0xb6d0, 0xb617, 0xb560, }; +#define fracN(NAME) glue(glue(glue(frac,N),_),NAME) +#define fracW(NAME) glue(glue(glue(frac,W),_),NAME) #define partsN(NAME) glue(glue(glue(parts,N),_),NAME) #define partsW(NAME) glue(glue(glue(parts,W),_),NAME) #define FloatPartsN glue(FloatParts,N) @@ -XXX,XX +XXX,XX @@ static const uint16_t rsqrt_tab[128] = { #undef N #undef W +#undef fracN +#undef fracW #undef partsN #undef partsW #undef FloatPartsN @@ -XXX,XX +XXX,XX @@ static float64 float64r32_pack_raw(FloatParts64 *p) * The result is denormal for float32, but can be represented * in normalized form for float64. Adjust, per canonicalize. */ - int shift = frac_normalize(p); + int shift = frac64_normalize(p); p->exp = (float32_params.frac_shift - float32_params.exp_bias - shift + 1 + float64_params.exp_bias); - frac_shr(p, float64_params.frac_shift); + frac64_shr(p, float64_params.frac_shift); } else { - frac_shl(p, float32_params.frac_shift - float64_params.frac_shift); + frac64_shl(p, float32_params.frac_shift - float64_params.frac_shift); p->exp += float64_params.exp_bias - float32_params.exp_bias; } break; case float_class_snan: case float_class_qnan: - frac_shl(p, float32_params.frac_shift - float64_params.frac_shift); + frac64_shl(p, float32_params.frac_shift - float64_params.frac_shift); p->exp = float64_params.exp_max; break; case float_class_inf: @@ -XXX,XX +XXX,XX @@ static floatx80 floatx80_round_pack_canonical(FloatParts128 *p, p64.sign = p->sign; p64.exp = p->exp; - frac_truncjam(&p64, p); + frac64_truncjam(&p64, p); parts64_uncanon_normal(&p64, s, fmt, false); frac = p64.frac; exp = p64.exp; @@ -XXX,XX +XXX,XX @@ static void parts_float_to_float_narrow(FloatParts64 *a, FloatParts128 *b, float_raise(float_flag_input_denormal_used, s); /* fall through */ case float_class_normal: - frac_truncjam(a, b); + frac64_truncjam(a, b); break; case float_class_snan: case float_class_qnan: @@ -XXX,XX +XXX,XX @@ static void parts_float_to_float_widen(FloatParts128 *a, FloatParts64 *b, a->cls = b->cls; a->sign = b->sign; a->exp = b->exp; - frac_widen(a, b); + frac64_widen(a, b); if (is_nan(a->cls)) { parts128_return_nan(a, s); @@ -XXX,XX +XXX,XX @@ static void parts64_log2(FloatParts64 *a, float_status *s, const FloatFmt *fmt) FloatParts64 f = { .cls = float_class_normal, .frac = r }; - f.exp = f_exp - frac_normalize(&f); + f.exp = f_exp - frac64_normalize(&f); if (a_exp < 0) { parts64_sub_normal(a, &f); @@ -XXX,XX +XXX,XX @@ float128 float128_default_nan(float_status *status) FloatParts128 p; parts128_default_nan(&p, status); - frac_shr(&p, float128_params.frac_shift); + frac128_shr(&p, float128_params.frac_shift); return float128_pack_raw(&p); } @@ -XXX,XX +XXX,XX @@ float128 float128_silence_nan(float128 a, float_status *status) FloatParts128 p; float128_unpack_raw(&p, a); - frac_shl(&p, float128_params.frac_shift); + frac128_shl(&p, float128_params.frac_shift); parts128_silence_nan(&p, status); - frac_shr(&p, float128_params.frac_shift); + frac128_shr(&p, float128_params.frac_shift); return float128_pack_raw(&p); } diff --git a/fpu/softfloat-parts-addsub.c.inc b/fpu/softfloat-parts-addsub.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts-addsub.c.inc +++ b/fpu/softfloat-parts-addsub.c.inc @@ -XXX,XX +XXX,XX @@ static void partsN(add_normal)(FloatPartsN *a, FloatPartsN *b) int exp_diff = a->exp - b->exp; if (exp_diff > 0) { - frac_shrjam(b, exp_diff); + fracN(shrjam)(b, exp_diff); } else if (exp_diff < 0) { - frac_shrjam(a, -exp_diff); + fracN(shrjam)(a, -exp_diff); a->exp = b->exp; } - if (frac_add(a, a, b)) { - frac_shrjam(a, 1); + if (fracN(add)(a, a, b)) { + fracN(shrjam)(a, 1); a->frac_hi |= DECOMPOSED_IMPLICIT_BIT; a->exp += 1; } @@ -XXX,XX +XXX,XX @@ static bool partsN(sub_normal)(FloatPartsN *a, FloatPartsN *b) int shift; if (exp_diff > 0) { - frac_shrjam(b, exp_diff); - frac_sub(a, a, b); + fracN(shrjam)(b, exp_diff); + fracN(sub)(a, a, b); } else if (exp_diff < 0) { a->exp = b->exp; a->sign ^= 1; - frac_shrjam(a, -exp_diff); - frac_sub(a, b, a); - } else if (frac_sub(a, a, b)) { + fracN(shrjam)(a, -exp_diff); + fracN(sub)(a, b, a); + } else if (fracN(sub)(a, a, b)) { /* Overflow means that A was less than B. */ - frac_neg(a); + fracN(neg)(a); a->sign ^= 1; } - shift = frac_normalize(a); + shift = fracN(normalize)(a); if (likely(shift < N)) { a->exp -= shift; return true; 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)(FloatPartsN *a, FloatPartsN *b, ret = b; break; } - cmp = frac_cmp(a, b); + cmp = fracN(cmp)(a, b); if (cmp == 0) { cmp = a->sign < b->sign; } @@ -XXX,XX +XXX,XX @@ static void partsN(canonicalize)(FloatPartsN *p, float_status *status, (status->floatx80_behaviour & floatx80_pseudo_denormal_valid); if (unlikely(p->exp == 0)) { - if (likely(frac_eqz(p))) { + if (likely(fracN(eqz)(p))) { p->cls = float_class_zero; } else if (status->flush_inputs_to_zero) { float_raise(float_flag_input_denormal_flushed, status); p->cls = float_class_zero; - frac_clear(p); + fracN(clear)(p); } else { - int shift = frac_normalize(p); + int shift = fracN(normalize)(p); p->cls = float_class_denormal; p->exp = fmt->frac_shift - fmt->exp_bias - shift + !has_pseudo_denormals; @@ -XXX,XX +XXX,XX @@ static void partsN(canonicalize)(FloatPartsN *p, float_status *status, if (unlikely(p->exp == fmt->exp_max)) { switch (fmt->exp_max_kind) { case float_expmax_ieee: - if (likely(frac_eqz(p))) { + if (likely(fracN(eqz)(p))) { p->cls = float_class_inf; } else { - frac_shl(p, fmt->frac_shift); + fracN(shl)(p, fmt->frac_shift); p->cls = (parts_is_snan_frac(p->frac_hi, status) ? float_class_snan : float_class_qnan); } @@ -XXX,XX +XXX,XX @@ static void partsN(canonicalize)(FloatPartsN *p, float_status *status, break; case float_expmax_e4m3: if (p->frac_hi == 0b111) { - frac_shl(p, fmt->frac_shift); + fracN(shl)(p, fmt->frac_shift); p->cls = (parts_is_snan_frac(p->frac_hi, status) ? float_class_snan : float_class_qnan); return; @@ -XXX,XX +XXX,XX @@ static void partsN(canonicalize)(FloatPartsN *p, float_status *status, p->cls = float_class_normal; p->exp -= fmt->exp_bias; - frac_shl(p, fmt->frac_shift); + fracN(shl)(p, fmt->frac_shift); p->frac_hi |= DECOMPOSED_IMPLICIT_BIT; } @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, if (likely(exp > 0)) { if (p->frac_lo & round_mask) { flags |= float_flag_inexact; - if (frac_addi(p, p, inc)) { - frac_shr(p, 1); + if (fracN(addi)(p, p, inc)) { + fracN(shr)(p, 1); p->frac_hi |= DECOMPOSED_IMPLICIT_BIT; exp++; } @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, } else if (overflow_norm) { flags |= float_flag_inexact; exp = exp_max - 1; - frac_allones(p); + fracN(allones)(p); p->frac_lo &= ~round_mask; } else { flags |= float_flag_inexact; p->cls = float_class_inf; exp = exp_max; - frac_clear(p); + fracN(clear)(p); } break; @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, ? float_flag_invalid : float_flag_overflow | float_flag_inexact); exp = exp_max; - frac_allones(p); + fracN(allones)(p); p->frac_lo &= ~round_mask; } break; @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, g_assert_not_reached(); } } - frac_shr(p, frac_shift); + fracN(shr)(p, frac_shift); } else if (unlikely(s->rebias_underflow)) { flags |= float_flag_underflow; exp += fmt->exp_re_bias; if (p->frac_lo & round_mask) { flags |= float_flag_inexact; - if (frac_addi(p, p, inc)) { - frac_shr(p, 1); + if (fracN(addi)(p, p, inc)) { + fracN(shr)(p, 1); p->frac_hi |= DECOMPOSED_IMPLICIT_BIT; exp++; } p->frac_lo &= ~round_mask; } - frac_shr(p, frac_shift); + fracN(shr)(p, frac_shift); } else if (s->flush_to_zero && s->ftz_detection == float_ftz_before_rounding) { flags |= float_flag_output_denormal_flushed; p->cls = float_class_zero; exp = 0; - frac_clear(p); + fracN(clear)(p); } else { bool is_tiny = s->tininess_before_rounding || exp < 0; bool has_pseudo_denormals = fmt->has_explicit_bit && @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, if (!is_tiny) { FloatPartsN discard; - is_tiny = !frac_addi(&discard, p, inc); + is_tiny = !fracN(addi)(&discard, p, inc); } - frac_shrjam(p, !has_pseudo_denormals - exp); + fracN(shrjam)(p, !has_pseudo_denormals - exp); if (p->frac_lo & round_mask) { /* Need to recompute round-to-even/round-to-odd. */ @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, break; } flags |= float_flag_inexact; - frac_addi(p, p, inc); + fracN(addi)(p, p, inc); p->frac_lo &= ~round_mask; } exp = (p->frac_hi & DECOMPOSED_IMPLICIT_BIT) && !has_pseudo_denormals; - frac_shr(p, frac_shift); + fracN(shr)(p, frac_shift); if (is_tiny) { if (s->flush_to_zero) { @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, flags |= float_flag_output_denormal_flushed; p->cls = float_class_zero; exp = 0; - frac_clear(p); + fracN(clear)(p); } else if (flags & float_flag_inexact) { flags |= float_flag_underflow; } - if (exp == 0 && frac_eqz(p)) { + if (exp == 0 && fracN(eqz)(p)) { p->cls = float_class_zero; } } @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon)(FloatPartsN *p, float_status *s, switch (p->cls) { case float_class_zero: p->exp = 0; - frac_clear(p); + fracN(clear)(p); return; case float_class_inf: switch (fmt->exp_max_kind) { case float_expmax_ieee: p->exp = fmt->exp_max; - frac_clear(p); + fracN(clear)(p); break; case float_expmax_e4m3: partsN(uncanon_e4m3_overflow)(p, s, fmt, saturate); - frac_shr(p, fmt->frac_shift); + fracN(shr)(p, fmt->frac_shift); break; case float_expmax_normal: default: @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon)(FloatPartsN *p, float_status *s, case float_class_snan: assert(fmt->exp_max_kind != float_expmax_normal); p->exp = fmt->exp_max; - frac_shr(p, fmt->frac_shift); + fracN(shr)(p, fmt->frac_shift); return; default: break; @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(mul)(FloatPartsN *a, FloatPartsN *b, float_raise(float_flag_input_denormal_used, s); } - frac_mulw(&tmp, a, b); - frac_truncjam(a, &tmp); + fracN(mulw)(&tmp, a, b); + fracN(truncjam)(a, &tmp); a->exp += b->exp + 1; if (!(a->frac_hi & DECOMPOSED_IMPLICIT_BIT)) { - frac_add(a, a, a); + fracN(add)(a, a, a); a->exp -= 1; } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd_scalbn)(FloatPartsN *a, FloatPartsN *b, /* Perform the multiplication step. */ p_widen.sign = a->sign; p_widen.exp = a->exp + b->exp + 1; - frac_mulw(&p_widen, a, b); + fracN(mulw)(&p_widen, a, b); if (!(p_widen.frac_hi & DECOMPOSED_IMPLICIT_BIT)) { - frac_add(&p_widen, &p_widen, &p_widen); + 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. */ - frac_widen(&c_widen, c); + fracN(widen)(&c_widen, c); c_widen.exp = c->exp; if (a->sign == c->sign) { @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd_scalbn)(FloatPartsN *a, FloatPartsN *b, } /* Narrow with sticky bit, for proper rounding later. */ - frac_truncjam(a, &p_widen); + fracN(truncjam)(a, &p_widen); a->sign = p_widen.sign; a->exp = p_widen.exp; @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(div)(FloatPartsN *a, FloatPartsN *b, float_raise(float_flag_input_denormal_used, s); } a->sign = sign; - a->exp -= b->exp + frac_div(a, b); + a->exp -= b->exp + fracN(div)(a, b); return a; } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(modrem)(FloatPartsN *a, FloatPartsN *b, if (ab_mask & float_cmask_denormal) { float_raise(float_flag_input_denormal_used, s); } - frac_modrem(a, b, mod_quot); + fracN(modrem)(a, b, mod_quot); return a; } @@ -XXX,XX +XXX,XX @@ static void partsN(sqrt)(FloatPartsN *a, float_status *status, exp_odd = a->exp & 1; index = extract64(a->frac_hi, 57, 6) | (!exp_odd << 6); if (!exp_odd) { - frac_shr(a, 1); + fracN(shr)(a, 1); } /* @@ -XXX,XX +XXX,XX @@ static void partsN(sqrt)(FloatPartsN *a, float_status *status, /* Convert back from base 4 to base 2. */ a->exp >>= 1; if (!(a->frac_hi & DECOMPOSED_IMPLICIT_BIT)) { - frac_add(a, a, a); + fracN(add)(a, a, a); } else { a->exp += 1; } @@ -XXX,XX +XXX,XX @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode, if (a->exp == -1) { FloatPartsN tmp; /* Shift left one, discarding DECOMPOSED_IMPLICIT_BIT */ - frac_add(&tmp, a, a); + fracN(add)(&tmp, a, a); /* Anything remaining means frac > 0.5. */ - one = !frac_eqz(&tmp); + one = !fracN(eqz)(&tmp); } break; case float_round_ties_away: @@ -XXX,XX +XXX,XX @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode, g_assert_not_reached(); } - frac_clear(a); + fracN(clear)(a); a->exp = 0; if (one) { a->frac_hi = DECOMPOSED_IMPLICIT_BIT; @@ -XXX,XX +XXX,XX @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode, * which leaves room for sticky and rounding bit. */ shift_adj = (N - 1) - (a->exp + 2); - frac_shrjam(a, shift_adj); + fracN(shrjam)(a, shift_adj); frac_lsb = 1 << 2; } else { /* @@ -XXX,XX +XXX,XX @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode, if (!(a->frac_lo & rnd_mask)) { /* Fractional bits already clear, undo the shift above. */ - frac_shl(a, shift_adj); + fracN(shl)(a, shift_adj); return false; } @@ -XXX,XX +XXX,XX @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode, } if (shift_adj == 0) { - if (frac_addi(a, a, inc)) { - frac_shr(a, 1); + if (fracN(addi)(a, a, inc)) { + fracN(shr)(a, 1); a->frac_hi |= DECOMPOSED_IMPLICIT_BIT; a->exp++; } a->frac_lo &= ~rnd_mask; } else { - frac_addi(a, a, inc); + fracN(addi)(a, a, inc); a->frac_lo &= ~rnd_mask; /* Be careful shifting back, not to overflow */ - frac_shl(a, shift_adj - 1); + fracN(shl)(a, shift_adj - 1); if (a->frac_hi & DECOMPOSED_IMPLICIT_BIT) { a->exp++; } else { - frac_add(a, a, a); + fracN(add)(a, a, a); } } return true; @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b, /* Compare magnitudes. */ cmp = a_exp - b_exp; if (cmp == 0) { - cmp = frac_cmp(a, b); + cmp = fracN(cmp)(a, b); } /* @@ -XXX,XX +XXX,XX @@ static FloatRelation partsN(compare)(FloatPartsN *a, FloatPartsN *b, goto a_sign; } if (a->exp == b->exp) { - cmp = frac_cmp(a, b); + cmp = fracN(cmp)(a, b); } else if (a->exp < b->exp) { cmp = float_relation_less; } else { -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 53 +++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 22 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) * Helper functions for softfloat-parts.c.inc, per-size operations. */ -static bool frac64_add(FloatParts64 *r, FloatParts64 *a, FloatParts64 *b) +static bool frac64_add(FloatParts64 *r, + const FloatParts64 *a, const FloatParts64 *b) { return uadd64_overflow(a->frac, b->frac, &r->frac); } -static bool frac128_add(FloatParts128 *r, FloatParts128 *a, FloatParts128 *b) +static bool frac128_add(FloatParts128 *r, + const FloatParts128 *a, const FloatParts128 *b) { bool c = 0; r->frac_lo = uadd64_carry(a->frac_lo, b->frac_lo, &c); @@ -XXX,XX +XXX,XX @@ static bool frac128_add(FloatParts128 *r, FloatParts128 *a, FloatParts128 *b) return c; } -static bool frac256_add(FloatParts256 *r, FloatParts256 *a, FloatParts256 *b) +static bool frac256_add(FloatParts256 *r, + const FloatParts256 *a, const FloatParts256 *b) { bool c = 0; r->frac_lo = uadd64_carry(a->frac_lo, b->frac_lo, &c); @@ -XXX,XX +XXX,XX @@ static bool frac256_add(FloatParts256 *r, FloatParts256 *a, FloatParts256 *b) return c; } -static bool frac64_addi(FloatParts64 *r, FloatParts64 *a, uint64_t c) +static bool frac64_addi(FloatParts64 *r, const FloatParts64 *a, uint64_t c) { return uadd64_overflow(a->frac, c, &r->frac); } -static bool frac128_addi(FloatParts128 *r, FloatParts128 *a, uint64_t c) +static bool frac128_addi(FloatParts128 *r, const FloatParts128 *a, uint64_t c) { c = uadd64_overflow(a->frac_lo, c, &r->frac_lo); return uadd64_overflow(a->frac_hi, c, &r->frac_hi); @@ -XXX,XX +XXX,XX @@ static void frac128_allones(FloatParts128 *a) a->frac_hi = a->frac_lo = -1; } -static FloatRelation frac64_cmp(FloatParts64 *a, FloatParts64 *b) +static FloatRelation frac64_cmp(const FloatParts64 *a, const FloatParts64 *b) { return (a->frac == b->frac ? float_relation_equal : a->frac < b->frac ? float_relation_less : float_relation_greater); } -static FloatRelation frac128_cmp(FloatParts128 *a, FloatParts128 *b) +static FloatRelation frac128_cmp(const FloatParts128 *a, const FloatParts128 *b) { uint64_t ta = a->frac_hi, tb = b->frac_hi; if (ta == tb) { @@ -XXX,XX +XXX,XX @@ static void frac128_clear(FloatParts128 *a) a->frac_hi = a->frac_lo = 0; } -static bool frac64_div(FloatParts64 *a, FloatParts64 *b) +static bool frac64_div(FloatParts64 *a, const FloatParts64 *b) { uint64_t n1, n0, r, q; bool ret; @@ -XXX,XX +XXX,XX @@ static bool frac64_div(FloatParts64 *a, FloatParts64 *b) return ret; } -static bool frac128_div(FloatParts128 *a, FloatParts128 *b) +static bool frac128_div(FloatParts128 *a, const FloatParts128 *b) { uint64_t q0, q1, a0, a1, b0, b1; uint64_t r0, r1, r2, r3, t0, t1, t2, t3; @@ -XXX,XX +XXX,XX @@ static bool frac128_div(FloatParts128 *a, FloatParts128 *b) return ret; } -static bool frac64_eqz(FloatParts64 *a) +static bool frac64_eqz(const FloatParts64 *a) { return a->frac == 0; } -static bool frac128_eqz(FloatParts128 *a) +static bool frac128_eqz(const FloatParts128 *a) { return (a->frac_hi | a->frac_lo) == 0; } -static void frac64_mulw(FloatParts128 *r, FloatParts64 *a, FloatParts64 *b) +static void frac64_mulw(FloatParts128 *r, + const FloatParts64 *a, const FloatParts64 *b) { mulu64(&r->frac_lo, &r->frac_hi, a->frac, b->frac); } -static void frac128_mulw(FloatParts256 *r, FloatParts128 *a, FloatParts128 *b) +static void frac128_mulw(FloatParts256 *r, + const FloatParts128 *a, const FloatParts128 *b) { mul128To256(a->frac_hi, a->frac_lo, b->frac_hi, b->frac_lo, &r->frac_hi, &r->frac_hm, &r->frac_lm, &r->frac_lo); @@ -XXX,XX +XXX,XX @@ static int frac256_normalize(FloatParts256 *a) return ret; } -static void frac64_modrem(FloatParts64 *a, FloatParts64 *b, uint64_t *mod_quot) +static void frac64_modrem(FloatParts64 *a, const FloatParts64 *b, + uint64_t *mod_quot) { uint64_t a0, a1, b0, t0, t1, q, quot; int exp_diff = a->exp - b->exp; @@ -XXX,XX +XXX,XX @@ static void frac64_modrem(FloatParts64 *a, FloatParts64 *b, uint64_t *mod_quot) a->frac = a0 | (a1 != 0); } -static void frac128_modrem(FloatParts128 *a, FloatParts128 *b, +static void frac128_modrem(FloatParts128 *a, const FloatParts128 *b, uint64_t *mod_quot) { uint64_t a0, a1, a2, b0, b1, t0, t1, t2, q, quot; @@ -XXX,XX +XXX,XX @@ static void frac256_shrjam(FloatParts256 *a, int c) a->frac_hi = a0; } -static bool frac64_sub(FloatParts64 *r, FloatParts64 *a, FloatParts64 *b) +static bool frac64_sub(FloatParts64 *r, + const FloatParts64 *a, const FloatParts64 *b) { return usub64_overflow(a->frac, b->frac, &r->frac); } -static bool frac128_sub(FloatParts128 *r, FloatParts128 *a, FloatParts128 *b) +static bool frac128_sub(FloatParts128 *r, + const FloatParts128 *a, const FloatParts128 *b) { bool c = 0; r->frac_lo = usub64_borrow(a->frac_lo, b->frac_lo, &c); @@ -XXX,XX +XXX,XX @@ static bool frac128_sub(FloatParts128 *r, FloatParts128 *a, FloatParts128 *b) return c; } -static bool frac256_sub(FloatParts256 *r, FloatParts256 *a, FloatParts256 *b) +static bool frac256_sub(FloatParts256 *r, + const FloatParts256 *a, const FloatParts256 *b) { bool c = 0; r->frac_lo = usub64_borrow(a->frac_lo, b->frac_lo, &c); @@ -XXX,XX +XXX,XX @@ static bool frac256_sub(FloatParts256 *r, FloatParts256 *a, FloatParts256 *b) return c; } -static void frac64_truncjam(FloatParts64 *r, FloatParts128 *a) +static void frac64_truncjam(FloatParts64 *r, const FloatParts128 *a) { r->frac = a->frac_hi | (a->frac_lo != 0); } -static void frac128_truncjam(FloatParts128 *r, FloatParts256 *a) +static void frac128_truncjam(FloatParts128 *r, const FloatParts256 *a) { r->frac_hi = a->frac_hi; r->frac_lo = a->frac_hm | ((a->frac_lm | a->frac_lo) != 0); } -static void frac64_widen(FloatParts128 *r, FloatParts64 *a) +static void frac64_widen(FloatParts128 *r, const FloatParts64 *a) { r->frac_hi = a->frac; r->frac_lo = 0; } -static void frac128_widen(FloatParts256 *r, FloatParts128 *a) +static void frac128_widen(FloatParts256 *r, const FloatParts128 *a) { r->frac_hi = a->frac_hi; r->frac_hm = a->frac_lo; -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 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 const FloatFmt floatx80_params[3] = { }; /* Unpack a float to parts, but do not canonicalize. */ -static void unpack_raw64(FloatParts64 *r, const FloatFmt *fmt, uint64_t raw) +static FloatParts64 unpack_raw64(const FloatFmt *fmt, uint64_t raw) { const int f_size = fmt->frac_size; const int e_size = fmt->exp_size; - *r = (FloatParts64) { + return (FloatParts64) { .cls = float_class_unclassified, .sign = extract64(raw, f_size + e_size, 1), .exp = extract64(raw, f_size, e_size), @@ -XXX,XX +XXX,XX @@ static void unpack_raw64(FloatParts64 *r, const FloatFmt *fmt, uint64_t raw) static void QEMU_FLATTEN float4_e2m1_unpack_raw(FloatParts64 *p, float4_e2m1 f) { - unpack_raw64(p, &float4_e2m1_params, f); + *p = unpack_raw64(&float4_e2m1_params, f); } static void QEMU_FLATTEN float8_e4m3_unpack_raw(FloatParts64 *p, float8_e4m3 f) { - unpack_raw64(p, &float8_e4m3_params, f); + *p = unpack_raw64(&float8_e4m3_params, f); } static void QEMU_FLATTEN float8_e5m2_unpack_raw(FloatParts64 *p, float8_e5m2 f) { - unpack_raw64(p, &float8_e5m2_params, f); + *p = unpack_raw64(&float8_e5m2_params, f); } static void QEMU_FLATTEN float16_unpack_raw(FloatParts64 *p, float16 f) { - unpack_raw64(p, &float16_params, f); + *p = unpack_raw64(&float16_params, f); } static void QEMU_FLATTEN bfloat16_unpack_raw(FloatParts64 *p, bfloat16 f) { - unpack_raw64(p, &bfloat16_params, f); + *p = unpack_raw64(&bfloat16_params, f); } static void QEMU_FLATTEN float32_unpack_raw(FloatParts64 *p, float32 f) { - unpack_raw64(p, &float32_params, f); + *p = unpack_raw64(&float32_params, f); } static void QEMU_FLATTEN float64_unpack_raw(FloatParts64 *p, float64 f) { - unpack_raw64(p, &float64_params, f); + *p = unpack_raw64(&float64_params, f); } static void QEMU_FLATTEN floatx80_unpack_raw(FloatParts128 *p, floatx80 f) -- 2.43.0
Inline float4_e2m1_unpack_raw at the same time. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 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 FloatParts64 unpack_raw64(const FloatFmt *fmt, uint64_t raw) }; } -static void QEMU_FLATTEN float4_e2m1_unpack_raw(FloatParts64 *p, float4_e2m1 f) -{ - *p = unpack_raw64(&float4_e2m1_params, f); -} - static void QEMU_FLATTEN float8_e4m3_unpack_raw(FloatParts64 *p, float8_e4m3 f) { *p = unpack_raw64(&float8_e4m3_params, f); @@ -XXX,XX +XXX,XX @@ static const uint16_t rsqrt_tab[128] = { * Pack/unpack routines with a specific FloatFmt. */ -static void float4_e2m1_unpack_canonical(FloatParts64 *p, float4_e2m1 f, - float_status *s) +static FloatParts64 float4_e2m1_unpack_canonical(float4_e2m1 f, float_status *s) { - float4_e2m1_unpack_raw(p, f); - parts64_canonicalize(p, s, &float4_e2m1_params); + FloatParts64 p = unpack_raw64(&float4_e2m1_params, f); + parts64_canonicalize(&p, s, &float4_e2m1_params); + return p; } static void float8_e4m3_unpack_canonical(FloatParts64 *p, float8_e4m3 f, @@ -XXX,XX +XXX,XX @@ static void parts_float_to_float_widen(FloatParts128 *a, FloatParts64 *b, float8_e4m3 float4_e2m1_to_float8_e4m3(float4_e2m1 a, float_status *s) { - FloatParts64 p; - - float4_e2m1_unpack_canonical(&p, a, s); + FloatParts64 p = float4_e2m1_unpack_canonical(a, s); parts64_float_to_float(&p, s); return float8_e4m3_round_pack_canonical(&p, s, false); } -- 2.43.0
Inline float8_e4m3_unpack_raw at the same time. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 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 FloatParts64 unpack_raw64(const FloatFmt *fmt, uint64_t raw) }; } -static void QEMU_FLATTEN float8_e4m3_unpack_raw(FloatParts64 *p, float8_e4m3 f) -{ - *p = unpack_raw64(&float8_e4m3_params, f); -} - static void QEMU_FLATTEN float8_e5m2_unpack_raw(FloatParts64 *p, float8_e5m2 f) { *p = unpack_raw64(&float8_e5m2_params, f); @@ -XXX,XX +XXX,XX @@ static FloatParts64 float4_e2m1_unpack_canonical(float4_e2m1 f, float_status *s) return p; } -static void float8_e4m3_unpack_canonical(FloatParts64 *p, float8_e4m3 f, - float_status *s) +static FloatParts64 float8_e4m3_unpack_canonical(float8_e4m3 f, float_status *s) { - float8_e4m3_unpack_raw(p, f); - parts64_canonicalize(p, s, &float8_e4m3_params); + FloatParts64 p = unpack_raw64(&float8_e4m3_params, f); + parts64_canonicalize(&p, s, &float8_e4m3_params); + return p; } static void float8_e5m2_unpack_canonical(FloatParts64 *p, float8_e5m2 f, @@ -XXX,XX +XXX,XX @@ float8_e4m3 float4_e2m1_to_float8_e4m3(float4_e2m1 a, float_status *s) bfloat16 float8_e4m3_to_bfloat16(float8_e4m3 a, float_status *s) { - FloatParts64 p; - - float8_e4m3_unpack_canonical(&p, a, s); + FloatParts64 p = float8_e4m3_unpack_canonical(a, s); parts64_float_to_float(&p, s); return bfloat16_round_pack_canonical(&p, s); } -- 2.43.0
Inline float8_e5m2_unpack_raw at the same time. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 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 FloatParts64 unpack_raw64(const FloatFmt *fmt, uint64_t raw) }; } -static void QEMU_FLATTEN float8_e5m2_unpack_raw(FloatParts64 *p, float8_e5m2 f) -{ - *p = unpack_raw64(&float8_e5m2_params, f); -} - static void QEMU_FLATTEN float16_unpack_raw(FloatParts64 *p, float16 f) { *p = unpack_raw64(&float16_params, f); @@ -XXX,XX +XXX,XX @@ static FloatParts64 float8_e4m3_unpack_canonical(float8_e4m3 f, float_status *s) return p; } -static void float8_e5m2_unpack_canonical(FloatParts64 *p, float8_e5m2 f, - float_status *s) +static FloatParts64 float8_e5m2_unpack_canonical(float8_e5m2 f, float_status *s) { - float8_e5m2_unpack_raw(p, f); - parts64_canonicalize(p, s, &float8_e5m2_params); + FloatParts64 p = unpack_raw64(&float8_e5m2_params, f); + parts64_canonicalize(&p, s, &float8_e5m2_params); + return p; } static void float16a_unpack_canonical(FloatParts64 *p, float16 f, @@ -XXX,XX +XXX,XX @@ bfloat16 float8_e4m3_to_bfloat16(float8_e4m3 a, float_status *s) bfloat16 float8_e5m2_to_bfloat16(float8_e5m2 a, float_status *s) { - FloatParts64 p; - - float8_e5m2_unpack_canonical(&p, a, s); + FloatParts64 p = float8_e5m2_unpack_canonical(a, s); parts64_float_to_float(&p, s); return bfloat16_round_pack_canonical(&p, s); } -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 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 FloatParts64 unpack_raw64(const FloatFmt *fmt, uint64_t raw) }; } -static void QEMU_FLATTEN float16_unpack_raw(FloatParts64 *p, float16 f) -{ - *p = unpack_raw64(&float16_params, f); -} - static void QEMU_FLATTEN bfloat16_unpack_raw(FloatParts64 *p, bfloat16 f) { *p = unpack_raw64(&bfloat16_params, f); @@ -XXX,XX +XXX,XX @@ static FloatParts64 float8_e5m2_unpack_canonical(float8_e5m2 f, float_status *s) static void float16a_unpack_canonical(FloatParts64 *p, float16 f, float_status *s, const FloatFmt *params) { - float16_unpack_raw(p, f); + *p = unpack_raw64(&float16_params, f); parts64_canonicalize(p, s, params); } @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_default_nan(float_status *status) float16 float16_silence_nan(float16 a, float_status *status) { - FloatParts64 p; + FloatParts64 p = unpack_raw64(&float16_params, a); - float16_unpack_raw(&p, a); p.frac <<= float16_params.frac_shift; parts64_silence_nan(&p, status); p.frac >>= float16_params.frac_shift; @@ -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) { - FloatParts64 p; + FloatParts64 p = unpack_raw64(&float16_params, a); - float16_unpack_raw(&p, a); if (parts_squash_denormal(p, status)) { return float16_set_sign(float16_zero, p.sign); } -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 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 FloatParts64 float8_e5m2_unpack_canonical(float8_e5m2 f, float_status *s) return p; } -static void float16a_unpack_canonical(FloatParts64 *p, float16 f, - float_status *s, const FloatFmt *params) +static FloatParts64 float16a_unpack_canonical(float16 f, float_status *s, + const FloatFmt *params) { - *p = unpack_raw64(&float16_params, f); - parts64_canonicalize(p, s, params); + FloatParts64 p = unpack_raw64(&float16_params, f); + parts64_canonicalize(&p, s, params); + return p; } static void float16_unpack_canonical(FloatParts64 *p, float16 f, float_status *s) { - float16a_unpack_canonical(p, f, s, &float16_params); + *p = float16a_unpack_canonical(f, s, &float16_params); } static void bfloat16_unpack_canonical(FloatParts64 *p, bfloat16 f, @@ -XXX,XX +XXX,XX @@ bfloat16 float8_e5m2_to_bfloat16(float8_e5m2 a, float_status *s) float32 float16_to_float32(float16 a, bool ieee, float_status *s) { const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp; - FloatParts64 p; + FloatParts64 p = float16a_unpack_canonical(a, s, fmt16); - float16a_unpack_canonical(&p, a, s, fmt16); parts64_float_to_float(&p, s); return float32_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ float32 float16_to_float32(float16 a, bool ieee, float_status *s) float64 float16_to_float64(float16 a, bool ieee, float_status *s) { const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp; - FloatParts64 p; + FloatParts64 p = float16a_unpack_canonical(a, s, fmt16); - float16a_unpack_canonical(&p, a, s, fmt16); parts64_float_to_float(&p, s); return float64_round_pack_canonical(&p, s); } -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 94 +++++++++++++++++-------------------------------- 1 file changed, 32 insertions(+), 62 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 FloatParts64 float16a_unpack_canonical(float16 f, float_status *s, return p; } -static void float16_unpack_canonical(FloatParts64 *p, float16 f, - float_status *s) +static FloatParts64 float16_unpack_canonical(float16 f, float_status *s) { - *p = float16a_unpack_canonical(f, s, &float16_params); + return float16a_unpack_canonical(f, s, &float16_params); } static void bfloat16_unpack_canonical(FloatParts64 *p, bfloat16 f, @@ -XXX,XX +XXX,XX @@ static floatx80 floatx80_round_pack_canonical(FloatParts128 *p, static float16 QEMU_FLATTEN float16_addsub(float16 a, float16 b, float_status *status, bool subtract) { - FloatParts64 pa, pb, *pr; - - float16_unpack_canonical(&pa, a, status); - float16_unpack_canonical(&pb, b, status); - pr = parts64_addsub(&pa, &pb, status, subtract); + FloatParts64 pa = float16_unpack_canonical(a, status); + FloatParts64 pb = float16_unpack_canonical(b, status); + FloatParts64 *pr = parts64_addsub(&pa, &pb, status, subtract); return float16_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sub(floatx80 a, floatx80 b, float_status *status) float16 QEMU_FLATTEN float16_mul(float16 a, float16 b, float_status *status) { - FloatParts64 pa, pb, *pr; - - float16_unpack_canonical(&pa, a, status); - float16_unpack_canonical(&pb, b, status); - pr = parts64_mul(&pa, &pb, status); + FloatParts64 pa = float16_unpack_canonical(a, status); + FloatParts64 pb = float16_unpack_canonical(b, status); + FloatParts64 *pr = parts64_mul(&pa, &pb, status); return float16_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float16 QEMU_FLATTEN float16_muladd_scalbn(float16 a, float16 b, float16 c, int scale, int flags, float_status *status) { - FloatParts64 pa, pb, pc, *pr; - - float16_unpack_canonical(&pa, a, status); - float16_unpack_canonical(&pb, b, status); - float16_unpack_canonical(&pc, c, status); - pr = parts64_muladd_scalbn(&pa, &pb, &pc, scale, flags, status); + 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_scalbn(&pa, &pb, &pc, scale, flags, status); /* Round before applying negate result. */ parts64_uncanon(pr, status, &float16_params, false); @@ -XXX,XX +XXX,XX @@ float128 QEMU_FLATTEN float128_muladd(float128 a, float128 b, float128 c, float16 float16_div(float16 a, float16 b, float_status *status) { - FloatParts64 pa, pb, *pr; - - float16_unpack_canonical(&pa, a, status); - float16_unpack_canonical(&pb, b, status); - pr = parts64_div(&pa, &pb, status); + FloatParts64 pa = float16_unpack_canonical(a, status); + FloatParts64 pb = float16_unpack_canonical(b, status); + FloatParts64 *pr = parts64_div(&pa, &pb, status); return float16_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ floatx80 float128_to_floatx80(float128 a, float_status *s) float16 float16_round_to_int(float16 a, float_status *s) { - FloatParts64 p; + FloatParts64 p = float16_unpack_canonical(a, s); - float16_unpack_canonical(&p, a, s); parts64_round_to_int(&p, s->float_rounding_mode, 0, s, &float16_params); return float16_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status) int8_t float16_to_int8_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float16_unpack_canonical(&p, a, s); + FloatParts64 p = float16_unpack_canonical(a, s); return parts64_float_to_sint(&p, rmode, scale, INT8_MIN, INT8_MAX, s); } int16_t float16_to_int16_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float16_unpack_canonical(&p, a, s); + FloatParts64 p = float16_unpack_canonical(a, s); return parts64_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s); } int32_t float16_to_int32_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float16_unpack_canonical(&p, a, s); + FloatParts64 p = float16_unpack_canonical(a, s); return parts64_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); } int64_t float16_to_int64_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float16_unpack_canonical(&p, a, s); + FloatParts64 p = float16_unpack_canonical(a, s); return parts64_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } @@ -XXX,XX +XXX,XX @@ int64_t float64_to_int64_modulo(float64 a, FloatRoundMode rmode, uint8_t float16_to_uint8_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float16_unpack_canonical(&p, a, s); + FloatParts64 p = float16_unpack_canonical(a, s); return parts64_float_to_uint(&p, rmode, scale, UINT8_MAX, s); } uint16_t float16_to_uint16_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float16_unpack_canonical(&p, a, s); + FloatParts64 p = float16_unpack_canonical(a, s); return parts64_float_to_uint(&p, rmode, scale, UINT16_MAX, s); } uint32_t float16_to_uint32_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float16_unpack_canonical(&p, a, s); + FloatParts64 p = float16_unpack_canonical(a, s); return parts64_float_to_uint(&p, rmode, scale, UINT32_MAX, s); } uint64_t float16_to_uint64_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float16_unpack_canonical(&p, a, s); + FloatParts64 p = float16_unpack_canonical(a, s); return parts64_float_to_uint(&p, rmode, scale, UINT64_MAX, s); } @@ -XXX,XX +XXX,XX @@ float128 uint128_to_float128(Int128 a, float_status *status) static float16 float16_minmax(float16 a, float16 b, float_status *s, int flags) { - FloatParts64 pa, pb, *pr; - - float16_unpack_canonical(&pa, a, s); - float16_unpack_canonical(&pb, b, s); - pr = parts64_minmax(&pa, &pb, s, flags); + FloatParts64 pa = float16_unpack_canonical(a, s); + FloatParts64 pb = float16_unpack_canonical(b, s); + FloatParts64 *pr = parts64_minmax(&pa, &pb, s, flags); return float16_round_pack_canonical(pr, s); } @@ -XXX,XX +XXX,XX @@ MINMAX_2(float128) static FloatRelation QEMU_FLATTEN float16_do_compare(float16 a, float16 b, float_status *s, bool is_quiet) { - FloatParts64 pa, pb; + FloatParts64 pa = float16_unpack_canonical(a, s); + FloatParts64 pb = float16_unpack_canonical(b, s); - float16_unpack_canonical(&pa, a, s); - float16_unpack_canonical(&pb, b, s); return parts64_compare(&pa, &pb, s, is_quiet); } @@ -XXX,XX +XXX,XX @@ FloatRelation floatx80_compare_quiet(floatx80 a, floatx80 b, float_status *s) float16 float16_scalbn(float16 a, int n, float_status *status) { - FloatParts64 p; + FloatParts64 p = float16_unpack_canonical(a, status); - float16_unpack_canonical(&p, a, status); parts64_scalbn(&p, n, status); return float16_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_scalbn(floatx80 a, int n, float_status *status) float16 QEMU_FLATTEN float16_sqrt(float16 a, float_status *status) { - FloatParts64 p; + FloatParts64 p = float16_unpack_canonical(a, status); - float16_unpack_canonical(&p, a, status); parts64_sqrt(&p, status, &float16_params); return float16_round_pack_canonical(&p, status); } -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 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 FloatParts64 unpack_raw64(const FloatFmt *fmt, uint64_t raw) }; } -static void QEMU_FLATTEN bfloat16_unpack_raw(FloatParts64 *p, bfloat16 f) -{ - *p = unpack_raw64(&bfloat16_params, f); -} - static void QEMU_FLATTEN float32_unpack_raw(FloatParts64 *p, float32 f) { *p = unpack_raw64(&float32_params, f); @@ -XXX,XX +XXX,XX @@ static FloatParts64 float16_unpack_canonical(float16 f, float_status *s) static void bfloat16_unpack_canonical(FloatParts64 *p, bfloat16 f, float_status *s) { - bfloat16_unpack_raw(p, f); + *p = unpack_raw64(&bfloat16_params, f); parts64_canonicalize(p, s, &bfloat16_params); } @@ -XXX,XX +XXX,XX @@ float64 float64_silence_nan(float64 a, float_status *status) bfloat16 bfloat16_silence_nan(bfloat16 a, float_status *status) { - FloatParts64 p; + FloatParts64 p = unpack_raw64(&bfloat16_params, a); - bfloat16_unpack_raw(&p, a); p.frac <<= bfloat16_params.frac_shift; parts64_silence_nan(&p, status); p.frac >>= bfloat16_params.frac_shift; @@ -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) { - FloatParts64 p; + FloatParts64 p = unpack_raw64(&bfloat16_params, a); - bfloat16_unpack_raw(&p, a); if (parts_squash_denormal(p, status)) { return bfloat16_set_sign(bfloat16_zero, p.sign); } -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 108 +++++++++++++++++------------------------------- 1 file changed, 37 insertions(+), 71 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 FloatParts64 float16_unpack_canonical(float16 f, float_status *s) return float16a_unpack_canonical(f, s, &float16_params); } -static void bfloat16_unpack_canonical(FloatParts64 *p, bfloat16 f, - float_status *s) +static FloatParts64 bfloat16_unpack_canonical(bfloat16 f, float_status *s) { - *p = unpack_raw64(&bfloat16_params, f); - parts64_canonicalize(p, s, &bfloat16_params); + FloatParts64 p = unpack_raw64(&bfloat16_params, f); + parts64_canonicalize(&p, s, &bfloat16_params); + return p; } static float8_e4m3 float8_e4m3_round_pack_canonical(FloatParts64 *p, @@ -XXX,XX +XXX,XX @@ float64 float64r32_sub(float64 a, float64 b, float_status *status) static bfloat16 QEMU_FLATTEN bfloat16_addsub(bfloat16 a, bfloat16 b, float_status *status, bool subtract) { - FloatParts64 pa, pb, *pr; - - bfloat16_unpack_canonical(&pa, a, status); - bfloat16_unpack_canonical(&pb, b, status); - pr = parts64_addsub(&pa, &pb, status, subtract); + FloatParts64 pa = bfloat16_unpack_canonical(a, status); + FloatParts64 pb = bfloat16_unpack_canonical(b, status); + FloatParts64 *pr = parts64_addsub(&pa, &pb, status, subtract); return bfloat16_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float64 float64r32_mul(float64 a, float64 b, float_status *status) bfloat16 QEMU_FLATTEN bfloat16_mul(bfloat16 a, bfloat16 b, float_status *status) { - FloatParts64 pa, pb, *pr; - - bfloat16_unpack_canonical(&pa, a, status); - bfloat16_unpack_canonical(&pb, b, status); - pr = parts64_mul(&pa, &pb, status); + FloatParts64 pa = bfloat16_unpack_canonical(a, status); + FloatParts64 pb = bfloat16_unpack_canonical(b, status); + FloatParts64 *pr = parts64_mul(&pa, &pb, status); return bfloat16_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float64 float64r32_muladd(float64 a, float64 b, float64 c, bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, int flags, float_status *status) { - FloatParts64 pa, pb, pc, *pr; - - bfloat16_unpack_canonical(&pa, a, status); - bfloat16_unpack_canonical(&pb, b, status); - bfloat16_unpack_canonical(&pc, c, status); - pr = parts64_muladd_scalbn(&pa, &pb, &pc, 0, flags, status); + 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_scalbn(&pa, &pb, &pc, 0, flags, status); /* Round before applying negate result. */ parts64_uncanon(pr, status, &bfloat16_params, false); @@ -XXX,XX +XXX,XX @@ float64 float64r32_div(float64 a, float64 b, float_status *status) bfloat16 QEMU_FLATTEN bfloat16_div(bfloat16 a, bfloat16 b, float_status *status) { - FloatParts64 pa, pb, *pr; - - bfloat16_unpack_canonical(&pa, a, status); - bfloat16_unpack_canonical(&pb, b, status); - pr = parts64_div(&pa, &pb, status); + FloatParts64 pa = bfloat16_unpack_canonical(a, status); + FloatParts64 pb = bfloat16_unpack_canonical(b, status); + FloatParts64 *pr = parts64_div(&pa, &pb, status); return bfloat16_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float32 float64_to_float32(float64 a, float_status *s) float8_e4m3 bfloat16_to_float8_e4m3(bfloat16 a, bool saturate, float_status *s) { - FloatParts64 p; + FloatParts64 p = bfloat16_unpack_canonical(a, s); - bfloat16_unpack_canonical(&p, a, s); parts64_float_to_float(&p, s); return float8_e4m3_round_pack_canonical(&p, s, saturate); } float8_e5m2 bfloat16_to_float8_e5m2(bfloat16 a, bool saturate, float_status *s) { - FloatParts64 p; + FloatParts64 p = bfloat16_unpack_canonical(a, s); - bfloat16_unpack_canonical(&p, a, s); parts_float_to_e5m2(&p, s, saturate); return float8_e5m2_round_pack_canonical(&p, s, saturate); } float32 bfloat16_to_float32(bfloat16 a, float_status *s) { - FloatParts64 p; + FloatParts64 p = bfloat16_unpack_canonical(a, s); - bfloat16_unpack_canonical(&p, a, s); parts64_float_to_float(&p, s); return float32_round_pack_canonical(&p, s); } float64 bfloat16_to_float64(bfloat16 a, float_status *s) { - FloatParts64 p; + FloatParts64 p = bfloat16_unpack_canonical(a, s); - bfloat16_unpack_canonical(&p, a, s); parts64_float_to_float(&p, s); return float64_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ float64 float64_round_to_int(float64 a, float_status *s) bfloat16 bfloat16_round_to_int(bfloat16 a, float_status *s) { - FloatParts64 p; + FloatParts64 p = bfloat16_unpack_canonical(a, s); - bfloat16_unpack_canonical(&p, a, s); parts64_round_to_int(&p, s->float_rounding_mode, 0, s, &bfloat16_params); return bfloat16_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ int64_t float64_to_int64_scalbn(float64 a, FloatRoundMode rmode, int scale, int8_t bfloat16_to_int8_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - bfloat16_unpack_canonical(&p, a, s); + FloatParts64 p = bfloat16_unpack_canonical(a, s); return parts64_float_to_sint(&p, rmode, scale, INT8_MIN, INT8_MAX, s); } int16_t bfloat16_to_int16_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - bfloat16_unpack_canonical(&p, a, s); + FloatParts64 p = bfloat16_unpack_canonical(a, s); return parts64_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s); } int32_t bfloat16_to_int32_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - bfloat16_unpack_canonical(&p, a, s); + FloatParts64 p = bfloat16_unpack_canonical(a, s); return parts64_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); } int64_t bfloat16_to_int64_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - bfloat16_unpack_canonical(&p, a, s); + FloatParts64 p = bfloat16_unpack_canonical(a, s); return parts64_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } @@ -XXX,XX +XXX,XX @@ uint64_t float64_to_uint64_scalbn(float64 a, FloatRoundMode rmode, int scale, uint8_t bfloat16_to_uint8_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - bfloat16_unpack_canonical(&p, a, s); + FloatParts64 p = bfloat16_unpack_canonical(a, s); return parts64_float_to_uint(&p, rmode, scale, UINT8_MAX, s); } uint16_t bfloat16_to_uint16_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - bfloat16_unpack_canonical(&p, a, s); + FloatParts64 p = bfloat16_unpack_canonical(a, s); return parts64_float_to_uint(&p, rmode, scale, UINT16_MAX, s); } uint32_t bfloat16_to_uint32_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - bfloat16_unpack_canonical(&p, a, s); + FloatParts64 p = bfloat16_unpack_canonical(a, s); return parts64_float_to_uint(&p, rmode, scale, UINT32_MAX, s); } uint64_t bfloat16_to_uint64_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - bfloat16_unpack_canonical(&p, a, s); + FloatParts64 p = bfloat16_unpack_canonical(a, s); return parts64_float_to_uint(&p, rmode, scale, UINT64_MAX, s); } @@ -XXX,XX +XXX,XX @@ static float16 float16_minmax(float16 a, float16 b, float_status *s, int flags) static bfloat16 bfloat16_minmax(bfloat16 a, bfloat16 b, float_status *s, int flags) { - FloatParts64 pa, pb, *pr; - - bfloat16_unpack_canonical(&pa, a, s); - bfloat16_unpack_canonical(&pb, b, s); - pr = parts64_minmax(&pa, &pb, s, flags); + FloatParts64 pa = bfloat16_unpack_canonical(a, s); + FloatParts64 pb = bfloat16_unpack_canonical(b, s); + FloatParts64 *pr = parts64_minmax(&pa, &pb, s, flags); return bfloat16_round_pack_canonical(pr, s); } @@ -XXX,XX +XXX,XX @@ FloatRelation float64_compare_quiet(float64 a, float64 b, float_status *s) static FloatRelation QEMU_FLATTEN bfloat16_do_compare(bfloat16 a, bfloat16 b, float_status *s, bool is_quiet) { - FloatParts64 pa, pb; + FloatParts64 pa = bfloat16_unpack_canonical(a, s); + FloatParts64 pb = bfloat16_unpack_canonical(b, s); - bfloat16_unpack_canonical(&pa, a, s); - bfloat16_unpack_canonical(&pb, b, s); return parts64_compare(&pa, &pb, s, is_quiet); } @@ -XXX,XX +XXX,XX @@ float64 float64_scalbn(float64 a, int n, float_status *status) bfloat16 bfloat16_scalbn(bfloat16 a, int n, float_status *status) { - FloatParts64 p; + FloatParts64 p = bfloat16_unpack_canonical(a, status); - bfloat16_unpack_canonical(&p, a, status); parts64_scalbn(&p, n, status); return bfloat16_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float64 float64r32_sqrt(float64 a, float_status *status) bfloat16 QEMU_FLATTEN bfloat16_sqrt(bfloat16 a, float_status *status) { - FloatParts64 p; + FloatParts64 p = bfloat16_unpack_canonical(a, status); - bfloat16_unpack_canonical(&p, a, status); parts64_sqrt(&p, status, &bfloat16_params); return bfloat16_round_pack_canonical(&p, status); } -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 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 FloatParts64 unpack_raw64(const FloatFmt *fmt, uint64_t raw) }; } -static void QEMU_FLATTEN float32_unpack_raw(FloatParts64 *p, float32 f) -{ - *p = unpack_raw64(&float32_params, f); -} - static void QEMU_FLATTEN float64_unpack_raw(FloatParts64 *p, float64 f) { *p = unpack_raw64(&float64_params, f); @@ -XXX,XX +XXX,XX @@ static bfloat16 bfloat16_round_pack_canonical(FloatParts64 *p, static void float32_unpack_canonical(FloatParts64 *p, float32 f, float_status *s) { - float32_unpack_raw(p, f); + *p = unpack_raw64(&float32_params, f); parts64_canonicalize(p, s, &float32_params); } @@ -XXX,XX +XXX,XX @@ float16 float16_silence_nan(float16 a, float_status *status) float32 float32_silence_nan(float32 a, float_status *status) { - FloatParts64 p; + FloatParts64 p = unpack_raw64(&float32_params, a); - float32_unpack_raw(&p, a); p.frac <<= float32_params.frac_shift; parts64_silence_nan(&p, status); p.frac >>= float32_params.frac_shift; @@ -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) { - FloatParts64 p; + FloatParts64 p = unpack_raw64(&float32_params, a); - float32_unpack_raw(&p, a); if (parts_squash_denormal(p, status)) { return float32_set_sign(float32_zero, p.sign); } -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 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 FloatParts64 unpack_raw64(const FloatFmt *fmt, uint64_t raw) }; } -static void QEMU_FLATTEN float64_unpack_raw(FloatParts64 *p, float64 f) -{ - *p = unpack_raw64(&float64_params, f); -} - static void QEMU_FLATTEN floatx80_unpack_raw(FloatParts128 *p, floatx80 f) { *p = (FloatParts128) { @@ -XXX,XX +XXX,XX @@ static float32 float32_round_pack_canonical(FloatParts64 *p, static void float64_unpack_canonical(FloatParts64 *p, float64 f, float_status *s) { - float64_unpack_raw(p, f); + *p = unpack_raw64(&float64_params, f); parts64_canonicalize(p, s, &float64_params); } @@ -XXX,XX +XXX,XX @@ float32 float32_silence_nan(float32 a, float_status *status) float64 float64_silence_nan(float64 a, float_status *status) { - FloatParts64 p; + FloatParts64 p = unpack_raw64(&float64_params, a); - float64_unpack_raw(&p, a); p.frac <<= float64_params.frac_shift; parts64_silence_nan(&p, status); p.frac >>= float64_params.frac_shift; @@ -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) { - FloatParts64 p; + FloatParts64 p = unpack_raw64(&float64_params, a); - float64_unpack_raw(&p, a); if (parts_squash_denormal(p, status)) { return float64_set_sign(float64_zero, p.sign); } -- 2.43.0
We must change float32 and float64 at once because of the DEFINE_S390_DIVIDE_TO_INTEGER macro. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 300 +++++++++++++++++------------------------------- 1 file changed, 107 insertions(+), 193 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 bfloat16 bfloat16_round_pack_canonical(FloatParts64 *p, return bfloat16_pack_raw(p); } -static void float32_unpack_canonical(FloatParts64 *p, float32 f, - float_status *s) +static FloatParts64 float32_unpack_canonical(float32 f, float_status *s) { - *p = unpack_raw64(&float32_params, f); - parts64_canonicalize(p, s, &float32_params); + FloatParts64 p = unpack_raw64(&float32_params, f); + parts64_canonicalize(&p, s, &float32_params); + return p; } static float32 float32_round_pack_canonical(FloatParts64 *p, @@ -XXX,XX +XXX,XX @@ static float32 float32_round_pack_canonical(FloatParts64 *p, return float32_pack_raw(p); } -static void float64_unpack_canonical(FloatParts64 *p, float64 f, - float_status *s) +static FloatParts64 float64_unpack_canonical(float64 f, float_status *s) { - *p = unpack_raw64(&float64_params, f); - parts64_canonicalize(p, s, &float64_params); + FloatParts64 p = unpack_raw64(&float64_params, f); + parts64_canonicalize(&p, s, &float64_params); + return p; } static float64 float64_round_pack_canonical(FloatParts64 *p, @@ -XXX,XX +XXX,XX @@ float16 float16_sub(float16 a, float16 b, float_status *status) static float32 QEMU_SOFTFLOAT_ATTR soft_f32_addsub(float32 a, float32 b, float_status *status, bool subtract) { - FloatParts64 pa, pb, *pr; - - float32_unpack_canonical(&pa, a, status); - float32_unpack_canonical(&pb, b, status); - pr = parts64_addsub(&pa, &pb, status, subtract); + FloatParts64 pa = float32_unpack_canonical(a, status); + FloatParts64 pb = float32_unpack_canonical(b, status); + FloatParts64 *pr = parts64_addsub(&pa, &pb, status, subtract); return float32_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ static float32 soft_f32_sub(float32 a, float32 b, float_status *status) static float64 QEMU_SOFTFLOAT_ATTR soft_f64_addsub(float64 a, float64 b, float_status *status, bool subtract) { - FloatParts64 pa, pb, *pr; - - float64_unpack_canonical(&pa, a, status); - float64_unpack_canonical(&pb, b, status); - pr = parts64_addsub(&pa, &pb, status, subtract); + FloatParts64 pa = float64_unpack_canonical(a, status); + FloatParts64 pb = float64_unpack_canonical(b, status); + FloatParts64 *pr = parts64_addsub(&pa, &pb, status, subtract); return float64_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float64_sub(float64 a, float64 b, float_status *s) static float64 float64r32_addsub(float64 a, float64 b, float_status *status, bool subtract) { - FloatParts64 pa, pb, *pr; - - float64_unpack_canonical(&pa, a, status); - float64_unpack_canonical(&pb, b, status); - pr = parts64_addsub(&pa, &pb, status, subtract); + FloatParts64 pa = float64_unpack_canonical(a, status); + FloatParts64 pb = float64_unpack_canonical(b, status); + FloatParts64 *pr = parts64_addsub(&pa, &pb, status, subtract); return float64r32_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float16 QEMU_FLATTEN float16_mul(float16 a, float16 b, float_status *status) static float32 QEMU_SOFTFLOAT_ATTR soft_f32_mul(float32 a, float32 b, float_status *status) { - FloatParts64 pa, pb, *pr; - - float32_unpack_canonical(&pa, a, status); - float32_unpack_canonical(&pb, b, status); - pr = parts64_mul(&pa, &pb, status); + FloatParts64 pa = float32_unpack_canonical(a, status); + FloatParts64 pb = float32_unpack_canonical(b, status); + FloatParts64 *pr = parts64_mul(&pa, &pb, status); return float32_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ soft_f32_mul(float32 a, float32 b, float_status *status) static float64 QEMU_SOFTFLOAT_ATTR soft_f64_mul(float64 a, float64 b, float_status *status) { - FloatParts64 pa, pb, *pr; - - float64_unpack_canonical(&pa, a, status); - float64_unpack_canonical(&pb, b, status); - pr = parts64_mul(&pa, &pb, status); + FloatParts64 pa = float64_unpack_canonical(a, status); + FloatParts64 pb = float64_unpack_canonical(b, status); + FloatParts64 *pr = parts64_mul(&pa, &pb, status); return float64_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float64_mul(float64 a, float64 b, float_status *s) float64 float64r32_mul(float64 a, float64 b, float_status *status) { - FloatParts64 pa, pb, *pr; - - float64_unpack_canonical(&pa, a, status); - float64_unpack_canonical(&pb, b, status); - pr = parts64_mul(&pa, &pb, status); + FloatParts64 pa = float64_unpack_canonical(a, status); + FloatParts64 pb = float64_unpack_canonical(b, status); + FloatParts64 *pr = parts64_mul(&pa, &pb, status); return float64r32_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float32 QEMU_SOFTFLOAT_ATTR float32_muladd_scalbn(float32 a, float32 b, float32 c, int scale, int flags, float_status *status) { - FloatParts64 pa, pb, pc, *pr; - - float32_unpack_canonical(&pa, a, status); - float32_unpack_canonical(&pb, b, status); - float32_unpack_canonical(&pc, c, status); - pr = parts64_muladd_scalbn(&pa, &pb, &pc, scale, flags, status); + 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_scalbn(&pa, &pb, &pc, scale, flags, status); /* Round before applying negate result. */ parts64_uncanon(pr, status, &float32_params, false); @@ -XXX,XX +XXX,XX @@ float64 QEMU_SOFTFLOAT_ATTR float64_muladd_scalbn(float64 a, float64 b, float64 c, int scale, int flags, float_status *status) { - FloatParts64 pa, pb, pc, *pr; - - float64_unpack_canonical(&pa, a, status); - float64_unpack_canonical(&pb, b, status); - float64_unpack_canonical(&pc, c, status); - pr = parts64_muladd_scalbn(&pa, &pb, &pc, scale, flags, status); + 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_scalbn(&pa, &pb, &pc, scale, flags, status); /* Round before applying negate result. */ parts64_uncanon(pr, status, &float64_params, false); @@ -XXX,XX +XXX,XX @@ float64_muladd(float64 xa, float64 xb, float64 xc, int flags, float_status *s) float64 float64r32_muladd(float64 a, float64 b, float64 c, int flags, float_status *status) { - FloatParts64 pa, pb, pc, *pr; - - float64_unpack_canonical(&pa, a, status); - float64_unpack_canonical(&pb, b, status); - float64_unpack_canonical(&pc, c, status); - pr = parts64_muladd_scalbn(&pa, &pb, &pc, 0, flags, status); + 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_scalbn(&pa, &pb, &pc, 0, flags, status); /* Round before applying negate result. */ parts64_uncanon(pr, status, &float32_params, false); @@ -XXX,XX +XXX,XX @@ float16 float16_div(float16 a, float16 b, float_status *status) static float32 QEMU_SOFTFLOAT_ATTR soft_f32_div(float32 a, float32 b, float_status *status) { - FloatParts64 pa, pb, *pr; - - float32_unpack_canonical(&pa, a, status); - float32_unpack_canonical(&pb, b, status); - pr = parts64_div(&pa, &pb, status); + FloatParts64 pa = float32_unpack_canonical(a, status); + FloatParts64 pb = float32_unpack_canonical(b, status); + FloatParts64 *pr = parts64_div(&pa, &pb, status); return float32_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ soft_f32_div(float32 a, float32 b, float_status *status) static float64 QEMU_SOFTFLOAT_ATTR soft_f64_div(float64 a, float64 b, float_status *status) { - FloatParts64 pa, pb, *pr; - - float64_unpack_canonical(&pa, a, status); - float64_unpack_canonical(&pb, b, status); - pr = parts64_div(&pa, &pb, status); + FloatParts64 pa = float64_unpack_canonical(a, status); + FloatParts64 pb = float64_unpack_canonical(b, status); + FloatParts64 *pr = parts64_div(&pa, &pb, status); return float64_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float64_div(float64 a, float64 b, float_status *s) float64 float64r32_div(float64 a, float64 b, float_status *status) { - FloatParts64 pa, pb, *pr; - - float64_unpack_canonical(&pa, a, status); - float64_unpack_canonical(&pb, b, status); - pr = parts64_div(&pa, &pb, status); + FloatParts64 pa = float64_unpack_canonical(a, status); + FloatParts64 pb = float64_unpack_canonical(b, status); + FloatParts64 *pr = parts64_div(&pa, &pb, status); return float64r32_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status) float32 float32_rem(float32 a, float32 b, float_status *status) { - FloatParts64 pa, pb, *pr; - - float32_unpack_canonical(&pa, a, status); - float32_unpack_canonical(&pb, b, status); - pr = parts64_modrem(&pa, &pb, NULL, status); + FloatParts64 pa = float32_unpack_canonical(a, status); + FloatParts64 pb = float32_unpack_canonical(b, status); + FloatParts64 *pr = parts64_modrem(&pa, &pb, NULL, status); return float32_round_pack_canonical(pr, status); } float64 float64_rem(float64 a, float64 b, float_status *status) { - FloatParts64 pa, pb, *pr; - - float64_unpack_canonical(&pa, a, status); - float64_unpack_canonical(&pb, b, status); - pr = parts64_modrem(&pa, &pb, NULL, status); + FloatParts64 pa = float64_unpack_canonical(a, status); + FloatParts64 pb = float64_unpack_canonical(b, status); + FloatParts64 *pr = parts64_modrem(&pa, &pb, NULL, status); return float64_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float64 float16_to_float64(float16 a, bool ieee, float_status *s) float8_e4m3 float32_to_float8_e4m3(float32 a, bool saturate, float_status *s) { - FloatParts64 p; + FloatParts64 p = float32_unpack_canonical(a, s); - float32_unpack_canonical(&p, a, s); parts64_float_to_float(&p, s); return float8_e4m3_round_pack_canonical(&p, s, saturate); } float8_e5m2 float32_to_float8_e5m2(float32 a, bool saturate, float_status *s) { - FloatParts64 p; + FloatParts64 p = float32_unpack_canonical(a, s); - float32_unpack_canonical(&p, a, s); parts_float_to_e5m2(&p, s, saturate); return float8_e5m2_round_pack_canonical(&p, s, saturate); } float16 float32_to_float16(float32 a, bool ieee, float_status *s) { - FloatParts64 p; + FloatParts64 p = float32_unpack_canonical(a, s); const FloatFmt *fmt; - float32_unpack_canonical(&p, a, s); if (ieee) { parts64_float_to_float(&p, s); fmt = &float16_params; @@ -XXX,XX +XXX,XX @@ float16 float32_to_float16(float32 a, bool ieee, float_status *s) static float64 QEMU_SOFTFLOAT_ATTR soft_float32_to_float64(float32 a, float_status *s) { - FloatParts64 p; + FloatParts64 p = float32_unpack_canonical(a, s); - float32_unpack_canonical(&p, a, s); parts64_float_to_float(&p, s); return float64_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ float64 float32_to_float64(float32 a, float_status *s) float16 float64_to_float16(float64 a, bool ieee, float_status *s) { - FloatParts64 p; + FloatParts64 p = float64_unpack_canonical(a, s); const FloatFmt *fmt; - float64_unpack_canonical(&p, a, s); if (ieee) { parts64_float_to_float(&p, s); fmt = &float16_params; @@ -XXX,XX +XXX,XX @@ float16 float64_to_float16(float64 a, bool ieee, float_status *s) float32 float64_to_float32(float64 a, float_status *s) { - FloatParts64 p; + FloatParts64 p = float64_unpack_canonical(a, s); - float64_unpack_canonical(&p, a, s); parts64_float_to_float(&p, s); return float32_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ float64 bfloat16_to_float64(bfloat16 a, float_status *s) bfloat16 float32_to_bfloat16(float32 a, float_status *s) { - FloatParts64 p; + FloatParts64 p = float32_unpack_canonical(a, s); - float32_unpack_canonical(&p, a, s); parts64_float_to_float(&p, s); return bfloat16_round_pack_canonical(&p, s); } bfloat16 float64_to_bfloat16(float64 a, float_status *s) { - FloatParts64 p; + FloatParts64 p = float64_unpack_canonical(a, s); - float64_unpack_canonical(&p, a, s); parts64_float_to_float(&p, s); return bfloat16_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ float64 float128_to_float64(float128 a, float_status *s) float128 float32_to_float128(float32 a, float_status *s) { - FloatParts64 p64; + FloatParts64 p64 = float32_unpack_canonical(a, s); FloatParts128 p128; - float32_unpack_canonical(&p64, a, s); parts_float_to_float_widen(&p128, &p64, s); return float128_round_pack_canonical(&p128, s); } float128 float64_to_float128(float64 a, float_status *s) { - FloatParts64 p64; + FloatParts64 p64 = float64_unpack_canonical(a, s); FloatParts128 p128; - float64_unpack_canonical(&p64, a, s); parts_float_to_float_widen(&p128, &p64, s); return float128_round_pack_canonical(&p128, s); } @@ -XXX,XX +XXX,XX @@ float128 floatx80_to_float128(floatx80 a, float_status *s) floatx80 float32_to_floatx80(float32 a, float_status *s) { - FloatParts64 p64; + FloatParts64 p64 = float32_unpack_canonical(a, s); FloatParts128 p128; - float32_unpack_canonical(&p64, a, s); parts_float_to_float_widen(&p128, &p64, s); return floatx80_round_pack_canonical(&p128, s); } floatx80 float64_to_floatx80(float64 a, float_status *s) { - FloatParts64 p64; + FloatParts64 p64 = float64_unpack_canonical(a, s); FloatParts128 p128; - float64_unpack_canonical(&p64, a, s); parts_float_to_float_widen(&p128, &p64, s); return floatx80_round_pack_canonical(&p128, s); } @@ -XXX,XX +XXX,XX @@ float16 float16_round_to_int(float16 a, float_status *s) float32 float32_round_to_int(float32 a, float_status *s) { - FloatParts64 p; + FloatParts64 p = float32_unpack_canonical(a, s); - float32_unpack_canonical(&p, a, s); parts64_round_to_int(&p, s->float_rounding_mode, 0, s, &float32_params); return float32_round_pack_canonical(&p, s); } float64 float64_round_to_int(float64 a, float_status *s) { - FloatParts64 p; + FloatParts64 p = float64_unpack_canonical(a, s); - float64_unpack_canonical(&p, a, s); parts64_round_to_int(&p, s->float_rounding_mode, 0, s, &float64_params); return float64_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ int64_t float16_to_int64_scalbn(float16 a, FloatRoundMode rmode, int scale, int16_t float32_to_int16_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float32_unpack_canonical(&p, a, s); + FloatParts64 p = float32_unpack_canonical(a, s); return parts64_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s); } int32_t float32_to_int32_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float32_unpack_canonical(&p, a, s); + FloatParts64 p = float32_unpack_canonical(a, s); return parts64_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); } int64_t float32_to_int64_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float32_unpack_canonical(&p, a, s); + FloatParts64 p = float32_unpack_canonical(a, s); return parts64_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } int16_t float64_to_int16_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float64_unpack_canonical(&p, a, s); + FloatParts64 p = float64_unpack_canonical(a, s); return parts64_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s); } int32_t float64_to_int32_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float64_unpack_canonical(&p, a, s); + FloatParts64 p = float64_unpack_canonical(a, s); return parts64_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); } int64_t float64_to_int64_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float64_unpack_canonical(&p, a, s); + FloatParts64 p = float64_unpack_canonical(a, s); return parts64_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } @@ -XXX,XX +XXX,XX @@ static int64_t parts64_float_to_sint_modulo(FloatParts64 *p, int32_t float64_to_int32_modulo(float64 a, FloatRoundMode rmode, float_status *s) { - FloatParts64 p; - - float64_unpack_canonical(&p, a, s); + FloatParts64 p = float64_unpack_canonical(a, s); return parts64_float_to_sint_modulo(&p, rmode, 31, s); } int64_t float64_to_int64_modulo(float64 a, FloatRoundMode rmode, float_status *s) { - FloatParts64 p; - - float64_unpack_canonical(&p, a, s); + FloatParts64 p = float64_unpack_canonical(a, s); return parts64_float_to_sint_modulo(&p, rmode, 63, s); } @@ -XXX,XX +XXX,XX @@ uint64_t float16_to_uint64_scalbn(float16 a, FloatRoundMode rmode, int scale, uint16_t float32_to_uint16_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float32_unpack_canonical(&p, a, s); + FloatParts64 p = float32_unpack_canonical(a, s); return parts64_float_to_uint(&p, rmode, scale, UINT16_MAX, s); } uint32_t float32_to_uint32_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float32_unpack_canonical(&p, a, s); + FloatParts64 p = float32_unpack_canonical(a, s); return parts64_float_to_uint(&p, rmode, scale, UINT32_MAX, s); } uint64_t float32_to_uint64_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float32_unpack_canonical(&p, a, s); + FloatParts64 p = float32_unpack_canonical(a, s); return parts64_float_to_uint(&p, rmode, scale, UINT64_MAX, s); } uint16_t float64_to_uint16_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float64_unpack_canonical(&p, a, s); + FloatParts64 p = float64_unpack_canonical(a, s); return parts64_float_to_uint(&p, rmode, scale, UINT16_MAX, s); } uint32_t float64_to_uint32_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float64_unpack_canonical(&p, a, s); + FloatParts64 p = float64_unpack_canonical(a, s); return parts64_float_to_uint(&p, rmode, scale, UINT32_MAX, s); } uint64_t float64_to_uint64_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts64 p; - - float64_unpack_canonical(&p, a, s); + FloatParts64 p = float64_unpack_canonical(a, s); return parts64_float_to_uint(&p, rmode, scale, UINT64_MAX, s); } @@ -XXX,XX +XXX,XX @@ static bfloat16 bfloat16_minmax(bfloat16 a, bfloat16 b, static float32 float32_minmax(float32 a, float32 b, float_status *s, int flags) { - FloatParts64 pa, pb, *pr; - - float32_unpack_canonical(&pa, a, s); - float32_unpack_canonical(&pb, b, s); - pr = parts64_minmax(&pa, &pb, s, flags); + FloatParts64 pa = float32_unpack_canonical(a, s); + FloatParts64 pb = float32_unpack_canonical(b, s); + FloatParts64 *pr = parts64_minmax(&pa, &pb, s, flags); return float32_round_pack_canonical(pr, s); } static float64 float64_minmax(float64 a, float64 b, float_status *s, int flags) { - FloatParts64 pa, pb, *pr; - - float64_unpack_canonical(&pa, a, s); - float64_unpack_canonical(&pb, b, s); - pr = parts64_minmax(&pa, &pb, s, flags); + FloatParts64 pa = float64_unpack_canonical(a, s); + FloatParts64 pb = float64_unpack_canonical(b, s); + FloatParts64 *pr = parts64_minmax(&pa, &pb, s, flags); return float64_round_pack_canonical(pr, s); } @@ -XXX,XX +XXX,XX @@ FloatRelation float16_compare_quiet(float16 a, float16 b, float_status *s) static FloatRelation QEMU_SOFTFLOAT_ATTR float32_do_compare(float32 a, float32 b, float_status *s, bool is_quiet) { - FloatParts64 pa, pb; + FloatParts64 pa = float32_unpack_canonical(a, s); + FloatParts64 pb = float32_unpack_canonical(b, s); - float32_unpack_canonical(&pa, a, s); - float32_unpack_canonical(&pb, b, s); return parts64_compare(&pa, &pb, s, is_quiet); } @@ -XXX,XX +XXX,XX @@ FloatRelation float32_compare_quiet(float32 a, float32 b, float_status *s) static FloatRelation QEMU_SOFTFLOAT_ATTR float64_do_compare(float64 a, float64 b, float_status *s, bool is_quiet) { - FloatParts64 pa, pb; + FloatParts64 pa = float64_unpack_canonical(a, s); + FloatParts64 pb = float64_unpack_canonical(b, s); - float64_unpack_canonical(&pa, a, s); - float64_unpack_canonical(&pb, b, s); return parts64_compare(&pa, &pb, s, is_quiet); } @@ -XXX,XX +XXX,XX @@ float16 float16_scalbn(float16 a, int n, float_status *status) float32 float32_scalbn(float32 a, int n, float_status *status) { - FloatParts64 p; + FloatParts64 p = float32_unpack_canonical(a, status); - float32_unpack_canonical(&p, a, status); parts64_scalbn(&p, n, status); return float32_round_pack_canonical(&p, status); } float64 float64_scalbn(float64 a, int n, float_status *status) { - FloatParts64 p; + FloatParts64 p = float64_unpack_canonical(a, status); - float64_unpack_canonical(&p, a, status); parts64_scalbn(&p, n, status); return float64_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float16 QEMU_FLATTEN float16_sqrt(float16 a, float_status *status) static float32 QEMU_SOFTFLOAT_ATTR soft_f32_sqrt(float32 a, float_status *status) { - FloatParts64 p; + FloatParts64 p = float32_unpack_canonical(a, status); - float32_unpack_canonical(&p, a, status); parts64_sqrt(&p, status, &float32_params); return float32_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ soft_f32_sqrt(float32 a, float_status *status) static float64 QEMU_SOFTFLOAT_ATTR soft_f64_sqrt(float64 a, float_status *status) { - FloatParts64 p; + FloatParts64 p = float64_unpack_canonical(a, status); - float64_unpack_canonical(&p, a, status); parts64_sqrt(&p, status, &float64_params); return float64_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float64 QEMU_FLATTEN float64_sqrt(float64 xa, float_status *s) float64 float64r32_sqrt(float64 a, float_status *status) { - FloatParts64 p; + FloatParts64 p = float64_unpack_canonical(a, status); - float64_unpack_canonical(&p, a, status); parts64_sqrt(&p, status, &float64_params); return float64r32_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ static void parts64_log2(FloatParts64 *a, float_status *s, const FloatFmt *fmt) float32 float32_log2(float32 a, float_status *status) { - FloatParts64 p; + FloatParts64 p = float32_unpack_canonical(a, status); - float32_unpack_canonical(&p, a, status); parts64_log2(&p, status, &float32_params); return float32_round_pack_canonical(&p, status); } float64 float64_log2(float64 a, float_status *status) { - FloatParts64 p; + FloatParts64 p = float64_unpack_canonical(a, status); - float64_unpack_canonical(&p, a, status); parts64_log2(&p, status, &float64_params); return float64_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ static const float64 float32_exp2_coefficients[15] = float32 float32_exp2(float32 a, float_status *status) { - FloatParts64 xp, xnp, tp, rp; - int i; + FloatParts64 xnp, tp, rp; + FloatParts64 xp = float32_unpack_canonical(a, status); - float32_unpack_canonical(&xp, a, status); if (unlikely(xp.cls != float_class_normal)) { switch (xp.cls) { case float_class_denormal: @@ -XXX,XX +XXX,XX @@ float32 float32_exp2(float32 a, float_status *status) float_raise(float_flag_inexact, status); - float64_unpack_canonical(&tp, float64_ln2, status); + tp = float64_unpack_canonical(float64_ln2, status); xp = *parts64_mul(&xp, &tp, status); xnp = xp; - float64_unpack_canonical(&rp, float64_one, status); - for (i = 0 ; i < 15 ; i++) { - - float64_unpack_canonical(&tp, float32_exp2_coefficients[i], 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_scalbn(&tp, &xnp, &rp, 0, 0, status); xnp = *parts64_mul(&xnp, &xp, status); } @@ -XXX,XX +XXX,XX @@ void floatN ## _s390_divide_to_integer(floatN a, floatN b, \ uint32_t *cc, int *dxc, \ float_status *status) \ { \ - FloatParts64 pa, pb, pr, pn; \ - \ - floatN ## _unpack_canonical(&pa, a, status); \ - floatN ## _unpack_canonical(&pb, b, 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, \ -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 17 ++++++----------- 1 file changed, 6 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 @@ static FloatParts64 unpack_raw64(const FloatFmt *fmt, uint64_t raw) }; } -static void QEMU_FLATTEN floatx80_unpack_raw(FloatParts128 *p, floatx80 f) -{ - *p = (FloatParts128) { - .cls = float_class_unclassified, - .sign = extract32(f.high, 15, 1), - .exp = extract32(f.high, 0, 15), - .frac_hi = f.low - }; -} - static void QEMU_FLATTEN float128_unpack_raw(FloatParts128 *p, float128 f) { const int f_size = float128_params.frac_size - 64; @@ -XXX,XX +XXX,XX @@ static bool floatx80_unpack_canonical(FloatParts128 *p, floatx80 f, return false; } - floatx80_unpack_raw(p, f); + *p = (FloatParts128) { + .cls = float_class_unclassified, + .sign = extract32(f.high, 15, 1), + .exp = extract32(f.high, 0, 15), + .frac_hi = f.low + }; if (likely(p->exp != floatx80_params[floatx80_precision_x].exp_max)) { parts128_canonicalize(p, s, &floatx80_params[floatx80_precision_x]); -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 9 ++++----- 1 file changed, 4 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 @@ static FloatParts64 unpack_raw64(const FloatFmt *fmt, uint64_t raw) }; } -static void QEMU_FLATTEN float128_unpack_raw(FloatParts128 *p, float128 f) +static FloatParts128 float128_unpack_raw(float128 f) { const int f_size = float128_params.frac_size - 64; const int e_size = float128_params.exp_size; - *p = (FloatParts128) { + return (FloatParts128) { .cls = float_class_unclassified, .sign = extract64(f.high, f_size + e_size, 1), .exp = extract64(f.high, f_size, e_size), @@ -XXX,XX +XXX,XX @@ static float64 float64r32_round_pack_canonical(FloatParts64 *p, static void float128_unpack_canonical(FloatParts128 *p, float128 f, float_status *s) { - float128_unpack_raw(p, f); + *p = float128_unpack_raw(f); parts128_canonicalize(p, s, &float128_params); } @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_silence_nan(bfloat16 a, float_status *status) float128 float128_silence_nan(float128 a, float_status *status) { - FloatParts128 p; + FloatParts128 p = float128_unpack_raw(a); - float128_unpack_raw(&p, a); frac128_shl(&p, float128_params.frac_shift); parts128_silence_nan(&p, status); frac128_shr(&p, float128_params.frac_shift); -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 105 +++++++++++++++++------------------------------- 1 file changed, 37 insertions(+), 68 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 float64 float64r32_round_pack_canonical(FloatParts64 *p, return float64r32_pack_raw(p); } -static void float128_unpack_canonical(FloatParts128 *p, float128 f, - float_status *s) +static FloatParts128 float128_unpack_canonical(float128 f, float_status *s) { - *p = float128_unpack_raw(f); - parts128_canonicalize(p, s, &float128_params); + FloatParts128 p = float128_unpack_raw(f); + parts128_canonicalize(&p, s, &float128_params); + return p; } static float128 float128_round_pack_canonical(FloatParts128 *p, @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_sub(bfloat16 a, bfloat16 b, float_status *status) static float128 QEMU_FLATTEN float128_addsub(float128 a, float128 b, float_status *status, bool subtract) { - FloatParts128 pa, pb, *pr; - - float128_unpack_canonical(&pa, a, status); - float128_unpack_canonical(&pb, b, status); - pr = parts128_addsub(&pa, &pb, status, subtract); + FloatParts128 pa = float128_unpack_canonical(a, status); + FloatParts128 pb = float128_unpack_canonical(b, status); + FloatParts128 *pr = parts128_addsub(&pa, &pb, status, subtract); return float128_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ bfloat16_mul(bfloat16 a, bfloat16 b, float_status *status) float128 QEMU_FLATTEN float128_mul(float128 a, float128 b, float_status *status) { - FloatParts128 pa, pb, *pr; - - float128_unpack_canonical(&pa, a, status); - float128_unpack_canonical(&pb, b, status); - pr = parts128_mul(&pa, &pb, status); + FloatParts128 pa = float128_unpack_canonical(a, status); + FloatParts128 pb = float128_unpack_canonical(b, status); + FloatParts128 *pr = parts128_mul(&pa, &pb, status); return float128_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, float128 QEMU_FLATTEN float128_muladd(float128 a, float128 b, float128 c, int flags, float_status *status) { - FloatParts128 pa, pb, pc, *pr; - - float128_unpack_canonical(&pa, a, status); - float128_unpack_canonical(&pb, b, status); - float128_unpack_canonical(&pc, c, status); - pr = parts128_muladd_scalbn(&pa, &pb, &pc, 0, flags, status); + 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_scalbn(&pa, &pb, &pc, 0, flags, status); /* Round before applying negate result. */ parts128_uncanon(pr, status, &float128_params, false); @@ -XXX,XX +XXX,XX @@ bfloat16_div(bfloat16 a, bfloat16 b, float_status *status) float128 QEMU_FLATTEN float128_div(float128 a, float128 b, float_status *status) { - FloatParts128 pa, pb, *pr; - - float128_unpack_canonical(&pa, a, status); - float128_unpack_canonical(&pb, b, status); - pr = parts128_div(&pa, &pb, status); + FloatParts128 pa = float128_unpack_canonical(a, status); + FloatParts128 pb = float128_unpack_canonical(b, status); + FloatParts128 *pr = parts128_div(&pa, &pb, status); return float128_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ float64 float64_rem(float64 a, float64 b, float_status *status) float128 float128_rem(float128 a, float128 b, float_status *status) { - FloatParts128 pa, pb, *pr; - - float128_unpack_canonical(&pa, a, status); - float128_unpack_canonical(&pb, b, status); - pr = parts128_modrem(&pa, &pb, NULL, status); + FloatParts128 pa = float128_unpack_canonical(a, status); + FloatParts128 pb = float128_unpack_canonical(b, status); + FloatParts128 *pr = parts128_modrem(&pa, &pb, NULL, status); return float128_round_pack_canonical(pr, status); } @@ -XXX,XX +XXX,XX @@ bfloat16 float64_to_bfloat16(float64 a, float_status *s) float32 float128_to_float32(float128 a, float_status *s) { + FloatParts128 p128 = float128_unpack_canonical(a, s); FloatParts64 p64; - FloatParts128 p128; - float128_unpack_canonical(&p128, a, s); parts_float_to_float_narrow(&p64, &p128, s); return float32_round_pack_canonical(&p64, s); } float64 float128_to_float64(float128 a, float_status *s) { + FloatParts128 p128 = float128_unpack_canonical(a, s); FloatParts64 p64; - FloatParts128 p128; - float128_unpack_canonical(&p128, a, s); parts_float_to_float_narrow(&p64, &p128, s); return float64_round_pack_canonical(&p64, s); } @@ -XXX,XX +XXX,XX @@ floatx80 float64_to_floatx80(float64 a, float_status *s) floatx80 float128_to_floatx80(float128 a, float_status *s) { - FloatParts128 p; + FloatParts128 p = float128_unpack_canonical(a, s); - float128_unpack_canonical(&p, a, s); parts128_float_to_float(&p, s); return floatx80_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_round_to_int(bfloat16 a, float_status *s) float128 float128_round_to_int(float128 a, float_status *s) { - FloatParts128 p; + FloatParts128 p = float128_unpack_canonical(a, s); - float128_unpack_canonical(&p, a, s); parts128_round_to_int(&p, s->float_rounding_mode, 0, s, &float128_params); return float128_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ int64_t bfloat16_to_int64_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, static int32_t float128_to_int32_scalbn(float128 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts128 p; - - float128_unpack_canonical(&p, a, s); + FloatParts128 p = float128_unpack_canonical(a, s); return parts128_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); } static int64_t float128_to_int64_scalbn(float128 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts128 p; - - float128_unpack_canonical(&p, a, s); + FloatParts128 p = float128_unpack_canonical(a, s); return parts128_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } @@ -XXX,XX +XXX,XX @@ static Int128 float128_to_int128_scalbn(float128 a, FloatRoundMode rmode, { int flags = 0; Int128 r; - FloatParts128 p; - - float128_unpack_canonical(&p, a, s); + FloatParts128 p = float128_unpack_canonical(a, s); switch (p.cls) { case float_class_snan: @@ -XXX,XX +XXX,XX @@ uint64_t bfloat16_to_uint64_scalbn(bfloat16 a, FloatRoundMode rmode, static uint32_t float128_to_uint32_scalbn(float128 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts128 p; - - float128_unpack_canonical(&p, a, s); + FloatParts128 p = float128_unpack_canonical(a, s); return parts128_float_to_uint(&p, rmode, scale, UINT32_MAX, s); } static uint64_t float128_to_uint64_scalbn(float128 a, FloatRoundMode rmode, int scale, float_status *s) { - FloatParts128 p; - - float128_unpack_canonical(&p, a, s); + FloatParts128 p = float128_unpack_canonical(a, s); return parts128_float_to_uint(&p, rmode, scale, UINT64_MAX, s); } @@ -XXX,XX +XXX,XX @@ static Int128 float128_to_uint128_scalbn(float128 a, FloatRoundMode rmode, { int flags = 0; Int128 r; - FloatParts128 p; - - float128_unpack_canonical(&p, a, s); + FloatParts128 p = float128_unpack_canonical(a, s); switch (p.cls) { case float_class_snan: @@ -XXX,XX +XXX,XX @@ static float64 float64_minmax(float64 a, float64 b, float_status *s, int flags) static float128 float128_minmax(float128 a, float128 b, float_status *s, int flags) { - FloatParts128 pa, pb, *pr; - - float128_unpack_canonical(&pa, a, s); - float128_unpack_canonical(&pb, b, s); - pr = parts128_minmax(&pa, &pb, s, flags); + FloatParts128 pa = float128_unpack_canonical(a, s); + FloatParts128 pb = float128_unpack_canonical(b, s); + FloatParts128 *pr = parts128_minmax(&pa, &pb, s, flags); return float128_round_pack_canonical(pr, s); } @@ -XXX,XX +XXX,XX @@ FloatRelation bfloat16_compare_quiet(bfloat16 a, bfloat16 b, float_status *s) static FloatRelation QEMU_FLATTEN float128_do_compare(float128 a, float128 b, float_status *s, bool is_quiet) { - FloatParts128 pa, pb; + FloatParts128 pa = float128_unpack_canonical(a, s); + FloatParts128 pb = float128_unpack_canonical(b, s); - float128_unpack_canonical(&pa, a, s); - float128_unpack_canonical(&pb, b, s); return parts128_compare(&pa, &pb, s, is_quiet); } @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_scalbn(bfloat16 a, int n, float_status *status) float128 float128_scalbn(float128 a, int n, float_status *status) { - FloatParts128 p; + FloatParts128 p = float128_unpack_canonical(a, status); - float128_unpack_canonical(&p, a, status); parts128_scalbn(&p, n, status); return float128_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ bfloat16 QEMU_FLATTEN bfloat16_sqrt(bfloat16 a, float_status *status) float128 QEMU_FLATTEN float128_sqrt(float128 a, float_status *status) { - FloatParts128 p; + FloatParts128 p = float128_unpack_canonical(a, status); - float128_unpack_canonical(&p, a, status); parts128_sqrt(&p, status, &float128_params); return float128_round_pack_canonical(&p, status); } -- 2.43.0
Rename and return FloatParts64 structure. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 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 parts128_float_to_float(FloatParts128 *a, float_status *s) } } -static void parts_float_to_float_narrow(FloatParts64 *a, FloatParts128 *b, - float_status *s) +static FloatParts64 parts128_to_parts64(FloatParts128 *b, float_status *s) { - a->cls = b->cls; - a->sign = b->sign; - a->exp = b->exp; + FloatParts64 r = { + .cls = b->cls, + .sign = b->sign, + .exp = b->exp, + }; - switch (a->cls) { + switch (r.cls) { case float_class_denormal: float_raise(float_flag_input_denormal_used, s); /* fall through */ case float_class_normal: - frac64_truncjam(a, b); + frac64_truncjam(&r, b); break; case float_class_snan: case float_class_qnan: /* Discard the low bits of the NaN. */ - a->frac = b->frac_hi; - parts64_return_nan(a, s); + r.frac = b->frac_hi; + parts64_return_nan(&r, s); break; default: break; } + return r; } static void parts_float_to_float_widen(FloatParts128 *a, FloatParts64 *b, @@ -XXX,XX +XXX,XX @@ bfloat16 float64_to_bfloat16(float64 a, float_status *s) float32 float128_to_float32(float128 a, float_status *s) { FloatParts128 p128 = float128_unpack_canonical(a, s); - FloatParts64 p64; + FloatParts64 p64 = parts128_to_parts64(&p128, s); - parts_float_to_float_narrow(&p64, &p128, s); return float32_round_pack_canonical(&p64, s); } float64 float128_to_float64(float128 a, float_status *s) { FloatParts128 p128 = float128_unpack_canonical(a, s); - FloatParts64 p64; + FloatParts64 p64 = parts128_to_parts64(&p128, s); - parts_float_to_float_narrow(&p64, &p128, s); return float64_round_pack_canonical(&p64, s); } @@ -XXX,XX +XXX,XX @@ float32 floatx80_to_float32(floatx80 a, float_status *s) FloatParts128 p128; if (floatx80_unpack_canonical(&p128, a, s)) { - parts_float_to_float_narrow(&p64, &p128, s); + p64 = parts128_to_parts64(&p128, s); } else { parts64_default_nan(&p64, s); } @@ -XXX,XX +XXX,XX @@ float64 floatx80_to_float64(floatx80 a, float_status *s) FloatParts128 p128; if (floatx80_unpack_canonical(&p128, a, s)) { - parts_float_to_float_narrow(&p64, &p128, s); + p64 = parts128_to_parts64(&p128, s); } else { parts64_default_nan(&p64, s); } -- 2.43.0
Rename and return FloatParts128 structure. Use switch instead of 2 ifs. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 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 FloatParts64 parts128_to_parts64(FloatParts128 *b, float_status *s) return r; } -static void parts_float_to_float_widen(FloatParts128 *a, FloatParts64 *b, - float_status *s) +static FloatParts128 parts64_to_parts128(FloatParts64 *b, float_status *s) { - a->cls = b->cls; - a->sign = b->sign; - a->exp = b->exp; - frac64_widen(a, b); + FloatParts128 r = { + .cls = b->cls, + .sign = b->sign, + .exp = b->exp, + .frac_hi = b->frac, + }; - if (is_nan(a->cls)) { - parts128_return_nan(a, s); - } - if (a->cls == float_class_denormal) { + switch (r.cls) { + case float_class_qnan: + case float_class_snan: + parts128_return_nan(&r, s); + break; + case float_class_denormal: float_raise(float_flag_input_denormal_used, s); + break; + default: + break; } + return r; } float8_e4m3 float4_e2m1_to_float8_e4m3(float4_e2m1 a, float_status *s) @@ -XXX,XX +XXX,XX @@ float64 float128_to_float64(float128 a, float_status *s) float128 float32_to_float128(float32 a, float_status *s) { FloatParts64 p64 = float32_unpack_canonical(a, s); - FloatParts128 p128; + FloatParts128 p128 = parts64_to_parts128(&p64, s); - parts_float_to_float_widen(&p128, &p64, s); return float128_round_pack_canonical(&p128, s); } float128 float64_to_float128(float64 a, float_status *s) { FloatParts64 p64 = float64_unpack_canonical(a, s); - FloatParts128 p128; + FloatParts128 p128 = parts64_to_parts128(&p64, s); - parts_float_to_float_widen(&p128, &p64, s); return float128_round_pack_canonical(&p128, s); } @@ -XXX,XX +XXX,XX @@ float128 floatx80_to_float128(floatx80 a, float_status *s) floatx80 float32_to_floatx80(float32 a, float_status *s) { FloatParts64 p64 = float32_unpack_canonical(a, s); - FloatParts128 p128; + FloatParts128 p128 = parts64_to_parts128(&p64, s); - parts_float_to_float_widen(&p128, &p64, s); return floatx80_round_pack_canonical(&p128, s); } floatx80 float64_to_floatx80(float64 a, float_status *s) { FloatParts64 p64 = float64_unpack_canonical(a, s); - FloatParts128 p128; + FloatParts128 p128 = parts64_to_parts128(&p64, s); - parts_float_to_float_widen(&p128, &p64, s); return floatx80_round_pack_canonical(&p128, s); } -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 7 +------ 1 file changed, 1 insertion(+), 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 uint64_t pack_raw64(const FloatParts64 *p, const FloatFmt *fmt) return ret; } -static float8_e4m3 QEMU_FLATTEN float8_e4m3_pack_raw(const FloatParts64 *p) -{ - return pack_raw64(p, &float8_e4m3_params); -} - static float8_e5m2 QEMU_FLATTEN float8_e5m2_pack_raw(const FloatParts64 *p) { return pack_raw64(p, &float8_e5m2_params); @@ -XXX,XX +XXX,XX @@ static float8_e4m3 float8_e4m3_round_pack_canonical(FloatParts64 *p, bool saturate) { parts64_uncanon(p, s, &float8_e4m3_params, saturate); - return float8_e4m3_pack_raw(p); + return pack_raw64(p, &float8_e4m3_params); } static float8_e5m2 float8_e5m2_round_pack_canonical(FloatParts64 *p, -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 7 +------ 1 file changed, 1 insertion(+), 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 uint64_t pack_raw64(const FloatParts64 *p, const FloatFmt *fmt) return ret; } -static float8_e5m2 QEMU_FLATTEN float8_e5m2_pack_raw(const FloatParts64 *p) -{ - return pack_raw64(p, &float8_e5m2_params); -} - static float16 QEMU_FLATTEN float16_pack_raw(const FloatParts64 *p) { return make_float16(pack_raw64(p, &float16_params)); @@ -XXX,XX +XXX,XX @@ static float8_e5m2 float8_e5m2_round_pack_canonical(FloatParts64 *p, bool saturate) { parts64_uncanon(p, s, &float8_e5m2_params, saturate); - return float8_e5m2_pack_raw(p); + return pack_raw64(p, &float8_e5m2_params); } static float16 float16a_round_pack_canonical(FloatParts64 *p, -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 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 uint64_t pack_raw64(const FloatParts64 *p, const FloatFmt *fmt) return ret; } -static float16 QEMU_FLATTEN float16_pack_raw(const FloatParts64 *p) -{ - return make_float16(pack_raw64(p, &float16_params)); -} - static bfloat16 QEMU_FLATTEN bfloat16_pack_raw(const FloatParts64 *p) { return pack_raw64(p, &bfloat16_params); @@ -XXX,XX +XXX,XX @@ static float16 float16a_round_pack_canonical(FloatParts64 *p, const FloatFmt *params) { parts64_uncanon(p, s, params, false); - return float16_pack_raw(p); + return pack_raw64(p, &float16_params); } static float16 float16_round_pack_canonical(FloatParts64 *p, @@ -XXX,XX +XXX,XX @@ float16_muladd_scalbn(float16 a, float16 b, float16 c, if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { pr->sign ^= 1; } - return float16_pack_raw(pr); + return pack_raw64(pr, &float16_params); } float16 float16_muladd(float16 a, float16 b, float16 c, @@ -XXX,XX +XXX,XX @@ float16 float16_default_nan(float_status *status) parts64_default_nan(&p, status); p.frac >>= float16_params.frac_shift; - return float16_pack_raw(&p); + return pack_raw64(&p, &float16_params); } float32 float32_default_nan(float_status *status) @@ -XXX,XX +XXX,XX @@ float16 float16_silence_nan(float16 a, float_status *status) p.frac <<= float16_params.frac_shift; parts64_silence_nan(&p, status); p.frac >>= float16_params.frac_shift; - return float16_pack_raw(&p); + return pack_raw64(&p, &float16_params); } float32 float32_silence_nan(float32 a, float_status *status) -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 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 uint64_t pack_raw64(const FloatParts64 *p, const FloatFmt *fmt) return ret; } -static bfloat16 QEMU_FLATTEN bfloat16_pack_raw(const FloatParts64 *p) -{ - return pack_raw64(p, &bfloat16_params); -} - static float32 QEMU_FLATTEN float32_pack_raw(const FloatParts64 *p) { return make_float32(pack_raw64(p, &float32_params)); @@ -XXX,XX +XXX,XX @@ static bfloat16 bfloat16_round_pack_canonical(FloatParts64 *p, float_status *s) { parts64_uncanon(p, s, &bfloat16_params, false); - return bfloat16_pack_raw(p); + return pack_raw64(p, &bfloat16_params); } static FloatParts64 float32_unpack_canonical(float32 f, float_status *s) @@ -XXX,XX +XXX,XX @@ bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { pr->sign ^= 1; } - return bfloat16_pack_raw(pr); + return pack_raw64(pr, &bfloat16_params); } float128 QEMU_FLATTEN float128_muladd(float128 a, float128 b, float128 c, @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_default_nan(float_status *status) parts64_default_nan(&p, status); p.frac >>= bfloat16_params.frac_shift; - return bfloat16_pack_raw(&p); + return pack_raw64(&p, &bfloat16_params); } /*---------------------------------------------------------------------------- @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_silence_nan(bfloat16 a, float_status *status) p.frac <<= bfloat16_params.frac_shift; parts64_silence_nan(&p, status); p.frac >>= bfloat16_params.frac_shift; - return bfloat16_pack_raw(&p); + return pack_raw64(&p, &bfloat16_params); } float128 float128_silence_nan(float128 a, float_status *status) -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 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 uint64_t pack_raw64(const FloatParts64 *p, const FloatFmt *fmt) return ret; } -static float32 QEMU_FLATTEN float32_pack_raw(const FloatParts64 *p) -{ - return make_float32(pack_raw64(p, &float32_params)); -} - static float64 QEMU_FLATTEN float64_pack_raw(const FloatParts64 *p) { return make_float64(pack_raw64(p, &float64_params)); @@ -XXX,XX +XXX,XX @@ static float32 float32_round_pack_canonical(FloatParts64 *p, float_status *s) { parts64_uncanon(p, s, &float32_params, false); - return float32_pack_raw(p); + return pack_raw64(p, &float32_params); } static FloatParts64 float64_unpack_canonical(float64 f, float_status *s) @@ -XXX,XX +XXX,XX @@ float32_muladd_scalbn(float32 a, float32 b, float32 c, if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { pr->sign ^= 1; } - return float32_pack_raw(pr); + return pack_raw64(pr, &float32_params); } float64 QEMU_SOFTFLOAT_ATTR @@ -XXX,XX +XXX,XX @@ float32 float32_default_nan(float_status *status) parts64_default_nan(&p, status); p.frac >>= float32_params.frac_shift; - return float32_pack_raw(&p); + return pack_raw64(&p, &float32_params); } float64 float64_default_nan(float_status *status) @@ -XXX,XX +XXX,XX @@ float32 float32_silence_nan(float32 a, float_status *status) p.frac <<= float32_params.frac_shift; parts64_silence_nan(&p, status); p.frac >>= float32_params.frac_shift; - return float32_pack_raw(&p); + return pack_raw64(&p, &float32_params); } float64 float64_silence_nan(float64 a, float_status *status) -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 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 uint64_t pack_raw64(const FloatParts64 *p, const FloatFmt *fmt) return ret; } -static float64 QEMU_FLATTEN float64_pack_raw(const FloatParts64 *p) -{ - return make_float64(pack_raw64(p, &float64_params)); -} - static float128 QEMU_FLATTEN float128_pack_raw(const FloatParts128 *p) { const int f_size = float128_params.frac_size - 64; @@ -XXX,XX +XXX,XX @@ static float64 float64_round_pack_canonical(FloatParts64 *p, float_status *s) { parts64_uncanon(p, s, &float64_params, false); - return float64_pack_raw(p); + return pack_raw64(p, &float64_params); } static float64 float64r32_pack_raw(FloatParts64 *p) @@ -XXX,XX +XXX,XX @@ static float64 float64r32_pack_raw(FloatParts64 *p) g_assert_not_reached(); } - return float64_pack_raw(p); + return pack_raw64(p, &float64_params); } static float64 float64r32_round_pack_canonical(FloatParts64 *p, @@ -XXX,XX +XXX,XX @@ float64_muladd_scalbn(float64 a, float64 b, float64 c, if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { pr->sign ^= 1; } - return float64_pack_raw(pr); + return pack_raw64(pr, &float64_params); } static bool force_soft_fma; @@ -XXX,XX +XXX,XX @@ float64 float64_default_nan(float_status *status) parts64_default_nan(&p, status); p.frac >>= float64_params.frac_shift; - return float64_pack_raw(&p); + return pack_raw64(&p, &float64_params); } float128 float128_default_nan(float_status *status) @@ -XXX,XX +XXX,XX @@ float64 float64_silence_nan(float64 a, float_status *status) p.frac <<= float64_params.frac_shift; parts64_silence_nan(&p, status); p.frac >>= float64_params.frac_shift; - return float64_pack_raw(&p); + return pack_raw64(&p, &float64_params); } bfloat16 bfloat16_silence_nan(bfloat16 a, float_status *status) -- 2.43.0
This is almost always used with a constant FloatFmt, so inlining pulls the constants into the shifts. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 const FloatFmt floatx80_params[3] = { }; /* Unpack a float to parts, but do not canonicalize. */ -static FloatParts64 unpack_raw64(const FloatFmt *fmt, uint64_t raw) +static inline QEMU_ALWAYS_INLINE +FloatParts64 unpack_raw64(const FloatFmt *fmt, uint64_t raw) { const int f_size = fmt->frac_size; const int e_size = fmt->exp_size; -- 2.43.0
This is almost always used with a constant FloatFmt, so inlining pulls the constants into the shifts. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 FloatParts128 float128_unpack_raw(float128 f) } /* Pack a float from parts, but do not canonicalize. */ -static uint64_t pack_raw64(const FloatParts64 *p, const FloatFmt *fmt) +static inline uint64_t QEMU_ALWAYS_INLINE +pack_raw64(const FloatParts64 *p, const FloatFmt *fmt) { const int f_size = fmt->frac_size; const int e_size = fmt->exp_size; -- 2.43.0
Begin exposing the intermediate representation of softfloat. Start with just the representation structures. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 88 +++++++++++++++++++++++++++++++++++ fpu/softfloat.c | 69 +-------------------------- 2 files changed, 90 insertions(+), 67 deletions(-) create mode 100644 include/fpu/softfloat-parts.h diff --git a/include/fpu/softfloat-parts.h b/include/fpu/softfloat-parts.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/fpu/softfloat-parts.h @@ -XXX,XX +XXX,XX @@ +/* + * Floating point intermediate representation + * + * The code in this source file is derived from release 2a of the SoftFloat + * IEC/IEEE Floating-point Arithmetic Package. Those parts of the code (and + * some later contributions) are provided under that license, as detailed below. + * It has subsequently been modified by contributors to the QEMU Project, + * so some portions are provided under: + * the SoftFloat-2a license + * the BSD license + * GPL-v2-or-later + * + * Any future contributions to this file after December 1st 2014 will be + * taken to be licensed under the Softfloat-2a license unless specifically + * indicated otherwise. + */ + +#ifndef SOFTFLOAT_PARTS_H +#define SOFTFLOAT_PARTS_H + +/* + * Classify a floating point number. Everything above float_class_qnan + * is a NaN so cls >= float_class_qnan is any NaN. + * + * Note that we canonicalize denormals, so most code should treat + * class_normal and class_denormal identically. + */ + +typedef enum __attribute__ ((__packed__)) { + float_class_unclassified, + float_class_zero, + float_class_normal, + float_class_denormal, /* input was a non-squashed denormal */ + float_class_inf, + float_class_qnan, /* all NaNs from here */ + float_class_snan, +} FloatClass; + +#define float_cmask(bit) (1u << (bit)) + +enum { + float_cmask_zero = float_cmask(float_class_zero), + float_cmask_normal = float_cmask(float_class_normal), + float_cmask_denormal = float_cmask(float_class_denormal), + float_cmask_inf = float_cmask(float_class_inf), + float_cmask_qnan = float_cmask(float_class_qnan), + float_cmask_snan = float_cmask(float_class_snan), + + float_cmask_infzero = float_cmask_zero | float_cmask_inf, + float_cmask_anynan = float_cmask_qnan | float_cmask_snan, + float_cmask_anynorm = float_cmask_normal | float_cmask_denormal, +}; + +/* + * Structure holding all of the decomposed parts of a float. + * The exponent is unbiased and the fraction is normalized. + * + * The fraction words are stored in big-endian word ordering, + * so that truncation from a larger format to a smaller format + * can be done simply by ignoring subsequent elements. + */ + +typedef struct { + FloatClass cls; + bool sign; + int32_t exp; + union { + /* Routines that know the structure may reference the singular name. */ + uint64_t frac; + /* + * Routines expanded with multiple structures reference "hi" and "lo" + * depending on the operation. In FloatParts64, "hi" and "lo" are + * both the same word and aliased here. + */ + uint64_t frac_hi; + uint64_t frac_lo; + }; +} FloatParts64; + +typedef struct { + FloatClass cls; + bool sign; + int32_t exp; + uint64_t frac_hi; + uint64_t frac_lo; +} FloatParts128; + +#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 @@ this code that are retained. #include <math.h> #include "qemu/bitops.h" #include "fpu/softfloat.h" +#include "fpu/softfloat-parts.h" /* We only need stdlib for abort() */ @@ -XXX,XX +XXX,XX @@ float64_gen2(float64 xa, float64 xb, float_status *s, return soft(ua.s, ub.s, s); } -/* - * Classify a floating point number. Everything above float_class_qnan - * is a NaN so cls >= float_class_qnan is any NaN. - * - * Note that we canonicalize denormals, so most code should treat - * class_normal and class_denormal identically. - */ - -typedef enum __attribute__ ((__packed__)) { - float_class_unclassified, - float_class_zero, - float_class_normal, - float_class_denormal, /* input was a non-squashed denormal */ - float_class_inf, - float_class_qnan, /* all NaNs from here */ - float_class_snan, -} FloatClass; - -#define float_cmask(bit) (1u << (bit)) - -enum { - float_cmask_zero = float_cmask(float_class_zero), - float_cmask_normal = float_cmask(float_class_normal), - float_cmask_denormal = float_cmask(float_class_denormal), - float_cmask_inf = float_cmask(float_class_inf), - float_cmask_qnan = float_cmask(float_class_qnan), - float_cmask_snan = float_cmask(float_class_snan), - - float_cmask_infzero = float_cmask_zero | float_cmask_inf, - float_cmask_anynan = float_cmask_qnan | float_cmask_snan, - float_cmask_anynorm = float_cmask_normal | float_cmask_denormal, -}; - /* Flags for parts_minmax. */ enum { /* Set for minimum; clear for maximum. */ @@ -XXX,XX +XXX,XX @@ static inline bool is_anynorm(FloatClass c) return float_cmask(c) & float_cmask_anynorm; } -/* - * Structure holding all of the decomposed parts of a float. - * The exponent is unbiased and the fraction is normalized. - * - * The fraction words are stored in big-endian word ordering, - * so that truncation from a larger format to a smaller format - * can be done simply by ignoring subsequent elements. - */ - -typedef struct { - FloatClass cls; - bool sign; - int32_t exp; - union { - /* Routines that know the structure may reference the singular name. */ - uint64_t frac; - /* - * Routines expanded with multiple structures reference "hi" and "lo" - * depending on the operation. In FloatParts64, "hi" and "lo" are - * both the same word and aliased here. - */ - uint64_t frac_hi; - uint64_t frac_lo; - }; -} FloatParts64; - -typedef struct { - FloatClass cls; - bool sign; - int32_t exp; - uint64_t frac_hi; - uint64_t frac_lo; -} FloatParts128; - +/* FloatParts256 is entirely internal, for parts128_mul* */ typedef struct { FloatClass cls; bool sign; -- 2.43.0
Export most of the FloatFmt structures. Skip float16_params_ahp and the floatx80 precisions. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 48 ++++++++++++++++++++++++++++++ fpu/softfloat.c | 55 +++++------------------------------ 2 files changed, 56 insertions(+), 47 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 @@ #ifndef SOFTFLOAT_PARTS_H #define SOFTFLOAT_PARTS_H +/* Format-specific handling of exp == exp_max */ +typedef enum __attribute__((__packed__)) { + /* exp==max, frac==0 ? infinity : nan; this is ieee standard. */ + float_expmax_ieee, + /* exp==max is a normal number; no infinity or nan representation. */ + float_expmax_normal, + /* exp==max, frac==max ? nan : normal; no infinity representation. */ + float_expmax_e4m3, +} FloatFmtExpMaxKind; + +/* + * Structure holding all of the relevant parameters for a format. + * exp_size: the size of the exponent field + * exp_bias: the offset applied to the exponent field + * exp_max: the maximum normalised exponent + * frac_size: the size of the fraction field + * frac_shift: shift to normalise the fraction with DECOMPOSED_BINARY_POINT + * The following are computed based the size of fraction + * round_mask: bits below lsb which must be rounded + * The following optional modifiers are available: + * exp_max_kind: affects how exp == exp_max is interpreted + * has_explicit_bit: has an explicit integer bit; this affects whether + * the float_status floatx80_behaviour handling applies + * overflow_raises_invalid: for float_expmax_normal, raise invalid + * instead of overflow. + */ +typedef struct { + int exp_size; + int exp_bias; + int exp_re_bias; + int exp_max; + int frac_size; + int frac_shift; + FloatFmtExpMaxKind exp_max_kind; + bool has_explicit_bit; + bool overflow_raises_invalid; + uint64_t round_mask; +} FloatFmt; + +extern const FloatFmt float4_e2m1_params; +extern const FloatFmt float8_e4m3_params; +extern const FloatFmt float8_e5m2_params; +extern const FloatFmt float16_params; +extern const FloatFmt bfloat16_params; +extern const FloatFmt float32_params; +extern const FloatFmt float64_params; +extern const FloatFmt float128_params; + /* * Classify a floating point number. Everything above float_class_qnan * is a NaN so cls >= float_class_qnan is any NaN. 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 { #define DECOMPOSED_BINARY_POINT 63 #define DECOMPOSED_IMPLICIT_BIT (1ull << DECOMPOSED_BINARY_POINT) -/* Format-specific handling of exp == exp_max */ -typedef enum __attribute__((__packed__)) { - /* exp==max, frac==0 ? infinity : nan; this is ieee standard. */ - float_expmax_ieee, - /* exp==max is a normal number; no infinity or nan representation. */ - float_expmax_normal, - /* exp==max, frac==max ? nan : normal; no infinity representation. */ - float_expmax_e4m3, -} FloatFmtExpMaxKind; - -/* - * Structure holding all of the relevant parameters for a format. - * exp_size: the size of the exponent field - * exp_bias: the offset applied to the exponent field - * exp_max: the maximum normalised exponent - * frac_size: the size of the fraction field - * frac_shift: shift to normalise the fraction with DECOMPOSED_BINARY_POINT - * The following are computed based the size of fraction - * round_mask: bits below lsb which must be rounded - * The following optional modifiers are available: - * exp_max_kind: affects how exp == exp_max is interpreted - * has_explicit_bit: has an explicit integer bit; this affects whether - * the float_status floatx80_behaviour handling applies - * overflow_raises_invalid: for float_expmax_normal, raise invalid - * instead of overflow. - */ -typedef struct { - int exp_size; - int exp_bias; - int exp_re_bias; - int exp_max; - int frac_size; - int frac_shift; - FloatFmtExpMaxKind exp_max_kind; - bool has_explicit_bit; - bool overflow_raises_invalid; - uint64_t round_mask; -} FloatFmt; - /* Expand fields based on the size of exponent and fraction */ #define FLOAT_PARAMS_(E) \ .exp_size = E, \ @@ -XXX,XX +XXX,XX @@ typedef struct { .frac_shift = (-F - 1) & 63, \ .round_mask = (1ull << ((-F - 1) & 63)) - 1 -static const FloatFmt float4_e2m1_params = { +const FloatFmt float4_e2m1_params = { FLOAT_PARAMS(2, 1), .exp_max_kind = float_expmax_normal, }; -static const FloatFmt float8_e4m3_params = { +const FloatFmt float8_e4m3_params = { FLOAT_PARAMS(4, 3), .exp_max_kind = float_expmax_e4m3 }; @@ -XXX,XX +XXX,XX @@ static const FloatFmt float8_e4m3_params = { /* 110 << frac_shift, with the implicit bit set */ #define E4M3_NORMAL_FRAC_MAX 0xe000000000000000ull -static const FloatFmt float8_e5m2_params = { +const FloatFmt float8_e5m2_params = { FLOAT_PARAMS(5, 2) }; -static const FloatFmt float16_params = { +const FloatFmt float16_params = { FLOAT_PARAMS(5, 10) }; @@ -XXX,XX +XXX,XX @@ static const FloatFmt float16_params_ahp = { .overflow_raises_invalid = true, }; -static const FloatFmt bfloat16_params = { +const FloatFmt bfloat16_params = { FLOAT_PARAMS(8, 7) }; -static const FloatFmt float32_params = { +const FloatFmt float32_params = { FLOAT_PARAMS(8, 23) }; -static const FloatFmt float64_params = { +const FloatFmt float64_params = { FLOAT_PARAMS(11, 52) }; -static const FloatFmt float128_params = { +const FloatFmt float128_params = { FLOAT_PARAMS(15, 112) }; -- 2.43.0
Export the unpacking and repacking into the various formats. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 30 ++++++++++++++++++++++ fpu/softfloat.c | 47 ++++++++++++++--------------------- 2 files changed, 49 insertions(+), 28 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 @@ typedef struct { uint64_t frac_lo; } FloatParts128; +/* + * Unpack routines from a specific floating-point format. + */ + +FloatParts64 float4_e2m1_unpack_canonical(float4_e2m1 f, float_status *s); +FloatParts64 float8_e4m3_unpack_canonical(float8_e4m3 f, float_status *s); +FloatParts64 float8_e5m2_unpack_canonical(float8_e5m2 f, float_status *s); +FloatParts64 float16_unpack_canonical(float16 f, float_status *s); +FloatParts64 bfloat16_unpack_canonical(bfloat16 f, float_status *s); +FloatParts64 float32_unpack_canonical(float32 f, float_status *s); +FloatParts64 float64_unpack_canonical(float64 f, float_status *s); +FloatParts128 float128_unpack_canonical(float128 f, float_status *s); +/* Returns false if the encoding is invalid. */ +bool floatx80_unpack_canonical(FloatParts128 *p, floatx80 f, float_status *s); + +/* + * Pack routines to a specific floating-point format. + */ + +float8_e4m3 float8_e4m3_round_pack_canonical(FloatParts64 *p, float_status *s, + bool saturate); +float8_e5m2 float8_e5m2_round_pack_canonical(FloatParts64 *p, float_status *s, + bool saturate); +float16 float16_round_pack_canonical(FloatParts64 *p, float_status *s); +bfloat16 bfloat16_round_pack_canonical(FloatParts64 *p, float_status *s); +float32 float32_round_pack_canonical(FloatParts64 *p, float_status *s); +float64 float64_round_pack_canonical(FloatParts64 *p, float_status *s); +float128 float128_round_pack_canonical(FloatParts128 *p, float_status *s); +floatx80 floatx80_round_pack_canonical(FloatParts128 *p, 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 @@ static const uint16_t rsqrt_tab[128] = { * Pack/unpack routines with a specific FloatFmt. */ -static FloatParts64 float4_e2m1_unpack_canonical(float4_e2m1 f, float_status *s) +FloatParts64 float4_e2m1_unpack_canonical(float4_e2m1 f, float_status *s) { FloatParts64 p = unpack_raw64(&float4_e2m1_params, f); parts64_canonicalize(&p, s, &float4_e2m1_params); return p; } -static FloatParts64 float8_e4m3_unpack_canonical(float8_e4m3 f, float_status *s) +FloatParts64 float8_e4m3_unpack_canonical(float8_e4m3 f, float_status *s) { FloatParts64 p = unpack_raw64(&float8_e4m3_params, f); parts64_canonicalize(&p, s, &float8_e4m3_params); return p; } -static FloatParts64 float8_e5m2_unpack_canonical(float8_e5m2 f, float_status *s) +FloatParts64 float8_e5m2_unpack_canonical(float8_e5m2 f, float_status *s) { FloatParts64 p = unpack_raw64(&float8_e5m2_params, f); parts64_canonicalize(&p, s, &float8_e5m2_params); @@ -XXX,XX +XXX,XX @@ static FloatParts64 float16a_unpack_canonical(float16 f, float_status *s, return p; } -static FloatParts64 float16_unpack_canonical(float16 f, float_status *s) +FloatParts64 float16_unpack_canonical(float16 f, float_status *s) { return float16a_unpack_canonical(f, s, &float16_params); } -static FloatParts64 bfloat16_unpack_canonical(bfloat16 f, float_status *s) +FloatParts64 bfloat16_unpack_canonical(bfloat16 f, float_status *s) { FloatParts64 p = unpack_raw64(&bfloat16_params, f); parts64_canonicalize(&p, s, &bfloat16_params); return p; } -static float8_e4m3 float8_e4m3_round_pack_canonical(FloatParts64 *p, - float_status *s, - bool saturate) +float8_e4m3 float8_e4m3_round_pack_canonical(FloatParts64 *p, float_status *s, + bool saturate) { parts64_uncanon(p, s, &float8_e4m3_params, saturate); return pack_raw64(p, &float8_e4m3_params); } -static float8_e5m2 float8_e5m2_round_pack_canonical(FloatParts64 *p, - float_status *s, - bool saturate) +float8_e5m2 float8_e5m2_round_pack_canonical(FloatParts64 *p, float_status *s, + bool saturate) { parts64_uncanon(p, s, &float8_e5m2_params, saturate); return pack_raw64(p, &float8_e5m2_params); @@ -XXX,XX +XXX,XX @@ static float16 float16a_round_pack_canonical(FloatParts64 *p, return pack_raw64(p, &float16_params); } -static float16 float16_round_pack_canonical(FloatParts64 *p, - float_status *s) +float16 float16_round_pack_canonical(FloatParts64 *p, float_status *s) { return float16a_round_pack_canonical(p, s, &float16_params); } -static bfloat16 bfloat16_round_pack_canonical(FloatParts64 *p, - float_status *s) +bfloat16 bfloat16_round_pack_canonical(FloatParts64 *p, float_status *s) { parts64_uncanon(p, s, &bfloat16_params, false); return pack_raw64(p, &bfloat16_params); } -static FloatParts64 float32_unpack_canonical(float32 f, float_status *s) +FloatParts64 float32_unpack_canonical(float32 f, float_status *s) { FloatParts64 p = unpack_raw64(&float32_params, f); parts64_canonicalize(&p, s, &float32_params); return p; } -static float32 float32_round_pack_canonical(FloatParts64 *p, - float_status *s) +float32 float32_round_pack_canonical(FloatParts64 *p, float_status *s) { parts64_uncanon(p, s, &float32_params, false); return pack_raw64(p, &float32_params); } -static FloatParts64 float64_unpack_canonical(float64 f, float_status *s) +FloatParts64 float64_unpack_canonical(float64 f, float_status *s) { FloatParts64 p = unpack_raw64(&float64_params, f); parts64_canonicalize(&p, s, &float64_params); return p; } -static float64 float64_round_pack_canonical(FloatParts64 *p, - float_status *s) +float64 float64_round_pack_canonical(FloatParts64 *p, float_status *s) { parts64_uncanon(p, s, &float64_params, false); return pack_raw64(p, &float64_params); @@ -XXX,XX +XXX,XX @@ static float64 float64r32_round_pack_canonical(FloatParts64 *p, return float64r32_pack_raw(p); } -static FloatParts128 float128_unpack_canonical(float128 f, float_status *s) +FloatParts128 float128_unpack_canonical(float128 f, float_status *s) { FloatParts128 p = float128_unpack_raw(f); parts128_canonicalize(&p, s, &float128_params); return p; } -static float128 float128_round_pack_canonical(FloatParts128 *p, - float_status *s) +float128 float128_round_pack_canonical(FloatParts128 *p, float_status *s) { parts128_uncanon(p, s, &float128_params, false); return float128_pack_raw(p); } /* Returns false if the encoding is invalid. */ -static bool floatx80_unpack_canonical(FloatParts128 *p, floatx80 f, - 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) { @@ -XXX,XX +XXX,XX @@ static bool floatx80_unpack_canonical(FloatParts128 *p, floatx80 f, return true; } -static floatx80 floatx80_round_pack_canonical(FloatParts128 *p, - float_status *s) +floatx80 floatx80_round_pack_canonical(FloatParts128 *p, float_status *s) { const FloatFmt *fmt = &floatx80_params[s->floatx80_rounding_precision]; uint64_t frac; -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 29 ++++++++++++----------------- fpu/softfloat-parts.c.inc | 22 +++++++++++----------- fpu/softfloat-specialize.c.inc | 22 ++++++++++------------ 3 files changed, 33 insertions(+), 40 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 @@ float32 floatx80_to_float32(floatx80 a, float_status *s) if (floatx80_unpack_canonical(&p128, a, s)) { p64 = parts128_to_parts64(&p128, s); } else { - parts64_default_nan(&p64, s); + p64 = parts64_default_nan(s); } return float32_round_pack_canonical(&p64, s); } @@ -XXX,XX +XXX,XX @@ float64 floatx80_to_float64(floatx80 a, float_status *s) if (floatx80_unpack_canonical(&p128, a, s)) { p64 = parts128_to_parts64(&p128, s); } else { - parts64_default_nan(&p64, s); + p64 = parts64_default_nan(s); } return float64_round_pack_canonical(&p64, s); } @@ -XXX,XX +XXX,XX @@ float128 floatx80_to_float128(floatx80 a, float_status *s) if (floatx80_unpack_canonical(&p, a, s)) { parts128_float_to_float(&p, s); } else { - parts128_default_nan(&p, s); + p = parts128_default_nan(s); } return float128_round_pack_canonical(&p, s); } @@ -XXX,XX +XXX,XX @@ static int32_t floatx80_to_int32_scalbn(floatx80 a, FloatRoundMode rmode, FloatParts128 p; if (!floatx80_unpack_canonical(&p, a, s)) { - parts128_default_nan(&p, s); + p = parts128_default_nan(s); } return parts128_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); } @@ -XXX,XX +XXX,XX @@ static int64_t floatx80_to_int64_scalbn(floatx80 a, FloatRoundMode rmode, FloatParts128 p; if (!floatx80_unpack_canonical(&p, a, s)) { - parts128_default_nan(&p, s); + p = parts128_default_nan(s); } return parts128_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } @@ -XXX,XX +XXX,XX @@ static void parts64_log2(FloatParts64 *a, float_status *s, const FloatFmt *fmt) d_nan: float_raise(float_flag_invalid, s); - parts64_default_nan(a, s); + *a = parts64_default_nan(s); } float32 float32_log2(float32 a, float_status *status) @@ -XXX,XX +XXX,XX @@ float64 float64_log2(float64 a, float_status *status) float16 float16_default_nan(float_status *status) { - FloatParts64 p; + FloatParts64 p = parts64_default_nan(status); - parts64_default_nan(&p, status); p.frac >>= float16_params.frac_shift; return pack_raw64(&p, &float16_params); } float32 float32_default_nan(float_status *status) { - FloatParts64 p; + FloatParts64 p = parts64_default_nan(status); - parts64_default_nan(&p, status); p.frac >>= float32_params.frac_shift; return pack_raw64(&p, &float32_params); } float64 float64_default_nan(float_status *status) { - FloatParts64 p; + FloatParts64 p = parts64_default_nan(status); - parts64_default_nan(&p, status); p.frac >>= float64_params.frac_shift; return pack_raw64(&p, &float64_params); } float128 float128_default_nan(float_status *status) { - FloatParts128 p; + FloatParts128 p = parts128_default_nan(status); - parts128_default_nan(&p, status); frac128_shr(&p, float128_params.frac_shift); return float128_pack_raw(&p); } bfloat16 bfloat16_default_nan(float_status *status) { - FloatParts64 p; + FloatParts64 p = parts64_default_nan(status); - parts64_default_nan(&p, status); p.frac >>= bfloat16_params.frac_shift; return pack_raw64(&p, &bfloat16_params); } @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, *n = *r; *cc = 1; } else if (a->cls == float_class_inf || b->cls == float_class_zero) { - parts64_default_nan(r, status); + *r = parts64_default_nan(status); *n = *r; *cc = 1; status->float_exception_flags |= float_flag_invalid; 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(return_nan)(FloatPartsN *a, float_status *s) case float_class_snan: float_raise(float_flag_invalid | float_flag_invalid_snan, s); if (s->default_nan_mode) { - partsN(default_nan)(a, s); + *a = partsN(default_nan)(s); } else { partsN(silence_nan)(a, s); } break; case float_class_qnan: if (s->default_nan_mode) { - partsN(default_nan)(a, s); + *a = partsN(default_nan)(s); } break; default: @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, } if (s->default_nan_mode) { - partsN(default_nan)(a, s); + *a = partsN(default_nan)(s); return a; } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, return ret; default_nan: - partsN(default_nan)(a, s); + *a = partsN(default_nan)(s); return a; } @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_e4m3_overflow)(FloatPartsN *p, float_status *s, p->exp = fmt->exp_max; p->frac_hi = E4M3_NORMAL_FRAC_MAX; } else { - partsN(default_nan)(p, s); + *p = partsN(default_nan)(s); } } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b, } /* Inf - Inf */ float_raise(float_flag_invalid | float_flag_invalid_isi, s); - partsN(default_nan)(a, s); + *a = partsN(default_nan)(s); return a; } } else { @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(mul)(FloatPartsN *a, FloatPartsN *b, /* Inf * Zero == NaN */ if (unlikely(ab_mask == float_cmask_infzero)) { float_raise(float_flag_invalid | float_flag_invalid_imz, s); - partsN(default_nan)(a, s); + *a = partsN(default_nan)(s); return a; } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd_scalbn)(FloatPartsN *a, FloatPartsN *b, goto finish_sign; d_nan: - partsN(default_nan)(a, s); + *a = partsN(default_nan)(s); return a; } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(div)(FloatPartsN *a, FloatPartsN *b, return a; d_nan: - partsN(default_nan)(a, s); + *a = partsN(default_nan)(s); return a; } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(modrem)(FloatPartsN *a, FloatPartsN *b, /* Inf % N; N % 0 */ if (a->cls == float_class_inf || b->cls == float_class_zero) { float_raise(float_flag_invalid, s); - partsN(default_nan)(a, s); + *a = partsN(default_nan)(s); return a; } @@ -XXX,XX +XXX,XX @@ static void partsN(sqrt)(FloatPartsN *a, float_status *status, d_nan: float_raise(float_flag_invalid | float_flag_invalid_sqrt, status); - partsN(default_nan)(a, status); + *a = partsN(default_nan)(status); } /* 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 bool parts_is_snan_frac(uint64_t frac, float_status *status) | The pattern for a default generated deconstructed floating-point NaN. *----------------------------------------------------------------------------*/ -static void parts64_default_nan(FloatParts64 *p, float_status *status) +static FloatParts64 parts64_default_nan(float_status *status) { bool sign = 0; uint64_t frac; @@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status) frac = deposit64(0, DECOMPOSED_BINARY_POINT - 7, 7, dnan_pattern); frac = deposit64(frac, 0, DECOMPOSED_BINARY_POINT - 7, -(dnan_pattern & 1)); - *p = (FloatParts64) { + return (FloatParts64) { .cls = float_class_qnan, .sign = sign, .exp = INT_MAX, @@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status) }; } -static void parts128_default_nan(FloatParts128 *p, float_status *status) +static FloatParts128 parts128_default_nan(float_status *status) { /* * Extrapolate from the choices made by parts64_default_nan to fill * in the quad-floating format. If the low bit is set, assume we * want to set all non-snan bits. */ - FloatParts64 p64; - parts64_default_nan(&p64, status); + FloatParts64 p64 = parts64_default_nan(status); - *p = (FloatParts128) { + return (FloatParts128) { .cls = float_class_qnan, .sign = p64.sign, .exp = INT_MAX, @@ -XXX,XX +XXX,XX @@ static void parts128_silence_nan(FloatParts128 *p, float_status *status) *----------------------------------------------------------------------------*/ floatx80 floatx80_default_nan(float_status *status) { - floatx80 r; /* * Extrapolate from the choices made by parts64_default_nan to fill * in the floatx80 format. We assume that floatx80's explicit * integer bit is always set (this is true for i386 and m68k, * which are the only real users of this format). */ - FloatParts64 p64; - parts64_default_nan(&p64, status); + FloatParts64 p64 = parts64_default_nan(status); - r.high = 0x7FFF | (p64.sign << 15); - r.low = (1ULL << DECOMPOSED_BINARY_POINT) | p64.frac; - return r; + return (floatx80) { + .high = 0x7FFF | (p64.sign << 15), + .low = (1ULL << DECOMPOSED_BINARY_POINT) | p64.frac, + }; } /*---------------------------------------------------------------------------- -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 10 +++++----- fpu/softfloat-parts.c.inc | 6 +++--- fpu/softfloat-specialize.c.inc | 20 ++++++++++++++------ 3 files changed, 22 insertions(+), 14 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 @@ float16 float16_silence_nan(float16 a, float_status *status) FloatParts64 p = unpack_raw64(&float16_params, a); p.frac <<= float16_params.frac_shift; - parts64_silence_nan(&p, status); + p = parts64_silence_nan(&p, status); p.frac >>= float16_params.frac_shift; return pack_raw64(&p, &float16_params); } @@ -XXX,XX +XXX,XX @@ float32 float32_silence_nan(float32 a, float_status *status) FloatParts64 p = unpack_raw64(&float32_params, a); p.frac <<= float32_params.frac_shift; - parts64_silence_nan(&p, status); + p = parts64_silence_nan(&p, status); p.frac >>= float32_params.frac_shift; return pack_raw64(&p, &float32_params); } @@ -XXX,XX +XXX,XX @@ float64 float64_silence_nan(float64 a, float_status *status) FloatParts64 p = unpack_raw64(&float64_params, a); p.frac <<= float64_params.frac_shift; - parts64_silence_nan(&p, status); + p = parts64_silence_nan(&p, status); p.frac >>= float64_params.frac_shift; return pack_raw64(&p, &float64_params); } @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_silence_nan(bfloat16 a, float_status *status) FloatParts64 p = unpack_raw64(&bfloat16_params, a); p.frac <<= bfloat16_params.frac_shift; - parts64_silence_nan(&p, status); + p = parts64_silence_nan(&p, status); p.frac >>= bfloat16_params.frac_shift; return pack_raw64(&p, &bfloat16_params); } @@ -XXX,XX +XXX,XX @@ float128 float128_silence_nan(float128 a, float_status *status) FloatParts128 p = float128_unpack_raw(a); frac128_shl(&p, float128_params.frac_shift); - parts128_silence_nan(&p, status); + p = parts128_silence_nan(&p, status); frac128_shr(&p, float128_params.frac_shift); return float128_pack_raw(&p); } 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(return_nan)(FloatPartsN *a, float_status *s) if (s->default_nan_mode) { *a = partsN(default_nan)(s); } else { - partsN(silence_nan)(a, s); + *a = partsN(silence_nan)(a, s); } break; case float_class_qnan: @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, } if (is_snan(ret->cls)) { - partsN(silence_nan)(ret, s); + *ret = partsN(silence_nan)(ret, s); } return ret; } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, } if (is_snan(ret->cls)) { - partsN(silence_nan)(ret, s); + *ret = partsN(silence_nan)(ret, s); } return ret; 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 uint64_t parts_silence_nan_frac(uint64_t frac, float_status *status) return frac; } -static void parts64_silence_nan(FloatParts64 *p, float_status *status) +static FloatParts64 parts64_silence_nan(const FloatParts64 *p, + float_status *status) { - p->frac = parts_silence_nan_frac(p->frac, status); - p->cls = float_class_qnan; + FloatParts64 r = *p; + + r.frac = parts_silence_nan_frac(r.frac, status); + r.cls = float_class_qnan; + return r; } -static void parts128_silence_nan(FloatParts128 *p, float_status *status) +static FloatParts128 parts128_silence_nan(const FloatParts128 *p, + float_status *status) { - p->frac_hi = parts_silence_nan_frac(p->frac_hi, status); - p->cls = float_class_qnan; + FloatParts128 r = *p; + + r.frac_hi = parts_silence_nan_frac(r.frac_hi, status); + r.cls = float_class_qnan; + return r; } /*---------------------------------------------------------------------------- -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 14 +++++++------- fpu/softfloat-parts.c.inc | 15 ++++++++------- 2 files changed, 15 insertions(+), 14 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_float_to_e5m2(FloatParts64 *a, float_status *s, bool saturate) switch (a->cls) { case float_class_snan: case float_class_qnan: - parts64_return_nan(a, s); + *a = parts64_return_nan(a, s); break; case float_class_inf: @@ -XXX,XX +XXX,XX @@ static void parts_float_to_e5m2(FloatParts64 *a, float_status *s, bool saturate) static void parts64_float_to_float(FloatParts64 *a, float_status *s) { if (is_nan(a->cls)) { - parts64_return_nan(a, s); + *a = parts64_return_nan(a, s); } if (a->cls == float_class_denormal) { float_raise(float_flag_input_denormal_used, s); @@ -XXX,XX +XXX,XX @@ static void parts64_float_to_float(FloatParts64 *a, float_status *s) static void parts128_float_to_float(FloatParts128 *a, float_status *s) { if (is_nan(a->cls)) { - parts128_return_nan(a, s); + *a = parts128_return_nan(a, s); } if (a->cls == float_class_denormal) { float_raise(float_flag_input_denormal_used, s); @@ -XXX,XX +XXX,XX @@ static FloatParts64 parts128_to_parts64(FloatParts128 *b, float_status *s) case float_class_qnan: /* Discard the low bits of the NaN. */ r.frac = b->frac_hi; - parts64_return_nan(&r, s); + r = parts64_return_nan(&r, s); break; default: break; @@ -XXX,XX +XXX,XX @@ static FloatParts128 parts64_to_parts128(FloatParts64 *b, float_status *s) switch (r.cls) { case float_class_qnan: case float_class_snan: - parts128_return_nan(&r, s); + r = parts128_return_nan(&r, s); break; case float_class_denormal: float_raise(float_flag_input_denormal_used, s); @@ -XXX,XX +XXX,XX @@ static void parts64_log2(FloatParts64 *a, float_status *s, const FloatFmt *fmt) break; case float_class_snan: case float_class_qnan: - parts64_return_nan(a, s); + *a = parts64_return_nan(a, s); return; case float_class_zero: float_raise(float_flag_divbyzero, s); @@ -XXX,XX +XXX,XX @@ float32 float32_exp2(float32 a, float_status *status) break; case float_class_snan: case float_class_qnan: - parts64_return_nan(&xp, status); + xp = parts64_return_nan(&xp, status); return float32_round_pack_canonical(&xp, status); case float_class_inf: return xp.sign ? float32_zero : a; 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 @@ * indicated otherwise. */ -static void partsN(return_nan)(FloatPartsN *a, float_status *s) +static 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) { - *a = partsN(default_nan)(s); + return partsN(default_nan)(s); } else { - *a = partsN(silence_nan)(a, s); + return partsN(silence_nan)(a, s); } break; case float_class_qnan: if (s->default_nan_mode) { - *a = partsN(default_nan)(s); + return partsN(default_nan)(s); } break; default: g_assert_not_reached(); } + return *a; } static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, @@ -XXX,XX +XXX,XX @@ static void partsN(sqrt)(FloatPartsN *a, float_status *status, break; case float_class_snan: case float_class_qnan: - partsN(return_nan)(a, status); + *a = partsN(return_nan)(a, status); return; case float_class_zero: return; @@ -XXX,XX +XXX,XX @@ static void partsN(round_to_int)(FloatPartsN *a, FloatRoundMode rmode, switch (a->cls) { case float_class_qnan: case float_class_snan: - partsN(return_nan)(a, s); + *a = partsN(return_nan)(a, s); break; case float_class_zero: case float_class_inf: @@ -XXX,XX +XXX,XX @@ static void partsN(scalbn)(FloatPartsN *a, int n, float_status *s) switch (a->cls) { case float_class_snan: case float_class_qnan: - partsN(return_nan)(a, s); + *a = partsN(return_nan)(a, s); break; case float_class_zero: case float_class_inf: -- 2.43.0
Share the float32->float64 bias adjustment from both the normal and denormal paths. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 6 ++---- 1 file changed, 2 insertions(+), 4 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 float64 float64r32_pack_raw(FloatParts64 *p) * in normalized form for float64. Adjust, per canonicalize. */ int shift = frac64_normalize(p); - p->exp = (float32_params.frac_shift - - float32_params.exp_bias - shift + 1 + - float64_params.exp_bias); frac64_shr(p, float64_params.frac_shift); + p->exp = float32_params.frac_shift - shift + 1; } else { frac64_shl(p, float32_params.frac_shift - float64_params.frac_shift); - p->exp += float64_params.exp_bias - float32_params.exp_bias; } + p->exp += float64_params.exp_bias - float32_params.exp_bias; break; case float_class_snan: case float_class_qnan: -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 8 ++++---- fpu/softfloat-parts.c.inc | 28 ++++++++++++++++------------ 2 files changed, 20 insertions(+), 16 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 @@ void normalizeFloatx80Subnormal(uint64_t aSig, int32_t *zExpPtr, floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status) { - FloatParts128 pa, pb, *pr; + FloatParts128 pa, pb; if (!floatx80_unpack_canonical(&pa, a, status) || !floatx80_unpack_canonical(&pb, b, status)) { return floatx80_default_nan(status); } - pr = parts128_pick_nan(&pa, &pb, status); - return floatx80_round_pack_canonical(pr, status); + pa = parts128_pick_nan(&pa, &pb, status); + return floatx80_round_pack_canonical(&pa, status); } /*---------------------------------------------------------------------------- @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, { /* 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); + *r = parts64_pick_nan(a, b, status); *n = *r; *cc = 1; } else if (a->cls == float_class_inf || b->cls == float_class_zero) { 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(return_nan)(const FloatPartsN *a, float_status *s) return *a; } -static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, - float_status *s) +static FloatPartsN partsN(pick_nan)(const FloatPartsN *a, const FloatPartsN *b, + float_status *s) { bool have_snan = false; - FloatPartsN *ret; + const FloatPartsN *ret; int cmp; if (is_snan(a->cls) || is_snan(b->cls)) { @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, } if (s->default_nan_mode) { - *a = partsN(default_nan)(s); - return a; + return partsN(default_nan)(s); } switch (s->float_2nan_prop_rule) { @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, } if (is_snan(ret->cls)) { - *ret = partsN(silence_nan)(ret, s); + return partsN(silence_nan)(ret, s); } - return ret; + return *ret; } static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b, return b; p_nan: - return partsN(pick_nan)(a, b, s); + *a = partsN(pick_nan)(a, b, s); + return a; } /* @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(mul)(FloatPartsN *a, FloatPartsN *b, } if (unlikely(ab_mask & float_cmask_anynan)) { - return partsN(pick_nan)(a, b, s); + *a = partsN(pick_nan)(a, b, s); + return a; } /* Multiply by 0 or Inf */ @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(div)(FloatPartsN *a, FloatPartsN *b, /* All the NaN cases */ if (unlikely(ab_mask & float_cmask_anynan)) { - return partsN(pick_nan)(a, b, s); + *a = partsN(pick_nan)(a, b, s); + return a; } if ((ab_mask & float_cmask_denormal) && b->cls != float_class_zero) { @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(modrem)(FloatPartsN *a, FloatPartsN *b, /* All the NaN cases */ if (unlikely(ab_mask & float_cmask_anynan)) { - return partsN(pick_nan)(a, b, s); + *a = partsN(pick_nan)(a, b, s); + return a; } /* Inf % N; N % 0 */ @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b, return is_nan(a->cls) ? b : a; } - return partsN(pick_nan)(a, b, s); + *a = partsN(pick_nan)(a, b, s); + return a; } if (ab_mask & float_cmask_denormal) { -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 34 ++++++++++++++--------------- fpu/softfloat-parts.c.inc | 45 +++++++++++++++++---------------------- 2 files changed, 37 insertions(+), 42 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 @@ float16 float16_div(float16 a, float16 b, float_status *status) { FloatParts64 pa = float16_unpack_canonical(a, status); FloatParts64 pb = float16_unpack_canonical(b, status); - FloatParts64 *pr = parts64_div(&pa, &pb, status); + FloatParts64 pr = parts64_div(&pa, &pb, status); - return float16_round_pack_canonical(pr, status); + return float16_round_pack_canonical(&pr, status); } static float32 QEMU_SOFTFLOAT_ATTR @@ -XXX,XX +XXX,XX @@ soft_f32_div(float32 a, float32 b, float_status *status) { FloatParts64 pa = float32_unpack_canonical(a, status); FloatParts64 pb = float32_unpack_canonical(b, status); - FloatParts64 *pr = parts64_div(&pa, &pb, status); + FloatParts64 pr = parts64_div(&pa, &pb, status); - return float32_round_pack_canonical(pr, status); + return float32_round_pack_canonical(&pr, status); } static float64 QEMU_SOFTFLOAT_ATTR @@ -XXX,XX +XXX,XX @@ soft_f64_div(float64 a, float64 b, float_status *status) { FloatParts64 pa = float64_unpack_canonical(a, status); FloatParts64 pb = float64_unpack_canonical(b, status); - FloatParts64 *pr = parts64_div(&pa, &pb, status); + FloatParts64 pr = parts64_div(&pa, &pb, status); - return float64_round_pack_canonical(pr, status); + return float64_round_pack_canonical(&pr, status); } static float hard_f32_div(float a, float b) @@ -XXX,XX +XXX,XX @@ float64 float64r32_div(float64 a, float64 b, float_status *status) { FloatParts64 pa = float64_unpack_canonical(a, status); FloatParts64 pb = float64_unpack_canonical(b, status); - FloatParts64 *pr = parts64_div(&pa, &pb, status); + FloatParts64 pr = parts64_div(&pa, &pb, status); - return float64r32_round_pack_canonical(pr, status); + return float64r32_round_pack_canonical(&pr, status); } bfloat16 QEMU_FLATTEN @@ -XXX,XX +XXX,XX @@ bfloat16_div(bfloat16 a, bfloat16 b, float_status *status) { FloatParts64 pa = bfloat16_unpack_canonical(a, status); FloatParts64 pb = bfloat16_unpack_canonical(b, status); - FloatParts64 *pr = parts64_div(&pa, &pb, status); + FloatParts64 pr = parts64_div(&pa, &pb, status); - return bfloat16_round_pack_canonical(pr, status); + return bfloat16_round_pack_canonical(&pr, status); } float128 QEMU_FLATTEN @@ -XXX,XX +XXX,XX @@ float128_div(float128 a, float128 b, float_status *status) { FloatParts128 pa = float128_unpack_canonical(a, status); FloatParts128 pb = float128_unpack_canonical(b, status); - FloatParts128 *pr = parts128_div(&pa, &pb, status); + FloatParts128 pr = parts128_div(&pa, &pb, status); - return float128_round_pack_canonical(pr, status); + return float128_round_pack_canonical(&pr, status); } floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status) { - FloatParts128 pa, pb, *pr; + FloatParts128 pa, pb; if (!floatx80_unpack_canonical(&pa, a, status) || !floatx80_unpack_canonical(&pb, b, status)) { return floatx80_default_nan(status); } - pr = parts128_div(&pa, &pb, status); - return floatx80_round_pack_canonical(pr, status); + pa = parts128_div(&pa, &pb, status); + return floatx80_round_pack_canonical(&pa, status); } /* @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, uint32_t r_flags; /* Compute precise quotient */ - q_buf = *a; - q = parts64_div(&q_buf, b, status); + q_buf = parts64_div(a, b, status); + q = &q_buf; /* * Check whether two closest integers can be precisely represented, 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_scalbn)(FloatPartsN *a, FloatPartsN *b, * corresponding value `b'. The operation is performed according to * the IEC/IEEE Standard for Binary Floating-Point Arithmetic. */ -static FloatPartsN *partsN(div)(FloatPartsN *a, FloatPartsN *b, - float_status *s) +static FloatPartsN partsN(div)(const FloatPartsN *a, const FloatPartsN *b, + float_status *s) { int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); - bool sign = a->sign ^ b->sign; + FloatPartsN r = *a; + + r.sign ^= b->sign; + r.exp -= b->exp; if (likely(cmask_is_only_normals(ab_mask))) { if (ab_mask & float_cmask_denormal) { float_raise(float_flag_input_denormal_used, s); } - a->sign = sign; - a->exp -= b->exp + fracN(div)(a, b); - return a; + r.exp -= fracN(div)(&r, b); + return r; } /* 0/0 or Inf/Inf => NaN */ if (unlikely(ab_mask == float_cmask_zero)) { float_raise(float_flag_invalid | float_flag_invalid_zdz, s); - goto d_nan; + return partsN(default_nan)(s); } if (unlikely(ab_mask == float_cmask_inf)) { float_raise(float_flag_invalid | float_flag_invalid_idi, s); - goto d_nan; + return partsN(default_nan)(s); } /* All the NaN cases */ if (unlikely(ab_mask & float_cmask_anynan)) { - *a = partsN(pick_nan)(a, b, s); - return a; + return partsN(pick_nan)(a, b, s); } if ((ab_mask & float_cmask_denormal) && b->cls != float_class_zero) { float_raise(float_flag_input_denormal_used, s); } - a->sign = sign; - /* Inf / X */ - if (a->cls == float_class_inf) { - return a; + if (r.cls == float_class_inf) { + return r; } /* 0 / X */ - if (a->cls == float_class_zero) { - return a; + if (r.cls == float_class_zero) { + return r; } /* X / Inf */ if (b->cls == float_class_inf) { - a->cls = float_class_zero; - return a; + r.cls = float_class_zero; + return r; } /* X / 0 => Inf */ - g_assert(b->cls == float_class_zero); + assert(b->cls == float_class_zero); float_raise(float_flag_divbyzero, s); - a->cls = float_class_inf; - return a; - - d_nan: - *a = partsN(default_nan)(s); - return a; + r.cls = float_class_inf; + return r; } /* -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 19 ++++++++++++------- fpu/softfloat-parts.c.inc | 21 ++++++++++++--------- 2 files changed, 24 insertions(+), 16 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 @@ float16 float16_round_to_int(float16 a, float_status *s) { FloatParts64 p = float16_unpack_canonical(a, s); - parts64_round_to_int(&p, s->float_rounding_mode, 0, s, &float16_params); + p = parts64_round_to_int(&p, s->float_rounding_mode, 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); - parts64_round_to_int(&p, s->float_rounding_mode, 0, s, &float32_params); + p = parts64_round_to_int(&p, s->float_rounding_mode, 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); - parts64_round_to_int(&p, s->float_rounding_mode, 0, s, &float64_params); + p = parts64_round_to_int(&p, s->float_rounding_mode, 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); - parts64_round_to_int(&p, s->float_rounding_mode, 0, s, &bfloat16_params); + p = parts64_round_to_int(&p, s->float_rounding_mode, 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); - parts128_round_to_int(&p, s->float_rounding_mode, 0, s, &float128_params); + p = parts128_round_to_int(&p, s->float_rounding_mode, 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); } - parts128_round_to_int(&p, status->float_rounding_mode, 0, status, - &floatx80_params[status->floatx80_rounding_precision]); + p = parts128_round_to_int(&p, status->float_rounding_mode, 0, status, + &floatx80_params[status->floatx80_rounding_precision]); 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 @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode, return true; } -static void partsN(round_to_int)(FloatPartsN *a, FloatRoundMode rmode, - int scale, float_status *s, - const FloatFmt *fmt) +static FloatPartsN partsN(round_to_int)(const FloatPartsN *a, + FloatRoundMode rmode, + int scale, float_status *s, + const FloatFmt *fmt) { switch (a->cls) { case float_class_qnan: case float_class_snan: - *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_normal: case float_class_denormal: - if (partsN(round_to_int_normal)(a, rmode, scale, fmt->frac_size)) { - float_raise(float_flag_inexact, s); + { + FloatPartsN r = *a; + if (partsN(round_to_int_normal)(&r, rmode, scale, fmt->frac_size)) { + float_raise(float_flag_inexact, s); + } + return r; } - break; default: g_assert_not_reached(); } -- 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_buf = *b; -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 12 ++++++++++++ fpu/softfloat-parts.c.inc | 4 ++-- fpu/softfloat-specialize.c.inc | 4 ++-- 3 files changed, 16 insertions(+), 4 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 @@ float64 float64_round_pack_canonical(FloatParts64 *p, float_status *s); float128 float128_round_pack_canonical(FloatParts128 *p, float_status *s); floatx80 floatx80_round_pack_canonical(FloatParts128 *p, float_status *s); +/* + * NaN handling + */ + +FloatParts64 parts64_default_nan(float_status *status); +FloatParts128 parts128_default_nan(float_status *status); + +FloatParts64 parts64_pick_nan(const FloatParts64 *, const FloatParts64 *, + float_status *); +FloatParts128 parts128_pick_nan(const FloatParts128 *, const FloatParts128 *, + float_status *); + #endif 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(return_nan)(const FloatPartsN *a, float_status *s) return *a; } -static FloatPartsN partsN(pick_nan)(const FloatPartsN *a, const FloatPartsN *b, - float_status *s) +FloatPartsN partsN(pick_nan)(const FloatPartsN *a, const FloatPartsN *b, + float_status *s) { bool have_snan = false; const FloatPartsN *ret; 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 bool parts_is_snan_frac(uint64_t frac, float_status *status) | The pattern for a default generated deconstructed floating-point NaN. *----------------------------------------------------------------------------*/ -static FloatParts64 parts64_default_nan(float_status *status) +FloatParts64 parts64_default_nan(float_status *status) { bool sign = 0; uint64_t frac; @@ -XXX,XX +XXX,XX @@ static FloatParts64 parts64_default_nan(float_status *status) }; } -static FloatParts128 parts128_default_nan(float_status *status) +FloatParts128 parts128_default_nan(float_status *status) { /* * Extrapolate from the choices made by parts64_default_nan to fill -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 7 +++++++ fpu/softfloat.c | 19 ++++++++++++++++--- 2 files changed, 23 insertions(+), 3 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_pick_nan(const FloatParts64 *, const FloatParts64 *, FloatParts128 parts128_pick_nan(const FloatParts128 *, const FloatParts128 *, float_status *); +/* + * Operations + */ + +void parts64_round_canonical(FloatParts64 *p, float_status *s, + const FloatFmt *fmt); + #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 @@ float64 float64_round_pack_canonical(FloatParts64 *p, float_status *s) return pack_raw64(p, &float64_params); } +/* + * Round to Fmt while remaining canonicalized. + */ +void parts64_round_canonical(FloatParts64 *p, float_status *s, + const FloatFmt *fmt) +{ + parts64_uncanon(p, s, fmt, false); + /* + * We normally expect uncanon to be followed by pack_raw, + * so we don't actually crop the bits. Do so now. + */ + p->frac &= MAKE_64BIT_MASK(0, fmt->frac_size); + parts64_canonicalize(p, s, fmt); +} + static float64 float64r32_pack_raw(FloatParts64 *p) { /* @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, /* Round remainder to the target format */ *r = *r_precise; status->float_exception_flags = 0; - parts64_uncanon(r, status, fmt, false); + parts64_round_canonical(r, status, fmt); r_flags = status->float_exception_flags; - r->frac &= (1ULL << fmt->frac_size) - 1; - parts64_canonicalize(r, status, fmt); /* POp table "Results: DIVIDE TO INTEGER (Part 2 of 2)" */ if (is_q_smallish) { -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 5 +++++ fpu/softfloat-parts.c.inc | 4 ++-- 2 files changed, 7 insertions(+), 2 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_pick_nan(const FloatParts128 *, const FloatParts128 *, * Operations */ +FloatParts64 parts64_div(const FloatParts64 *a, const FloatParts64 *b, + float_status *s); +FloatParts128 parts128_div(const FloatParts128 *a, const FloatParts128 *b, + float_status *s); + void parts64_round_canonical(FloatParts64 *p, float_status *s, const FloatFmt *fmt); 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_scalbn)(FloatPartsN *a, FloatPartsN *b, * corresponding value `b'. The operation is performed according to * the IEC/IEEE Standard for Binary Floating-Point Arithmetic. */ -static FloatPartsN partsN(div)(const FloatPartsN *a, const FloatPartsN *b, - float_status *s) +FloatPartsN partsN(div)(const FloatPartsN *a, const FloatPartsN *b, + float_status *s) { int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); FloatPartsN r = *a; -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 9 +++++++++ fpu/softfloat-parts.c.inc | 8 ++++---- 2 files changed, 13 insertions(+), 4 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_div(const FloatParts128 *a, const FloatParts128 *b, void parts64_round_canonical(FloatParts64 *p, float_status *s, const FloatFmt *fmt); +FloatParts64 parts64_round_to_int(const FloatParts64 *a, + FloatRoundMode rmode, + int scale, float_status *s, + const FloatFmt *fmt); +FloatParts128 parts128_round_to_int(const FloatParts128 *a, + FloatRoundMode rmode, + int scale, float_status *s, + const FloatFmt *fmt); + #endif 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, return true; } -static FloatPartsN partsN(round_to_int)(const FloatPartsN *a, - FloatRoundMode rmode, - int scale, float_status *s, - const FloatFmt *fmt) +FloatPartsN partsN(round_to_int)(const FloatPartsN *a, + FloatRoundMode rmode, + int scale, float_status *s, + const FloatFmt *fmt) { switch (a->cls) { case float_class_qnan: -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 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(pick_nan)(const FloatPartsN *a, const FloatPartsN *b, return *ret; } -static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, - FloatPartsN *c, float_status *s, - int ab_mask, int abc_mask) +static FloatPartsN partsN(pick_nan_muladd)(const FloatPartsN *a, + const FloatPartsN *b, + const FloatPartsN *c, + float_status *s, + int ab_mask, int abc_mask) { bool infzero = (ab_mask == float_cmask_infzero); bool have_snan = (abc_mask & float_cmask_snan); - FloatPartsN *ret; + const FloatPartsN *ret; if (unlikely(have_snan)) { float_raise(float_flag_invalid | float_flag_invalid_snan, s); @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, } ret = c; } else { - FloatPartsN *val[R_3NAN_1ST_MASK + 1] = { a, b, c }; + const FloatPartsN *val[R_3NAN_1ST_MASK + 1] = { a, b, c }; Float3NaNPropRule rule = s->float_3nan_prop_rule; assert(rule != float_3nan_prop_none); @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, } if (is_snan(ret->cls)) { - *ret = partsN(silence_nan)(ret, s); + return partsN(silence_nan)(ret, s); } - return ret; + return *ret; default_nan: - *a = partsN(default_nan)(s); - return a; + return partsN(default_nan)(s); } /* @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd_scalbn)(FloatPartsN *a, FloatPartsN *b, * off to the target-specific pick-a-NaN routine. */ if (unlikely(abc_mask & float_cmask_anynan)) { - return partsN(pick_nan_muladd)(a, b, c, s, ab_mask, abc_mask); + *a = partsN(pick_nan_muladd)(a, b, c, s, ab_mask, abc_mask); + return a; } if (flags & float_muladd_negate_c) { -- 2.43.0
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 8 +++++++ fpu/softfloat-parts.c.inc | 49 +++++++++++---------------------------- 2 files changed, 22 insertions(+), 35 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 inline bool is_anynorm(FloatClass c) return float_cmask(c) & float_cmask_anynorm; } +/* Record when denormals have been used. */ +static void record_denormals_used(int mask, float_status *s) +{ + if (unlikely(mask & float_cmask_denormal)) { + float_raise(float_flag_input_denormal_used, s); + } +} + /* FloatParts256 is entirely internal, for parts128_mul* */ typedef struct { FloatClass cls; 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(addsub)(FloatPartsN *a, FloatPartsN *b, * For addition and subtraction, we will consume an * input denormal unless the other input is a NaN. */ - if ((ab_mask & (float_cmask_denormal | float_cmask_anynan)) == - float_cmask_denormal) { - float_raise(float_flag_input_denormal_used, s); + if (!(ab_mask & float_cmask_anynan)) { + record_denormals_used(ab_mask, s); } if (a->sign != b_sign) { @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(mul)(FloatPartsN *a, FloatPartsN *b, if (likely(cmask_is_only_normals(ab_mask))) { FloatPartsW tmp; - if (ab_mask & float_cmask_denormal) { - float_raise(float_flag_input_denormal_used, s); - } + record_denormals_used(ab_mask, s); fracN(mulw)(&tmp, a, b); fracN(truncjam)(a, &tmp); @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(mul)(FloatPartsN *a, FloatPartsN *b, } /* Multiply by 0 or Inf */ - if (ab_mask & float_cmask_denormal) { - float_raise(float_flag_input_denormal_used, s); - } + record_denormals_used(ab_mask, s); if (ab_mask & float_cmask_inf) { a->cls = float_class_inf; @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd_scalbn)(FloatPartsN *a, FloatPartsN *b, * this matches the set of cases where we consumed a * denormal input. */ - if (abc_mask & float_cmask_denormal) { - float_raise(float_flag_input_denormal_used, s); - } + record_denormals_used(abc_mask, s); return a; return_sub_zero: @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(div)(const FloatPartsN *a, const FloatPartsN *b, r.exp -= b->exp; if (likely(cmask_is_only_normals(ab_mask))) { - if (ab_mask & float_cmask_denormal) { - float_raise(float_flag_input_denormal_used, s); - } + record_denormals_used(ab_mask, s); r.exp -= fracN(div)(&r, b); return r; } @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(div)(const FloatPartsN *a, const FloatPartsN *b, return partsN(pick_nan)(a, b, s); } - if ((ab_mask & float_cmask_denormal) && b->cls != float_class_zero) { - float_raise(float_flag_input_denormal_used, s); + if (b->cls != float_class_zero) { + record_denormals_used(ab_mask, s); } /* Inf / X */ @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(modrem)(FloatPartsN *a, FloatPartsN *b, int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); if (likely(cmask_is_only_normals(ab_mask))) { - if (ab_mask & float_cmask_denormal) { - float_raise(float_flag_input_denormal_used, s); - } + record_denormals_used(ab_mask, s); fracN(modrem)(a, b, mod_quot); return a; } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(modrem)(FloatPartsN *a, FloatPartsN *b, return a; } - if (ab_mask & float_cmask_denormal) { - float_raise(float_flag_input_denormal_used, s); - } + record_denormals_used(ab_mask, s); /* N % Inf; 0 % N */ g_assert(b->cls == float_class_inf || a->cls == float_class_zero); @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b, if ((flags & (minmax_isnum | minmax_isnumber)) && !(ab_mask & float_cmask_snan) && (ab_mask & ~float_cmask_qnan)) { - if (ab_mask & float_cmask_denormal) { - float_raise(float_flag_input_denormal_used, s); - } + record_denormals_used(ab_mask, s); return is_nan(a->cls) ? b : a; } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b, return a; } - if (ab_mask & float_cmask_denormal) { - float_raise(float_flag_input_denormal_used, s); - } + record_denormals_used(ab_mask, s); a_exp = a->exp; b_exp = b->exp; @@ -XXX,XX +XXX,XX @@ static FloatRelation partsN(compare)(FloatPartsN *a, FloatPartsN *b, if (likely(cmask_is_only_normals(ab_mask))) { FloatRelation cmp; - if (ab_mask & float_cmask_denormal) { - float_raise(float_flag_input_denormal_used, s); - } + record_denormals_used(ab_mask, s); if (a->sign != b->sign) { goto a_sign; @@ -XXX,XX +XXX,XX @@ static FloatRelation partsN(compare)(FloatPartsN *a, FloatPartsN *b, return float_relation_unordered; } - if (ab_mask & float_cmask_denormal) { - float_raise(float_flag_input_denormal_used, s); - } + record_denormals_used(ab_mask, s); if (ab_mask & float_cmask_zero) { if (ab_mask == float_cmask_zero) { -- 2.43.0
At the same time, export. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 9 +++ fpu/softfloat.c | 81 ++++++++++--------- fpu/softfloat-parts.c.inc | 148 +++++++++++++++++----------------- 3 files changed, 122 insertions(+), 116 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_div(const FloatParts64 *a, const FloatParts64 *b, FloatParts128 parts128_div(const FloatParts128 *a, const FloatParts128 *b, float_status *s); +FloatParts64 parts64_muladd_scalbn(const FloatParts64 *a, + const FloatParts64 *b, + const FloatParts64 *c, + int scale, int flags, float_status *s); +FloatParts128 parts128_muladd_scalbn(const FloatParts128 *a, + const FloatParts128 *b, + const FloatParts128 *c, + int scale, int flags, float_status *s); + void parts64_round_canonical(FloatParts64 *p, float_status *s, const FloatFmt *fmt); 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_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_scalbn(&pa, &pb, &pc, scale, flags, status); + FloatParts64 pr = parts64_muladd_scalbn(&pa, &pb, &pc, + scale, flags, status); /* Round before applying negate result. */ - parts64_uncanon(pr, status, &float16_params, false); - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + parts64_uncanon(&pr, status, &float16_params, false); + 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_scalbn(&pa, &pb, &pc, scale, flags, status); + FloatParts64 pr = parts64_muladd_scalbn(&pa, &pb, &pc, + scale, 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 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_scalbn(&pa, &pb, &pc, scale, flags, status); + FloatParts64 pr = parts64_muladd_scalbn(&pa, &pb, &pc, + scale, flags, status); /* Round before applying negate result. */ - parts64_uncanon(pr, status, &float64_params, false); - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + parts64_uncanon(&pr, status, &float64_params, false); + 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_scalbn(&pa, &pb, &pc, 0, flags, status); + FloatParts64 pr = parts64_muladd_scalbn(&pa, &pb, &pc, 0, 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 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, @@ -XXX,XX +XXX,XX @@ bfloat16 QEMU_FLATTEN 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_scalbn(&pa, &pb, &pc, 0, flags, status); + FloatParts64 pr = parts64_muladd_scalbn(&pa, &pb, &pc, 0, 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 QEMU_FLATTEN float128_muladd(float128 a, float128 b, float128 c, @@ -XXX,XX +XXX,XX @@ float128 QEMU_FLATTEN 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_scalbn(&pa, &pb, &pc, 0, flags, status); + FloatParts128 pr = parts128_muladd_scalbn(&pa, &pb, &pc, 0, 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_scalbn(&tp, &xnp, &rp, 0, 0, status); + rp = parts64_muladd_scalbn(&tp, &xnp, &rp, 0, 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, status, fmt); /* Compute precise remainder */ - r_precise_buf = *b; - r_precise = parts64_muladd_scalbn(&r_precise_buf, n, a, 0, + r_precise = parts64_muladd_scalbn(b, n, a, 0, float_muladd_negate_product, status); /* Round remainder to the target format */ - *r = *r_precise; + *r = r_precise; status->float_exception_flags = 0; parts64_round_canonical(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 @@ static FloatPartsN *partsN(mul)(FloatPartsN *a, 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_scalbn)(FloatPartsN *a, FloatPartsN *b, - FloatPartsN *c, int scale, - int flags, float_status *s) +FloatPartsN partsN(muladd_scalbn)(const FloatPartsN *a, + const FloatPartsN *b, + const FloatPartsN *c, + int scale, int flags, float_status *s) { - int ab_mask, abc_mask; - FloatPartsW p_widen, c_widen; - - ab_mask = float_cmask(a->cls) | float_cmask(b->cls); - abc_mask = float_cmask(c->cls) | ab_mask; + int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); + int abc_mask = float_cmask(c->cls) | ab_mask; + bool c_sign = c->sign ^ !!(flags & float_muladd_negate_c); + bool p_sign = a->sign ^ b->sign ^ !!(flags & float_muladd_negate_product); /* * It is implementation-defined whether the cases of (0,inf,qnan) @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd_scalbn)(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; - } - - if (flags & float_muladd_negate_c) { - c->sign ^= 1; - } - - /* Compute the sign of the product into A. */ - a->sign ^= b->sign; - if (flags & float_muladd_negate_product) { - a->sign ^= 1; + return partsN(pick_nan_muladd)(a, b, c, s, ab_mask, abc_mask); } if (unlikely(!cmask_is_only_normals(ab_mask))) { @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd_scalbn)(FloatPartsN *a, FloatPartsN *b, } if (ab_mask & float_cmask_inf) { - if (c->cls == float_class_inf && a->sign != c->sign) { + if (c->cls == float_class_inf && p_sign != c_sign) { float_raise(float_flag_invalid | float_flag_invalid_isi, s); goto d_nan; } - goto return_inf; + record_denormals_used(abc_mask, s); + return (FloatPartsN){ .sign = p_sign, .cls = float_class_inf }; } - g_assert(ab_mask & float_cmask_zero); - if (is_anynorm(c->cls)) { - *a = *c; - goto return_normal; - } - if (c->cls == float_class_zero) { + record_denormals_used(abc_mask, s); + + assert(ab_mask & float_cmask_zero); + switch (c->cls) { + case float_class_normal: + case float_class_denormal: + { + FloatPartsN r = *c; + r.exp += scale; + return r; + } + + case float_class_zero: if (flags & float_muladd_suppress_add_product_zero) { - a->sign = c->sign; - } else if (a->sign != c->sign) { + /* return zero with new sign */ + } else if (p_sign != c_sign) { goto return_sub_zero; } - goto return_zero; + goto return_zero_c; + + case float_class_inf: + goto return_inf_c; + + default: + g_assert_not_reached(); } - g_assert(c->cls == float_class_inf); } + record_denormals_used(abc_mask, s); + if (unlikely(c->cls == float_class_inf)) { - a->sign = c->sign; - goto return_inf; + goto return_inf_c; } /* 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; - } + { + FloatPartsW p_widen = { .sign = p_sign, .exp = a->exp + b->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; + 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; + } - 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; + /* Perform the addition step. */ + if (c->cls != float_class_zero) { + /* Zero-extend C to less significant bits. */ + FloatPartsW c_widen = { .sign = c_sign, .exp = c->exp }; + fracN(widen)(&c_widen, c); + + if (p_widen.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. */ + { + FloatPartsN r = { + .sign = p_widen.sign, + .exp = p_widen.exp + scale, + .cls = float_class_normal, + }; + fracN(truncjam)(&r, &p_widen); + return r; } } - /* Narrow with sticky bit, for proper rounding later. */ - fracN(truncjam)(a, &p_widen); - a->sign = p_widen.sign; - a->exp = p_widen.exp; - - return_normal: - a->exp += scale; - 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; + return_inf_c: + return (FloatPartsN){ .sign = c_sign, .cls = float_class_inf }; return_sub_zero: - 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; + c_sign = s->float_rounding_mode == float_round_down; + return_zero_c: + return (FloatPartsN){ .sign = c_sign, .cls = float_class_zero }; d_nan: - *a = partsN(default_nan)(s); - return a; + return partsN(default_nan)(s); } /* -- 2.43.0
The float16, bfloat16 and float128 paths are not so important that they require forced optimization. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 13 ++++++------- 1 file changed, 6 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_mul(floatx80 a, floatx80 b, float_status *status) * Fused multiply-add */ -float16 QEMU_FLATTEN -float16_muladd_scalbn(float16 a, float16 b, float16 c, - int scale, int flags, float_status *status) +float16 float16_muladd_scalbn(float16 a, float16 b, float16 c, + int scale, int flags, float_status *status) { FloatParts64 pa = float16_unpack_canonical(a, status); FloatParts64 pb = float16_unpack_canonical(b, status); @@ -XXX,XX +XXX,XX @@ float64 float64r32_muladd(float64 a, float64 b, float64 c, return float64r32_pack_raw(&pr); } -bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, - int flags, float_status *status) +bfloat16 bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, + int flags, float_status *status) { FloatParts64 pa = bfloat16_unpack_canonical(a, status); FloatParts64 pb = bfloat16_unpack_canonical(b, status); @@ -XXX,XX +XXX,XX @@ bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, return pack_raw64(&pr, &bfloat16_params); } -float128 QEMU_FLATTEN float128_muladd(float128 a, float128 b, float128 c, - int flags, float_status *status) +float128 float128_muladd(float128 a, float128 b, float128 c, + int flags, float_status *status) { FloatParts128 pa = float128_unpack_canonical(a, status); FloatParts128 pb = float128_unpack_canonical(b, status); -- 2.43.0
At the same time, constify the inputs. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 5 +++++ fpu/softfloat-parts.c.inc | 4 ++-- 2 files changed, 7 insertions(+), 2 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_div(const FloatParts64 *a, const FloatParts64 *b, FloatParts128 parts128_div(const FloatParts128 *a, const FloatParts128 *b, float_status *s); +FloatRelation parts64_compare(const FloatParts64 *a, const FloatParts64 *b, + float_status *s, bool quiet); +FloatRelation parts128_compare(const FloatParts128 *a, const FloatParts128 *b, + float_status *s, bool quiet); + FloatParts64 parts64_muladd_scalbn(const FloatParts64 *a, const FloatParts64 *b, const FloatParts64 *c, 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, /* * Floating point compare */ -static FloatRelation partsN(compare)(FloatPartsN *a, FloatPartsN *b, - float_status *s, bool is_quiet) +FloatRelation partsN(compare)(const FloatPartsN *a, const FloatPartsN *b, + float_status *s, bool is_quiet) { int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); -- 2.43.0
At the same time, export. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 5 +++++ fpu/softfloat.c | 34 +++++++++++++++++----------------- fpu/softfloat-parts.c.inc | 35 ++++++++++++++++------------------- 3 files changed, 38 insertions(+), 36 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 @@ FloatRelation parts64_compare(const FloatParts64 *a, const FloatParts64 *b, FloatRelation parts128_compare(const FloatParts128 *a, const FloatParts128 *b, float_status *s, bool quiet); +FloatParts64 parts64_mul(const FloatParts64 *a, const FloatParts64 *b, + float_status *s); +FloatParts128 parts128_mul(const FloatParts128 *a, const FloatParts128 *b, + float_status *s); + FloatParts64 parts64_muladd_scalbn(const FloatParts64 *a, const FloatParts64 *b, const FloatParts64 *c, 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 QEMU_FLATTEN float16_mul(float16 a, float16 b, float_status *status) { FloatParts64 pa = float16_unpack_canonical(a, status); FloatParts64 pb = float16_unpack_canonical(b, status); - FloatParts64 *pr = parts64_mul(&pa, &pb, status); + FloatParts64 pr = parts64_mul(&pa, &pb, status); - return float16_round_pack_canonical(pr, status); + return float16_round_pack_canonical(&pr, status); } static float32 QEMU_SOFTFLOAT_ATTR @@ -XXX,XX +XXX,XX @@ soft_f32_mul(float32 a, float32 b, float_status *status) { FloatParts64 pa = float32_unpack_canonical(a, status); FloatParts64 pb = float32_unpack_canonical(b, status); - FloatParts64 *pr = parts64_mul(&pa, &pb, status); + FloatParts64 pr = parts64_mul(&pa, &pb, status); - return float32_round_pack_canonical(pr, status); + return float32_round_pack_canonical(&pr, status); } static float64 QEMU_SOFTFLOAT_ATTR @@ -XXX,XX +XXX,XX @@ soft_f64_mul(float64 a, float64 b, float_status *status) { FloatParts64 pa = float64_unpack_canonical(a, status); FloatParts64 pb = float64_unpack_canonical(b, status); - FloatParts64 *pr = parts64_mul(&pa, &pb, status); + FloatParts64 pr = parts64_mul(&pa, &pb, status); - return float64_round_pack_canonical(pr, status); + return float64_round_pack_canonical(&pr, status); } static float hard_f32_mul(float a, float b) @@ -XXX,XX +XXX,XX @@ float64 float64r32_mul(float64 a, float64 b, float_status *status) { FloatParts64 pa = float64_unpack_canonical(a, status); FloatParts64 pb = float64_unpack_canonical(b, status); - FloatParts64 *pr = parts64_mul(&pa, &pb, status); + FloatParts64 pr = parts64_mul(&pa, &pb, status); - return float64r32_round_pack_canonical(pr, status); + return float64r32_round_pack_canonical(&pr, status); } bfloat16 QEMU_FLATTEN @@ -XXX,XX +XXX,XX @@ bfloat16_mul(bfloat16 a, bfloat16 b, float_status *status) { FloatParts64 pa = bfloat16_unpack_canonical(a, status); FloatParts64 pb = bfloat16_unpack_canonical(b, status); - FloatParts64 *pr = parts64_mul(&pa, &pb, status); + FloatParts64 pr = parts64_mul(&pa, &pb, status); - return bfloat16_round_pack_canonical(pr, status); + return bfloat16_round_pack_canonical(&pr, status); } float128 QEMU_FLATTEN @@ -XXX,XX +XXX,XX @@ float128_mul(float128 a, float128 b, float_status *status) { FloatParts128 pa = float128_unpack_canonical(a, status); FloatParts128 pb = float128_unpack_canonical(b, status); - FloatParts128 *pr = parts128_mul(&pa, &pb, status); + FloatParts128 pr = parts128_mul(&pa, &pb, status); - return float128_round_pack_canonical(pr, status); + return float128_round_pack_canonical(&pr, status); } floatx80 QEMU_FLATTEN floatx80_mul(floatx80 a, floatx80 b, float_status *status) { - FloatParts128 pa, pb, *pr; + FloatParts128 pa, pb; if (!floatx80_unpack_canonical(&pa, a, status) || !floatx80_unpack_canonical(&pb, b, status)) { return floatx80_default_nan(status); } - pr = parts128_mul(&pa, &pb, status); - return floatx80_round_pack_canonical(pr, status); + pa = parts128_mul(&pa, &pb, status); + return floatx80_round_pack_canonical(&pa, status); } /* @@ -XXX,XX +XXX,XX @@ float32 float32_exp2(float32 a, float_status *status) float_raise(float_flag_inexact, status); tp = float64_unpack_canonical(float64_ln2, status); - xp = *parts64_mul(&xp, &tp, status); + xp = parts64_mul(&xp, &tp, status); xnp = xp; 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_scalbn(&tp, &xnp, &rp, 0, 0, status); - xnp = *parts64_mul(&xnp, &xp, status); + xnp = parts64_mul(&xnp, &xp, status); } return float32_round_pack_canonical(&rp, 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 FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b, * `b'. The operation is performed according to the IEC/IEEE Standard * for Binary Floating-Point Arithmetic. */ -static FloatPartsN *partsN(mul)(FloatPartsN *a, FloatPartsN *b, - float_status *s) +FloatPartsN partsN(mul)(const FloatPartsN *a, const FloatPartsN *b, + float_status *s) { int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); bool sign = a->sign ^ b->sign; if (likely(cmask_is_only_normals(ab_mask))) { FloatPartsW tmp; + FloatPartsN r = { + .cls = float_class_normal, + .sign = sign, + .exp = a->exp + b->exp + 1, + }; record_denormals_used(ab_mask, s); fracN(mulw)(&tmp, a, b); - fracN(truncjam)(a, &tmp); + fracN(truncjam)(&r, &tmp); - a->exp += b->exp + 1; - if (!(a->frac_hi & DECOMPOSED_IMPLICIT_BIT)) { - fracN(add)(a, a, a); - a->exp -= 1; + if (!(r.frac_hi & DECOMPOSED_IMPLICIT_BIT)) { + fracN(add)(&r, &r, &r); + r.exp -= 1; } - a->sign = sign; - return a; + return r; } /* Inf * Zero == NaN */ if (unlikely(ab_mask == float_cmask_infzero)) { float_raise(float_flag_invalid | float_flag_invalid_imz, s); - *a = partsN(default_nan)(s); - return a; + return partsN(default_nan)(s); } if (unlikely(ab_mask & float_cmask_anynan)) { - *a = partsN(pick_nan)(a, b, s); - return a; + return partsN(pick_nan)(a, b, s); } /* Multiply by 0 or Inf */ record_denormals_used(ab_mask, s); if (ab_mask & float_cmask_inf) { - a->cls = float_class_inf; - a->sign = sign; - return a; + return (FloatPartsN){ .cls = float_class_inf, .sign = sign }; } g_assert(ab_mask & float_cmask_zero); - a->cls = float_class_zero; - a->sign = sign; - return a; + return (FloatPartsN){ .cls = float_class_zero, .sign = sign }; } /* -- 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. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 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(addsub)(FloatPartsN *a, FloatPartsN *b, bool b_sign = b->sign ^ subtract; int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); + if (unlikely(ab_mask & float_cmask_anynan)) { + *a = partsN(pick_nan)(a, b, s); + return a; + } + /* * 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); if (a->sign != b_sign) { /* Subtraction */ @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b, 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 @@ static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b, 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 @@ static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b, return_b: b->sign = b_sign; return b; - - p_nan: - *a = partsN(pick_nan)(a, b, s); - return a; } /* -- 2.43.0
At the same time, export. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 5 ++++ fpu/softfloat.c | 30 +++++++++++------------ fpu/softfloat-parts.c.inc | 45 ++++++++++++++++++----------------- 3 files changed, 43 insertions(+), 37 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_pick_nan(const FloatParts128 *, const FloatParts128 *, * Operations */ +FloatParts64 parts64_addsub(const FloatParts64 *a, const FloatParts64 *b, + float_status *s, bool subtract); +FloatParts128 parts128_addsub(const FloatParts128 *a, const FloatParts128 *b, + float_status *s, bool subtract); + FloatParts64 parts64_div(const FloatParts64 *a, const FloatParts64 *b, float_status *s); FloatParts128 parts128_div(const FloatParts128 *a, const FloatParts128 *b, 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_addsub(float16 a, float16 b, float_status *status, bool subtract) { FloatParts64 pa = float16_unpack_canonical(a, status); FloatParts64 pb = float16_unpack_canonical(b, status); - FloatParts64 *pr = parts64_addsub(&pa, &pb, status, subtract); + FloatParts64 pr = parts64_addsub(&pa, &pb, status, subtract); - return float16_round_pack_canonical(pr, status); + return float16_round_pack_canonical(&pr, status); } float16 float16_add(float16 a, float16 b, float_status *status) @@ -XXX,XX +XXX,XX @@ soft_f32_addsub(float32 a, float32 b, float_status *status, bool subtract) { FloatParts64 pa = float32_unpack_canonical(a, status); FloatParts64 pb = float32_unpack_canonical(b, status); - FloatParts64 *pr = parts64_addsub(&pa, &pb, status, subtract); + FloatParts64 pr = parts64_addsub(&pa, &pb, status, subtract); - return float32_round_pack_canonical(pr, status); + return float32_round_pack_canonical(&pr, status); } static float32 soft_f32_add(float32 a, float32 b, float_status *status) @@ -XXX,XX +XXX,XX @@ soft_f64_addsub(float64 a, float64 b, float_status *status, bool subtract) { FloatParts64 pa = float64_unpack_canonical(a, status); FloatParts64 pb = float64_unpack_canonical(b, status); - FloatParts64 *pr = parts64_addsub(&pa, &pb, status, subtract); + FloatParts64 pr = parts64_addsub(&pa, &pb, status, subtract); - return float64_round_pack_canonical(pr, status); + return float64_round_pack_canonical(&pr, status); } static float64 soft_f64_add(float64 a, float64 b, float_status *status) @@ -XXX,XX +XXX,XX @@ static float64 float64r32_addsub(float64 a, float64 b, float_status *status, { FloatParts64 pa = float64_unpack_canonical(a, status); FloatParts64 pb = float64_unpack_canonical(b, status); - FloatParts64 *pr = parts64_addsub(&pa, &pb, status, subtract); + FloatParts64 pr = parts64_addsub(&pa, &pb, status, subtract); - return float64r32_round_pack_canonical(pr, status); + return float64r32_round_pack_canonical(&pr, status); } float64 float64r32_add(float64 a, float64 b, float_status *status) @@ -XXX,XX +XXX,XX @@ bfloat16_addsub(bfloat16 a, bfloat16 b, float_status *status, bool subtract) { FloatParts64 pa = bfloat16_unpack_canonical(a, status); FloatParts64 pb = bfloat16_unpack_canonical(b, status); - FloatParts64 *pr = parts64_addsub(&pa, &pb, status, subtract); + FloatParts64 pr = parts64_addsub(&pa, &pb, status, subtract); - return bfloat16_round_pack_canonical(pr, status); + return bfloat16_round_pack_canonical(&pr, status); } bfloat16 bfloat16_add(bfloat16 a, bfloat16 b, float_status *status) @@ -XXX,XX +XXX,XX @@ float128_addsub(float128 a, float128 b, float_status *status, bool subtract) { FloatParts128 pa = float128_unpack_canonical(a, status); FloatParts128 pb = float128_unpack_canonical(b, status); - FloatParts128 *pr = parts128_addsub(&pa, &pb, status, subtract); + FloatParts128 pr = parts128_addsub(&pa, &pb, status, subtract); - return float128_round_pack_canonical(pr, status); + return float128_round_pack_canonical(&pr, status); } float128 float128_add(float128 a, float128 b, float_status *status) @@ -XXX,XX +XXX,XX @@ float128 float128_sub(float128 a, float128 b, float_status *status) static floatx80 QEMU_FLATTEN floatx80_addsub(floatx80 a, floatx80 b, float_status *status, bool subtract) { - FloatParts128 pa, pb, *pr; + FloatParts128 pa, pb; if (!floatx80_unpack_canonical(&pa, a, status) || !floatx80_unpack_canonical(&pb, b, status)) { return floatx80_default_nan(status); } - pr = parts128_addsub(&pa, &pb, status, subtract); - return floatx80_round_pack_canonical(pr, status); + pa = parts128_addsub(&pa, &pb, status, subtract); + return floatx80_round_pack_canonical(&pa, status); } floatx80 floatx80_add(floatx80 a, floatx80 b, float_status *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(uncanon)(FloatPartsN *p, float_status *s, * according to the IEC/IEEE Standard for Binary Floating-Point * Arithmetic. */ -static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b, - float_status *s, bool subtract) +FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, + const FloatPartsN *b_orig, + float_status *s, bool subtract) { - bool b_sign = b->sign ^ subtract; - int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); + int ab_mask = float_cmask(a_orig->cls) | float_cmask(b_orig->cls); if (unlikely(ab_mask & float_cmask_anynan)) { - *a = partsN(pick_nan)(a, b, s); - return a; + return partsN(pick_nan)(a_orig, b_orig, s); } /* @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b, */ record_denormals_used(ab_mask, s); - if (a->sign != b_sign) { + FloatPartsN a = *a_orig; + FloatPartsN b = *b_orig; + + b.sign ^= subtract; + + if (a.sign != b.sign) { /* Subtraction */ if (likely(cmask_is_only_normals(ab_mask))) { - if (partsN(sub_normal)(a, b)) { + if (partsN(sub_normal)(&a, &b)) { return a; } /* Subtract was exact, fall through to set sign. */ @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b, } if (ab_mask == float_cmask_zero) { - a->sign = s->float_rounding_mode == float_round_down; + a.sign = s->float_rounding_mode == float_round_down; return a; } if (ab_mask & float_cmask_inf) { - if (a->cls != float_class_inf) { + if (a.cls != float_class_inf) { /* N - Inf */ - goto return_b; + return b; } - if (b->cls != float_class_inf) { + if (b.cls != float_class_inf) { /* Inf - N */ return a; } /* Inf - Inf */ float_raise(float_flag_invalid | float_flag_invalid_isi, s); - *a = partsN(default_nan)(s); - return a; + return partsN(default_nan)(s); } } else { /* Addition */ if (likely(cmask_is_only_normals(ab_mask))) { - partsN(add_normal)(a, b); + partsN(add_normal)(&a, &b); return a; } @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b, } if (ab_mask & float_cmask_inf) { - a->cls = float_class_inf; + a.cls = float_class_inf; return a; } } - if (b->cls == float_class_zero) { - g_assert(is_anynorm(a->cls)); + 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: - b->sign = b_sign; + g_assert(a.cls == float_class_zero); + g_assert(is_anynorm(b.cls)); return b; } -- 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
Now that we've exposed enough infrastructure, this can be implemented in the backend that needs it. 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_scalbn(b, n, a, 0, - float_muladd_negate_product, status); - - /* Round remainder to the target format */ - *r = r_precise; - status->float_exception_flags = 0; - parts64_round_canonical(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_scalbn(b, n, a, 0, + float_muladd_negate_product, status); + + /* Round remainder to the target format */ + *r = r_precise; + status->float_exception_flags = 0; + parts64_round_canonical(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_scalbn(&p1c, &p2c, &tmp, 0, 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. 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_scalbn(&p1c, &p2c, &tmp, 0, 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
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