: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
Fixes for scalbn and muladd. r~ Richard Henderson (12): fpu: Return struct from parts{64,128}_scalbn fpu: Reorganize partsN(muladd) fpu: Return struct from parts{64,128}_muladd fpu: Hoist nan check in partsN_addsub fpu: Simplify 0 +/- N case in parts_addsub fpu: Use parts64_round_to_int in parts_s390_divide_to_integer target/s390x: Move float{32,64}_s390_divide_to_integer target/arm: Use FloatParts64 in bfdotadd_ebf target/arm: Drop oddstatus from is_ebf and bfdotadd_ebf target/arm: Use FloatParts64 in f16_dotadd fpu: Saturate the exponent in uncanon_normal fpu: Introduce exp_scalbn include/fpu/softfloat-parts.h | 12 ++ include/fpu/softfloat.h | 11 -- target/arm/tcg/vec_internal.h | 12 +- fpu/softfloat.c | 236 ++++++++-------------------------- target/arm/tcg/sme_helper.c | 102 +++++++-------- target/arm/tcg/vec_helper.c | 127 +++++++++--------- target/s390x/tcg/fpu_helper.c | 135 +++++++++++++++++++ fpu/softfloat-parts.c.inc | 236 ++++++++++++++++------------------ 8 files changed, 424 insertions(+), 447 deletions(-) -- 2.43.0
At the same time, export. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 3 +++ fpu/softfloat.c | 18 +++++++++--------- fpu/softfloat-parts.c.inc | 14 ++++++++------ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/include/fpu/softfloat-parts.h b/include/fpu/softfloat-parts.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-parts.h +++ b/include/fpu/softfloat-parts.h @@ -XXX,XX +XXX,XX @@ FloatParts128 parts128_round_to_int(const FloatParts128 *a, FloatParts64 parts64_round_to_fmt(const FloatParts64 *p, float_status *s, const FloatFmt *fmt); +FloatParts64 parts64_scalbn(const FloatParts64 *a, int n, float_status *s); +FloatParts128 parts128_scalbn(const FloatParts128 *a, int n, float_status *s); + #endif diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ float16 float16_muladd_scalbn(float16 a, float16 b, float16 c, /* Before rounding, scale. */ if (scale) { - parts64_scalbn(pr, scale, status); + *pr = parts64_scalbn(pr, scale, status); } parts64_uncanon(pr, status, &float16_params, false); /* After rounding, apply negate result, especially for -0.0. */ @@ -XXX,XX +XXX,XX @@ float32_muladd_scalbn(float32 a, float32 b, float32 c, /* Before rounding, scale. */ if (scale) { - parts64_scalbn(pr, scale, status); + *pr = parts64_scalbn(pr, scale, status); } parts64_uncanon(pr, status, &float32_params, false); /* After rounding, apply negate result, especially for -0.0. */ @@ -XXX,XX +XXX,XX @@ float64_muladd_scalbn(float64 a, float64 b, float64 c, /* Before rounding, scale. */ if (scale) { - parts64_scalbn(pr, scale, status); + *pr = parts64_scalbn(pr, scale, status); } parts64_uncanon(pr, status, &float64_params, false); /* After rounding, apply negate result, especially for -0.0. */ @@ -XXX,XX +XXX,XX @@ float16 float16_scalbn(float16 a, int n, float_status *status) { FloatParts64 p = float16_unpack_canonical(a, status); - parts64_scalbn(&p, n, status); + p = parts64_scalbn(&p, n, status); return float16_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float32 float32_scalbn(float32 a, int n, float_status *status) { FloatParts64 p = float32_unpack_canonical(a, status); - parts64_scalbn(&p, n, status); + p = parts64_scalbn(&p, n, status); return float32_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float64 float64_scalbn(float64 a, int n, float_status *status) { FloatParts64 p = float64_unpack_canonical(a, status); - parts64_scalbn(&p, n, status); + p = parts64_scalbn(&p, n, status); return float64_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_scalbn(bfloat16 a, int n, float_status *status) { FloatParts64 p = bfloat16_unpack_canonical(a, status); - parts64_scalbn(&p, n, status); + p = parts64_scalbn(&p, n, status); return bfloat16_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ float128 float128_scalbn(float128 a, int n, float_status *status) { FloatParts128 p = float128_unpack_canonical(a, status); - parts128_scalbn(&p, n, status); + p = parts128_scalbn(&p, n, status); return float128_round_pack_canonical(&p, status); } @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_scalbn(floatx80 a, int n, float_status *status) if (!floatx80_unpack_canonical(&p, a, status)) { return floatx80_default_nan(status); } - parts128_scalbn(&p, n, status); + p = parts128_scalbn(&p, n, status); return floatx80_round_pack_canonical(&p, status); } diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ FloatRelation partsN(compare)(const FloatPartsN *a, const FloatPartsN *b, /* * Multiply A by 2 raised to the power N. */ -static void partsN(scalbn)(FloatPartsN *a, int n, float_status *s) +FloatPartsN partsN(scalbn)(const FloatPartsN *a, int n, float_status *s) { switch (a->cls) { case float_class_snan: case float_class_qnan: - *a = partsN(return_nan)(a, s); - break; + return partsN(return_nan)(a, s); case float_class_zero: case float_class_inf: - break; + return *a; case float_class_denormal: float_raise(float_flag_input_denormal_used, s); /* fall through */ case float_class_normal: - a->exp += MIN(MAX(n, -0x10000), 0x10000); - break; + { + FloatPartsN r = *a; + r.exp += MIN(MAX(n, -0x10000), 0x10000); + return r; + } default: g_assert_not_reached(); } -- 2.43.0
Check the likely case of normal product and normal or zero addend first; shift NaN and infinity detection down; end with zero product + addend. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 156 +++++++++++++++++--------------------- 1 file changed, 71 insertions(+), 85 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, FloatPartsN *c, int flags, float_status *s) { - int ab_mask, abc_mask; - FloatPartsW p_widen, c_widen; + int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); + int c_mask = float_cmask(c->cls); + int abc_mask = ab_mask | c_mask; + bool c_sign = c->sign ^ !!(flags & float_muladd_negate_c); + bool p_sign = a->sign ^ b->sign ^ !!(flags & float_muladd_negate_product); - ab_mask = float_cmask(a->cls) | float_cmask(b->cls); - abc_mask = float_cmask(c->cls) | ab_mask; + /* + * The "likely" case is A and B normal, so that the product is normal, + * and C normal or zero so that the result is normal. + */ + int likely_mask = ab_mask | (c_mask & ~float_cmask_zero); + if (likely(cmask_is_only_normals(likely_mask))) { + record_denormals_used(abc_mask, s); + + /* Perform the multiplication step. */ + FloatPartsW p_widen = { .sign = p_sign, .exp = a->exp + b->exp + 1 }; + fracN(mulw)(&p_widen, a, b); + if (!(p_widen.frac_hi & DECOMPOSED_IMPLICIT_BIT)) { + fracW(add)(&p_widen, &p_widen, &p_widen); + p_widen.exp -= 1; + } + + /* Perform the addition step. */ + if (!(c_mask & float_cmask_zero)) { + /* Zero-extend C to less significant bits. */ + FloatPartsW c_widen = { .sign = c_sign, .exp = c->exp }; + fracN(widen)(&c_widen, c); + + if (p_sign == c_sign) { + partsW(add_normal)(&p_widen, &c_widen); + } else if (!partsW(sub_normal)(&p_widen, &c_widen)) { + goto return_sub_zero; + } + } + + /* Narrow with sticky bit, for proper rounding later. */ + fracN(truncjam)(a, &p_widen); + a->sign = p_widen.sign; + a->exp = p_widen.exp; + return a; + } /* * It is implementation-defined whether the cases of (0,inf,qnan) @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, return a; } - if (flags & float_muladd_negate_c) { - c->sign ^= 1; + if (unlikely(ab_mask == float_cmask_infzero)) { + /* Inf * Zero == NaN */ + float_raise(float_flag_invalid | float_flag_invalid_imz, s); + goto d_nan; } - /* Compute the sign of the product into A. */ - a->sign ^= b->sign; - if (flags & float_muladd_negate_product) { - a->sign ^= 1; - } - - if (unlikely(!cmask_is_only_normals(ab_mask))) { - if (unlikely(ab_mask == float_cmask_infzero)) { - float_raise(float_flag_invalid | float_flag_invalid_imz, s); + if (unlikely(ab_mask & float_cmask_inf)) { + if ((c_mask & float_cmask_inf) && p_sign != c_sign) { + /* Inf - Inf == NaN */ + float_raise(float_flag_invalid | float_flag_invalid_isi, s); goto d_nan; } - - if (ab_mask & float_cmask_inf) { - if (c->cls == float_class_inf && a->sign != c->sign) { - float_raise(float_flag_invalid | float_flag_invalid_isi, s); - goto d_nan; - } - goto return_inf; - } - - g_assert(ab_mask & float_cmask_zero); - if (is_anynorm(c->cls)) { - *a = *c; - goto finish_sign; - } - if (c->cls == float_class_zero) { - if (flags & float_muladd_suppress_add_product_zero) { - a->sign = c->sign; - } else if (a->sign != c->sign) { - goto return_sub_zero; - } - goto return_zero; - } - g_assert(c->cls == float_class_inf); + /* Inf + C == Inf */ + record_denormals_used(abc_mask, s); + a->sign = p_sign; + a->cls = float_class_inf; + return a; } - - if (unlikely(c->cls == float_class_inf)) { - a->sign = c->sign; - goto return_inf; - } - - /* Perform the multiplication step. */ - p_widen.sign = a->sign; - p_widen.exp = a->exp + b->exp + 1; - fracN(mulw)(&p_widen, a, b); - if (!(p_widen.frac_hi & DECOMPOSED_IMPLICIT_BIT)) { - fracW(add)(&p_widen, &p_widen, &p_widen); - p_widen.exp -= 1; - } - - /* Perform the addition step. */ - if (c->cls != float_class_zero) { - /* Zero-extend C to less significant bits. */ - fracN(widen)(&c_widen, c); - c_widen.exp = c->exp; - - if (a->sign == c->sign) { - partsW(add_normal)(&p_widen, &c_widen); - } else if (!partsW(sub_normal)(&p_widen, &c_widen)) { - goto return_sub_zero; - } - } - - /* Narrow with sticky bit, for proper rounding later. */ - fracN(truncjam)(a, &p_widen); - a->sign = p_widen.sign; - a->exp = p_widen.exp; - - finish_sign: - /* - * All result types except for "return the default NaN - * because this is an Invalid Operation" go through here; - * this matches the set of cases where we consumed a - * denormal input. - */ record_denormals_used(abc_mask, s); - return a; + + /* Only remaining cases are zero product or inf addend. */ + assert((ab_mask & float_cmask_zero) | (c_mask & float_cmask_inf)); + + /* + * P + Inf == Inf, or + * 0 + C == C, + * except for 0 - 0, which needs special rounding, + * except for when we want to suppress this addition step. + */ + if (!(c_mask & float_cmask_zero) + || p_sign == c_sign + || (flags & float_muladd_suppress_add_product_zero)) { + c->sign = c_sign; + return c; + } return_sub_zero: + /* 0 - 0 == -0 for round_down, +0 otherwise. */ a->sign = s->float_rounding_mode == float_round_down; - return_zero: a->cls = float_class_zero; - goto finish_sign; - - return_inf: - a->cls = float_class_inf; - goto finish_sign; + return a; d_nan: *a = partsN(default_nan)(s); -- 2.43.0
At the same time, export. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat-parts.h | 9 ++++ fpu/softfloat.c | 83 +++++++++++++++++------------------ fpu/softfloat-parts.c.inc | 38 ++++++++-------- 3 files changed, 69 insertions(+), 61 deletions(-) diff --git a/include/fpu/softfloat-parts.h b/include/fpu/softfloat-parts.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat-parts.h +++ b/include/fpu/softfloat-parts.h @@ -XXX,XX +XXX,XX @@ FloatParts64 parts64_mul(const FloatParts64 *a, const FloatParts64 *b, FloatParts128 parts128_mul(const FloatParts128 *a, const FloatParts128 *b, float_status *s); +FloatParts64 parts64_muladd(const FloatParts64 *a, + const FloatParts64 *b, + const FloatParts64 *c, + int flags, float_status *s); +FloatParts128 parts128_muladd(const FloatParts128 *a, + const FloatParts128 *b, + const FloatParts128 *c, + int flags, float_status *s); + FloatParts64 parts64_round_to_int(const FloatParts64 *a, FloatRoundMode rmode, int scale, float_status *s, diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ float16 float16_muladd_scalbn(float16 a, float16 b, float16 c, FloatParts64 pa = float16_unpack_canonical(a, status); FloatParts64 pb = float16_unpack_canonical(b, status); FloatParts64 pc = float16_unpack_canonical(c, status); - FloatParts64 *pr = parts64_muladd(&pa, &pb, &pc, flags, status); + FloatParts64 pr = parts64_muladd(&pa, &pb, &pc, flags, status); /* Before rounding, scale. */ if (scale) { - *pr = parts64_scalbn(pr, scale, status); + pr = parts64_scalbn(&pr, scale, status); } - parts64_uncanon(pr, status, &float16_params, false); + parts64_uncanon(&pr, status, &float16_params, false); /* After rounding, apply negate result, especially for -0.0. */ - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return pack_raw64(pr, &float16_params); + return pack_raw64(&pr, &float16_params); } float16 float16_muladd(float16 a, float16 b, float16 c, @@ -XXX,XX +XXX,XX @@ float32_muladd_scalbn(float32 a, float32 b, float32 c, FloatParts64 pa = float32_unpack_canonical(a, status); FloatParts64 pb = float32_unpack_canonical(b, status); FloatParts64 pc = float32_unpack_canonical(c, status); - FloatParts64 *pr = parts64_muladd(&pa, &pb, &pc, flags, status); + FloatParts64 pr = parts64_muladd(&pa, &pb, &pc, flags, status); /* Before rounding, scale. */ if (scale) { - *pr = parts64_scalbn(pr, scale, status); + pr = parts64_scalbn(&pr, scale, status); } - parts64_uncanon(pr, status, &float32_params, false); + parts64_uncanon(&pr, status, &float32_params, false); /* After rounding, apply negate result, especially for -0.0. */ - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return pack_raw64(pr, &float32_params); + return pack_raw64(&pr, &float32_params); } float64 QEMU_SOFTFLOAT_ATTR @@ -XXX,XX +XXX,XX @@ float64_muladd_scalbn(float64 a, float64 b, float64 c, FloatParts64 pa = float64_unpack_canonical(a, status); FloatParts64 pb = float64_unpack_canonical(b, status); FloatParts64 pc = float64_unpack_canonical(c, status); - FloatParts64 *pr = parts64_muladd(&pa, &pb, &pc, flags, status); + FloatParts64 pr = parts64_muladd(&pa, &pb, &pc, flags, status); /* Before rounding, scale. */ if (scale) { - *pr = parts64_scalbn(pr, scale, status); + pr = parts64_scalbn(&pr, scale, status); } - parts64_uncanon(pr, status, &float64_params, false); + parts64_uncanon(&pr, status, &float64_params, false); /* After rounding, apply negate result, especially for -0.0. */ - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return pack_raw64(pr, &float64_params); + return pack_raw64(&pr, &float64_params); } static bool force_soft_fma; @@ -XXX,XX +XXX,XX @@ float64 float64r32_muladd(float64 a, float64 b, float64 c, FloatParts64 pa = float64_unpack_canonical(a, status); FloatParts64 pb = float64_unpack_canonical(b, status); FloatParts64 pc = float64_unpack_canonical(c, status); - FloatParts64 *pr = parts64_muladd(&pa, &pb, &pc, flags, status); + FloatParts64 pr = parts64_muladd(&pa, &pb, &pc, flags, status); /* Round before applying negate result. */ - parts64_uncanon(pr, status, &float32_params, false); - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + parts64_uncanon(&pr, status, &float32_params, false); + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return float64r32_pack_raw(pr); + return float64r32_pack_raw(&pr); } bfloat16 bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, @@ -XXX,XX +XXX,XX @@ bfloat16 bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, FloatParts64 pa = bfloat16_unpack_canonical(a, status); FloatParts64 pb = bfloat16_unpack_canonical(b, status); FloatParts64 pc = bfloat16_unpack_canonical(c, status); - FloatParts64 *pr = parts64_muladd(&pa, &pb, &pc, flags, status); + FloatParts64 pr = parts64_muladd(&pa, &pb, &pc, flags, status); /* Round before applying negate result. */ - parts64_uncanon(pr, status, &bfloat16_params, false); - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + parts64_uncanon(&pr, status, &bfloat16_params, false); + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return pack_raw64(pr, &bfloat16_params); + return pack_raw64(&pr, &bfloat16_params); } float128 float128_muladd(float128 a, float128 b, float128 c, @@ -XXX,XX +XXX,XX @@ float128 float128_muladd(float128 a, float128 b, float128 c, FloatParts128 pa = float128_unpack_canonical(a, status); FloatParts128 pb = float128_unpack_canonical(b, status); FloatParts128 pc = float128_unpack_canonical(c, status); - FloatParts128 *pr = parts128_muladd(&pa, &pb, &pc, flags, status); + FloatParts128 pr = parts128_muladd(&pa, &pb, &pc, flags, status); /* Round before applying negate result. */ - parts128_uncanon(pr, status, &float128_params, false); - if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { - pr->sign ^= 1; + parts128_uncanon(&pr, status, &float128_params, false); + if ((flags & float_muladd_negate_result) && !is_nan(pr.cls)) { + pr.sign ^= 1; } - return float128_pack_raw(pr); + return float128_pack_raw(&pr); } /* @@ -XXX,XX +XXX,XX @@ float32 float32_exp2(float32 a, float_status *status) rp = float64_unpack_canonical(float64_one, status); for (int i = 0; i < 15; i++) { tp = float64_unpack_canonical(float32_exp2_coefficients[i], status); - rp = *parts64_muladd(&tp, &xnp, &rp, 0, status); + rp = parts64_muladd(&tp, &xnp, &rp, 0, status); xnp = parts64_mul(&xnp, &xp, status); } @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, n->sign = a->sign ^ b->sign; *cc = 0; } else { - FloatParts64 *q, q_buf, *r_precise, r_precise_buf; + FloatParts64 *q, q_buf, r_precise; int float_exception_flags = 0; bool is_q_smallish; uint32_t r_flags; @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, 0, fmt->frac_size); /* Compute precise remainder */ - r_precise_buf = *b; - r_precise = parts64_muladd(&r_precise_buf, n, a, + r_precise = parts64_muladd(b, n, a, float_muladd_negate_product, status); /* Round remainder to the target format */ - *r = *r_precise; + *r = r_precise; status->float_exception_flags = 0; *r = parts64_round_to_fmt(r, status, fmt); r_flags = status->float_exception_flags; @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, * toward zero) or incremented. */ saved_r_sign = r->sign; - saved_r_precise_sign = r_precise->sign; + saved_r_precise_sign = r_precise.sign; r->sign = false; - r_precise->sign = false; - if (parts64_compare(r, r_precise, status, true) < + r_precise.sign = false; + if (parts64_compare(r, &r_precise, status, true) < float_relation_equal) { *dxc = 0x8; } else { *dxc = 0xc; } r->sign = saved_r_sign; - r_precise->sign = saved_r_precise_sign; + r_precise.sign = saved_r_precise_sign; } } } diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(mul)(const FloatPartsN *a, const FloatPartsN *b, * Requires A and C extracted into a double-sized structure to provide the * extra space for the widening multiply. */ -static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, - FloatPartsN *c, - int flags, float_status *s) +FloatPartsN partsN(muladd)(const FloatPartsN *a, const FloatPartsN *b, + const FloatPartsN *c, int flags, float_status *s) { int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); int c_mask = float_cmask(c->cls); @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, } /* Narrow with sticky bit, for proper rounding later. */ - fracN(truncjam)(a, &p_widen); - a->sign = p_widen.sign; - a->exp = p_widen.exp; - return a; + FloatPartsN r = { + .sign = p_widen.sign, + .exp = p_widen.exp, + .cls = float_class_normal, + }; + fracN(truncjam)(&r, &p_widen); + return r; } /* @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, * off to the target-specific pick-a-NaN routine. */ if (unlikely(abc_mask & float_cmask_anynan)) { - *a = partsN(pick_nan_muladd)(a, b, c, s, ab_mask, abc_mask); - return a; + return partsN(pick_nan_muladd)(a, b, c, s, ab_mask, abc_mask); } if (unlikely(ab_mask == float_cmask_infzero)) { @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, } /* Inf + C == Inf */ record_denormals_used(abc_mask, s); - a->sign = p_sign; - a->cls = float_class_inf; - return a; + return (FloatPartsN){ .sign = p_sign, .cls = float_class_inf }; } record_denormals_used(abc_mask, s); @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, if (!(c_mask & float_cmask_zero) || p_sign == c_sign || (flags & float_muladd_suppress_add_product_zero)) { - c->sign = c_sign; - return c; + FloatPartsN r = *c; + r.sign = c_sign; + return r; } return_sub_zero: /* 0 - 0 == -0 for round_down, +0 otherwise. */ - a->sign = s->float_rounding_mode == float_round_down; - a->cls = float_class_zero; - return a; + return (FloatPartsN){ + .sign = s->float_rounding_mode == float_round_down, + .cls = float_class_zero + }; d_nan: - *a = partsN(default_nan)(s); - return a; + return partsN(default_nan)(s); } /* -- 2.43.0
The nan test had been down below because it was unlikely. But if we have to have one anyway because of denormals, we might as well take care of them right away. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, { int ab_mask = float_cmask(a_orig->cls) | float_cmask(b_orig->cls); + if (unlikely(ab_mask & float_cmask_anynan)) { + return partsN(pick_nan)(a_orig, b_orig, s); + } + /* * For addition and subtraction, we will consume an * input denormal unless the other input is a NaN. */ - if (!(ab_mask & float_cmask_anynan)) { - record_denormals_used(ab_mask, s); - } + record_denormals_used(ab_mask, s); FloatPartsN a = *a_orig; FloatPartsN b = *b_orig; @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, return a; } - if (unlikely(ab_mask & float_cmask_anynan)) { - goto p_nan; - } - if (ab_mask & float_cmask_inf) { if (a.cls != float_class_inf) { /* N - Inf */ @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, return a; } - if (unlikely(ab_mask & float_cmask_anynan)) { - goto p_nan; - } - if (ab_mask & float_cmask_inf) { a.cls = float_class_inf; return a; @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, g_assert(a.cls == float_class_zero); g_assert(is_anynorm(b.cls)); return b; - - p_nan: - return partsN(pick_nan)(a_orig, b_orig, s); } /* -- 2.43.0
Consolidate the tests for zero and anynorm. Add comments for a few cases. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, } if (ab_mask == float_cmask_zero) { + /* 0 - 0 */ a.sign = s->float_rounding_mode == float_round_down; return a; } @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(addsub)(const FloatPartsN *a_orig, } if (ab_mask == float_cmask_zero) { + /* 0 + 0 */ return a; } if (ab_mask & float_cmask_inf) { + /* N + Inf or Inf + N */ a.cls = float_class_inf; return a; } } - if (b.cls == float_class_zero) { - g_assert(is_anynorm(a.cls)); - return a; - } - - g_assert(a.cls == float_class_zero); - g_assert(is_anynorm(b.cls)); - return b; + /* 0 +/- N or N +/- 0 */ + assert((ab_mask & float_cmask_zero) && (ab_mask & float_cmask_anynorm)); + return b.cls == float_class_zero ? a : b; } /* -- 2.43.0
We will not expose parts_round_to_int_normal. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, * Rounding of partial quotient may be inexact. This is the whole point * of distinguishing partial quotients, so ignore the exception. */ - *n = *q; - parts64_round_to_int_normal(n, - is_q_smallish - ? final_quotient_rounding_mode - : float_round_to_zero, - 0, fmt->frac_size); + *n = parts64_round_to_int(q, + is_q_smallish + ? final_quotient_rounding_mode + : float_round_to_zero, + 0, status, fmt); /* Compute precise remainder */ r_precise = parts64_muladd(b, n, a, -- 2.43.0
Now that we've exposed enough infrastructure, this can be implemented in the backend that needs it. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Ilya Leoshkevich <iii@linux.ibm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/fpu/softfloat.h | 11 --- fpu/softfloat.c | 137 ---------------------------------- target/s390x/tcg/fpu_helper.c | 135 +++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 148 deletions(-) diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index XXXXXXX..XXXXXXX 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -XXX,XX +XXX,XX @@ static inline bool float128_unordered_quiet(float128 a, float128 b, *----------------------------------------------------------------------------*/ float128 float128_default_nan(float_status *status); -#define DECLARE_S390_DIVIDE_TO_INTEGER(floatN) \ -void floatN ## _s390_divide_to_integer(floatN a, floatN b, \ - int final_quotient_rounding_mode, \ - bool mask_underflow, bool mask_inexact, \ - floatN *r, floatN *n, \ - uint32_t *cc, int *dxc, \ - float_status *status) -DECLARE_S390_DIVIDE_TO_INTEGER(float32); -DECLARE_S390_DIVIDE_TO_INTEGER(float64); - - #endif /* SOFTFLOAT_H */ diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_round(floatx80 a, float_status *status) return floatx80_round_pack_canonical(&p, status); } -static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, - int final_quotient_rounding_mode, - bool mask_underflow, bool mask_inexact, - const FloatFmt *fmt, - FloatParts64 *r, FloatParts64 *n, - uint32_t *cc, int *dxc, - float_status *status) -{ - /* POp table "Results: DIVIDE TO INTEGER (Part 1 of 2)" */ - if ((float_cmask(a->cls) | float_cmask(b->cls)) & float_cmask_anynan) { - *r = parts64_pick_nan(a, b, status); - *n = *r; - *cc = 1; - } else if (a->cls == float_class_inf || b->cls == float_class_zero) { - *r = parts64_default_nan(status); - *n = *r; - *cc = 1; - status->float_exception_flags |= float_flag_invalid; - } else if (b->cls == float_class_inf) { - *r = *a; - n->cls = float_class_zero; - n->sign = a->sign ^ b->sign; - *cc = 0; - } else { - FloatParts64 *q, q_buf, r_precise; - int float_exception_flags = 0; - bool is_q_smallish; - uint32_t r_flags; - - /* Compute precise quotient */ - q_buf = parts64_div(a, b, status); - q = &q_buf; - - /* - * Check whether two closest integers can be precisely represented, - * i.e., all their bits fit into the fractional part. - */ - is_q_smallish = q->exp < (fmt->frac_size + 1); - - /* - * Final quotient is rounded using final-quotient-rounding method, and - * partial quotient is rounded toward zero. - * - * Rounding of partial quotient may be inexact. This is the whole point - * of distinguishing partial quotients, so ignore the exception. - */ - *n = parts64_round_to_int(q, - is_q_smallish - ? final_quotient_rounding_mode - : float_round_to_zero, - 0, status, fmt); - - /* Compute precise remainder */ - r_precise = parts64_muladd(b, n, a, - float_muladd_negate_product, status); - - /* Round remainder to the target format */ - *r = r_precise; - status->float_exception_flags = 0; - *r = parts64_round_to_fmt(r, status, fmt); - r_flags = status->float_exception_flags; - - /* POp table "Results: DIVIDE TO INTEGER (Part 2 of 2)" */ - if (is_q_smallish) { - if (r->cls != float_class_zero) { - if (r->exp < 2 - (1 << (fmt->exp_size - 1))) { - if (mask_underflow) { - float_exception_flags |= float_flag_underflow; - *dxc = 0x10; - r->exp += fmt->exp_re_bias; - } - } else if (r_flags & float_flag_inexact) { - float_exception_flags |= float_flag_inexact; - if (mask_inexact) { - bool saved_r_sign, saved_r_precise_sign; - - /* - * Check whether remainder was truncated (rounded - * toward zero) or incremented. - */ - saved_r_sign = r->sign; - saved_r_precise_sign = r_precise.sign; - r->sign = false; - r_precise.sign = false; - if (parts64_compare(r, &r_precise, status, true) < - float_relation_equal) { - *dxc = 0x8; - } else { - *dxc = 0xc; - } - r->sign = saved_r_sign; - r_precise.sign = saved_r_precise_sign; - } - } - } - *cc = 0; - } else if (n->exp > (1 << (fmt->exp_size - 1)) - 1) { - n->exp -= fmt->exp_re_bias; - *cc = r->cls == float_class_zero ? 1 : 3; - } else { - *cc = r->cls == float_class_zero ? 0 : 2; - } - - /* Adjust signs of zero results */ - if (r->cls == float_class_zero) { - r->sign = a->sign; - } - if (n->cls == float_class_zero) { - n->sign = a->sign ^ b->sign; - } - - status->float_exception_flags = float_exception_flags; - } -} - -#define DEFINE_S390_DIVIDE_TO_INTEGER(floatN) \ -void floatN ## _s390_divide_to_integer(floatN a, floatN b, \ - int final_quotient_rounding_mode, \ - bool mask_underflow, bool mask_inexact, \ - floatN *r, floatN *n, \ - uint32_t *cc, int *dxc, \ - float_status *status) \ -{ \ - FloatParts64 pa = floatN ## _unpack_canonical(a, status); \ - FloatParts64 pb = floatN ## _unpack_canonical(b, status); \ - FloatParts64 pr, pn; \ - parts_s390_divide_to_integer(&pa, &pb, final_quotient_rounding_mode, \ - mask_underflow, mask_inexact, \ - &floatN ## _params, \ - &pr, &pn, cc, dxc, status); \ - *r = floatN ## _round_pack_canonical(&pr, status); \ - *n = floatN ## _round_pack_canonical(&pn, status); \ -} - -DEFINE_S390_DIVIDE_TO_INTEGER(float32) -DEFINE_S390_DIVIDE_TO_INTEGER(float64) - static void __attribute__((constructor)) softfloat_init(void) { union_float64 ua, ub, uc, ur; diff --git a/target/s390x/tcg/fpu_helper.c b/target/s390x/tcg/fpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/s390x/tcg/fpu_helper.c +++ b/target/s390x/tcg/fpu_helper.c @@ -XXX,XX +XXX,XX @@ #include "tcg_s390x.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" +#include "fpu/softfloat-parts.h" /* #define DEBUG_HELPER */ #ifdef DEBUG_HELPER @@ -XXX,XX +XXX,XX @@ Int128 HELPER(dxb)(CPUS390XState *env, Int128 a, Int128 b) return RET128(ret); } +static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, + int final_quotient_rounding_mode, + bool mask_underflow, bool mask_inexact, + const FloatFmt *fmt, + FloatParts64 *r, FloatParts64 *n, + uint32_t *cc, int *dxc, + float_status *status) +{ + /* POp table "Results: DIVIDE TO INTEGER (Part 1 of 2)" */ + if ((float_cmask(a->cls) | float_cmask(b->cls)) & float_cmask_anynan) { + *r = parts64_pick_nan(a, b, status); + *n = *r; + *cc = 1; + } else if (a->cls == float_class_inf || b->cls == float_class_zero) { + *r = parts64_default_nan(status); + *n = *r; + *cc = 1; + status->float_exception_flags |= float_flag_invalid; + } else if (b->cls == float_class_inf) { + *r = *a; + n->cls = float_class_zero; + n->sign = a->sign ^ b->sign; + *cc = 0; + } else { + FloatParts64 *q, q_buf, r_precise; + int float_exception_flags = 0; + bool is_q_smallish; + uint32_t r_flags; + + /* Compute precise quotient */ + q_buf = parts64_div(a, b, status); + q = &q_buf; + + /* + * Check whether two closest integers can be precisely represented, + * i.e., all their bits fit into the fractional part. + */ + is_q_smallish = q->exp < (fmt->frac_size + 1); + + /* + * Final quotient is rounded using final-quotient-rounding method, and + * partial quotient is rounded toward zero. + * + * Rounding of partial quotient may be inexact. This is the whole point + * of distinguishing partial quotients, so ignore the exception. + */ + *n = parts64_round_to_int(q, + is_q_smallish + ? final_quotient_rounding_mode + : float_round_to_zero, + 0, status, fmt); + + /* Compute precise remainder */ + r_precise = parts64_muladd(b, n, a, + float_muladd_negate_product, status); + + /* Round remainder to the target format */ + *r = r_precise; + status->float_exception_flags = 0; + *r = parts64_round_to_fmt(r, status, fmt); + r_flags = status->float_exception_flags; + + /* POp table "Results: DIVIDE TO INTEGER (Part 2 of 2)" */ + if (is_q_smallish) { + if (r->cls != float_class_zero) { + if (r->exp < 2 - (1 << (fmt->exp_size - 1))) { + if (mask_underflow) { + float_exception_flags |= float_flag_underflow; + *dxc = 0x10; + r->exp += fmt->exp_re_bias; + } + } else if (r_flags & float_flag_inexact) { + float_exception_flags |= float_flag_inexact; + if (mask_inexact) { + bool saved_r_sign, saved_r_precise_sign; + + /* + * Check whether remainder was truncated (rounded + * toward zero) or incremented. + */ + saved_r_sign = r->sign; + saved_r_precise_sign = r_precise.sign; + r->sign = false; + r_precise.sign = false; + if (parts64_compare(r, &r_precise, status, true) < + float_relation_equal) { + *dxc = 0x8; + } else { + *dxc = 0xc; + } + r->sign = saved_r_sign; + r_precise.sign = saved_r_precise_sign; + } + } + } + *cc = 0; + } else if (n->exp > (1 << (fmt->exp_size - 1)) - 1) { + n->exp -= fmt->exp_re_bias; + *cc = r->cls == float_class_zero ? 1 : 3; + } else { + *cc = r->cls == float_class_zero ? 0 : 2; + } + + /* Adjust signs of zero results */ + if (r->cls == float_class_zero) { + r->sign = a->sign; + } + if (n->cls == float_class_zero) { + n->sign = a->sign ^ b->sign; + } + + status->float_exception_flags = float_exception_flags; + } +} + +#define DEFINE_S390_DIVIDE_TO_INTEGER(floatN) \ +static void floatN ## _s390_divide_to_integer(floatN a, floatN b, \ + int final_quotient_rounding_mode, bool mask_underflow, bool mask_inexact, \ + floatN *r, floatN *n, uint32_t *cc, int *dxc, float_status *status) \ +{ \ + FloatParts64 pa = floatN ## _unpack_canonical(a, status); \ + FloatParts64 pb = floatN ## _unpack_canonical(b, status); \ + FloatParts64 pr, pn; \ + parts_s390_divide_to_integer(&pa, &pb, final_quotient_rounding_mode, \ + mask_underflow, mask_inexact, \ + &floatN ## _params, \ + &pr, &pn, cc, dxc, status); \ + *r = floatN ## _round_pack_canonical(&pr, status); \ + *n = floatN ## _round_pack_canonical(&pn, status); \ +} + +DEFINE_S390_DIVIDE_TO_INTEGER(float32) +DEFINE_S390_DIVIDE_TO_INTEGER(float64) + void HELPER(dib)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3, uint32_t m4, uint32_t bits) { -- 2.43.0
Use softfloat-parts.h so that we can more naturally perform the required operations witha single rounding step. This happens to also simplify the NaN detection step. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/arm/tcg/vec_helper.c | 77 +++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vec_helper.c +++ b/target/arm/tcg/vec_helper.c @@ -XXX,XX +XXX,XX @@ #include "helper.h" #include "tcg/tcg-gvec-desc.h" #include "fpu/softfloat.h" +#include "fpu/softfloat-parts.h" #include "qemu/int128.h" #include "crypto/clmul.h" #include "vec_internal.h" @@ -XXX,XX +XXX,XX @@ float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst) float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst, float_status *fpst_odd) { + /* Unpack two BFloat16 into two Float32, trivially. */ float32 s1r = e1 << 16; float32 s1c = e1 & 0xffff0000u; float32 s2r = e2 << 16; float32 s2c = e2 & 0xffff0000u; float32 t32; + /* + * Compare f16_dotadd() in sme_helper.c, but here we have + * bfloat16 inputs. In particular that means that we do not + * want the FPCR.FZ16 flush semantics, so we use the normal + * float_status for the input handling here. + */ + FloatParts64 p1r = float32_unpack_canonical(s1r, fpst); + FloatParts64 p1c = float32_unpack_canonical(s1c, fpst); + FloatParts64 p2r = float32_unpack_canonical(s2r, fpst); + FloatParts64 p2c = float32_unpack_canonical(s2c, fpst); + + int all_mask = (float_cmask(p1r.cls) | float_cmask(p1c.cls) | + float_cmask(p1r.cls) | float_cmask(p1c.cls)); + /* C.f. FPProcessNaNs4 */ - if (float32_is_any_nan(s1r) || float32_is_any_nan(s1c) || - float32_is_any_nan(s2r) || float32_is_any_nan(s2c)) { - if (float32_is_signaling_nan(s1r, fpst)) { - t32 = s1r; - } else if (float32_is_signaling_nan(s1c, fpst)) { - t32 = s1c; - } else if (float32_is_signaling_nan(s2r, fpst)) { - t32 = s2r; - } else if (float32_is_signaling_nan(s2c, fpst)) { - t32 = s2c; - } else if (float32_is_any_nan(s1r)) { - t32 = s1r; - } else if (float32_is_any_nan(s1c)) { - t32 = s1c; - } else if (float32_is_any_nan(s2r)) { - t32 = s2r; + if (unlikely(all_mask & float_cmask_anynan)) { + if (unlikely(all_mask & float_cmask_snan)) { + if (p1r.cls == float_class_snan) { + t32 = s1r; + } else if (p1c.cls == float_class_snan) { + t32 = s1c; + } else if (p2r.cls == float_class_snan) { + t32 = s2r; + } else { + t32 = s2c; + } } else { - t32 = s2c; + if (p1r.cls == float_class_qnan) { + t32 = s1r; + } else if (p1c.cls == float_class_qnan) { + t32 = s1c; + } else if (p2r.cls == float_class_qnan) { + t32 = s2r; + } else { + t32 = s2c; + } } /* * FPConvertNaN(FPProcessNaN(t32)) will be done as part * of the final addition below. */ } else { - /* - * Compare f16_dotadd() in sme_helper.c, but here we have - * bfloat16 inputs. In particular that means that we do not - * want the FPCR.FZ16 flush semantics, so we use the normal - * float_status for the input handling here. - */ - float64 e1r = float32_to_float64(s1r, fpst); - float64 e1c = float32_to_float64(s1c, fpst); - float64 e2r = float32_to_float64(s2r, fpst); - float64 e2c = float32_to_float64(s2c, fpst); - float64 t64; - /* * The ARM pseudocode function FPDot performs both multiplies - * and the add with a single rounding operation. Emulate this - * by performing the first multiply in round-to-odd, then doing - * the second multiply as fused multiply-add, and rounding to - * float32 all in one step. + * and the add with a single rounding operation. */ - t64 = float64_mul(e1r, e2r, fpst_odd); - t64 = float64r32_muladd(e1c, e2c, t64, 0, fpst); + FloatParts64 tmp = parts64_mul(&p1r, &p2r, fpst); + tmp = parts64_muladd(&p1c, &p2c, &tmp, 0, fpst); - /* This conversion is exact, because we've already rounded. */ - t32 = float64_to_float32(t64, fpst); + t32 = float32_round_pack_canonical(&tmp, fpst); } /* The final accumulation step is not fused. */ -- 2.43.0
This argument is no longer used. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/arm/tcg/vec_internal.h | 12 +++------ target/arm/tcg/sme_helper.c | 6 ++--- target/arm/tcg/vec_helper.c | 50 +++++++++++++++-------------------- 3 files changed, 29 insertions(+), 39 deletions(-) diff --git a/target/arm/tcg/vec_internal.h b/target/arm/tcg/vec_internal.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vec_internal.h +++ b/target/arm/tcg/vec_internal.h @@ -XXX,XX +XXX,XX @@ float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst); * @sum: addend * @e1, @e2: multiplicand vectors * @fpst: floating-point status to use - * @fpst_odd: floating-point status to use for round-to-odd operations * * BFloat16 2-way dot product of @e1 & @e2, accumulating with @sum. * The @e1 and @e2 operands correspond to the 32-bit source vector @@ -XXX,XX +XXX,XX @@ float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst); * Corresponds to the ARM pseudocode function BFDotAdd, specialized * for the FPCR.EBF == 1 case. */ -float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2, - float_status *fpst, float_status *fpst_odd); +float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst); /** * is_ebf: * @env: CPU state * @statusp: pointer to floating point status to fill in - * @oddstatusp: pointer to floating point status to fill in for round-to-odd * * Determine whether a BFDotAdd operation should use FPCR.EBF = 0 - * or FPCR.EBF = 1 semantics. On return, has initialized *statusp - * and *oddstatusp to suitable float_status arguments to use with either - * bfdotadd() or bfdotadd_ebf(). + * or FPCR.EBF = 1 semantics. On return, has initialized *statusp as suitable + * for float_status arguments to either bfdotadd() or bfdotadd_ebf(). * Returns true for EBF = 1, false for EBF = 0. (The caller should use this * to decide whether to call bfdotadd() or bfdotadd_ebf().) */ -bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp); +bool is_ebf(CPUARMState *env, float_status *statusp); /* * Negate as for FPCR.AH=1 -- do not negate NaNs. diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ static void do_bfmopa_w(void *vza, void *vzn, void *vzm, uint32_t desc, uint32_t negx, bool ah_neg) { intptr_t row, col, oprsz = simd_maxsz(desc); - float_status fpst, fpst_odd; + float_status fpst; - if (is_ebf(env, &fpst, &fpst_odd)) { + if (is_ebf(env, &fpst)) { for (row = 0; row < oprsz; ) { uint16_t prow = pn[H2(row >> 4)]; do { @@ -XXX,XX +XXX,XX @@ static void do_bfmopa_w(void *vza, void *vzn, void *vzm, uint32_t m = *(uint32_t *)(vzm + H1_4(col)); m = f16mop_adj_pair(m, pcol, 0); - *a = bfdotadd_ebf(*a, n, m, &fpst, &fpst_odd); + *a = bfdotadd_ebf(*a, n, m, &fpst); } col += 4; pcol >>= 4; diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vec_helper.c +++ b/target/arm/tcg/vec_helper.c @@ -XXX,XX +XXX,XX @@ DO_MMLA_B(gvec_usmmla_b, do_usmmla_b) * BFloat16 Dot Product */ -bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp) +bool is_ebf(CPUARMState *env, float_status *statusp) { /* * For BFDOT, BFMMLA, etc, the behaviour depends on FPCR.EBF. @@ -XXX,XX +XXX,XX @@ bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp) *statusp = env->vfp.fp_status[is_a64(env) ? FPST_A64 : FPST_A32]; set_default_nan_mode(true, statusp); - if (ebf) { - /* EBF=1 needs to do a step with round-to-odd semantics */ - *oddstatusp = *statusp; - set_float_rounding_mode(float_round_to_odd, oddstatusp); - } else { + if (!ebf) { set_flush_to_zero(true, statusp); set_flush_inputs_to_zero(true, statusp); set_float_rounding_mode(float_round_to_odd_inf, statusp); @@ -XXX,XX +XXX,XX @@ float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst) return t1; } -float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2, - float_status *fpst, float_status *fpst_odd) +float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst) { /* Unpack two BFloat16 into two Float32, trivially. */ float32 s1r = e1 << 16; @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_bfdot)(void *vd, void *vn, void *vm, void *va, intptr_t i, opr_sz = simd_oprsz(desc); float32 *d = vd, *a = va; uint32_t *n = vn, *m = vm; - float_status fpst, fpst_odd; + float_status fpst; - if (is_ebf(env, &fpst, &fpst_odd)) { + if (is_ebf(env, &fpst)) { for (i = 0; i < opr_sz / 4; ++i) { - d[i] = bfdotadd_ebf(a[i], n[i], m[i], &fpst, &fpst_odd); + d[i] = bfdotadd_ebf(a[i], n[i], m[i], &fpst); } } else { for (i = 0; i < opr_sz / 4; ++i) { @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_bfdot_idx)(void *vd, void *vn, void *vm, intptr_t eltspersegment = MIN(16 / 4, elements); float32 *d = vd, *a = va; uint32_t *n = vn, *m = vm; - float_status fpst, fpst_odd; + float_status fpst; - if (is_ebf(env, &fpst, &fpst_odd)) { + if (is_ebf(env, &fpst)) { for (i = 0; i < elements; i += eltspersegment) { uint32_t m_idx = m[i + H4(index)]; for (j = i; j < i + eltspersegment; j++) { - d[j] = bfdotadd_ebf(a[j], n[j], m_idx, &fpst, &fpst_odd); + d[j] = bfdotadd_ebf(a[j], n[j], m_idx, &fpst); } } } else { @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_bfvdot_idx)(void *vd, void *vn, void *vm, uint16_t *n0 = vn; uint16_t *n1 = vn + sizeof(ARMVectorReg); uint32_t *m = vm; - float_status fpst, fpst_odd; + float_status fpst; - if (is_ebf(env, &fpst, &fpst_odd)) { + if (is_ebf(env, &fpst)) { for (i = 0; i < elements; i += eltspersegment) { uint32_t m_idx = m[i + H4(idx)]; for (j = 0; j < eltspersegment; j++) { uint32_t nn = (n0[H2(2 * (i + j) + sel)]) | (n1[H2(2 * (i + j) + sel)] << 16); - d[i + H4(j)] = bfdotadd_ebf(a[i + H4(j)], nn, m_idx, - &fpst, &fpst_odd); + d[i + H4(j)] = bfdotadd_ebf(a[i + H4(j)], nn, m_idx, &fpst); } } } else { @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_bfmmla)(void *vd, void *vn, void *vm, void *va, intptr_t s, opr_sz = simd_oprsz(desc); float32 *d = vd, *a = va; uint32_t *n = vn, *m = vm; - float_status fpst, fpst_odd; + float_status fpst; - if (is_ebf(env, &fpst, &fpst_odd)) { + if (is_ebf(env, &fpst)) { for (s = 0; s < opr_sz / 4; s += 4) { float32 sum00, sum01, sum10, sum11; @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_bfmmla)(void *vd, void *vn, void *vm, void *va, * i j i k j k */ sum00 = a[s + H4(0 + 0)]; - sum00 = bfdotadd_ebf(sum00, n[s + H4(0 + 0)], m[s + H4(0 + 0)], &fpst, &fpst_odd); - sum00 = bfdotadd_ebf(sum00, n[s + H4(0 + 1)], m[s + H4(0 + 1)], &fpst, &fpst_odd); + sum00 = bfdotadd_ebf(sum00, n[s + H4(0 + 0)], m[s + H4(0 + 0)], &fpst); + sum00 = bfdotadd_ebf(sum00, n[s + H4(0 + 1)], m[s + H4(0 + 1)], &fpst); sum01 = a[s + H4(0 + 1)]; - sum01 = bfdotadd_ebf(sum01, n[s + H4(0 + 0)], m[s + H4(2 + 0)], &fpst, &fpst_odd); - sum01 = bfdotadd_ebf(sum01, n[s + H4(0 + 1)], m[s + H4(2 + 1)], &fpst, &fpst_odd); + sum01 = bfdotadd_ebf(sum01, n[s + H4(0 + 0)], m[s + H4(2 + 0)], &fpst); + sum01 = bfdotadd_ebf(sum01, n[s + H4(0 + 1)], m[s + H4(2 + 1)], &fpst); sum10 = a[s + H4(2 + 0)]; - sum10 = bfdotadd_ebf(sum10, n[s + H4(2 + 0)], m[s + H4(0 + 0)], &fpst, &fpst_odd); - sum10 = bfdotadd_ebf(sum10, n[s + H4(2 + 1)], m[s + H4(0 + 1)], &fpst, &fpst_odd); + sum10 = bfdotadd_ebf(sum10, n[s + H4(2 + 0)], m[s + H4(0 + 0)], &fpst); + sum10 = bfdotadd_ebf(sum10, n[s + H4(2 + 1)], m[s + H4(0 + 1)], &fpst); sum11 = a[s + H4(2 + 1)]; - sum11 = bfdotadd_ebf(sum11, n[s + H4(2 + 0)], m[s + H4(2 + 0)], &fpst, &fpst_odd); - sum11 = bfdotadd_ebf(sum11, n[s + H4(2 + 1)], m[s + H4(2 + 1)], &fpst, &fpst_odd); + sum11 = bfdotadd_ebf(sum11, n[s + H4(2 + 0)], m[s + H4(2 + 0)], &fpst); + sum11 = bfdotadd_ebf(sum11, n[s + H4(2 + 1)], m[s + H4(2 + 1)], &fpst); d[s + H4(0 + 0)] = sum00; d[s + H4(0 + 1)] = sum01; -- 2.43.0
Use softfloat-parts.h so that we can more naturally perform the required operations witha single rounding step. This happens to also simplify the NaN detection step. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/arm/tcg/sme_helper.c | 96 ++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 56 deletions(-) diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ #include "accel/tcg/helper-retaddr.h" #include "qemu/int128.h" #include "fpu/softfloat.h" +#include "fpu/softfloat-parts.h" #include "vec_internal.h" #include "sve_ldst_internal.h" @@ -XXX,XX +XXX,XX @@ static inline uint32_t bf16mop_ah_neg_adj_pair(uint32_t pair, uint32_t pg) } static float32 f16_dotadd(float32 sum, uint32_t e1, uint32_t e2, - float_status *s_f16, float_status *s_std, - float_status *s_odd) + float_status *s_f16, float_status *s_std) { /* - * We need three different float_status for different parts of this + * We need two different float_status for different parts of this * operation: * - the input conversion of the float16 values must use the * f16-specific float_status, so that the FPCR.FZ16 control is applied * - operations on float32 including the final accumulation must use * the normal float_status, so that FPCR.FZ is applied - * - we have pre-set-up copy of s_std which is set to round-to-odd, - * for the multiply (see below) */ float16 h1r = e1 & 0xffff; float16 h1c = e1 >> 16; @@ -XXX,XX +XXX,XX @@ static float32 f16_dotadd(float32 sum, uint32_t e1, uint32_t e2, float16 h2c = e2 >> 16; float32 t32; + FloatParts64 p1r = float16_unpack_canonical(h1r, s_f16); + FloatParts64 p1c = float16_unpack_canonical(h1c, s_f16); + FloatParts64 p2r = float16_unpack_canonical(h2r, s_f16); + FloatParts64 p2c = float16_unpack_canonical(h2c, s_f16); + + int all_mask = (float_cmask(p1r.cls) | float_cmask(p1c.cls) | + float_cmask(p1r.cls) | float_cmask(p1c.cls)); + /* C.f. FPProcessNaNs4 */ - if (float16_is_any_nan(h1r) || float16_is_any_nan(h1c) || - float16_is_any_nan(h2r) || float16_is_any_nan(h2c)) { + if (unlikely(all_mask & float_cmask_anynan)) { float16 t16; - if (float16_is_signaling_nan(h1r, s_f16)) { - t16 = h1r; - } else if (float16_is_signaling_nan(h1c, s_f16)) { - t16 = h1c; - } else if (float16_is_signaling_nan(h2r, s_f16)) { - t16 = h2r; - } else if (float16_is_signaling_nan(h2c, s_f16)) { - t16 = h2c; - } else if (float16_is_any_nan(h1r)) { - t16 = h1r; - } else if (float16_is_any_nan(h1c)) { - t16 = h1c; - } else if (float16_is_any_nan(h2r)) { - t16 = h2r; + if (unlikely(all_mask & float_cmask_snan)) { + if (p1r.cls == float_class_snan) { + t16 = h1r; + } else if (p1c.cls == float_class_snan) { + t16 = h1c; + } else if (p2r.cls == float_class_snan) { + t16 = h2r; + } else { + t16 = h2c; + } } else { - t16 = h2c; + if (p1r.cls == float_class_qnan) { + t16 = h1r; + } else if (p1c.cls == float_class_qnan) { + t16 = h1c; + } else if (p2r.cls == float_class_qnan) { + t16 = h2r; + } else { + t16 = h2c; + } } t32 = float16_to_float32(t16, true, s_f16); } else { - float64 e1r = float16_to_float64(h1r, true, s_f16); - float64 e1c = float16_to_float64(h1c, true, s_f16); - float64 e2r = float16_to_float64(h2r, true, s_f16); - float64 e2c = float16_to_float64(h2c, true, s_f16); - float64 t64; - /* * The ARM pseudocode function FPDot performs both multiplies - * and the add with a single rounding operation. Emulate this - * by performing the first multiply in round-to-odd, then doing - * the second multiply as fused multiply-add, and rounding to - * float32 all in one step. + * and the add with a single rounding operation. */ - t64 = float64_mul(e1r, e2r, s_odd); - t64 = float64r32_muladd(e1c, e2c, t64, 0, s_std); + FloatParts64 tmp = parts64_mul(&p1r, &p2r, s_std); + tmp = parts64_muladd(&p1c, &p2c, &tmp, 0, s_std); - /* This conversion is exact, because we've already rounded. */ - t32 = float64_to_float32(t64, s_std); + t32 = float32_round_pack_canonical(&tmp, s_std); } /* The final accumulation step is not fused. */ @@ -XXX,XX +XXX,XX @@ static void do_fmopa_w_h(void *vza, void *vzn, void *vzm, uint16_t *pn, uint32_t negx, bool ah_neg) { intptr_t row, col, oprsz = simd_maxsz(desc); - float_status fpst_odd = env->vfp.fp_status[FPST_ZA]; - - set_float_rounding_mode(float_round_to_odd, &fpst_odd); for (row = 0; row < oprsz; ) { uint16_t prow = pn[H2(row >> 4)]; @@ -XXX,XX +XXX,XX @@ static void do_fmopa_w_h(void *vza, void *vzn, void *vzm, uint16_t *pn, m = f16mop_adj_pair(m, pcol, 0); *a = f16_dotadd(*a, n, m, &env->vfp.fp_status[FPST_ZA_F16], - &env->vfp.fp_status[FPST_ZA], - &fpst_odd); + &env->vfp.fp_status[FPST_ZA]); } col += 4; pcol >>= 4; @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_fdot_h)(void *vd, void *vn, void *vm, void *va, bool za = extract32(desc, SIMD_DATA_SHIFT, 1); float_status *fpst_std = &env->vfp.fp_status[za ? FPST_ZA : FPST_A64]; float_status *fpst_f16 = &env->vfp.fp_status[za ? FPST_ZA_F16 : FPST_A64_F16]; - float_status fpst_odd = *fpst_std; float32 *d = vd, *a = va; uint32_t *n = vn, *m = vm; - set_float_rounding_mode(float_round_to_odd, &fpst_odd); - for (i = 0; i < oprsz / sizeof(float32); ++i) { d[H4(i)] = f16_dotadd(a[H4(i)], n[H4(i)], m[H4(i)], - fpst_f16, fpst_std, &fpst_odd); + fpst_f16, fpst_std); } } @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_fdot_idx_h)(void *vd, void *vn, void *vm, void *va, bool za = extract32(desc, SIMD_DATA_SHIFT + 2, 1); float_status *fpst_std = &env->vfp.fp_status[za ? FPST_ZA : FPST_A64]; float_status *fpst_f16 = &env->vfp.fp_status[za ? FPST_ZA_F16 : FPST_A64_F16]; - float_status fpst_odd = *fpst_std; float32 *d = vd, *a = va; uint32_t *n = vn, *m = (uint32_t *)vm + H4(idx); - set_float_rounding_mode(float_round_to_odd, &fpst_odd); - for (i = 0; i < elements; i += eltspersegment) { uint32_t mm = m[i]; for (j = 0; j < eltspersegment; ++j) { d[H4(i + j)] = f16_dotadd(a[H4(i + j)], n[H4(i + j)], mm, - fpst_f16, fpst_std, &fpst_odd); + fpst_f16, fpst_std); } } } @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_fvdot_idx_h)(void *vd, void *vn, void *vm, void *va, intptr_t eltspersegment = MIN(4, elements); int idx = extract32(desc, SIMD_DATA_SHIFT, 2); int sel = extract32(desc, SIMD_DATA_SHIFT + 2, 1); - float_status fpst_odd, *fpst_std, *fpst_f16; float32 *d = vd, *a = va; uint16_t *n0 = vn; uint16_t *n1 = vn + sizeof(ARMVectorReg); uint32_t *m = (uint32_t *)vm + H4(idx); - fpst_std = &env->vfp.fp_status[FPST_ZA]; - fpst_f16 = &env->vfp.fp_status[FPST_ZA_F16]; - fpst_odd = *fpst_std; - set_float_rounding_mode(float_round_to_odd, &fpst_odd); - for (i = 0; i < elements; i += eltspersegment) { uint32_t mm = m[i]; for (j = 0; j < eltspersegment; ++j) { uint32_t nn = (n0[H2(2 * (i + j) + sel)]) | (n1[H2(2 * (i + j) + sel)] << 16); d[i + H4(j)] = f16_dotadd(a[i + H4(j)], nn, mm, - fpst_f16, fpst_std, &fpst_odd); + &env->vfp.fp_status[FPST_ZA_F16], + &env->vfp.fp_status[FPST_ZA]); } } } -- 2.43.0
Notice the conflict between saturation and rebias_overflow, which should never happen. Otherwise, saturate to INT32_MAX and allow the usual overflow to max, infinity, or dnan. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, g_assert_not_reached(); } - exp = p->exp + fmt->exp_bias; + /* Because exp_bias is positive, we can only overflow past INT_MAX. */ + if (sadd32_overflow(p->exp, fmt->exp_bias, &exp)) { + /* + * rebias_overflow wants to compute a modulo exponent, which + * conflicts with saturation. That said, saturation can only + * happen with scalbn, which is not a PowerPC operation. + */ + assert(!s->rebias_overflow); + exp = INT32_MAX; + } + if (likely(exp > 0)) { if (p->frac_lo & round_mask) { flags |= float_flag_inexact; -- 2.43.0
Avoid exponent overflow as well as checking that we don't lose information with opposing scaling. Use it in partsN(scalbn) and partsN(round_to_int_normal). Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat.c | 17 +++++++++++++++++ fpu/softfloat-parts.c.inc | 5 ++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -XXX,XX +XXX,XX @@ static float128 QEMU_FLATTEN float128_pack_raw(const FloatParts128 *p) *----------------------------------------------------------------------------*/ #include "softfloat-specialize.c.inc" +static int32_t exp_scalbn(int32_t exp, int32_t scale) +{ + /* + * Catch chains of scaling which lose information. + * In particular, if the exponent has been saturated, + * do not allow it to become unsaturated. + */ + if (unlikely(exp == INT32_MAX)) { + assert(scale >= 0); + } else if (unlikely(exp == INT32_MIN)) { + assert(scale <= 0); + } else { + exp = sadd32_saturate(exp, scale); + } + return exp; +} + /* * Helper functions for softfloat-parts.c.inc, per-size operations. */ diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode, uint64_t frac_lsb, frac_lsbm1, rnd_even_mask, rnd_mask, inc; int shift_adj; - scale = MIN(MAX(scale, -0x10000), 0x10000); - a->exp += scale; + a->exp = exp_scalbn(a->exp, scale); if (a->exp < 0) { bool one; @@ -XXX,XX +XXX,XX @@ FloatPartsN partsN(scalbn)(const FloatPartsN *a, int n, float_status *s) case float_class_normal: { FloatPartsN r = *a; - r.exp += MIN(MAX(n, -0x10000), 0x10000); + r.exp = exp_scalbn(r.exp, n); return r; } default: -- 2.43.0