]>
Commit | Line | Data |
---|---|---|
b20e47cb | 1 | /* Inline math functions for i387. |
a334319f | 2 | Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004 |
3dbfd811 | 3 | Free Software Foundation, Inc. |
f8b87ef0 | 4 | This file is part of the GNU C Library. |
3996f34b | 5 | Contributed by John C. Bowman <bowman@math.ualberta.ca>, 1995. |
b20e47cb | 6 | |
f8b87ef0 | 7 | The GNU C Library is free software; you can redistribute it and/or |
41bdb6e2 AJ |
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. | |
b20e47cb | 11 | |
f8b87ef0 UD |
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 | |
41bdb6e2 | 15 | Lesser General Public License for more details. |
b20e47cb | 16 | |
41bdb6e2 AJ |
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. */ | |
b20e47cb | 21 | |
61eb22d3 UD |
22 | #ifndef _MATH_H |
23 | # error "Never use <bits/mathinline.h> directly; include <math.h> instead." | |
24 | #endif | |
f8b87ef0 | 25 | |
f43ce637 UD |
26 | #ifdef __cplusplus |
27 | # define __MATH_INLINE __inline | |
28 | #else | |
29 | # define __MATH_INLINE extern __inline | |
30 | #endif | |
31 | ||
cd6ede75 | 32 | |
ec751a23 | 33 | #if defined __USE_ISOC99 && defined __GNUC__ && __GNUC__ >= 2 |
a720a3ac | 34 | /* GCC 2.97 and up have builtins that actually can be used. */ |
f4c024d1 | 35 | # if !__GNUC_PREREQ (2,97) |
ec751a23 | 36 | /* ISO C99 defines some macros to perform unordered comparisons. The |
cd6ede75 UD |
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. */ | |
f4c024d1 UD |
40 | # undef isgreater |
41 | # undef isgreaterequal | |
42 | # undef isless | |
43 | # undef islessequal | |
44 | # undef islessgreater | |
45 | # undef isunordered | |
a720a3ac | 46 | # ifdef __i686__ |
f43ce637 UD |
47 | /* For the PentiumPro and more recent processors we can provide |
48 | better code. */ | |
a720a3ac | 49 | # define isgreater(x, y) \ |
f43ce637 | 50 | ({ register char __result; \ |
d111572f | 51 | __asm__ ("fucomip %%st(1), %%st; seta %%al" \ |
f43ce637 UD |
52 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \ |
53 | __result; }) | |
a720a3ac | 54 | # define isgreaterequal(x, y) \ |
f43ce637 | 55 | ({ register char __result; \ |
d111572f | 56 | __asm__ ("fucomip %%st(1), %%st; setae %%al" \ |
f43ce637 UD |
57 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \ |
58 | __result; }) | |
59 | ||
a720a3ac | 60 | # define isless(x, y) \ |
f43ce637 | 61 | ({ register char __result; \ |
d111572f UD |
62 | __asm__ ("fucomip %%st(1), %%st; seta %%al" \ |
63 | : "=a" (__result) : "u" (x), "t" (y) : "cc", "st"); \ | |
f43ce637 UD |
64 | __result; }) |
65 | ||
a720a3ac | 66 | # define islessequal(x, y) \ |
f43ce637 | 67 | ({ register char __result; \ |
d111572f UD |
68 | __asm__ ("fucomip %%st(1), %%st; setae %%al" \ |
69 | : "=a" (__result) : "u" (x), "t" (y) : "cc", "st"); \ | |
f43ce637 UD |
70 | __result; }) |
71 | ||
a720a3ac | 72 | # define islessgreater(x, y) \ |
f43ce637 | 73 | ({ register char __result; \ |
d111572f | 74 | __asm__ ("fucomip %%st(1), %%st; setne %%al" \ |
f43ce637 UD |
75 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \ |
76 | __result; }) | |
77 | ||
a720a3ac | 78 | # define isunordered(x, y) \ |
f43ce637 | 79 | ({ register char __result; \ |
d111572f | 80 | __asm__ ("fucomip %%st(1), %%st; setp %%al" \ |
f43ce637 UD |
81 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \ |
82 | __result; }) | |
a720a3ac | 83 | # else |
f43ce637 | 84 | /* This is the dumb, portable code for i386 and above. */ |
a720a3ac | 85 | # define isgreater(x, y) \ |
9a0a462c | 86 | ({ register char __result; \ |
f43ce637 | 87 | __asm__ ("fucompp; fnstsw; testb $0x45, %%ah; setz %%al" \ |
3996f34b UD |
88 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \ |
89 | __result; }) | |
cd6ede75 | 90 | |
a720a3ac | 91 | # define isgreaterequal(x, y) \ |
9a0a462c | 92 | ({ register char __result; \ |
f43ce637 | 93 | __asm__ ("fucompp; fnstsw; testb $0x05, %%ah; setz %%al" \ |
3996f34b UD |
94 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \ |
95 | __result; }) | |
cd6ede75 | 96 | |
a720a3ac | 97 | # define isless(x, y) \ |
9a0a462c | 98 | ({ register char __result; \ |
d111572f UD |
99 | __asm__ ("fucompp; fnstsw; testb $0x45, %%ah; setz %%al" \ |
100 | : "=a" (__result) : "u" (x), "t" (y) : "cc", "st", "st(1)"); \ | |
3996f34b | 101 | __result; }) |
cd6ede75 | 102 | |
a720a3ac | 103 | # define islessequal(x, y) \ |
9a0a462c | 104 | ({ register char __result; \ |
d111572f UD |
105 | __asm__ ("fucompp; fnstsw; testb $0x05, %%ah; setz %%al" \ |
106 | : "=a" (__result) : "u" (x), "t" (y) : "cc", "st", "st(1)"); \ | |
3996f34b | 107 | __result; }) |
cd6ede75 | 108 | |
a720a3ac | 109 | # define islessgreater(x, y) \ |
9a0a462c | 110 | ({ register char __result; \ |
f43ce637 | 111 | __asm__ ("fucompp; fnstsw; testb $0x44, %%ah; setz %%al" \ |
3996f34b UD |
112 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \ |
113 | __result; }) | |
cd6ede75 | 114 | |
a720a3ac | 115 | # define isunordered(x, y) \ |
9a0a462c UD |
116 | ({ register char __result; \ |
117 | __asm__ ("fucompp; fnstsw; sahf; setp %%al" \ | |
3996f34b UD |
118 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \ |
119 | __result; }) | |
a720a3ac UD |
120 | # endif /* __i686__ */ |
121 | # endif /* GCC 2.97 */ | |
cd6ede75 | 122 | |
090d93cd UD |
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. */ | |
655c0697 | 125 | # if __GNUC_PREREQ (2, 8) |
f43ce637 UD |
126 | /* Test for negative number. Used in the signbit() macro. */ |
127 | __MATH_INLINE int | |
f377d022 | 128 | __NTH (__signbitf (float __x)) |
f43ce637 | 129 | { |
e150fddc | 130 | __extension__ union { float __f; int __i; } __u = { __f: __x }; |
fc370352 | 131 | return __u.__i < 0; |
f43ce637 UD |
132 | } |
133 | __MATH_INLINE int | |
f377d022 | 134 | __NTH (__signbit (double __x)) |
f43ce637 | 135 | { |
e150fddc | 136 | __extension__ union { double __d; int __i[2]; } __u = { __d: __x }; |
fc370352 | 137 | return __u.__i[1] < 0; |
f43ce637 UD |
138 | } |
139 | __MATH_INLINE int | |
f377d022 | 140 | __NTH (__signbitl (long double __x)) |
f43ce637 | 141 | { |
e150fddc | 142 | __extension__ union { long double __l; int __i[3]; } __u = { __l: __x }; |
f43ce637 UD |
143 | return (__u.__i[2] & 0x8000) != 0; |
144 | } | |
090d93cd | 145 | # endif |
f43ce637 | 146 | #endif |
cd6ede75 | 147 | |
b20e47cb | 148 | |
f41c8091 UD |
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. */ | |
4360eafd | 151 | #if __GNUC_PREREQ (2, 8) |
f41c8091 | 152 | |
f43ce637 UD |
153 | #if ((!defined __NO_MATH_INLINES || defined __LIBC_INTERNAL_MATH_INLINES) \ |
154 | && defined __OPTIMIZE__) | |
b20e47cb | 155 | |
3996f34b UD |
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, | |
300583a7 UD |
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. */ | |
b20e47cb | 162 | |
ec751a23 | 163 | #if defined __USE_MISC || defined __USE_ISOC99 |
3996f34b UD |
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) | |
300583a7 UD |
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) | |
3996f34b UD |
172 | #else |
173 | # define __inline_mathop(func, op) \ | |
174 | __inline_mathop_ (double, func, op) | |
300583a7 UD |
175 | # define __inline_mathopNP(func, op) \ |
176 | __inline_mathopNP_ (double, func, op) | |
3996f34b | 177 | #endif |
b20e47cb | 178 | |
3996f34b UD |
179 | #define __inline_mathop_(float_type, func, op) \ |
180 | __inline_mathop_decl_ (float_type, func, op, "0" (__x)) | |
300583a7 UD |
181 | #define __inline_mathopNP_(float_type, func, op) \ |
182 | __inline_mathop_declNP_ (float_type, func, op, "0" (__x)) | |
b20e47cb | 183 | |
b20e47cb | 184 | |
ec751a23 | 185 | #if defined __USE_MISC || defined __USE_ISOC99 |
3996f34b UD |
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) | |
300583a7 UD |
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) | |
3996f34b UD |
194 | #else |
195 | # define __inline_mathop_decl(func, op, params...) \ | |
196 | __inline_mathop_decl_ (double, func, op, params) | |
300583a7 UD |
197 | # define __inline_mathop_declNP(func, op, params...) \ |
198 | __inline_mathop_declNP_ (double, func, op, params) | |
3996f34b | 199 | #endif |
b20e47cb | 200 | |
3996f34b | 201 | #define __inline_mathop_decl_(float_type, func, op, params...) \ |
cc46c92d | 202 | __MATH_INLINE float_type func (float_type) __THROW; \ |
300583a7 UD |
203 | __inline_mathop_declNP_ (float_type, func, op, params) |
204 | ||
205 | #define __inline_mathop_declNP_(float_type, func, op, params...) \ | |
f377d022 | 206 | __MATH_INLINE float_type __NTH (func (float_type __x)) \ |
3996f34b UD |
207 | { \ |
208 | register float_type __result; \ | |
8f2ece69 | 209 | __asm __volatile__ (op : "=t" (__result) : params); \ |
3996f34b UD |
210 | return __result; \ |
211 | } | |
212 | ||
213 | ||
ec751a23 | 214 | #if defined __USE_MISC || defined __USE_ISOC99 |
3996f34b UD |
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) | |
300583a7 | 219 | # define __inline_mathcodeNP(func, arg, code) \ |
3dbfd811 | 220 | __inline_mathcodeNP_ (double, func, arg, code) \ |
300583a7 UD |
221 | __inline_mathcodeNP_ (float, __CONCAT(func,f), arg, code) \ |
222 | __inline_mathcodeNP_ (long double, __CONCAT(func,l), arg, code) | |
1ea89a40 UD |
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) | |
300583a7 | 227 | # define __inline_mathcodeNP2(func, arg1, arg2, code) \ |
3dbfd811 | 228 | __inline_mathcodeNP2_ (double, func, arg1, arg2, code) \ |
300583a7 UD |
229 | __inline_mathcodeNP2_ (float, __CONCAT(func,f), arg1, arg2, code) \ |
230 | __inline_mathcodeNP2_ (long double, __CONCAT(func,l), arg1, arg2, code) | |
1ea89a40 UD |
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) | |
300583a7 UD |
235 | # define __inline_mathcodeNP3(func, arg1, arg2, arg3, code) \ |
236 | __inline_mathcodeNP3_ (double, func, arg1, arg2, arg3, code) \ | |
3dbfd811 | 237 | __inline_mathcodeNP3_ (float, __CONCAT(func,f), arg1, arg2, arg3, code) \ |
300583a7 | 238 | __inline_mathcodeNP3_ (long double, __CONCAT(func,l), arg1, arg2, arg3, code) |
3996f34b UD |
239 | #else |
240 | # define __inline_mathcode(func, arg, code) \ | |
1ea89a40 | 241 | __inline_mathcode_ (double, func, (arg), code) |
300583a7 UD |
242 | # define __inline_mathcodeNP(func, arg, code) \ |
243 | __inline_mathcodeNP_ (double, func, (arg), code) | |
1ea89a40 UD |
244 | # define __inline_mathcode2(func, arg1, arg2, code) \ |
245 | __inline_mathcode2_ (double, func, arg1, arg2, code) | |
300583a7 UD |
246 | # define __inline_mathcodeNP2(func, arg1, arg2, code) \ |
247 | __inline_mathcodeNP2_ (double, func, arg1, arg2, code) | |
1ea89a40 UD |
248 | # define __inline_mathcode3(func, arg1, arg2, arg3, code) \ |
249 | __inline_mathcode3_ (double, func, arg1, arg2, arg3, code) | |
300583a7 UD |
250 | # define __inline_mathcodeNP3(func, arg1, arg2, arg3, code) \ |
251 | __inline_mathcodeNP3_ (double, func, arg1, arg2, arg3, code) | |
3996f34b | 252 | #endif |
b20e47cb | 253 | |
3996f34b | 254 | #define __inline_mathcode_(float_type, func, arg, code) \ |
cc46c92d | 255 | __MATH_INLINE float_type func (float_type) __THROW; \ |
300583a7 UD |
256 | __inline_mathcodeNP_(float_type, func, arg, code) |
257 | ||
258 | #define __inline_mathcodeNP_(float_type, func, arg, code) \ | |
f377d022 | 259 | __MATH_INLINE float_type __NTH (func (float_type arg)) \ |
3996f34b UD |
260 | { \ |
261 | code; \ | |
262 | } | |
b20e47cb | 263 | |
300583a7 | 264 | |
3996f34b | 265 | #define __inline_mathcode2_(float_type, func, arg1, arg2, code) \ |
cc46c92d | 266 | __MATH_INLINE float_type func (float_type, float_type) __THROW; \ |
300583a7 UD |
267 | __inline_mathcodeNP2_ (float_type, func, arg1, arg2, code) |
268 | ||
269 | #define __inline_mathcodeNP2_(float_type, func, arg1, arg2, code) \ | |
f377d022 | 270 | __MATH_INLINE float_type __NTH (func (float_type arg1, float_type arg2)) \ |
3996f34b UD |
271 | { \ |
272 | code; \ | |
273 | } | |
274 | ||
1ea89a40 | 275 | #define __inline_mathcode3_(float_type, func, arg1, arg2, arg3, code) \ |
cc46c92d | 276 | __MATH_INLINE float_type func (float_type, float_type, float_type) __THROW; \ |
300583a7 UD |
277 | __inline_mathcodeNP3_(float_type, func, arg1, arg2, arg3, code) |
278 | ||
279 | #define __inline_mathcodeNP3_(float_type, func, arg1, arg2, arg3, code) \ | |
f377d022 UD |
280 | __MATH_INLINE float_type __NTH (func (float_type arg1, float_type arg2, \ |
281 | float_type arg3)) \ | |
1ea89a40 UD |
282 | { \ |
283 | code; \ | |
284 | } | |
f43ce637 | 285 | #endif |
1ea89a40 | 286 | |
3996f34b | 287 | |
f43ce637 | 288 | #if !defined __NO_MATH_INLINES && defined __OPTIMIZE__ |
f41c8091 UD |
289 | /* Miscellaneous functions */ |
290 | ||
291 | __inline_mathcode (__sgn, __x, \ | |
292 | return __x == 0.0 ? 0.0 : (__x > 0.0 ? 1.0 : -1.0)) | |
293 | ||
378fbeb4 UD |
294 | /* __FAST_MATH__ is defined by gcc -ffast-math. */ |
295 | #ifdef __FAST_MATH__ | |
f41c8091 UD |
296 | __inline_mathcode (__pow2, __x, \ |
297 | register long double __value; \ | |
298 | register long double __exponent; \ | |
7782d0bf | 299 | __extension__ long long int __p = (long long int) __x; \ |
f41c8091 UD |
300 | if (__x == (long double) __p) \ |
301 | { \ | |
302 | __asm __volatile__ \ | |
303 | ("fscale" \ | |
304 | : "=t" (__value) : "0" (1.0), "u" (__x)); \ | |
305 | return __value; \ | |
306 | } \ | |
307 | __asm __volatile__ \ | |
c0016081 | 308 | ("fld %%st(0)\n\t" \ |
f41c8091 UD |
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) | |
319 | ||
378fbeb4 UD |
320 | # ifdef __USE_GNU |
321 | # define __sincos_code \ | |
f41c8091 UD |
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 | |
342 | ||
f41c8091 | 343 | __MATH_INLINE void |
f377d022 | 344 | __NTH (__sincos (double __x, double *__sinx, double *__cosx)) |
f41c8091 UD |
345 | { |
346 | __sincos_code; | |
347 | } | |
348 | ||
f41c8091 | 349 | __MATH_INLINE void |
f377d022 | 350 | __NTH (__sincosf (float __x, float *__sinx, float *__cosx)) |
f41c8091 UD |
351 | { |
352 | __sincos_code; | |
353 | } | |
354 | ||
f41c8091 | 355 | __MATH_INLINE void |
f377d022 | 356 | __NTH (__sincosl (long double __x, long double *__sinx, long double *__cosx)) |
f41c8091 UD |
357 | { |
358 | __sincos_code; | |
359 | } | |
378fbeb4 | 360 | # endif |
f41c8091 UD |
361 | |
362 | ||
8f2ece69 | 363 | /* Optimized inline implementation, sometimes with reduced precision |
3996f34b | 364 | and/or argument range. */ |
8f2ece69 | 365 | |
3dbfd811 UD |
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 \ | |
3996f34b UD |
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" \ | |
50304ef0 | 379 | "fst %%st(1)\n\t" \ |
3996f34b UD |
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; \ | |
4e142297 RM |
390 | __temp += __value; \ |
391 | return __temp ? __temp : __x | |
3dbfd811 | 392 | # endif |
300583a7 | 393 | __inline_mathcodeNP_ (long double, __expm1l, __x, __expm1_code) |
3996f34b | 394 | |
3dbfd811 UD |
395 | # if __GNUC_PREREQ (3, 4) |
396 | __inline_mathcodeNP_ (long double, __expl, __x, return __builtin_expl (__x)) | |
397 | # else | |
398 | # define __exp_code \ | |
3996f34b UD |
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" \ | |
50304ef0 | 404 | "fst %%st(1)\n\t" \ |
3996f34b UD |
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 | |
300583a7 UD |
415 | __inline_mathcodeNP (exp, __x, __exp_code) |
416 | __inline_mathcodeNP_ (long double, __expl, __x, __exp_code) | |
3dbfd811 | 417 | # endif |
3996f34b UD |
418 | |
419 | ||
3dbfd811 | 420 | # if !__GNUC_PREREQ (3, 5) |
300583a7 | 421 | __inline_mathcodeNP (tan, __x, \ |
3996f34b | 422 | register long double __value; \ |
fa1f94fe | 423 | register long double __value2 __attribute__ ((__unused__)); \ |
3996f34b UD |
424 | __asm __volatile__ \ |
425 | ("fptan" \ | |
426 | : "=t" (__value2), "=u" (__value) : "0" (__x)); \ | |
427 | return __value) | |
3dbfd811 | 428 | # endif |
378fbeb4 UD |
429 | #endif /* __FAST_MATH__ */ |
430 | ||
431 | ||
3dbfd811 UD |
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 \ | |
378fbeb4 UD |
437 | register long double __value; \ |
438 | __asm __volatile__ \ | |
439 | ("fpatan" \ | |
440 | : "=t" (__value) : "0" (__x), "u" (__y) : "st(1)"); \ | |
441 | return __value | |
3dbfd811 | 442 | # ifdef __FAST_MATH__ |
378fbeb4 | 443 | __inline_mathcodeNP2 (atan2, __y, __x, __atan2_code) |
3dbfd811 | 444 | # endif |
378fbeb4 | 445 | __inline_mathcodeNP2_ (long double, __atan2l, __y, __x, __atan2_code) |
3dbfd811 | 446 | #endif |
378fbeb4 UD |
447 | |
448 | ||
3dbfd811 | 449 | #if defined __FAST_MATH__ && !__GNUC_PREREQ (3, 5) |
378fbeb4 UD |
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) | |
3dbfd811 | 459 | #endif |
3996f34b UD |
460 | |
461 | ||
dfb87dc8 | 462 | #ifdef __FAST_MATH__ |
6d316b07 | 463 | # if !__GNUC_PREREQ (3,3) |
300583a7 UD |
464 | __inline_mathopNP (sqrt, "fsqrt") |
465 | __inline_mathopNP_ (long double, __sqrtl, "fsqrt") | |
0135bde4 UD |
466 | # define __libc_sqrtl(n) __sqrtl (n) |
467 | # else | |
468 | # define __libc_sqrtl(n) __builtin_sqrtl (n) | |
6d316b07 | 469 | # endif |
dfb87dc8 | 470 | #endif |
3996f34b | 471 | |
4360eafd | 472 | #if __GNUC_PREREQ (2, 8) |
300583a7 | 473 | __inline_mathcodeNP_ (double, fabs, __x, return __builtin_fabs (__x)) |
3dbfd811 | 474 | # if defined __USE_MISC || defined __USE_ISOC99 |
300583a7 UD |
475 | __inline_mathcodeNP_ (float, fabsf, __x, return __builtin_fabsf (__x)) |
476 | __inline_mathcodeNP_ (long double, fabsl, __x, return __builtin_fabsl (__x)) | |
3dbfd811 | 477 | # endif |
300583a7 | 478 | __inline_mathcodeNP_ (long double, __fabsl, __x, return __builtin_fabsl (__x)) |
8f2ece69 | 479 | #else |
3996f34b | 480 | __inline_mathop (fabs, "fabs") |
8f2ece69 UD |
481 | __inline_mathop_ (long double, __fabsl, "fabs") |
482 | #endif | |
3996f34b | 483 | |
378fbeb4 | 484 | #ifdef __FAST_MATH__ |
3dbfd811 | 485 | # if !__GNUC_PREREQ (3, 4) |
3996f34b | 486 | /* The argument range of this inline version is reduced. */ |
300583a7 | 487 | __inline_mathopNP (sin, "fsin") |
3996f34b | 488 | /* The argument range of this inline version is reduced. */ |
300583a7 | 489 | __inline_mathopNP (cos, "fcos") |
3996f34b | 490 | |
300583a7 | 491 | __inline_mathop_declNP (log, "fldln2; fxch; fyl2x", "0" (__x) : "st(1)") |
3dbfd811 UD |
492 | # endif |
493 | ||
494 | # if !__GNUC_PREREQ (3, 5) | |
300583a7 | 495 | __inline_mathop_declNP (log10, "fldlg2; fxch; fyl2x", "0" (__x) : "st(1)") |
3996f34b | 496 | |
0135bde4 UD |
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)) | |
3dbfd811 | 499 | # endif |
378fbeb4 | 500 | |
3dbfd811 | 501 | # if !__GNUC_PREREQ (3, 4) |
378fbeb4 | 502 | __inline_mathop_declNP (atan, "fld1; fpatan", "0" (__x) : "st(1)") |
3dbfd811 UD |
503 | # endif |
504 | #endif /* __FAST_MATH__ */ | |
3996f34b | 505 | |
15daa639 | 506 | __inline_mathcode_ (long double, __sgn1l, __x, \ |
2caacb0a | 507 | __extension__ union { long double __xld; unsigned int __xi[3]; } __n = \ |
e150fddc | 508 | { __xld: __x }; \ |
15daa639 UD |
509 | __n.__xi[2] = (__n.__xi[2] & 0x8000) | 0x3fff; \ |
510 | __n.__xi[1] = 0x80000000; \ | |
511 | __n.__xi[0] = 0; \ | |
512 | return __n.__xld) | |
3996f34b UD |
513 | |
514 | ||
1dd54850 | 515 | #ifdef __FAST_MATH__ |
3996f34b | 516 | /* The argument range of the inline version of sinhl is slightly reduced. */ |
300583a7 | 517 | __inline_mathcodeNP (sinh, __x, \ |
8f2ece69 | 518 | register long double __exm1 = __expm1l (__fabsl (__x)); \ |
3996f34b UD |
519 | return 0.5 * (__exm1 / (__exm1 + 1.0) + __exm1) * __sgn1l (__x)) |
520 | ||
300583a7 | 521 | __inline_mathcodeNP (cosh, __x, \ |
3996f34b UD |
522 | register long double __ex = __expl (__x); \ |
523 | return 0.5 * (__ex + 1.0 / __ex)) | |
524 | ||
300583a7 | 525 | __inline_mathcodeNP (tanh, __x, \ |
8f2ece69 | 526 | register long double __exm1 = __expm1l (-__fabsl (__x + __x)); \ |
3996f34b | 527 | return __exm1 / (__exm1 + 2.0) * __sgn1l (-__x)) |
1dd54850 | 528 | #endif |
3996f34b | 529 | |
300583a7 | 530 | __inline_mathcodeNP (floor, __x, \ |
3996f34b | 531 | register long double __value; \ |
a334319f UD |
532 | __volatile unsigned short int __cw; \ |
533 | __volatile unsigned short int __cwtmp; \ | |
534 | __asm __volatile ("fnstcw %0" : "=m" (__cw)); \ | |
535 | __cwtmp = (__cw & 0xf3ff) | 0x0400; /* rounding down */ \ | |
536 | __asm __volatile ("fldcw %0" : : "m" (__cwtmp)); \ | |
537 | __asm __volatile ("frndint" : "=t" (__value) : "0" (__x)); \ | |
538 | __asm __volatile ("fldcw %0" : : "m" (__cw)); \ | |
3996f34b UD |
539 | return __value) |
540 | ||
300583a7 | 541 | __inline_mathcodeNP (ceil, __x, \ |
3996f34b | 542 | register long double __value; \ |
a334319f UD |
543 | __volatile unsigned short int __cw; \ |
544 | __volatile unsigned short int __cwtmp; \ | |
545 | __asm __volatile ("fnstcw %0" : "=m" (__cw)); \ | |
546 | __cwtmp = (__cw & 0xf3ff) | 0x0800; /* rounding up */ \ | |
547 | __asm __volatile ("fldcw %0" : : "m" (__cwtmp)); \ | |
548 | __asm __volatile ("frndint" : "=t" (__value) : "0" (__x)); \ | |
549 | __asm __volatile ("fldcw %0" : : "m" (__cw)); \ | |
3996f34b | 550 | return __value) |
b20e47cb | 551 | |
dfb87dc8 UD |
552 | #ifdef __FAST_MATH__ |
553 | # define __ldexp_code \ | |
8f2ece69 UD |
554 | register long double __value; \ |
555 | __asm __volatile__ \ | |
556 | ("fscale" \ | |
557 | : "=t" (__value) : "0" (__x), "u" ((long double) __y)); \ | |
558 | return __value | |
559 | ||
8f2ece69 | 560 | __MATH_INLINE double |
f377d022 | 561 | __NTH (ldexp (double __x, int __y)) |
8f2ece69 UD |
562 | { |
563 | __ldexp_code; | |
564 | } | |
dfb87dc8 | 565 | #endif |
8f2ece69 | 566 | |
b20e47cb RM |
567 | |
568 | /* Optimized versions for some non-standardized functions. */ | |
ec751a23 | 569 | #if defined __USE_ISOC99 || defined __USE_MISC |
b20e47cb | 570 | |
81e43fc1 | 571 | # ifdef __FAST_MATH__ |
300583a7 | 572 | __inline_mathcodeNP (expm1, __x, __expm1_code) |
b20e47cb | 573 | |
714a562f UD |
574 | /* We cannot rely on M_SQRT being defined. So we do it for ourself |
575 | here. */ | |
35915ec8 | 576 | # define __M_SQRT2 1.41421356237309504880L /* sqrt(2) */ |
714a562f | 577 | |
3dbfd811 | 578 | # if !__GNUC_PREREQ (3, 5) |
300583a7 | 579 | __inline_mathcodeNP (log1p, __x, \ |
3996f34b | 580 | register long double __value; \ |
8f2ece69 | 581 | if (__fabsl (__x) >= 1.0 - 0.5 * __M_SQRT2) \ |
3996f34b UD |
582 | __value = logl (1.0 + __x); \ |
583 | else \ | |
584 | __asm __volatile__ \ | |
585 | ("fldln2\n\t" \ | |
586 | "fxch\n\t" \ | |
587 | "fyl2xp1" \ | |
5892e305 | 588 | : "=t" (__value) : "0" (__x) : "st(1)"); \ |
3996f34b | 589 | return __value) |
3dbfd811 | 590 | # endif |
3996f34b UD |
591 | |
592 | ||
593 | /* The argument range of the inline version of asinhl is slightly reduced. */ | |
300583a7 | 594 | __inline_mathcodeNP (asinh, __x, \ |
8f2ece69 | 595 | register long double __y = __fabsl (__x); \ |
0135bde4 | 596 | return (log1pl (__y * __y / (__libc_sqrtl (__y * __y + 1.0) + 1.0) + __y) \ |
ca34d7a7 | 597 | * __sgn1l (__x))) |
3996f34b | 598 | |
300583a7 | 599 | __inline_mathcodeNP (acosh, __x, \ |
0135bde4 | 600 | return logl (__x + __libc_sqrtl (__x - 1.0) * __libc_sqrtl (__x + 1.0))) |
3996f34b | 601 | |
300583a7 | 602 | __inline_mathcodeNP (atanh, __x, \ |
8f2ece69 | 603 | register long double __y = __fabsl (__x); \ |
bd355af0 | 604 | return -0.5 * log1pl (-(__y + __y) / (1.0 + __y)) * __sgn1l (__x)) |
3996f34b | 605 | |
3996f34b | 606 | /* The argument range of the inline version of hypotl is slightly reduced. */ |
0135bde4 UD |
607 | __inline_mathcodeNP2 (hypot, __x, __y, |
608 | return __libc_sqrtl (__x * __x + __y * __y)) | |
3996f34b | 609 | |
3dbfd811 | 610 | # if !__GNUC_PREREQ (3, 5) |
300583a7 | 611 | __inline_mathcodeNP(logb, __x, \ |
3996f34b UD |
612 | register long double __value; \ |
613 | register long double __junk; \ | |
614 | __asm __volatile__ \ | |
615 | ("fxtract\n\t" \ | |
616 | : "=t" (__junk), "=u" (__value) : "0" (__x)); \ | |
617 | return __value) | |
3dbfd811 | 618 | # endif |
3996f34b | 619 | |
35915ec8 | 620 | # endif |
7d6a8338 UD |
621 | #endif |
622 | ||
ec751a23 | 623 | #ifdef __USE_ISOC99 |
3dbfd811 UD |
624 | # ifdef __FAST_MATH__ |
625 | ||
626 | # if !__GNUC_PREREQ (3, 5) | |
300583a7 | 627 | __inline_mathop_declNP (log2, "fld1; fxch; fyl2x", "0" (__x) : "st(1)") |
3dbfd811 | 628 | # endif |
7d6a8338 | 629 | |
8f2ece69 | 630 | __MATH_INLINE float |
f377d022 | 631 | __NTH (ldexpf (float __x, int __y)) |
8f2ece69 UD |
632 | { |
633 | __ldexp_code; | |
634 | } | |
635 | ||
8f2ece69 | 636 | __MATH_INLINE long double |
f377d022 | 637 | __NTH (ldexpl (long double __x, int __y)) |
8f2ece69 UD |
638 | { |
639 | __ldexp_code; | |
640 | } | |
3996f34b | 641 | |
300583a7 | 642 | __inline_mathcodeNP3 (fma, __x, __y, __z, return (__x * __y) + __z) |
7d6a8338 | 643 | |
300583a7 | 644 | __inline_mathopNP (rint, "frndint") |
3dbfd811 | 645 | # endif /* __FAST_MATH__ */ |
7d6a8338 | 646 | |
3dbfd811 | 647 | # define __lrint_code \ |
33127459 UD |
648 | long int __lrintres; \ |
649 | __asm__ __volatile__ \ | |
650 | ("fistpl %0" \ | |
651 | : "=m" (__lrintres) : "t" (__x) : "st"); \ | |
652 | return __lrintres | |
653 | __MATH_INLINE long int | |
f377d022 | 654 | __NTH (lrintf (float __x)) |
33127459 UD |
655 | { |
656 | __lrint_code; | |
657 | } | |
658 | __MATH_INLINE long int | |
f377d022 | 659 | __NTH (lrint (double __x)) |
33127459 UD |
660 | { |
661 | __lrint_code; | |
662 | } | |
663 | __MATH_INLINE long int | |
f377d022 | 664 | __NTH (lrintl (long double __x)) |
33127459 UD |
665 | { |
666 | __lrint_code; | |
667 | } | |
3dbfd811 | 668 | # undef __lrint_code |
33127459 | 669 | |
3dbfd811 | 670 | # define __llrint_code \ |
33127459 UD |
671 | long long int __llrintres; \ |
672 | __asm__ __volatile__ \ | |
673 | ("fistpll %0" \ | |
674 | : "=m" (__llrintres) : "t" (__x) : "st"); \ | |
675 | return __llrintres | |
676 | __MATH_INLINE long long int | |
f377d022 | 677 | __NTH (llrintf (float __x)) |
33127459 UD |
678 | { |
679 | __llrint_code; | |
680 | } | |
681 | __MATH_INLINE long long int | |
f377d022 | 682 | __NTH (llrint (double __x)) |
33127459 UD |
683 | { |
684 | __llrint_code; | |
685 | } | |
686 | __MATH_INLINE long long int | |
f377d022 | 687 | __NTH (llrintl (long double __x)) |
33127459 UD |
688 | { |
689 | __llrint_code; | |
690 | } | |
3dbfd811 | 691 | # undef __llrint_code |
33127459 | 692 | |
cd6ede75 UD |
693 | #endif |
694 | ||
b20e47cb | 695 | |
cd6ede75 | 696 | #ifdef __USE_MISC |
8f2ece69 | 697 | |
3dbfd811 | 698 | # if defined __FAST_MATH__ && !__GNUC_PREREQ (3, 5) |
300583a7 | 699 | __inline_mathcodeNP2 (drem, __x, __y, \ |
3996f34b | 700 | register double __value; \ |
33127459 | 701 | register int __clobbered; \ |
3996f34b UD |
702 | __asm __volatile__ \ |
703 | ("1: fprem1\n\t" \ | |
704 | "fstsw %%ax\n\t" \ | |
705 | "sahf\n\t" \ | |
706 | "jp 1b" \ | |
33127459 | 707 | : "=t" (__value), "=&a" (__clobbered) : "0" (__x), "u" (__y) : "cc"); \ |
3996f34b | 708 | return __value) |
3dbfd811 | 709 | # endif |
3996f34b | 710 | |
b20e47cb | 711 | |
7799b7b3 | 712 | /* This function is used in the `isfinite' macro. */ |
7799b7b3 | 713 | __MATH_INLINE int |
f377d022 | 714 | __NTH (__finite (double __x)) |
7799b7b3 | 715 | { |
db24ce47 | 716 | return (__extension__ |
e150fddc | 717 | (((((union { double __d; int __i[2]; }) {__d: __x}).__i[1] |
77faa354 | 718 | | 0x800fffffu) + 1) >> 31)); |
7799b7b3 | 719 | } |
dd33e89f | 720 | |
3996f34b | 721 | /* Miscellaneous functions */ |
3dbfd811 | 722 | # ifdef __FAST_MATH__ |
3996f34b | 723 | __inline_mathcode (__coshm1, __x, \ |
8f2ece69 | 724 | register long double __exm1 = __expm1l (__fabsl (__x)); \ |
3996f34b UD |
725 | return 0.5 * (__exm1 / (__exm1 + 1.0)) * __exm1) |
726 | ||
727 | __inline_mathcode (__acosh1p, __x, \ | |
0135bde4 | 728 | return log1pl (__x + __libc_sqrtl (__x) * __libc_sqrtl (__x + 2.0))) |
3996f34b | 729 | |
3dbfd811 | 730 | # endif /* __FAST_MATH__ */ |
b20e47cb RM |
731 | #endif /* __USE_MISC */ |
732 | ||
3996f34b | 733 | /* Undefine some of the large macros which are not used anymore. */ |
3996f34b | 734 | #undef __atan2_code |
378fbeb4 UD |
735 | #ifdef __FAST_MATH__ |
736 | # undef __expm1_code | |
737 | # undef __exp_code | |
738 | # undef __sincos_code | |
739 | #endif /* __FAST_MATH__ */ | |
3996f34b | 740 | |
b20e47cb | 741 | #endif /* __NO_MATH_INLINES */ |
f43ce637 UD |
742 | |
743 | ||
744 | /* This code is used internally in the GNU libc. */ | |
f43ce637 UD |
745 | #ifdef __LIBC_INTERNAL_MATH_INLINES |
746 | __inline_mathop (__ieee754_sqrt, "fsqrt") | |
bd355af0 UD |
747 | __inline_mathcode2 (__ieee754_atan2, __y, __x, |
748 | register long double __value; | |
749 | __asm __volatile__ ("fpatan\n\t" | |
750 | : "=t" (__value) | |
751 | : "0" (__x), "u" (__y) : "st(1)"); | |
752 | return __value;) | |
f43ce637 UD |
753 | #endif |
754 | ||
b20e47cb | 755 | #endif /* __GNUC__ */ |