darwin-ldouble.c: Build file for SOFT_FLOAT.
* 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. From-SVN: r120828
This commit is contained in:
parent
05794ce850
commit
d0768f1953
@ -1,3 +1,29 @@
|
||||
2007-01-16 David Edelsohn <edelsohn@gnu.org>
|
||||
|
||||
* 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.
|
||||
|
||||
2007-01-16 Dorit Nuzman <dorit@il.ibm.com>
|
||||
Tehila Meyzels <tehila@il.ibm.com>
|
||||
|
||||
|
@ -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
|
||||
|
@ -20,6 +20,9 @@ GCC_4.1.0 {
|
||||
|
||||
%else
|
||||
GCC_3.4.4 {
|
||||
%endif
|
||||
%else
|
||||
GCC_4.2.0 {
|
||||
%endif
|
||||
|
||||
# long double support
|
||||
@ -27,5 +30,23 @@ GCC_3.4.4 {
|
||||
__gcc_qsub
|
||||
__gcc_qmul
|
||||
__gcc_qdiv
|
||||
}
|
||||
|
||||
%ifdef _SOFT_FLOAT
|
||||
__gcc_qneg
|
||||
__gcc_qeq
|
||||
__gcc_qne
|
||||
__gcc_ggt
|
||||
__gcc_qge
|
||||
__gcc_qlt
|
||||
__gcc_qle
|
||||
__gcc_qunord
|
||||
__gcc_stoq
|
||||
__gcc_dtoq
|
||||
__gcc_qtos
|
||||
__gcc_qtod
|
||||
__gcc_qtoi
|
||||
__gcc_qtou
|
||||
__gcc_itoq
|
||||
__gcc_utoq
|
||||
%endif
|
||||
}
|
||||
|
@ -9401,9 +9401,6 @@ rs6000_common_init_builtins (void)
|
||||
static void
|
||||
rs6000_init_libfuncs (void)
|
||||
{
|
||||
if (!TARGET_HARD_FLOAT)
|
||||
return;
|
||||
|
||||
if (DEFAULT_ABI != ABI_V4 && TARGET_XCOFF
|
||||
&& !TARGET_POWER2 && !TARGET_POWERPC)
|
||||
{
|
||||
@ -9422,6 +9419,27 @@ rs6000_init_libfuncs (void)
|
||||
set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub");
|
||||
set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul");
|
||||
set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv");
|
||||
|
||||
if (TARGET_SOFT_FLOAT)
|
||||
{
|
||||
set_optab_libfunc (neg_optab, TFmode, "__gcc_qneg");
|
||||
set_optab_libfunc (eq_optab, TFmode, "__gcc_qeq");
|
||||
set_optab_libfunc (ne_optab, TFmode, "__gcc_qne");
|
||||
set_optab_libfunc (gt_optab, TFmode, "__gcc_qgt");
|
||||
set_optab_libfunc (ge_optab, TFmode, "__gcc_qge");
|
||||
set_optab_libfunc (lt_optab, TFmode, "__gcc_qlt");
|
||||
set_optab_libfunc (le_optab, TFmode, "__gcc_qle");
|
||||
set_optab_libfunc (unord_optab, TFmode, "__gcc_qunord");
|
||||
|
||||
set_conv_libfunc (sext_optab, TFmode, SFmode, "__gcc_stoq");
|
||||
set_conv_libfunc (sext_optab, TFmode, DFmode, "__gcc_dtoq");
|
||||
set_conv_libfunc (trunc_optab, SFmode, TFmode, "__gcc_qtos");
|
||||
set_conv_libfunc (trunc_optab, DFmode, TFmode, "__gcc_qtod");
|
||||
set_conv_libfunc (sfix_optab, SImode, TFmode, "__gcc_qtoi");
|
||||
set_conv_libfunc (ufix_optab, SImode, TFmode, "__gcc_qtou");
|
||||
set_conv_libfunc (sfloat_optab, TFmode, SImode, "__gcc_itoq");
|
||||
set_conv_libfunc (ufloat_optab, TFmode, SImode, "__gcc_utoq");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -215,10 +215,6 @@ do { \
|
||||
error ("-msecure-plt not supported by your assembler"); \
|
||||
} \
|
||||
\
|
||||
if (TARGET_SOFT_FLOAT && TARGET_LONG_DOUBLE_128 \
|
||||
&& rs6000_explicit_options.long_double) \
|
||||
warning (0, "-msoft-float and -mlong-double-128 not supported"); \
|
||||
\
|
||||
/* Treat -fPIC the same as -mrelocatable. */ \
|
||||
if (flag_pic > 1 && DEFAULT_ABI != ABI_AIX) \
|
||||
{ \
|
||||
|
Loading…
Reference in New Issue
Block a user