131914882SAlex Richardson /*
231914882SAlex Richardson  * Single-precision math error handling.
331914882SAlex Richardson  *
431914882SAlex Richardson  * Copyright (c) 2017-2020, 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 float
with_errnof(float y,int e)1531914882SAlex Richardson with_errnof (float y, int e)
1631914882SAlex Richardson {
1731914882SAlex Richardson   errno = e;
1831914882SAlex Richardson   return y;
1931914882SAlex Richardson }
2031914882SAlex Richardson #else
2131914882SAlex Richardson #define with_errnof(x, e) (x)
2231914882SAlex Richardson #endif
2331914882SAlex Richardson 
2431914882SAlex Richardson /* NOINLINE reduces code size.  */
2531914882SAlex Richardson NOINLINE static float
xflowf(uint32_t sign,float y)2631914882SAlex Richardson xflowf (uint32_t sign, float y)
2731914882SAlex Richardson {
2831914882SAlex Richardson   y = eval_as_float (opt_barrier_float (sign ? -y : y) * y);
2931914882SAlex Richardson   return with_errnof (y, ERANGE);
3031914882SAlex Richardson }
3131914882SAlex Richardson 
3231914882SAlex Richardson HIDDEN float
__math_uflowf(uint32_t sign)3331914882SAlex Richardson __math_uflowf (uint32_t sign)
3431914882SAlex Richardson {
3531914882SAlex Richardson   return xflowf (sign, 0x1p-95f);
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 float
__math_may_uflowf(uint32_t sign)4231914882SAlex Richardson __math_may_uflowf (uint32_t sign)
4331914882SAlex Richardson {
4431914882SAlex Richardson   return xflowf (sign, 0x1.4p-75f);
4531914882SAlex Richardson }
4631914882SAlex Richardson #endif
4731914882SAlex Richardson 
4831914882SAlex Richardson HIDDEN float
__math_oflowf(uint32_t sign)4931914882SAlex Richardson __math_oflowf (uint32_t sign)
5031914882SAlex Richardson {
5131914882SAlex Richardson   return xflowf (sign, 0x1p97f);
5231914882SAlex Richardson }
5331914882SAlex Richardson 
5431914882SAlex Richardson HIDDEN float
__math_divzerof(uint32_t sign)5531914882SAlex Richardson __math_divzerof (uint32_t sign)
5631914882SAlex Richardson {
5731914882SAlex Richardson   float y = opt_barrier_float (sign ? -1.0f : 1.0f) / 0.0f;
5831914882SAlex Richardson   return with_errnof (y, ERANGE);
5931914882SAlex Richardson }
6031914882SAlex Richardson 
6131914882SAlex Richardson HIDDEN float
__math_invalidf(float x)6231914882SAlex Richardson __math_invalidf (float x)
6331914882SAlex Richardson {
6431914882SAlex Richardson   float y = (x - x) / (x - x);
6531914882SAlex Richardson   return isnan (x) ? y : with_errnof (y, EDOM);
6631914882SAlex Richardson }
6731914882SAlex Richardson 
6831914882SAlex Richardson /* Check result and set errno if necessary.  */
6931914882SAlex Richardson 
7031914882SAlex Richardson HIDDEN float
__math_check_uflowf(float y)7131914882SAlex Richardson __math_check_uflowf (float y)
7231914882SAlex Richardson {
7331914882SAlex Richardson   return y == 0.0f ? with_errnof (y, ERANGE) : y;
7431914882SAlex Richardson }
7531914882SAlex Richardson 
7631914882SAlex Richardson HIDDEN float
__math_check_oflowf(float y)7731914882SAlex Richardson __math_check_oflowf (float y)
7831914882SAlex Richardson {
7931914882SAlex Richardson   return isinf (y) ? with_errnof (y, ERANGE) : y;
8031914882SAlex Richardson }
81