1570af302Sopenharmony_ci#ifndef _LIBM_H
2570af302Sopenharmony_ci#define _LIBM_H
3570af302Sopenharmony_ci
4570af302Sopenharmony_ci#include <stdint.h>
5570af302Sopenharmony_ci#include <float.h>
6570af302Sopenharmony_ci#include <math.h>
7570af302Sopenharmony_ci#include <endian.h>
8570af302Sopenharmony_ci#include "../include/features.h"
9570af302Sopenharmony_ci
10570af302Sopenharmony_ci
11570af302Sopenharmony_ci#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
12570af302Sopenharmony_ci#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN
13570af302Sopenharmony_ciunion ldshape {
14570af302Sopenharmony_ci	long double f;
15570af302Sopenharmony_ci	struct {
16570af302Sopenharmony_ci		uint64_t m;
17570af302Sopenharmony_ci		uint16_t se;
18570af302Sopenharmony_ci	} i;
19570af302Sopenharmony_ci};
20570af302Sopenharmony_ci#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN
21570af302Sopenharmony_ci/* This is the m68k variant of 80-bit long double, and this definition only works
22570af302Sopenharmony_ci * on archs where the alignment requirement of uint64_t is <= 4. */
23570af302Sopenharmony_ciunion ldshape {
24570af302Sopenharmony_ci	long double f;
25570af302Sopenharmony_ci	struct {
26570af302Sopenharmony_ci		uint16_t se;
27570af302Sopenharmony_ci		uint16_t pad;
28570af302Sopenharmony_ci		uint64_t m;
29570af302Sopenharmony_ci	} i;
30570af302Sopenharmony_ci};
31570af302Sopenharmony_ci#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN
32570af302Sopenharmony_ciunion ldshape {
33570af302Sopenharmony_ci	long double f;
34570af302Sopenharmony_ci	struct {
35570af302Sopenharmony_ci		uint64_t lo;
36570af302Sopenharmony_ci		uint32_t mid;
37570af302Sopenharmony_ci		uint16_t top;
38570af302Sopenharmony_ci		uint16_t se;
39570af302Sopenharmony_ci	} i;
40570af302Sopenharmony_ci	struct {
41570af302Sopenharmony_ci		uint64_t lo;
42570af302Sopenharmony_ci		uint64_t hi;
43570af302Sopenharmony_ci	} i2;
44570af302Sopenharmony_ci};
45570af302Sopenharmony_ci#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN
46570af302Sopenharmony_ciunion ldshape {
47570af302Sopenharmony_ci	long double f;
48570af302Sopenharmony_ci	struct {
49570af302Sopenharmony_ci		uint16_t se;
50570af302Sopenharmony_ci		uint16_t top;
51570af302Sopenharmony_ci		uint32_t mid;
52570af302Sopenharmony_ci		uint64_t lo;
53570af302Sopenharmony_ci	} i;
54570af302Sopenharmony_ci	struct {
55570af302Sopenharmony_ci		uint64_t hi;
56570af302Sopenharmony_ci		uint64_t lo;
57570af302Sopenharmony_ci	} i2;
58570af302Sopenharmony_ci};
59570af302Sopenharmony_ci#else
60570af302Sopenharmony_ci#error Unsupported long double representation
61570af302Sopenharmony_ci#endif
62570af302Sopenharmony_ci
63570af302Sopenharmony_ci/* Support non-nearest rounding mode.  */
64570af302Sopenharmony_ci#define WANT_ROUNDING 1
65570af302Sopenharmony_ci/* Support signaling NaNs.  */
66570af302Sopenharmony_ci#define WANT_SNAN 0
67570af302Sopenharmony_ci
68570af302Sopenharmony_ci#if WANT_SNAN
69570af302Sopenharmony_ci#error SNaN is unsupported
70570af302Sopenharmony_ci#else
71570af302Sopenharmony_ci#define issignalingf_inline(x) 0
72570af302Sopenharmony_ci#define issignaling_inline(x) 0
73570af302Sopenharmony_ci#endif
74570af302Sopenharmony_ci
75570af302Sopenharmony_ci#ifndef TOINT_INTRINSICS
76570af302Sopenharmony_ci#define TOINT_INTRINSICS 0
77570af302Sopenharmony_ci#endif
78570af302Sopenharmony_ci
79570af302Sopenharmony_ci#if TOINT_INTRINSICS
80570af302Sopenharmony_ci/* Round x to nearest int in all rounding modes, ties have to be rounded
81570af302Sopenharmony_ci   consistently with converttoint so the results match.  If the result
82570af302Sopenharmony_ci   would be outside of [-2^31, 2^31-1] then the semantics is unspecified.  */
83570af302Sopenharmony_cistatic double_t roundtoint(double_t);
84570af302Sopenharmony_ci
85570af302Sopenharmony_ci/* Convert x to nearest int in all rounding modes, ties have to be rounded
86570af302Sopenharmony_ci   consistently with roundtoint.  If the result is not representible in an
87570af302Sopenharmony_ci   int32_t then the semantics is unspecified.  */
88570af302Sopenharmony_cistatic int32_t converttoint(double_t);
89570af302Sopenharmony_ci#endif
90570af302Sopenharmony_ci
91570af302Sopenharmony_ci/* Helps static branch prediction so hot path can be better optimized.  */
92570af302Sopenharmony_ci#ifdef __GNUC__
93570af302Sopenharmony_ci#define predict_true(x) __builtin_expect(!!(x), 1)
94570af302Sopenharmony_ci#define predict_false(x) __builtin_expect(x, 0)
95570af302Sopenharmony_ci#else
96570af302Sopenharmony_ci#define predict_true(x) (x)
97570af302Sopenharmony_ci#define predict_false(x) (x)
98570af302Sopenharmony_ci#endif
99570af302Sopenharmony_ci
100570af302Sopenharmony_ci/* Evaluate an expression as the specified type. With standard excess
101570af302Sopenharmony_ci   precision handling a type cast or assignment is enough (with
102570af302Sopenharmony_ci   -ffloat-store an assignment is required, in old compilers argument
103570af302Sopenharmony_ci   passing and return statement may not drop excess precision).  */
104570af302Sopenharmony_ci
105570af302Sopenharmony_cistatic inline float eval_as_float(float x)
106570af302Sopenharmony_ci{
107570af302Sopenharmony_ci	float y = x;
108570af302Sopenharmony_ci	return y;
109570af302Sopenharmony_ci}
110570af302Sopenharmony_ci
111570af302Sopenharmony_cistatic inline double eval_as_double(double x)
112570af302Sopenharmony_ci{
113570af302Sopenharmony_ci	double y = x;
114570af302Sopenharmony_ci	return y;
115570af302Sopenharmony_ci}
116570af302Sopenharmony_ci
117570af302Sopenharmony_ci/* fp_barrier returns its input, but limits code transformations
118570af302Sopenharmony_ci   as if it had a side-effect (e.g. observable io) and returned
119570af302Sopenharmony_ci   an arbitrary value.  */
120570af302Sopenharmony_ci
121570af302Sopenharmony_ci#ifndef fp_barrierf
122570af302Sopenharmony_ci#define fp_barrierf fp_barrierf
123570af302Sopenharmony_cistatic inline float fp_barrierf(float x)
124570af302Sopenharmony_ci{
125570af302Sopenharmony_ci	volatile float y = x;
126570af302Sopenharmony_ci	return y;
127570af302Sopenharmony_ci}
128570af302Sopenharmony_ci#endif
129570af302Sopenharmony_ci
130570af302Sopenharmony_ci#ifndef fp_barrier
131570af302Sopenharmony_ci#define fp_barrier fp_barrier
132570af302Sopenharmony_cistatic inline double fp_barrier(double x)
133570af302Sopenharmony_ci{
134570af302Sopenharmony_ci	volatile double y = x;
135570af302Sopenharmony_ci	return y;
136570af302Sopenharmony_ci}
137570af302Sopenharmony_ci#endif
138570af302Sopenharmony_ci
139570af302Sopenharmony_ci#ifndef fp_barrierl
140570af302Sopenharmony_ci#define fp_barrierl fp_barrierl
141570af302Sopenharmony_cistatic inline long double fp_barrierl(long double x)
142570af302Sopenharmony_ci{
143570af302Sopenharmony_ci	volatile long double y = x;
144570af302Sopenharmony_ci	return y;
145570af302Sopenharmony_ci}
146570af302Sopenharmony_ci#endif
147570af302Sopenharmony_ci
148570af302Sopenharmony_ci/* fp_force_eval ensures that the input value is computed when that's
149570af302Sopenharmony_ci   otherwise unused.  To prevent the constant folding of the input
150570af302Sopenharmony_ci   expression, an additional fp_barrier may be needed or a compilation
151570af302Sopenharmony_ci   mode that does so (e.g. -frounding-math in gcc). Then it can be
152570af302Sopenharmony_ci   used to evaluate an expression for its fenv side-effects only.   */
153570af302Sopenharmony_ci
154570af302Sopenharmony_ci#ifndef fp_force_evalf
155570af302Sopenharmony_ci#define fp_force_evalf fp_force_evalf
156570af302Sopenharmony_cistatic inline void fp_force_evalf(float x)
157570af302Sopenharmony_ci{
158570af302Sopenharmony_ci	volatile float y;
159570af302Sopenharmony_ci	y = x;
160570af302Sopenharmony_ci}
161570af302Sopenharmony_ci#endif
162570af302Sopenharmony_ci
163570af302Sopenharmony_ci#ifndef fp_force_eval
164570af302Sopenharmony_ci#define fp_force_eval fp_force_eval
165570af302Sopenharmony_cistatic inline void fp_force_eval(double x)
166570af302Sopenharmony_ci{
167570af302Sopenharmony_ci	volatile double y;
168570af302Sopenharmony_ci	y = x;
169570af302Sopenharmony_ci}
170570af302Sopenharmony_ci#endif
171570af302Sopenharmony_ci
172570af302Sopenharmony_ci#ifndef fp_force_evall
173570af302Sopenharmony_ci#define fp_force_evall fp_force_evall
174570af302Sopenharmony_cistatic inline void fp_force_evall(long double x)
175570af302Sopenharmony_ci{
176570af302Sopenharmony_ci	volatile long double y;
177570af302Sopenharmony_ci	y = x;
178570af302Sopenharmony_ci}
179570af302Sopenharmony_ci#endif
180570af302Sopenharmony_ci
181570af302Sopenharmony_ci#define FORCE_EVAL(x) do {                        \
182570af302Sopenharmony_ci	if (sizeof(x) == sizeof(float)) {         \
183570af302Sopenharmony_ci		fp_force_evalf(x);                \
184570af302Sopenharmony_ci	} else if (sizeof(x) == sizeof(double)) { \
185570af302Sopenharmony_ci		fp_force_eval(x);                 \
186570af302Sopenharmony_ci	} else {                                  \
187570af302Sopenharmony_ci		fp_force_evall(x);                \
188570af302Sopenharmony_ci	}                                         \
189570af302Sopenharmony_ci} while(0)
190570af302Sopenharmony_ci
191570af302Sopenharmony_ci#define asuint(f) ((union{float _f; uint32_t _i;}){f})._i
192570af302Sopenharmony_ci#define asfloat(i) ((union{uint32_t _i; float _f;}){i})._f
193570af302Sopenharmony_ci#define asuint64(f) ((union{double _f; uint64_t _i;}){f})._i
194570af302Sopenharmony_ci#define asdouble(i) ((union{uint64_t _i; double _f;}){i})._f
195570af302Sopenharmony_ci
196570af302Sopenharmony_ci#define EXTRACT_WORDS(hi,lo,d)                    \
197570af302Sopenharmony_cido {                                              \
198570af302Sopenharmony_ci  uint64_t __u = asuint64(d);                     \
199570af302Sopenharmony_ci  (hi) = __u >> 32;                               \
200570af302Sopenharmony_ci  (lo) = (uint32_t)__u;                           \
201570af302Sopenharmony_ci} while (0)
202570af302Sopenharmony_ci
203570af302Sopenharmony_ci#define GET_HIGH_WORD(hi,d)                       \
204570af302Sopenharmony_cido {                                              \
205570af302Sopenharmony_ci  (hi) = asuint64(d) >> 32;                       \
206570af302Sopenharmony_ci} while (0)
207570af302Sopenharmony_ci
208570af302Sopenharmony_ci#define GET_LOW_WORD(lo,d)                        \
209570af302Sopenharmony_cido {                                              \
210570af302Sopenharmony_ci  (lo) = (uint32_t)asuint64(d);                   \
211570af302Sopenharmony_ci} while (0)
212570af302Sopenharmony_ci
213570af302Sopenharmony_ci#define INSERT_WORDS(d,hi,lo)                     \
214570af302Sopenharmony_cido {                                              \
215570af302Sopenharmony_ci  (d) = asdouble(((uint64_t)(hi)<<32) | (uint32_t)(lo)); \
216570af302Sopenharmony_ci} while (0)
217570af302Sopenharmony_ci
218570af302Sopenharmony_ci#define SET_HIGH_WORD(d,hi)                       \
219570af302Sopenharmony_ci  INSERT_WORDS(d, hi, (uint32_t)asuint64(d))
220570af302Sopenharmony_ci
221570af302Sopenharmony_ci#define SET_LOW_WORD(d,lo)                        \
222570af302Sopenharmony_ci  INSERT_WORDS(d, asuint64(d)>>32, lo)
223570af302Sopenharmony_ci
224570af302Sopenharmony_ci#define GET_FLOAT_WORD(w,d)                       \
225570af302Sopenharmony_cido {                                              \
226570af302Sopenharmony_ci  (w) = asuint(d);                                \
227570af302Sopenharmony_ci} while (0)
228570af302Sopenharmony_ci
229570af302Sopenharmony_ci#define SET_FLOAT_WORD(d,w)                       \
230570af302Sopenharmony_cido {                                              \
231570af302Sopenharmony_ci  (d) = asfloat(w);                               \
232570af302Sopenharmony_ci} while (0)
233570af302Sopenharmony_ci
234570af302Sopenharmony_cihidden int    __rem_pio2_large(double*,double*,int,int,int);
235570af302Sopenharmony_ci
236570af302Sopenharmony_cihidden int    __rem_pio2(double,double*);
237570af302Sopenharmony_cihidden double __sin(double,double,int);
238570af302Sopenharmony_cihidden double __cos(double,double);
239570af302Sopenharmony_cihidden double __tan(double,double,int);
240570af302Sopenharmony_cihidden double __expo2(double);
241570af302Sopenharmony_ci
242570af302Sopenharmony_cihidden int    __rem_pio2f(float,double*);
243570af302Sopenharmony_cihidden float  __sindf(double);
244570af302Sopenharmony_cihidden float  __cosdf(double);
245570af302Sopenharmony_cihidden float  __tandf(double,int);
246570af302Sopenharmony_cihidden float  __expo2f(float);
247570af302Sopenharmony_ci
248570af302Sopenharmony_cihidden int __rem_pio2l(long double, long double *);
249570af302Sopenharmony_cihidden long double __sinl(long double, long double, int);
250570af302Sopenharmony_cihidden long double __cosl(long double, long double);
251570af302Sopenharmony_cihidden long double __tanl(long double, long double, int);
252570af302Sopenharmony_ci
253570af302Sopenharmony_cihidden long double __polevll(long double, const long double *, int);
254570af302Sopenharmony_cihidden long double __p1evll(long double, const long double *, int);
255570af302Sopenharmony_ci
256570af302Sopenharmony_ciextern int __signgam;
257570af302Sopenharmony_cihidden double __lgamma_r(double, int *);
258570af302Sopenharmony_cihidden float __lgammaf_r(float, int *);
259570af302Sopenharmony_ci
260570af302Sopenharmony_ci/* error handling functions */
261570af302Sopenharmony_cihidden float __math_xflowf(uint32_t, float);
262570af302Sopenharmony_cihidden float __math_uflowf(uint32_t);
263570af302Sopenharmony_cihidden float __math_oflowf(uint32_t);
264570af302Sopenharmony_cihidden float __math_divzerof(uint32_t);
265570af302Sopenharmony_cihidden float __math_invalidf(float);
266570af302Sopenharmony_cihidden double __math_xflow(uint32_t, double);
267570af302Sopenharmony_cihidden double __math_uflow(uint32_t);
268570af302Sopenharmony_cihidden double __math_oflow(uint32_t);
269570af302Sopenharmony_cihidden double __math_divzero(uint32_t);
270570af302Sopenharmony_cihidden double __math_invalid(double);
271570af302Sopenharmony_ci
272570af302Sopenharmony_ci#endif
273