@@ -39,24 +39,88 @@ static void partsN(return_nan)(FloatPartsN *a, float_status *s)
static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
float_status *s)
{
+ int cmp, which;
+
if (is_snan(a->cls) || is_snan(b->cls)) {
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
}
if (s->default_nan_mode) {
parts_default_nan(a, s);
- } else {
- int cmp = frac_cmp(a, b);
- if (cmp == 0) {
- cmp = a->sign < b->sign;
- }
+ return a;
+ }
- if (pickNaN(a->cls, b->cls, cmp > 0, s)) {
- a = b;
- }
+ cmp = frac_cmp(a, b);
+ if (cmp == 0) {
+ cmp = a->sign < b->sign;
+ }
+
+ switch (s->float_2nan_prop_rule) {
+ case float_2nan_prop_s_ab:
if (is_snan(a->cls)) {
- parts_silence_nan(a, s);
+ which = 0;
+ } else if (is_snan(b->cls)) {
+ which = 1;
+ } else if (is_qnan(a->cls)) {
+ which = 0;
+ } else {
+ which = 1;
}
+ break;
+ case float_2nan_prop_s_ba:
+ if (is_snan(b->cls)) {
+ which = 1;
+ } else if (is_snan(a->cls)) {
+ which = 0;
+ } else if (is_qnan(b->cls)) {
+ which = 1;
+ } else {
+ which = 0;
+ }
+ break;
+ case float_2nan_prop_ab:
+ which = is_nan(a->cls) ? 0 : 1;
+ break;
+ case float_2nan_prop_ba:
+ which = is_nan(b->cls) ? 1 : 0;
+ break;
+ case float_2nan_prop_x87:
+ /*
+ * This implements x87 NaN propagation rules:
+ * SNaN + QNaN => return the QNaN
+ * two SNaNs => return the one with the larger significand, silenced
+ * two QNaNs => return the one with the larger significand
+ * SNaN and a non-NaN => return the SNaN, silenced
+ * QNaN and a non-NaN => return the QNaN
+ *
+ * If we get down to comparing significands and they are the same,
+ * return the NaN with the positive sign bit (if any).
+ */
+ if (is_snan(a->cls)) {
+ if (is_snan(b->cls)) {
+ which = cmp > 0 ? 0 : 1;
+ } else {
+ which = is_qnan(b->cls) ? 1 : 0;
+ }
+ } else if (is_qnan(a->cls)) {
+ if (is_snan(b->cls) || !is_qnan(b->cls)) {
+ which = 0;
+ } else {
+ which = cmp > 0 ? 0 : 1;
+ }
+ } else {
+ which = 1;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (which) {
+ a = b;
+ }
+ if (is_snan(a->cls)) {
+ parts_silence_nan(a, s);
}
return a;
}
@@ -352,102 +352,6 @@ bool float32_is_signaling_nan(float32 a_, float_status *status)
}
}
-/*----------------------------------------------------------------------------
-| Select which NaN to propagate for a two-input operation.
-| IEEE754 doesn't specify all the details of this, so the
-| algorithm is target-specific.
-| The routine is passed various bits of information about the
-| two NaNs and should return 0 to select NaN a and 1 for NaN b.
-| Note that signalling NaNs are always squashed to quiet NaNs
-| by the caller, by calling floatXX_silence_nan() before
-| returning them.
-|
-| aIsLargerSignificand is only valid if both a and b are NaNs
-| of some kind, and is true if a has the larger significand,
-| or if both a and b have the same significand but a is
-| positive but b is negative. It is only needed for the x87
-| tie-break rule.
-*----------------------------------------------------------------------------*/
-
-static int pickNaN(FloatClass a_cls, FloatClass b_cls,
- bool aIsLargerSignificand, float_status *status)
-{
- /*
- * We guarantee not to require the target to tell us how to
- * pick a NaN if we're always returning the default NaN.
- * But if we're not in default-NaN mode then the target must
- * specify via set_float_2nan_prop_rule().
- */
- assert(!status->default_nan_mode);
-
- switch (status->float_2nan_prop_rule) {
- case float_2nan_prop_s_ab:
- if (is_snan(a_cls)) {
- return 0;
- } else if (is_snan(b_cls)) {
- return 1;
- } else if (is_qnan(a_cls)) {
- return 0;
- } else {
- return 1;
- }
- break;
- case float_2nan_prop_s_ba:
- if (is_snan(b_cls)) {
- return 1;
- } else if (is_snan(a_cls)) {
- return 0;
- } else if (is_qnan(b_cls)) {
- return 1;
- } else {
- return 0;
- }
- break;
- case float_2nan_prop_ab:
- if (is_nan(a_cls)) {
- return 0;
- } else {
- return 1;
- }
- break;
- case float_2nan_prop_ba:
- if (is_nan(b_cls)) {
- return 1;
- } else {
- return 0;
- }
- break;
- case float_2nan_prop_x87:
- /*
- * This implements x87 NaN propagation rules:
- * SNaN + QNaN => return the QNaN
- * two SNaNs => return the one with the larger significand, silenced
- * two QNaNs => return the one with the larger significand
- * SNaN and a non-NaN => return the SNaN, silenced
- * QNaN and a non-NaN => return the QNaN
- *
- * If we get down to comparing significands and they are the same,
- * return the NaN with the positive sign bit (if any).
- */
- if (is_snan(a_cls)) {
- if (is_snan(b_cls)) {
- return aIsLargerSignificand ? 0 : 1;
- }
- return is_qnan(b_cls) ? 1 : 0;
- } else if (is_qnan(a_cls)) {
- if (is_snan(b_cls) || !is_qnan(b_cls)) {
- return 0;
- } else {
- return aIsLargerSignificand ? 0 : 1;
- }
- } else {
- return 1;
- }
- default:
- g_assert_not_reached();
- }
-}
-
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is a quiet
| NaN; otherwise returns 0.
Inline pickNaN into its only caller. This makes one assert redundant with the immediately preceding IF. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- fpu/softfloat-parts.c.inc | 82 +++++++++++++++++++++++++---- fpu/softfloat-specialize.c.inc | 96 ---------------------------------- 2 files changed, 73 insertions(+), 105 deletions(-)