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