From 1f5d3cebf0d5131e4dada5c07d778b00eb9ce2e2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 28 Apr 2026 08:01:10 +1000 Subject: [PATCH] fpu: Split scalbn from partsN(muladd_scalbn) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handle the scaling separately with parts64_scalbn. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- fpu/softfloat-parts.c.inc | 20 ++++++++++---------- fpu/softfloat.c | 37 ++++++++++++++++++++++++------------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index 028c2daa27..b8baaf1e76 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -669,17 +669,19 @@ static FloatPartsN *partsN(mul)(FloatPartsN *a, FloatPartsN *b, * `b' then adding 'c', with no intermediate rounding step after the * multiplication. The operation is performed according to the * IEC/IEEE Standard for Binary Floating-Point Arithmetic 754-2008. - * The flags argument allows the caller to select negation of the - * addend, the intermediate product, or the final result. (The - * difference between this and having the caller do a separate - * negation is that negating externally will flip the sign bit on NaNs.) + * The flags argument allows the caller to select negation of the addend + * or the intermediate product. (The difference between this and having + * the caller do a separate negation is that negating externally will + * flip the sign bit on NaNs.) Note that float_muladd_negate_result + * is not applied here, and should be handled separately after rounding + * chooses the final sign of 0.0. * * 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) +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; @@ -725,7 +727,7 @@ static FloatPartsN *partsN(muladd_scalbn)(FloatPartsN *a, FloatPartsN *b, g_assert(ab_mask & float_cmask_zero); if (is_anynorm(c->cls)) { *a = *c; - goto return_normal; + goto finish_sign; } if (c->cls == float_class_zero) { if (flags & float_muladd_suppress_add_product_zero) { @@ -770,8 +772,6 @@ static FloatPartsN *partsN(muladd_scalbn)(FloatPartsN *a, FloatPartsN *b, 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 diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 0a8da13e01..962528cb73 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -1907,11 +1907,14 @@ 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(&pa, &pb, &pc, flags, status); - /* Round before applying negate result. */ + /* Before rounding, scale. */ + if (scale) { + parts64_scalbn(pr, scale, status); + } 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; } @@ -1931,10 +1934,14 @@ 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(&pa, &pb, &pc, flags, status); - /* Round before applying negate result. */ + /* Before rounding, scale. */ + if (scale) { + parts64_scalbn(pr, scale, status); + } 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; } @@ -1948,10 +1955,14 @@ 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(&pa, &pb, &pc, flags, status); - /* Round before applying negate result. */ + /* Before rounding, scale. */ + if (scale) { + parts64_scalbn(pr, scale, status); + } 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; } @@ -2105,7 +2116,7 @@ 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(&pa, &pb, &pc, flags, status); /* Round before applying negate result. */ parts64_uncanon(pr, status, &float32_params, false); @@ -2121,7 +2132,7 @@ 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(&pa, &pb, &pc, flags, status); /* Round before applying negate result. */ parts64_uncanon(pr, status, &bfloat16_params, false); @@ -2137,7 +2148,7 @@ 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(&pa, &pb, &pc, flags, status); /* Round before applying negate result. */ parts128_uncanon(pr, status, &float128_params, false); @@ -5116,7 +5127,7 @@ 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(&tp, &xnp, &rp, 0, status); xnp = *parts64_mul(&xnp, &xp, status); } @@ -5196,8 +5207,8 @@ static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b, /* Compute precise remainder */ r_precise_buf = *b; - r_precise = parts64_muladd_scalbn(&r_precise_buf, n, a, 0, - float_muladd_negate_product, status); + r_precise = parts64_muladd(&r_precise_buf, n, a, + float_muladd_negate_product, status); /* Round remainder to the target format */ *r = *r_precise;