2.9
[glibc/nacl-glibc.git] / sysdeps / i386 / fpu / bits / mathinline.h
bloba786cc69cd151de47f6e66b11f92ae59d9c9eec3
1 /* Inline math functions for i387.
2 Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2003,2004,2006,2007
3 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
5 Contributed by John C. Bowman <bowman@math.ualberta.ca>, 1995.
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with the GNU C Library; if not, write to the Free
19 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 USA. */
22 #ifndef _MATH_H
23 # error "Never use <bits/mathinline.h> directly; include <math.h> instead."
24 #endif
26 #ifndef __extern_inline
27 # define __MATH_INLINE __inline
28 #else
29 # define __MATH_INLINE __extern_inline
30 #endif
33 #if defined __USE_ISOC99 && defined __GNUC__ && __GNUC__ >= 2
34 /* GCC 2.97 and up have builtins that actually can be used. */
35 # if !__GNUC_PREREQ (2,97)
36 /* ISO C99 defines some macros to perform unordered comparisons. The
37 ix87 FPU supports this with special opcodes and we should use them.
38 These must not be inline functions since we have to be able to handle
39 all floating-point types. */
40 # undef isgreater
41 # undef isgreaterequal
42 # undef isless
43 # undef islessequal
44 # undef islessgreater
45 # undef isunordered
46 # ifdef __i686__
47 /* For the PentiumPro and more recent processors we can provide
48 better code. */
49 # define isgreater(x, y) \
50 ({ register char __result; \
51 __asm__ ("fucomip %%st(1), %%st; seta %%al" \
52 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \
53 __result; })
54 # define isgreaterequal(x, y) \
55 ({ register char __result; \
56 __asm__ ("fucomip %%st(1), %%st; setae %%al" \
57 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \
58 __result; })
60 # define isless(x, y) \
61 ({ register char __result; \
62 __asm__ ("fucomip %%st(1), %%st; seta %%al" \
63 : "=a" (__result) : "u" (x), "t" (y) : "cc", "st"); \
64 __result; })
66 # define islessequal(x, y) \
67 ({ register char __result; \
68 __asm__ ("fucomip %%st(1), %%st; setae %%al" \
69 : "=a" (__result) : "u" (x), "t" (y) : "cc", "st"); \
70 __result; })
72 # define islessgreater(x, y) \
73 ({ register char __result; \
74 __asm__ ("fucomip %%st(1), %%st; setne %%al" \
75 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \
76 __result; })
78 # define isunordered(x, y) \
79 ({ register char __result; \
80 __asm__ ("fucomip %%st(1), %%st; setp %%al" \
81 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \
82 __result; })
83 # else
84 /* This is the dumb, portable code for i386 and above. */
85 # define isgreater(x, y) \
86 ({ register char __result; \
87 __asm__ ("fucompp; fnstsw; testb $0x45, %%ah; setz %%al" \
88 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \
89 __result; })
91 # define isgreaterequal(x, y) \
92 ({ register char __result; \
93 __asm__ ("fucompp; fnstsw; testb $0x05, %%ah; setz %%al" \
94 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \
95 __result; })
97 # define isless(x, y) \
98 ({ register char __result; \
99 __asm__ ("fucompp; fnstsw; testb $0x45, %%ah; setz %%al" \
100 : "=a" (__result) : "u" (x), "t" (y) : "cc", "st", "st(1)"); \
101 __result; })
103 # define islessequal(x, y) \
104 ({ register char __result; \
105 __asm__ ("fucompp; fnstsw; testb $0x05, %%ah; setz %%al" \
106 : "=a" (__result) : "u" (x), "t" (y) : "cc", "st", "st(1)"); \
107 __result; })
109 # define islessgreater(x, y) \
110 ({ register char __result; \
111 __asm__ ("fucompp; fnstsw; testb $0x44, %%ah; setz %%al" \
112 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \
113 __result; })
115 # define isunordered(x, y) \
116 ({ register char __result; \
117 __asm__ ("fucompp; fnstsw; sahf; setp %%al" \
118 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \
119 __result; })
120 # endif /* __i686__ */
121 # endif /* GCC 2.97 */
123 /* The gcc, version 2.7 or below, has problems with all this inlining
124 code. So disable it for this version of the compiler. */
125 # if __GNUC_PREREQ (2, 8)
126 /* Test for negative number. Used in the signbit() macro. */
127 __MATH_INLINE int
128 __NTH (__signbitf (float __x))
130 __extension__ union { float __f; int __i; } __u = { __f: __x };
131 return __u.__i < 0;
133 __MATH_INLINE int
134 __NTH (__signbit (double __x))
136 __extension__ union { double __d; int __i[2]; } __u = { __d: __x };
137 return __u.__i[1] < 0;
139 __MATH_INLINE int
140 __NTH (__signbitl (long double __x))
142 __extension__ union { long double __l; int __i[3]; } __u = { __l: __x };
143 return (__u.__i[2] & 0x8000) != 0;
145 # endif
146 #endif
149 /* The gcc, version 2.7 or below, has problems with all this inlining
150 code. So disable it for this version of the compiler. */
151 #if __GNUC_PREREQ (2, 8)
153 #if ((!defined __NO_MATH_INLINES || defined __LIBC_INTERNAL_MATH_INLINES) \
154 && defined __OPTIMIZE__)
156 /* A macro to define float, double, and long double versions of various
157 math functions for the ix87 FPU. FUNC is the function name (which will
158 be suffixed with f and l for the float and long double version,
159 respectively). OP is the name of the FPU operation.
160 We define two sets of macros. The set with the additional NP
161 doesn't add a prototype declaration. */
163 #if defined __USE_MISC || defined __USE_ISOC99
164 # define __inline_mathop(func, op) \
165 __inline_mathop_ (double, func, op) \
166 __inline_mathop_ (float, __CONCAT(func,f), op) \
167 __inline_mathop_ (long double, __CONCAT(func,l), op)
168 # define __inline_mathopNP(func, op) \
169 __inline_mathopNP_ (double, func, op) \
170 __inline_mathopNP_ (float, __CONCAT(func,f), op) \
171 __inline_mathopNP_ (long double, __CONCAT(func,l), op)
172 #else
173 # define __inline_mathop(func, op) \
174 __inline_mathop_ (double, func, op)
175 # define __inline_mathopNP(func, op) \
176 __inline_mathopNP_ (double, func, op)
177 #endif
179 #define __inline_mathop_(float_type, func, op) \
180 __inline_mathop_decl_ (float_type, func, op, "0" (__x))
181 #define __inline_mathopNP_(float_type, func, op) \
182 __inline_mathop_declNP_ (float_type, func, op, "0" (__x))
185 #if defined __USE_MISC || defined __USE_ISOC99
186 # define __inline_mathop_decl(func, op, params...) \
187 __inline_mathop_decl_ (double, func, op, params) \
188 __inline_mathop_decl_ (float, __CONCAT(func,f), op, params) \
189 __inline_mathop_decl_ (long double, __CONCAT(func,l), op, params)
190 # define __inline_mathop_declNP(func, op, params...) \
191 __inline_mathop_declNP_ (double, func, op, params) \
192 __inline_mathop_declNP_ (float, __CONCAT(func,f), op, params) \
193 __inline_mathop_declNP_ (long double, __CONCAT(func,l), op, params)
194 #else
195 # define __inline_mathop_decl(func, op, params...) \
196 __inline_mathop_decl_ (double, func, op, params)
197 # define __inline_mathop_declNP(func, op, params...) \
198 __inline_mathop_declNP_ (double, func, op, params)
199 #endif
201 #define __inline_mathop_decl_(float_type, func, op, params...) \
202 __MATH_INLINE float_type func (float_type) __THROW; \
203 __inline_mathop_declNP_ (float_type, func, op, params)
205 #define __inline_mathop_declNP_(float_type, func, op, params...) \
206 __MATH_INLINE float_type __NTH (func (float_type __x)) \
208 register float_type __result; \
209 __asm __volatile__ (op : "=t" (__result) : params); \
210 return __result; \
214 #if defined __USE_MISC || defined __USE_ISOC99
215 # define __inline_mathcode(func, arg, code) \
216 __inline_mathcode_ (double, func, arg, code) \
217 __inline_mathcode_ (float, __CONCAT(func,f), arg, code) \
218 __inline_mathcode_ (long double, __CONCAT(func,l), arg, code)
219 # define __inline_mathcodeNP(func, arg, code) \
220 __inline_mathcodeNP_ (double, func, arg, code) \
221 __inline_mathcodeNP_ (float, __CONCAT(func,f), arg, code) \
222 __inline_mathcodeNP_ (long double, __CONCAT(func,l), arg, code)
223 # define __inline_mathcode2(func, arg1, arg2, code) \
224 __inline_mathcode2_ (double, func, arg1, arg2, code) \
225 __inline_mathcode2_ (float, __CONCAT(func,f), arg1, arg2, code) \
226 __inline_mathcode2_ (long double, __CONCAT(func,l), arg1, arg2, code)
227 # define __inline_mathcodeNP2(func, arg1, arg2, code) \
228 __inline_mathcodeNP2_ (double, func, arg1, arg2, code) \
229 __inline_mathcodeNP2_ (float, __CONCAT(func,f), arg1, arg2, code) \
230 __inline_mathcodeNP2_ (long double, __CONCAT(func,l), arg1, arg2, code)
231 # define __inline_mathcode3(func, arg1, arg2, arg3, code) \
232 __inline_mathcode3_ (double, func, arg1, arg2, arg3, code) \
233 __inline_mathcode3_ (float, __CONCAT(func,f), arg1, arg2, arg3, code) \
234 __inline_mathcode3_ (long double, __CONCAT(func,l), arg1, arg2, arg3, code)
235 # define __inline_mathcodeNP3(func, arg1, arg2, arg3, code) \
236 __inline_mathcodeNP3_ (double, func, arg1, arg2, arg3, code) \
237 __inline_mathcodeNP3_ (float, __CONCAT(func,f), arg1, arg2, arg3, code) \
238 __inline_mathcodeNP3_ (long double, __CONCAT(func,l), arg1, arg2, arg3, code)
239 #else
240 # define __inline_mathcode(func, arg, code) \
241 __inline_mathcode_ (double, func, (arg), code)
242 # define __inline_mathcodeNP(func, arg, code) \
243 __inline_mathcodeNP_ (double, func, (arg), code)
244 # define __inline_mathcode2(func, arg1, arg2, code) \
245 __inline_mathcode2_ (double, func, arg1, arg2, code)
246 # define __inline_mathcodeNP2(func, arg1, arg2, code) \
247 __inline_mathcodeNP2_ (double, func, arg1, arg2, code)
248 # define __inline_mathcode3(func, arg1, arg2, arg3, code) \
249 __inline_mathcode3_ (double, func, arg1, arg2, arg3, code)
250 # define __inline_mathcodeNP3(func, arg1, arg2, arg3, code) \
251 __inline_mathcodeNP3_ (double, func, arg1, arg2, arg3, code)
252 #endif
254 #define __inline_mathcode_(float_type, func, arg, code) \
255 __MATH_INLINE float_type func (float_type) __THROW; \
256 __inline_mathcodeNP_(float_type, func, arg, code)
258 #define __inline_mathcodeNP_(float_type, func, arg, code) \
259 __MATH_INLINE float_type __NTH (func (float_type arg)) \
261 code; \
265 #define __inline_mathcode2_(float_type, func, arg1, arg2, code) \
266 __MATH_INLINE float_type func (float_type, float_type) __THROW; \
267 __inline_mathcodeNP2_ (float_type, func, arg1, arg2, code)
269 #define __inline_mathcodeNP2_(float_type, func, arg1, arg2, code) \
270 __MATH_INLINE float_type __NTH (func (float_type arg1, float_type arg2)) \
272 code; \
275 #define __inline_mathcode3_(float_type, func, arg1, arg2, arg3, code) \
276 __MATH_INLINE float_type func (float_type, float_type, float_type) __THROW; \
277 __inline_mathcodeNP3_(float_type, func, arg1, arg2, arg3, code)
279 #define __inline_mathcodeNP3_(float_type, func, arg1, arg2, arg3, code) \
280 __MATH_INLINE float_type __NTH (func (float_type arg1, float_type arg2, \
281 float_type arg3)) \
283 code; \
285 #endif
288 #if !defined __NO_MATH_INLINES && defined __OPTIMIZE__
289 /* Miscellaneous functions */
291 __inline_mathcode (__sgn, __x, \
292 return __x == 0.0 ? 0.0 : (__x > 0.0 ? 1.0 : -1.0))
294 /* __FAST_MATH__ is defined by gcc -ffast-math. */
295 #ifdef __FAST_MATH__
296 __inline_mathcode (__pow2, __x, \
297 register long double __value; \
298 register long double __exponent; \
299 __extension__ long long int __p = (long long int) __x; \
300 if (__x == (long double) __p) \
302 __asm __volatile__ \
303 ("fscale" \
304 : "=t" (__value) : "0" (1.0), "u" (__x)); \
305 return __value; \
307 __asm __volatile__ \
308 ("fld %%st(0)\n\t" \
309 "frndint # int(x)\n\t" \
310 "fxch\n\t" \
311 "fsub %%st(1) # fract(x)\n\t" \
312 "f2xm1 # 2^(fract(x)) - 1\n\t" \
313 : "=t" (__value), "=u" (__exponent) : "0" (__x)); \
314 __value += 1.0; \
315 __asm __volatile__ \
316 ("fscale" \
317 : "=t" (__value) : "0" (__value), "u" (__exponent)); \
318 return __value)
320 # ifdef __USE_GNU
321 # define __sincos_code \
322 register long double __cosr; \
323 register long double __sinr; \
324 __asm __volatile__ \
325 ("fsincos\n\t" \
326 "fnstsw %%ax\n\t" \
327 "testl $0x400, %%eax\n\t" \
328 "jz 1f\n\t" \
329 "fldpi\n\t" \
330 "fadd %%st(0)\n\t" \
331 "fxch %%st(1)\n\t" \
332 "2: fprem1\n\t" \
333 "fnstsw %%ax\n\t" \
334 "testl $0x400, %%eax\n\t" \
335 "jnz 2b\n\t" \
336 "fstp %%st(1)\n\t" \
337 "fsincos\n\t" \
338 "1:" \
339 : "=t" (__cosr), "=u" (__sinr) : "0" (__x)); \
340 *__sinx = __sinr; \
341 *__cosx = __cosr
343 __MATH_INLINE void
344 __NTH (__sincos (double __x, double *__sinx, double *__cosx))
346 __sincos_code;
349 __MATH_INLINE void
350 __NTH (__sincosf (float __x, float *__sinx, float *__cosx))
352 __sincos_code;
355 __MATH_INLINE void
356 __NTH (__sincosl (long double __x, long double *__sinx, long double *__cosx))
358 __sincos_code;
360 # endif
363 /* Optimized inline implementation, sometimes with reduced precision
364 and/or argument range. */
366 # if __GNUC_PREREQ (3, 5)
367 # define __expm1_code \
368 register long double __temp; \
369 __temp = __builtin_expm1l (__x); \
370 return __temp ? __temp : __x
371 # else
372 # define __expm1_code \
373 register long double __value; \
374 register long double __exponent; \
375 register long double __temp; \
376 __asm __volatile__ \
377 ("fldl2e # e^x - 1 = 2^(x * log2(e)) - 1\n\t" \
378 "fmul %%st(1) # x * log2(e)\n\t" \
379 "fst %%st(1)\n\t" \
380 "frndint # int(x * log2(e))\n\t" \
381 "fxch\n\t" \
382 "fsub %%st(1) # fract(x * log2(e))\n\t" \
383 "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" \
384 "fscale # 2^(x * log2(e)) - 2^(int(x * log2(e)))\n\t" \
385 : "=t" (__value), "=u" (__exponent) : "0" (__x)); \
386 __asm __volatile__ \
387 ("fscale # 2^int(x * log2(e))\n\t" \
388 : "=t" (__temp) : "0" (1.0), "u" (__exponent)); \
389 __temp -= 1.0; \
390 __temp += __value; \
391 return __temp ? __temp : __x
392 # endif
393 __inline_mathcodeNP_ (long double, __expm1l, __x, __expm1_code)
395 # if __GNUC_PREREQ (3, 4)
396 __inline_mathcodeNP_ (long double, __expl, __x, return __builtin_expl (__x))
397 # else
398 # define __exp_code \
399 register long double __value; \
400 register long double __exponent; \
401 __asm __volatile__ \
402 ("fldl2e # e^x = 2^(x * log2(e))\n\t" \
403 "fmul %%st(1) # x * log2(e)\n\t" \
404 "fst %%st(1)\n\t" \
405 "frndint # int(x * log2(e))\n\t" \
406 "fxch\n\t" \
407 "fsub %%st(1) # fract(x * log2(e))\n\t" \
408 "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" \
409 : "=t" (__value), "=u" (__exponent) : "0" (__x)); \
410 __value += 1.0; \
411 __asm __volatile__ \
412 ("fscale" \
413 : "=t" (__value) : "0" (__value), "u" (__exponent)); \
414 return __value
415 __inline_mathcodeNP (exp, __x, __exp_code)
416 __inline_mathcodeNP_ (long double, __expl, __x, __exp_code)
417 # endif
420 # if !__GNUC_PREREQ (3, 5)
421 __inline_mathcodeNP (tan, __x, \
422 register long double __value; \
423 register long double __value2 __attribute__ ((__unused__)); \
424 __asm __volatile__ \
425 ("fptan" \
426 : "=t" (__value2), "=u" (__value) : "0" (__x)); \
427 return __value)
428 # endif
429 #endif /* __FAST_MATH__ */
432 #if __GNUC_PREREQ (3, 4)
433 __inline_mathcodeNP2_ (long double, __atan2l, __y, __x,
434 return __builtin_atan2l (__y, __x))
435 #else
436 # define __atan2_code \
437 register long double __value; \
438 __asm __volatile__ \
439 ("fpatan" \
440 : "=t" (__value) : "0" (__x), "u" (__y) : "st(1)"); \
441 return __value
442 # ifdef __FAST_MATH__
443 __inline_mathcodeNP2 (atan2, __y, __x, __atan2_code)
444 # endif
445 __inline_mathcodeNP2_ (long double, __atan2l, __y, __x, __atan2_code)
446 #endif
449 #if defined __FAST_MATH__ && !__GNUC_PREREQ (3, 5)
450 __inline_mathcodeNP2 (fmod, __x, __y, \
451 register long double __value; \
452 __asm __volatile__ \
453 ("1: fprem\n\t" \
454 "fnstsw %%ax\n\t" \
455 "sahf\n\t" \
456 "jp 1b" \
457 : "=t" (__value) : "0" (__x), "u" (__y) : "ax", "cc"); \
458 return __value)
459 #endif
462 #ifdef __FAST_MATH__
463 # if !__GNUC_PREREQ (3,3)
464 __inline_mathopNP (sqrt, "fsqrt")
465 __inline_mathopNP_ (long double, __sqrtl, "fsqrt")
466 # define __libc_sqrtl(n) __sqrtl (n)
467 # else
468 # define __libc_sqrtl(n) __builtin_sqrtl (n)
469 # endif
470 #endif
472 #if __GNUC_PREREQ (2, 8)
473 __inline_mathcodeNP_ (double, fabs, __x, return __builtin_fabs (__x))
474 # if defined __USE_MISC || defined __USE_ISOC99
475 __inline_mathcodeNP_ (float, fabsf, __x, return __builtin_fabsf (__x))
476 __inline_mathcodeNP_ (long double, fabsl, __x, return __builtin_fabsl (__x))
477 # endif
478 __inline_mathcodeNP_ (long double, __fabsl, __x, return __builtin_fabsl (__x))
479 #else
480 __inline_mathop (fabs, "fabs")
481 __inline_mathop_ (long double, __fabsl, "fabs")
482 #endif
484 #ifdef __FAST_MATH__
485 # if !__GNUC_PREREQ (3, 4)
486 /* The argument range of this inline version is reduced. */
487 __inline_mathopNP (sin, "fsin")
488 /* The argument range of this inline version is reduced. */
489 __inline_mathopNP (cos, "fcos")
491 __inline_mathop_declNP (log, "fldln2; fxch; fyl2x", "0" (__x) : "st(1)")
492 # endif
494 # if !__GNUC_PREREQ (3, 5)
495 __inline_mathop_declNP (log10, "fldlg2; fxch; fyl2x", "0" (__x) : "st(1)")
497 __inline_mathcodeNP (asin, __x, return __atan2l (__x, __libc_sqrtl (1.0 - __x * __x)))
498 __inline_mathcodeNP (acos, __x, return __atan2l (__libc_sqrtl (1.0 - __x * __x), __x))
499 # endif
501 # if !__GNUC_PREREQ (3, 4)
502 __inline_mathop_declNP (atan, "fld1; fpatan", "0" (__x) : "st(1)")
503 # endif
504 #endif /* __FAST_MATH__ */
506 __inline_mathcode_ (long double, __sgn1l, __x, \
507 __extension__ union { long double __xld; unsigned int __xi[3]; } __n = \
508 { __xld: __x }; \
509 __n.__xi[2] = (__n.__xi[2] & 0x8000) | 0x3fff; \
510 __n.__xi[1] = 0x80000000; \
511 __n.__xi[0] = 0; \
512 return __n.__xld)
515 #ifdef __FAST_MATH__
516 /* The argument range of the inline version of sinhl is slightly reduced. */
517 __inline_mathcodeNP (sinh, __x, \
518 register long double __exm1 = __expm1l (__fabsl (__x)); \
519 return 0.5 * (__exm1 / (__exm1 + 1.0) + __exm1) * __sgn1l (__x))
521 __inline_mathcodeNP (cosh, __x, \
522 register long double __ex = __expl (__x); \
523 return 0.5 * (__ex + 1.0 / __ex))
525 __inline_mathcodeNP (tanh, __x, \
526 register long double __exm1 = __expm1l (-__fabsl (__x + __x)); \
527 return __exm1 / (__exm1 + 2.0) * __sgn1l (-__x))
528 #endif
530 __inline_mathcodeNP (floor, __x, \
531 register long double __value; \
532 register int __ignore; \
533 unsigned short int __cw; \
534 unsigned short int __cwtmp; \
535 __asm __volatile ("fnstcw %3\n\t" \
536 "movzwl %3, %1\n\t" \
537 "andl $0xf3ff, %1\n\t" \
538 "orl $0x0400, %1\n\t" /* rounding down */ \
539 "movw %w1, %2\n\t" \
540 "fldcw %2\n\t" \
541 "frndint\n\t" \
542 "fldcw %3" \
543 : "=t" (__value), "=&q" (__ignore), "=m" (__cwtmp), \
544 "=m" (__cw) \
545 : "0" (__x)); \
546 return __value)
548 __inline_mathcodeNP (ceil, __x, \
549 register long double __value; \
550 register int __ignore; \
551 unsigned short int __cw; \
552 unsigned short int __cwtmp; \
553 __asm __volatile ("fnstcw %3\n\t" \
554 "movzwl %3, %1\n\t" \
555 "andl $0xf3ff, %1\n\t" \
556 "orl $0x0800, %1\n\t" /* rounding up */ \
557 "movw %w1, %2\n\t" \
558 "fldcw %2\n\t" \
559 "frndint\n\t" \
560 "fldcw %3" \
561 : "=t" (__value), "=&q" (__ignore), "=m" (__cwtmp), \
562 "=m" (__cw) \
563 : "0" (__x)); \
564 return __value)
566 #ifdef __FAST_MATH__
567 # define __ldexp_code \
568 register long double __value; \
569 __asm __volatile__ \
570 ("fscale" \
571 : "=t" (__value) : "0" (__x), "u" ((long double) __y)); \
572 return __value
574 __MATH_INLINE double
575 __NTH (ldexp (double __x, int __y))
577 __ldexp_code;
579 #endif
582 /* Optimized versions for some non-standardized functions. */
583 #if defined __USE_ISOC99 || defined __USE_MISC
585 # ifdef __FAST_MATH__
586 __inline_mathcodeNP (expm1, __x, __expm1_code)
588 /* We cannot rely on M_SQRT being defined. So we do it for ourself
589 here. */
590 # define __M_SQRT2 1.41421356237309504880L /* sqrt(2) */
592 # if !__GNUC_PREREQ (3, 5)
593 __inline_mathcodeNP (log1p, __x, \
594 register long double __value; \
595 if (__fabsl (__x) >= 1.0 - 0.5 * __M_SQRT2) \
596 __value = logl (1.0 + __x); \
597 else \
598 __asm __volatile__ \
599 ("fldln2\n\t" \
600 "fxch\n\t" \
601 "fyl2xp1" \
602 : "=t" (__value) : "0" (__x) : "st(1)"); \
603 return __value)
604 # endif
607 /* The argument range of the inline version of asinhl is slightly reduced. */
608 __inline_mathcodeNP (asinh, __x, \
609 register long double __y = __fabsl (__x); \
610 return (log1pl (__y * __y / (__libc_sqrtl (__y * __y + 1.0) + 1.0) + __y) \
611 * __sgn1l (__x)))
613 __inline_mathcodeNP (acosh, __x, \
614 return logl (__x + __libc_sqrtl (__x - 1.0) * __libc_sqrtl (__x + 1.0)))
616 __inline_mathcodeNP (atanh, __x, \
617 register long double __y = __fabsl (__x); \
618 return -0.5 * log1pl (-(__y + __y) / (1.0 + __y)) * __sgn1l (__x))
620 /* The argument range of the inline version of hypotl is slightly reduced. */
621 __inline_mathcodeNP2 (hypot, __x, __y,
622 return __libc_sqrtl (__x * __x + __y * __y))
624 # if !__GNUC_PREREQ (3, 5)
625 __inline_mathcodeNP(logb, __x, \
626 register long double __value; \
627 register long double __junk; \
628 __asm __volatile__ \
629 ("fxtract\n\t" \
630 : "=t" (__junk), "=u" (__value) : "0" (__x)); \
631 return __value)
632 # endif
634 # endif
635 #endif
637 #ifdef __USE_ISOC99
638 # ifdef __FAST_MATH__
640 # if !__GNUC_PREREQ (3, 5)
641 __inline_mathop_declNP (log2, "fld1; fxch; fyl2x", "0" (__x) : "st(1)")
642 # endif
644 __MATH_INLINE float
645 __NTH (ldexpf (float __x, int __y))
647 __ldexp_code;
650 __MATH_INLINE long double
651 __NTH (ldexpl (long double __x, int __y))
653 __ldexp_code;
656 __inline_mathcodeNP3 (fma, __x, __y, __z, return (__x * __y) + __z)
658 __inline_mathopNP (rint, "frndint")
659 # endif /* __FAST_MATH__ */
661 # define __lrint_code \
662 long int __lrintres; \
663 __asm__ __volatile__ \
664 ("fistpl %0" \
665 : "=m" (__lrintres) : "t" (__x) : "st"); \
666 return __lrintres
667 __MATH_INLINE long int
668 __NTH (lrintf (float __x))
670 __lrint_code;
672 __MATH_INLINE long int
673 __NTH (lrint (double __x))
675 __lrint_code;
677 __MATH_INLINE long int
678 __NTH (lrintl (long double __x))
680 __lrint_code;
682 # undef __lrint_code
684 # define __llrint_code \
685 long long int __llrintres; \
686 __asm__ __volatile__ \
687 ("fistpll %0" \
688 : "=m" (__llrintres) : "t" (__x) : "st"); \
689 return __llrintres
690 __MATH_INLINE long long int
691 __NTH (llrintf (float __x))
693 __llrint_code;
695 __MATH_INLINE long long int
696 __NTH (llrint (double __x))
698 __llrint_code;
700 __MATH_INLINE long long int
701 __NTH (llrintl (long double __x))
703 __llrint_code;
705 # undef __llrint_code
707 #endif
710 #ifdef __USE_MISC
712 # if defined __FAST_MATH__ && !__GNUC_PREREQ (3, 5)
713 __inline_mathcodeNP2 (drem, __x, __y, \
714 register double __value; \
715 register int __clobbered; \
716 __asm __volatile__ \
717 ("1: fprem1\n\t" \
718 "fstsw %%ax\n\t" \
719 "sahf\n\t" \
720 "jp 1b" \
721 : "=t" (__value), "=&a" (__clobbered) : "0" (__x), "u" (__y) : "cc"); \
722 return __value)
723 # endif
726 /* This function is used in the `isfinite' macro. */
727 __MATH_INLINE int
728 __NTH (__finite (double __x))
730 return (__extension__
731 (((((union { double __d; int __i[2]; }) {__d: __x}).__i[1]
732 | 0x800fffffu) + 1) >> 31));
735 /* Miscellaneous functions */
736 # ifdef __FAST_MATH__
737 __inline_mathcode (__coshm1, __x, \
738 register long double __exm1 = __expm1l (__fabsl (__x)); \
739 return 0.5 * (__exm1 / (__exm1 + 1.0)) * __exm1)
741 __inline_mathcode (__acosh1p, __x, \
742 return log1pl (__x + __libc_sqrtl (__x) * __libc_sqrtl (__x + 2.0)))
744 # endif /* __FAST_MATH__ */
745 #endif /* __USE_MISC */
747 /* Undefine some of the large macros which are not used anymore. */
748 #undef __atan2_code
749 #ifdef __FAST_MATH__
750 # undef __expm1_code
751 # undef __exp_code
752 # undef __sincos_code
753 #endif /* __FAST_MATH__ */
755 #endif /* __NO_MATH_INLINES */
758 /* This code is used internally in the GNU libc. */
759 #ifdef __LIBC_INTERNAL_MATH_INLINES
760 __inline_mathop (__ieee754_sqrt, "fsqrt")
761 __inline_mathcode2 (__ieee754_atan2, __y, __x,
762 register long double __value;
763 __asm __volatile__ ("fpatan\n\t"
764 : "=t" (__value)
765 : "0" (__x), "u" (__y) : "st(1)");
766 return __value;)
767 #endif
769 #endif /* __GNUC__ */