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 <[email protected]>
---
fpu/softfloat-parts.c.inc | 155 +++++++++++++++++---------------------
1 file changed, 70 insertions(+), 85 deletions(-)
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
index 3a9c2748cd..3d2606c07c 100644
--- a/fpu/softfloat-parts.c.inc
+++ b/fpu/softfloat-parts.c.inc
@@ -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,46 @@ 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 case is zero product. */
+ assert(ab_mask & float_cmask_zero);