fpu: Reorganize partsN(muladd)

Check the likely case of normal product and normal or
zero addend first; shift NaN and infinity detection down;
end with zero product + addend.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson
2026-04-28 10:13:45 +10:00
parent 5f36d09bf6
commit 8b44b423ff

View File

@@ -681,11 +681,47 @@ 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)
@@ -698,97 +734,47 @@ 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);