summaryrefslogtreecommitdiff
path: root/gcc/config/rs6000/darwin-ldouble.c
diff options
context:
space:
mode:
authorgeoffk <geoffk@138bc75d-0d04-0410-961f-82ee72b054a4>2004-07-31 01:40:18 +0000
committergeoffk <geoffk@138bc75d-0d04-0410-961f-82ee72b054a4>2004-07-31 01:40:18 +0000
commitea1f8f68f1ba51ab60d2a1d1066821eb890bf1da (patch)
tree4d9dd0c1be8c782967c209e2f38d6be5b51df9bb /gcc/config/rs6000/darwin-ldouble.c
parent24a7efd05505b767bad23d6a63f7d07e5734d05f (diff)
downloadgcc-ea1f8f68f1ba51ab60d2a1d1066821eb890bf1da.tar.gz
2004-07-30 Geoffrey Keating <geoffk@apple.com>
* config/rs6000/rs6000.c (legitimate_lo_sum_address_p): Permit non-offsettable addresses even for DImode. (rs6000_split_multireg_move): Cope with non-offsettable addresses being moved into multiple GPRs. * config/rs6000/rs6000.c (RS6000_DEFAULT_LONG_DOUBLE_SIZE): Default to 64. (rs6000_override_options): Use RS6000_DEFAULT_LONG_DOUBLE_SIZE. * config/rs6000/darwin.h (RS6000_DEFAULT_LONG_DOUBLE_SIZE): Define to 128. * config/rs6000/darwin-ldouble.c (isless): New macro. (inf): New macro. (nonfinite): New macro. (FPKINF): Delete. (_xlqadd): Completely rewrite. (_xlqmul): Correct overflow handling. (_xlqdiv): Correct overflow handling. * config/rs6000/darwin-ldouble-format: New file. Index: testsuite/ChangeLog 2004-07-30 Geoffrey Keating <geoffk@apple.com> * gcc.dg/darwin-longdouble.c: New file. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@85371 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/rs6000/darwin-ldouble.c')
-rw-r--r--gcc/config/rs6000/darwin-ldouble.c103
1 files changed, 39 insertions, 64 deletions
diff --git a/gcc/config/rs6000/darwin-ldouble.c b/gcc/config/rs6000/darwin-ldouble.c
index 58786075011..91c00281585 100644
--- a/gcc/config/rs6000/darwin-ldouble.c
+++ b/gcc/config/rs6000/darwin-ldouble.c
@@ -51,9 +51,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#if !_SOFT_FLOAT && (defined (__MACH__) || defined (__powerpc64__))
#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 ()))
+
/* 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. */
@@ -69,66 +73,40 @@ typedef union
double dval[2];
} longDblUnion;
-static const double FPKINF = 1.0/0.0;
-
/* Add two 'long double' values and return the result. */
long double
-_xlqadd (double a, double b, double c, double d)
+_xlqadd (double a, double aa, double c, double cc)
{
- longDblUnion z;
- double t, tau, u, FPR_zero, FPR_PosInf;
-
- FPR_zero = 0.0;
- FPR_PosInf = FPKINF;
-
- if (unlikely (a != a) || unlikely (c != c))
- return a + c; /* NaN result. */
+ longDblUnion x;
+ double z, q, zz, xh;
- /* Ordered operands are arranged in order of their magnitudes. */
+ z = a + c;
- /* Switch inputs if |(c,d)| > |(a,b)|. */
- if (fabs (c) > fabs (a))
+ if (nonfinite (z))
{
- t = a;
- tau = b;
- a = c;
- b = d;
- c = t;
- d = tau;
+ z = cc + aa + c + a;
+ if (nonfinite (z))
+ return z;
+ x.dval[0] = z; /* Will always be DBL_MAX. */
+ zz = aa + cc;
+ if (fabs(a) > fabs(c))
+ x.dval[1] = a - z + c + zz;
+ else
+ x.dval[1] = c - z + a + zz;
}
-
- /* b <- second largest magnitude double. */
- if (fabs (c) > fabs (b))
+ else
{
- t = b;
- b = c;
- c = t;
- }
+ q = a - z;
+ zz = q + c + (a - (q + z)) + aa + cc;
+ xh = z + zz;
- /* Thanks to commutativity, sum is invariant w.r.t. the next
- conditional exchange. */
- tau = d + c;
+ if (nonfinite (xh))
+ return xh;
- /* Order the smallest magnitude doubles. */
- if (fabs (d) > fabs (c))
- {
- t = c;
- c = d;
- d = t;
+ x.dval[0] = xh;
+ x.dval[1] = z - xh + zz;
}
-
- t = (tau + b) + a; /* Sum values in ascending magnitude order. */
-
- /* Infinite or zero result. */
- if (unlikely (t == FPR_zero) || unlikely (fabs (t) == FPR_PosInf))
- return t;
-
- /* Usual case. */
- tau = (((a-t) + b) + c) + d;
- u = t + tau;
- z.dval[0] = u; /* Final fixup for long double result. */
- z.dval[1] = (t - u) + tau;
- return z.ldval;
+ return x.ldval;
}
long double
@@ -141,21 +119,17 @@ long double
_xlqmul (double a, double b, double c, double d)
{
longDblUnion z;
- double t, tau, u, v, w, FPR_zero, FPR_PosInf;
+ double t, tau, u, v, w;
- FPR_zero = 0.0;
- FPR_PosInf = FPKINF;
-
t = a * c; /* Highest order double term. */
- if (unlikely (t != t) || unlikely (t == FPR_zero)
- || unlikely (fabs (t) == FPR_PosInf))
+ if (unlikely (t == 0) /* Preserve -0. */
+ || nonfinite (t))
return t;
- /* Finite nonzero result requires summing of terms of two highest
- orders. */
+ /* Sum terms of two highest orders. */
- /* Use fused multiply-add to get low part of a * c. */
+ /* Use fused multiply-add to get low part of a * c. */
asm ("fmsub %0,%1,%2,%3" : "=f"(tau) : "f"(a), "f"(c), "f"(t));
v = a*d;
w = b*c;
@@ -163,6 +137,8 @@ _xlqmul (double a, double b, double c, double d)
u = t + tau;
/* Construct long double result. */
+ if (nonfinite (u))
+ return u;
z.dval[0] = u;
z.dval[1] = (t - u) + tau;
return z.ldval;
@@ -172,15 +148,12 @@ long double
_xlqdiv (double a, double b, double c, double d)
{
longDblUnion z;
- double s, sigma, t, tau, u, v, w, FPR_zero, FPR_PosInf;
-
- FPR_zero = 0.0;
- FPR_PosInf = FPKINF;
+ double s, sigma, t, tau, u, v, w;
t = a / c; /* highest order double term */
- if (unlikely (t != t) || unlikely (t == FPR_zero)
- || unlikely (fabs (t) == FPR_PosInf))
+ if (unlikely (t == 0) /* Preserve -0. */
+ || nonfinite (t))
return t;
/* Finite nonzero result requires corrections to the highest order term. */
@@ -197,6 +170,8 @@ _xlqdiv (double a, double b, double c, double d)
u = t + tau;
/* Construct long double result. */
+ if (nonfinite (u))
+ return u;
z.dval[0] = u;
z.dval[1] = (t - u) + tau;
return z.ldval;