]>
Commit | Line | Data |
---|---|---|
b20e47cb | 1 | /* Inline math functions for i387. |
fc370352 | 2 | Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. |
f8b87ef0 | 3 | This file is part of the GNU C Library. |
3996f34b | 4 | Contributed by John C. Bowman <bowman@math.ualberta.ca>, 1995. |
b20e47cb | 5 | |
f8b87ef0 UD |
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. | |
b20e47cb | 10 | |
f8b87ef0 UD |
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. | |
b20e47cb | 15 | |
f8b87ef0 UD |
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. */ | |
b20e47cb | 20 | |
61eb22d3 UD |
21 | #ifndef _MATH_H |
22 | # error "Never use <bits/mathinline.h> directly; include <math.h> instead." | |
23 | #endif | |
f8b87ef0 | 24 | |
f43ce637 UD |
25 | #ifdef __cplusplus |
26 | # define __MATH_INLINE __inline | |
27 | #else | |
28 | # define __MATH_INLINE extern __inline | |
29 | #endif | |
30 | ||
cd6ede75 UD |
31 | |
32 | #if defined __USE_ISOC9X && defined __GNUC__ && __GNUC__ >= 2 | |
33 | /* ISO C 9X defines some macros to perform unordered comparisons. The | |
34 | ix87 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. */ | |
f43ce637 UD |
37 | # ifdef __i686__ |
38 | /* For the PentiumPro and more recent processors we can provide | |
39 | better code. */ | |
40 | # define isgreater(x, y) \ | |
41 | ({ register char __result; \ | |
d111572f | 42 | __asm__ ("fucomip %%st(1), %%st; seta %%al" \ |
f43ce637 UD |
43 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \ |
44 | __result; }) | |
45 | # define isgreaterequal(x, y) \ | |
46 | ({ register char __result; \ | |
d111572f | 47 | __asm__ ("fucomip %%st(1), %%st; setae %%al" \ |
f43ce637 UD |
48 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \ |
49 | __result; }) | |
50 | ||
51 | # define isless(x, y) \ | |
52 | ({ register char __result; \ | |
d111572f UD |
53 | __asm__ ("fucomip %%st(1), %%st; seta %%al" \ |
54 | : "=a" (__result) : "u" (x), "t" (y) : "cc", "st"); \ | |
f43ce637 UD |
55 | __result; }) |
56 | ||
57 | # define islessequal(x, y) \ | |
58 | ({ register char __result; \ | |
d111572f UD |
59 | __asm__ ("fucomip %%st(1), %%st; setae %%al" \ |
60 | : "=a" (__result) : "u" (x), "t" (y) : "cc", "st"); \ | |
f43ce637 UD |
61 | __result; }) |
62 | ||
63 | # define islessgreater(x, y) \ | |
64 | ({ register char __result; \ | |
d111572f | 65 | __asm__ ("fucomip %%st(1), %%st; setne %%al" \ |
f43ce637 UD |
66 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \ |
67 | __result; }) | |
68 | ||
69 | # define isunordered(x, y) \ | |
70 | ({ register char __result; \ | |
d111572f | 71 | __asm__ ("fucomip %%st(1), %%st; setp %%al" \ |
f43ce637 UD |
72 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \ |
73 | __result; }) | |
74 | # else | |
75 | /* This is the dumb, portable code for i386 and above. */ | |
76 | # define isgreater(x, y) \ | |
9a0a462c | 77 | ({ register char __result; \ |
f43ce637 | 78 | __asm__ ("fucompp; fnstsw; testb $0x45, %%ah; setz %%al" \ |
3996f34b UD |
79 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \ |
80 | __result; }) | |
cd6ede75 | 81 | |
f43ce637 | 82 | # define isgreaterequal(x, y) \ |
9a0a462c | 83 | ({ register char __result; \ |
f43ce637 | 84 | __asm__ ("fucompp; fnstsw; testb $0x05, %%ah; setz %%al" \ |
3996f34b UD |
85 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \ |
86 | __result; }) | |
cd6ede75 | 87 | |
f43ce637 | 88 | # define isless(x, y) \ |
9a0a462c | 89 | ({ register char __result; \ |
d111572f UD |
90 | __asm__ ("fucompp; fnstsw; testb $0x45, %%ah; setz %%al" \ |
91 | : "=a" (__result) : "u" (x), "t" (y) : "cc", "st", "st(1)"); \ | |
3996f34b | 92 | __result; }) |
cd6ede75 | 93 | |
f43ce637 | 94 | # define islessequal(x, y) \ |
9a0a462c | 95 | ({ register char __result; \ |
d111572f UD |
96 | __asm__ ("fucompp; fnstsw; testb $0x05, %%ah; setz %%al" \ |
97 | : "=a" (__result) : "u" (x), "t" (y) : "cc", "st", "st(1)"); \ | |
3996f34b | 98 | __result; }) |
cd6ede75 | 99 | |
f43ce637 | 100 | # define islessgreater(x, y) \ |
9a0a462c | 101 | ({ register char __result; \ |
f43ce637 | 102 | __asm__ ("fucompp; fnstsw; testb $0x44, %%ah; setz %%al" \ |
3996f34b UD |
103 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \ |
104 | __result; }) | |
cd6ede75 | 105 | |
f43ce637 | 106 | # define isunordered(x, y) \ |
9a0a462c UD |
107 | ({ register char __result; \ |
108 | __asm__ ("fucompp; fnstsw; sahf; setp %%al" \ | |
3996f34b UD |
109 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \ |
110 | __result; }) | |
f43ce637 | 111 | # endif /* __i686__ */ |
cd6ede75 | 112 | |
090d93cd UD |
113 | /* The gcc, version 2.7 or below, has problems with all this inlining |
114 | code. So disable it for this version of the compiler. */ | |
115 | # if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 7)) | |
f43ce637 UD |
116 | /* Test for negative number. Used in the signbit() macro. */ |
117 | __MATH_INLINE int | |
118 | __signbitf (float __x) | |
119 | { | |
fc370352 UD |
120 | __extension__ union { float __f; int __i; } __u = { __f: __x }; |
121 | return __u.__i < 0; | |
f43ce637 UD |
122 | } |
123 | __MATH_INLINE int | |
124 | __signbit (double __x) | |
125 | { | |
fc370352 UD |
126 | __extension__ union { double __d; int __i[2]; } __u = { __d: __x }; |
127 | return __u.__i[1] < 0; | |
f43ce637 UD |
128 | } |
129 | __MATH_INLINE int | |
130 | __signbitl (long double __x) | |
131 | { | |
fc370352 | 132 | __extension__ union { long double __l; int __i[3]; } __u = { __l: __x }; |
f43ce637 UD |
133 | return (__u.__i[2] & 0x8000) != 0; |
134 | } | |
090d93cd | 135 | # endif |
f43ce637 | 136 | #endif |
cd6ede75 | 137 | |
b20e47cb | 138 | |
f41c8091 UD |
139 | /* The gcc, version 2.7 or below, has problems with all this inlining |
140 | code. So disable it for this version of the compiler. */ | |
4360eafd | 141 | #if __GNUC_PREREQ (2, 8) |
f41c8091 | 142 | |
f43ce637 UD |
143 | #if ((!defined __NO_MATH_INLINES || defined __LIBC_INTERNAL_MATH_INLINES) \ |
144 | && defined __OPTIMIZE__) | |
b20e47cb | 145 | |
3996f34b UD |
146 | /* A macro to define float, double, and long double versions of various |
147 | math functions for the ix87 FPU. FUNC is the function name (which will | |
148 | be suffixed with f and l for the float and long double version, | |
149 | respectively). OP is the name of the FPU operation. */ | |
b20e47cb | 150 | |
3996f34b UD |
151 | #if defined __USE_MISC || defined __USE_ISOC9X |
152 | # define __inline_mathop(func, op) \ | |
153 | __inline_mathop_ (double, func, op) \ | |
154 | __inline_mathop_ (float, __CONCAT(func,f), op) \ | |
155 | __inline_mathop_ (long double, __CONCAT(func,l), op) | |
156 | #else | |
157 | # define __inline_mathop(func, op) \ | |
158 | __inline_mathop_ (double, func, op) | |
159 | #endif | |
b20e47cb | 160 | |
3996f34b UD |
161 | #define __inline_mathop_(float_type, func, op) \ |
162 | __inline_mathop_decl_ (float_type, func, op, "0" (__x)) | |
b20e47cb | 163 | |
b20e47cb | 164 | |
3996f34b UD |
165 | #if defined __USE_MISC || defined __USE_ISOC9X |
166 | # define __inline_mathop_decl(func, op, params...) \ | |
167 | __inline_mathop_decl_ (double, func, op, params) \ | |
168 | __inline_mathop_decl_ (float, __CONCAT(func,f), op, params) \ | |
169 | __inline_mathop_decl_ (long double, __CONCAT(func,l), op, params) | |
170 | #else | |
171 | # define __inline_mathop_decl(func, op, params...) \ | |
172 | __inline_mathop_decl_ (double, func, op, params) | |
173 | #endif | |
b20e47cb | 174 | |
3996f34b | 175 | #define __inline_mathop_decl_(float_type, func, op, params...) \ |
8f2ece69 UD |
176 | __MATH_INLINE float_type func (float_type); \ |
177 | __MATH_INLINE float_type func (float_type __x) \ | |
3996f34b UD |
178 | { \ |
179 | register float_type __result; \ | |
8f2ece69 | 180 | __asm __volatile__ (op : "=t" (__result) : params); \ |
3996f34b UD |
181 | return __result; \ |
182 | } | |
183 | ||
184 | ||
185 | #if defined __USE_MISC || defined __USE_ISOC9X | |
186 | # define __inline_mathcode(func, arg, code) \ | |
187 | __inline_mathcode_ (double, func, arg, code) \ | |
188 | __inline_mathcode_ (float, __CONCAT(func,f), arg, code) \ | |
189 | __inline_mathcode_ (long double, __CONCAT(func,l), arg, code) | |
1ea89a40 UD |
190 | # define __inline_mathcode2(func, arg1, arg2, code) \ |
191 | __inline_mathcode2_ (double, func, arg1, arg2, code) \ | |
192 | __inline_mathcode2_ (float, __CONCAT(func,f), arg1, arg2, code) \ | |
193 | __inline_mathcode2_ (long double, __CONCAT(func,l), arg1, arg2, code) | |
194 | # define __inline_mathcode3(func, arg1, arg2, arg3, code) \ | |
195 | __inline_mathcode3_ (double, func, arg1, arg2, arg3, code) \ | |
196 | __inline_mathcode3_ (float, __CONCAT(func,f), arg1, arg2, arg3, code) \ | |
197 | __inline_mathcode3_ (long double, __CONCAT(func,l), arg1, arg2, arg3, code) | |
3996f34b UD |
198 | #else |
199 | # define __inline_mathcode(func, arg, code) \ | |
1ea89a40 UD |
200 | __inline_mathcode_ (double, func, (arg), code) |
201 | # define __inline_mathcode2(func, arg1, arg2, code) \ | |
202 | __inline_mathcode2_ (double, func, arg1, arg2, code) | |
203 | # define __inline_mathcode3(func, arg1, arg2, arg3, code) \ | |
204 | __inline_mathcode3_ (double, func, arg1, arg2, arg3, code) | |
3996f34b | 205 | #endif |
b20e47cb | 206 | |
3996f34b UD |
207 | #define __inline_mathcode_(float_type, func, arg, code) \ |
208 | __MATH_INLINE float_type func (float_type); \ | |
209 | __MATH_INLINE float_type func (float_type arg) \ | |
210 | { \ | |
211 | code; \ | |
212 | } | |
b20e47cb | 213 | |
3996f34b UD |
214 | #define __inline_mathcode2_(float_type, func, arg1, arg2, code) \ |
215 | __MATH_INLINE float_type func (float_type, float_type); \ | |
216 | __MATH_INLINE float_type func (float_type arg1, float_type arg2) \ | |
217 | { \ | |
218 | code; \ | |
219 | } | |
220 | ||
1ea89a40 UD |
221 | #define __inline_mathcode3_(float_type, func, arg1, arg2, arg3, code) \ |
222 | __MATH_INLINE float_type func (float_type, float_type, float_type); \ | |
223 | __MATH_INLINE float_type func (float_type arg1, float_type arg2, \ | |
224 | float_type arg3) \ | |
225 | { \ | |
226 | code; \ | |
227 | } | |
f43ce637 | 228 | #endif |
1ea89a40 | 229 | |
3996f34b | 230 | |
f43ce637 | 231 | #if !defined __NO_MATH_INLINES && defined __OPTIMIZE__ |
f41c8091 UD |
232 | /* Miscellaneous functions */ |
233 | ||
234 | __inline_mathcode (__sgn, __x, \ | |
235 | return __x == 0.0 ? 0.0 : (__x > 0.0 ? 1.0 : -1.0)) | |
236 | ||
237 | __inline_mathcode (__pow2, __x, \ | |
238 | register long double __value; \ | |
239 | register long double __exponent; \ | |
7782d0bf | 240 | __extension__ long long int __p = (long long int) __x; \ |
f41c8091 UD |
241 | if (__x == (long double) __p) \ |
242 | { \ | |
243 | __asm __volatile__ \ | |
244 | ("fscale" \ | |
245 | : "=t" (__value) : "0" (1.0), "u" (__x)); \ | |
246 | return __value; \ | |
247 | } \ | |
248 | __asm __volatile__ \ | |
c0016081 | 249 | ("fld %%st(0)\n\t" \ |
f41c8091 UD |
250 | "frndint # int(x)\n\t" \ |
251 | "fxch\n\t" \ | |
252 | "fsub %%st(1) # fract(x)\n\t" \ | |
253 | "f2xm1 # 2^(fract(x)) - 1\n\t" \ | |
254 | : "=t" (__value), "=u" (__exponent) : "0" (__x)); \ | |
255 | __value += 1.0; \ | |
256 | __asm __volatile__ \ | |
257 | ("fscale" \ | |
258 | : "=t" (__value) : "0" (__value), "u" (__exponent)); \ | |
259 | return __value) | |
260 | ||
261 | #define __sincos_code \ | |
262 | register long double __cosr; \ | |
263 | register long double __sinr; \ | |
264 | __asm __volatile__ \ | |
265 | ("fsincos\n\t" \ | |
266 | "fnstsw %%ax\n\t" \ | |
267 | "testl $0x400, %%eax\n\t" \ | |
268 | "jz 1f\n\t" \ | |
269 | "fldpi\n\t" \ | |
270 | "fadd %%st(0)\n\t" \ | |
271 | "fxch %%st(1)\n\t" \ | |
272 | "2: fprem1\n\t" \ | |
273 | "fnstsw %%ax\n\t" \ | |
274 | "testl $0x400, %%eax\n\t" \ | |
275 | "jnz 2b\n\t" \ | |
276 | "fstp %%st(1)\n\t" \ | |
277 | "fsincos\n\t" \ | |
278 | "1:" \ | |
279 | : "=t" (__cosr), "=u" (__sinr) : "0" (__x)); \ | |
280 | *__sinx = __sinr; \ | |
281 | *__cosx = __cosr | |
282 | ||
283 | __MATH_INLINE void __sincos (double __x, double *__sinx, double *__cosx); | |
284 | __MATH_INLINE void | |
285 | __sincos (double __x, double *__sinx, double *__cosx) | |
286 | { | |
287 | __sincos_code; | |
288 | } | |
289 | ||
290 | __MATH_INLINE void __sincosf (float __x, float *__sinx, float *__cosx); | |
291 | __MATH_INLINE void | |
292 | __sincosf (float __x, float *__sinx, float *__cosx) | |
293 | { | |
294 | __sincos_code; | |
295 | } | |
296 | ||
297 | __MATH_INLINE void __sincosl (long double __x, long double *__sinx, | |
298 | long double *__cosx); | |
299 | __MATH_INLINE void | |
300 | __sincosl (long double __x, long double *__sinx, long double *__cosx) | |
301 | { | |
302 | __sincos_code; | |
303 | } | |
304 | ||
305 | ||
8f2ece69 | 306 | /* Optimized inline implementation, sometimes with reduced precision |
3996f34b | 307 | and/or argument range. */ |
8f2ece69 | 308 | |
3996f34b UD |
309 | #define __expm1_code \ |
310 | register long double __value; \ | |
311 | register long double __exponent; \ | |
312 | register long double __temp; \ | |
313 | __asm __volatile__ \ | |
314 | ("fldl2e # e^x - 1 = 2^(x * log2(e)) - 1\n\t" \ | |
315 | "fmul %%st(1) # x * log2(e)\n\t" \ | |
50304ef0 | 316 | "fst %%st(1)\n\t" \ |
3996f34b UD |
317 | "frndint # int(x * log2(e))\n\t" \ |
318 | "fxch\n\t" \ | |
319 | "fsub %%st(1) # fract(x * log2(e))\n\t" \ | |
320 | "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" \ | |
321 | "fscale # 2^(x * log2(e)) - 2^(int(x * log2(e)))\n\t" \ | |
322 | : "=t" (__value), "=u" (__exponent) : "0" (__x)); \ | |
323 | __asm __volatile__ \ | |
324 | ("fscale # 2^int(x * log2(e))\n\t" \ | |
325 | : "=t" (__temp) : "0" (1.0), "u" (__exponent)); \ | |
326 | __temp -= 1.0; \ | |
327 | return __temp + __value | |
328 | __inline_mathcode_ (long double, __expm1l, __x, __expm1_code) | |
329 | ||
330 | ||
331 | #define __exp_code \ | |
332 | register long double __value; \ | |
333 | register long double __exponent; \ | |
334 | __asm __volatile__ \ | |
335 | ("fldl2e # e^x = 2^(x * log2(e))\n\t" \ | |
336 | "fmul %%st(1) # x * log2(e)\n\t" \ | |
50304ef0 | 337 | "fst %%st(1)\n\t" \ |
3996f34b UD |
338 | "frndint # int(x * log2(e))\n\t" \ |
339 | "fxch\n\t" \ | |
340 | "fsub %%st(1) # fract(x * log2(e))\n\t" \ | |
341 | "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" \ | |
342 | : "=t" (__value), "=u" (__exponent) : "0" (__x)); \ | |
343 | __value += 1.0; \ | |
344 | __asm __volatile__ \ | |
345 | ("fscale" \ | |
346 | : "=t" (__value) : "0" (__value), "u" (__exponent)); \ | |
347 | return __value | |
348 | __inline_mathcode (exp, __x, __exp_code) | |
349 | __inline_mathcode_ (long double, __expl, __x, __exp_code) | |
350 | ||
351 | ||
352 | __inline_mathcode (tan, __x, \ | |
353 | register long double __value; \ | |
fa1f94fe | 354 | register long double __value2 __attribute__ ((__unused__)); \ |
3996f34b UD |
355 | __asm __volatile__ \ |
356 | ("fptan" \ | |
357 | : "=t" (__value2), "=u" (__value) : "0" (__x)); \ | |
358 | return __value) | |
359 | ||
360 | ||
361 | #define __atan2_code \ | |
362 | register long double __value; \ | |
363 | __asm __volatile__ \ | |
364 | ("fpatan\n\t" \ | |
365 | : "=t" (__value) : "0" (__x), "u" (__y) : "st(1)"); \ | |
366 | return __value | |
367 | __inline_mathcode2 (atan2, __y, __x, __atan2_code) | |
368 | __inline_mathcode2_ (long double, __atan2l, __y, __x, __atan2_code) | |
369 | ||
370 | ||
371 | __inline_mathcode2 (fmod, __x, __y, \ | |
372 | register long double __value; \ | |
373 | __asm __volatile__ \ | |
374 | ("1: fprem\n\t" \ | |
375 | "fnstsw %%ax\n\t" \ | |
376 | "sahf\n\t" \ | |
377 | "jp 1b" \ | |
378 | : "=t" (__value) : "0" (__x), "u" (__y) : "ax", "cc"); \ | |
379 | return __value) | |
380 | ||
381 | ||
382 | __inline_mathcode2 (pow, __x, __y, \ | |
383 | register long double __value; \ | |
384 | register long double __exponent; \ | |
7782d0bf | 385 | __extension__ long long int __p = (long long int) __y; \ |
3996f34b UD |
386 | if (__x == 0.0 && __y > 0.0) \ |
387 | return 0.0; \ | |
388 | if (__y == (double) __p) \ | |
389 | { \ | |
390 | long double __r = 1.0; \ | |
391 | if (__p == 0) \ | |
392 | return 1.0; \ | |
393 | if (__p < 0) \ | |
394 | { \ | |
395 | __p = -__p; \ | |
396 | __x = 1.0 / __x; \ | |
397 | } \ | |
398 | while (1) \ | |
399 | { \ | |
400 | if (__p & 1) \ | |
401 | __r *= __x; \ | |
402 | __p >>= 1; \ | |
403 | if (__p == 0) \ | |
404 | return __r; \ | |
405 | __x *= __x; \ | |
406 | } \ | |
407 | /* NOTREACHED */ \ | |
408 | } \ | |
409 | __asm __volatile__ \ | |
8f2ece69 | 410 | ("fyl2x" : "=t" (__value) : "0" (__x), "u" (1.0) : "st(1)"); \ |
3996f34b UD |
411 | __asm __volatile__ \ |
412 | ("fmul %%st(1) # y * log2(x)\n\t" \ | |
413 | "fst %%st(1)\n\t" \ | |
414 | "frndint # int(y * log2(x))\n\t" \ | |
415 | "fxch\n\t" \ | |
416 | "fsub %%st(1) # fract(y * log2(x))\n\t" \ | |
417 | "f2xm1 # 2^(fract(y * log2(x))) - 1\n\t" \ | |
418 | : "=t" (__value), "=u" (__exponent) : "0" (__y), "1" (__value)); \ | |
419 | __value += 1.0; \ | |
420 | __asm __volatile__ \ | |
421 | ("fscale" \ | |
422 | : "=t" (__value) : "0" (__value), "u" (__exponent)); \ | |
423 | return __value) | |
424 | ||
425 | ||
426 | __inline_mathop (sqrt, "fsqrt") | |
427 | __inline_mathop_ (long double, __sqrtl, "fsqrt") | |
428 | ||
4360eafd | 429 | #if __GNUC_PREREQ (2, 8) |
f41c8091 UD |
430 | __inline_mathcode_ (double, fabs, __x, return __builtin_fabs (__x)) |
431 | __inline_mathcode_ (float, fabsf, __x, return __builtin_fabsf (__x)) | |
432 | __inline_mathcode_ (long double, fabsl, __x, return __builtin_fabsl (__x)) | |
433 | __inline_mathcode_ (long double, __fabsl, __x, return __builtin_fabsl (__x)) | |
8f2ece69 | 434 | #else |
3996f34b | 435 | __inline_mathop (fabs, "fabs") |
8f2ece69 UD |
436 | __inline_mathop_ (long double, __fabsl, "fabs") |
437 | #endif | |
3996f34b UD |
438 | |
439 | /* The argument range of this inline version is reduced. */ | |
440 | __inline_mathop (sin, "fsin") | |
441 | /* The argument range of this inline version is reduced. */ | |
442 | __inline_mathop (cos, "fcos") | |
443 | ||
ca34d7a7 | 444 | __inline_mathop (atan, "fld1; fpatan") |
3996f34b UD |
445 | __inline_mathop (log, "fldln2; fxch; fyl2x") |
446 | __inline_mathop (log10, "fldlg2; fxch; fyl2x") | |
447 | ||
448 | __inline_mathcode (asin, __x, return __atan2l (__x, __sqrtl (1.0 - __x * __x))) | |
449 | __inline_mathcode (acos, __x, return __atan2l (__sqrtl (1.0 - __x * __x), __x)) | |
450 | ||
8f2ece69 | 451 | __inline_mathcode_ (long double, __sgn1l, __x, return __x >= 0.0 ? 1.0 : -1.0) |
3996f34b UD |
452 | |
453 | ||
454 | /* The argument range of the inline version of sinhl is slightly reduced. */ | |
455 | __inline_mathcode (sinh, __x, \ | |
8f2ece69 | 456 | register long double __exm1 = __expm1l (__fabsl (__x)); \ |
3996f34b UD |
457 | return 0.5 * (__exm1 / (__exm1 + 1.0) + __exm1) * __sgn1l (__x)) |
458 | ||
459 | __inline_mathcode (cosh, __x, \ | |
460 | register long double __ex = __expl (__x); \ | |
461 | return 0.5 * (__ex + 1.0 / __ex)) | |
462 | ||
463 | __inline_mathcode (tanh, __x, \ | |
8f2ece69 | 464 | register long double __exm1 = __expm1l (-__fabsl (__x + __x)); \ |
3996f34b UD |
465 | return __exm1 / (__exm1 + 2.0) * __sgn1l (-__x)) |
466 | ||
467 | ||
468 | __inline_mathcode (floor, __x, \ | |
469 | register long double __value; \ | |
470 | __volatile unsigned short int __cw; \ | |
471 | __volatile unsigned short int __cwtmp; \ | |
472 | __asm __volatile ("fnstcw %0" : "=m" (__cw)); \ | |
473 | __cwtmp = (__cw & 0xf3ff) | 0x0400; /* rounding down */ \ | |
474 | __asm __volatile ("fldcw %0" : : "m" (__cwtmp)); \ | |
475 | __asm __volatile ("frndint" : "=t" (__value) : "0" (__x)); \ | |
476 | __asm __volatile ("fldcw %0" : : "m" (__cw)); \ | |
477 | return __value) | |
478 | ||
479 | __inline_mathcode (ceil, __x, \ | |
480 | register long double __value; \ | |
481 | __volatile unsigned short int __cw; \ | |
482 | __volatile unsigned short int __cwtmp; \ | |
483 | __asm __volatile ("fnstcw %0" : "=m" (__cw)); \ | |
484 | __cwtmp = (__cw & 0xf3ff) | 0x0800; /* rounding up */ \ | |
485 | __asm __volatile ("fldcw %0" : : "m" (__cwtmp)); \ | |
486 | __asm __volatile ("frndint" : "=t" (__value) : "0" (__x)); \ | |
487 | __asm __volatile ("fldcw %0" : : "m" (__cw)); \ | |
488 | return __value) | |
b20e47cb | 489 | |
8f2ece69 UD |
490 | #define __ldexp_code \ |
491 | register long double __value; \ | |
492 | __asm __volatile__ \ | |
493 | ("fscale" \ | |
494 | : "=t" (__value) : "0" (__x), "u" ((long double) __y)); \ | |
495 | return __value | |
496 | ||
497 | __MATH_INLINE double ldexp (double __x, int __y); | |
498 | __MATH_INLINE double | |
499 | ldexp (double __x, int __y) | |
500 | { | |
501 | __ldexp_code; | |
502 | } | |
503 | ||
b20e47cb RM |
504 | |
505 | /* Optimized versions for some non-standardized functions. */ | |
7799b7b3 | 506 | #if defined __USE_ISOC9X || defined __USE_MISC |
b20e47cb | 507 | |
3996f34b | 508 | __inline_mathcode (expm1, __x, __expm1_code) |
b20e47cb | 509 | |
714a562f UD |
510 | /* We cannot rely on M_SQRT being defined. So we do it for ourself |
511 | here. */ | |
0a614877 | 512 | # define __M_SQRT2 1.41421356237309504880L /* sqrt(2) */ |
714a562f | 513 | |
3996f34b UD |
514 | __inline_mathcode (log1p, __x, \ |
515 | register long double __value; \ | |
8f2ece69 | 516 | if (__fabsl (__x) >= 1.0 - 0.5 * __M_SQRT2) \ |
3996f34b UD |
517 | __value = logl (1.0 + __x); \ |
518 | else \ | |
519 | __asm __volatile__ \ | |
520 | ("fldln2\n\t" \ | |
521 | "fxch\n\t" \ | |
522 | "fyl2xp1" \ | |
523 | : "=t" (__value) : "0" (__x)); \ | |
524 | return __value) | |
525 | ||
526 | ||
527 | /* The argument range of the inline version of asinhl is slightly reduced. */ | |
528 | __inline_mathcode (asinh, __x, \ | |
8f2ece69 | 529 | register long double __y = __fabsl (__x); \ |
3996f34b | 530 | return (log1pl (__y * __y / (__sqrtl (__y * __y + 1.0) + 1.0) + __y) \ |
ca34d7a7 | 531 | * __sgn1l (__x))) |
3996f34b UD |
532 | |
533 | __inline_mathcode (acosh, __x, \ | |
534 | return logl (__x + __sqrtl (__x - 1.0) * __sqrtl (__x + 1.0))) | |
535 | ||
536 | __inline_mathcode (atanh, __x, \ | |
8f2ece69 | 537 | register long double __y = __fabsl (__x); \ |
bd355af0 | 538 | return -0.5 * log1pl (-(__y + __y) / (1.0 + __y)) * __sgn1l (__x)) |
3996f34b | 539 | |
3996f34b UD |
540 | /* The argument range of the inline version of hypotl is slightly reduced. */ |
541 | __inline_mathcode2 (hypot, __x, __y, return __sqrtl (__x * __x + __y * __y)) | |
542 | ||
543 | __inline_mathcode(logb, __x, \ | |
544 | register long double __value; \ | |
545 | register long double __junk; \ | |
546 | __asm __volatile__ \ | |
547 | ("fxtract\n\t" \ | |
548 | : "=t" (__junk), "=u" (__value) : "0" (__x)); \ | |
549 | return __value) | |
550 | ||
7d6a8338 UD |
551 | #endif |
552 | ||
553 | #ifdef __USE_ISOC9X | |
554 | __inline_mathop(log2, "fld1; fxch; fyl2x") | |
555 | ||
8f2ece69 UD |
556 | __MATH_INLINE float ldexpf (float __x, int __y); |
557 | __MATH_INLINE float | |
558 | ldexpf (float __x, int __y) | |
559 | { | |
560 | __ldexp_code; | |
561 | } | |
562 | ||
563 | __MATH_INLINE long double ldexpl (long double __x, int __y); | |
564 | __MATH_INLINE long double | |
565 | ldexpl (long double __x, int __y) | |
566 | { | |
567 | __ldexp_code; | |
568 | } | |
3996f34b | 569 | |
1ea89a40 | 570 | __inline_mathcode3 (fma, __x, __y, __z, return (__x * __y) + __z) |
7d6a8338 UD |
571 | |
572 | __inline_mathop(rint, "frndint") | |
573 | ||
33127459 UD |
574 | #define __lrint_code \ |
575 | long int __lrintres; \ | |
576 | __asm__ __volatile__ \ | |
577 | ("fistpl %0" \ | |
578 | : "=m" (__lrintres) : "t" (__x) : "st"); \ | |
579 | return __lrintres | |
580 | __MATH_INLINE long int | |
581 | lrintf (float __x) | |
582 | { | |
583 | __lrint_code; | |
584 | } | |
585 | __MATH_INLINE long int | |
586 | lrint (double __x) | |
587 | { | |
588 | __lrint_code; | |
589 | } | |
590 | __MATH_INLINE long int | |
591 | lrintl (long double __x) | |
592 | { | |
593 | __lrint_code; | |
594 | } | |
595 | #undef __lrint_code | |
596 | ||
597 | #define __llrint_code \ | |
598 | long long int __llrintres; \ | |
599 | __asm__ __volatile__ \ | |
600 | ("fistpll %0" \ | |
601 | : "=m" (__llrintres) : "t" (__x) : "st"); \ | |
602 | return __llrintres | |
603 | __MATH_INLINE long long int | |
604 | llrintf (float __x) | |
605 | { | |
606 | __llrint_code; | |
607 | } | |
608 | __MATH_INLINE long long int | |
609 | llrint (double __x) | |
610 | { | |
611 | __llrint_code; | |
612 | } | |
613 | __MATH_INLINE long long int | |
614 | llrintl (long double __x) | |
615 | { | |
616 | __llrint_code; | |
617 | } | |
618 | #undef __llrint_code | |
619 | ||
cd6ede75 UD |
620 | #endif |
621 | ||
b20e47cb | 622 | |
cd6ede75 | 623 | #ifdef __USE_MISC |
8f2ece69 | 624 | |
3996f34b UD |
625 | __inline_mathcode2 (drem, __x, __y, \ |
626 | register double __value; \ | |
33127459 | 627 | register int __clobbered; \ |
3996f34b UD |
628 | __asm __volatile__ \ |
629 | ("1: fprem1\n\t" \ | |
630 | "fstsw %%ax\n\t" \ | |
631 | "sahf\n\t" \ | |
632 | "jp 1b" \ | |
33127459 | 633 | : "=t" (__value), "=&a" (__clobbered) : "0" (__x), "u" (__y) : "cc"); \ |
3996f34b UD |
634 | return __value) |
635 | ||
b20e47cb | 636 | |
7799b7b3 | 637 | /* This function is used in the `isfinite' macro. */ |
bd355af0 | 638 | __MATH_INLINE int __finite (double __x) __attribute__ ((__const__)); |
7799b7b3 UD |
639 | __MATH_INLINE int |
640 | __finite (double __x) | |
641 | { | |
db24ce47 | 642 | return (__extension__ |
69bf5f75 | 643 | (((((union { double __d; int __i[2]; }) {__d: __x}).__i[1] |
db24ce47 | 644 | | 0x800fffff) + 1) >> 31)); |
7799b7b3 | 645 | } |
dd33e89f | 646 | |
3996f34b UD |
647 | /* Miscellaneous functions */ |
648 | ||
3996f34b | 649 | __inline_mathcode (__coshm1, __x, \ |
8f2ece69 | 650 | register long double __exm1 = __expm1l (__fabsl (__x)); \ |
3996f34b UD |
651 | return 0.5 * (__exm1 / (__exm1 + 1.0)) * __exm1) |
652 | ||
653 | __inline_mathcode (__acosh1p, __x, \ | |
654 | return log1pl (__x + __sqrtl (__x) * __sqrtl (__x + 2.0))) | |
655 | ||
b20e47cb RM |
656 | #endif /* __USE_MISC */ |
657 | ||
3996f34b UD |
658 | /* Undefine some of the large macros which are not used anymore. */ |
659 | #undef __expm1_code | |
660 | #undef __exp_code | |
661 | #undef __atan2_code | |
662 | #undef __sincos_code | |
663 | ||
b20e47cb | 664 | #endif /* __NO_MATH_INLINES */ |
f43ce637 UD |
665 | |
666 | ||
667 | /* This code is used internally in the GNU libc. */ | |
f43ce637 UD |
668 | #ifdef __LIBC_INTERNAL_MATH_INLINES |
669 | __inline_mathop (__ieee754_sqrt, "fsqrt") | |
bd355af0 UD |
670 | __inline_mathcode2 (__ieee754_atan2, __y, __x, |
671 | register long double __value; | |
672 | __asm __volatile__ ("fpatan\n\t" | |
673 | : "=t" (__value) | |
674 | : "0" (__x), "u" (__y) : "st(1)"); | |
675 | return __value;) | |
f43ce637 UD |
676 | #endif |
677 | ||
b20e47cb | 678 | #endif /* __GNUC__ */ |