]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/i386/fpu/bits/mathinline.h
55e91714590fbb49ec8a2c0a5d46cf4152a888c9
[thirdparty/glibc.git] / sysdeps / i386 / fpu / bits / mathinline.h
1 /* Inline math functions for i387.
2 Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by John C. Bowman <bowman@math.ualberta.ca>, 1995.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
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 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 #ifndef _BITS_MATHINLINE_H
22 #define _BITS_MATHINLINE_H 1
23
24
25 #if defined __USE_ISOC9X && defined __GNUC__ && __GNUC__ >= 2
26 /* ISO C 9X defines some macros to perform unordered comparisons. The
27 ix87 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. */
30 # define isgreater(x, y) \
31 ({ register char __result; \
32 __asm__ ("fucompp; fnstsw; testb $0x45, %%ah; setz %%al;" \
33 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \
34 __result; })
35
36 # define isgreaterequal(x, y) \
37 ({ register char __result; \
38 __asm__ ("fucompp; fnstsw; testb $0x05, %%ah; setz %%al;" \
39 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \
40 __result; })
41
42 # define isless(x, y) \
43 ({ register char __result; \
44 __asm__ ("fucompp; fnstsw; xorb $0x01, %%ah; testb $0x45, %%ah;" \
45 "setz %%al" \
46 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \
47 __result; })
48
49 # define islessequal(x, y) \
50 ({ register char __result; \
51 __asm__ ("fucompp; fnstsw; xorb $0x01, %%ah; testb $0x05, %%ah;" \
52 "setz %%al" \
53 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \
54 __result; })
55
56 # define islessgreater(x, y) \
57 ({ register char __result; \
58 __asm__ ("fucompp; fnstsw; testb $0x44, %%ah; setz %%al;" \
59 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \
60 __result; })
61
62 # define isunordered(x, y) \
63 ({ register char __result; \
64 __asm__ ("fucompp; fnstsw; sahf; setp %%al" \
65 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \
66 __result; })
67 #endif
68
69
70 #ifdef __GNUC__
71 #if !defined __NO_MATH_INLINES && defined __OPTIMIZE__
72
73 /* The gcc, version 2.7 or below, has problems with all this inlining
74 code. So disable it for this version of the compiler. */
75 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 7)
76
77 #ifdef __cplusplus
78 # define __MATH_INLINE __inline
79 #else
80 # define __MATH_INLINE extern __inline
81 #endif
82
83 /* A macro to define float, double, and long double versions of various
84 math functions for the ix87 FPU. FUNC is the function name (which will
85 be suffixed with f and l for the float and long double version,
86 respectively). OP is the name of the FPU operation. */
87
88 #if defined __USE_MISC || defined __USE_ISOC9X
89 # define __inline_mathop(func, op) \
90 __inline_mathop_ (double, func, op) \
91 __inline_mathop_ (float, __CONCAT(func,f), op) \
92 __inline_mathop_ (long double, __CONCAT(func,l), op)
93 #else
94 # define __inline_mathop(func, op) \
95 __inline_mathop_ (double, func, op)
96 #endif
97
98 #define __inline_mathop_(float_type, func, op) \
99 __inline_mathop_decl_ (float_type, func, op, "0" (__x))
100
101
102 #if defined __USE_MISC || defined __USE_ISOC9X
103 # define __inline_mathop_decl(func, op, params...) \
104 __inline_mathop_decl_ (double, func, op, params) \
105 __inline_mathop_decl_ (float, __CONCAT(func,f), op, params) \
106 __inline_mathop_decl_ (long double, __CONCAT(func,l), op, params)
107 #else
108 # define __inline_mathop_decl(func, op, params...) \
109 __inline_mathop_decl_ (double, func, op, params)
110 #endif
111
112 #define __inline_mathop_decl_(float_type, func, op, params...) \
113 __MATH_INLINE float_type func (float_type); \
114 __MATH_INLINE float_type func (float_type __x) \
115 { \
116 register float_type __result; \
117 __asm __volatile__ (op : "=t" (__result) : params); \
118 return __result; \
119 }
120
121
122 #if defined __USE_MISC || defined __USE_ISOC9X
123 # define __inline_mathcode(func, arg, code) \
124 __inline_mathcode_ (double, func, arg, code) \
125 __inline_mathcode_ (float, __CONCAT(func,f), arg, code) \
126 __inline_mathcode_ (long double, __CONCAT(func,l), arg, code)
127 #else
128 # define __inline_mathcode(func, arg, code) \
129 __inline_mathcode_ (double, func, arg, code)
130 #endif
131
132 #define __inline_mathcode_(float_type, func, arg, code) \
133 __MATH_INLINE float_type func (float_type); \
134 __MATH_INLINE float_type func (float_type arg) \
135 { \
136 code; \
137 }
138
139
140 #if defined __USE_MISC || defined __USE_ISOC9X
141 # define __inline_mathcode2(func, arg1, arg2, code) \
142 __inline_mathcode2_ (double, func, arg1, arg2, code) \
143 __inline_mathcode2_ (float, __CONCAT(func,f), arg1, arg2, code) \
144 __inline_mathcode2_ (long double, __CONCAT(func,l), arg1, arg2, code)
145 #else
146 # define __inline_mathcode2(func, arg1, arg2, code) \
147 __inline_mathcode2_ (double, func, arg1, arg2, code)
148 #endif
149
150 #define __inline_mathcode2_(float_type, func, arg1, arg2, code) \
151 __MATH_INLINE float_type func (float_type, float_type); \
152 __MATH_INLINE float_type func (float_type arg1, float_type arg2) \
153 { \
154 code; \
155 }
156
157
158 /* Miscellaneous functions */
159
160 __inline_mathcode (__sgn, __x, \
161 return __x == 0.0 ? 0.0 : (__x > 0.0 ? 1.0 : -1.0))
162
163 __inline_mathcode (__pow2, __x, \
164 register long double __value; \
165 register long double __exponent; \
166 long int __p = (long int) __x; \
167 if (__x == (long double) __p) \
168 { \
169 __asm __volatile__ \
170 ("fscale" \
171 : "=t" (__value) : "0" (1.0), "u" (__x)); \
172 return __value; \
173 } \
174 __asm __volatile__ \
175 ("fldl %%st(0)\n\t" \
176 "frndint # int(x)\n\t" \
177 "fxch\n\t" \
178 "fsub %%st(1) # fract(x)\n\t" \
179 "f2xm1 # 2^(fract(x)) - 1\n\t" \
180 : "=t" (__value), "=u" (__exponent) : "0" (__x)); \
181 __value += 1.0; \
182 __asm __volatile__ \
183 ("fscale" \
184 : "=t" (__value) : "0" (__value), "u" (__exponent)); \
185 return __value)
186
187 #define __sincos_code \
188 register long double __cosr; \
189 register long double __sinr; \
190 __asm __volatile__ \
191 ("fsincos\n\t" \
192 "fnstsw %%ax\n\t" \
193 "testl $0x400, %%eax\n\t" \
194 "jz 1f\n\t" \
195 "fldpi\n\t" \
196 "fadd %%st(0)\n\t" \
197 "fxch %%st(1)\n\t" \
198 "2: fprem1\n\t" \
199 "fnstsw %%ax\n\t" \
200 "testl $0x400, %%eax\n\t" \
201 "jnz 2b\n\t" \
202 "fstp %%st(1)\n\t" \
203 "fsincos\n\t" \
204 "1:" \
205 : "=t" (__cosr), "=u" (__sinr) : "0" (__x)); \
206 *__sinx = __sinr; \
207 *__cosx = __cosr
208
209 __MATH_INLINE void __sincos (double __x, double *__sinx, double *__cosx);
210 __MATH_INLINE void
211 __sincos (double __x, double *__sinx, double *__cosx)
212 {
213 __sincos_code;
214 }
215
216 __MATH_INLINE void __sincosf (float __x, float *__sinx, float *__cosx);
217 __MATH_INLINE void
218 __sincosf (float __x, float *__sinx, float *__cosx)
219 {
220 __sincos_code;
221 }
222
223 __MATH_INLINE void __sincosl (long double __x, long double *__sinx,
224 long double *__cosx);
225 __MATH_INLINE void
226 __sincosl (long double __x, long double *__sinx, long double *__cosx)
227 {
228 __sincos_code;
229 }
230
231
232 /* Optimized inline implementation, sometimes with reduced precision
233 and/or argument range. */
234
235 #define __expm1_code \
236 register long double __value; \
237 register long double __exponent; \
238 register long double __temp; \
239 __asm __volatile__ \
240 ("fldl2e # e^x - 1 = 2^(x * log2(e)) - 1\n\t" \
241 "fmul %%st(1) # x * log2(e)\n\t" \
242 "fstl %%st(1)\n\t" \
243 "frndint # int(x * log2(e))\n\t" \
244 "fxch\n\t" \
245 "fsub %%st(1) # fract(x * log2(e))\n\t" \
246 "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" \
247 "fscale # 2^(x * log2(e)) - 2^(int(x * log2(e)))\n\t" \
248 : "=t" (__value), "=u" (__exponent) : "0" (__x)); \
249 __asm __volatile__ \
250 ("fscale # 2^int(x * log2(e))\n\t" \
251 : "=t" (__temp) : "0" (1.0), "u" (__exponent)); \
252 __temp -= 1.0; \
253 return __temp + __value
254 __inline_mathcode_ (long double, __expm1l, __x, __expm1_code)
255
256
257 #define __exp_code \
258 register long double __value; \
259 register long double __exponent; \
260 __asm __volatile__ \
261 ("fldl2e # e^x = 2^(x * log2(e))\n\t" \
262 "fmul %%st(1) # x * log2(e)\n\t" \
263 "fstl %%st(1)\n\t" \
264 "frndint # int(x * log2(e))\n\t" \
265 "fxch\n\t" \
266 "fsub %%st(1) # fract(x * log2(e))\n\t" \
267 "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" \
268 : "=t" (__value), "=u" (__exponent) : "0" (__x)); \
269 __value += 1.0; \
270 __asm __volatile__ \
271 ("fscale" \
272 : "=t" (__value) : "0" (__value), "u" (__exponent)); \
273 return __value
274 __inline_mathcode (exp, __x, __exp_code)
275 __inline_mathcode_ (long double, __expl, __x, __exp_code)
276
277
278 __inline_mathcode (tan, __x, \
279 register long double __value; \
280 register long double __value2 __attribute__ ((unused)); \
281 __asm __volatile__ \
282 ("fptan" \
283 : "=t" (__value2), "=u" (__value) : "0" (__x)); \
284 return __value)
285
286
287 #define __atan2_code \
288 register long double __value; \
289 __asm __volatile__ \
290 ("fpatan\n\t" \
291 : "=t" (__value) : "0" (__x), "u" (__y) : "st(1)"); \
292 return __value
293 __inline_mathcode2 (atan2, __y, __x, __atan2_code)
294 __inline_mathcode2_ (long double, __atan2l, __y, __x, __atan2_code)
295
296
297 __inline_mathcode2 (fmod, __x, __y, \
298 register long double __value; \
299 __asm __volatile__ \
300 ("1: fprem\n\t" \
301 "fnstsw %%ax\n\t" \
302 "sahf\n\t" \
303 "jp 1b" \
304 : "=t" (__value) : "0" (__x), "u" (__y) : "ax", "cc"); \
305 return __value)
306
307
308 __inline_mathcode2 (pow, __x, __y, \
309 register long double __value; \
310 register long double __exponent; \
311 long int __p = (long int) __y; \
312 if (__x == 0.0 && __y > 0.0) \
313 return 0.0; \
314 if (__y == (double) __p) \
315 { \
316 long double __r = 1.0; \
317 if (__p == 0) \
318 return 1.0; \
319 if (__p < 0) \
320 { \
321 __p = -__p; \
322 __x = 1.0 / __x; \
323 } \
324 while (1) \
325 { \
326 if (__p & 1) \
327 __r *= __x; \
328 __p >>= 1; \
329 if (__p == 0) \
330 return __r; \
331 __x *= __x; \
332 } \
333 /* NOTREACHED */ \
334 } \
335 __asm __volatile__ \
336 ("fyl2x" : "=t" (__value) : "0" (__x), "u" (1.0) : "st(1)"); \
337 __asm __volatile__ \
338 ("fmul %%st(1) # y * log2(x)\n\t" \
339 "fst %%st(1)\n\t" \
340 "frndint # int(y * log2(x))\n\t" \
341 "fxch\n\t" \
342 "fsub %%st(1) # fract(y * log2(x))\n\t" \
343 "f2xm1 # 2^(fract(y * log2(x))) - 1\n\t" \
344 : "=t" (__value), "=u" (__exponent) : "0" (__y), "1" (__value)); \
345 __value += 1.0; \
346 __asm __volatile__ \
347 ("fscale" \
348 : "=t" (__value) : "0" (__value), "u" (__exponent)); \
349 return __value)
350
351
352 __inline_mathop (sqrt, "fsqrt")
353 __inline_mathop_ (long double, __sqrtl, "fsqrt")
354
355 #if defined __GNUC__ && (__GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 8)
356 __inline_mathcode_ (double, fabs, __x, return __builtin_fabs (__x))
357 __inline_mathcode_ (float, fabsf, __x, return __builtin_fabsf (__x))
358 __inline_mathcode_ (long double, fabsl, __x, return __builtin_fabsl (__x))
359 __inline_mathcode_ (long double, __fabsl, __x, return __builtin_fabsl (__x))
360 #else
361 __inline_mathop (fabs, "fabs")
362 __inline_mathop_ (long double, __fabsl, "fabs")
363 #endif
364
365 /* The argument range of this inline version is reduced. */
366 __inline_mathop (sin, "fsin")
367 /* The argument range of this inline version is reduced. */
368 __inline_mathop (cos, "fcos")
369
370 __inline_mathop (atan, "fld1; fpatan")
371 __inline_mathop (log, "fldln2; fxch; fyl2x")
372 __inline_mathop (log10, "fldlg2; fxch; fyl2x")
373
374 __inline_mathcode (asin, __x, return __atan2l (__x, __sqrtl (1.0 - __x * __x)))
375 __inline_mathcode (acos, __x, return __atan2l (__sqrtl (1.0 - __x * __x), __x))
376
377 __inline_mathcode_ (long double, __sgn1l, __x, return __x >= 0.0 ? 1.0 : -1.0)
378
379
380 /* The argument range of the inline version of sinhl is slightly reduced. */
381 __inline_mathcode (sinh, __x, \
382 register long double __exm1 = __expm1l (__fabsl (__x)); \
383 return 0.5 * (__exm1 / (__exm1 + 1.0) + __exm1) * __sgn1l (__x))
384
385 __inline_mathcode (cosh, __x, \
386 register long double __ex = __expl (__x); \
387 return 0.5 * (__ex + 1.0 / __ex))
388
389 __inline_mathcode (tanh, __x, \
390 register long double __exm1 = __expm1l (-__fabsl (__x + __x)); \
391 return __exm1 / (__exm1 + 2.0) * __sgn1l (-__x))
392
393
394 __inline_mathcode (floor, __x, \
395 register long double __value; \
396 __volatile unsigned short int __cw; \
397 __volatile unsigned short int __cwtmp; \
398 __asm __volatile ("fnstcw %0" : "=m" (__cw)); \
399 __cwtmp = (__cw & 0xf3ff) | 0x0400; /* rounding down */ \
400 __asm __volatile ("fldcw %0" : : "m" (__cwtmp)); \
401 __asm __volatile ("frndint" : "=t" (__value) : "0" (__x)); \
402 __asm __volatile ("fldcw %0" : : "m" (__cw)); \
403 return __value)
404
405 __inline_mathcode (ceil, __x, \
406 register long double __value; \
407 __volatile unsigned short int __cw; \
408 __volatile unsigned short int __cwtmp; \
409 __asm __volatile ("fnstcw %0" : "=m" (__cw)); \
410 __cwtmp = (__cw & 0xf3ff) | 0x0800; /* rounding up */ \
411 __asm __volatile ("fldcw %0" : : "m" (__cwtmp)); \
412 __asm __volatile ("frndint" : "=t" (__value) : "0" (__x)); \
413 __asm __volatile ("fldcw %0" : : "m" (__cw)); \
414 return __value)
415
416 #define __ldexp_code \
417 register long double __value; \
418 __asm __volatile__ \
419 ("fscale" \
420 : "=t" (__value) : "0" (__x), "u" ((long double) __y)); \
421 return __value
422
423 __MATH_INLINE double ldexp (double __x, int __y);
424 __MATH_INLINE double
425 ldexp (double __x, int __y)
426 {
427 __ldexp_code;
428 }
429
430
431 /* Optimized versions for some non-standardized functions. */
432 #if defined __USE_ISOC9X || defined __USE_MISC
433
434 __inline_mathop(log2, "fld1; fxch; fyl2x")
435
436 __inline_mathcode (expm1, __x, __expm1_code)
437
438 /* We cannot rely on M_SQRT being defined. So we do it for ourself
439 here. */
440 # define __M_SQRT2 _Mldbl(1.41421356237309504880) /* sqrt(2) */
441
442 __inline_mathcode (log1p, __x, \
443 register long double __value; \
444 if (__fabsl (__x) >= 1.0 - 0.5 * __M_SQRT2) \
445 __value = logl (1.0 + __x); \
446 else \
447 __asm __volatile__ \
448 ("fldln2\n\t" \
449 "fxch\n\t" \
450 "fyl2xp1" \
451 : "=t" (__value) : "0" (__x)); \
452 return __value)
453
454
455 /* The argument range of the inline version of asinhl is slightly reduced. */
456 __inline_mathcode (asinh, __x, \
457 register long double __y = __fabsl (__x); \
458 return (log1pl (__y * __y / (__sqrtl (__y * __y + 1.0) + 1.0) + __y) \
459 * __sgn1l (__x)))
460
461 __inline_mathcode (acosh, __x, \
462 return logl (__x + __sqrtl (__x - 1.0) * __sqrtl (__x + 1.0)))
463
464 __inline_mathcode (atanh, __x, \
465 register long double __y = __fabsl (__x); \
466 return (-0.5 * log1pl (-(__y + __y) / (1.0 + __y)) * \
467 __sgn1l (__x)))
468
469
470 /* The argument range of the inline version of hypotl is slightly reduced. */
471 __inline_mathcode2 (hypot, __x, __y, return __sqrtl (__x * __x + __y * __y))
472
473 __inline_mathcode(logb, __x, \
474 register long double __value; \
475 register long double __junk; \
476 __asm __volatile__ \
477 ("fxtract\n\t" \
478 : "=t" (__junk), "=u" (__value) : "0" (__x)); \
479 return __value)
480
481 __MATH_INLINE float ldexpf (float __x, int __y);
482 __MATH_INLINE float
483 ldexpf (float __x, int __y)
484 {
485 __ldexp_code;
486 }
487
488 __MATH_INLINE long double ldexpl (long double __x, int __y);
489 __MATH_INLINE long double
490 ldexpl (long double __x, int __y)
491 {
492 __ldexp_code;
493 }
494
495 #endif
496
497
498 #ifdef __USE_MISC
499
500 __inline_mathcode2 (drem, __x, __y, \
501 register double __value; \
502 __asm __volatile__ \
503 ("1: fprem1\n\t" \
504 "fstsw %%ax\n\t" \
505 "sahf\n\t" \
506 "jp 1b" \
507 : "=t" (__value) : "0" (__x), "u" (__y) : "ax", "cc"); \
508 return __value)
509
510
511 /* This function is used in the `isfinite' macro. */
512 __MATH_INLINE int __finite (double __x);
513 __MATH_INLINE int
514 __finite (double __x)
515 {
516 register int __result;
517 __asm__ __volatile__
518 ("orl $0x800fffff, %0\n\t"
519 "incl %0\n\t"
520 "shrl $31, %0"
521 : "=q" (__result) : "0" (((int *) &__x)[1]) : "cc");
522 return __result;
523 }
524
525 /* Miscellaneous functions */
526
527 __inline_mathcode (__coshm1, __x, \
528 register long double __exm1 = __expm1l (__fabsl (__x)); \
529 return 0.5 * (__exm1 / (__exm1 + 1.0)) * __exm1)
530
531 __inline_mathcode (__acosh1p, __x, \
532 return log1pl (__x + __sqrtl (__x) * __sqrtl (__x + 2.0)))
533
534 #endif /* __USE_MISC */
535
536 /* Undefine some of the large macros which are not used anymore. */
537 #undef __expm1_code
538 #undef __exp_code
539 #undef __atan2_code
540 #undef __sincos_code
541
542 #endif /* Not gcc <= 2.7. */
543 #endif /* __NO_MATH_INLINES */
544 #endif /* __GNUC__ */
545
546 #endif /* _BITS_MATHINLINE_H */