blob: 85fc58478f3a4f13ebfc31997a65505bfdc71d5a [file] [log] [blame]
Szabolcs Nagy86067a72017-08-11 15:35:12 +01001/*
Szabolcs Nagy1b945972018-05-14 14:46:40 +01002 * Configuration for math routines.
Szabolcs Nagy86067a72017-08-11 15:35:12 +01003 *
Szabolcs Nagy11253b02018-11-12 11:10:57 +00004 * Copyright (c) 2017-2018, Arm Limited.
5 * SPDX-License-Identifier: MIT
Szabolcs Nagy86067a72017-08-11 15:35:12 +01006 */
7
8#ifndef _MATH_CONFIG_H
9#define _MATH_CONFIG_H
10
Szabolcs Nagy86067a72017-08-11 15:35:12 +010011#include <math.h>
12#include <stdint.h>
13
14#ifndef WANT_ROUNDING
Wilco Dijkstra6f41cff2020-02-27 16:25:40 +000015/* If defined to 1, return correct results for special cases in non-nearest
16 rounding modes (logf (1.0f) returns 0.0f with FE_DOWNWARD rather than -0.0f).
17 This may be set to 0 if there is no fenv support or if math functions only
18 get called in round to nearest mode. */
Szabolcs Nagy97599cd2017-09-28 15:41:06 +010019# define WANT_ROUNDING 1
Szabolcs Nagy86067a72017-08-11 15:35:12 +010020#endif
21#ifndef WANT_ERRNO
Wilco Dijkstra6f41cff2020-02-27 16:25:40 +000022/* If defined to 1, set errno in math functions according to ISO C. Many math
23 libraries do not set errno, so this is 0 by default. It may need to be
24 set to 1 if math.h has (math_errhandling & MATH_ERRNO) != 0. */
25# define WANT_ERRNO 0
Szabolcs Nagy86067a72017-08-11 15:35:12 +010026#endif
27#ifndef WANT_ERRNO_UFLOW
28/* Set errno to ERANGE if result underflows to 0 (in all rounding modes). */
Szabolcs Nagy97599cd2017-09-28 15:41:06 +010029# define WANT_ERRNO_UFLOW (WANT_ROUNDING && WANT_ERRNO)
Szabolcs Nagy86067a72017-08-11 15:35:12 +010030#endif
31
Szabolcs Nagy39b01912018-05-10 15:35:06 +010032/* Compiler can inline round as a single instruction. */
33#ifndef HAVE_FAST_ROUND
34# if __aarch64__
35# define HAVE_FAST_ROUND 1
36# else
37# define HAVE_FAST_ROUND 0
38# endif
39#endif
Szabolcs Nagy86067a72017-08-11 15:35:12 +010040
Szabolcs Nagy39b01912018-05-10 15:35:06 +010041/* Compiler can inline lround, but not (long)round(x). */
42#ifndef HAVE_FAST_LROUND
43# if __aarch64__ && (100*__GNUC__ + __GNUC_MINOR__) >= 408 && __NO_MATH_ERRNO__
44# define HAVE_FAST_LROUND 1
45# else
46# define HAVE_FAST_LROUND 0
47# endif
48#endif
49
Szabolcs Nagy56091b72018-05-31 18:13:20 +010050/* Compiler can inline fma as a single instruction. */
51#ifndef HAVE_FAST_FMA
Wilco Dijkstra51757592018-08-17 16:51:32 +010052# if defined FP_FAST_FMA || __aarch64__
Szabolcs Nagy56091b72018-05-31 18:13:20 +010053# define HAVE_FAST_FMA 1
54# else
55# define HAVE_FAST_FMA 0
56# endif
57#endif
58
Szabolcs Nagy9e6e14e2019-11-06 18:01:15 +000059/* Provide *_finite symbols and some of the glibc hidden symbols
60 so libmathlib can be used with binaries compiled against glibc
61 to interpose math functions with both static and dynamic linking. */
62#ifndef USE_GLIBC_ABI
63# if __GNUC__
64# define USE_GLIBC_ABI 1
65# else
66# define USE_GLIBC_ABI 0
67# endif
68#endif
69
70/* Optionally used extensions. */
71#ifdef __GNUC__
72# define HIDDEN __attribute__ ((__visibility__ ("hidden")))
73# define NOINLINE __attribute__ ((noinline))
Szabolcs Nagy17cd8af2019-11-06 18:10:17 +000074# define UNUSED __attribute__ ((unused))
Szabolcs Nagy9e6e14e2019-11-06 18:01:15 +000075# define likely(x) __builtin_expect (!!(x), 1)
76# define unlikely(x) __builtin_expect (x, 0)
Szabolcs Nagy2c6c2402019-11-06 18:14:23 +000077# if __GNUC__ >= 9
78# define attribute_copy(f) __attribute__ ((copy (f)))
79# else
80# define attribute_copy(f)
81# endif
Szabolcs Nagy9e6e14e2019-11-06 18:01:15 +000082# define strong_alias(f, a) \
Szabolcs Nagy2c6c2402019-11-06 18:14:23 +000083 extern __typeof (f) a __attribute__ ((alias (#f))) attribute_copy (f);
Szabolcs Nagy9e6e14e2019-11-06 18:01:15 +000084# define hidden_alias(f, a) \
Szabolcs Nagy2c6c2402019-11-06 18:14:23 +000085 extern __typeof (f) a __attribute__ ((alias (#f), visibility ("hidden"))) \
86 attribute_copy (f);
Szabolcs Nagy9e6e14e2019-11-06 18:01:15 +000087#else
88# define HIDDEN
89# define NOINLINE
Szabolcs Nagy17cd8af2019-11-06 18:10:17 +000090# define UNUSED
Szabolcs Nagy9e6e14e2019-11-06 18:01:15 +000091# define likely(x) (x)
92# define unlikely(x) (x)
93#endif
94
Szabolcs Nagy39b01912018-05-10 15:35:06 +010095#if HAVE_FAST_ROUND
Szabolcs Nagydd178df2018-07-04 09:54:29 +010096/* When set, the roundtoint and converttoint functions are provided with
97 the semantics documented below. */
Szabolcs Nagy97599cd2017-09-28 15:41:06 +010098# define TOINT_INTRINSICS 1
Szabolcs Nagy86067a72017-08-11 15:35:12 +010099
Szabolcs Nagydd178df2018-07-04 09:54:29 +0100100/* Round x to nearest int in all rounding modes, ties have to be rounded
101 consistently with converttoint so the results match. If the result
102 would be outside of [-2^31, 2^31-1] then the semantics is unspecified. */
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100103static inline double_t
104roundtoint (double_t x)
105{
Szabolcs Nagy39b01912018-05-10 15:35:06 +0100106 return round (x);
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100107}
108
Szabolcs Nagydd178df2018-07-04 09:54:29 +0100109/* Convert x to nearest int in all rounding modes, ties have to be rounded
110 consistently with roundtoint. If the result is not representible in an
111 int32_t then the semantics is unspecified. */
112static inline int32_t
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100113converttoint (double_t x)
114{
Szabolcs Nagy39b01912018-05-10 15:35:06 +0100115# if HAVE_FAST_LROUND
116 return lround (x);
117# else
118 return (long) round (x);
119# endif
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100120}
121#endif
122
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100123static inline uint32_t
124asuint (float f)
125{
126 union
127 {
128 float f;
129 uint32_t i;
130 } u = {f};
131 return u.i;
132}
133
134static inline float
135asfloat (uint32_t i)
136{
137 union
138 {
139 uint32_t i;
140 float f;
141 } u = {i};
142 return u.f;
143}
144
145static inline uint64_t
146asuint64 (double f)
147{
148 union
149 {
150 double f;
151 uint64_t i;
152 } u = {f};
153 return u.i;
154}
155
156static inline double
157asdouble (uint64_t i)
158{
159 union
160 {
161 uint64_t i;
162 double f;
163 } u = {i};
164 return u.f;
165}
166
Szabolcs Nagy6f846e12017-09-28 15:45:41 +0100167#ifndef IEEE_754_2008_SNAN
168# define IEEE_754_2008_SNAN 1
169#endif
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100170static inline int
Szabolcs Nagy6f846e12017-09-28 15:45:41 +0100171issignalingf_inline (float x)
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100172{
173 uint32_t ix = asuint (x);
Szabolcs Nagy6f846e12017-09-28 15:45:41 +0100174 if (!IEEE_754_2008_SNAN)
175 return (ix & 0x7fc00000) == 0x7fc00000;
176 return 2 * (ix ^ 0x00400000) > 2u * 0x7fc00000;
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100177}
178
Szabolcs Nagyed0ecff2018-06-06 18:17:16 +0100179static inline int
180issignaling_inline (double x)
181{
182 uint64_t ix = asuint64 (x);
183 if (!IEEE_754_2008_SNAN)
184 return (ix & 0x7ff8000000000000) == 0x7ff8000000000000;
185 return 2 * (ix ^ 0x0008000000000000) > 2 * 0x7ff8000000000000ULL;
186}
187
Szabolcs Nagy5eb9d192018-05-11 13:20:04 +0100188#if __aarch64__ && __GNUC__
Szabolcs Nagy5fa69e12018-06-12 17:18:24 +0100189/* Prevent the optimization of a floating-point expression. */
190static inline float
191opt_barrier_float (float x)
192{
193 __asm__ __volatile__ ("" : "+w" (x));
194 return x;
195}
196static inline double
197opt_barrier_double (double x)
198{
199 __asm__ __volatile__ ("" : "+w" (x));
200 return x;
201}
202/* Force the evaluation of a floating-point expression for its side-effect. */
Szabolcs Nagy5eb9d192018-05-11 13:20:04 +0100203static inline void
204force_eval_float (float x)
205{
206 __asm__ __volatile__ ("" : "+w" (x));
207}
208static inline void
209force_eval_double (double x)
210{
211 __asm__ __volatile__ ("" : "+w" (x));
212}
213#else
Szabolcs Nagyf6717402018-06-14 17:22:11 +0100214static inline float
Szabolcs Nagy5fa69e12018-06-12 17:18:24 +0100215opt_barrier_float (float x)
216{
217 volatile float y = x;
218 return y;
219}
Szabolcs Nagyf6717402018-06-14 17:22:11 +0100220static inline double
Szabolcs Nagy5fa69e12018-06-12 17:18:24 +0100221opt_barrier_double (double x)
222{
223 volatile double y = x;
224 return y;
225}
226static inline void
Szabolcs Nagy5eb9d192018-05-11 13:20:04 +0100227force_eval_float (float x)
228{
Szabolcs Nagy17cd8af2019-11-06 18:10:17 +0000229 volatile float y UNUSED = x;
Szabolcs Nagy5eb9d192018-05-11 13:20:04 +0100230}
231static inline void
232force_eval_double (double x)
233{
Szabolcs Nagy17cd8af2019-11-06 18:10:17 +0000234 volatile double y UNUSED = x;
Szabolcs Nagy5eb9d192018-05-11 13:20:04 +0100235}
236#endif
237
238/* Evaluate an expression as the specified type, normally a type
239 cast should be enough, but compilers implement non-standard
240 excess-precision handling, so when FLT_EVAL_METHOD != 0 then
241 these functions may need to be customized. */
242static inline float
243eval_as_float (float x)
244{
245 return x;
246}
247static inline double
248eval_as_double (double x)
249{
250 return x;
251}
252
Szabolcs Nagy58ce45c2018-06-29 11:06:13 +0100253/* Error handling tail calls for special cases, with a sign argument.
254 The sign of the return value is set if the argument is non-zero. */
255
256/* The result overflows. */
Szabolcs Nagyc65db172018-05-10 17:53:31 +0100257HIDDEN float __math_oflowf (uint32_t);
Szabolcs Nagy58ce45c2018-06-29 11:06:13 +0100258/* The result underflows to 0 in nearest rounding mode. */
Szabolcs Nagyc65db172018-05-10 17:53:31 +0100259HIDDEN float __math_uflowf (uint32_t);
Szabolcs Nagy58ce45c2018-06-29 11:06:13 +0100260/* The result underflows to 0 in some directed rounding mode only. */
Szabolcs Nagyc65db172018-05-10 17:53:31 +0100261HIDDEN float __math_may_uflowf (uint32_t);
Szabolcs Nagy58ce45c2018-06-29 11:06:13 +0100262/* Division by zero. */
Szabolcs Nagyc65db172018-05-10 17:53:31 +0100263HIDDEN float __math_divzerof (uint32_t);
Szabolcs Nagy58ce45c2018-06-29 11:06:13 +0100264/* The result overflows. */
Szabolcs Nagy872aa772018-04-27 16:17:24 +0100265HIDDEN double __math_oflow (uint32_t);
Szabolcs Nagy58ce45c2018-06-29 11:06:13 +0100266/* The result underflows to 0 in nearest rounding mode. */
Szabolcs Nagy872aa772018-04-27 16:17:24 +0100267HIDDEN double __math_uflow (uint32_t);
Szabolcs Nagy58ce45c2018-06-29 11:06:13 +0100268/* The result underflows to 0 in some directed rounding mode only. */
Szabolcs Nagy872aa772018-04-27 16:17:24 +0100269HIDDEN double __math_may_uflow (uint32_t);
Szabolcs Nagy58ce45c2018-06-29 11:06:13 +0100270/* Division by zero. */
Szabolcs Nagy872aa772018-04-27 16:17:24 +0100271HIDDEN double __math_divzero (uint32_t);
Szabolcs Nagy58ce45c2018-06-29 11:06:13 +0100272
Szabolcs Nagy872aa772018-04-27 16:17:24 +0100273/* Error handling using input checking. */
Szabolcs Nagy58ce45c2018-06-29 11:06:13 +0100274
275/* Invalid input unless it is a quiet NaN. */
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100276HIDDEN float __math_invalidf (float);
Szabolcs Nagy58ce45c2018-06-29 11:06:13 +0100277/* Invalid input unless it is a quiet NaN. */
Szabolcs Nagy872aa772018-04-27 16:17:24 +0100278HIDDEN double __math_invalid (double);
Szabolcs Nagy58ce45c2018-06-29 11:06:13 +0100279
Szabolcs Nagy872aa772018-04-27 16:17:24 +0100280/* Error handling using output checking, only for errno setting. */
Szabolcs Nagy58ce45c2018-06-29 11:06:13 +0100281
282/* Check if the result overflowed to infinity. */
Szabolcs Nagy872aa772018-04-27 16:17:24 +0100283HIDDEN double __math_check_oflow (double);
Szabolcs Nagy58ce45c2018-06-29 11:06:13 +0100284/* Check if the result underflowed to 0. */
Szabolcs Nagy872aa772018-04-27 16:17:24 +0100285HIDDEN double __math_check_uflow (double);
286
Szabolcs Nagy58ce45c2018-06-29 11:06:13 +0100287/* Check if the result overflowed to infinity. */
Szabolcs Nagy872aa772018-04-27 16:17:24 +0100288static inline double
289check_oflow (double x)
290{
291 return WANT_ERRNO ? __math_check_oflow (x) : x;
292}
293
Szabolcs Nagy58ce45c2018-06-29 11:06:13 +0100294/* Check if the result underflowed to 0. */
Szabolcs Nagy872aa772018-04-27 16:17:24 +0100295static inline double
296check_uflow (double x)
297{
298 return WANT_ERRNO ? __math_check_uflow (x) : x;
299}
300
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100301
302/* Shared between expf, exp2f and powf. */
303#define EXP2F_TABLE_BITS 5
304#define EXP2F_POLY_ORDER 3
305extern const struct exp2f_data
306{
307 uint64_t tab[1 << EXP2F_TABLE_BITS];
308 double shift_scaled;
309 double poly[EXP2F_POLY_ORDER];
310 double shift;
311 double invln2_scaled;
312 double poly_scaled[EXP2F_POLY_ORDER];
Szabolcs Nagy97599cd2017-09-28 15:41:06 +0100313} __exp2f_data HIDDEN;
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100314
315#define LOGF_TABLE_BITS 4
316#define LOGF_POLY_ORDER 4
317extern const struct logf_data
318{
319 struct
320 {
321 double invc, logc;
322 } tab[1 << LOGF_TABLE_BITS];
323 double ln2;
Szabolcs Nagye353e492017-09-28 16:12:20 +0100324 double poly[LOGF_POLY_ORDER - 1]; /* First order coefficient is 1. */
Szabolcs Nagy97599cd2017-09-28 15:41:06 +0100325} __logf_data HIDDEN;
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100326
327#define LOG2F_TABLE_BITS 4
328#define LOG2F_POLY_ORDER 4
329extern const struct log2f_data
330{
331 struct
332 {
333 double invc, logc;
334 } tab[1 << LOG2F_TABLE_BITS];
335 double poly[LOG2F_POLY_ORDER];
Szabolcs Nagy97599cd2017-09-28 15:41:06 +0100336} __log2f_data HIDDEN;
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100337
338#define POWF_LOG2_TABLE_BITS 4
339#define POWF_LOG2_POLY_ORDER 5
340#if TOINT_INTRINSICS
Szabolcs Nagy97599cd2017-09-28 15:41:06 +0100341# define POWF_SCALE_BITS EXP2F_TABLE_BITS
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100342#else
Szabolcs Nagy97599cd2017-09-28 15:41:06 +0100343# define POWF_SCALE_BITS 0
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100344#endif
345#define POWF_SCALE ((double) (1 << POWF_SCALE_BITS))
346extern const struct powf_log2_data
347{
348 struct
349 {
350 double invc, logc;
351 } tab[1 << POWF_LOG2_TABLE_BITS];
352 double poly[POWF_LOG2_POLY_ORDER];
Szabolcs Nagy97599cd2017-09-28 15:41:06 +0100353} __powf_log2_data HIDDEN;
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100354
Szabolcs Nagy872aa772018-04-27 16:17:24 +0100355
356#define EXP_TABLE_BITS 7
357#define EXP_POLY_ORDER 5
358/* Use polynomial that is optimized for a wider input range. This may be
359 needed for good precision in non-nearest rounding and !TOINT_INTRINSICS. */
360#define EXP_POLY_WIDE 0
361/* Use close to nearest rounding toint when !TOINT_INTRINSICS. This may be
362 needed for good precision in non-nearest rouning and !EXP_POLY_WIDE. */
363#define EXP_USE_TOINT_NARROW 0
364#define EXP2_POLY_ORDER 5
365#define EXP2_POLY_WIDE 0
Szabolcs Nagy5e838912018-06-29 09:56:54 +0100366extern const struct exp_data
367{
Szabolcs Nagy872aa772018-04-27 16:17:24 +0100368 double invln2N;
369 double shift;
370 double negln2hiN;
371 double negln2loN;
372 double poly[4]; /* Last four coefficients. */
373 double exp2_shift;
374 double exp2_poly[EXP2_POLY_ORDER];
375 uint64_t tab[2*(1 << EXP_TABLE_BITS)];
376} __exp_data HIDDEN;
377
Szabolcs Nagy56091b72018-05-31 18:13:20 +0100378#define LOG_TABLE_BITS 7
379#define LOG_POLY_ORDER 6
380#define LOG_POLY1_ORDER 12
Szabolcs Nagy5e838912018-06-29 09:56:54 +0100381extern const struct log_data
382{
Szabolcs Nagy56091b72018-05-31 18:13:20 +0100383 double ln2hi;
384 double ln2lo;
385 double poly[LOG_POLY_ORDER - 1]; /* First coefficient is 1. */
386 double poly1[LOG_POLY1_ORDER - 1];
387 struct {double invc, logc;} tab[1 << LOG_TABLE_BITS];
388#if !HAVE_FAST_FMA
389 struct {double chi, clo;} tab2[1 << LOG_TABLE_BITS];
390#endif
391} __log_data HIDDEN;
392
Szabolcs Nagyd69e5042018-06-05 16:15:27 +0100393#define LOG2_TABLE_BITS 6
394#define LOG2_POLY_ORDER 7
395#define LOG2_POLY1_ORDER 11
Szabolcs Nagy5e838912018-06-29 09:56:54 +0100396extern const struct log2_data
397{
Szabolcs Nagyd69e5042018-06-05 16:15:27 +0100398 double invln2hi;
399 double invln2lo;
400 double poly[LOG2_POLY_ORDER - 1];
401 double poly1[LOG2_POLY1_ORDER - 1];
402 struct {double invc, logc;} tab[1 << LOG2_TABLE_BITS];
403#if !HAVE_FAST_FMA
404 struct {double chi, clo;} tab2[1 << LOG2_TABLE_BITS];
405#endif
406} __log2_data HIDDEN;
407
Szabolcs Nagya6230322018-06-21 17:53:15 +0100408#define POW_LOG_TABLE_BITS 7
409#define POW_LOG_POLY_ORDER 8
Szabolcs Nagy5e838912018-06-29 09:56:54 +0100410extern const struct pow_log_data
411{
Szabolcs Nagyed0ecff2018-06-06 18:17:16 +0100412 double ln2hi;
413 double ln2lo;
414 double poly[POW_LOG_POLY_ORDER - 1]; /* First coefficient is 1. */
Szabolcs Nagya6230322018-06-21 17:53:15 +0100415 /* Note: the pad field is unused, but allows slightly faster indexing. */
416 struct {double invc, pad, logc, logctail;} tab[1 << POW_LOG_TABLE_BITS];
Szabolcs Nagyed0ecff2018-06-06 18:17:16 +0100417} __pow_log_data HIDDEN;
418
Szabolcs Nagy86067a72017-08-11 15:35:12 +0100419#endif