darwin-ldouble.c revision 132718
1/* 128-bit long double support routines for Darwin.
2   Copyright (C) 1993, 2003, 2004 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 2, or (at your option) any later
9version.
10
11In addition to the permissions in the GNU General Public License, the
12Free Software Foundation gives you unlimited permission to link the
13compiled version of this file into combinations with other programs,
14and to distribute those combinations without any restriction coming
15from the use of this file.  (The General Public License restrictions
16do apply in other respects; for example, they cover modification of
17the file, and distribution when not linked into a combine
18executable.)
19
20GCC is distributed in the hope that it will be useful, but WITHOUT ANY
21WARRANTY; without even the implied warranty of MERCHANTABILITY or
22FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23for more details.
24
25You should have received a copy of the GNU General Public License
26along with GCC; see the file COPYING.  If not, write to the Free
27Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2802111-1307, USA.  */
29
30/* Implementations of floating-point long double basic arithmetic
31   functions called by the IBM C compiler when generating code for
32   PowerPC platforms.  In particular, the following functions are
33   implemented: _xlqadd, _xlqsub, _xlqmul, and _xlqdiv.  Double-double
34   algorithms are based on the paper "Doubled-Precision IEEE Standard
35   754 Floating-Point Arithmetic" by W. Kahan, February 26, 1987.  An
36   alternative published reference is "Software for Doubled-Precision
37   Floating-Point Computations", by Seppo Linnainmaa, ACM TOMS vol 7
38   no 3, September 1961, pages 272-283.  */
39
40/* Each long double is made up of two IEEE doubles.  The value of the
41   long double is the sum of the values of the two parts.  The most
42   significant part is required to be the value of the long double
43   rounded to the nearest double, as specified by IEEE.  For Inf
44   values, the least significant part is required to be one of +0.0 or
45   -0.0.  No other requirements are made; so, for example, 1.0 may be
46   represented as (1.0, +0.0) or (1.0, -0.0), and the low part of a
47   NaN is don't-care.
48
49   This code currently assumes big-endian.  */
50
51#if !_SOFT_FLOAT && (defined (__MACH__) || defined (__powerpc64__))
52
53#define fabs(x) __builtin_fabs(x)
54
55#define unlikely(x) __builtin_expect ((x), 0)
56
57/* All these routines actually take two long doubles as parameters,
58   but GCC currently generates poor code when a union is used to turn
59   a long double into a pair of doubles.  */
60
61extern long double _xlqadd (double, double, double, double);
62extern long double _xlqsub (double, double, double, double);
63extern long double _xlqmul (double, double, double, double);
64extern long double _xlqdiv (double, double, double, double);
65
66typedef union
67{
68  long double ldval;
69  double dval[2];
70} longDblUnion;
71
72static const double FPKINF = 1.0/0.0;
73
74/* Add two 'long double' values and return the result.	*/
75long double
76_xlqadd (double a, double b, double c, double d)
77{
78  longDblUnion z;
79  double t, tau, u, FPR_zero, FPR_PosInf;
80
81  FPR_zero = 0.0;
82  FPR_PosInf = FPKINF;
83
84  if (unlikely (a != a) || unlikely (c != c))
85    return a + c;  /* NaN result.  */
86
87  /* Ordered operands are arranged in order of their magnitudes.  */
88
89  /* Switch inputs if |(c,d)| > |(a,b)|. */
90  if (fabs (c) > fabs (a))
91    {
92      t = a;
93      tau = b;
94      a = c;
95      b = d;
96      c = t;
97      d = tau;
98    }
99
100  /* b <- second largest magnitude double. */
101  if (fabs (c) > fabs (b))
102    {
103      t = b;
104      b = c;
105      c = t;
106    }
107
108  /* Thanks to commutivity, sum is invariant w.r.t. the next
109     conditional exchange. */
110  tau = d + c;
111
112  /* Order the smallest magnitude doubles.  */
113  if (fabs (d) > fabs (c))
114    {
115      t = c;
116      c = d;
117      d = t;
118    }
119
120  t = (tau + b) + a;	     /* Sum values in ascending magnitude order.  */
121
122  /* Infinite or zero result.  */
123  if (unlikely (t == FPR_zero) || unlikely (fabs (t) == FPR_PosInf))
124    return t;
125
126  /* Usual case.  */
127  tau = (((a-t) + b) + c) + d;
128  u = t + tau;
129  z.dval[0] = u;	       /* Final fixup for long double result.  */
130  z.dval[1] = (t - u) + tau;
131  return z.ldval;
132}
133
134long double
135_xlqsub (double a, double b, double c, double d)
136{
137  return _xlqadd (a, b, -c, -d);
138}
139
140long double
141_xlqmul (double a, double b, double c, double d)
142{
143  longDblUnion z;
144  double t, tau, u, v, w, FPR_zero, FPR_PosInf;
145
146  FPR_zero = 0.0;
147  FPR_PosInf = FPKINF;
148
149  t = a * c;			/* Highest order double term.  */
150
151  if (unlikely (t != t) || unlikely (t == FPR_zero)
152      || unlikely (fabs (t) == FPR_PosInf))
153    return t;
154
155  /* Finite nonzero result requires summing of terms of two highest
156     orders.	*/
157
158  /* Use fused multiply-add to get low part of a * c.	 */
159  asm ("fmsub %0,%1,%2,%3" : "=f"(tau) : "f"(a), "f"(c), "f"(t));
160  v = a*d;
161  w = b*c;
162  tau += v + w;	    /* Add in other second-order terms.	 */
163  u = t + tau;
164
165  /* Construct long double result.  */
166  z.dval[0] = u;
167  z.dval[1] = (t - u) + tau;
168  return z.ldval;
169}
170
171long double
172_xlqdiv (double a, double b, double c, double d)
173{
174  longDblUnion z;
175  double s, sigma, t, tau, u, v, w, FPR_zero, FPR_PosInf;
176
177  FPR_zero = 0.0;
178  FPR_PosInf = FPKINF;
179
180  t = a / c;                    /* highest order double term */
181
182  if (unlikely (t != t) || unlikely (t == FPR_zero)
183      || unlikely (fabs (t) == FPR_PosInf))
184    return t;
185
186  /* Finite nonzero result requires corrections to the highest order term.  */
187
188  s = c * t;                    /* (s,sigma) = c*t exactly. */
189  w = -(-b + d * t);	/* Written to get fnmsub for speed, but not
190			   numerically necessary.  */
191
192  /* Use fused multiply-add to get low part of c * t.	 */
193  asm ("fmsub %0,%1,%2,%3" : "=f"(sigma) : "f"(c), "f"(t), "f"(s));
194  v = a - s;
195
196  tau = ((v-sigma)+w)/c;   /* Correction to t. */
197  u = t + tau;
198
199  /* Construct long double result. */
200  z.dval[0] = u;
201  z.dval[1] = (t - u) + tau;
202  return z.ldval;
203}
204
205#endif
206