1132718Skan/* 128-bit long double support routines for Darwin.
2169689Skan   Copyright (C) 1993, 2003, 2004, 2005, 2006, 2007
3169689Skan   Free Software Foundation, Inc.
4132718Skan
5132718SkanThis file is part of GCC.
6132718Skan
7132718SkanGCC is free software; you can redistribute it and/or modify it under
8132718Skanthe terms of the GNU General Public License as published by the Free
9132718SkanSoftware Foundation; either version 2, or (at your option) any later
10132718Skanversion.
11132718Skan
12132718SkanIn addition to the permissions in the GNU General Public License, the
13132718SkanFree Software Foundation gives you unlimited permission to link the
14132718Skancompiled version of this file into combinations with other programs,
15132718Skanand to distribute those combinations without any restriction coming
16132718Skanfrom the use of this file.  (The General Public License restrictions
17132718Skando apply in other respects; for example, they cover modification of
18132718Skanthe file, and distribution when not linked into a combine
19132718Skanexecutable.)
20132718Skan
21132718SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY
22132718SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or
23132718SkanFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24132718Skanfor more details.
25132718Skan
26132718SkanYou should have received a copy of the GNU General Public License
27132718Skanalong with GCC; see the file COPYING.  If not, write to the Free
28169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
29169689Skan02110-1301, USA.  */
30132718Skan
31132718Skan/* Implementations of floating-point long double basic arithmetic
32132718Skan   functions called by the IBM C compiler when generating code for
33132718Skan   PowerPC platforms.  In particular, the following functions are
34169689Skan   implemented: __gcc_qadd, __gcc_qsub, __gcc_qmul, and __gcc_qdiv.
35169689Skan   Double-double algorithms are based on the paper "Doubled-Precision
36169689Skan   IEEE Standard 754 Floating-Point Arithmetic" by W. Kahan, February 26,
37169689Skan   1987.  An alternative published reference is "Software for
38169689Skan   Doubled-Precision Floating-Point Computations", by Seppo Linnainmaa,
39169689Skan   ACM TOMS vol 7 no 3, September 1981, pages 272-283.  */
40132718Skan
41132718Skan/* Each long double is made up of two IEEE doubles.  The value of the
42132718Skan   long double is the sum of the values of the two parts.  The most
43132718Skan   significant part is required to be the value of the long double
44132718Skan   rounded to the nearest double, as specified by IEEE.  For Inf
45132718Skan   values, the least significant part is required to be one of +0.0 or
46132718Skan   -0.0.  No other requirements are made; so, for example, 1.0 may be
47132718Skan   represented as (1.0, +0.0) or (1.0, -0.0), and the low part of a
48132718Skan   NaN is don't-care.
49132718Skan
50132718Skan   This code currently assumes big-endian.  */
51132718Skan
52169689Skan#if ((!defined (__NO_FPRS__) || defined (_SOFT_FLOAT)) \
53169689Skan     && !defined (__LITTLE_ENDIAN__) \
54169689Skan     && (defined (__MACH__) || defined (__powerpc__) || defined (_AIX)))
55132718Skan
56132718Skan#define fabs(x) __builtin_fabs(x)
57169689Skan#define isless(x, y) __builtin_isless (x, y)
58169689Skan#define inf() __builtin_inf()
59132718Skan
60132718Skan#define unlikely(x) __builtin_expect ((x), 0)
61132718Skan
62169689Skan#define nonfinite(a) unlikely (! isless (fabs (a), inf ()))
63169689Skan
64169689Skan/* Define ALIASNAME as a strong alias for NAME.  */
65169689Skan# define strong_alias(name, aliasname) _strong_alias(name, aliasname)
66169689Skan# define _strong_alias(name, aliasname) \
67169689Skan  extern __typeof (name) aliasname __attribute__ ((alias (#name)));
68169689Skan
69132718Skan/* All these routines actually take two long doubles as parameters,
70132718Skan   but GCC currently generates poor code when a union is used to turn
71132718Skan   a long double into a pair of doubles.  */
72132718Skan
73169689Skanlong double __gcc_qadd (double, double, double, double);
74169689Skanlong double __gcc_qsub (double, double, double, double);
75169689Skanlong double __gcc_qmul (double, double, double, double);
76169689Skanlong double __gcc_qdiv (double, double, double, double);
77132718Skan
78169689Skan#if defined __ELF__ && defined SHARED \
79169689Skan    && (defined __powerpc64__ || !(defined __linux__ || defined __gnu_hurd__))
80169689Skan/* Provide definitions of the old symbol names to satisfy apps and
81146895Skan   shared libs built against an older libgcc.  To access the _xlq
82146895Skan   symbols an explicit version reference is needed, so these won't
83146895Skan   satisfy an unadorned reference like _xlqadd.  If dot symbols are
84146895Skan   not needed, the assembler will remove the aliases from the symbol
85146895Skan   table.  */
86146895Skan__asm__ (".symver __gcc_qadd,_xlqadd@GCC_3.4\n\t"
87169689Skan	 ".symver __gcc_qsub,_xlqsub@GCC_3.4\n\t"
88169689Skan	 ".symver __gcc_qmul,_xlqmul@GCC_3.4\n\t"
89169689Skan	 ".symver __gcc_qdiv,_xlqdiv@GCC_3.4\n\t"
90169689Skan	 ".symver .__gcc_qadd,._xlqadd@GCC_3.4\n\t"
91169689Skan	 ".symver .__gcc_qsub,._xlqsub@GCC_3.4\n\t"
92169689Skan	 ".symver .__gcc_qmul,._xlqmul@GCC_3.4\n\t"
93169689Skan	 ".symver .__gcc_qdiv,._xlqdiv@GCC_3.4");
94146895Skan#endif
95146895Skan
96132718Skantypedef union
97132718Skan{
98132718Skan  long double ldval;
99132718Skan  double dval[2];
100132718Skan} longDblUnion;
101132718Skan
102132718Skan/* Add two 'long double' values and return the result.	*/
103132718Skanlong double
104169689Skan__gcc_qadd (double a, double aa, double c, double cc)
105132718Skan{
106169689Skan  longDblUnion x;
107169689Skan  double z, q, zz, xh;
108132718Skan
109169689Skan  z = a + c;
110132718Skan
111169689Skan  if (nonfinite (z))
112132718Skan    {
113169689Skan      z = cc + aa + c + a;
114169689Skan      if (nonfinite (z))
115169689Skan	return z;
116169689Skan      x.dval[0] = z;  /* Will always be DBL_MAX.  */
117169689Skan      zz = aa + cc;
118169689Skan      if (fabs(a) > fabs(c))
119169689Skan	x.dval[1] = a - z + c + zz;
120169689Skan      else
121169689Skan	x.dval[1] = c - z + a + zz;
122132718Skan    }
123169689Skan  else
124132718Skan    {
125169689Skan      q = a - z;
126169689Skan      zz = q + c + (a - (q + z)) + aa + cc;
127132718Skan
128169689Skan      /* Keep -0 result.  */
129169689Skan      if (zz == 0.0)
130169689Skan	return z;
131132718Skan
132169689Skan      xh = z + zz;
133169689Skan      if (nonfinite (xh))
134169689Skan	return xh;
135169689Skan
136169689Skan      x.dval[0] = xh;
137169689Skan      x.dval[1] = z - xh + zz;
138132718Skan    }
139169689Skan  return x.ldval;
140132718Skan}
141132718Skan
142132718Skanlong double
143146895Skan__gcc_qsub (double a, double b, double c, double d)
144132718Skan{
145146895Skan  return __gcc_qadd (a, b, -c, -d);
146132718Skan}
147132718Skan
148169689Skan#ifdef _SOFT_FLOAT
149169689Skanstatic double fmsub (double, double, double);
150169689Skan#endif
151169689Skan
152132718Skanlong double
153146895Skan__gcc_qmul (double a, double b, double c, double d)
154132718Skan{
155132718Skan  longDblUnion z;
156169689Skan  double t, tau, u, v, w;
157132718Skan
158132718Skan  t = a * c;			/* Highest order double term.  */
159132718Skan
160169689Skan  if (unlikely (t == 0)		/* Preserve -0.  */
161169689Skan      || nonfinite (t))
162132718Skan    return t;
163132718Skan
164169689Skan  /* Sum terms of two highest orders. */
165132718Skan
166169689Skan  /* Use fused multiply-add to get low part of a * c.  */
167169689Skan#ifndef _SOFT_FLOAT
168132718Skan  asm ("fmsub %0,%1,%2,%3" : "=f"(tau) : "f"(a), "f"(c), "f"(t));
169169689Skan#else
170169689Skan  tau = fmsub (a, c, t);
171169689Skan#endif
172132718Skan  v = a*d;
173132718Skan  w = b*c;
174132718Skan  tau += v + w;	    /* Add in other second-order terms.	 */
175132718Skan  u = t + tau;
176132718Skan
177132718Skan  /* Construct long double result.  */
178169689Skan  if (nonfinite (u))
179169689Skan    return u;
180132718Skan  z.dval[0] = u;
181132718Skan  z.dval[1] = (t - u) + tau;
182132718Skan  return z.ldval;
183132718Skan}
184132718Skan
185132718Skanlong double
186146895Skan__gcc_qdiv (double a, double b, double c, double d)
187132718Skan{
188132718Skan  longDblUnion z;
189169689Skan  double s, sigma, t, tau, u, v, w;
190132718Skan
191132718Skan  t = a / c;                    /* highest order double term */
192132718Skan
193169689Skan  if (unlikely (t == 0)		/* Preserve -0.  */
194169689Skan      || nonfinite (t))
195132718Skan    return t;
196132718Skan
197132718Skan  /* Finite nonzero result requires corrections to the highest order term.  */
198132718Skan
199169689Skan  s = c * t;                    /* (s,sigma) = c*t exactly.  */
200132718Skan  w = -(-b + d * t);	/* Written to get fnmsub for speed, but not
201132718Skan			   numerically necessary.  */
202132718Skan
203132718Skan  /* Use fused multiply-add to get low part of c * t.	 */
204169689Skan#ifndef _SOFT_FLOAT
205132718Skan  asm ("fmsub %0,%1,%2,%3" : "=f"(sigma) : "f"(c), "f"(t), "f"(s));
206169689Skan#else
207169689Skan  sigma = fmsub (c, t, s);
208169689Skan#endif
209132718Skan  v = a - s;
210132718Skan
211169689Skan  tau = ((v-sigma)+w)/c;   /* Correction to t.  */
212132718Skan  u = t + tau;
213132718Skan
214169689Skan  /* Construct long double result.  */
215169689Skan  if (nonfinite (u))
216169689Skan    return u;
217132718Skan  z.dval[0] = u;
218132718Skan  z.dval[1] = (t - u) + tau;
219132718Skan  return z.ldval;
220132718Skan}
221132718Skan
222169689Skan#if defined (_SOFT_FLOAT) && defined (__LONG_DOUBLE_128__)
223169689Skan
224169689Skanlong double __gcc_qneg (double, double);
225169689Skanint __gcc_qeq (double, double, double, double);
226169689Skanint __gcc_qne (double, double, double, double);
227169689Skanint __gcc_qge (double, double, double, double);
228169689Skanint __gcc_qle (double, double, double, double);
229169689Skanint __gcc_qunord (double, double, double, double);
230169689Skanlong double __gcc_stoq (float);
231169689Skanlong double __gcc_dtoq (double);
232169689Skanfloat __gcc_qtos (double, double);
233169689Skandouble __gcc_qtod (double, double);
234169689Skanint __gcc_qtoi (double, double);
235169689Skanunsigned int __gcc_qtou (double, double);
236169689Skanlong double __gcc_itoq (int);
237169689Skanlong double __gcc_utoq (unsigned int);
238169689Skan
239169689Skanextern int __eqdf2 (double, double);
240169689Skanextern int __ledf2 (double, double);
241169689Skanextern int __gedf2 (double, double);
242169689Skanextern int __unorddf2 (double, double);
243169689Skan
244169689Skan/* Negate 'long double' value and return the result.	*/
245169689Skanlong double
246169689Skan__gcc_qneg (double a, double aa)
247169689Skan{
248169689Skan  longDblUnion x;
249169689Skan
250169689Skan  x.dval[0] = -a;
251169689Skan  x.dval[1] = -aa;
252169689Skan  return x.ldval;
253169689Skan}
254169689Skan
255169689Skan/* Compare two 'long double' values for equality.  */
256169689Skanint
257169689Skan__gcc_qeq (double a, double aa, double c, double cc)
258169689Skan{
259169689Skan  if (__eqdf2 (a, c) == 0)
260169689Skan    return __eqdf2 (aa, cc);
261169689Skan  return 1;
262169689Skan}
263169689Skan
264169689Skanstrong_alias (__gcc_qeq, __gcc_qne);
265169689Skan
266169689Skan/* Compare two 'long double' values for less than or equal.  */
267169689Skanint
268169689Skan__gcc_qle (double a, double aa, double c, double cc)
269169689Skan{
270169689Skan  if (__eqdf2 (a, c) == 0)
271169689Skan    return __ledf2 (aa, cc);
272169689Skan  return __ledf2 (a, c);
273169689Skan}
274169689Skan
275169689Skanstrong_alias (__gcc_qle, __gcc_qlt);
276169689Skan
277169689Skan/* Compare two 'long double' values for greater than or equal.  */
278169689Skanint
279169689Skan__gcc_qge (double a, double aa, double c, double cc)
280169689Skan{
281169689Skan  if (__eqdf2 (a, c) == 0)
282169689Skan    return __gedf2 (aa, cc);
283169689Skan  return __gedf2 (a, c);
284169689Skan}
285169689Skan
286169689Skanstrong_alias (__gcc_qge, __gcc_qgt);
287169689Skan
288169689Skan/* Compare two 'long double' values for unordered.  */
289169689Skanint
290169689Skan__gcc_qunord (double a, double aa, double c, double cc)
291169689Skan{
292169689Skan  if (__eqdf2 (a, c) == 0)
293169689Skan    return __unorddf2 (aa, cc);
294169689Skan  return __unorddf2 (a, c);
295169689Skan}
296169689Skan
297169689Skan/* Convert single to long double.  */
298169689Skanlong double
299169689Skan__gcc_stoq (float a)
300169689Skan{
301169689Skan  longDblUnion x;
302169689Skan
303169689Skan  x.dval[0] = (double) a;
304169689Skan  x.dval[1] = 0.0;
305169689Skan
306169689Skan  return x.ldval;
307169689Skan}
308169689Skan
309169689Skan/* Convert double to long double.  */
310169689Skanlong double
311169689Skan__gcc_dtoq (double a)
312169689Skan{
313169689Skan  longDblUnion x;
314169689Skan
315169689Skan  x.dval[0] = a;
316169689Skan  x.dval[1] = 0.0;
317169689Skan
318169689Skan  return x.ldval;
319169689Skan}
320169689Skan
321169689Skan/* Convert long double to single.  */
322169689Skanfloat
323169689Skan__gcc_qtos (double a, double aa __attribute__ ((__unused__)))
324169689Skan{
325169689Skan  return (float) a;
326169689Skan}
327169689Skan
328169689Skan/* Convert long double to double.  */
329169689Skandouble
330169689Skan__gcc_qtod (double a, double aa __attribute__ ((__unused__)))
331169689Skan{
332169689Skan  return a;
333169689Skan}
334169689Skan
335169689Skan/* Convert long double to int.  */
336169689Skanint
337169689Skan__gcc_qtoi (double a, double aa)
338169689Skan{
339169689Skan  double z = a + aa;
340169689Skan  return (int) z;
341169689Skan}
342169689Skan
343169689Skan/* Convert long double to unsigned int.  */
344169689Skanunsigned int
345169689Skan__gcc_qtou (double a, double aa)
346169689Skan{
347169689Skan  double z = a + aa;
348169689Skan  return (unsigned int) z;
349169689Skan}
350169689Skan
351169689Skan/* Convert int to long double.  */
352169689Skanlong double
353169689Skan__gcc_itoq (int a)
354169689Skan{
355169689Skan  return __gcc_dtoq ((double) a);
356169689Skan}
357169689Skan
358169689Skan/* Convert unsigned int to long double.  */
359169689Skanlong double
360169689Skan__gcc_utoq (unsigned int a)
361169689Skan{
362169689Skan  return __gcc_dtoq ((double) a);
363169689Skan}
364169689Skan
365169689Skan#include "config/soft-fp/soft-fp.h"
366169689Skan#include "config/soft-fp/double.h"
367169689Skan#include "config/soft-fp/quad.h"
368169689Skan
369169689Skan/* Compute floating point multiply-subtract with higher (quad) precision.  */
370169689Skanstatic double
371169689Skanfmsub (double a, double b, double c)
372169689Skan{
373169689Skan    FP_DECL_EX;
374169689Skan    FP_DECL_D(A);
375169689Skan    FP_DECL_D(B);
376169689Skan    FP_DECL_D(C);
377169689Skan    FP_DECL_Q(X);
378169689Skan    FP_DECL_Q(Y);
379169689Skan    FP_DECL_Q(Z);
380169689Skan    FP_DECL_Q(U);
381169689Skan    FP_DECL_Q(V);
382169689Skan    FP_DECL_D(R);
383169689Skan    double r;
384169689Skan    long double u, v, x, y, z;
385169689Skan
386169689Skan    FP_INIT_ROUNDMODE;
387169689Skan    FP_UNPACK_RAW_D (A, a);
388169689Skan    FP_UNPACK_RAW_D (B, b);
389169689Skan    FP_UNPACK_RAW_D (C, c);
390169689Skan
391169689Skan    /* Extend double to quad.  */
392169689Skan#if (2 * _FP_W_TYPE_SIZE) < _FP_FRACBITS_Q
393169689Skan    FP_EXTEND(Q,D,4,2,X,A);
394169689Skan    FP_EXTEND(Q,D,4,2,Y,B);
395169689Skan    FP_EXTEND(Q,D,4,2,Z,C);
396169689Skan#else
397169689Skan    FP_EXTEND(Q,D,2,1,X,A);
398169689Skan    FP_EXTEND(Q,D,2,1,Y,B);
399169689Skan    FP_EXTEND(Q,D,2,1,Z,C);
400132718Skan#endif
401169689Skan    FP_PACK_RAW_Q(x,X);
402169689Skan    FP_PACK_RAW_Q(y,Y);
403169689Skan    FP_PACK_RAW_Q(z,Z);
404169689Skan    FP_HANDLE_EXCEPTIONS;
405169689Skan
406169689Skan    /* Multiply.  */
407169689Skan    FP_INIT_ROUNDMODE;
408169689Skan    FP_UNPACK_Q(X,x);
409169689Skan    FP_UNPACK_Q(Y,y);
410169689Skan    FP_MUL_Q(U,X,Y);
411169689Skan    FP_PACK_Q(u,U);
412169689Skan    FP_HANDLE_EXCEPTIONS;
413169689Skan
414169689Skan    /* Subtract.  */
415169689Skan    FP_INIT_ROUNDMODE;
416169689Skan    FP_UNPACK_SEMIRAW_Q(U,u);
417169689Skan    FP_UNPACK_SEMIRAW_Q(Z,z);
418169689Skan    FP_SUB_Q(V,U,Z);
419169689Skan    FP_PACK_SEMIRAW_Q(v,V);
420169689Skan    FP_HANDLE_EXCEPTIONS;
421169689Skan
422169689Skan    /* Truncate quad to double.  */
423169689Skan    FP_INIT_ROUNDMODE;
424169689Skan    FP_UNPACK_SEMIRAW_Q(V,v);
425169689Skan#if (2 * _FP_W_TYPE_SIZE) < _FP_FRACBITS_Q
426169689Skan    FP_TRUNC(D,Q,2,4,R,V);
427169689Skan#else
428169689Skan    FP_TRUNC(D,Q,1,2,R,V);
429169689Skan#endif
430169689Skan    FP_PACK_SEMIRAW_D(r,R);
431169689Skan    FP_HANDLE_EXCEPTIONS;
432169689Skan
433169689Skan    return r;
434169689Skan}
435169689Skan
436169689Skan#endif
437169689Skan
438169689Skan#endif
439