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
45typedef union
46{
47 double value;
48 struct
49 {
50 u_int32_t msw;
51 u_int32_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
60typedef union
61{
62 double value;
63 struct
64 {
65 u_int32_t lsw;
66 u_int32_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 EXTRACT_WORDS(ix0,ix1,d) \
76do { \
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) \
87do { \
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) \
98do { \
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) \
108do { \
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) \
118do { \
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) \
129do { \
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) \
139do { \
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) \
150do { \
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
161typedef union
162{
163 float value;
164 u_int32_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) \
170do { \
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) \
180do { \
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>
232extern 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
243extern inline _Float128
244fabsf128 (_Float128 x)
245{
246 return __builtin_fabsf128 (x);
247}
248#endif
249
250
251
252/* fdlibm kernel function */
253extern double __kernel_standard (double,double,int);
254extern float __kernel_standard_f (float,float,int);
255extern long double __kernel_standard_l (long double,long double,int);
256
257/* Prototypes for functions of the IBM Accurate Mathematical Library. */
258extern double __exp1 (double __x, double __xx, double __error);
259extern double __sin (double __x);
260extern double __cos (double __x);
261extern int __branred (double __x, double *__a, double *__aa);
262extern void __doasin (double __x, double __dx, double __v[]);
263extern void __dubsin (double __x, double __dx, double __v[]);
264extern void __dubcos (double __x, double __dx, double __v[]);
265extern double __halfulp (double __x, double __y);
266extern double __sin32 (double __x, double __res, double __res1);
267extern double __cos32 (double __x, double __res, double __res1);
268extern double __mpsin (double __x, double __dx, bool __range_reduce);
269extern double __mpcos (double __x, double __dx, bool __range_reduce);
270extern double __slowexp (double __x);
271extern double __slowpow (double __x, double __y, double __z);
272extern void __docos (double __x, double __dx, double __v[]);
273
274#ifndef math_opt_barrier
275# define math_opt_barrier(x) \
276({ __typeof (x) __x = (x); __asm ("" : "+m" (__x)); __x; })
277# define math_force_eval(x) \
278({ __typeof (x) __x = (x); __asm __volatile__ ("" : : "m" (__x)); })
279#endif
280
281/* math_narrow_eval reduces its floating-point argument to the range
282 and precision of its semantic type. (The original evaluation may
283 still occur with excess range and precision, so the result may be
284 affected by double rounding.) */
285#if FLT_EVAL_METHOD == 0
286# define math_narrow_eval(x) (x)
287#else
288# if FLT_EVAL_METHOD == 1
289# define excess_precision(type) __builtin_types_compatible_p (type, float)
290# else
291# define excess_precision(type) (__builtin_types_compatible_p (type, float) \
292 || __builtin_types_compatible_p (type, \
293 double))
294# endif
295# define math_narrow_eval(x) \
296 ({ \
297 __typeof (x) math_narrow_eval_tmp = (x); \
298 if (excess_precision (__typeof (math_narrow_eval_tmp))) \
299 __asm__ ("" : "+m" (math_narrow_eval_tmp)); \
300 math_narrow_eval_tmp; \
301 })
302#endif
303
304#if __HAVE_DISTINCT_FLOAT128
305# define __EXPR_FLT128(x, yes, no) \
306 __builtin_choose_expr (__builtin_types_compatible_p \
307 (x, long double), no, yes)
308#else
309# define __EXPR_FLT128(x, yes, no) no
310#endif
311
312
313#define fabs_tg(x) __MATH_TG ((x), (__typeof (x)) __builtin_fabs, (x))
314
315#define min_of_type(type) __builtin_choose_expr \
316 (__builtin_types_compatible_p (type, float), \
317 FLT_MIN, \
318 __builtin_choose_expr \
319 (__builtin_types_compatible_p (type, double), \
320 DBL_MIN, \
321 __EXPR_FLT128 (type, FLT128_MIN, LDBL_MIN)))
322
323/* If X (which is not a NaN) is subnormal, force an underflow
324 exception. */
325#define math_check_force_underflow(x) \
326 do \
327 { \
328 __typeof (x) force_underflow_tmp = (x); \
329 if (fabs_tg (force_underflow_tmp) \
330 < min_of_type (__typeof (force_underflow_tmp))) \
331 { \
332 __typeof (force_underflow_tmp) force_underflow_tmp2 \
333 = force_underflow_tmp * force_underflow_tmp; \
334 math_force_eval (force_underflow_tmp2); \
335 } \
336 } \
337 while (0)
338/* Likewise, but X is also known to be nonnegative. */
339#define math_check_force_underflow_nonneg(x) \
340 do \
341 { \
342 __typeof (x) force_underflow_tmp = (x); \
343 if (force_underflow_tmp \
344 < min_of_type (__typeof (force_underflow_tmp))) \
345 { \
346 __typeof (force_underflow_tmp) force_underflow_tmp2 \
347 = force_underflow_tmp * force_underflow_tmp; \
348 math_force_eval (force_underflow_tmp2); \
349 } \
350 } \
351 while (0)
352/* Likewise, for both real and imaginary parts of a complex
353 result. */
354#define math_check_force_underflow_complex(x) \
355 do \
356 { \
357 __typeof (x) force_underflow_complex_tmp = (x); \
358 math_check_force_underflow (__real__ force_underflow_complex_tmp); \
359 math_check_force_underflow (__imag__ force_underflow_complex_tmp); \
360 } \
361 while (0)
362
363/* The standards only specify one variant of the fenv.h interfaces.
364 But at least for some architectures we can be more efficient if we
365 know what operations are going to be performed. Therefore we
366 define additional interfaces. By default they refer to the normal
367 interfaces. */
368
369static __always_inline void
370default_libc_feholdexcept (fenv_t *e)
371{
372 (void) __feholdexcept (e);
373}
374
375#ifndef libc_feholdexcept
376# define libc_feholdexcept default_libc_feholdexcept
377#endif
378#ifndef libc_feholdexceptf
379# define libc_feholdexceptf default_libc_feholdexcept
380#endif
381#ifndef libc_feholdexceptl
382# define libc_feholdexceptl default_libc_feholdexcept
383#endif
384
385static __always_inline void
386default_libc_fesetround (int r)
387{
388 (void) __fesetround (r);
389}
390
391#ifndef libc_fesetround
392# define libc_fesetround default_libc_fesetround
393#endif
394#ifndef libc_fesetroundf
395# define libc_fesetroundf default_libc_fesetround
396#endif
397#ifndef libc_fesetroundl
398# define libc_fesetroundl default_libc_fesetround
399#endif
400
401static __always_inline void
402default_libc_feholdexcept_setround (fenv_t *e, int r)
403{
404 __feholdexcept (e);
405 __fesetround (r);
406}
407
408#ifndef libc_feholdexcept_setround
409# define libc_feholdexcept_setround default_libc_feholdexcept_setround
410#endif
411#ifndef libc_feholdexcept_setroundf
412# define libc_feholdexcept_setroundf default_libc_feholdexcept_setround
413#endif
414#ifndef libc_feholdexcept_setroundl
415# define libc_feholdexcept_setroundl default_libc_feholdexcept_setround
416#endif
417
418#ifndef libc_feholdsetround_53bit
419# define libc_feholdsetround_53bit libc_feholdsetround
420#endif
421
422#ifndef libc_fetestexcept
423# define libc_fetestexcept fetestexcept
424#endif
425#ifndef libc_fetestexceptf
426# define libc_fetestexceptf fetestexcept
427#endif
428#ifndef libc_fetestexceptl
429# define libc_fetestexceptl fetestexcept
430#endif
431
432static __always_inline void
433default_libc_fesetenv (fenv_t *e)
434{
435 (void) __fesetenv (e);
436}
437
438#ifndef libc_fesetenv
439# define libc_fesetenv default_libc_fesetenv
440#endif
441#ifndef libc_fesetenvf
442# define libc_fesetenvf default_libc_fesetenv
443#endif
444#ifndef libc_fesetenvl
445# define libc_fesetenvl default_libc_fesetenv
446#endif
447
448static __always_inline void
449default_libc_feupdateenv (fenv_t *e)
450{
451 (void) __feupdateenv (e);
452}
453
454#ifndef libc_feupdateenv
455# define libc_feupdateenv default_libc_feupdateenv
456#endif
457#ifndef libc_feupdateenvf
458# define libc_feupdateenvf default_libc_feupdateenv
459#endif
460#ifndef libc_feupdateenvl
461# define libc_feupdateenvl default_libc_feupdateenv
462#endif
463
464#ifndef libc_feresetround_53bit
465# define libc_feresetround_53bit libc_feresetround
466#endif
467
468static __always_inline int
469default_libc_feupdateenv_test (fenv_t *e, int ex)
470{
471 int ret = fetestexcept (ex);
472 __feupdateenv (e);
473 return ret;
474}
475
476#ifndef libc_feupdateenv_test
477# define libc_feupdateenv_test default_libc_feupdateenv_test
478#endif
479#ifndef libc_feupdateenv_testf
480# define libc_feupdateenv_testf default_libc_feupdateenv_test
481#endif
482#ifndef libc_feupdateenv_testl
483# define libc_feupdateenv_testl default_libc_feupdateenv_test
484#endif
485
486/* Save and set the rounding mode. The use of fenv_t to store the old mode
487 allows a target-specific version of this function to avoid converting the
488 rounding mode from the fpu format. By default we have no choice but to
489 manipulate the entire env. */
490
491#ifndef libc_feholdsetround
492# define libc_feholdsetround libc_feholdexcept_setround
493#endif
494#ifndef libc_feholdsetroundf
495# define libc_feholdsetroundf libc_feholdexcept_setroundf
496#endif
497#ifndef libc_feholdsetroundl
498# define libc_feholdsetroundl libc_feholdexcept_setroundl
499#endif
500
501/* ... and the reverse. */
502
503#ifndef libc_feresetround
504# define libc_feresetround libc_feupdateenv
505#endif
506#ifndef libc_feresetroundf
507# define libc_feresetroundf libc_feupdateenvf
508#endif
509#ifndef libc_feresetroundl
510# define libc_feresetroundl libc_feupdateenvl
511#endif
512
513/* ... and a version that may also discard exceptions. */
514
515#ifndef libc_feresetround_noex
516# define libc_feresetround_noex libc_fesetenv
517#endif
518#ifndef libc_feresetround_noexf
519# define libc_feresetround_noexf libc_fesetenvf
520#endif
521#ifndef libc_feresetround_noexl
522# define libc_feresetround_noexl libc_fesetenvl
523#endif
524
525#ifndef HAVE_RM_CTX
526# define HAVE_RM_CTX 0
527#endif
528
529#if HAVE_RM_CTX
530/* Set/Restore Rounding Modes only when necessary. If defined, these functions
531 set/restore floating point state only if the state needed within the lexical
532 block is different from the current state. This saves a lot of time when
533 the floating point unit is much slower than the fixed point units. */
534
535# ifndef libc_feholdsetround_noex_ctx
536# define libc_feholdsetround_noex_ctx libc_feholdsetround_ctx
537# endif
538# ifndef libc_feholdsetround_noexf_ctx
539# define libc_feholdsetround_noexf_ctx libc_feholdsetroundf_ctx
540# endif
541# ifndef libc_feholdsetround_noexl_ctx
542# define libc_feholdsetround_noexl_ctx libc_feholdsetroundl_ctx
543# endif
544
545# ifndef libc_feresetround_noex_ctx
546# define libc_feresetround_noex_ctx libc_fesetenv_ctx
547# endif
548# ifndef libc_feresetround_noexf_ctx
549# define libc_feresetround_noexf_ctx libc_fesetenvf_ctx
550# endif
551# ifndef libc_feresetround_noexl_ctx
552# define libc_feresetround_noexl_ctx libc_fesetenvl_ctx
553# endif
554
555#else
556
557/* Default implementation using standard fenv functions.
558 Avoid unnecessary rounding mode changes by first checking the
559 current rounding mode. Note the use of __glibc_unlikely is
560 important for performance. */
561
562static __always_inline void
563libc_feholdsetround_ctx (struct rm_ctx *ctx, int round)
564{
565 ctx->updated_status = false;
566
567 /* Update rounding mode only if different. */
568 if (__glibc_unlikely (round != get_rounding_mode ()))
569 {
570 ctx->updated_status = true;
571 __fegetenv (&ctx->env);
572 __fesetround (round);
573 }
574}
575
576static __always_inline void
577libc_feresetround_ctx (struct rm_ctx *ctx)
578{
579 /* Restore the rounding mode if updated. */
580 if (__glibc_unlikely (ctx->updated_status))
581 __feupdateenv (&ctx->env);
582}
583
584static __always_inline void
585libc_feholdsetround_noex_ctx (struct rm_ctx *ctx, int round)
586{
587 /* Save exception flags and rounding mode. */
588 __fegetenv (&ctx->env);
589
590 /* Update rounding mode only if different. */
591 if (__glibc_unlikely (round != get_rounding_mode ()))
592 __fesetround (round);
593}
594
595static __always_inline void
596libc_feresetround_noex_ctx (struct rm_ctx *ctx)
597{
598 /* Restore exception flags and rounding mode. */
599 __fesetenv (&ctx->env);
600}
601
602# define libc_feholdsetroundf_ctx libc_feholdsetround_ctx
603# define libc_feholdsetroundl_ctx libc_feholdsetround_ctx
604# define libc_feresetroundf_ctx libc_feresetround_ctx
605# define libc_feresetroundl_ctx libc_feresetround_ctx
606
607# define libc_feholdsetround_noexf_ctx libc_feholdsetround_noex_ctx
608# define libc_feholdsetround_noexl_ctx libc_feholdsetround_noex_ctx
609# define libc_feresetround_noexf_ctx libc_feresetround_noex_ctx
610# define libc_feresetround_noexl_ctx libc_feresetround_noex_ctx
611
612#endif
613
614#ifndef libc_feholdsetround_53bit_ctx
615# define libc_feholdsetround_53bit_ctx libc_feholdsetround_ctx
616#endif
617#ifndef libc_feresetround_53bit_ctx
618# define libc_feresetround_53bit_ctx libc_feresetround_ctx
619#endif
620
621#define SET_RESTORE_ROUND_GENERIC(RM,ROUNDFUNC,CLEANUPFUNC) \
622 struct rm_ctx ctx __attribute__((cleanup (CLEANUPFUNC ## _ctx))); \
623 ROUNDFUNC ## _ctx (&ctx, (RM))
624
625/* Set the rounding mode within a lexical block. Restore the rounding mode to
626 the value at the start of the block. The exception mode must be preserved.
627 Exceptions raised within the block must be set in the exception flags.
628 Non-stop mode may be enabled inside the block. */
629
630#define SET_RESTORE_ROUND(RM) \
631 SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround, libc_feresetround)
632#define SET_RESTORE_ROUNDF(RM) \
633 SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetroundf, libc_feresetroundf)
634#define SET_RESTORE_ROUNDL(RM) \
635 SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetroundl, libc_feresetroundl)
636
637/* Set the rounding mode within a lexical block. Restore the rounding mode to
638 the value at the start of the block. The exception mode must be preserved.
639 Exceptions raised within the block must be discarded, and exception flags
640 are restored to the value at the start of the block.
641 Non-stop mode may be enabled inside the block. */
642
643#define SET_RESTORE_ROUND_NOEX(RM) \
644 SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_noex, \
645 libc_feresetround_noex)
646#define SET_RESTORE_ROUND_NOEXF(RM) \
647 SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_noexf, \
648 libc_feresetround_noexf)
649#define SET_RESTORE_ROUND_NOEXL(RM) \
650 SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_noexl, \
651 libc_feresetround_noexl)
652
653/* Like SET_RESTORE_ROUND, but also set rounding precision to 53 bits. */
654#define SET_RESTORE_ROUND_53BIT(RM) \
655 SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_53bit, \
656 libc_feresetround_53bit)
657
658#endif /* _MATH_PRIVATE_H_ */
659