diff mbox

[v7,4/6] softfloat: Add minNum() and maxNum() functions to softfloat.

Message ID 1386015177-6621-5-git-send-email-will.newton@linaro.org
State New
Headers show

Commit Message

Will Newton Dec. 2, 2013, 8:12 p.m. UTC
Add floatnn_minnum() and floatnn_maxnum() functions which are equivalent
to the minNum() and maxNum() functions from IEEE 754-2008. They are
similar to min() and max() but differ in the handling of QNaN arguments.
---
 fpu/softfloat.c         | 54 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/fpu/softfloat.h |  4 ++++
 2 files changed, 58 insertions(+)

Changes in v7:
 - New patch

Comments

Peter Maydell Dec. 2, 2013, 9:55 p.m. UTC | #1
On 2 December 2013 20:12, Will Newton <will.newton@linaro.org> wrote:
> Add floatnn_minnum() and floatnn_maxnum() functions which are equivalent
> to the minNum() and maxNum() functions from IEEE 754-2008. They are
> similar to min() and max() but differ in the handling of QNaN arguments.

Missing Signed-off-by: line here.

> ---
>  fpu/softfloat.c         | 54 +++++++++++++++++++++++++++++++++++++++++++++++++
>  include/fpu/softfloat.h |  4 ++++
>  2 files changed, 58 insertions(+)
>
> Changes in v7:
>  - New patch
>
> diff --git a/fpu/softfloat.c b/fpu/softfloat.c
> index 97bf627..9834927 100644
> --- a/fpu/softfloat.c
> +++ b/fpu/softfloat.c
> @@ -6750,6 +6750,60 @@ float ## s float ## s ## _max(float ## s a, float ## s b STATUS_PARAM)  \
>  MINMAX(32)
>  MINMAX(64)
>
> +/* minnum() and maxnum() functions. These are similar to the min()
> + * and max() functions but if one of the arguments is a QNaN and
> + * the other is numerical then the numerical argument is returned.

I think this comment could usefully be expanded to add:
 * minnum() and maxnum correspond to the IEEE 754-2008 minNum()
 * and maxNum() operations. min() and max() are the typical min/max
 * semantics provided by many CPUs which predate that specification.



> + */
> +#define MINMAXNUM(s)                                                       \
> +INLINE float ## s float ## s ## _minmaxnum(float ## s a, float ## s b,     \
> +                                           int ismin STATUS_PARAM )        \
> +{                                                                          \
> +    flag aSign, bSign;                                                     \
> +    uint ## s ## _t av, bv;                                                \
> +    a = float ## s ## _squash_input_denormal(a STATUS_VAR);                \
> +    b = float ## s ## _squash_input_denormal(b STATUS_VAR);                \
> +    if (float ## s ## _is_quiet_nan(a) &&                                  \
> +        !float ## s ##_is_quiet_nan(b)) {                                  \
> +        return b;                                                          \
> +    } else if (float ## s ## _is_quiet_nan(b) &&                           \
> +               !float ## s ## _is_quiet_nan(a)) {                          \
> +        return a;                                                          \

This is incorrect if the inputs are one signalling NaN and one
quiet NaN (both according to the IEEE spec and the ARM ARM
pseudocode). Among other things we will fail to signal InvalidOp.

Also, the bulk of this macro is identical to MINMAX. That suggests
we could instead extend MINMAX to define functions taking an
extra parameter isminmaxnum indicating we want 754-2008
semantics, and then we just need to replace the current NaN-check
clause in it with this one:

    if (float ## s ## _is_any_nan(a) ||
        float ## s ## _is_any_nan(b)) {
        if (isminmax) {
            if ((float ## s ## _is_quiet_nan(a) && !float ## s ##
_is_any_nan(b)) {
                return b;
            }
             if ((float ## s ## _is_quiet_nan(b) && !float ## s ##
_is_any_nan(a)) {
                return a;
            }
       }
       return propagateFloat ## s ## NaN(a, b STATUS_VAR);
  }

(line continuation backslashes omitted for clarity)

thanks
-- PMM
diff mbox

Patch

diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 97bf627..9834927 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -6750,6 +6750,60 @@  float ## s float ## s ## _max(float ## s a, float ## s b STATUS_PARAM)  \
 MINMAX(32)
 MINMAX(64)
 
+/* minnum() and maxnum() functions. These are similar to the min()
+ * and max() functions but if one of the arguments is a QNaN and
+ * the other is numerical then the numerical argument is returned.
+ */
+#define MINMAXNUM(s)                                                       \
+INLINE float ## s float ## s ## _minmaxnum(float ## s a, float ## s b,     \
+                                           int ismin STATUS_PARAM )        \
+{                                                                          \
+    flag aSign, bSign;                                                     \
+    uint ## s ## _t av, bv;                                                \
+    a = float ## s ## _squash_input_denormal(a STATUS_VAR);                \
+    b = float ## s ## _squash_input_denormal(b STATUS_VAR);                \
+    if (float ## s ## _is_quiet_nan(a) &&                                  \
+        !float ## s ##_is_quiet_nan(b)) {                                  \
+        return b;                                                          \
+    } else if (float ## s ## _is_quiet_nan(b) &&                           \
+               !float ## s ## _is_quiet_nan(a)) {                          \
+        return a;                                                          \
+    } else if (float ## s ## _is_any_nan(a) ||                             \
+        float ## s ## _is_any_nan(b)) {                                    \
+        return propagateFloat ## s ## NaN(a, b STATUS_VAR);                \
+    }                                                                      \
+    aSign = extractFloat ## s ## Sign(a);                                  \
+    bSign = extractFloat ## s ## Sign(b);                                  \
+    av = float ## s ## _val(a);                                            \
+    bv = float ## s ## _val(b);                                            \
+    if (aSign != bSign) {                                                  \
+        if (ismin) {                                                       \
+            return aSign ? a : b;                                          \
+        } else {                                                           \
+            return aSign ? b : a;                                          \
+        }                                                                  \
+    } else {                                                               \
+        if (ismin) {                                                       \
+            return (aSign ^ (av < bv)) ? a : b;                            \
+        } else {                                                           \
+            return (aSign ^ (av < bv)) ? b : a;                            \
+        }                                                                  \
+    }                                                                      \
+}                                                                          \
+                                                                           \
+float ## s float ## s ## _minnum(float ## s a, float ## s b STATUS_PARAM)  \
+{                                                                          \
+    return float ## s ## _minmaxnum(a, b, 1 STATUS_VAR);                   \
+}                                                                          \
+                                                                           \
+float ## s float ## s ## _maxnum(float ## s a, float ## s b STATUS_PARAM)  \
+{                                                                          \
+    return float ## s ## _minmaxnum(a, b, 0 STATUS_VAR);                   \
+}
+
+MINMAXNUM(32)
+MINMAXNUM(64)
+
 
 /* Multiply A by 2 raised to the power N.  */
 float32 float32_scalbn( float32 a, int n STATUS_PARAM )
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
index f3927e2..2365274 100644
--- a/include/fpu/softfloat.h
+++ b/include/fpu/softfloat.h
@@ -302,6 +302,8 @@  int float32_compare( float32, float32 STATUS_PARAM );
 int float32_compare_quiet( float32, float32 STATUS_PARAM );
 float32 float32_min(float32, float32 STATUS_PARAM);
 float32 float32_max(float32, float32 STATUS_PARAM);
+float32 float32_minnum(float32, float32 STATUS_PARAM);
+float32 float32_maxnum(float32, float32 STATUS_PARAM);
 int float32_is_quiet_nan( float32 );
 int float32_is_signaling_nan( float32 );
 float32 float32_maybe_silence_nan( float32 );
@@ -408,6 +410,8 @@  int float64_compare( float64, float64 STATUS_PARAM );
 int float64_compare_quiet( float64, float64 STATUS_PARAM );
 float64 float64_min(float64, float64 STATUS_PARAM);
 float64 float64_max(float64, float64 STATUS_PARAM);
+float64 float64_minnum(float64, float64 STATUS_PARAM);
+float64 float64_maxnum(float64, float64 STATUS_PARAM);
 int float64_is_quiet_nan( float64 a );
 int float64_is_signaling_nan( float64 );
 float64 float64_maybe_silence_nan( float64 );