1 /* Definitions of inline math functions implemented by the m68881/2.
2 Copyright (C) 1991,92,93,94,96,97,98,99,2000,2002, 2003, 2004
3 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 /* GCC 3.1 and up have builtins that actually can be used. */
25 # if !__GNUC_PREREQ (3,1)
26 /* ISO C99 defines some macros to perform unordered comparisons. The
27 m68k FPU supports this with special opcodes and we should use them.
28 These must not be inline functions since we have to be able to handle
29 all floating-point types. */
31 # undef isgreaterequal
36 # define isgreater(x, y) \
39 __asm__ ("fcmp%.x %2,%1; fsogt %0" \
40 : "=dm" (__result) : "f" (x), "f" (y)); \
43 # define isgreaterequal(x, y) \
46 __asm__ ("fcmp%.x %2,%1; fsoge %0" \
47 : "=dm" (__result) : "f" (x), "f" (y)); \
50 # define isless(x, y) \
53 __asm__ ("fcmp%.x %2,%1; fsolt %0" \
54 : "=dm" (__result) : "f" (x), "f" (y)); \
57 # define islessequal(x, y) \
60 __asm__ ("fcmp%.x %2,%1; fsole %0" \
61 : "=dm" (__result) : "f" (x), "f" (y)); \
64 # define islessgreater(x, y) \
67 __asm__ ("fcmp%.x %2,%1; fsogl %0" \
68 : "=dm" (__result) : "f" (x), "f" (y)); \
71 # define isunordered(x, y) \
74 __asm__ ("fcmp%.x %2,%1; fsun %0" \
75 : "=dm" (__result) : "f" (x), "f" (y)); \
81 #if (!defined __NO_MATH_INLINES && defined __OPTIMIZE__) \
82 || defined __LIBC_INTERNAL_MATH_INLINES
84 #ifdef __LIBC_INTERNAL_MATH_INLINES
85 /* This is used when defining the functions themselves. Define them with
86 __ names, and with `static inline' instead of `extern inline' so the
87 bodies will always be used, never an external function call. */
88 # define __m81_u(x) __CONCAT(__,x)
89 # define __m81_inline static __inline
93 # define __m81_inline __inline
95 # define __m81_inline extern __inline
97 # define __M81_MATH_INLINES 1
100 /* Define a const math function. */
101 #define __m81_defun(rettype, func, args) \
102 __m81_inline rettype __attribute__((__const__)) \
105 /* Define the three variants of a math function that has a direct
106 implementation in the m68k fpu. FUNC is the name for C (which will be
107 suffixed with f and l for the float and long double version, resp). OP
108 is the name of the fpu operation (without leading f). */
110 #if defined __USE_MISC || defined __USE_ISOC99
111 #ifndef NO_LONG_DOUBLE
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) \
119 __inline_mathop1(float, __CONCAT(func,f), op)
122 # define __inline_mathop(func, op) \
123 __inline_mathop1(double, func, op)
126 #define __inline_mathop1(float_type,func, op) \
127 __m81_defun (float_type, func, (float_type __mathop_x)) \
129 float_type __result; \
130 __asm("f" __STRING(op) "%.x %1, %0" : "=f" (__result) : "f" (__mathop_x));\
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
)
141 #if defined __USE_MISC || defined __USE_XOPEN_EXTENDED || defined __USE_ISOC99
142 __inline_mathop(__rint
, int)
143 __inline_mathop(__expm1
, etoxm1
)
144 __inline_mathop(__log1p
, lognp1
)
148 __inline_mathop(__significand
, getman
)
152 __inline_mathop(__trunc
, intrz
)
155 #if !defined __NO_MATH_INLINES && defined __OPTIMIZE__
157 __inline_mathop(atan
, atan
)
158 __inline_mathop(cos
, cos
)
159 __inline_mathop(sin
, sin
)
160 __inline_mathop(tan
, tan
)
161 __inline_mathop(tanh
, tanh
)
163 # if defined __USE_MISC || defined __USE_XOPEN_EXTENDED || defined __USE_ISOC99
164 __inline_mathop(rint
, int)
165 __inline_mathop(expm1
, etoxm1
)
166 __inline_mathop(log1p
, lognp1
)
170 __inline_mathop(significand
, getman
)
174 __inline_mathop(trunc
, intrz
)
177 #endif /* !__NO_MATH_INLINES && __OPTIMIZE__ */
179 /* This macro contains the definition for the rest of the inline
180 functions, using FLOAT_TYPE as the domain type and S as the suffix
181 for the function names. */
183 #define __inline_functions(float_type, s) \
184 __m81_defun (float_type, __CONCAT(__floor,s), (float_type __x)) \
186 float_type __result; \
187 unsigned long int __ctrl_reg; \
188 __asm __volatile__ ("fmove%.l %!, %0" : "=dm" (__ctrl_reg)); \
189 /* Set rounding towards negative infinity. */ \
190 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
191 : "dmi" ((__ctrl_reg & ~0x10) | 0x20)); \
192 /* Convert X to an integer, using -Inf rounding. */ \
193 __asm __volatile__ ("fint%.x %1, %0" : "=f" (__result) : "f" (__x)); \
194 /* Restore the previous rounding mode. */ \
195 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
196 : "dmi" (__ctrl_reg)); \
200 __m81_defun (float_type, __CONCAT(__ceil,s), (float_type __x)) \
202 float_type __result; \
203 unsigned long int __ctrl_reg; \
204 __asm __volatile__ ("fmove%.l %!, %0" : "=dm" (__ctrl_reg)); \
205 /* Set rounding towards positive infinity. */ \
206 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
207 : "dmi" (__ctrl_reg | 0x30)); \
208 /* Convert X to an integer, using +Inf rounding. */ \
209 __asm __volatile__ ("fint%.x %1, %0" : "=f" (__result) : "f" (__x)); \
210 /* Restore the previous rounding mode. */ \
211 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
212 : "dmi" (__ctrl_reg)); \
216 __inline_functions(double,)
217 #if defined __USE_MISC || defined __USE_ISOC99
218 __inline_functions(float,f
)
219 #ifndef NO_LONG_DOUBLE
220 __inline_functions(long double,l
)
223 #undef __inline_functions
227 # define __inline_functions(float_type, s) \
228 __m81_defun (int, __CONCAT(__isinf,s), (float_type __value)) \
230 /* There is no branch-condition for infinity, \
231 so we must extract and examine the condition codes manually. */ \
232 unsigned long int __fpsr; \
233 __asm("ftst%.x %1\n" \
234 "fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value)); \
235 return (__fpsr & (2 << 24)) ? (__fpsr & (8 << 24) ? -1 : 1) : 0; \
238 __m81_defun (int, __CONCAT(__finite,s), (float_type __value)) \
240 /* There is no branch-condition for infinity, so we must extract and \
241 examine the condition codes manually. */ \
242 unsigned long int __fpsr; \
243 __asm ("ftst%.x %1\n" \
244 "fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value)); \
245 return (__fpsr & (3 << 24)) == 0; \
248 __m81_defun (float_type, __CONCAT(__scalbn,s), \
249 (float_type __x, int __n)) \
251 float_type __result; \
252 __asm ("fscale%.l %1, %0" : "=f" (__result) : "dmi" (__n), "0" (__x)); \
256 __inline_functions(double,)
257 __inline_functions(float,f
)
258 #ifndef NO_LONG_DOUBLE
259 __inline_functions(long double,l
)
261 # undef __inline_functions
263 #endif /* Use misc. */
265 #if defined __USE_MISC || defined __USE_XOPEN
267 # define __inline_functions(float_type, s) \
268 __m81_defun (int, __CONCAT(__isnan,s), (float_type __value)) \
271 __asm("ftst%.x %1\n" \
272 "fsun %0" : "=dm" (__result) : "f" (__value)); \
276 __inline_functions(double,)
278 __inline_functions(float,f
)
279 #ifndef NO_LONG_DOUBLE
280 __inline_functions(long double,l
)
283 # undef __inline_functions
289 # define __inline_functions(float_type, s) \
290 __m81_defun (int, __CONCAT(__signbit,s), (float_type __value)) \
292 /* There is no branch-condition for the sign bit, so we must extract \
293 and examine the condition codes manually. */ \
294 unsigned long int __fpsr; \
295 __asm ("ftst%.x %1\n" \
296 "fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value)); \
297 return (__fpsr >> 27) & 1; \
300 __m81_defun (float_type, __CONCAT(__scalbln,s), \
301 (float_type __x, long int __n)) \
303 return __CONCAT(__scalbn,s) (__x, __n); \
306 __m81_defun (float_type, __CONCAT(__nearbyint,s), (float_type __x)) \
308 float_type __result; \
309 unsigned long int __ctrl_reg; \
310 __asm __volatile__ ("fmove%.l %!, %0" : "=dm" (__ctrl_reg)); \
311 /* Temporarily disable the inexact exception. */ \
312 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
313 : "dmi" (__ctrl_reg & ~0x200)); \
314 __asm __volatile__ ("fint%.x %1, %0" : "=f" (__result) : "f" (__x)); \
315 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
316 : "dmi" (__ctrl_reg)); \
320 __m81_defun (long int, __CONCAT(__lrint,s), (float_type __x)) \
323 __asm ("fmove%.l %1, %0" : "=dm" (__result) : "f" (__x)); \
327 __m81_inline float_type \
328 __m81_u(__CONCAT(__fma,s))(float_type __x, float_type __y, \
331 return (__x * __y) + __z; \
334 __inline_functions (double,)
335 __inline_functions (float,f
)
336 #ifndef NO_LONG_DOUBLE
337 __inline_functions (long double,l
)
339 # undef __inline_functions
341 #endif /* Use ISO C9x */
345 # define __inline_functions(float_type, s) \
347 __m81_u(__CONCAT(__sincos,s))(float_type __x, float_type *__sinx, \
348 float_type *__cosx) \
350 __asm ("fsincos%.x %2,%1:%0" \
351 : "=f" (*__sinx), "=f" (*__cosx) : "f" (__x)); \
354 __inline_functions (double,)
355 __inline_functions (float,f
)
356 #ifndef NO_LONG_DOUBLE
357 __inline_functions (long double,l
)
359 # undef __inline_functions
363 #if !defined __NO_MATH_INLINES && defined __OPTIMIZE__
365 /* Define inline versions of the user visible functions. */
367 /* Note that there must be no whitespace before the argument passed for
368 NAME, to make token pasting work correctly with -traditional. */
369 # define __inline_forward_c(rettype, name, args1, args2) \
370 extern __inline rettype __attribute__((__const__)) \
373 return __CONCAT(__,name) args2; \
376 # define __inline_forward(rettype, name, args1, args2) \
377 extern __inline rettype name args1 \
379 return __CONCAT(__,name) args2; \
382 __inline_forward_c(double,floor
, (double __x
), (__x
))
383 __inline_forward_c(double,ceil
, (double __x
), (__x
))
385 # ifndef __USE_ISOC99 /* Conflict with macro of same name. */
386 __inline_forward_c(int,isinf
, (double __value
), (__value
))
388 __inline_forward_c(int,finite
, (double __value
), (__value
))
389 __inline_forward_c(double,scalbn
, (double __x
, int __n
), (__x
, __n
))
391 # if defined __USE_MISC || defined __USE_XOPEN
392 # ifndef __USE_ISOC99 /* Conflict with macro of same name. */
393 __inline_forward_c(int,isnan
, (double __value
), (__value
))
397 __inline_forward_c(double,scalbln
, (double __x
, long int __n
), (__x
, __n
))
398 __inline_forward_c(double,nearbyint
, (double __value
), (__value
))
399 __inline_forward_c(long int,lrint
, (double __value
), (__value
))
400 __inline_forward_c(double,fma
, (double __x
, double __y
, double __z
),
404 __inline_forward(void,sincos
, (double __x
, double *__sinx
, double *__cosx
),
405 (__x
, __sinx
, __cosx
))
408 # if defined __USE_MISC || defined __USE_ISOC99
410 __inline_forward_c(float,floorf
, (float __x
), (__x
))
411 __inline_forward_c(float,ceilf
, (float __x
), (__x
))
413 __inline_forward_c(int,isinff
, (float __value
), (__value
))
414 __inline_forward_c(int,finitef
, (float __value
), (__value
))
415 __inline_forward_c(float,scalbnf
, (float __x
, int __n
), (__x
, __n
))
416 __inline_forward_c(int,isnanf
, (float __value
), (__value
))
419 __inline_forward_c(float,scalblnf
, (float __x
, long int __n
), (__x
, __n
))
420 __inline_forward_c(float,nearbyintf
, (float __value
), (__value
))
421 __inline_forward_c(long int,lrintf
, (float __value
), (__value
))
422 __inline_forward_c(float,fmaf
, (float __x
, float __y
, float __z
),
426 __inline_forward(void,sincosf
, (float __x
, float *__sinx
, float *__cosx
),
427 (__x
, __sinx
, __cosx
))
430 # ifndef NO_LONG_DOUBLE
431 __inline_forward_c(long double,floorl
, (long double __x
), (__x
))
432 __inline_forward_c(long double,ceill
, (long double __x
), (__x
))
434 __inline_forward_c(int,isinfl
, (long double __value
), (__value
))
435 __inline_forward_c(int,finitel
, (long double __value
), (__value
))
436 __inline_forward_c(long double,scalbnl
, (long double __x
, int __n
), (__x
, __n
))
437 __inline_forward_c(int,isnanl
, (long double __value
), (__value
))
440 __inline_forward_c(long double,scalblnl
, (long double __x
, long int __n
),
442 __inline_forward_c(long double,nearbyintl
, (long double __value
), (__value
))
443 __inline_forward_c(long int,lrintl
, (long double __value
), (__value
))
444 __inline_forward_c(long double,fmal
,
445 (long double __x
, long double __y
, long double __z
),
449 __inline_forward(void,sincosl
,
450 (long double __x
, long double *__sinx
, long double *__cosx
),
451 (__x
, __sinx
, __cosx
))
455 #endif /* Use misc or ISO C99 */
457 #undef __inline_forward
458 #undef __inline_forward_c
460 #endif /* !__NO_MATH_INLINES && __OPTIMIZE__ */