1/* Inline math functions for i387 and SSE.
2 Copyright (C) 1995-2018 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
18
19#ifndef _MATH_H
20# error "Never use <bits/mathinline.h> directly; include <math.h> instead."
21#endif
22
23#ifndef __extern_always_inline
24# define __MATH_INLINE __inline
25#else
26# define __MATH_INLINE __extern_always_inline
27#endif
28
29/* Disable x87 inlines when -fpmath=sse is passed and also when we're building
30 on x86_64. Older gcc (gcc-3.2 for example) does not define __SSE2_MATH__
31 for x86_64. */
32#if !defined __SSE2_MATH__ && !defined __x86_64__
33# if ((!defined __NO_MATH_INLINES || defined __LIBC_INTERNAL_MATH_INLINES) \
34 && defined __OPTIMIZE__)
35
36/* The inline functions do not set errno or raise necessarily the
37 correct exceptions. */
38# undef math_errhandling
39
40/* A macro to define float, double, and long double versions of various
41 math functions for the ix87 FPU. FUNC is the function name (which will
42 be suffixed with f and l for the float and long double version,
43 respectively). OP is the name of the FPU operation.
44 We define two sets of macros. The set with the additional NP
45 doesn't add a prototype declaration. */
46
47# ifdef __USE_ISOC99
48# define __inline_mathop(func, op) \
49 __inline_mathop_ (double, func, op) \
50 __inline_mathop_ (float, __CONCAT(func,f), op) \
51 __inline_mathop_ (long double, __CONCAT(func,l), op)
52# define __inline_mathopNP(func, op) \
53 __inline_mathopNP_ (double, func, op) \
54 __inline_mathopNP_ (float, __CONCAT(func,f), op) \
55 __inline_mathopNP_ (long double, __CONCAT(func,l), op)
56# else
57# define __inline_mathop(func, op) \
58 __inline_mathop_ (double, func, op)
59# define __inline_mathopNP(func, op) \
60 __inline_mathopNP_ (double, func, op)
61# endif
62
63# define __inline_mathop_(float_type, func, op) \
64 __inline_mathop_decl_ (float_type, func, op, "0" (__x))
65# define __inline_mathopNP_(float_type, func, op) \
66 __inline_mathop_declNP_ (float_type, func, op, "0" (__x))
67
68
69# ifdef __USE_ISOC99
70# define __inline_mathop_decl(func, op, params...) \
71 __inline_mathop_decl_ (double, func, op, params) \
72 __inline_mathop_decl_ (float, __CONCAT(func,f), op, params) \
73 __inline_mathop_decl_ (long double, __CONCAT(func,l), op, params)
74# define __inline_mathop_declNP(func, op, params...) \
75 __inline_mathop_declNP_ (double, func, op, params) \
76 __inline_mathop_declNP_ (float, __CONCAT(func,f), op, params) \
77 __inline_mathop_declNP_ (long double, __CONCAT(func,l), op, params)
78# else
79# define __inline_mathop_decl(func, op, params...) \
80 __inline_mathop_decl_ (double, func, op, params)
81# define __inline_mathop_declNP(func, op, params...) \
82 __inline_mathop_declNP_ (double, func, op, params)
83# endif
84
85# define __inline_mathop_decl_(float_type, func, op, params...) \
86 __MATH_INLINE float_type func (float_type) __THROW; \
87 __inline_mathop_declNP_ (float_type, func, op, params)
88
89# define __inline_mathop_declNP_(float_type, func, op, params...) \
90 __MATH_INLINE float_type __NTH (func (float_type __x)) \
91 { \
92 register float_type __result; \
93 __asm __volatile__ (op : "=t" (__result) : params); \
94 return __result; \
95 }
96
97
98# ifdef __USE_ISOC99
99# define __inline_mathcode(func, arg, code) \
100 __inline_mathcode_ (double, func, arg, code) \
101 __inline_mathcode_ (float, __CONCAT(func,f), arg, code) \
102 __inline_mathcode_ (long double, __CONCAT(func,l), arg, code)
103# define __inline_mathcodeNP(func, arg, code) \
104 __inline_mathcodeNP_ (double, func, arg, code) \
105 __inline_mathcodeNP_ (float, __CONCAT(func,f), arg, code) \
106 __inline_mathcodeNP_ (long double, __CONCAT(func,l), arg, code)
107# define __inline_mathcode2(func, arg1, arg2, code) \
108 __inline_mathcode2_ (double, func, arg1, arg2, code) \
109 __inline_mathcode2_ (float, __CONCAT(func,f), arg1, arg2, code) \
110 __inline_mathcode2_ (long double, __CONCAT(func,l), arg1, arg2, code)
111# define __inline_mathcodeNP2(func, arg1, arg2, code) \
112 __inline_mathcodeNP2_ (double, func, arg1, arg2, code) \
113 __inline_mathcodeNP2_ (float, __CONCAT(func,f), arg1, arg2, code) \
114 __inline_mathcodeNP2_ (long double, __CONCAT(func,l), arg1, arg2, code)
115# define __inline_mathcode3(func, arg1, arg2, arg3, code) \
116 __inline_mathcode3_ (double, func, arg1, arg2, arg3, code) \
117 __inline_mathcode3_ (float, __CONCAT(func,f), arg1, arg2, arg3, code) \
118 __inline_mathcode3_ (long double, __CONCAT(func,l), arg1, arg2, arg3, code)
119# define __inline_mathcodeNP3(func, arg1, arg2, arg3, code) \
120 __inline_mathcodeNP3_ (double, func, arg1, arg2, arg3, code) \
121 __inline_mathcodeNP3_ (float, __CONCAT(func,f), arg1, arg2, arg3, code) \
122 __inline_mathcodeNP3_ (long double, __CONCAT(func,l), arg1, arg2, arg3, code)
123# else
124# define __inline_mathcode(func, arg, code) \
125 __inline_mathcode_ (double, func, (arg), code)
126# define __inline_mathcodeNP(func, arg, code) \
127 __inline_mathcodeNP_ (double, func, (arg), code)
128# define __inline_mathcode2(func, arg1, arg2, code) \
129 __inline_mathcode2_ (double, func, arg1, arg2, code)
130# define __inline_mathcodeNP2(func, arg1, arg2, code) \
131 __inline_mathcodeNP2_ (double, func, arg1, arg2, code)
132# define __inline_mathcode3(func, arg1, arg2, arg3, code) \
133 __inline_mathcode3_ (double, func, arg1, arg2, arg3, code)
134# define __inline_mathcodeNP3(func, arg1, arg2, arg3, code) \
135 __inline_mathcodeNP3_ (double, func, arg1, arg2, arg3, code)
136# endif
137
138# define __inline_mathcode_(float_type, func, arg, code) \
139 __MATH_INLINE float_type func (float_type) __THROW; \
140 __inline_mathcodeNP_(float_type, func, arg, code)
141
142# define __inline_mathcodeNP_(float_type, func, arg, code) \
143 __MATH_INLINE float_type __NTH (func (float_type arg)) \
144 { \
145 code; \
146 }
147
148
149# define __inline_mathcode2_(float_type, func, arg1, arg2, code) \
150 __MATH_INLINE float_type func (float_type, float_type) __THROW; \
151 __inline_mathcodeNP2_ (float_type, func, arg1, arg2, code)
152
153# define __inline_mathcodeNP2_(float_type, func, arg1, arg2, code) \
154 __MATH_INLINE float_type __NTH (func (float_type arg1, float_type arg2)) \
155 { \
156 code; \
157 }
158
159# define __inline_mathcode3_(float_type, func, arg1, arg2, arg3, code) \
160 __MATH_INLINE float_type func (float_type, float_type, float_type) __THROW; \
161 __inline_mathcodeNP3_(float_type, func, arg1, arg2, arg3, code)
162
163# define __inline_mathcodeNP3_(float_type, func, arg1, arg2, arg3, code) \
164 __MATH_INLINE float_type __NTH (func (float_type arg1, float_type arg2, \
165 float_type arg3)) \
166 { \
167 code; \
168 }
169# endif
170
171
172# if !defined __NO_MATH_INLINES && defined __OPTIMIZE__
173/* Miscellaneous functions */
174
175/* __FAST_MATH__ is defined by gcc -ffast-math. */
176# ifdef __FAST_MATH__
177/* Optimized inline implementation, sometimes with reduced precision
178 and/or argument range. */
179
180# if __GNUC_PREREQ (3, 5)
181# define __expm1_code \
182 register long double __temp; \
183 __temp = __builtin_expm1l (__x); \
184 return __temp ? __temp : __x
185# else
186# define __expm1_code \
187 register long double __value; \
188 register long double __exponent; \
189 register long double __temp; \
190 __asm __volatile__ \
191 ("fldl2e # e^x - 1 = 2^(x * log2(e)) - 1\n\t" \
192 "fmul %%st(1) # x * log2(e)\n\t" \
193 "fst %%st(1)\n\t" \
194 "frndint # int(x * log2(e))\n\t" \
195 "fxch\n\t" \
196 "fsub %%st(1) # fract(x * log2(e))\n\t" \
197 "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" \
198 "fscale # 2^(x * log2(e)) - 2^(int(x * log2(e)))\n\t" \
199 : "=t" (__value), "=u" (__exponent) : "0" (__x)); \
200 __asm __volatile__ \
201 ("fscale # 2^int(x * log2(e))\n\t" \
202 : "=t" (__temp) : "0" (1.0), "u" (__exponent)); \
203 __temp -= 1.0; \
204 __temp += __value; \
205 return __temp ? __temp : __x
206# endif
207__inline_mathcodeNP_ (long double, __expm1l, __x, __expm1_code)
208
209# if __GNUC_PREREQ (3, 4)
210__inline_mathcodeNP_ (long double, __expl, __x, return __builtin_expl (__x))
211# else
212# define __exp_code \
213 register long double __value; \
214 register long double __exponent; \
215 __asm __volatile__ \
216 ("fldl2e # e^x = 2^(x * log2(e))\n\t" \
217 "fmul %%st(1) # x * log2(e)\n\t" \
218 "fst %%st(1)\n\t" \
219 "frndint # int(x * log2(e))\n\t" \
220 "fxch\n\t" \
221 "fsub %%st(1) # fract(x * log2(e))\n\t" \
222 "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" \
223 : "=t" (__value), "=u" (__exponent) : "0" (__x)); \
224 __value += 1.0; \
225 __asm __volatile__ \
226 ("fscale" \
227 : "=t" (__value) : "0" (__value), "u" (__exponent)); \
228 return __value
229__inline_mathcodeNP (exp, __x, __exp_code)
230__inline_mathcodeNP_ (long double, __expl, __x, __exp_code)
231# endif
232# endif /* __FAST_MATH__ */
233
234
235# ifdef __FAST_MATH__
236# if !__GNUC_PREREQ (3,3)
237__inline_mathopNP (sqrt, "fsqrt")
238__inline_mathopNP_ (long double, __sqrtl, "fsqrt")
239# define __libc_sqrtl(n) __sqrtl (n)
240# else
241# define __libc_sqrtl(n) __builtin_sqrtl (n)
242# endif
243# endif
244
245# if __GNUC_PREREQ (2, 8)
246__inline_mathcodeNP_ (double, fabs, __x, return __builtin_fabs (__x))
247# ifdef __USE_ISOC99
248__inline_mathcodeNP_ (float, fabsf, __x, return __builtin_fabsf (__x))
249__inline_mathcodeNP_ (long double, fabsl, __x, return __builtin_fabsl (__x))
250# endif
251__inline_mathcodeNP_ (long double, __fabsl, __x, return __builtin_fabsl (__x))
252# else
253__inline_mathop (fabs, "fabs")
254__inline_mathop_ (long double, __fabsl, "fabs")
255# endif
256
257__inline_mathcode_ (long double, __sgn1l, __x, \
258 __extension__ union { long double __xld; unsigned int __xi[3]; } __n = \
259 { __xld: __x }; \
260 __n.__xi[2] = (__n.__xi[2] & 0x8000) | 0x3fff; \
261 __n.__xi[1] = 0x80000000; \
262 __n.__xi[0] = 0; \
263 return __n.__xld)
264
265
266# ifdef __FAST_MATH__
267/* The argument range of the inline version of sinhl is slightly reduced. */
268__inline_mathcodeNP (sinh, __x, \
269 register long double __exm1 = __expm1l (__fabsl (__x)); \
270 return 0.5 * (__exm1 / (__exm1 + 1.0) + __exm1) * __sgn1l (__x))
271
272__inline_mathcodeNP (cosh, __x, \
273 register long double __ex = __expl (__x); \
274 return 0.5 * (__ex + 1.0 / __ex))
275
276__inline_mathcodeNP (tanh, __x, \
277 register long double __exm1 = __expm1l (-__fabsl (__x + __x)); \
278 return __exm1 / (__exm1 + 2.0) * __sgn1l (-__x))
279# endif
280
281
282/* Optimized versions for some non-standardized functions. */
283# ifdef __USE_ISOC99
284
285# ifdef __FAST_MATH__
286__inline_mathcodeNP (expm1, __x, __expm1_code)
287
288/* The argument range of the inline version of asinhl is slightly reduced. */
289__inline_mathcodeNP (asinh, __x, \
290 register long double __y = __fabsl (__x); \
291 return (log1pl (__y * __y / (__libc_sqrtl (__y * __y + 1.0) + 1.0) + __y) \
292 * __sgn1l (__x)))
293
294__inline_mathcodeNP (acosh, __x, \
295 return logl (__x + __libc_sqrtl (__x - 1.0) * __libc_sqrtl (__x + 1.0)))
296
297__inline_mathcodeNP (atanh, __x, \
298 register long double __y = __fabsl (__x); \
299 return -0.5 * log1pl (-(__y + __y) / (1.0 + __y)) * __sgn1l (__x))
300
301/* The argument range of the inline version of hypotl is slightly reduced. */
302__inline_mathcodeNP2 (hypot, __x, __y,
303 return __libc_sqrtl (__x * __x + __y * __y))
304
305# endif
306# endif
307
308
309/* Undefine some of the large macros which are not used anymore. */
310# ifdef __FAST_MATH__
311# undef __expm1_code
312# undef __exp_code
313# endif /* __FAST_MATH__ */
314
315# endif /* __NO_MATH_INLINES */
316
317
318/* This code is used internally in the GNU libc. */
319# ifdef __LIBC_INTERNAL_MATH_INLINES
320__inline_mathcode2_ (long double, __ieee754_atan2l, __y, __x,
321 register long double __value;
322 __asm __volatile__ ("fpatan\n\t"
323 : "=t" (__value)
324 : "0" (__x), "u" (__y) : "st(1)");
325 return __value;)
326# endif
327
328#endif /* !__SSE2_MATH__ && !__x86_64__ */
329