alpha: fix corner cases in ceil, floor, rint.
authorAurelien Jarno <aurelien@aurel32.net>
Tue, 4 May 2010 03:25:05 +0000 (23:25 -0400)
committerRichard Henderson <rth@twiddle.net>
Tue, 4 May 2010 16:01:40 +0000 (09:01 -0700)
Partial revert of bebc49030c15. Even with the revert, ceil and floor are
still faster than libcpml's equivalent.

Fixes bug 5350.

Signed-off-by: Matt Turner <mattst88@gmail.com>
ChangeLog.alpha
sysdeps/alpha/fpu/s_ceil.c
sysdeps/alpha/fpu/s_ceilf.c
sysdeps/alpha/fpu/s_floor.c
sysdeps/alpha/fpu/s_floorf.c
sysdeps/alpha/fpu/s_rint.c
sysdeps/alpha/fpu/s_rintf.c

index 80236fe..8b0a824 100644 (file)
@@ -1,3 +1,12 @@
+2010-05-03  Aurelien Jarno  <aurelien@aurel32.net>
+
+       * sysdeps/alpha/fpu/s_ceil.c: Fix corner cases.
+       * sysdeps/alpha/fpu/s_ceilf.c: Likewise.
+       * sysdeps/alpha/fpu/s_floor.c: Likewise.
+       * sysdeps/alpha/fpu/s_floorf.c: Likewise.
+       * sysdeps/alpha/fpu/s_rint.c: Likewise.
+       * sysdeps/alpha/fpu/s_rintf.c: Likewise.
+
 2010-05-03  GOTO Masanori  <gotom@debian.or.jp>
 
        * sysdeps/unix/sysv/linux/alpha/kernel-features.h: Define
index 40c2379..fe20902 100644 (file)
 double
 __ceil (double x)
 {
-  double two52 = copysign (0x1.0p52, x);
-  double r, tmp;
-  
-  __asm (
+  if (isless (fabs (x), 9007199254740992.0))   /* 1 << DBL_MANT_DIG */
+    {
+      double tmp1, new_x;
+
+      new_x = -x;
+      __asm (
 #ifdef _IEEE_FP_INEXACT
-        "addt/suim %2, %3, %1\n\tsubt/suim %1, %3, %0"
+            "cvttq/svim %2,%1\n\t"
 #else
-        "addt/sum %2, %3, %1\n\tsubt/sum %1, %3, %0"
+            "cvttq/svm %2,%1\n\t"
 #endif
-        : "=&f"(r), "=&f"(tmp)
-        : "f"(-x), "f"(-two52));
-
-  /* Fix up the negation we did above, as well as handling -0 properly. */
-  return copysign (r, x);
+            "cvtqt/m %1,%0\n\t"
+            : "=f"(new_x), "=&f"(tmp1)
+            : "f"(new_x));
+
+      /* Fix up the negation we did above, as well as handling -0 properly. */
+      x = copysign(new_x, x);
+    }
+  return x;
 }
 
 weak_alias (__ceil, ceil)
index 0df651f..c722e72 100644 (file)
 float
 __ceilf (float x)
 {
-  float two23 = copysignf (0x1.0p23, x);
-  float r, tmp;
-  
-  __asm (
+  if (isless (fabsf (x), 16777216.0f)) /* 1 << FLT_MANT_DIG */
+    {
+      /* Note that Alpha S_Floating is stored in registers in a
+        restricted T_Floating format, so we don't even need to
+        convert back to S_Floating in the end.  The initial
+        conversion to T_Floating is needed to handle denormals.  */
+
+      float tmp1, tmp2, new_x;
+
+      new_x = -x;
+      __asm ("cvtst/s %3,%2\n\t"
 #ifdef _IEEE_FP_INEXACT
-        "adds/suim %2, %3, %1\n\tsubs/suim %1, %3, %0"
+            "cvttq/svim %2,%1\n\t"
 #else
-        "adds/sum %2, %3, %1\n\tsubs/sum %1, %3, %0"
+            "cvttq/svm %2,%1\n\t"
 #endif
-        : "=&f"(r), "=&f"(tmp)
-        : "f"(-x), "f"(-two23));
-
-  /* Fix up the negation we did above, as well as handling -0 properly. */
-  return copysignf (r, x);
+            "cvtqt/m %1,%0\n\t"
+            : "=f"(new_x), "=&f"(tmp1), "=&f"(tmp2)
+            : "f"(new_x));
+
+      /* Fix up the negation we did above, as well as handling -0 properly. */
+      x = copysignf(new_x, x);
+    }
+  return x;
 }
 
 weak_alias (__ceilf, ceilf)
index 5af6386..6b16401 100644 (file)
 #include <math_ldbl_opt.h>
 
 
-/* Use the -inf rounding mode conversion instructions to implement floor.  */
+/* Use the -inf rounding mode conversion instructions to implement
+   floor.  We note when the exponent is large enough that the value
+   must be integral, as this avoids unpleasant integer overflows.  */
 
 double
 __floor (double x)
 {
-  double two52 = copysign (0x1.0p52, x);
-  double r, tmp;
-  
-  __asm (
+  if (isless (fabs (x), 9007199254740992.0))   /* 1 << DBL_MANT_DIG */
+    {
+      double tmp1, new_x;
+
+      __asm (
 #ifdef _IEEE_FP_INEXACT
-        "addt/suim %2, %3, %1\n\tsubt/suim %1, %3, %0"
+            "cvttq/svim %2,%1\n\t"
 #else
-        "addt/sum %2, %3, %1\n\tsubt/sum %1, %3, %0"
+            "cvttq/svm %2,%1\n\t"
 #endif
-        : "=&f"(r), "=&f"(tmp)
-        : "f"(x), "f"(two52));
-
-  /* floor(-0) == -0, and in general we'll always have the same
-     sign as our input.  */
-  return copysign (r, x);
+            "cvtqt/m %1,%0\n\t"
+            : "=f"(new_x), "=&f"(tmp1)
+            : "f"(x));
+
+      /* floor(-0) == -0, and in general we'll always have the same
+        sign as our input.  */
+      x = copysign(new_x, x);
+    }
+  return x;
 }
 
 weak_alias (__floor, floor)
index 8b42170..5da08ae 100644 (file)
 #include <math.h>
 
 
-/* Use the -inf rounding mode conversion instructions to implement floor.  */
+/* Use the -inf rounding mode conversion instructions to implement
+   floor.  We note when the exponent is large enough that the value
+   must be integral, as this avoids unpleasant integer overflows.  */
 
 float
 __floorf (float x)
 {
-  float two23 = copysignf (0x1.0p23, x);
-  float r, tmp;
-  
-  __asm (
+  if (isless (fabsf (x), 16777216.0f)) /* 1 << FLT_MANT_DIG */
+    {
+      /* Note that Alpha S_Floating is stored in registers in a
+        restricted T_Floating format, so we don't even need to
+        convert back to S_Floating in the end.  The initial
+        conversion to T_Floating is needed to handle denormals.  */
+
+      float tmp1, tmp2, new_x;
+
+      __asm ("cvtst/s %3,%2\n\t"
 #ifdef _IEEE_FP_INEXACT
-        "adds/suim %2, %3, %1\n\tsubs/suim %1, %3, %0"
+            "cvttq/svim %2,%1\n\t"
 #else
-        "adds/sum %2, %3, %1\n\tsubs/sum %1, %3, %0"
+            "cvttq/svm %2,%1\n\t"
 #endif
-        : "=&f"(r), "=&f"(tmp)
-        : "f"(x), "f"(two23));
-
-  /* floor(-0) == -0, and in general we'll always have the same
-     sign as our input.  */
-  return copysignf (r, x);
+            "cvtqt/m %1,%0\n\t"
+            : "=f"(new_x), "=&f"(tmp1), "=&f"(tmp2)
+            : "f"(x));
+
+      /* floor(-0) == -0, and in general we'll always have the same
+        sign as our input.  */
+      x = copysignf(new_x, x);
+    }
+  return x;
 }
 
 weak_alias (__floorf, floorf)
index e9aa028..9624631 100644 (file)
 double
 __rint (double x)
 {
-  double two52 = copysign (0x1.0p52, x);
-  double r;
-  
-  r = x + two52;
-  r = r - two52;
-
-  /* rint(-0.1) == -0, and in general we'll always have the same sign
-     as our input.  */
-  return copysign (r, x);
+  if (isless (fabs (x), 9007199254740992.0))   /* 1 << DBL_MANT_DIG */
+    {
+      double tmp1, new_x;
+      __asm (
+#ifdef _IEEE_FP_INEXACT
+            "cvttq/svid %2,%1\n\t"
+#else
+            "cvttq/svd %2,%1\n\t"
+#endif
+            "cvtqt/d %1,%0\n\t"
+            : "=f"(new_x), "=&f"(tmp1)
+            : "f"(x));
+
+      /* rint(-0.1) == -0, and in general we'll always have the same
+        sign as our input.  */
+      x = copysign(new_x, x);
+    }
+  return x;
 }
 
 weak_alias (__rint, rint)
index 9e4cbd1..39fb72f 100644 (file)
 float
 __rintf (float x)
 {
-  float two23 = copysignf (0x1.0p23, x);
-  float r;
-
-  r = x + two23;
-  r = r - two23;
-
-  /* rint(-0.1) == -0, and in general we'll always have the same sign
-     as our input.  */
-  return copysign (r, x);
+  if (isless (fabsf (x), 16777216.0f)) /* 1 << FLT_MANT_DIG */
+    {
+      /* Note that Alpha S_Floating is stored in registers in a
+        restricted T_Floating format, so we don't even need to
+        convert back to S_Floating in the end.  The initial
+        conversion to T_Floating is needed to handle denormals.  */
+
+      float tmp1, tmp2, new_x;
+
+      __asm ("cvtst/s %3,%2\n\t"
+#ifdef _IEEE_FP_INEXACT
+            "cvttq/svid %2,%1\n\t"
+#else
+            "cvttq/svd %2,%1\n\t"
+#endif
+            "cvtqt/d %1,%0\n\t"
+            : "=f"(new_x), "=&f"(tmp1), "=&f"(tmp2)
+            : "f"(x));
+
+      /* rint(-0.1) == -0, and in general we'll always have the same
+        sign as our input.  */
+      x = copysignf(new_x, x);
+    }
+  return x;
 }
 
 weak_alias (__rintf, rintf)