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