#if ((!defined (__NO_FPRS__) || defined (_SOFT_FLOAT)) \
&& !defined (__LITTLE_ENDIAN__) \
&& (defined (__MACH__) || defined (__powerpc__) || defined (_AIX)))
#define fabs(x) __builtin_fabs(x)
#define isless(x, y) __builtin_isless (x, y)
#define inf() __builtin_inf()
#define unlikely(x) __builtin_expect ((x), 0)
#define nonfinite(a) unlikely (! isless (fabs (a), inf ()))
# define strong_alias(name, aliasname) _strong_alias(name, aliasname)
# define _strong_alias(name, aliasname) \
extern __typeof (name) aliasname __attribute__ ((alias (#name)));
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__))
__asm__ (".symver __gcc_qadd,_xlqadd@GCC_3.4\n\t"
".symver __gcc_qsub,_xlqsub@GCC_3.4\n\t"
".symver __gcc_qmul,_xlqmul@GCC_3.4\n\t"
".symver __gcc_qdiv,_xlqdiv@GCC_3.4\n\t"
".symver .__gcc_qadd,._xlqadd@GCC_3.4\n\t"
".symver .__gcc_qsub,._xlqsub@GCC_3.4\n\t"
".symver .__gcc_qmul,._xlqmul@GCC_3.4\n\t"
".symver .__gcc_qdiv,._xlqdiv@GCC_3.4");
#endif
typedef union
{
long double ldval;
double dval[2];
} longDblUnion;
long double
__gcc_qadd (double a, double aa, double c, double cc)
{
longDblUnion x;
double z, q, zz, xh;
z = a + c;
if (nonfinite (z))
{
z = cc + aa + c + a;
if (nonfinite (z))
return z;
x.dval[0] = z;
zz = aa + cc;
if (fabs(a) > fabs(c))
x.dval[1] = a - z + c + zz;
else
x.dval[1] = c - z + a + zz;
}
else
{
q = a - z;
zz = q + c + (a - (q + z)) + aa + cc;
if (zz == 0.0)
return z;
xh = z + zz;
if (nonfinite (xh))
return xh;
x.dval[0] = xh;
x.dval[1] = z - xh + zz;
}
return x.ldval;
}
long double
__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)
{
longDblUnion z;
double t, tau, u, v, w;
t = a * c;
if (unlikely (t == 0)
|| nonfinite (t))
return t;
#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;
u = t + tau;
if (nonfinite (u))
return u;
z.dval[0] = u;
z.dval[1] = (t - u) + tau;
return z.ldval;
}
long double
__gcc_qdiv (double a, double b, double c, double d)
{
longDblUnion z;
double s, sigma, t, tau, u, v, w;
t = a / c;
if (unlikely (t == 0)
|| nonfinite (t))
return t;
s = c * t;
w = -(-b + d * 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;
u = t + tau;
if (nonfinite (u))
return u;
z.dval[0] = u;
z.dval[1] = (t - u) + tau;
return z.ldval;
}
#if defined (_SOFT_FLOAT) && defined (__LONG_DOUBLE_128__)
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);
long double
__gcc_qneg (double a, double aa)
{
longDblUnion x;
x.dval[0] = -a;
x.dval[1] = -aa;
return x.ldval;
}
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);
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);
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);
int
__gcc_qunord (double a, double aa, double c, double cc)
{
if (__eqdf2 (a, c) == 0)
return __unorddf2 (aa, cc);
return __unorddf2 (a, c);
}
long double
__gcc_stoq (float a)
{
longDblUnion x;
x.dval[0] = (double) a;
x.dval[1] = 0.0;
return x.ldval;
}
long double
__gcc_dtoq (double a)
{
longDblUnion x;
x.dval[0] = a;
x.dval[1] = 0.0;
return x.ldval;
}
float
__gcc_qtos (double a, double aa __attribute__ ((__unused__)))
{
return (float) a;
}
double
__gcc_qtod (double a, double aa __attribute__ ((__unused__)))
{
return a;
}
int
__gcc_qtoi (double a, double aa)
{
double z = a + aa;
return (int) z;
}
unsigned int
__gcc_qtou (double a, double aa)
{
double z = a + aa;
return (unsigned int) z;
}
long double
__gcc_itoq (int a)
{
return __gcc_dtoq ((double) a);
}
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"
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);
#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;
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;
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;
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