(fenv_t): Add member to hold fpiar value, to match spirit of the
[kopensolaris-gnu/glibc.git] / sysdeps / m68k / fpu / bits / mathinline.h
1 /* Definitions of inline math functions implemented by the m68881/2.
2    Copyright (C) 1991, 92, 93, 94, 96, 97 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #ifdef  __GNUC__
21
22 #ifdef __USE_ISOC9X
23
24 /* ISO C 9X defines some macros to perform unordered comparisons.  The
25    m68k FPU supports this with special opcodes and we should use them.
26    These must not be inline functions since we have to be able to handle
27    all floating-point types.  */
28 # define isgreater(x, y)                                        \
29    __extension__                                        \
30    ({ char __result;                                    \
31       __asm__ ("fcmp%.x %2,%1; fsogt %0"                \
32                : "=dm" (__result) : "f" (x), "f" (y));  \
33       (int) __result; })
34
35 # define isgreaterequal(x, y)                           \
36    __extension__                                        \
37    ({ char __result;                                    \
38       __asm__ ("fcmp%.x %2,%1; fsoge %0"                \
39                : "=dm" (__result) : "f" (x), "f" (y));  \
40       (int) __result; })
41
42 # define isless(x, y)                                   \
43    __extension__                                        \
44    ({ char __result;                                    \
45       __asm__ ("fcmp%.x %2,%1; fsolt %0"                \
46                : "=dm" (__result) : "f" (x), "f" (y));  \
47       (int) __result; })
48
49 # define islessequal(x, y)                              \
50    __extension__                                        \
51    ({ char __result;                                    \
52       __asm__ ("fcmp%.x %2,%1; fsole %0"                \
53                : "=dm" (__result) : "f" (x), "f" (y));  \
54       (int) __result; })
55
56 # define islessgreater(x, y)                            \
57    __extension__                                        \
58    ({ char __result;                                    \
59       __asm__ ("fcmp%.x %2,%1; fsogl %0"                \
60                : "=dm" (__result) : "f" (x), "f" (y));  \
61       (int) __result; })
62
63 # define isunordered(x, y)                              \
64    __extension__                                        \
65    ({ char __result;                                    \
66       __asm__ ("fcmp%.x %2,%1; fsun %0"                 \
67                : "=dm" (__result) : "f" (x), "f" (y));  \
68       (int) __result; })
69 #endif
70
71
72 #if (!defined __NO_MATH_INLINES && defined __OPTIMIZE__) \
73     || defined __LIBC_INTERNAL_MATH_INLINES
74
75 #ifdef  __LIBC_INTERNAL_MATH_INLINES
76 /* This is used when defining the functions themselves.  Define them with
77    __ names, and with `static inline' instead of `extern inline' so the
78    bodies will always be used, never an external function call.  */
79 # define __m81_u(x)             __CONCAT(__,x)
80 # define __m81_inline           static __inline
81 #else
82 # define __m81_u(x)             x
83 # ifdef __cplusplus
84 #  define __m81_inline          __inline
85 # else
86 #  define __m81_inline          extern __inline
87 # endif
88 # define __M81_MATH_INLINES     1
89 #endif
90
91 /* Define a const math function.  */
92 #define __m81_defun(rettype, func, args)                                      \
93   __m81_inline rettype __attribute__((__const__))                             \
94   __m81_u(func) args
95
96 /* Define the three variants of a math function that has a direct
97    implementation in the m68k fpu.  FUNC is the name for C (which will be
98    suffixed with f and l for the float and long double version, resp).  OP
99    is the name of the fpu operation (without leading f).  */
100
101 #if defined __USE_MISC || defined __USE_ISOC9X
102 # define __inline_mathop(func, op)                      \
103   __inline_mathop1(double, func, op)                    \
104   __inline_mathop1(float, __CONCAT(func,f), op)         \
105   __inline_mathop1(long double, __CONCAT(func,l), op)
106 #else
107 # define __inline_mathop(func, op)                      \
108   __inline_mathop1(double, func, op)
109 #endif
110
111 #define __inline_mathop1(float_type,func, op)                                 \
112   __m81_defun (float_type, func, (float_type __mathop_x))                     \
113   {                                                                           \
114     float_type __result;                                                      \
115     __asm("f" __STRING(op) "%.x %1, %0" : "=f" (__result) : "f" (__mathop_x));\
116     return __result;                                                          \
117   }
118
119 #ifdef __LIBC_INTERNAL_MATH_INLINES
120 /* ieee style elementary functions */
121 /* These are internal to the implementation of libm.  */
122 __inline_mathop(__ieee754_acos, acos)
123 __inline_mathop(__ieee754_asin, asin)
124 __inline_mathop(__ieee754_cosh, cosh)
125 __inline_mathop(__ieee754_sinh, sinh)
126 __inline_mathop(__ieee754_exp, etox)
127 __inline_mathop(__ieee754_exp2, twotox)
128 __inline_mathop(__ieee754_log10, log10)
129 __inline_mathop(__ieee754_log, logn)
130 __inline_mathop(__ieee754_sqrt, sqrt)
131 __inline_mathop(__ieee754_atanh, atanh)
132 #endif
133
134 __inline_mathop(__atan, atan)
135 __inline_mathop(__cos, cos)
136 __inline_mathop(__sin, sin)
137 __inline_mathop(__tan, tan)
138 __inline_mathop(__tanh, tanh)
139 __inline_mathop(__fabs, abs)
140
141 __inline_mathop(__rint, int)
142 __inline_mathop(__expm1, etoxm1)
143 __inline_mathop(__log1p, lognp1)
144 __inline_mathop(__significand, getman)
145
146 __inline_mathop(__log2, log2)
147 __inline_mathop(__trunc, intrz)
148
149 #if !defined __NO_MATH_INLINES && defined __OPTIMIZE__
150
151 __inline_mathop(atan, atan)
152 __inline_mathop(cos, cos)
153 __inline_mathop(sin, sin)
154 __inline_mathop(tan, tan)
155 __inline_mathop(tanh, tanh)
156
157 # if defined __USE_MISC || defined __USE_XOPEN_EXTENDED || defined __USE_ISOC9X
158 __inline_mathop(rint, int)
159 __inline_mathop(expm1, etoxm1)
160 __inline_mathop(log1p, lognp1)
161 # endif
162
163 # ifdef __USE_MISC
164 __inline_mathop(significand, getman)
165 # endif
166
167 # ifdef __USE_ISOC9X
168 __inline_mathop(log2, log2)
169 __inline_mathop(exp2, twotox)
170 __inline_mathop(trunc, intrz)
171 # endif
172
173 #endif /* !__NO_MATH_INLINES && __OPTIMIZE__ */
174
175 /* This macro contains the definition for the rest of the inline
176    functions, using __FLOAT_TYPE as the domain type and __S as the suffix
177    for the function names.  */
178
179 #ifdef __LIBC_INTERNAL_MATH_INLINES
180 /* Internally used functions.  */
181 # define __internal_inline_functions(float_type, s)                          \
182 __m81_defun (float_type, __CONCAT(__ieee754_remainder,s),                    \
183              (float_type __x, float_type __y))                               \
184 {                                                                            \
185   float_type __result;                                                       \
186   __asm("frem%.x %1, %0" : "=f" (__result) : "f" (__y), "0" (__x));          \
187   return __result;                                                           \
188 }                                                                            \
189                                                                              \
190 __m81_defun (float_type, __CONCAT(__ieee754_fmod,s),                         \
191              (float_type __x, float_type __y))                               \
192 {                                                                            \
193   float_type __result;                                                       \
194   __asm("fmod%.x %1, %0" : "=f" (__result) : "f" (__y), "0" (__x));          \
195   return __result;                                                           \
196 }
197
198 __internal_inline_functions (double,)
199 __internal_inline_functions (float,f)
200 __internal_inline_functions (long double,l)
201 # undef __internal_inline_functions
202
203 /* Get the m68881 condition codes, to quickly check multiple conditions.  */
204 static __inline__ unsigned long
205 __m81_test (long double __val)
206 {
207   unsigned long __fpsr;
208   __asm ("ftst%.x %1; fmove%.l %/fpsr,%0" : "=dm" (__fpsr) : "f" (__val));
209   return __fpsr;
210 }
211
212 /* Bit values returned by __m81_test.  */
213 # define __M81_COND_NAN (1 << 24)
214 # define __M81_COND_INF (2 << 24)
215 # define __M81_COND_ZERO (4 << 24)
216 # define __M81_COND_NEG (8 << 24)
217
218 #endif /* __LIBC_INTENRAL_MATH_INLINES */
219
220 /* The rest of the functions are available to the user.  */
221
222 #define __inline_functions(float_type, s)                                 \
223 __m81_inline float_type                                                   \
224 __m81_u(__CONCAT(__frexp,s))(float_type __value, int *__expptr)           \
225 {                                                                         \
226   float_type __mantissa, __exponent;                                      \
227   int __iexponent;                                                        \
228   unsigned long __fpsr;                                                   \
229   __asm("ftst%.x %1\n"                                                    \
230         "fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value));          \
231   if (__fpsr & (7 << 24))                                                 \
232     {                                                                     \
233       /* Not finite or zero.  */                                          \
234       *__expptr = 0;                                                      \
235       return __value;                                                     \
236     }                                                                     \
237   __asm("fgetexp%.x %1, %0" : "=f" (__exponent) : "f" (__value));         \
238   __iexponent = (int) __exponent + 1;                                     \
239   *__expptr = __iexponent;                                                \
240   __asm("fscale%.l %2, %0" : "=f" (__mantissa)                            \
241         : "0" (__value), "dmi" (-__iexponent));                           \
242   return __mantissa;                                                      \
243 }                                                                         \
244                                                                           \
245 __m81_defun (float_type, __CONCAT(__floor,s), (float_type __x))           \
246 {                                                                         \
247   float_type __result;                                                    \
248   unsigned long int __ctrl_reg;                                           \
249   __asm __volatile__ ("fmove%.l %!, %0" : "=dm" (__ctrl_reg));            \
250   /* Set rounding towards negative infinity.  */                          \
251   __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs.  */              \
252                       : "dmi" ((__ctrl_reg & ~0x10) | 0x20));             \
253   /* Convert X to an integer, using -Inf rounding.  */                    \
254   __asm __volatile__ ("fint%.x %1, %0" : "=f" (__result) : "f" (__x));    \
255   /* Restore the previous rounding mode.  */                              \
256   __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs.  */              \
257                       : "dmi" (__ctrl_reg));                              \
258   return __result;                                                        \
259 }                                                                         \
260                                                                           \
261 __m81_defun (float_type, __CONCAT(__ceil,s), (float_type __x))            \
262 {                                                                         \
263   float_type __result;                                                    \
264   unsigned long int __ctrl_reg;                                           \
265   __asm __volatile__ ("fmove%.l %!, %0" : "=dm" (__ctrl_reg));            \
266   /* Set rounding towards positive infinity.  */                          \
267   __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs.  */              \
268                       : "dmi" (__ctrl_reg | 0x30));                       \
269   /* Convert X to an integer, using +Inf rounding.  */                    \
270   __asm __volatile__ ("fint%.x %1, %0" : "=f" (__result) : "f" (__x));    \
271   /* Restore the previous rounding mode.  */                              \
272   __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs.  */              \
273                       : "dmi" (__ctrl_reg));                              \
274   return __result;                                                        \
275 }                                                                         \
276                                                                           \
277 __m81_defun (int, __CONCAT(__isinf,s), (float_type __value))              \
278 {                                                                         \
279   /* There is no branch-condition for infinity,                           \
280      so we must extract and examine the condition codes manually.  */     \
281   unsigned long int __fpsr;                                               \
282   __asm("ftst%.x %1\n"                                                    \
283         "fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value));          \
284   return (__fpsr & (2 << 24)) ? (__fpsr & (8 << 24) ? -1 : 1) : 0;        \
285 }                                                                         \
286                                                                           \
287 __m81_defun (int, __CONCAT(__isnan,s), (float_type __value))              \
288 {                                                                         \
289   char __result;                                                          \
290   __asm("ftst%.x %1\n"                                                    \
291         "fsun %0" : "=dm" (__result) : "f" (__value));                    \
292   return __result;                                                        \
293 }                                                                         \
294                                                                           \
295 __m81_defun (int, __CONCAT(__finite,s), (float_type __value))             \
296 {                                                                         \
297   /* There is no branch-condition for infinity, so we must extract and    \
298      examine the condition codes manually.  */                            \
299   unsigned long int __fpsr;                                               \
300   __asm ("ftst%.x %1\n"                                                   \
301          "fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value));         \
302   return (__fpsr & (3 << 24)) == 0;                                       \
303 }                                                                         \
304                                                                           \
305 __m81_defun (int, __CONCAT(__signbit,s), (float_type __value))            \
306 {                                                                         \
307   /* There is no branch-condition for the sign bit, so we must extract    \
308      and examine the condition codes manually.  */                        \
309   unsigned long int __fpsr;                                               \
310   __asm ("ftst%.x %1\n"                                                   \
311          "fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value));         \
312   return (__fpsr >> 27) & 1;                                              \
313 }                                                                         \
314                                                                           \
315 __m81_defun (float_type, __CONCAT(__scalbn,s),                            \
316              (float_type __x, int __n))                                   \
317 {                                                                         \
318   float_type __result;                                                    \
319   __asm ("fscale%.l %1, %0" : "=f" (__result) : "dmi" (__n), "0" (__x));  \
320   return __result;                                                        \
321 }                                                                         \
322                                                                           \
323 __m81_defun (float_type, __CONCAT(__scalbln,s),                           \
324              (float_type __x, long int __n))                              \
325 {                                                                         \
326   return __CONCAT(__scalbn,s) (__x, __n);                                 \
327 }                                                                         \
328                                                                           \
329 __m81_defun (float_type, __CONCAT(__nearbyint,s), (float_type __x))       \
330 {                                                                         \
331   float_type __result;                                                    \
332   unsigned long int __ctrl_reg;                                           \
333   __asm __volatile__ ("fmove%.l %!, %0" : "=dm" (__ctrl_reg));            \
334   /* Temporarily disable the inexact exception.  */                       \
335   __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs.  */              \
336                       : "dmi" (__ctrl_reg & ~0x200));                     \
337   __asm __volatile__ ("fint%.x %1, %0" : "=f" (__result) : "f" (__x));    \
338   __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs.  */              \
339                       : "dmi" (__ctrl_reg));                              \
340   return __result;                                                        \
341 }                                                                         \
342                                                                           \
343 __m81_defun (long int, __CONCAT(__lrint,s), (float_type __x))             \
344 {                                                                         \
345   long int __result;                                                      \
346   __asm ("fmove%.l %1, %0" : "=dm" (__result) : "f" (__x));               \
347   return __result;                                                        \
348 }                                                                         \
349                                                                           \
350 __m81_inline void                                                         \
351 __m81_u(__CONCAT(__sincos,s))(float_type __x, float_type *__sinx,         \
352                               float_type *__cosx)                         \
353 {                                                                         \
354   __asm ("fsincos%.x %2,%1:%0"                                            \
355          : "=f" (*__sinx), "=f" (*__cosx) : "f" (__x));                   \
356 }                                                                         \
357                                                                           \
358 __m81_inline float_type                                                   \
359 __m81_u(__CONCAT(__fma,s))(float_type __x, float_type __y,                \
360                            float_type __z)                                \
361 {                                                                         \
362   return (__x * __y) + __z;                                               \
363 }
364
365 /* This defines the three variants of the inline functions.  */
366 __inline_functions (double,)
367 __inline_functions (float,f)
368 __inline_functions (long double,l)
369 #undef __inline_functions
370
371 #if !defined __NO_MATH_INLINES && defined __OPTIMIZE__
372
373 /* Define inline versions of the user visible functions.  */
374
375 /* Note that there must be no whitespace before the argument passed for
376    NAME, to make token pasting work correctly with -traditional.  */
377 # define __inline_forward_c(rettype, name, args1, args2)        \
378 extern __inline rettype __attribute__((__const__))      \
379 name args1                                              \
380 {                                                       \
381   return __CONCAT(__,name) args2;                       \
382 }
383
384 # define __inline_forward(rettype, name, args1, args2)  \
385 extern __inline rettype name args1                      \
386 {                                                       \
387   return __CONCAT(__,name) args2;                       \
388 }
389
390 __inline_forward(double,frexp, (double __value, int *__expptr),
391                  (__value, __expptr))
392 __inline_forward_c(double,floor, (double __x), (__x))
393 __inline_forward_c(double,ceil, (double __x), (__x))
394 # ifdef __USE_MISC
395 __inline_forward_c(int,isinf, (double __value), (__value))
396 __inline_forward_c(int,finite, (double __value), (__value))
397 __inline_forward_c(double,scalbn, (double __x, int __n), (__x, __n))
398 __inline_forward_c(double,scalbln, (double __x, long int __n), (__x, __n))
399 # endif
400 # if defined __USE_MISC || defined __USE_XOPEN
401 #  ifndef __USE_ISOC9X /* Conflict with macro of same name.  */
402 __inline_forward_c(int,isnan, (double __value), (__value))
403 #  endif
404 # endif
405 # ifdef __USE_ISOC9X
406 __inline_forward_c(double,nearbyint, (double __value), (__value))
407 __inline_forward_c(long int,lrint, (double __value), (__value))
408 __inline_forward_c(double,fma, (double __x, double __y, double __z),
409                    (__x, __y, __z))
410 # endif
411 # ifdef __USE_GNU
412 __inline_forward(void,sincos, (double __x, double *__sinx, double *__cosx),
413                  (__x, __sinx, __cosx))
414 # endif
415
416 # if defined __USE_MISC || defined __USE_ISOC9X
417
418 __inline_forward(float,frexpf, (float __value, int *__expptr),
419                  (__value, __expptr))
420 __inline_forward_c(float,floorf, (float __x), (__x))
421 __inline_forward_c(float,ceilf, (float __x), (__x))
422 #  ifdef __USE_MISC
423 __inline_forward_c(int,isinff, (float __value), (__value))
424 __inline_forward_c(int,finitef, (float __value), (__value))
425 __inline_forward_c(float,scalbnf, (float __x, int __n), (__x, __n))
426 __inline_forward_c(float,scalblnf, (float __x, long int __n), (__x, __n))
427 __inline_forward_c(int,isnanf, (float __value), (__value))
428 #  endif
429 # ifdef __USE_ISOC9X
430 __inline_forward_c(float,nearbyintf, (float __value), (__value))
431 __inline_forward_c(long int,lrintf, (float __value), (__value))
432 __inline_forward_c(float,fmaf, (float __x, float __y, float __z),
433                    (__x, __y, __z))
434 # endif
435 # ifdef __USE_GNU
436 __inline_forward(void,sincosf, (float __x, float *__sinx, float *__cosx),
437                  (__x, __sinx, __cosx))
438 # endif
439
440 __inline_forward(long double,frexpl, (long double __value, int *__expptr),
441                  (__value, __expptr))
442 __inline_forward_c(long double,floorl, (long double __x), (__x))
443 __inline_forward_c(long double,ceill, (long double __x), (__x))
444 # ifdef __USE_MISC
445 __inline_forward_c(int,isinfl, (long double __value), (__value))
446 __inline_forward_c(int,finitel, (long double __value), (__value))
447 __inline_forward_c(long double,scalbnl, (long double __x, int __n), (__x, __n))
448 __inline_forward_c(long double,scalblnl, (long double __x, long int __n),
449                    (__x, __n))
450 __inline_forward_c(int,isnanl, (long double __value), (__value))
451 # endif
452 # ifdef __USE_ISOC9X
453 __inline_forward_c(long double,nearbyintl, (long double __value), (__value))
454 __inline_forward_c(long int,lrintl, (long double __value), (__value))
455 __inline_forward_c(long double,fmal,
456                    (long double __x, long double __y, long double __z),
457                    (__x, __y, __z))
458 # endif
459 # ifdef __USE_GNU
460 __inline_forward(void,sincosl,
461                  (long double __x, long double *__sinx, long double *__cosx),
462                  (__x, __sinx, __cosx))
463 # endif
464
465 #endif /* Use misc or ISO C9X */
466
467 #undef __inline_forward
468 #undef __inline_forward_c
469
470 #endif /* !__NO_MATH_INLINES && __OPTIMIZE__ */
471
472 #endif
473 #endif  /* GCC.  */