1 /* Definitions of inline math functions implemented by the m68881/2.
2 Copyright (C) 1991,92,93,94,96,97,98,99,2000,2002 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 # if __GNUC_PREREQ (3,1)
25 /* GCC 3.1 and up have builtins that actually can be used. */
26 # define isgreater(x, y) __builtin_isgreater (x, y)
27 # define isgreaterequal(x, y) __builtin_isgreaterequal (x, y)
28 # define isless(x, y) __builtin_isless (x, y)
29 # define islessequal(x, y) __builtin_islessequal (x, y)
30 # define islessgreater(x, y) __builtin_islessgreater (x, y)
31 # define isunordered(x, y) __builtin_isunordered (x, y)
33 /* ISO C99 defines some macros to perform unordered comparisons. The
34 m68k FPU supports this with special opcodes and we should use them.
35 These must not be inline functions since we have to be able to handle
36 all floating-point types. */
37 # define isgreater(x, y) \
40 __asm__ ("fcmp%.x %2,%1; fsogt %0" \
41 : "=dm" (__result) : "f" (x), "f" (y)); \
44 # define isgreaterequal(x, y) \
47 __asm__ ("fcmp%.x %2,%1; fsoge %0" \
48 : "=dm" (__result) : "f" (x), "f" (y)); \
51 # define isless(x, y) \
54 __asm__ ("fcmp%.x %2,%1; fsolt %0" \
55 : "=dm" (__result) : "f" (x), "f" (y)); \
58 # define islessequal(x, y) \
61 __asm__ ("fcmp%.x %2,%1; fsole %0" \
62 : "=dm" (__result) : "f" (x), "f" (y)); \
65 # define islessgreater(x, y) \
68 __asm__ ("fcmp%.x %2,%1; fsogl %0" \
69 : "=dm" (__result) : "f" (x), "f" (y)); \
72 # define isunordered(x, y) \
75 __asm__ ("fcmp%.x %2,%1; fsun %0" \
76 : "=dm" (__result) : "f" (x), "f" (y)); \
82 #if (!defined __NO_MATH_INLINES && defined __OPTIMIZE__) \
83 || defined __LIBC_INTERNAL_MATH_INLINES
85 #ifdef __LIBC_INTERNAL_MATH_INLINES
86 /* This is used when defining the functions themselves. Define them with
87 __ names, and with `static inline' instead of `extern inline' so the
88 bodies will always be used, never an external function call. */
89 # define __m81_u(x) __CONCAT(__,x)
90 # define __m81_inline static __inline
94 # define __m81_inline __inline
96 # define __m81_inline extern __inline
98 # define __M81_MATH_INLINES 1
101 /* Define a const math function. */
102 #define __m81_defun(rettype, func, args) \
103 __m81_inline rettype __attribute__((__const__)) \
106 /* Define the three variants of a math function that has a direct
107 implementation in the m68k fpu. FUNC is the name for C (which will be
108 suffixed with f and l for the float and long double version, resp). OP
109 is the name of the fpu operation (without leading f). */
111 #if defined __USE_MISC || defined __USE_ISOC99
112 # define __inline_mathop(func, op) \
113 __inline_mathop1(double, func, op) \
114 __inline_mathop1(float, __CONCAT(func,f), op) \
115 __inline_mathop1(long double, __CONCAT(func,l), op)
117 # define __inline_mathop(func, op) \
118 __inline_mathop1(double, func, op)
121 #define __inline_mathop1(float_type,func, op) \
122 __m81_defun (float_type, func, (float_type __mathop_x)) __THROW \
124 float_type __result; \
125 __asm("f" __STRING(op) "%.x %1, %0" : "=f" (__result) : "f" (__mathop_x));\
129 __inline_mathop(__atan
, atan
)
130 __inline_mathop(__cos
, cos
)
131 __inline_mathop(__sin
, sin
)
132 __inline_mathop(__tan
, tan
)
133 __inline_mathop(__tanh
, tanh
)
134 __inline_mathop(__fabs
, abs
)
136 #if defined __USE_MISC || defined __USE_XOPEN_EXTENDED || defined __USE_ISOC99
137 __inline_mathop(__rint
, int)
138 __inline_mathop(__expm1
, etoxm1
)
139 __inline_mathop(__log1p
, lognp1
)
143 __inline_mathop(__significand
, getman
)
147 __inline_mathop(__trunc
, intrz
)
150 #if !defined __NO_MATH_INLINES && defined __OPTIMIZE__
152 __inline_mathop(atan
, atan
)
153 __inline_mathop(cos
, cos
)
154 __inline_mathop(sin
, sin
)
155 __inline_mathop(tan
, tan
)
156 __inline_mathop(tanh
, tanh
)
158 # if defined __USE_MISC || defined __USE_XOPEN_EXTENDED || defined __USE_ISOC99
159 __inline_mathop(rint
, int)
160 __inline_mathop(expm1
, etoxm1
)
161 __inline_mathop(log1p
, lognp1
)
165 __inline_mathop(significand
, getman
)
169 __inline_mathop(trunc
, intrz
)
172 #endif /* !__NO_MATH_INLINES && __OPTIMIZE__ */
174 /* This macro contains the definition for the rest of the inline
175 functions, using FLOAT_TYPE as the domain type and S as the suffix
176 for the function names. */
178 #define __inline_functions(float_type, s) \
179 __m81_inline float_type \
180 __m81_u(__CONCAT(__frexp,s))(float_type __value, int *__expptr) __THROW \
182 float_type __mantissa, __exponent; \
184 unsigned long __fpsr; \
185 __asm("ftst%.x %1\n" \
186 "fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value)); \
187 if (__fpsr & (7 << 24)) \
189 /* Not finite or zero. */ \
193 __asm("fgetexp%.x %1, %0" : "=f" (__exponent) : "f" (__value)); \
194 __iexponent = (int) __exponent + 1; \
195 *__expptr = __iexponent; \
196 __asm("fscale%.l %2, %0" : "=f" (__mantissa) \
197 : "0" (__value), "dmi" (-__iexponent)); \
201 __m81_defun (float_type, __CONCAT(__floor,s), (float_type __x)) __THROW \
203 float_type __result; \
204 unsigned long int __ctrl_reg; \
205 __asm __volatile__ ("fmove%.l %!, %0" : "=dm" (__ctrl_reg)); \
206 /* Set rounding towards negative infinity. */ \
207 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
208 : "dmi" ((__ctrl_reg & ~0x10) | 0x20)); \
209 /* Convert X to an integer, using -Inf rounding. */ \
210 __asm __volatile__ ("fint%.x %1, %0" : "=f" (__result) : "f" (__x)); \
211 /* Restore the previous rounding mode. */ \
212 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
213 : "dmi" (__ctrl_reg)); \
217 __m81_defun (float_type, __CONCAT(__ceil,s), (float_type __x)) __THROW \
219 float_type __result; \
220 unsigned long int __ctrl_reg; \
221 __asm __volatile__ ("fmove%.l %!, %0" : "=dm" (__ctrl_reg)); \
222 /* Set rounding towards positive infinity. */ \
223 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
224 : "dmi" (__ctrl_reg | 0x30)); \
225 /* Convert X to an integer, using +Inf rounding. */ \
226 __asm __volatile__ ("fint%.x %1, %0" : "=f" (__result) : "f" (__x)); \
227 /* Restore the previous rounding mode. */ \
228 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
229 : "dmi" (__ctrl_reg)); \
233 __inline_functions(double,)
234 #if defined __USE_MISC || defined __USE_ISOC99
235 __inline_functions(float,f
)
236 __inline_functions(long double,l
)
238 #undef __inline_functions
242 # define __inline_functions(float_type, s) \
243 __m81_defun (int, __CONCAT(__isinf,s), (float_type __value)) __THROW \
245 /* There is no branch-condition for infinity, \
246 so we must extract and examine the condition codes manually. */ \
247 unsigned long int __fpsr; \
248 __asm("ftst%.x %1\n" \
249 "fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value)); \
250 return (__fpsr & (2 << 24)) ? (__fpsr & (8 << 24) ? -1 : 1) : 0; \
253 __m81_defun (int, __CONCAT(__finite,s), (float_type __value)) __THROW \
255 /* There is no branch-condition for infinity, so we must extract and \
256 examine the condition codes manually. */ \
257 unsigned long int __fpsr; \
258 __asm ("ftst%.x %1\n" \
259 "fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value)); \
260 return (__fpsr & (3 << 24)) == 0; \
263 __m81_defun (float_type, __CONCAT(__scalbn,s), \
264 (float_type __x, int __n)) __THROW \
266 float_type __result; \
267 __asm ("fscale%.l %1, %0" : "=f" (__result) : "dmi" (__n), "0" (__x)); \
271 __inline_functions(double,)
272 __inline_functions(float,f
)
273 __inline_functions(long double,l
)
274 # undef __inline_functions
276 #endif /* Use misc. */
278 #if defined __USE_MISC || defined __USE_XOPEN
280 # define __inline_functions(float_type, s) \
281 __m81_defun (int, __CONCAT(__isnan,s), (float_type __value)) __THROW \
284 __asm("ftst%.x %1\n" \
285 "fsun %0" : "=dm" (__result) : "f" (__value)); \
289 __inline_functions(double,)
291 __inline_functions(float,f
)
292 __inline_functions(long double,l
)
294 # undef __inline_functions
300 # define __inline_functions(float_type, s) \
301 __m81_defun (int, __CONCAT(__signbit,s), (float_type __value)) __THROW \
303 /* There is no branch-condition for the sign bit, so we must extract \
304 and examine the condition codes manually. */ \
305 unsigned long int __fpsr; \
306 __asm ("ftst%.x %1\n" \
307 "fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value)); \
308 return (__fpsr >> 27) & 1; \
311 __m81_defun (float_type, __CONCAT(__scalbln,s), \
312 (float_type __x, long int __n)) __THROW \
314 return __CONCAT(__scalbn,s) (__x, __n); \
317 __m81_defun (float_type, __CONCAT(__nearbyint,s), (float_type __x)) __THROW \
319 float_type __result; \
320 unsigned long int __ctrl_reg; \
321 __asm __volatile__ ("fmove%.l %!, %0" : "=dm" (__ctrl_reg)); \
322 /* Temporarily disable the inexact exception. */ \
323 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
324 : "dmi" (__ctrl_reg & ~0x200)); \
325 __asm __volatile__ ("fint%.x %1, %0" : "=f" (__result) : "f" (__x)); \
326 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
327 : "dmi" (__ctrl_reg)); \
331 __m81_defun (long int, __CONCAT(__lrint,s), (float_type __x)) __THROW \
334 __asm ("fmove%.l %1, %0" : "=dm" (__result) : "f" (__x)); \
338 __m81_inline float_type \
339 __m81_u(__CONCAT(__fma,s))(float_type __x, float_type __y, \
340 float_type __z) __THROW \
342 return (__x * __y) + __z; \
345 __inline_functions (double,)
346 __inline_functions (float,f
)
347 __inline_functions (long double,l
)
348 # undef __inline_functions
350 #endif /* Use ISO C9x */
354 # define __inline_functions(float_type, s) \
356 __m81_u(__CONCAT(__sincos,s))(float_type __x, float_type *__sinx, \
357 float_type *__cosx) __THROW \
359 __asm ("fsincos%.x %2,%1:%0" \
360 : "=f" (*__sinx), "=f" (*__cosx) : "f" (__x)); \
363 __inline_functions (double,)
364 __inline_functions (float,f
)
365 __inline_functions (long double,l
)
366 # undef __inline_functions
370 #if !defined __NO_MATH_INLINES && defined __OPTIMIZE__
372 /* Define inline versions of the user visible functions. */
374 /* Note that there must be no whitespace before the argument passed for
375 NAME, to make token pasting work correctly with -traditional. */
376 # define __inline_forward_c(rettype, name, args1, args2) \
377 extern __inline rettype __attribute__((__const__)) \
380 return __CONCAT(__,name) args2; \
383 # define __inline_forward(rettype, name, args1, args2) \
384 extern __inline rettype name args1 __THROW \
386 return __CONCAT(__,name) args2; \
389 __inline_forward(double,frexp
, (double __value
, int *__expptr
),
391 __inline_forward_c(double,floor
, (double __x
), (__x
))
392 __inline_forward_c(double,ceil
, (double __x
), (__x
))
394 # ifndef __USE_ISOC99 /* Conflict with macro of same name. */
395 __inline_forward_c(int,isinf
, (double __value
), (__value
))
397 __inline_forward_c(int,finite
, (double __value
), (__value
))
398 __inline_forward_c(double,scalbn
, (double __x
, int __n
), (__x
, __n
))
400 # if defined __USE_MISC || defined __USE_XOPEN
401 # ifndef __USE_ISOC99 /* Conflict with macro of same name. */
402 __inline_forward_c(int,isnan
, (double __value
), (__value
))
406 __inline_forward_c(double,scalbln
, (double __x
, long int __n
), (__x
, __n
))
407 __inline_forward_c(double,nearbyint
, (double __value
), (__value
))
408 __inline_forward_c(long int,lrint
, (double __value
), (__value
))
409 __inline_forward_c(double,fma
, (double __x
, double __y
, double __z
),
413 __inline_forward(void,sincos
, (double __x
, double *__sinx
, double *__cosx
),
414 (__x
, __sinx
, __cosx
))
417 # if defined __USE_MISC || defined __USE_ISOC99
419 __inline_forward(float,frexpf
, (float __value
, int *__expptr
),
421 __inline_forward_c(float,floorf
, (float __x
), (__x
))
422 __inline_forward_c(float,ceilf
, (float __x
), (__x
))
424 __inline_forward_c(int,isinff
, (float __value
), (__value
))
425 __inline_forward_c(int,finitef
, (float __value
), (__value
))
426 __inline_forward_c(float,scalbnf
, (float __x
, int __n
), (__x
, __n
))
427 __inline_forward_c(int,isnanf
, (float __value
), (__value
))
430 __inline_forward_c(float,scalblnf
, (float __x
, long int __n
), (__x
, __n
))
431 __inline_forward_c(float,nearbyintf
, (float __value
), (__value
))
432 __inline_forward_c(long int,lrintf
, (float __value
), (__value
))
433 __inline_forward_c(float,fmaf
, (float __x
, float __y
, float __z
),
437 __inline_forward(void,sincosf
, (float __x
, float *__sinx
, float *__cosx
),
438 (__x
, __sinx
, __cosx
))
441 __inline_forward(long double,frexpl
, (long double __value
, int *__expptr
),
443 __inline_forward_c(long double,floorl
, (long double __x
), (__x
))
444 __inline_forward_c(long double,ceill
, (long double __x
), (__x
))
446 __inline_forward_c(int,isinfl
, (long double __value
), (__value
))
447 __inline_forward_c(int,finitel
, (long double __value
), (__value
))
448 __inline_forward_c(long double,scalbnl
, (long double __x
, int __n
), (__x
, __n
))
449 __inline_forward_c(int,isnanl
, (long double __value
), (__value
))
452 __inline_forward_c(long double,scalblnl
, (long double __x
, long int __n
),
454 __inline_forward_c(long double,nearbyintl
, (long double __value
), (__value
))
455 __inline_forward_c(long int,lrintl
, (long double __value
), (__value
))
456 __inline_forward_c(long double,fmal
,
457 (long double __x
, long double __y
, long double __z
),
461 __inline_forward(void,sincosl
,
462 (long double __x
, long double *__sinx
, long double *__cosx
),
463 (__x
, __sinx
, __cosx
))
466 #endif /* Use misc or ISO C99 */
468 #undef __inline_forward
469 #undef __inline_forward_c
471 #endif /* !__NO_MATH_INLINES && __OPTIMIZE__ */