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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user