1 | /* |
2 | * ==================================================== |
3 | * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. |
4 | * |
5 | * Developed at SunPro, a Sun Microsystems, Inc. business. |
6 | * Permission to use, copy, modify, and distribute this |
7 | * software is freely granted, provided that this notice |
8 | * is preserved. |
9 | * ==================================================== |
10 | */ |
11 | |
12 | /* |
13 | * from: @(#)fdlibm.h 5.1 93/09/24 |
14 | */ |
15 | |
16 | #ifndef _MATH_PRIVATE_H_ |
17 | #define _MATH_PRIVATE_H_ |
18 | |
19 | #include <endian.h> |
20 | #include <stdint.h> |
21 | #include <sys/types.h> |
22 | #include <fenv.h> |
23 | #include <float.h> |
24 | #include <get-rounding-mode.h> |
25 | |
26 | /* Gather machine dependent _Floatn support. */ |
27 | #include <bits/floatn.h> |
28 | |
29 | /* The original fdlibm code used statements like: |
30 | n0 = ((*(int*)&one)>>29)^1; * index of high word * |
31 | ix0 = *(n0+(int*)&x); * high word of x * |
32 | ix1 = *((1-n0)+(int*)&x); * low word of x * |
33 | to dig two 32 bit words out of the 64 bit IEEE floating point |
34 | value. That is non-ANSI, and, moreover, the gcc instruction |
35 | scheduler gets it wrong. We instead use the following macros. |
36 | Unlike the original code, we determine the endianness at compile |
37 | time, not at run time; I don't see much benefit to selecting |
38 | endianness at run time. */ |
39 | |
40 | /* A union which permits us to convert between a double and two 32 bit |
41 | ints. */ |
42 | |
43 | #if __FLOAT_WORD_ORDER == __BIG_ENDIAN |
44 | |
45 | typedef union |
46 | { |
47 | double value; |
48 | struct |
49 | { |
50 | uint32_t msw; |
51 | uint32_t lsw; |
52 | } parts; |
53 | uint64_t word; |
54 | } ieee_double_shape_type; |
55 | |
56 | #endif |
57 | |
58 | #if __FLOAT_WORD_ORDER == __LITTLE_ENDIAN |
59 | |
60 | typedef union |
61 | { |
62 | double value; |
63 | struct |
64 | { |
65 | uint32_t lsw; |
66 | uint32_t msw; |
67 | } parts; |
68 | uint64_t word; |
69 | } ieee_double_shape_type; |
70 | |
71 | #endif |
72 | |
73 | /* Get two 32 bit ints from a double. */ |
74 | |
75 | #define (ix0,ix1,d) \ |
76 | do { \ |
77 | ieee_double_shape_type ew_u; \ |
78 | ew_u.value = (d); \ |
79 | (ix0) = ew_u.parts.msw; \ |
80 | (ix1) = ew_u.parts.lsw; \ |
81 | } while (0) |
82 | |
83 | /* Get the more significant 32 bit int from a double. */ |
84 | |
85 | #ifndef GET_HIGH_WORD |
86 | # define GET_HIGH_WORD(i,d) \ |
87 | do { \ |
88 | ieee_double_shape_type gh_u; \ |
89 | gh_u.value = (d); \ |
90 | (i) = gh_u.parts.msw; \ |
91 | } while (0) |
92 | #endif |
93 | |
94 | /* Get the less significant 32 bit int from a double. */ |
95 | |
96 | #ifndef GET_LOW_WORD |
97 | # define GET_LOW_WORD(i,d) \ |
98 | do { \ |
99 | ieee_double_shape_type gl_u; \ |
100 | gl_u.value = (d); \ |
101 | (i) = gl_u.parts.lsw; \ |
102 | } while (0) |
103 | #endif |
104 | |
105 | /* Get all in one, efficient on 64-bit machines. */ |
106 | #ifndef EXTRACT_WORDS64 |
107 | # define EXTRACT_WORDS64(i,d) \ |
108 | do { \ |
109 | ieee_double_shape_type gh_u; \ |
110 | gh_u.value = (d); \ |
111 | (i) = gh_u.word; \ |
112 | } while (0) |
113 | #endif |
114 | |
115 | /* Set a double from two 32 bit ints. */ |
116 | #ifndef INSERT_WORDS |
117 | # define INSERT_WORDS(d,ix0,ix1) \ |
118 | do { \ |
119 | ieee_double_shape_type iw_u; \ |
120 | iw_u.parts.msw = (ix0); \ |
121 | iw_u.parts.lsw = (ix1); \ |
122 | (d) = iw_u.value; \ |
123 | } while (0) |
124 | #endif |
125 | |
126 | /* Get all in one, efficient on 64-bit machines. */ |
127 | #ifndef INSERT_WORDS64 |
128 | # define INSERT_WORDS64(d,i) \ |
129 | do { \ |
130 | ieee_double_shape_type iw_u; \ |
131 | iw_u.word = (i); \ |
132 | (d) = iw_u.value; \ |
133 | } while (0) |
134 | #endif |
135 | |
136 | /* Set the more significant 32 bits of a double from an int. */ |
137 | #ifndef SET_HIGH_WORD |
138 | #define SET_HIGH_WORD(d,v) \ |
139 | do { \ |
140 | ieee_double_shape_type sh_u; \ |
141 | sh_u.value = (d); \ |
142 | sh_u.parts.msw = (v); \ |
143 | (d) = sh_u.value; \ |
144 | } while (0) |
145 | #endif |
146 | |
147 | /* Set the less significant 32 bits of a double from an int. */ |
148 | #ifndef SET_LOW_WORD |
149 | # define SET_LOW_WORD(d,v) \ |
150 | do { \ |
151 | ieee_double_shape_type sl_u; \ |
152 | sl_u.value = (d); \ |
153 | sl_u.parts.lsw = (v); \ |
154 | (d) = sl_u.value; \ |
155 | } while (0) |
156 | #endif |
157 | |
158 | /* A union which permits us to convert between a float and a 32 bit |
159 | int. */ |
160 | |
161 | typedef union |
162 | { |
163 | float value; |
164 | uint32_t word; |
165 | } ieee_float_shape_type; |
166 | |
167 | /* Get a 32 bit int from a float. */ |
168 | #ifndef GET_FLOAT_WORD |
169 | # define GET_FLOAT_WORD(i,d) \ |
170 | do { \ |
171 | ieee_float_shape_type gf_u; \ |
172 | gf_u.value = (d); \ |
173 | (i) = gf_u.word; \ |
174 | } while (0) |
175 | #endif |
176 | |
177 | /* Set a float from a 32 bit int. */ |
178 | #ifndef SET_FLOAT_WORD |
179 | # define SET_FLOAT_WORD(d,i) \ |
180 | do { \ |
181 | ieee_float_shape_type sf_u; \ |
182 | sf_u.word = (i); \ |
183 | (d) = sf_u.value; \ |
184 | } while (0) |
185 | #endif |
186 | |
187 | /* We need to guarantee an expansion of name when building |
188 | ldbl-128 files as another type (e.g _Float128). */ |
189 | #define mathx_hidden_def(name) hidden_def(name) |
190 | |
191 | /* Get long double macros from a separate header. */ |
192 | #include <math_ldbl.h> |
193 | |
194 | /* Include function declarations for each floating-point. */ |
195 | #define _Mdouble_ double |
196 | #define _MSUF_ |
197 | #include <math_private_calls.h> |
198 | #undef _MSUF_ |
199 | #undef _Mdouble_ |
200 | |
201 | #define _Mdouble_ float |
202 | #define _MSUF_ f |
203 | #define __MATH_DECLARING_FLOAT |
204 | #include <math_private_calls.h> |
205 | #undef __MATH_DECLARING_FLOAT |
206 | #undef _MSUF_ |
207 | #undef _Mdouble_ |
208 | |
209 | #define _Mdouble_ long double |
210 | #define _MSUF_ l |
211 | #define __MATH_DECLARING_LONG_DOUBLE |
212 | #include <math_private_calls.h> |
213 | #undef __MATH_DECLARING_LONG_DOUBLE |
214 | #undef _MSUF_ |
215 | #undef _Mdouble_ |
216 | |
217 | #if __HAVE_DISTINCT_FLOAT128 |
218 | # define _Mdouble_ _Float128 |
219 | # define _MSUF_ f128 |
220 | # define __MATH_DECLARING_FLOATN |
221 | # include <math_private_calls.h> |
222 | # undef __MATH_DECLARING_FLOATN |
223 | # undef _MSUF_ |
224 | # undef _Mdouble_ |
225 | #endif |
226 | |
227 | #if __HAVE_DISTINCT_FLOAT128 |
228 | |
229 | /* __builtin_isinf_sign is broken in GCC < 7 for float128. */ |
230 | # if ! __GNUC_PREREQ (7, 0) |
231 | # include <ieee754_float128.h> |
232 | extern inline int |
233 | __isinff128 (_Float128 x) |
234 | { |
235 | int64_t hx, lx; |
236 | GET_FLOAT128_WORDS64 (hx, lx, x); |
237 | lx |= (hx & 0x7fffffffffffffffLL) ^ 0x7fff000000000000LL; |
238 | lx |= -lx; |
239 | return ~(lx >> 63) & (hx >> 62); |
240 | } |
241 | # endif |
242 | |
243 | extern inline _Float128 |
244 | fabsf128 (_Float128 x) |
245 | { |
246 | return __builtin_fabsf128 (x); |
247 | } |
248 | #endif |
249 | |
250 | |
251 | |
252 | /* Prototypes for functions of the IBM Accurate Mathematical Library. */ |
253 | extern double __exp1 (double __x, double __xx, double __error); |
254 | extern double __sin (double __x); |
255 | extern double __cos (double __x); |
256 | extern int __branred (double __x, double *__a, double *__aa); |
257 | extern void __doasin (double __x, double __dx, double __v[]); |
258 | extern void __dubsin (double __x, double __dx, double __v[]); |
259 | extern void __dubcos (double __x, double __dx, double __v[]); |
260 | extern double __halfulp (double __x, double __y); |
261 | extern double __sin32 (double __x, double __res, double __res1); |
262 | extern double __cos32 (double __x, double __res, double __res1); |
263 | extern double __mpsin (double __x, double __dx, bool __range_reduce); |
264 | extern double __mpcos (double __x, double __dx, bool __range_reduce); |
265 | extern double __slowexp (double __x); |
266 | extern double __slowpow (double __x, double __y, double __z); |
267 | extern void __docos (double __x, double __dx, double __v[]); |
268 | |
269 | #ifndef math_opt_barrier |
270 | # define math_opt_barrier(x) \ |
271 | ({ __typeof (x) __x = (x); __asm ("" : "+m" (__x)); __x; }) |
272 | # define math_force_eval(x) \ |
273 | ({ __typeof (x) __x = (x); __asm __volatile__ ("" : : "m" (__x)); }) |
274 | #endif |
275 | |
276 | /* math_narrow_eval reduces its floating-point argument to the range |
277 | and precision of its semantic type. (The original evaluation may |
278 | still occur with excess range and precision, so the result may be |
279 | affected by double rounding.) */ |
280 | #if FLT_EVAL_METHOD == 0 |
281 | # define math_narrow_eval(x) (x) |
282 | #else |
283 | # if FLT_EVAL_METHOD == 1 |
284 | # define excess_precision(type) __builtin_types_compatible_p (type, float) |
285 | # else |
286 | # define excess_precision(type) (__builtin_types_compatible_p (type, float) \ |
287 | || __builtin_types_compatible_p (type, \ |
288 | double)) |
289 | # endif |
290 | # define math_narrow_eval(x) \ |
291 | ({ \ |
292 | __typeof (x) math_narrow_eval_tmp = (x); \ |
293 | if (excess_precision (__typeof (math_narrow_eval_tmp))) \ |
294 | __asm__ ("" : "+m" (math_narrow_eval_tmp)); \ |
295 | math_narrow_eval_tmp; \ |
296 | }) |
297 | #endif |
298 | |
299 | #define fabs_tg(x) __MATH_TG ((x), (__typeof (x)) __builtin_fabs, (x)) |
300 | |
301 | /* These must be function-like macros because some __MATH_TG |
302 | implementations macro-expand the function-name argument before |
303 | concatenating a suffix to it. */ |
304 | #define min_of_type_f() FLT_MIN |
305 | #define min_of_type_() DBL_MIN |
306 | #define min_of_type_l() LDBL_MIN |
307 | #define min_of_type_f128() FLT128_MIN |
308 | |
309 | #define min_of_type(x) __MATH_TG ((x), (__typeof (x)) min_of_type_, ()) |
310 | |
311 | /* If X (which is not a NaN) is subnormal, force an underflow |
312 | exception. */ |
313 | #define math_check_force_underflow(x) \ |
314 | do \ |
315 | { \ |
316 | __typeof (x) force_underflow_tmp = (x); \ |
317 | if (fabs_tg (force_underflow_tmp) \ |
318 | < min_of_type (force_underflow_tmp)) \ |
319 | { \ |
320 | __typeof (force_underflow_tmp) force_underflow_tmp2 \ |
321 | = force_underflow_tmp * force_underflow_tmp; \ |
322 | math_force_eval (force_underflow_tmp2); \ |
323 | } \ |
324 | } \ |
325 | while (0) |
326 | /* Likewise, but X is also known to be nonnegative. */ |
327 | #define math_check_force_underflow_nonneg(x) \ |
328 | do \ |
329 | { \ |
330 | __typeof (x) force_underflow_tmp = (x); \ |
331 | if (force_underflow_tmp \ |
332 | < min_of_type (force_underflow_tmp)) \ |
333 | { \ |
334 | __typeof (force_underflow_tmp) force_underflow_tmp2 \ |
335 | = force_underflow_tmp * force_underflow_tmp; \ |
336 | math_force_eval (force_underflow_tmp2); \ |
337 | } \ |
338 | } \ |
339 | while (0) |
340 | /* Likewise, for both real and imaginary parts of a complex |
341 | result. */ |
342 | #define math_check_force_underflow_complex(x) \ |
343 | do \ |
344 | { \ |
345 | __typeof (x) force_underflow_complex_tmp = (x); \ |
346 | math_check_force_underflow (__real__ force_underflow_complex_tmp); \ |
347 | math_check_force_underflow (__imag__ force_underflow_complex_tmp); \ |
348 | } \ |
349 | while (0) |
350 | |
351 | /* The standards only specify one variant of the fenv.h interfaces. |
352 | But at least for some architectures we can be more efficient if we |
353 | know what operations are going to be performed. Therefore we |
354 | define additional interfaces. By default they refer to the normal |
355 | interfaces. */ |
356 | |
357 | static __always_inline void |
358 | default_libc_feholdexcept (fenv_t *e) |
359 | { |
360 | (void) __feholdexcept (e); |
361 | } |
362 | |
363 | #ifndef libc_feholdexcept |
364 | # define libc_feholdexcept default_libc_feholdexcept |
365 | #endif |
366 | #ifndef libc_feholdexceptf |
367 | # define libc_feholdexceptf default_libc_feholdexcept |
368 | #endif |
369 | #ifndef libc_feholdexceptl |
370 | # define libc_feholdexceptl default_libc_feholdexcept |
371 | #endif |
372 | |
373 | static __always_inline void |
374 | default_libc_fesetround (int r) |
375 | { |
376 | (void) __fesetround (r); |
377 | } |
378 | |
379 | #ifndef libc_fesetround |
380 | # define libc_fesetround default_libc_fesetround |
381 | #endif |
382 | #ifndef libc_fesetroundf |
383 | # define libc_fesetroundf default_libc_fesetround |
384 | #endif |
385 | #ifndef libc_fesetroundl |
386 | # define libc_fesetroundl default_libc_fesetround |
387 | #endif |
388 | |
389 | static __always_inline void |
390 | default_libc_feholdexcept_setround (fenv_t *e, int r) |
391 | { |
392 | __feholdexcept (e); |
393 | __fesetround (r); |
394 | } |
395 | |
396 | #ifndef libc_feholdexcept_setround |
397 | # define libc_feholdexcept_setround default_libc_feholdexcept_setround |
398 | #endif |
399 | #ifndef libc_feholdexcept_setroundf |
400 | # define libc_feholdexcept_setroundf default_libc_feholdexcept_setround |
401 | #endif |
402 | #ifndef libc_feholdexcept_setroundl |
403 | # define libc_feholdexcept_setroundl default_libc_feholdexcept_setround |
404 | #endif |
405 | |
406 | #ifndef libc_feholdsetround_53bit |
407 | # define libc_feholdsetround_53bit libc_feholdsetround |
408 | #endif |
409 | |
410 | #ifndef libc_fetestexcept |
411 | # define libc_fetestexcept fetestexcept |
412 | #endif |
413 | #ifndef libc_fetestexceptf |
414 | # define libc_fetestexceptf fetestexcept |
415 | #endif |
416 | #ifndef libc_fetestexceptl |
417 | # define libc_fetestexceptl fetestexcept |
418 | #endif |
419 | |
420 | static __always_inline void |
421 | default_libc_fesetenv (fenv_t *e) |
422 | { |
423 | (void) __fesetenv (e); |
424 | } |
425 | |
426 | #ifndef libc_fesetenv |
427 | # define libc_fesetenv default_libc_fesetenv |
428 | #endif |
429 | #ifndef libc_fesetenvf |
430 | # define libc_fesetenvf default_libc_fesetenv |
431 | #endif |
432 | #ifndef libc_fesetenvl |
433 | # define libc_fesetenvl default_libc_fesetenv |
434 | #endif |
435 | |
436 | static __always_inline void |
437 | default_libc_feupdateenv (fenv_t *e) |
438 | { |
439 | (void) __feupdateenv (e); |
440 | } |
441 | |
442 | #ifndef libc_feupdateenv |
443 | # define libc_feupdateenv default_libc_feupdateenv |
444 | #endif |
445 | #ifndef libc_feupdateenvf |
446 | # define libc_feupdateenvf default_libc_feupdateenv |
447 | #endif |
448 | #ifndef libc_feupdateenvl |
449 | # define libc_feupdateenvl default_libc_feupdateenv |
450 | #endif |
451 | |
452 | #ifndef libc_feresetround_53bit |
453 | # define libc_feresetround_53bit libc_feresetround |
454 | #endif |
455 | |
456 | static __always_inline int |
457 | default_libc_feupdateenv_test (fenv_t *e, int ex) |
458 | { |
459 | int ret = fetestexcept (ex); |
460 | __feupdateenv (e); |
461 | return ret; |
462 | } |
463 | |
464 | #ifndef libc_feupdateenv_test |
465 | # define libc_feupdateenv_test default_libc_feupdateenv_test |
466 | #endif |
467 | #ifndef libc_feupdateenv_testf |
468 | # define libc_feupdateenv_testf default_libc_feupdateenv_test |
469 | #endif |
470 | #ifndef libc_feupdateenv_testl |
471 | # define libc_feupdateenv_testl default_libc_feupdateenv_test |
472 | #endif |
473 | |
474 | /* Save and set the rounding mode. The use of fenv_t to store the old mode |
475 | allows a target-specific version of this function to avoid converting the |
476 | rounding mode from the fpu format. By default we have no choice but to |
477 | manipulate the entire env. */ |
478 | |
479 | #ifndef libc_feholdsetround |
480 | # define libc_feholdsetround libc_feholdexcept_setround |
481 | #endif |
482 | #ifndef libc_feholdsetroundf |
483 | # define libc_feholdsetroundf libc_feholdexcept_setroundf |
484 | #endif |
485 | #ifndef libc_feholdsetroundl |
486 | # define libc_feholdsetroundl libc_feholdexcept_setroundl |
487 | #endif |
488 | |
489 | /* ... and the reverse. */ |
490 | |
491 | #ifndef libc_feresetround |
492 | # define libc_feresetround libc_feupdateenv |
493 | #endif |
494 | #ifndef libc_feresetroundf |
495 | # define libc_feresetroundf libc_feupdateenvf |
496 | #endif |
497 | #ifndef libc_feresetroundl |
498 | # define libc_feresetroundl libc_feupdateenvl |
499 | #endif |
500 | |
501 | /* ... and a version that also discards exceptions. */ |
502 | |
503 | #ifndef libc_feresetround_noex |
504 | # define libc_feresetround_noex libc_fesetenv |
505 | #endif |
506 | #ifndef libc_feresetround_noexf |
507 | # define libc_feresetround_noexf libc_fesetenvf |
508 | #endif |
509 | #ifndef libc_feresetround_noexl |
510 | # define libc_feresetround_noexl libc_fesetenvl |
511 | #endif |
512 | |
513 | #ifndef HAVE_RM_CTX |
514 | # define HAVE_RM_CTX 0 |
515 | #endif |
516 | |
517 | #if HAVE_RM_CTX |
518 | /* Set/Restore Rounding Modes only when necessary. If defined, these functions |
519 | set/restore floating point state only if the state needed within the lexical |
520 | block is different from the current state. This saves a lot of time when |
521 | the floating point unit is much slower than the fixed point units. */ |
522 | |
523 | # ifndef libc_feholdsetround_noex_ctx |
524 | # define libc_feholdsetround_noex_ctx libc_feholdsetround_ctx |
525 | # endif |
526 | # ifndef libc_feholdsetround_noexf_ctx |
527 | # define libc_feholdsetround_noexf_ctx libc_feholdsetroundf_ctx |
528 | # endif |
529 | # ifndef libc_feholdsetround_noexl_ctx |
530 | # define libc_feholdsetround_noexl_ctx libc_feholdsetroundl_ctx |
531 | # endif |
532 | |
533 | # ifndef libc_feresetround_noex_ctx |
534 | # define libc_feresetround_noex_ctx libc_fesetenv_ctx |
535 | # endif |
536 | # ifndef libc_feresetround_noexf_ctx |
537 | # define libc_feresetround_noexf_ctx libc_fesetenvf_ctx |
538 | # endif |
539 | # ifndef libc_feresetround_noexl_ctx |
540 | # define libc_feresetround_noexl_ctx libc_fesetenvl_ctx |
541 | # endif |
542 | |
543 | #else |
544 | |
545 | /* Default implementation using standard fenv functions. |
546 | Avoid unnecessary rounding mode changes by first checking the |
547 | current rounding mode. Note the use of __glibc_unlikely is |
548 | important for performance. */ |
549 | |
550 | static __always_inline void |
551 | libc_feholdsetround_ctx (struct rm_ctx *ctx, int round) |
552 | { |
553 | ctx->updated_status = false; |
554 | |
555 | /* Update rounding mode only if different. */ |
556 | if (__glibc_unlikely (round != get_rounding_mode ())) |
557 | { |
558 | ctx->updated_status = true; |
559 | __fegetenv (&ctx->env); |
560 | __fesetround (round); |
561 | } |
562 | } |
563 | |
564 | static __always_inline void |
565 | libc_feresetround_ctx (struct rm_ctx *ctx) |
566 | { |
567 | /* Restore the rounding mode if updated. */ |
568 | if (__glibc_unlikely (ctx->updated_status)) |
569 | __feupdateenv (&ctx->env); |
570 | } |
571 | |
572 | static __always_inline void |
573 | libc_feholdsetround_noex_ctx (struct rm_ctx *ctx, int round) |
574 | { |
575 | /* Save exception flags and rounding mode, and disable exception |
576 | traps. */ |
577 | __feholdexcept (&ctx->env); |
578 | |
579 | /* Update rounding mode only if different. */ |
580 | if (__glibc_unlikely (round != get_rounding_mode ())) |
581 | __fesetround (round); |
582 | } |
583 | |
584 | static __always_inline void |
585 | libc_feresetround_noex_ctx (struct rm_ctx *ctx) |
586 | { |
587 | /* Restore exception flags and rounding mode. */ |
588 | __fesetenv (&ctx->env); |
589 | } |
590 | |
591 | # define libc_feholdsetroundf_ctx libc_feholdsetround_ctx |
592 | # define libc_feholdsetroundl_ctx libc_feholdsetround_ctx |
593 | # define libc_feresetroundf_ctx libc_feresetround_ctx |
594 | # define libc_feresetroundl_ctx libc_feresetround_ctx |
595 | |
596 | # define libc_feholdsetround_noexf_ctx libc_feholdsetround_noex_ctx |
597 | # define libc_feholdsetround_noexl_ctx libc_feholdsetround_noex_ctx |
598 | # define libc_feresetround_noexf_ctx libc_feresetround_noex_ctx |
599 | # define libc_feresetround_noexl_ctx libc_feresetround_noex_ctx |
600 | |
601 | #endif |
602 | |
603 | #ifndef libc_feholdsetround_53bit_ctx |
604 | # define libc_feholdsetround_53bit_ctx libc_feholdsetround_ctx |
605 | #endif |
606 | #ifndef libc_feresetround_53bit_ctx |
607 | # define libc_feresetround_53bit_ctx libc_feresetround_ctx |
608 | #endif |
609 | |
610 | #define SET_RESTORE_ROUND_GENERIC(RM,ROUNDFUNC,CLEANUPFUNC) \ |
611 | struct rm_ctx ctx __attribute__((cleanup (CLEANUPFUNC ## _ctx))); \ |
612 | ROUNDFUNC ## _ctx (&ctx, (RM)) |
613 | |
614 | /* Set the rounding mode within a lexical block. Restore the rounding mode to |
615 | the value at the start of the block. The exception mode must be preserved. |
616 | Exceptions raised within the block must be set in the exception flags. |
617 | Non-stop mode may be enabled inside the block. */ |
618 | |
619 | #define SET_RESTORE_ROUND(RM) \ |
620 | SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround, libc_feresetround) |
621 | #define SET_RESTORE_ROUNDF(RM) \ |
622 | SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetroundf, libc_feresetroundf) |
623 | #define SET_RESTORE_ROUNDL(RM) \ |
624 | SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetroundl, libc_feresetroundl) |
625 | |
626 | /* Set the rounding mode within a lexical block. Restore the rounding mode to |
627 | the value at the start of the block. The exception mode must be preserved. |
628 | Exceptions raised within the block must be discarded, and exception flags |
629 | are restored to the value at the start of the block. |
630 | Non-stop mode must be enabled inside the block. */ |
631 | |
632 | #define SET_RESTORE_ROUND_NOEX(RM) \ |
633 | SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_noex, \ |
634 | libc_feresetround_noex) |
635 | #define SET_RESTORE_ROUND_NOEXF(RM) \ |
636 | SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_noexf, \ |
637 | libc_feresetround_noexf) |
638 | #define SET_RESTORE_ROUND_NOEXL(RM) \ |
639 | SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_noexl, \ |
640 | libc_feresetround_noexl) |
641 | |
642 | /* Like SET_RESTORE_ROUND, but also set rounding precision to 53 bits. */ |
643 | #define SET_RESTORE_ROUND_53BIT(RM) \ |
644 | SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_53bit, \ |
645 | libc_feresetround_53bit) |
646 | |
647 | #endif /* _MATH_PRIVATE_H_ */ |
648 | |