]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Simplify generic fdim implementations.
authorJoseph Myers <joseph@codesourcery.com>
Tue, 14 Jun 2016 14:56:42 +0000 (14:56 +0000)
committerJoseph Myers <joseph@codesourcery.com>
Tue, 14 Jun 2016 14:56:42 +0000 (14:56 +0000)
The generic fdim implementations have unnecessarily complicated code,
using fpclassify to determine whether the arguments are NaNs,
subtracting NaNs if so and otherwise subtracting the non-NaN arguments
if not (x <= y), then using fpclassify on the result to see if it is
infinite.

This patch simplifies the code.  Instead of handling NaNs separately,
it suffices to use an unordered comparison with islessequal (x, y) to
determine whether to return zero, and otherwise NaNs can go through
the same subtraction as non-NaN arguments; no explicit tests for NaN
are needed at all.  Then, isinf instead of fpclassify can be used to
determine whether to set errno (in the normal non-overflow case, only
one classification will need to occur, unlike the three in the
previous code, of which two occurred even if returning zero, because
the result will not be infinite in the normal case).

The resulting logic is essentially the same as that in the powerpc
version, except that the powerpc version is missing errno setting and
uses <= not islessequal, so relying on
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58684>, the GCC bug that
unordered comparison instructions are wrongly used on powerpc for
ordered comparisons.

The compiled code for fdim and fdimf on x86_64 is less than half the
size of the previous code.

Tested for x86_64.

* math/s_fdim.c (__fdim): Use islessequal and isinf instead of
fpclassify.
* math/s_fdimf.c (__fdimf): Likewise.
* math/s_fdiml.c (__fdiml): Likewise.

ChangeLog
math/s_fdim.c
math/s_fdimf.c
math/s_fdiml.c

index 495f0881964fc3a6d1904731e86305805f170720..abd8fcbba4c985c5d23bc688f1aa749f80205a51 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2016-06-14  Joseph Myers  <joseph@codesourcery.com>
+
+       * math/s_fdim.c (__fdim): Use islessequal and isinf instead of
+       fpclassify.
+       * math/s_fdimf.c (__fdimf): Likewise.
+       * math/s_fdiml.c (__fdiml): Likewise.
+
 2016-06-14  Rajalakshmi Srinivasaraghavan  <raji@linux.vnet.ibm.com>
 
        * sysdeps/powerpc/powerpc64/multiarch/Makefile:
index b02ed27233f17b95b023cf4a067e745303dcd24c..8789ca4c3812cff0e819f84b991dc5bbceea1351 100644 (file)
 double
 __fdim (double x, double y)
 {
-  int clsx = fpclassify (x);
-  int clsy = fpclassify (y);
-
-  if (clsx == FP_NAN || clsy == FP_NAN)
-    /* Raise invalid flag for signaling but not quiet NaN.  */
-    return x - y;
-
-  if (x <= y)
+  if (islessequal (x, y))
     return 0.0;
 
   double r = x - y;
-  if (fpclassify (r) == FP_INFINITE
-      && clsx != FP_INFINITE && clsy != FP_INFINITE)
+  if (isinf (r) && !isinf (x) && !isinf (y))
     __set_errno (ERANGE);
 
   return r;
index b905380478a82dda5f6685b9d42c35305ce1c14c..2e8eccfc4f24c7a0c49259b358ebf97941ccc9eb 100644 (file)
 float
 __fdimf (float x, float y)
 {
-  int clsx = fpclassify (x);
-  int clsy = fpclassify (y);
-
-  if (clsx == FP_NAN || clsy == FP_NAN)
-    /* Raise invalid flag for signaling but not quiet NaN.  */
-    return x - y;
-
-  if (x <= y)
+  if (islessequal (x, y))
     return 0.0f;
 
   float r = x - y;
-  if (fpclassify (r) == FP_INFINITE
-      && clsx != FP_INFINITE && clsy != FP_INFINITE)
+  if (isinf (r) && !isinf (x) && !isinf (y))
     __set_errno (ERANGE);
 
   return r;
index df3f1e5ba42e987835a2864de4018fb35cd6c428..4a1f6722c61482f7bbaadfaac5e0f122ad0d549a 100644 (file)
 long double
 __fdiml (long double x, long double y)
 {
-  int clsx = fpclassify (x);
-  int clsy = fpclassify (y);
-
-  if (clsx == FP_NAN || clsy == FP_NAN)
-    /* Raise invalid flag for signaling but not quiet NaN.  */
-    return x - y;
-
-  if (x <= y)
+  if (islessequal (x, y))
     return 0.0f;
 
   long double r = x - y;
-  if (fpclassify (r) == FP_INFINITE
-      && clsx != FP_INFINITE && clsy != FP_INFINITE)
+  if (isinf (r) && !isinf (x) && !isinf (y))
     __set_errno (ERANGE);
 
   return r;