Home | History | Annotate | Download | only in math
      1 /*
      2  * Configuration for math routines.
      3  *
      4  * Copyright (c) 2017-2018, Arm Limited.
      5  * SPDX-License-Identifier: MIT
      6  */
      7 
      8 #ifndef _MATH_CONFIG_H
      9 #define _MATH_CONFIG_H
     10 
     11 #include <math.h>
     12 #include <stdint.h>
     13 
     14 #ifndef WANT_ROUNDING
     15 /* Correct special case results in non-nearest rounding modes.  */
     16 # define WANT_ROUNDING 1
     17 #endif
     18 #ifndef WANT_ERRNO
     19 /* Set errno according to ISO C with (math_errhandling & MATH_ERRNO) != 0.  */
     20 # define WANT_ERRNO 1
     21 #endif
     22 #ifndef WANT_ERRNO_UFLOW
     23 /* Set errno to ERANGE if result underflows to 0 (in all rounding modes).  */
     24 # define WANT_ERRNO_UFLOW (WANT_ROUNDING && WANT_ERRNO)
     25 #endif
     26 
     27 /* Compiler can inline round as a single instruction.  */
     28 #ifndef HAVE_FAST_ROUND
     29 # if __aarch64__
     30 #   define HAVE_FAST_ROUND 1
     31 # else
     32 #   define HAVE_FAST_ROUND 0
     33 # endif
     34 #endif
     35 
     36 /* Compiler can inline lround, but not (long)round(x).  */
     37 #ifndef HAVE_FAST_LROUND
     38 # if __aarch64__ && (100*__GNUC__ + __GNUC_MINOR__) >= 408 && __NO_MATH_ERRNO__
     39 #   define HAVE_FAST_LROUND 1
     40 # else
     41 #   define HAVE_FAST_LROUND 0
     42 # endif
     43 #endif
     44 
     45 /* Compiler can inline fma as a single instruction.  */
     46 #ifndef HAVE_FAST_FMA
     47 # if defined FP_FAST_FMA || __aarch64__
     48 #   define HAVE_FAST_FMA 1
     49 # else
     50 #   define HAVE_FAST_FMA 0
     51 # endif
     52 #endif
     53 
     54 #if HAVE_FAST_ROUND
     55 /* When set, the roundtoint and converttoint functions are provided with
     56    the semantics documented below.  */
     57 # define TOINT_INTRINSICS 1
     58 
     59 /* Round x to nearest int in all rounding modes, ties have to be rounded
     60    consistently with converttoint so the results match.  If the result
     61    would be outside of [-2^31, 2^31-1] then the semantics is unspecified.  */
     62 static inline double_t
     63 roundtoint (double_t x)
     64 {
     65   return round (x);
     66 }
     67 
     68 /* Convert x to nearest int in all rounding modes, ties have to be rounded
     69    consistently with roundtoint.  If the result is not representible in an
     70    int32_t then the semantics is unspecified.  */
     71 static inline int32_t
     72 converttoint (double_t x)
     73 {
     74 # if HAVE_FAST_LROUND
     75   return lround (x);
     76 # else
     77   return (long) round (x);
     78 # endif
     79 }
     80 #endif
     81 
     82 static inline uint32_t
     83 asuint (float f)
     84 {
     85   union
     86   {
     87     float f;
     88     uint32_t i;
     89   } u = {f};
     90   return u.i;
     91 }
     92 
     93 static inline float
     94 asfloat (uint32_t i)
     95 {
     96   union
     97   {
     98     uint32_t i;
     99     float f;
    100   } u = {i};
    101   return u.f;
    102 }
    103 
    104 static inline uint64_t
    105 asuint64 (double f)
    106 {
    107   union
    108   {
    109     double f;
    110     uint64_t i;
    111   } u = {f};
    112   return u.i;
    113 }
    114 
    115 static inline double
    116 asdouble (uint64_t i)
    117 {
    118   union
    119   {
    120     uint64_t i;
    121     double f;
    122   } u = {i};
    123   return u.f;
    124 }
    125 
    126 #ifndef IEEE_754_2008_SNAN
    127 # define IEEE_754_2008_SNAN 1
    128 #endif
    129 static inline int
    130 issignalingf_inline (float x)
    131 {
    132   uint32_t ix = asuint (x);
    133   if (!IEEE_754_2008_SNAN)
    134     return (ix & 0x7fc00000) == 0x7fc00000;
    135   return 2 * (ix ^ 0x00400000) > 2u * 0x7fc00000;
    136 }
    137 
    138 static inline int
    139 issignaling_inline (double x)
    140 {
    141   uint64_t ix = asuint64 (x);
    142   if (!IEEE_754_2008_SNAN)
    143     return (ix & 0x7ff8000000000000) == 0x7ff8000000000000;
    144   return 2 * (ix ^ 0x0008000000000000) > 2 * 0x7ff8000000000000ULL;
    145 }
    146 
    147 #if __aarch64__ && __GNUC__
    148 /* Prevent the optimization of a floating-point expression.  */
    149 static inline float
    150 opt_barrier_float (float x)
    151 {
    152   __asm__ __volatile__ ("" : "+w" (x));
    153   return x;
    154 }
    155 static inline double
    156 opt_barrier_double (double x)
    157 {
    158   __asm__ __volatile__ ("" : "+w" (x));
    159   return x;
    160 }
    161 /* Force the evaluation of a floating-point expression for its side-effect.  */
    162 static inline void
    163 force_eval_float (float x)
    164 {
    165   __asm__ __volatile__ ("" : "+w" (x));
    166 }
    167 static inline void
    168 force_eval_double (double x)
    169 {
    170   __asm__ __volatile__ ("" : "+w" (x));
    171 }
    172 #else
    173 static inline float
    174 opt_barrier_float (float x)
    175 {
    176   volatile float y = x;
    177   return y;
    178 }
    179 static inline double
    180 opt_barrier_double (double x)
    181 {
    182   volatile double y = x;
    183   return y;
    184 }
    185 static inline void
    186 force_eval_float (float x)
    187 {
    188   volatile float y = x;
    189 }
    190 static inline void
    191 force_eval_double (double x)
    192 {
    193   volatile double y = x;
    194 }
    195 #endif
    196 
    197 /* Evaluate an expression as the specified type, normally a type
    198    cast should be enough, but compilers implement non-standard
    199    excess-precision handling, so when FLT_EVAL_METHOD != 0 then
    200    these functions may need to be customized.  */
    201 static inline float
    202 eval_as_float (float x)
    203 {
    204   return x;
    205 }
    206 static inline double
    207 eval_as_double (double x)
    208 {
    209   return x;
    210 }
    211 
    212 /* Provide *_finite symbols and some of the glibc hidden symbols
    213    so libmathlib can be used with binaries compiled against glibc
    214    to interpose math functions with both static and dynamic linking.  */
    215 #ifndef USE_GLIBC_ABI
    216 # if __GNUC__
    217 #   define USE_GLIBC_ABI 1
    218 # else
    219 #   define USE_GLIBC_ABI 0
    220 # endif
    221 #endif
    222 
    223 #ifdef __GNUC__
    224 # define HIDDEN __attribute__ ((__visibility__ ("hidden")))
    225 # define NOINLINE __attribute__ ((noinline))
    226 # define likely(x) __builtin_expect (!!(x), 1)
    227 # define unlikely(x) __builtin_expect (x, 0)
    228 # define strong_alias(f, a) \
    229   extern __typeof (f) a __attribute__ ((alias (#f)));
    230 # define hidden_alias(f, a) \
    231   extern __typeof (f) a __attribute__ ((alias (#f), visibility ("hidden")));
    232 #else
    233 # define HIDDEN
    234 # define NOINLINE
    235 # define likely(x) (x)
    236 # define unlikely(x) (x)
    237 #endif
    238 
    239 /* Error handling tail calls for special cases, with a sign argument.
    240    The sign of the return value is set if the argument is non-zero.  */
    241 
    242 /* The result overflows.  */
    243 HIDDEN float __math_oflowf (uint32_t);
    244 /* The result underflows to 0 in nearest rounding mode.  */
    245 HIDDEN float __math_uflowf (uint32_t);
    246 /* The result underflows to 0 in some directed rounding mode only.  */
    247 HIDDEN float __math_may_uflowf (uint32_t);
    248 /* Division by zero.  */
    249 HIDDEN float __math_divzerof (uint32_t);
    250 /* The result overflows.  */
    251 HIDDEN double __math_oflow (uint32_t);
    252 /* The result underflows to 0 in nearest rounding mode.  */
    253 HIDDEN double __math_uflow (uint32_t);
    254 /* The result underflows to 0 in some directed rounding mode only.  */
    255 HIDDEN double __math_may_uflow (uint32_t);
    256 /* Division by zero.  */
    257 HIDDEN double __math_divzero (uint32_t);
    258 
    259 /* Error handling using input checking.  */
    260 
    261 /* Invalid input unless it is a quiet NaN.  */
    262 HIDDEN float __math_invalidf (float);
    263 /* Invalid input unless it is a quiet NaN.  */
    264 HIDDEN double __math_invalid (double);
    265 
    266 /* Error handling using output checking, only for errno setting.  */
    267 
    268 /* Check if the result overflowed to infinity.  */
    269 HIDDEN double __math_check_oflow (double);
    270 /* Check if the result underflowed to 0.  */
    271 HIDDEN double __math_check_uflow (double);
    272 
    273 /* Check if the result overflowed to infinity.  */
    274 static inline double
    275 check_oflow (double x)
    276 {
    277   return WANT_ERRNO ? __math_check_oflow (x) : x;
    278 }
    279 
    280 /* Check if the result underflowed to 0.  */
    281 static inline double
    282 check_uflow (double x)
    283 {
    284   return WANT_ERRNO ? __math_check_uflow (x) : x;
    285 }
    286 
    287 
    288 /* Shared between expf, exp2f and powf.  */
    289 #define EXP2F_TABLE_BITS 5
    290 #define EXP2F_POLY_ORDER 3
    291 extern const struct exp2f_data
    292 {
    293   uint64_t tab[1 << EXP2F_TABLE_BITS];
    294   double shift_scaled;
    295   double poly[EXP2F_POLY_ORDER];
    296   double shift;
    297   double invln2_scaled;
    298   double poly_scaled[EXP2F_POLY_ORDER];
    299 } __exp2f_data HIDDEN;
    300 
    301 #define LOGF_TABLE_BITS 4
    302 #define LOGF_POLY_ORDER 4
    303 extern const struct logf_data
    304 {
    305   struct
    306   {
    307     double invc, logc;
    308   } tab[1 << LOGF_TABLE_BITS];
    309   double ln2;
    310   double poly[LOGF_POLY_ORDER - 1]; /* First order coefficient is 1.  */
    311 } __logf_data HIDDEN;
    312 
    313 #define LOG2F_TABLE_BITS 4
    314 #define LOG2F_POLY_ORDER 4
    315 extern const struct log2f_data
    316 {
    317   struct
    318   {
    319     double invc, logc;
    320   } tab[1 << LOG2F_TABLE_BITS];
    321   double poly[LOG2F_POLY_ORDER];
    322 } __log2f_data HIDDEN;
    323 
    324 #define POWF_LOG2_TABLE_BITS 4
    325 #define POWF_LOG2_POLY_ORDER 5
    326 #if TOINT_INTRINSICS
    327 # define POWF_SCALE_BITS EXP2F_TABLE_BITS
    328 #else
    329 # define POWF_SCALE_BITS 0
    330 #endif
    331 #define POWF_SCALE ((double) (1 << POWF_SCALE_BITS))
    332 extern const struct powf_log2_data
    333 {
    334   struct
    335   {
    336     double invc, logc;
    337   } tab[1 << POWF_LOG2_TABLE_BITS];
    338   double poly[POWF_LOG2_POLY_ORDER];
    339 } __powf_log2_data HIDDEN;
    340 
    341 
    342 #define EXP_TABLE_BITS 7
    343 #define EXP_POLY_ORDER 5
    344 /* Use polynomial that is optimized for a wider input range.  This may be
    345    needed for good precision in non-nearest rounding and !TOINT_INTRINSICS.  */
    346 #define EXP_POLY_WIDE 0
    347 /* Use close to nearest rounding toint when !TOINT_INTRINSICS.  This may be
    348    needed for good precision in non-nearest rouning and !EXP_POLY_WIDE.  */
    349 #define EXP_USE_TOINT_NARROW 0
    350 #define EXP2_POLY_ORDER 5
    351 #define EXP2_POLY_WIDE 0
    352 extern const struct exp_data
    353 {
    354   double invln2N;
    355   double shift;
    356   double negln2hiN;
    357   double negln2loN;
    358   double poly[4]; /* Last four coefficients.  */
    359   double exp2_shift;
    360   double exp2_poly[EXP2_POLY_ORDER];
    361   uint64_t tab[2*(1 << EXP_TABLE_BITS)];
    362 } __exp_data HIDDEN;
    363 
    364 #define LOG_TABLE_BITS 7
    365 #define LOG_POLY_ORDER 6
    366 #define LOG_POLY1_ORDER 12
    367 extern const struct log_data
    368 {
    369   double ln2hi;
    370   double ln2lo;
    371   double poly[LOG_POLY_ORDER - 1]; /* First coefficient is 1.  */
    372   double poly1[LOG_POLY1_ORDER - 1];
    373   struct {double invc, logc;} tab[1 << LOG_TABLE_BITS];
    374 #if !HAVE_FAST_FMA
    375   struct {double chi, clo;} tab2[1 << LOG_TABLE_BITS];
    376 #endif
    377 } __log_data HIDDEN;
    378 
    379 #define LOG2_TABLE_BITS 6
    380 #define LOG2_POLY_ORDER 7
    381 #define LOG2_POLY1_ORDER 11
    382 extern const struct log2_data
    383 {
    384   double invln2hi;
    385   double invln2lo;
    386   double poly[LOG2_POLY_ORDER - 1];
    387   double poly1[LOG2_POLY1_ORDER - 1];
    388   struct {double invc, logc;} tab[1 << LOG2_TABLE_BITS];
    389 #if !HAVE_FAST_FMA
    390   struct {double chi, clo;} tab2[1 << LOG2_TABLE_BITS];
    391 #endif
    392 } __log2_data HIDDEN;
    393 
    394 #define POW_LOG_TABLE_BITS 7
    395 #define POW_LOG_POLY_ORDER 8
    396 extern const struct pow_log_data
    397 {
    398   double ln2hi;
    399   double ln2lo;
    400   double poly[POW_LOG_POLY_ORDER - 1]; /* First coefficient is 1.  */
    401   /* Note: the pad field is unused, but allows slightly faster indexing.  */
    402   struct {double invc, pad, logc, logctail;} tab[1 << POW_LOG_TABLE_BITS];
    403 } __pow_log_data HIDDEN;
    404 
    405 #endif
    406