]>
Commit | Line | Data |
---|---|---|
b20e47cb | 1 | /* Inline math functions for i387. |
dfb87dc8 | 2 | Copyright (C) 1995,96,97,98,99,2000,2001,2003 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 | 6 | The GNU C Library is free software; you can redistribute it and/or |
41bdb6e2 AJ |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the 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 | |
41bdb6e2 | 14 | Lesser General Public License for more details. |
b20e47cb | 15 | |
41bdb6e2 AJ |
16 | You should have received a copy of the GNU Lesser General Public |
17 | License along with the GNU C Library; if not, write to the Free | |
18 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
19 | 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 | 31 | |
ec751a23 | 32 | #if defined __USE_ISOC99 && defined __GNUC__ && __GNUC__ >= 2 |
a720a3ac UD |
33 | # if __GNUC_PREREQ (2,97) |
34 | /* GCC 2.97 and up have builtins that actually can be used. */ | |
35 | # define isgreater(x, y) __builtin_isgreater (x, y) | |
36 | # define isgreaterequal(x, y) __builtin_isgreaterequal (x, y) | |
37 | # define isless(x, y) __builtin_isless (x, y) | |
38 | # define islessequal(x, y) __builtin_islessequal (x, y) | |
39 | # define islessgreater(x, y) __builtin_islessgreater (x, y) | |
40 | # define isunordered(x, y) __builtin_isunordered (x, y) | |
41 | # else | |
ec751a23 | 42 | /* ISO C99 defines some macros to perform unordered comparisons. The |
cd6ede75 UD |
43 | ix87 FPU supports this with special opcodes and we should use them. |
44 | These must not be inline functions since we have to be able to handle | |
45 | all floating-point types. */ | |
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 | |
cc46c92d | 128 | __signbitf (float __x) __THROW |
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 | |
cc46c92d | 134 | __signbit (double __x) __THROW |
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 | |
cc46c92d | 140 | __signbitl (long double __x) __THROW |
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...) \ | |
cc46c92d | 206 | __MATH_INLINE float_type func (float_type __x) __THROW \ |
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 UD |
219 | # define __inline_mathcodeNP(func, arg, code) \ |
220 | __inline_mathcodeNP_ (double, func, arg, code) \ | |
221 | __inline_mathcodeNP_ (float, __CONCAT(func,f), arg, code) \ | |
222 | __inline_mathcodeNP_ (long double, __CONCAT(func,l), arg, code) | |
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 UD |
227 | # define __inline_mathcodeNP2(func, arg1, arg2, code) \ |
228 | __inline_mathcodeNP2_ (double, func, arg1, arg2, code) \ | |
229 | __inline_mathcodeNP2_ (float, __CONCAT(func,f), arg1, arg2, code) \ | |
230 | __inline_mathcodeNP2_ (long double, __CONCAT(func,l), arg1, arg2, code) | |
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) \ | |
237 | __inline_mathcodeNP3_ (float, __CONCAT(func,f), arg1, arg2, arg3, code) \ | |
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) \ | |
cc46c92d | 259 | __MATH_INLINE float_type func (float_type arg) __THROW \ |
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) \ | |
cc46c92d | 270 | __MATH_INLINE float_type func (float_type arg1, float_type arg2) __THROW \ |
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) \ | |
1ea89a40 | 280 | __MATH_INLINE float_type func (float_type arg1, float_type arg2, \ |
cc46c92d | 281 | float_type arg3) __THROW \ |
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 |
cc46c92d | 344 | __sincos (double __x, double *__sinx, double *__cosx) __THROW |
f41c8091 UD |
345 | { |
346 | __sincos_code; | |
347 | } | |
348 | ||
f41c8091 | 349 | __MATH_INLINE void |
cc46c92d | 350 | __sincosf (float __x, float *__sinx, float *__cosx) __THROW |
f41c8091 UD |
351 | { |
352 | __sincos_code; | |
353 | } | |
354 | ||
f41c8091 | 355 | __MATH_INLINE void |
cc46c92d | 356 | __sincosl (long double __x, long double *__sinx, long double *__cosx) __THROW |
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 | |
378fbeb4 | 366 | # define __expm1_code \ |
3996f34b UD |
367 | register long double __value; \ |
368 | register long double __exponent; \ | |
369 | register long double __temp; \ | |
370 | __asm __volatile__ \ | |
371 | ("fldl2e # e^x - 1 = 2^(x * log2(e)) - 1\n\t" \ | |
372 | "fmul %%st(1) # x * log2(e)\n\t" \ | |
50304ef0 | 373 | "fst %%st(1)\n\t" \ |
3996f34b UD |
374 | "frndint # int(x * log2(e))\n\t" \ |
375 | "fxch\n\t" \ | |
376 | "fsub %%st(1) # fract(x * log2(e))\n\t" \ | |
377 | "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" \ | |
378 | "fscale # 2^(x * log2(e)) - 2^(int(x * log2(e)))\n\t" \ | |
379 | : "=t" (__value), "=u" (__exponent) : "0" (__x)); \ | |
380 | __asm __volatile__ \ | |
381 | ("fscale # 2^int(x * log2(e))\n\t" \ | |
382 | : "=t" (__temp) : "0" (1.0), "u" (__exponent)); \ | |
383 | __temp -= 1.0; \ | |
15daa639 | 384 | return __temp + __value ?: __x |
300583a7 | 385 | __inline_mathcodeNP_ (long double, __expm1l, __x, __expm1_code) |
3996f34b UD |
386 | |
387 | ||
378fbeb4 | 388 | # define __exp_code \ |
3996f34b UD |
389 | register long double __value; \ |
390 | register long double __exponent; \ | |
391 | __asm __volatile__ \ | |
392 | ("fldl2e # e^x = 2^(x * log2(e))\n\t" \ | |
393 | "fmul %%st(1) # x * log2(e)\n\t" \ | |
50304ef0 | 394 | "fst %%st(1)\n\t" \ |
3996f34b UD |
395 | "frndint # int(x * log2(e))\n\t" \ |
396 | "fxch\n\t" \ | |
397 | "fsub %%st(1) # fract(x * log2(e))\n\t" \ | |
398 | "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" \ | |
399 | : "=t" (__value), "=u" (__exponent) : "0" (__x)); \ | |
400 | __value += 1.0; \ | |
401 | __asm __volatile__ \ | |
402 | ("fscale" \ | |
403 | : "=t" (__value) : "0" (__value), "u" (__exponent)); \ | |
404 | return __value | |
300583a7 UD |
405 | __inline_mathcodeNP (exp, __x, __exp_code) |
406 | __inline_mathcodeNP_ (long double, __expl, __x, __exp_code) | |
3996f34b UD |
407 | |
408 | ||
300583a7 | 409 | __inline_mathcodeNP (tan, __x, \ |
3996f34b | 410 | register long double __value; \ |
fa1f94fe | 411 | register long double __value2 __attribute__ ((__unused__)); \ |
3996f34b UD |
412 | __asm __volatile__ \ |
413 | ("fptan" \ | |
414 | : "=t" (__value2), "=u" (__value) : "0" (__x)); \ | |
415 | return __value) | |
378fbeb4 UD |
416 | #endif /* __FAST_MATH__ */ |
417 | ||
418 | ||
419 | #define __atan2_code \ | |
420 | register long double __value; \ | |
421 | __asm __volatile__ \ | |
422 | ("fpatan" \ | |
423 | : "=t" (__value) : "0" (__x), "u" (__y) : "st(1)"); \ | |
424 | return __value | |
425 | __inline_mathcodeNP2 (atan2, __y, __x, __atan2_code) | |
426 | __inline_mathcodeNP2_ (long double, __atan2l, __y, __x, __atan2_code) | |
427 | ||
428 | ||
429 | __inline_mathcodeNP2 (fmod, __x, __y, \ | |
430 | register long double __value; \ | |
431 | __asm __volatile__ \ | |
432 | ("1: fprem\n\t" \ | |
433 | "fnstsw %%ax\n\t" \ | |
434 | "sahf\n\t" \ | |
435 | "jp 1b" \ | |
436 | : "=t" (__value) : "0" (__x), "u" (__y) : "ax", "cc"); \ | |
437 | return __value) | |
3996f34b UD |
438 | |
439 | ||
dfb87dc8 | 440 | #ifdef __FAST_MATH__ |
6d316b07 | 441 | # if !__GNUC_PREREQ (3,3) |
300583a7 UD |
442 | __inline_mathopNP (sqrt, "fsqrt") |
443 | __inline_mathopNP_ (long double, __sqrtl, "fsqrt") | |
0135bde4 UD |
444 | # define __libc_sqrtl(n) __sqrtl (n) |
445 | # else | |
446 | # define __libc_sqrtl(n) __builtin_sqrtl (n) | |
6d316b07 | 447 | # endif |
dfb87dc8 | 448 | #endif |
3996f34b | 449 | |
4360eafd | 450 | #if __GNUC_PREREQ (2, 8) |
300583a7 UD |
451 | __inline_mathcodeNP_ (double, fabs, __x, return __builtin_fabs (__x)) |
452 | __inline_mathcodeNP_ (float, fabsf, __x, return __builtin_fabsf (__x)) | |
453 | __inline_mathcodeNP_ (long double, fabsl, __x, return __builtin_fabsl (__x)) | |
454 | __inline_mathcodeNP_ (long double, __fabsl, __x, return __builtin_fabsl (__x)) | |
8f2ece69 | 455 | #else |
3996f34b | 456 | __inline_mathop (fabs, "fabs") |
8f2ece69 UD |
457 | __inline_mathop_ (long double, __fabsl, "fabs") |
458 | #endif | |
3996f34b | 459 | |
378fbeb4 | 460 | #ifdef __FAST_MATH__ |
3996f34b | 461 | /* The argument range of this inline version is reduced. */ |
300583a7 | 462 | __inline_mathopNP (sin, "fsin") |
3996f34b | 463 | /* The argument range of this inline version is reduced. */ |
300583a7 | 464 | __inline_mathopNP (cos, "fcos") |
3996f34b | 465 | |
300583a7 UD |
466 | __inline_mathop_declNP (log, "fldln2; fxch; fyl2x", "0" (__x) : "st(1)") |
467 | __inline_mathop_declNP (log10, "fldlg2; fxch; fyl2x", "0" (__x) : "st(1)") | |
3996f34b | 468 | |
0135bde4 UD |
469 | __inline_mathcodeNP (asin, __x, return __atan2l (__x, __libc_sqrtl (1.0 - __x * __x))) |
470 | __inline_mathcodeNP (acos, __x, return __atan2l (__libc_sqrtl (1.0 - __x * __x), __x)) | |
378fbeb4 UD |
471 | #endif /* __FAST_MATH__ */ |
472 | ||
473 | __inline_mathop_declNP (atan, "fld1; fpatan", "0" (__x) : "st(1)") | |
3996f34b | 474 | |
15daa639 | 475 | __inline_mathcode_ (long double, __sgn1l, __x, \ |
2caacb0a | 476 | __extension__ union { long double __xld; unsigned int __xi[3]; } __n = \ |
e150fddc | 477 | { __xld: __x }; \ |
15daa639 UD |
478 | __n.__xi[2] = (__n.__xi[2] & 0x8000) | 0x3fff; \ |
479 | __n.__xi[1] = 0x80000000; \ | |
480 | __n.__xi[0] = 0; \ | |
481 | return __n.__xld) | |
3996f34b UD |
482 | |
483 | ||
1dd54850 | 484 | #ifdef __FAST_MATH__ |
3996f34b | 485 | /* The argument range of the inline version of sinhl is slightly reduced. */ |
300583a7 | 486 | __inline_mathcodeNP (sinh, __x, \ |
8f2ece69 | 487 | register long double __exm1 = __expm1l (__fabsl (__x)); \ |
3996f34b UD |
488 | return 0.5 * (__exm1 / (__exm1 + 1.0) + __exm1) * __sgn1l (__x)) |
489 | ||
300583a7 | 490 | __inline_mathcodeNP (cosh, __x, \ |
3996f34b UD |
491 | register long double __ex = __expl (__x); \ |
492 | return 0.5 * (__ex + 1.0 / __ex)) | |
493 | ||
300583a7 | 494 | __inline_mathcodeNP (tanh, __x, \ |
8f2ece69 | 495 | register long double __exm1 = __expm1l (-__fabsl (__x + __x)); \ |
3996f34b | 496 | return __exm1 / (__exm1 + 2.0) * __sgn1l (-__x)) |
1dd54850 | 497 | #endif |
3996f34b | 498 | |
300583a7 | 499 | __inline_mathcodeNP (floor, __x, \ |
3996f34b UD |
500 | register long double __value; \ |
501 | __volatile unsigned short int __cw; \ | |
502 | __volatile unsigned short int __cwtmp; \ | |
503 | __asm __volatile ("fnstcw %0" : "=m" (__cw)); \ | |
504 | __cwtmp = (__cw & 0xf3ff) | 0x0400; /* rounding down */ \ | |
505 | __asm __volatile ("fldcw %0" : : "m" (__cwtmp)); \ | |
506 | __asm __volatile ("frndint" : "=t" (__value) : "0" (__x)); \ | |
507 | __asm __volatile ("fldcw %0" : : "m" (__cw)); \ | |
508 | return __value) | |
509 | ||
300583a7 | 510 | __inline_mathcodeNP (ceil, __x, \ |
3996f34b UD |
511 | register long double __value; \ |
512 | __volatile unsigned short int __cw; \ | |
513 | __volatile unsigned short int __cwtmp; \ | |
514 | __asm __volatile ("fnstcw %0" : "=m" (__cw)); \ | |
515 | __cwtmp = (__cw & 0xf3ff) | 0x0800; /* rounding up */ \ | |
516 | __asm __volatile ("fldcw %0" : : "m" (__cwtmp)); \ | |
517 | __asm __volatile ("frndint" : "=t" (__value) : "0" (__x)); \ | |
518 | __asm __volatile ("fldcw %0" : : "m" (__cw)); \ | |
519 | return __value) | |
b20e47cb | 520 | |
dfb87dc8 UD |
521 | #ifdef __FAST_MATH__ |
522 | # define __ldexp_code \ | |
8f2ece69 UD |
523 | register long double __value; \ |
524 | __asm __volatile__ \ | |
525 | ("fscale" \ | |
526 | : "=t" (__value) : "0" (__x), "u" ((long double) __y)); \ | |
527 | return __value | |
528 | ||
8f2ece69 | 529 | __MATH_INLINE double |
cc46c92d | 530 | ldexp (double __x, int __y) __THROW |
8f2ece69 UD |
531 | { |
532 | __ldexp_code; | |
533 | } | |
dfb87dc8 | 534 | #endif |
8f2ece69 | 535 | |
b20e47cb RM |
536 | |
537 | /* Optimized versions for some non-standardized functions. */ | |
ec751a23 | 538 | #if defined __USE_ISOC99 || defined __USE_MISC |
b20e47cb | 539 | |
81e43fc1 | 540 | # ifdef __FAST_MATH__ |
300583a7 | 541 | __inline_mathcodeNP (expm1, __x, __expm1_code) |
b20e47cb | 542 | |
714a562f UD |
543 | /* We cannot rely on M_SQRT being defined. So we do it for ourself |
544 | here. */ | |
35915ec8 | 545 | # define __M_SQRT2 1.41421356237309504880L /* sqrt(2) */ |
714a562f | 546 | |
300583a7 | 547 | __inline_mathcodeNP (log1p, __x, \ |
3996f34b | 548 | register long double __value; \ |
8f2ece69 | 549 | if (__fabsl (__x) >= 1.0 - 0.5 * __M_SQRT2) \ |
3996f34b UD |
550 | __value = logl (1.0 + __x); \ |
551 | else \ | |
552 | __asm __volatile__ \ | |
553 | ("fldln2\n\t" \ | |
554 | "fxch\n\t" \ | |
555 | "fyl2xp1" \ | |
5892e305 | 556 | : "=t" (__value) : "0" (__x) : "st(1)"); \ |
3996f34b UD |
557 | return __value) |
558 | ||
559 | ||
560 | /* The argument range of the inline version of asinhl is slightly reduced. */ | |
300583a7 | 561 | __inline_mathcodeNP (asinh, __x, \ |
8f2ece69 | 562 | register long double __y = __fabsl (__x); \ |
0135bde4 | 563 | return (log1pl (__y * __y / (__libc_sqrtl (__y * __y + 1.0) + 1.0) + __y) \ |
ca34d7a7 | 564 | * __sgn1l (__x))) |
3996f34b | 565 | |
300583a7 | 566 | __inline_mathcodeNP (acosh, __x, \ |
0135bde4 | 567 | return logl (__x + __libc_sqrtl (__x - 1.0) * __libc_sqrtl (__x + 1.0))) |
3996f34b | 568 | |
300583a7 | 569 | __inline_mathcodeNP (atanh, __x, \ |
8f2ece69 | 570 | register long double __y = __fabsl (__x); \ |
bd355af0 | 571 | return -0.5 * log1pl (-(__y + __y) / (1.0 + __y)) * __sgn1l (__x)) |
3996f34b | 572 | |
3996f34b | 573 | /* The argument range of the inline version of hypotl is slightly reduced. */ |
0135bde4 UD |
574 | __inline_mathcodeNP2 (hypot, __x, __y, |
575 | return __libc_sqrtl (__x * __x + __y * __y)) | |
3996f34b | 576 | |
300583a7 | 577 | __inline_mathcodeNP(logb, __x, \ |
3996f34b UD |
578 | register long double __value; \ |
579 | register long double __junk; \ | |
580 | __asm __volatile__ \ | |
581 | ("fxtract\n\t" \ | |
582 | : "=t" (__junk), "=u" (__value) : "0" (__x)); \ | |
583 | return __value) | |
584 | ||
35915ec8 | 585 | # endif |
7d6a8338 UD |
586 | #endif |
587 | ||
ec751a23 | 588 | #ifdef __USE_ISOC99 |
f9c9dc78 | 589 | #ifdef __FAST_MATH__ |
300583a7 | 590 | __inline_mathop_declNP (log2, "fld1; fxch; fyl2x", "0" (__x) : "st(1)") |
7d6a8338 | 591 | |
8f2ece69 | 592 | __MATH_INLINE float |
cc46c92d | 593 | ldexpf (float __x, int __y) __THROW |
8f2ece69 UD |
594 | { |
595 | __ldexp_code; | |
596 | } | |
597 | ||
8f2ece69 | 598 | __MATH_INLINE long double |
cc46c92d | 599 | ldexpl (long double __x, int __y) __THROW |
8f2ece69 UD |
600 | { |
601 | __ldexp_code; | |
602 | } | |
3996f34b | 603 | |
300583a7 | 604 | __inline_mathcodeNP3 (fma, __x, __y, __z, return (__x * __y) + __z) |
7d6a8338 | 605 | |
300583a7 | 606 | __inline_mathopNP (rint, "frndint") |
f9c9dc78 | 607 | #endif /* __FAST_MATH__ */ |
7d6a8338 | 608 | |
33127459 UD |
609 | #define __lrint_code \ |
610 | long int __lrintres; \ | |
611 | __asm__ __volatile__ \ | |
612 | ("fistpl %0" \ | |
613 | : "=m" (__lrintres) : "t" (__x) : "st"); \ | |
614 | return __lrintres | |
615 | __MATH_INLINE long int | |
cc46c92d | 616 | lrintf (float __x) __THROW |
33127459 UD |
617 | { |
618 | __lrint_code; | |
619 | } | |
620 | __MATH_INLINE long int | |
cc46c92d | 621 | lrint (double __x) __THROW |
33127459 UD |
622 | { |
623 | __lrint_code; | |
624 | } | |
625 | __MATH_INLINE long int | |
cc46c92d | 626 | lrintl (long double __x) __THROW |
33127459 UD |
627 | { |
628 | __lrint_code; | |
629 | } | |
630 | #undef __lrint_code | |
631 | ||
632 | #define __llrint_code \ | |
633 | long long int __llrintres; \ | |
634 | __asm__ __volatile__ \ | |
635 | ("fistpll %0" \ | |
636 | : "=m" (__llrintres) : "t" (__x) : "st"); \ | |
637 | return __llrintres | |
638 | __MATH_INLINE long long int | |
cc46c92d | 639 | llrintf (float __x) __THROW |
33127459 UD |
640 | { |
641 | __llrint_code; | |
642 | } | |
643 | __MATH_INLINE long long int | |
cc46c92d | 644 | llrint (double __x) __THROW |
33127459 UD |
645 | { |
646 | __llrint_code; | |
647 | } | |
648 | __MATH_INLINE long long int | |
cc46c92d | 649 | llrintl (long double __x) __THROW |
33127459 UD |
650 | { |
651 | __llrint_code; | |
652 | } | |
653 | #undef __llrint_code | |
654 | ||
cd6ede75 UD |
655 | #endif |
656 | ||
b20e47cb | 657 | |
cd6ede75 | 658 | #ifdef __USE_MISC |
8f2ece69 | 659 | |
300583a7 | 660 | __inline_mathcodeNP2 (drem, __x, __y, \ |
3996f34b | 661 | register double __value; \ |
33127459 | 662 | register int __clobbered; \ |
3996f34b UD |
663 | __asm __volatile__ \ |
664 | ("1: fprem1\n\t" \ | |
665 | "fstsw %%ax\n\t" \ | |
666 | "sahf\n\t" \ | |
667 | "jp 1b" \ | |
33127459 | 668 | : "=t" (__value), "=&a" (__clobbered) : "0" (__x), "u" (__y) : "cc"); \ |
3996f34b UD |
669 | return __value) |
670 | ||
b20e47cb | 671 | |
7799b7b3 | 672 | /* This function is used in the `isfinite' macro. */ |
7799b7b3 | 673 | __MATH_INLINE int |
cc46c92d | 674 | __finite (double __x) __THROW |
7799b7b3 | 675 | { |
db24ce47 | 676 | return (__extension__ |
e150fddc | 677 | (((((union { double __d; int __i[2]; }) {__d: __x}).__i[1] |
77faa354 | 678 | | 0x800fffffu) + 1) >> 31)); |
7799b7b3 | 679 | } |
dd33e89f | 680 | |
3996f34b | 681 | /* Miscellaneous functions */ |
f9c9dc78 | 682 | #ifdef __FAST_MATH__ |
3996f34b | 683 | __inline_mathcode (__coshm1, __x, \ |
8f2ece69 | 684 | register long double __exm1 = __expm1l (__fabsl (__x)); \ |
3996f34b UD |
685 | return 0.5 * (__exm1 / (__exm1 + 1.0)) * __exm1) |
686 | ||
687 | __inline_mathcode (__acosh1p, __x, \ | |
0135bde4 | 688 | return log1pl (__x + __libc_sqrtl (__x) * __libc_sqrtl (__x + 2.0))) |
3996f34b | 689 | |
f9c9dc78 | 690 | #endif /* __FAST_MATH__ */ |
b20e47cb RM |
691 | #endif /* __USE_MISC */ |
692 | ||
3996f34b | 693 | /* Undefine some of the large macros which are not used anymore. */ |
3996f34b | 694 | #undef __atan2_code |
378fbeb4 UD |
695 | #ifdef __FAST_MATH__ |
696 | # undef __expm1_code | |
697 | # undef __exp_code | |
698 | # undef __sincos_code | |
699 | #endif /* __FAST_MATH__ */ | |
3996f34b | 700 | |
b20e47cb | 701 | #endif /* __NO_MATH_INLINES */ |
f43ce637 UD |
702 | |
703 | ||
704 | /* This code is used internally in the GNU libc. */ | |
f43ce637 UD |
705 | #ifdef __LIBC_INTERNAL_MATH_INLINES |
706 | __inline_mathop (__ieee754_sqrt, "fsqrt") | |
bd355af0 UD |
707 | __inline_mathcode2 (__ieee754_atan2, __y, __x, |
708 | register long double __value; | |
709 | __asm __volatile__ ("fpatan\n\t" | |
710 | : "=t" (__value) | |
711 | : "0" (__x), "u" (__y) : "st(1)"); | |
712 | return __value;) | |
f43ce637 UD |
713 | #endif |
714 | ||
b20e47cb | 715 | #endif /* __GNUC__ */ |