Index: sysdeps/x86_64/fpu/libm_inlines_amd.h =================================================================== --- sysdeps/x86_64/fpu/libm_inlines_amd.h.orig +++ sysdeps/x86_64/fpu/libm_inlines_amd.h @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. +(C) 2002, 2009 Advanced Micro Devices, Inc. ** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH + LICENSE FOUND IN THE "LICENSE" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ @@ -254,6 +254,33 @@ static inline void clear_fpsw_flags(int #if defined(USE_RAISE_FPSW_FLAGS) +static inline void raise_fp_exc(int flags) +{ + if((flags & AMD_F_UNDERFLOW) == AMD_F_UNDERFLOW) + { + double a = 0x1.0p-1022; + __asm __volatile ("mulsd %1, %0" : "+x" (a)); + } + + if((flags & AMD_F_OVERFLOW) == AMD_F_OVERFLOW) + { + double a = 0x1.fffffffffffffp1023; + __asm __volatile ("mulsd %1, %0" : "+x" (a)); + } + + if((flags & AMD_F_DIVBYZERO) == AMD_F_DIVBYZERO) + { + double a = 1.0, b = 0.0; + __asm __volatile ("divsd %1, %0" : "+x" (a) : "x" (b)); + } + + if((flags & AMD_F_INVALID) == AMD_F_INVALID) + { + double a = 0.0; + __asm __volatile ("divsd %1, %0" : "+x" (a)); + } +} + /* Raises floating-point status flags. The argument should be the bitwise or of the flags to be raised, from the list above, e.g. @@ -269,11 +296,7 @@ static inline void raise_fpsw_flags(int /* Put the floating-point environment back */ __asm fldenv fenv; #elif defined(linux) - unsigned int cw; - /* Get the current floating-point control/status word */ - asm volatile ("STMXCSR %0" : "=m" (cw)); - cw |= flags; - asm volatile ("LDMXCSR %0" : : "m" (cw)); + raise_fp_exc(flags); #else #error Unknown machine #endif Index: sysdeps/x86_64/fpu/s_atan2.c =================================================================== --- sysdeps/x86_64/fpu/s_atan2.c.orig +++ sysdeps/x86_64/fpu/s_atan2.c @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. +(C) 2002, 2009 Advanced Micro Devices, Inc. ** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH + LICENSE FOUND IN THE "LICENSE" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ @@ -595,6 +595,14 @@ double __atan2(double y, double x) if (yneg) return val_with_flags(-piby2,AMD_F_INEXACT); else val_with_flags(piby2,AMD_F_INEXACT); } + else if((!xneg) && xinf && (!yinf) && (!yzero)) + { + if(yneg) + return -0.0; + else + return 0.0; + } + /* Scale up both x and y if they are both below 1/4. This avoids any possible later denormalised arithmetic. */ Index: sysdeps/x86_64/fpu/s_atan2f.c =================================================================== --- sysdeps/x86_64/fpu/s_atan2f.c.orig +++ sysdeps/x86_64/fpu/s_atan2f.c @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. +(C) 2002, 2009 Advanced Micro Devices, Inc. ** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH + LICENSE FOUND IN THE "LICENSE" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ @@ -349,6 +349,14 @@ float __atan2f(float fy, float fx) if (yneg) return val_with_flags(-piby2,AMD_F_INEXACT); else val_with_flags(piby2,AMD_F_INEXACT); } + else if((!xneg) && xinf && (!yinf) && (!yzero)) + { + if(yneg) + return -0.0; + else + return 0.0; + } + if (diffexp > 26) { /* abs(y)/abs(x) > 2^26 => arctan(x/y) Index: sysdeps/x86_64/fpu/s_atan.c =================================================================== --- sysdeps/x86_64/fpu/s_atan.c.orig +++ sysdeps/x86_64/fpu/s_atan.c @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. +(C) 2002, 2009 Advanced Micro Devices, Inc. ** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH + LICENSE FOUND IN THE "LICENSE" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ @@ -67,7 +67,7 @@ double __atan (double x) if (aux == 0) /* if x=0, then result is precise */ return x; else - return val_with_flags(x, AMD_F_INEXACT); + return val_with_flags(x, AMD_F_INEXACT | AMD_F_UNDERFLOW); } /* Argument reduction to range [-7/16,7/16] */ Index: sysdeps/x86_64/fpu/s_atanf.c =================================================================== --- sysdeps/x86_64/fpu/s_atanf.c.orig +++ sysdeps/x86_64/fpu/s_atanf.c @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. +(C) 2002, 2009 Advanced Micro Devices, Inc. ** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH + LICENSE FOUND IN THE "LICENSE" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ @@ -68,7 +68,7 @@ float __atanf (float fx) if (aux == 0) /* if x=0, then result is precise */ return fx; else - return valf_with_flags(fx, AMD_F_INEXACT); + return valf_with_flags(fx, AMD_F_INEXACT | AMD_F_UNDERFLOW); } v = x; Index: sysdeps/x86_64/fpu/s_sincos.c =================================================================== --- sysdeps/x86_64/fpu/s_sincos.c.orig +++ sysdeps/x86_64/fpu/s_sincos.c @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. -** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS - AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH +(C) 2002, 2009 Advanced Micro Devices, Inc. +** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS + AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC + LICENSE FOUND IN THE "LICENSE" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ @@ -97,7 +97,7 @@ void __sincos(double x, double *s, doubl } else { - *s = x; + *s = val_with_flags(x, AMD_F_INEXACT); *c = val_with_flags(1.0, AMD_F_INEXACT); } } Index: sysdeps/x86_64/fpu/s_sincosf.c =================================================================== --- sysdeps/x86_64/fpu/s_sincosf.c.orig +++ sysdeps/x86_64/fpu/s_sincosf.c @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. -** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS - AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH +(C) 2002 Advanced Micro Devices, Inc. +** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS + AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC + LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ Index: sysdeps/x86_64/fpu/s_tanf.c =================================================================== --- sysdeps/x86_64/fpu/s_tanf.c.orig +++ sysdeps/x86_64/fpu/s_tanf.c @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. -** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS - AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH +(C) 2002 Advanced Micro Devices, Inc. +** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS + AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC + LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ @@ -18,7 +18,7 @@ #undef USE_NAN_WITH_FLAGS #undef USE_REMAINDER_PIBY2F_INLINE -/* tan(x) approximation valid on the interval [-pi/4,pi/4]. +/* tan(x) approximation valid on the interval [-pi/4,pi/4]. If recip is true return -1/tan(x) instead. */ static inline double tanf_piby4(double x, int recip) { Index: sysdeps/x86_64/fpu/w_asin.c =================================================================== --- sysdeps/x86_64/fpu/w_asin.c.orig +++ sysdeps/x86_64/fpu/w_asin.c @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. +(C) 2002, 2009 Advanced Micro Devices, Inc. ** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH + LICENSE FOUND IN THE "LICENSE" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ @@ -76,7 +76,8 @@ double __asin(double x) if (xexp < -28) { /* y small enough that arcsin(x) = x */ - return val_with_flags(x, AMD_F_INEXACT); + if(aux == 0) return x; + return val_with_flags(x, AMD_F_INEXACT | AMD_F_UNDERFLOW); } else if (xnan) return x + x; else if (xexp >= 0) Index: sysdeps/x86_64/fpu/w_asinf.c =================================================================== --- sysdeps/x86_64/fpu/w_asinf.c.orig +++ sysdeps/x86_64/fpu/w_asinf.c @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. +(C) 2002, 2009 Advanced Micro Devices, Inc. ** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH + LICENSE FOUND IN THE "LICENSE" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ @@ -75,8 +75,11 @@ float __asinf(float x) /* Special cases */ if (xexp < -14) + { /* y small enough that arcsin(x) = x */ - return valf_with_flags(x, AMD_F_INEXACT); + if(aux == 0 ) return x; + return valf_with_flags(x, AMD_F_INEXACT | AMD_F_UNDERFLOW); + } else if (xnan) return x + x; else if (xexp >= 0) { Index: sysdeps/x86_64/fpu/w_hypotf.c =================================================================== --- sysdeps/x86_64/fpu/w_hypotf.c.orig +++ sysdeps/x86_64/fpu/w_hypotf.c @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. +(C) 2002, 2009 Advanced Micro Devices, Inc. ** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH + LICENSE FOUND IN THE "LICENSE" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ @@ -79,6 +79,20 @@ float __hypotf(float x, float y) return retval; } + /* Set x = abs(x) and y = abs(y) */ + if (ux == 0) + { + /* x is zero */ + PUT_BITS_DP64(avy, dy); + return dy; + } + if (uy == 0) + { + /* y is zero */ + PUT_BITS_DP64(avx, dx); + return dx; + } + dr = (dx*dx + dy*dy); #if USE_SOFTWARE_SQRT Index: sysdeps/x86_64/fpu/w_pow.c =================================================================== --- sysdeps/x86_64/fpu/w_pow.c.orig +++ sysdeps/x86_64/fpu/w_pow.c @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. +(C) 2002, 2009 Advanced Micro Devices, Inc. ** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH + LICENSE FOUND IN THE "LICENSE" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ @@ -364,8 +364,20 @@ double __pow(double x, double y) { /* y is -ve */ if (ax == 0) - /* abs(x) = 0.0. Return +infinity. */ - return retval_errno_edom(argx, argy, 1); + { + if(yinf) + { + /* Return +infinity with no flags */ + double sz; + PUT_BITS_DP64(PINFBITPATT_DP64, sz); + return sz; + } + else + { + /* abs(x) = 0.0. Return +infinity. */ + return retval_errno_edom(argx, argy, 1); + } + } else if (ax < 0x3ff0000000000000) { /* abs(x) < 1.0; return +infinity. */ Index: sysdeps/x86_64/fpu/w_powf.c =================================================================== --- sysdeps/x86_64/fpu/w_powf.c.orig +++ sysdeps/x86_64/fpu/w_powf.c @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. +(C) 2002, 2009 Advanced Micro Devices, Inc. ** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH + LICENSE FOUND IN THE "LICENSE" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ @@ -175,8 +175,20 @@ float __powf(float x, float y) { /* y is -ve */ if (ax == 0) - /* abs(x) = 0.0. Return +infinity. */ - return retval_errno_edom(x, y, 1); + { + if(yinf) + { + /* Return +infinity with no flags */ + float sz; + PUT_BITS_SP32(PINFBITPATT_SP32, sz); + return sz; + } + else + { + /* abs(x) = 0.0. Return +infinity. */ + return retval_errno_edom(x, y, 1); + } + } else if (ax < 0x3f800000) { /* abs(x) < 1.0; return +infinity. */ Index: sysdeps/x86_64/fpu/w_remainder.c =================================================================== --- sysdeps/x86_64/fpu/w_remainder.c.orig +++ sysdeps/x86_64/fpu/w_remainder.c @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. +(C) 2002, 2009 Advanced Micro Devices, Inc. ** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH + LICENSE FOUND IN THE "LICENSE" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ @@ -69,11 +69,31 @@ double __remainder(double x, double y) { /* x is NaN or infinity */ if (ux & MANTBITS_DP64) - /* x is NaN */ - return dx + dx; /* Raise invalid if it is a signalling NaN */ + { + if( (yexp > BIASEDEMAX_DP64) && (uy & MANTBITS_DP64) ) + { + /* y is also NaN */ + return dx + dy; + } + else + { + /* x is NaN */ + return dx + dx; /* Raise invalid if it is a signalling NaN */ + } + } else - /* x is infinity; result is NaN */ - return nan_with_flags(AMD_F_INVALID); + { + if((yexp > BIASEDEMAX_DP64) && (uy & MANTBITS_DP64)) + { + /* y is NaN */ + return dy+dy; + } + else + { + /* x is infinity; result is NaN */ + return nan_with_flags(AMD_F_INVALID); + } + } } else if (yexp > BIASEDEMAX_DP64) { Index: sysdeps/x86_64/fpu/w_remainderf.c =================================================================== --- sysdeps/x86_64/fpu/w_remainderf.c.orig +++ sysdeps/x86_64/fpu/w_remainderf.c @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. +(C) 2002, 2009 Advanced Micro Devices, Inc. ** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH + LICENSE FOUND IN THE "LICENSE" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ @@ -50,11 +50,31 @@ float __remainderf(float x, float y) { /* x is NaN or infinity */ if (ux & MANTBITS_DP64) - /* x is NaN */ - return dx + dx; /* Raise invalid if it is a signalling NaN */ + { + if((yexp > BIASEDEMAX_DP64) && (uy & MANTBITS_DP64)) + { + /* y is also NaN */ + return dx + dy; + } + else + { + /* x is NaN */ + return dx + dx; /* Raise invalid if it is a signalling NaN */ + } + } else - /* x is infinity; result is NaN */ - return nan_with_flags(AMD_F_INVALID); + { + if((yexp > BIASEDEMAX_DP64) && (uy & MANTBITS_DP64)) + { + /* y is NaN */ + return dy+dy; + } + else + { + /* x is infinity; result is NaN */ + return nan_with_flags(AMD_F_INVALID); + } + } } else if (yexp > BIASEDEMAX_DP64) { Index: sysdeps/x86_64/fpu/w_sinh.c =================================================================== --- sysdeps/x86_64/fpu/w_sinh.c.orig +++ sysdeps/x86_64/fpu/w_sinh.c @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. +(C) 2002, 2009 Advanced Micro Devices, Inc. ** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH + LICENSE FOUND IN THE "LICENSE" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ @@ -249,7 +249,7 @@ double __sinh(double x) /* with no inexact */ return x; else - return val_with_flags(x, AMD_F_INEXACT); + return val_with_flags(x, AMD_F_INEXACT | AMD_F_UNDERFLOW); } else if (aux >= 0x7ff0000000000000) /* |x| is NaN or Inf */ return x + x; Index: sysdeps/x86_64/fpu/w_sinhf.c =================================================================== --- sysdeps/x86_64/fpu/w_sinhf.c.orig +++ sysdeps/x86_64/fpu/w_sinhf.c @@ -1,8 +1,8 @@ /* -(C) 2002 Advanced Micro Devices, Inc. +(C) 2002, 2009 Advanced Micro Devices, Inc. ** YOUR USE OF THIS LIBRARY IS SUBJECT TO THE TERMS AND CONDITIONS OF THE GNU LESSER GENERAL PUBLIC - LICENSE FOUND IN THE "README" FILE THAT IS INCLUDED WITH + LICENSE FOUND IN THE "LICENSE" FILE THAT IS INCLUDED WITH THIS LIBRARY** */ @@ -13,11 +13,13 @@ #define USE_SCALEDOUBLE_1 #define USE_SCALEDOUBLE_2 #define USE_INFINITY_WITH_FLAGS +#define USE_VAL_WITH_FLAGS #include "libm_inlines_amd.h" #undef USE_SPLITEXP #undef USE_SCALEDOUBLE_1 #undef USE_SCALEDOUBLE_2 #undef USE_INFINITY_WITH_FLAGS +#undef USE_VAL_WITH_FLAGS /* Deal with errno for out-of-range result */ #include "libm_errno_amd.h" @@ -166,7 +168,8 @@ float __sinhf(float fx) if (aux < 0x3f10000000000000) /* |x| small enough that sinh(x) = x */ { if (aux == 0) return x; /* with no inexact */ - if (LAMBDA_DP64 + x > 1.0) return x; /* with inexact */ + else + return val_with_flags(x, AMD_F_INEXACT | AMD_F_UNDERFLOW); /* with inexact */ } else if (aux >= 0x7ff0000000000000) /* |x| is NaN or Inf */ return x + x;