xref: /freebsd/contrib/arm-optimized-routines/math/math_err.c (revision 072a4ba82a01476eaee33781ccd241033eefcf0b)
131914882SAlex Richardson /*
231914882SAlex Richardson  * Double-precision math error handling.
331914882SAlex Richardson  *
431914882SAlex Richardson  * Copyright (c) 2018, Arm Limited.
5*072a4ba8SAndrew Turner  * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
631914882SAlex Richardson  */
731914882SAlex Richardson 
831914882SAlex Richardson #include "math_config.h"
931914882SAlex Richardson 
1031914882SAlex Richardson #if WANT_ERRNO
1131914882SAlex Richardson #include <errno.h>
1231914882SAlex Richardson /* NOINLINE reduces code size and avoids making math functions non-leaf
1331914882SAlex Richardson    when the error handling is inlined.  */
1431914882SAlex Richardson NOINLINE static double
with_errno(double y,int e)1531914882SAlex Richardson with_errno (double y, int e)
1631914882SAlex Richardson {
1731914882SAlex Richardson   errno = e;
1831914882SAlex Richardson   return y;
1931914882SAlex Richardson }
2031914882SAlex Richardson #else
2131914882SAlex Richardson #define with_errno(x, e) (x)
2231914882SAlex Richardson #endif
2331914882SAlex Richardson 
2431914882SAlex Richardson /* NOINLINE reduces code size.  */
2531914882SAlex Richardson NOINLINE static double
xflow(uint32_t sign,double y)2631914882SAlex Richardson xflow (uint32_t sign, double y)
2731914882SAlex Richardson {
2831914882SAlex Richardson   y = eval_as_double (opt_barrier_double (sign ? -y : y) * y);
2931914882SAlex Richardson   return with_errno (y, ERANGE);
3031914882SAlex Richardson }
3131914882SAlex Richardson 
3231914882SAlex Richardson HIDDEN double
__math_uflow(uint32_t sign)3331914882SAlex Richardson __math_uflow (uint32_t sign)
3431914882SAlex Richardson {
3531914882SAlex Richardson   return xflow (sign, 0x1p-767);
3631914882SAlex Richardson }
3731914882SAlex Richardson 
3831914882SAlex Richardson #if WANT_ERRNO_UFLOW
3931914882SAlex Richardson /* Underflows to zero in some non-nearest rounding mode, setting errno
4031914882SAlex Richardson    is valid even if the result is non-zero, but in the subnormal range.  */
4131914882SAlex Richardson HIDDEN double
__math_may_uflow(uint32_t sign)4231914882SAlex Richardson __math_may_uflow (uint32_t sign)
4331914882SAlex Richardson {
4431914882SAlex Richardson   return xflow (sign, 0x1.8p-538);
4531914882SAlex Richardson }
4631914882SAlex Richardson #endif
4731914882SAlex Richardson 
4831914882SAlex Richardson HIDDEN double
__math_oflow(uint32_t sign)4931914882SAlex Richardson __math_oflow (uint32_t sign)
5031914882SAlex Richardson {
5131914882SAlex Richardson   return xflow (sign, 0x1p769);
5231914882SAlex Richardson }
5331914882SAlex Richardson 
5431914882SAlex Richardson HIDDEN double
__math_divzero(uint32_t sign)5531914882SAlex Richardson __math_divzero (uint32_t sign)
5631914882SAlex Richardson {
5731914882SAlex Richardson   double y = opt_barrier_double (sign ? -1.0 : 1.0) / 0.0;
5831914882SAlex Richardson   return with_errno (y, ERANGE);
5931914882SAlex Richardson }
6031914882SAlex Richardson 
6131914882SAlex Richardson HIDDEN double
__math_invalid(double x)6231914882SAlex Richardson __math_invalid (double x)
6331914882SAlex Richardson {
6431914882SAlex Richardson   double y = (x - x) / (x - x);
6531914882SAlex Richardson   return isnan (x) ? y : with_errno (y, EDOM);
6631914882SAlex Richardson }
6731914882SAlex Richardson 
6831914882SAlex Richardson /* Check result and set errno if necessary.  */
6931914882SAlex Richardson 
7031914882SAlex Richardson HIDDEN double
__math_check_uflow(double y)7131914882SAlex Richardson __math_check_uflow (double y)
7231914882SAlex Richardson {
7331914882SAlex Richardson   return y == 0.0 ? with_errno (y, ERANGE) : y;
7431914882SAlex Richardson }
7531914882SAlex Richardson 
7631914882SAlex Richardson HIDDEN double
__math_check_oflow(double y)7731914882SAlex Richardson __math_check_oflow (double y)
7831914882SAlex Richardson {
7931914882SAlex Richardson   return isinf (y) ? with_errno (y, ERANGE) : y;
8031914882SAlex Richardson }
81