diff options
author | Roland McGrath <roland@gnu.org> | 2006-03-16 11:47:24 +0000 |
---|---|---|
committer | Roland McGrath <roland@gnu.org> | 2006-03-16 11:47:24 +0000 |
commit | 5c68d401698a58cf7da150d9cce769fa6679ba5f (patch) | |
tree | 0f77818c4e9204e385b3cb1777e9171b75a7949e /sysdeps/powerpc | |
parent | 671ca699ddfee826a74a32590d369672b8039321 (diff) | |
download | glibc-5c68d401698a58cf7da150d9cce769fa6679ba5f.tar.gz glibc-5c68d401698a58cf7da150d9cce769fa6679ba5f.tar.xz glibc-5c68d401698a58cf7da150d9cce769fa6679ba5f.zip |
[BZ #2423]
2006-03-07 Jakub Jelinek <jakub@redhat.com> [BZ #2423] * math/libm-test.inc [TEST_LDOUBLE] (ceil_test, floor_test, rint_test, round_test, trunc_test): Only run some of the new tests if LDBL_MANT_DIG > 100. 2006-03-03 Steven Munroe <sjmunroe@us.ibm.com> Alan Modra <amodra@bigpond.net.au> * sysdeps/powerpc/fpu/fenv_libc.h (__fegetround, __fesetround): Define inline implementations. * sysdeps/powerpc/fpu/fegetround.c: Use __fegetround. * sysdeps/powerpc/fpu/fesetround.c: Use __fesetround. * sysdeps/powerpc/fpu/math_ldbl.h: New file. [BZ #2423] * math/libm-test.inc [TEST_LDOUBLE] (ceil_test, floor_test, rint_test, round_test, trunc_test): Add new tests. * sysdeps/ieee754/ldbl-128ibm/math_ldbl.h (EXTRACT_IBM_EXTENDED_MANTISSA, INSERT_IBM_EXTENDED_MANTISSA): Removed, replaced with ... (ldbl_extract_mantissa, ldbl_insert_mantissa, ldbl_pack, ldbl_unpack, ldbl_canonicalise, ldbl_nearbyint): New functions. * sysdeps/ieee754/ldbl-128ibm/e_fmodl.c (__ieee754_fmodl): Replace EXTRACT_IBM_EXTENDED_MANTISSA and INSERT_IBM_EXTENDED_MANTISSA with ldbl_extract_mantissa and ldbl_insert_mantissa. * sysdeps/ieee754/ldbl-128ibm/e_rem_pio2l.c (__ieee754_rem_pio2l): Replace EXTRACT_IBM_EXTENDED_MANTISSA with ldbl_extract_mantissa. (ldbl_extract_mantissa, ldbl_insert_mantissa): New inline functions. * sysdeps/ieee754/ldbl-128ibm/s_ceill.c (__ceill): Handle rounding that spans doubles in IBM long double format. * sysdeps/ieee754/ldbl-128ibm/s_floorl.c: Likewise. * sysdeps/ieee754/ldbl-128ibm/s_rintl.c: Likewise. * sysdeps/ieee754/ldbl-128ibm/s_roundl.c: Likewise. * sysdeps/ieee754/ldbl-128ibm/s_truncl.c: Likewise. * sysdeps/powerpc/powerpc64/fpu/s_rintl.S: File removed.
Diffstat (limited to 'sysdeps/powerpc')
-rw-r--r-- | sysdeps/powerpc/fpu/fegetround.c | 4 | ||||
-rw-r--r-- | sysdeps/powerpc/fpu/fenv_libc.h | 37 | ||||
-rw-r--r-- | sysdeps/powerpc/fpu/fesetround.c | 18 | ||||
-rw-r--r-- | sysdeps/powerpc/fpu/math_ldbl.h | 189 | ||||
-rw-r--r-- | sysdeps/powerpc/powerpc64/fpu/s_rintl.S | 113 |
5 files changed, 230 insertions, 131 deletions
diff --git a/sysdeps/powerpc/fpu/fegetround.c b/sysdeps/powerpc/fpu/fegetround.c index ae521fdf10..93663ad546 100644 --- a/sysdeps/powerpc/fpu/fegetround.c +++ b/sysdeps/powerpc/fpu/fegetround.c @@ -23,7 +23,5 @@ int fegetround (void) { - int result; - asm ("mcrfs 7,7 ; mfcr %0" : "=r"(result) : : "cr7"); \ - return result & 3; + return __fegetround(); } diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h index 7ae12a7d2b..fd5fc0c767 100644 --- a/sysdeps/powerpc/fpu/fenv_libc.h +++ b/sysdeps/powerpc/fpu/fenv_libc.h @@ -1,5 +1,5 @@ /* Internal libc stuff for floating point environment routines. - Copyright (C) 1997 Free Software Foundation, Inc. + Copyright (C) 1997, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -54,6 +54,41 @@ typedef union unsigned int l[2]; } fenv_union_t; + +static inline int +__fegetround (void) +{ + int result; + asm volatile ("mcrfs 7,7\n\t" + "mfcr %0" : "=r"(result) : : "cr7"); + return result & 3; +} +#define fegetround() __fegetround() + +static inline int +__fesetround (int round) +{ + if ((unsigned int) round < 2) + { + asm volatile ("mtfsb0 30"); + if ((unsigned int) round == 0) + asm volatile ("mtfsb0 31"); + else + asm volatile ("mtfsb1 31"); + } + else + { + asm volatile ("mtfsb1 30"); + if ((unsigned int) round == 2) + asm volatile ("mtfsb0 31"); + else + asm volatile ("mtfsb1 31"); + } + + return 0; +} +#define fesetround(mode) __fesetround(mode) + /* Definitions of all the FPSCR bit numbers */ enum { FPSCR_FX = 0, /* exception summary */ diff --git a/sysdeps/powerpc/fpu/fesetround.c b/sysdeps/powerpc/fpu/fesetround.c index 67518d0df4..a7efa3bbb0 100644 --- a/sysdeps/powerpc/fpu/fesetround.c +++ b/sysdeps/powerpc/fpu/fesetround.c @@ -1,5 +1,5 @@ /* Set current rounding direction. - Copyright (C) 1997, 2005 Free Software Foundation, Inc. + Copyright (C) 1997, 2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. @@ -20,23 +20,13 @@ #include <fenv_libc.h> +#undef fesetround int fesetround (int round) { - fenv_union_t u; - if ((unsigned int) round > 3) return 1; - - /* Get the current state. */ - u.fenv = fegetenv_register (); - - /* Set the relevant bits. */ - u.l[1] = (u.l[1] & ~3) | (round & 3); - - /* Put the new state in effect. */ - fesetenv_register (u.fenv); - - return 0; + else + return __fesetround(round); } libm_hidden_def (fesetround) diff --git a/sysdeps/powerpc/fpu/math_ldbl.h b/sysdeps/powerpc/fpu/math_ldbl.h new file mode 100644 index 0000000000..6cd6d0bdfe --- /dev/null +++ b/sysdeps/powerpc/fpu/math_ldbl.h @@ -0,0 +1,189 @@ +#ifndef _MATH_PRIVATE_H_ +#error "Never use <math_ldbl.h> directly; include <math_private.h> instead." +#endif + +#include <sysdeps/ieee754/ldbl-128/math_ldbl.h> +#include <ieee754.h> + +static inline void +ldbl_extract_mantissa (int64_t *hi64, u_int64_t *lo64, int *exp, long double x) +{ + /* We have 105 bits of mantissa plus one implicit digit. Since + 106 bits are representable we use the first implicit digit for + the number before the decimal point and the second implicit bit + as bit 53 of the mantissa. */ + unsigned long long hi, lo; + int ediff; + union ibm_extended_long_double eldbl; + eldbl.d = x; + *exp = eldbl.ieee.exponent - IBM_EXTENDED_LONG_DOUBLE_BIAS; + + lo = ((long long)eldbl.ieee.mantissa2 << 32) | eldbl.ieee.mantissa3; + hi = ((long long)eldbl.ieee.mantissa0 << 32) | eldbl.ieee.mantissa1; + /* If the lower double is not a denomal or zero then set the hidden + 53rd bit. */ + if (eldbl.ieee.exponent2 > 0x001) + { + lo |= (1ULL << 52); + lo = lo << 7; /* pre-shift lo to match ieee854. */ + /* The lower double is normalized separately from the upper. We + may need to adjust the lower manitissa to reflect this. */ + ediff = eldbl.ieee.exponent - eldbl.ieee.exponent2; + if (ediff > 53) + lo = lo >> (ediff-53); + } + hi |= (1ULL << 52); + + if ((eldbl.ieee.negative != eldbl.ieee.negative2) + && ((eldbl.ieee.exponent2 != 0) && (lo != 0LL))) + { + hi--; + lo = (1ULL << 60) - lo; + if (hi < (1ULL << 52)) + { + /* we have a borrow from the hidden bit, so shift left 1. */ + hi = (hi << 1) | (lo >> 59); + lo = 0xfffffffffffffffLL & (lo << 1); + *exp = *exp - 1; + } + } + *lo64 = (hi << 60) | lo; + *hi64 = hi >> 4; +} + +static inline long double +ldbl_insert_mantissa (int sign, int exp, int64_t hi64, u_int64_t lo64) +{ + union ibm_extended_long_double u; + unsigned long hidden2, lzcount; + unsigned long long hi, lo; + + u.ieee.negative = sign; + u.ieee.negative2 = sign; + u.ieee.exponent = exp + IBM_EXTENDED_LONG_DOUBLE_BIAS; + u.ieee.exponent2 = exp-53 + IBM_EXTENDED_LONG_DOUBLE_BIAS; + /* Expect 113 bits (112 bits + hidden) right justified in two longs. + The low order 53 bits (52 + hidden) go into the lower double */ + lo = (lo64 >> 7)& ((1ULL << 53) - 1); + hidden2 = (lo64 >> 59) & 1ULL; + /* The high order 53 bits (52 + hidden) go into the upper double */ + hi = (lo64 >> 60) & ((1ULL << 11) - 1); + hi |= (hi64 << 4); + + if (lo != 0LL) + { + /* hidden2 bit of low double controls rounding of the high double. + If hidden2 is '1' then round up hi and adjust lo (2nd mantissa) + plus change the sign of the low double to compensate. */ + if (hidden2) + { + hi++; + u.ieee.negative2 = !sign; + lo = (1ULL << 53) - lo; + } + /* The hidden bit of the lo mantissa is zero so we need to + normalize the it for the low double. Shift it left until the + hidden bit is '1' then adjust the 2nd exponent accordingly. */ + + if (sizeof (lo) == sizeof (long)) + lzcount = __builtin_clzl (lo); + else if ((lo >> 32) != 0) + lzcount = __builtin_clzl ((long) (lo >> 32)); + else + lzcount = __builtin_clzl ((long) lo) + 32; + lzcount = lzcount - 11; + if (lzcount > 0) + { + int expnt2 = u.ieee.exponent2 - lzcount; + if (expnt2 >= 1) + { + /* Not denormal. Normalize and set low exponent. */ + lo = lo << lzcount; + u.ieee.exponent2 = expnt2; + } + else + { + /* Is denormal. */ + lo = lo << (lzcount + expnt2); + u.ieee.exponent2 = 0; + } + } + } + else + { + u.ieee.negative2 = 0; + u.ieee.exponent2 = 0; + } + + u.ieee.mantissa3 = lo & ((1ULL << 32) - 1); + u.ieee.mantissa2 = (lo >> 32) & ((1ULL << 20) - 1); + u.ieee.mantissa1 = hi & ((1ULL << 32) - 1); + u.ieee.mantissa0 = (hi >> 32) & ((1ULL << 20) - 1); + return u.d; +} + +/* gcc generates disgusting code to pack and unpack long doubles. + This tells gcc that pack/unpack is really a nop. We use fr1/fr2 + because those are the regs used to pass/return a single + long double arg. */ +static inline long double +ldbl_pack (double a, double aa) +{ + register long double x __asm__ ("fr1"); + register double xh __asm__ ("fr1"); + register double xl __asm__ ("fr2"); + xh = a; + xl = aa; + __asm__ ("" : "=f" (x) : "f" (xh), "f" (xl)); + return x; +} + +static inline void +ldbl_unpack (long double l, double *a, double *aa) +{ + register long double x __asm__ ("fr1"); + register double xh __asm__ ("fr1"); + register double xl __asm__ ("fr2"); + x = l; + __asm__ ("" : "=f" (xh), "=f" (xl) : "f" (x)); + *a = xh; + *aa = xl; +} + + +/* Convert a finite long double to canonical form. + Does not handle +/-Inf properly. */ +static inline void +ldbl_canonicalize (double *a, double *aa) +{ + double xh, xl; + + xh = *a + *aa; + xl = (*a - xh) + *aa; + *a = xh; + *aa = xl; +} + +/* Simple inline nearbyint (double) function . + Only works in the default rounding mode + but is useful in long double rounding functions. */ +static inline double +ldbl_nearbyint (double a) +{ + double two52 = 0x10000000000000LL; + + if (__builtin_expect ((__builtin_fabs (a) < two52), 1)) + { + if (__builtin_expect ((a > 0.0), 1)) + { + a += two52; + a -= two52; + } + else if (__builtin_expect ((a < 0.0), 1)) + { + a = two52 - a; + a = -(a - two52); + } + } + return a; +} diff --git a/sysdeps/powerpc/powerpc64/fpu/s_rintl.S b/sysdeps/powerpc/powerpc64/fpu/s_rintl.S deleted file mode 100644 index 2ca2d4481f..0000000000 --- a/sysdeps/powerpc/powerpc64/fpu/s_rintl.S +++ /dev/null @@ -1,113 +0,0 @@ -/* Round to int long double floating-point values. - IBM extended format long double version. - Copyright (C) 2004, 2006 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -/* This has been coded in assembler because GCC makes such a mess of it - when it's coded in C. */ - -#include <sysdep.h> -#include <math_ldbl_opt.h> - - .section ".toc","aw" -.LC0: /* 2**52 */ - .tc FD_43300000_0[TC],0x4330000000000000 - .section ".text" - -ENTRY (__rintl) - lfd fp13,.LC0@toc(2) - fabs fp0,fp1 - fsub fp12,fp13,fp13 /* generate 0.0 */ - fabs fp9,fp2 - fcmpu cr7,fp0,fp13 /* if (fabs(x) > TWO52) */ - fcmpu cr6,fp1,fp12 /* if (x > 0.0) */ - bnl- cr7,.L2 - fmr fp2,fp12 - bng- cr6,.L1 - fadd fp1,fp1,fp13 /* x+= TWO52; */ - fsub fp1,fp1,fp13 /* x-= TWO52; */ - fabs fp1,fp1 /* if (x == 0.0) */ - blr /* x = 0.0; */ -.L1: - bnllr- cr6 /* if (x < 0.0) */ - fsub fp1,fp1,fp13 /* x-= TWO52; */ - fadd fp1,fp1,fp13 /* x+= TWO52; */ - fnabs fp1,fp1 /* if (x == 0.0) */ - blr /* x = -0.0; */ - -/* The high double is > TWO52 so we need to round the low double and - perhaps the high double. In this case we have to round the low - double and handle any adjustment to the high double that may be - caused by rounding (up). This is complicated by the fact that the - high double may already be rounded and the low double may have the - opposite sign to compensate.This gets a bit tricky so we use the - following algorithm: - - tau = floor(x_high/TWO52); - x0 = x_high - tau; - x1 = x_low + tau; - r1 = rint(x1); - y_high = x0 + r1; - y_low = x0 - y_high + r1; - return y; */ -.L2: - fcmpu cr7,fp9,fp13 /* if (|x_low| > TWO52) */ - fcmpu cr0,fp9,fp12 /* || (|x_low| == 0.0) */ - fcmpu cr5,fp2,fp12 /* if (x_low > 0.0) */ - bgelr- cr7 /* return x; */ - beqlr- cr0 - fdiv fp8,fp1,fp13 /* x_high/TWO52 */ - - bng- cr6,.L6 /* if (x > 0.0) */ - fctidz fp0,fp8 - fcfid fp8,fp0 /* tau = floor(x_high/TWO52); */ - fadd fp8,fp8,fp8 /* tau++; Make tau even */ - bng cr5,.L4 /* if (x_low > 0.0) */ - fmr fp3,fp1 - fmr fp4,fp2 - b .L5 -.L4: /* if (x_low < 0.0) */ - fsub fp3,fp1,fp8 /* x0 = x_high - tau; */ - fadd fp4,fp2,fp8 /* x1 = x_low + tau; */ -.L5: - fadd fp5,fp4,fp13 /* r1 = x1 + TWO52; */ - fsub fp5,fp5,fp13 /* r1 = r1 - TWO52; */ - b .L9 -.L6: /* if (x < 0.0) */ - fctidz fp0,fp8 - fcfid fp8,fp0 /* tau = floor(x_high/TWO52); */ - fadd fp8,fp8,fp8 /* tau++; Make tau even */ - bnl cr5,.L7 /* if (x_low < 0.0) */ - fmr fp3,fp1 - fmr fp4,fp2 - b .L8 -.L7: /* if (x_low > 0.0) */ - fsub fp3,fp1,fp8 /* x0 = x_high - tau; */ - fadd fp4,fp2,fp8 /* x1 = x_low + tau; */ -.L8: - fsub fp5,fp13,fp4 /* r1 = TWO52 - x1; */ - fsub fp0,fp5,fp13 /* r1 = - (r1 - TWO52); */ - fneg fp5,fp0 -.L9: - fadd fp1,fp3,fp5 /* y_high = x0 + r1; */ - fsub fp2,fp3,fp1 /* y_low = x0 - y_high + r1; */ - fadd fp2,fp2,fp5 - blr -END (__rintl) - -long_double_symbol (libm, __rintl, rintl) |