diff --git a/ChangeLog.alpha b/ChangeLog.alpha index 80236fe3e2..8b0a82428b 100644 --- a/ChangeLog.alpha +++ b/ChangeLog.alpha @@ -1,3 +1,12 @@ +2010-05-03 Aurelien Jarno + + * 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 * sysdeps/unix/sysv/linux/alpha/kernel-features.h: Define diff --git a/sysdeps/alpha/fpu/s_ceil.c b/sysdeps/alpha/fpu/s_ceil.c index 40c2379286..fe20902450 100644 --- a/sysdeps/alpha/fpu/s_ceil.c +++ b/sysdeps/alpha/fpu/s_ceil.c @@ -27,20 +27,25 @@ double __ceil (double x) { - double two52 = copysign (0x1.0p52, x); - double r, tmp; - - __asm ( -#ifdef _IEEE_FP_INEXACT - "addt/suim %2, %3, %1\n\tsubt/suim %1, %3, %0" -#else - "addt/sum %2, %3, %1\n\tsubt/sum %1, %3, %0" -#endif - : "=&f"(r), "=&f"(tmp) - : "f"(-x), "f"(-two52)); + if (isless (fabs (x), 9007199254740992.0)) /* 1 << DBL_MANT_DIG */ + { + double tmp1, new_x; - /* Fix up the negation we did above, as well as handling -0 properly. */ - return copysign (r, x); + new_x = -x; + __asm ( +#ifdef _IEEE_FP_INEXACT + "cvttq/svim %2,%1\n\t" +#else + "cvttq/svm %2,%1\n\t" +#endif + "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) diff --git a/sysdeps/alpha/fpu/s_ceilf.c b/sysdeps/alpha/fpu/s_ceilf.c index 0df651f405..c722e7294e 100644 --- a/sysdeps/alpha/fpu/s_ceilf.c +++ b/sysdeps/alpha/fpu/s_ceilf.c @@ -26,20 +26,30 @@ float __ceilf (float x) { - float two23 = copysignf (0x1.0p23, x); - float r, tmp; - - __asm ( -#ifdef _IEEE_FP_INEXACT - "adds/suim %2, %3, %1\n\tsubs/suim %1, %3, %0" -#else - "adds/sum %2, %3, %1\n\tsubs/sum %1, %3, %0" -#endif - : "=&f"(r), "=&f"(tmp) - : "f"(-x), "f"(-two23)); + 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. */ - /* Fix up the negation we did above, as well as handling -0 properly. */ - return copysignf (r, x); + float tmp1, tmp2, new_x; + + new_x = -x; + __asm ("cvtst/s %3,%2\n\t" +#ifdef _IEEE_FP_INEXACT + "cvttq/svim %2,%1\n\t" +#else + "cvttq/svm %2,%1\n\t" +#endif + "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) diff --git a/sysdeps/alpha/fpu/s_floor.c b/sysdeps/alpha/fpu/s_floor.c index 5af6386155..6b16401e43 100644 --- a/sysdeps/alpha/fpu/s_floor.c +++ b/sysdeps/alpha/fpu/s_floor.c @@ -21,26 +21,32 @@ #include -/* 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 ( -#ifdef _IEEE_FP_INEXACT - "addt/suim %2, %3, %1\n\tsubt/suim %1, %3, %0" -#else - "addt/sum %2, %3, %1\n\tsubt/sum %1, %3, %0" -#endif - : "=&f"(r), "=&f"(tmp) - : "f"(x), "f"(two52)); + if (isless (fabs (x), 9007199254740992.0)) /* 1 << DBL_MANT_DIG */ + { + double tmp1, new_x; - /* floor(-0) == -0, and in general we'll always have the same - sign as our input. */ - return copysign (r, x); + __asm ( +#ifdef _IEEE_FP_INEXACT + "cvttq/svim %2,%1\n\t" +#else + "cvttq/svm %2,%1\n\t" +#endif + "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) diff --git a/sysdeps/alpha/fpu/s_floorf.c b/sysdeps/alpha/fpu/s_floorf.c index 8b421705cd..5da08ae107 100644 --- a/sysdeps/alpha/fpu/s_floorf.c +++ b/sysdeps/alpha/fpu/s_floorf.c @@ -20,26 +20,37 @@ #include -/* 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 ( -#ifdef _IEEE_FP_INEXACT - "adds/suim %2, %3, %1\n\tsubs/suim %1, %3, %0" -#else - "adds/sum %2, %3, %1\n\tsubs/sum %1, %3, %0" -#endif - : "=&f"(r), "=&f"(tmp) - : "f"(x), "f"(two23)); + 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. */ - /* floor(-0) == -0, and in general we'll always have the same - sign as our input. */ - return copysignf (r, x); + float tmp1, tmp2, new_x; + + __asm ("cvtst/s %3,%2\n\t" +#ifdef _IEEE_FP_INEXACT + "cvttq/svim %2,%1\n\t" +#else + "cvttq/svm %2,%1\n\t" +#endif + "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) diff --git a/sysdeps/alpha/fpu/s_rint.c b/sysdeps/alpha/fpu/s_rint.c index e9aa028822..9624631292 100644 --- a/sysdeps/alpha/fpu/s_rint.c +++ b/sysdeps/alpha/fpu/s_rint.c @@ -24,15 +24,24 @@ double __rint (double x) { - double two52 = copysign (0x1.0p52, x); - double r; - - r = x + two52; - r = r - two52; + 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. */ - return copysign (r, 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) diff --git a/sysdeps/alpha/fpu/s_rintf.c b/sysdeps/alpha/fpu/s_rintf.c index 9e4cbd1ffd..39fb72fb64 100644 --- a/sysdeps/alpha/fpu/s_rintf.c +++ b/sysdeps/alpha/fpu/s_rintf.c @@ -23,15 +23,30 @@ float __rintf (float x) { - float two23 = copysignf (0x1.0p23, x); - float r; + 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. */ - r = x + two23; - r = r - two23; + float tmp1, tmp2, new_x; - /* rint(-0.1) == -0, and in general we'll always have the same sign - as our input. */ - return copysign (r, 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)