]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
soft-fp: Refine FP_EX_DENORM handling for comparisons.
authorJoseph Myers <joseph@codesourcery.com>
Fri, 6 Feb 2015 15:41:49 +0000 (15:41 +0000)
committerJoseph Myers <joseph@codesourcery.com>
Fri, 6 Feb 2015 15:41:49 +0000 (15:41 +0000)
In <https://sourceware.org/ml/libc-alpha/2014-09/msg00488.html>, I
noted that comparisons in soft-fp did not set FP_EX_DENORM unless
denormal operands were flushed to zero.

This patch fixes soft-fp to check for denormal operands for
comparisons and set that exception whenever FP_EX_DENORM is not zero.
In particular, for the one architecture for which the Linux kernel
defines FP_EX_DENORM (alpha), this corresponds to the existing logic
for comparisons and so allows that logic to be replaced by a simple
call to FP_CMP_D when soft-fp is updated in the kernel.

Tested for powerpc (e500) that installed stripped shared libraries are
unchanged by this patch.

* soft-fp/op-common.h (_FP_CMP_CHECK_DENORM): New macro.
(_FP_CMP_CHECK_FLUSH_ZERO): Likewise.
(_FP_CMP): Use_FP_CMP_CHECK_DENORM and _FP_CMP_CHECK_FLUSH_ZERO.
(_FP_CMP_EQ): Likewise.
(_FP_CMP_UNORD): Use _FP_CMP_CHECK_DENORM.

ChangeLog
soft-fp/op-common.h

index 0ef8a61b6566496e7c9b8ccbd62bb0b782e14aa2..32b766728e4a50765d09988424f903d60901fcb6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2015-02-06  Joseph Myers  <joseph@codesourcery.com>
 
+       * soft-fp/op-common.h (_FP_CMP_CHECK_DENORM): New macro.
+       (_FP_CMP_CHECK_FLUSH_ZERO): Likewise.
+       (_FP_CMP): Use_FP_CMP_CHECK_DENORM and _FP_CMP_CHECK_FLUSH_ZERO.
+       (_FP_CMP_EQ): Likewise.
+       (_FP_CMP_UNORD): Use _FP_CMP_CHECK_DENORM.
+
        * soft-fp/op-common.h (FP_EXTEND): Rename to _FP_EXTEND_CNAN with
        extra argument CHECK_NAN.  Redefine as wrapper around
        _FP_EXTEND_CNAN.
index 98cc72135524f16e8bad66a4be59daf71f8cea73..389ba3fcfa85e232d30a4f8946a96acd49b34b4f 100644 (file)
     }                                                                  \
   while (0)
 
+/* Helper for comparisons.  If denormal operands would raise an
+   exception, check for them, and flush to zero as appropriate
+   (otherwise, we need only check and flush to zero if it might affect
+   the result, which is done later with _FP_CMP_CHECK_FLUSH_ZERO).  */
+#define _FP_CMP_CHECK_DENORM(fs, wc, X, Y)                             \
+  do                                                                   \
+    {                                                                  \
+      if (FP_EX_DENORM != 0)                                           \
+       {                                                               \
+         /* We must ensure the correct exceptions are raised for       \
+            denormal operands, even though this may not affect the     \
+            result of the comparison.  */                              \
+         if (FP_DENORM_ZERO)                                           \
+           {                                                           \
+             _FP_CHECK_FLUSH_ZERO (fs, wc, X);                         \
+             _FP_CHECK_FLUSH_ZERO (fs, wc, Y);                         \
+           }                                                           \
+         else                                                          \
+           {                                                           \
+             if ((X##_e == 0 && !_FP_FRAC_ZEROP_##wc (X))              \
+                 || (Y##_e == 0 && !_FP_FRAC_ZEROP_##wc (Y)))          \
+               FP_SET_EXCEPTION (FP_EX_DENORM);                        \
+           }                                                           \
+       }                                                               \
+    }                                                                  \
+  while (0)
+
+/* Helper for comparisons.  Check for flushing denormals for zero if
+   we didn't need to check earlier for any denormal operands.  */
+#define _FP_CMP_CHECK_FLUSH_ZERO(fs, wc, X, Y) \
+  do                                           \
+    {                                          \
+      if (FP_EX_DENORM == 0)                   \
+       {                                       \
+         _FP_CHECK_FLUSH_ZERO (fs, wc, X);     \
+         _FP_CHECK_FLUSH_ZERO (fs, wc, Y);     \
+       }                                       \
+    }                                          \
+  while (0)
+
 /* Main differential comparison routine.  The inputs should be raw not
    cooked.  The return is -1, 0, 1 for normal values, UN
    otherwise.  */
 #define _FP_CMP(fs, wc, ret, X, Y, un, ex)                             \
   do                                                                   \
     {                                                                  \
+      _FP_CMP_CHECK_DENORM (fs, wc, X, Y);                             \
       /* NANs are unordered.  */                                       \
       if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc (X))       \
          || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc (Y)))    \
          int _FP_CMP_is_zero_x;                                        \
          int _FP_CMP_is_zero_y;                                        \
                                                                        \
-         _FP_CHECK_FLUSH_ZERO (fs, wc, X);                             \
-         _FP_CHECK_FLUSH_ZERO (fs, wc, Y);                             \
+         _FP_CMP_CHECK_FLUSH_ZERO (fs, wc, X, Y);                      \
                                                                        \
          _FP_CMP_is_zero_x                                             \
            = (!X##_e && _FP_FRAC_ZEROP_##wc (X)) ? 1 : 0;              \
 #define _FP_CMP_EQ(fs, wc, ret, X, Y, ex)                              \
   do                                                                   \
     {                                                                  \
+      _FP_CMP_CHECK_DENORM (fs, wc, X, Y);                             \
       /* NANs are unordered.  */                                       \
       if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc (X))       \
          || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc (Y)))    \
        }                                                               \
       else                                                             \
        {                                                               \
-         _FP_CHECK_FLUSH_ZERO (fs, wc, X);                             \
-         _FP_CHECK_FLUSH_ZERO (fs, wc, Y);                             \
+         _FP_CMP_CHECK_FLUSH_ZERO (fs, wc, X, Y);                      \
                                                                        \
          (ret) = !(X##_e == Y##_e                                      \
                    && _FP_FRAC_EQ_##wc (X, Y)                          \
 #define _FP_CMP_UNORD(fs, wc, ret, X, Y, ex)                           \
   do                                                                   \
     {                                                                  \
+      _FP_CMP_CHECK_DENORM (fs, wc, X, Y);                             \
       (ret) = ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc (X))  \
               || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc (Y))); \
       if (ret)                                                         \