diff options
author | dje <dje@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-01-16 16:03:26 +0000 |
---|---|---|
committer | dje <dje@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-01-16 16:03:26 +0000 |
commit | 23ee07771e8bcc4dfae2fc4e408df118990ef0f3 (patch) | |
tree | aab04471d4337abf0e76b39edfaba8c2f5cebe06 /gcc/config/rs6000/darwin-ldouble.c | |
parent | 34b0e09cd2ed4f463f7168b8ca0fb8f15443d455 (diff) | |
download | gcc-23ee07771e8bcc4dfae2fc4e408df118990ef0f3.tar.gz |
* config/rs6000/darwin-ldouble.c: Build file for SOFT_FLOAT.
(strong_alias): Define.
(__gcc_qmul): Provide non-FMA for soft-float.
(__gcc_qdiv): Same.
(__gcc_qneg): New.
(__gcc_qeq): New.
(__gcc_qle): New.
(__gcc_qge): New.
(__gcc_qunord): New.
(__gcc_stoq): New.
(__gcc_dtoq): New.
(__gcc_qtos): New.
(__gcc_qtod): New.
(__gcc_qtoi): New.
(__gcc_qtou): New.
(__gcc_itoq): New.
(__gcc_utoq): New.
(fmsub): New.
* config/rs6000/rs6000.c (rs6000_init_libfuncs): Initialize
soft-float functions.
* config/rs6000/libgcc-ppc-glibc.ver: Version soft-float symbols.
* config/rs6000/sysv4.h (SUBTARGET_OVERRIDE_OPTIONS): Do not warn
about long double soft float.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@120828 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/rs6000/darwin-ldouble.c')
-rw-r--r-- | gcc/config/rs6000/darwin-ldouble.c | 244 |
1 files changed, 239 insertions, 5 deletions
diff --git a/gcc/config/rs6000/darwin-ldouble.c b/gcc/config/rs6000/darwin-ldouble.c index 356bc18b57e..8ac69f2e627 100644 --- a/gcc/config/rs6000/darwin-ldouble.c +++ b/gcc/config/rs6000/darwin-ldouble.c @@ -49,7 +49,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA This code currently assumes big-endian. */ -#if (!defined (__NO_FPRS__) && !defined (__LITTLE_ENDIAN__) \ +#if ((!defined (__NO_FPRS__) || defined (_SOFT_FLOAT)) \ + && !defined (__LITTLE_ENDIAN__) \ && (defined (__MACH__) || defined (__powerpc__) || defined (_AIX))) #define fabs(x) __builtin_fabs(x) @@ -60,14 +61,19 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #define nonfinite(a) unlikely (! isless (fabs (a), inf ())) +/* Define ALIASNAME as a strong alias for NAME. */ +# define strong_alias(name, aliasname) _strong_alias(name, aliasname) +# define _strong_alias(name, aliasname) \ + extern __typeof (name) aliasname __attribute__ ((alias (#name))); + /* All these routines actually take two long doubles as parameters, but GCC currently generates poor code when a union is used to turn a long double into a pair of doubles. */ -extern long double __gcc_qadd (double, double, double, double); -extern long double __gcc_qsub (double, double, double, double); -extern long double __gcc_qmul (double, double, double, double); -extern long double __gcc_qdiv (double, double, double, double); +long double __gcc_qadd (double, double, double, double); +long double __gcc_qsub (double, double, double, double); +long double __gcc_qmul (double, double, double, double); +long double __gcc_qdiv (double, double, double, double); #if defined __ELF__ && defined SHARED \ && (defined __powerpc64__ || !(defined __linux__ || defined __gnu_hurd__)) @@ -139,6 +145,10 @@ __gcc_qsub (double a, double b, double c, double d) return __gcc_qadd (a, b, -c, -d); } +#ifdef _SOFT_FLOAT +static double fmsub (double, double, double); +#endif + long double __gcc_qmul (double a, double b, double c, double d) { @@ -154,7 +164,11 @@ __gcc_qmul (double a, double b, double c, double d) /* Sum terms of two highest orders. */ /* Use fused multiply-add to get low part of a * c. */ +#ifndef _SOFT_FLOAT asm ("fmsub %0,%1,%2,%3" : "=f"(tau) : "f"(a), "f"(c), "f"(t)); +#else + tau = fmsub (a, c, t); +#endif v = a*d; w = b*c; tau += v + w; /* Add in other second-order terms. */ @@ -187,7 +201,11 @@ __gcc_qdiv (double a, double b, double c, double d) numerically necessary. */ /* Use fused multiply-add to get low part of c * t. */ +#ifndef _SOFT_FLOAT asm ("fmsub %0,%1,%2,%3" : "=f"(sigma) : "f"(c), "f"(t), "f"(s)); +#else + sigma = fmsub (c, t, s); +#endif v = a - s; tau = ((v-sigma)+w)/c; /* Correction to t. */ @@ -201,4 +219,220 @@ __gcc_qdiv (double a, double b, double c, double d) return z.ldval; } +#ifdef _SOFT_FLOAT + +long double __gcc_qneg (double, double); +int __gcc_qeq (double, double, double, double); +int __gcc_qne (double, double, double, double); +int __gcc_qge (double, double, double, double); +int __gcc_qle (double, double, double, double); +int __gcc_qunord (double, double, double, double); +long double __gcc_stoq (float); +long double __gcc_dtoq (double); +float __gcc_qtos (double, double); +double __gcc_qtod (double, double); +int __gcc_qtoi (double, double); +unsigned int __gcc_qtou (double, double); +long double __gcc_itoq (int); +long double __gcc_utoq (unsigned int); + +extern int __eqdf2 (double, double); +extern int __ledf2 (double, double); +extern int __gedf2 (double, double); +extern int __unorddf2 (double, double); + +/* Negate 'long double' value and return the result. */ +long double +__gcc_qneg (double a, double aa) +{ + longDblUnion x; + + x.dval[0] = -a; + x.dval[1] = -aa; + return x.ldval; +} + +/* Compare two 'long double' values for equality. */ +int +__gcc_qeq (double a, double aa, double c, double cc) +{ + if (__eqdf2 (a, c) == 0) + return __eqdf2 (aa, cc); + return 1; +} + +strong_alias (__gcc_qeq, __gcc_qne); + +/* Compare two 'long double' values for less than or equal. */ +int +__gcc_qle (double a, double aa, double c, double cc) +{ + if (__eqdf2 (a, c) == 0) + return __ledf2 (aa, cc); + return __ledf2 (a, c); +} + +strong_alias (__gcc_qle, __gcc_qlt); + +/* Compare two 'long double' values for greater than or equal. */ +int +__gcc_qge (double a, double aa, double c, double cc) +{ + if (__eqdf2 (a, c) == 0) + return __gedf2 (aa, cc); + return __gedf2 (a, c); +} + +strong_alias (__gcc_qge, __gcc_qgt); + +/* Compare two 'long double' values for unordered. */ +int +__gcc_qunord (double a, double aa, double c, double cc) +{ + if (__eqdf2 (a, c) == 0) + return __unorddf2 (aa, cc); + return __unorddf2 (a, c); +} + +/* Convert single to long double. */ +long double +__gcc_stoq (float a) +{ + longDblUnion x; + + x.dval[0] = (double) a; + x.dval[1] = 0.0; + + return x.ldval; +} + +/* Convert double to long double. */ +long double +__gcc_dtoq (double a) +{ + longDblUnion x; + + x.dval[0] = a; + x.dval[1] = 0.0; + + return x.ldval; +} + +/* Convert long double to single. */ +float +__gcc_qtos (double a, double aa __attribute__ ((__unused__))) +{ + return (float) a; +} + +/* Convert long double to double. */ +double +__gcc_qtod (double a, double aa __attribute__ ((__unused__))) +{ + return a; +} + +/* Convert long double to int. */ +int +__gcc_qtoi (double a, double aa) +{ + double z = a + aa; + return (int) z; +} + +/* Convert long double to unsigned int. */ +unsigned int +__gcc_qtou (double a, double aa) +{ + double z = a + aa; + return (unsigned int) z; +} + +/* Convert int to long double. */ +long double +__gcc_itoq (int a) +{ + return __gcc_dtoq ((double) a); +} + +/* Convert unsigned int to long double. */ +long double +__gcc_utoq (unsigned int a) +{ + return __gcc_dtoq ((double) a); +} + +#include "config/soft-fp/soft-fp.h" +#include "config/soft-fp/double.h" +#include "config/soft-fp/quad.h" + +/* Compute floating point multiply-subtract with higher (quad) precision. */ +static double +fmsub (double a, double b, double c) +{ + FP_DECL_EX; + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_Q(X); + FP_DECL_Q(Y); + FP_DECL_Q(Z); + FP_DECL_Q(U); + FP_DECL_Q(V); + FP_DECL_D(R); + double r; + long double u, v, x, y, z; + + FP_INIT_ROUNDMODE; + FP_UNPACK_RAW_D (A, a); + FP_UNPACK_RAW_D (B, b); + FP_UNPACK_RAW_D (C, c); + + /* Extend double to quad. */ +#if (2 * _FP_W_TYPE_SIZE) < _FP_FRACBITS_Q + FP_EXTEND(Q,D,4,2,X,A); + FP_EXTEND(Q,D,4,2,Y,B); + FP_EXTEND(Q,D,4,2,Z,C); +#else + FP_EXTEND(Q,D,2,1,X,A); + FP_EXTEND(Q,D,2,1,Y,B); + FP_EXTEND(Q,D,2,1,Z,C); +#endif + FP_PACK_RAW_Q(x,X); + FP_PACK_RAW_Q(y,Y); + FP_PACK_RAW_Q(z,Z); + FP_HANDLE_EXCEPTIONS; + + /* Multiply. */ + FP_INIT_ROUNDMODE; + FP_UNPACK_Q(X,x); + FP_UNPACK_Q(Y,y); + FP_MUL_Q(U,X,Y); + FP_PACK_Q(u,U); + FP_HANDLE_EXCEPTIONS; + + /* Subtract. */ + FP_INIT_ROUNDMODE; + FP_UNPACK_SEMIRAW_Q(U,u); + FP_UNPACK_SEMIRAW_Q(Z,z); + FP_SUB_Q(V,U,Z); + FP_PACK_SEMIRAW_Q(v,V); + FP_HANDLE_EXCEPTIONS; + + /* Truncate quad to double. */ + FP_INIT_ROUNDMODE; + FP_UNPACK_SEMIRAW_Q(V,v); +#if (2 * _FP_W_TYPE_SIZE) < _FP_FRACBITS_Q + FP_TRUNC(D,Q,2,4,R,V); +#else + FP_TRUNC(D,Q,1,2,R,V); +#endif + FP_PACK_SEMIRAW_D(r,R); + FP_HANDLE_EXCEPTIONS; + + return r; +} + +#endif + #endif |