]>
Commit | Line | Data |
---|---|---|
e08ec256 | 1 | /* GCC Quad-Precision Math Library |
92920cc6 | 2 | Copyright (C) 2010, 2011 Free Software Foundation, Inc. |
e08ec256 | 3 | Written by Francois-Xavier Coudert <fxcoudert@gcc.gnu.org> |
4 | ||
657c8e78 | 5 | This file is part of the libquadmath library. |
6 | Libquadmath is free software; you can redistribute it and/or | |
e08ec256 | 7 | modify it under the terms of the GNU Library General Public |
8 | License as published by the Free Software Foundation; either | |
9 | version 2 of the License, or (at your option) any later version. | |
10 | ||
657c8e78 | 11 | Libquadmath is distributed in the hope that it will be useful, |
e08ec256 | 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. | |
15 | ||
16 | You should have received a copy of the GNU Library General Public | |
657c8e78 | 17 | License along with libquadmath; see the file COPYING.LIB. If |
e08ec256 | 18 | not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
19 | Boston, MA 02110-1301, USA. */ | |
20 | ||
87969c8c | 21 | #ifndef QUADMATH_IMP_H |
22 | #define QUADMATH_IMP_H | |
23 | ||
e409716d | 24 | #include <errno.h> |
25 | #include <limits.h> | |
26 | #include <stdbool.h> | |
87969c8c | 27 | #include <stdint.h> |
28 | #include <stdlib.h> | |
29 | #include "quadmath.h" | |
bcaa791f | 30 | #include "config.h" |
e409716d | 31 | #ifdef HAVE_FENV_H |
32 | # include <fenv.h> | |
33 | #endif | |
87969c8c | 34 | |
35 | ||
4a2f7ea2 | 36 | /* Under IEEE 754, an architecture may determine tininess of |
37 | floating-point results either "before rounding" or "after | |
38 | rounding", but must do so in the same way for all operations | |
39 | returning binary results. Define TININESS_AFTER_ROUNDING to 1 for | |
40 | "after rounding" architectures, 0 for "before rounding" | |
41 | architectures. */ | |
42 | ||
43 | #define TININESS_AFTER_ROUNDING 1 | |
44 | ||
e409716d | 45 | #define HIGH_ORDER_BIT_IS_SET_FOR_SNAN 0 |
46 | ||
47 | #define FIX_FLT128_LONG_CONVERT_OVERFLOW 0 | |
48 | #define FIX_FLT128_LLONG_CONVERT_OVERFLOW 0 | |
4a2f7ea2 | 49 | |
657c8e78 | 50 | /* Prototypes for internal functions. */ |
0aa903b3 | 51 | extern int32_t __quadmath_rem_pio2q (__float128, __float128 *); |
52 | extern void __quadmath_kernel_sincosq (__float128, __float128, __float128 *, | |
53 | __float128 *, int); | |
54 | extern __float128 __quadmath_kernel_sinq (__float128, __float128, int); | |
55 | extern __float128 __quadmath_kernel_cosq (__float128, __float128); | |
e409716d | 56 | extern __float128 __quadmath_kernel_tanq (__float128, __float128, int); |
57 | extern __float128 __quadmath_gamma_productq (__float128, __float128, int, | |
58 | __float128 *); | |
59 | extern __float128 __quadmath_gammaq_r (__float128, int *); | |
60 | extern __float128 __quadmath_lgamma_negq (__float128, int *); | |
61 | extern __float128 __quadmath_lgamma_productq (__float128, __float128, | |
62 | __float128, int); | |
63 | extern __float128 __quadmath_lgammaq_r (__float128, int *); | |
4a2f7ea2 | 64 | extern __float128 __quadmath_x2y2m1q (__float128 x, __float128 y); |
e409716d | 65 | extern __complex128 __quadmath_kernel_casinhq (__complex128, int); |
4a2f7ea2 | 66 | |
e409716d | 67 | static inline void |
68 | mul_splitq (__float128 *hi, __float128 *lo, __float128 x, __float128 y) | |
69 | { | |
70 | /* Fast built-in fused multiply-add. */ | |
71 | *hi = x * y; | |
72 | *lo = fmaq (x, y, -*hi); | |
73 | } | |
4a2f7ea2 | 74 | |
87969c8c | 75 | |
76 | ||
77 | ||
657c8e78 | 78 | /* Frankly, if you have __float128, you have 64-bit integers, right? */ |
87969c8c | 79 | #ifndef UINT64_C |
80 | # error "No way!" | |
81 | #endif | |
82 | ||
83 | ||
657c8e78 | 84 | /* Main union type we use to manipulate the floating-point type. */ |
87969c8c | 85 | typedef union |
86 | { | |
87 | __float128 value; | |
88 | ||
89 | struct | |
80b97f7f | 90 | #ifdef __MINGW32__ |
91 | /* On mingw targets the ms-bitfields option is active by default. | |
92 | Therefore enforce gnu-bitfield style. */ | |
93 | __attribute__ ((gcc_struct)) | |
94 | #endif | |
87969c8c | 95 | { |
e7b8ec29 | 96 | #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
87969c8c | 97 | unsigned negative:1; |
98 | unsigned exponent:15; | |
529ebc2a | 99 | unsigned mantissa0:16; |
100 | unsigned mantissa1:32; | |
101 | unsigned mantissa2:32; | |
102 | unsigned mantissa3:32; | |
e7b8ec29 | 103 | #else |
529ebc2a | 104 | unsigned mantissa3:32; |
105 | unsigned mantissa2:32; | |
106 | unsigned mantissa1:32; | |
107 | unsigned mantissa0:16; | |
87969c8c | 108 | unsigned exponent:15; |
109 | unsigned negative:1; | |
110 | #endif | |
111 | } ieee; | |
112 | ||
113 | struct | |
114 | { | |
e7b8ec29 | 115 | #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
87969c8c | 116 | uint64_t high; |
117 | uint64_t low; | |
e7b8ec29 | 118 | #else |
87969c8c | 119 | uint64_t low; |
120 | uint64_t high; | |
121 | #endif | |
122 | } words64; | |
123 | ||
124 | struct | |
125 | { | |
e7b8ec29 | 126 | #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
87969c8c | 127 | uint32_t w0; |
128 | uint32_t w1; | |
129 | uint32_t w2; | |
130 | uint32_t w3; | |
e7b8ec29 | 131 | #else |
87969c8c | 132 | uint32_t w3; |
133 | uint32_t w2; | |
134 | uint32_t w1; | |
135 | uint32_t w0; | |
136 | #endif | |
137 | } words32; | |
138 | ||
139 | struct | |
80b97f7f | 140 | #ifdef __MINGW32__ |
141 | /* Make sure we are using gnu-style bitfield handling. */ | |
142 | __attribute__ ((gcc_struct)) | |
143 | #endif | |
87969c8c | 144 | { |
e7b8ec29 | 145 | #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
87969c8c | 146 | unsigned negative:1; |
147 | unsigned exponent:15; | |
148 | unsigned quiet_nan:1; | |
529ebc2a | 149 | unsigned mantissa0:15; |
150 | unsigned mantissa1:32; | |
151 | unsigned mantissa2:32; | |
152 | unsigned mantissa3:32; | |
e7b8ec29 | 153 | #else |
529ebc2a | 154 | unsigned mantissa3:32; |
155 | unsigned mantissa2:32; | |
156 | unsigned mantissa1:32; | |
157 | unsigned mantissa0:15; | |
87969c8c | 158 | unsigned quiet_nan:1; |
159 | unsigned exponent:15; | |
160 | unsigned negative:1; | |
161 | #endif | |
529ebc2a | 162 | } ieee_nan; |
87969c8c | 163 | |
164 | } ieee854_float128; | |
165 | ||
166 | ||
167 | /* Get two 64 bit ints from a long double. */ | |
168 | #define GET_FLT128_WORDS64(ix0,ix1,d) \ | |
169 | do { \ | |
170 | ieee854_float128 u; \ | |
171 | u.value = (d); \ | |
172 | (ix0) = u.words64.high; \ | |
173 | (ix1) = u.words64.low; \ | |
174 | } while (0) | |
175 | ||
176 | /* Set a long double from two 64 bit ints. */ | |
177 | #define SET_FLT128_WORDS64(d,ix0,ix1) \ | |
178 | do { \ | |
179 | ieee854_float128 u; \ | |
180 | u.words64.high = (ix0); \ | |
181 | u.words64.low = (ix1); \ | |
182 | (d) = u.value; \ | |
183 | } while (0) | |
184 | ||
185 | /* Get the more significant 64 bits of a long double mantissa. */ | |
186 | #define GET_FLT128_MSW64(v,d) \ | |
187 | do { \ | |
188 | ieee854_float128 u; \ | |
189 | u.value = (d); \ | |
190 | (v) = u.words64.high; \ | |
191 | } while (0) | |
192 | ||
193 | /* Set the more significant 64 bits of a long double mantissa from an int. */ | |
194 | #define SET_FLT128_MSW64(d,v) \ | |
195 | do { \ | |
196 | ieee854_float128 u; \ | |
197 | u.value = (d); \ | |
198 | u.words64.high = (v); \ | |
199 | (d) = u.value; \ | |
200 | } while (0) | |
201 | ||
202 | /* Get the least significant 64 bits of a long double mantissa. */ | |
203 | #define GET_FLT128_LSW64(v,d) \ | |
204 | do { \ | |
205 | ieee854_float128 u; \ | |
206 | u.value = (d); \ | |
207 | (v) = u.words64.low; \ | |
208 | } while (0) | |
209 | ||
210 | ||
211 | #define IEEE854_FLOAT128_BIAS 0x3fff | |
212 | ||
b12676a5 | 213 | #define QUADFP_NAN 0 |
214 | #define QUADFP_INFINITE 1 | |
215 | #define QUADFP_ZERO 2 | |
216 | #define QUADFP_SUBNORMAL 3 | |
217 | #define QUADFP_NORMAL 4 | |
218 | #define fpclassifyq(x) \ | |
219 | __builtin_fpclassify (QUADFP_NAN, QUADFP_INFINITE, QUADFP_NORMAL, \ | |
220 | QUADFP_SUBNORMAL, QUADFP_ZERO, x) | |
87969c8c | 221 | |
c98f0ea6 | 222 | #ifndef math_opt_barrier |
223 | # define math_opt_barrier(x) \ | |
224 | ({ __typeof (x) __x = (x); __asm ("" : "+m" (__x)); __x; }) | |
225 | # define math_force_eval(x) \ | |
226 | ({ __typeof (x) __x = (x); __asm __volatile__ ("" : : "m" (__x)); }) | |
227 | #endif | |
228 | ||
229 | /* math_narrow_eval reduces its floating-point argument to the range | |
230 | and precision of its semantic type. (The original evaluation may | |
231 | still occur with excess range and precision, so the result may be | |
232 | affected by double rounding.) */ | |
233 | #define math_narrow_eval(x) (x) | |
234 | ||
235 | /* If X (which is not a NaN) is subnormal, force an underflow | |
236 | exception. */ | |
237 | #define math_check_force_underflow(x) \ | |
238 | do \ | |
239 | { \ | |
240 | __float128 force_underflow_tmp = (x); \ | |
241 | if (fabsq (force_underflow_tmp) < FLT128_MIN) \ | |
242 | { \ | |
243 | __float128 force_underflow_tmp2 \ | |
244 | = force_underflow_tmp * force_underflow_tmp; \ | |
245 | math_force_eval (force_underflow_tmp2); \ | |
246 | } \ | |
247 | } \ | |
248 | while (0) | |
249 | /* Likewise, but X is also known to be nonnegative. */ | |
250 | #define math_check_force_underflow_nonneg(x) \ | |
251 | do \ | |
252 | { \ | |
253 | __float128 force_underflow_tmp = (x); \ | |
254 | if (force_underflow_tmp < FLT128_MIN) \ | |
255 | { \ | |
256 | __float128 force_underflow_tmp2 \ | |
257 | = force_underflow_tmp * force_underflow_tmp; \ | |
258 | math_force_eval (force_underflow_tmp2); \ | |
259 | } \ | |
260 | } \ | |
261 | while (0) | |
262 | ||
e409716d | 263 | /* Likewise, for both real and imaginary parts of a complex |
264 | result. */ | |
265 | #define math_check_force_underflow_complex(x) \ | |
266 | do \ | |
267 | { \ | |
268 | __typeof (x) force_underflow_complex_tmp = (x); \ | |
269 | math_check_force_underflow (__real__ force_underflow_complex_tmp); \ | |
270 | math_check_force_underflow (__imag__ force_underflow_complex_tmp); \ | |
271 | } \ | |
272 | while (0) | |
273 | ||
274 | #ifndef HAVE_FENV_H | |
275 | # define feraiseexcept(arg) ((void) 0) | |
276 | typedef int fenv_t; | |
277 | # define feholdexcept(arg) ((void) 0) | |
278 | # define fesetround(arg) ((void) 0) | |
279 | # define feupdateenv(arg) ((void) (arg)) | |
280 | # define fesetenv(arg) ((void) (arg)) | |
281 | # define fetestexcept(arg) 0 | |
282 | # define feclearexcept(arg) ((void) 0) | |
283 | #else | |
284 | # ifndef HAVE_FEHOLDEXCEPT | |
285 | # define feholdexcept(arg) ((void) 0) | |
286 | # endif | |
287 | # ifndef HAVE_FESETROUND | |
288 | # define fesetround(arg) ((void) 0) | |
289 | # endif | |
290 | # ifndef HAVE_FEUPDATEENV | |
291 | # define feupdateenv(arg) ((void) (arg)) | |
292 | # endif | |
293 | # ifndef HAVE_FESETENV | |
294 | # define fesetenv(arg) ((void) (arg)) | |
295 | # endif | |
296 | # ifndef HAVE_FETESTEXCEPT | |
297 | # define fetestexcept(arg) 0 | |
298 | # endif | |
299 | #endif | |
300 | ||
301 | #ifndef __glibc_likely | |
302 | # define __glibc_likely(cond) __builtin_expect ((cond), 1) | |
303 | #endif | |
304 | ||
305 | #ifndef __glibc_unlikely | |
306 | # define __glibc_unlikely(cond) __builtin_expect ((cond), 0) | |
307 | #endif | |
308 | ||
309 | #if defined HAVE_FENV_H && defined HAVE_FESETROUND && defined HAVE_FEUPDATEENV | |
310 | struct rm_ctx | |
311 | { | |
312 | fenv_t env; | |
313 | bool updated_status; | |
314 | }; | |
315 | ||
316 | # define SET_RESTORE_ROUNDF128(RM) \ | |
317 | struct rm_ctx ctx __attribute__((cleanup (libc_feresetround_ctx))); \ | |
318 | libc_feholdsetround_ctx (&ctx, (RM)) | |
319 | ||
320 | static inline __attribute__ ((always_inline)) void | |
321 | libc_feholdsetround_ctx (struct rm_ctx *ctx, int round) | |
322 | { | |
323 | ctx->updated_status = false; | |
324 | ||
325 | /* Update rounding mode only if different. */ | |
326 | if (__glibc_unlikely (round != fegetround ())) | |
327 | { | |
328 | ctx->updated_status = true; | |
329 | fegetenv (&ctx->env); | |
330 | fesetround (round); | |
331 | } | |
332 | } | |
333 | ||
334 | static inline __attribute__ ((always_inline)) void | |
335 | libc_feresetround_ctx (struct rm_ctx *ctx) | |
336 | { | |
337 | /* Restore the rounding mode if updated. */ | |
338 | if (__glibc_unlikely (ctx->updated_status)) | |
339 | feupdateenv (&ctx->env); | |
340 | } | |
341 | #else | |
342 | # define SET_RESTORE_ROUNDF128(RM) ((void) 0) | |
343 | #endif | |
344 | ||
87969c8c | 345 | #endif |