1*31914882SAlex Richardson /* 2*31914882SAlex Richardson * Single-precision math error handling. 3*31914882SAlex Richardson * 4*31914882SAlex Richardson * Copyright (c) 2017-2020, Arm Limited. 5*31914882SAlex Richardson * SPDX-License-Identifier: MIT 6*31914882SAlex Richardson */ 7*31914882SAlex Richardson 8*31914882SAlex Richardson #include "math_config.h" 9*31914882SAlex Richardson 10*31914882SAlex Richardson #if WANT_ERRNO 11*31914882SAlex Richardson #include <errno.h> 12*31914882SAlex Richardson /* NOINLINE reduces code size and avoids making math functions non-leaf 13*31914882SAlex Richardson when the error handling is inlined. */ 14*31914882SAlex Richardson NOINLINE static float 15*31914882SAlex Richardson with_errnof (float y, int e) 16*31914882SAlex Richardson { 17*31914882SAlex Richardson errno = e; 18*31914882SAlex Richardson return y; 19*31914882SAlex Richardson } 20*31914882SAlex Richardson #else 21*31914882SAlex Richardson #define with_errnof(x, e) (x) 22*31914882SAlex Richardson #endif 23*31914882SAlex Richardson 24*31914882SAlex Richardson /* NOINLINE reduces code size. */ 25*31914882SAlex Richardson NOINLINE static float 26*31914882SAlex Richardson xflowf (uint32_t sign, float y) 27*31914882SAlex Richardson { 28*31914882SAlex Richardson y = eval_as_float (opt_barrier_float (sign ? -y : y) * y); 29*31914882SAlex Richardson return with_errnof (y, ERANGE); 30*31914882SAlex Richardson } 31*31914882SAlex Richardson 32*31914882SAlex Richardson HIDDEN float 33*31914882SAlex Richardson __math_uflowf (uint32_t sign) 34*31914882SAlex Richardson { 35*31914882SAlex Richardson return xflowf (sign, 0x1p-95f); 36*31914882SAlex Richardson } 37*31914882SAlex Richardson 38*31914882SAlex Richardson #if WANT_ERRNO_UFLOW 39*31914882SAlex Richardson /* Underflows to zero in some non-nearest rounding mode, setting errno 40*31914882SAlex Richardson is valid even if the result is non-zero, but in the subnormal range. */ 41*31914882SAlex Richardson HIDDEN float 42*31914882SAlex Richardson __math_may_uflowf (uint32_t sign) 43*31914882SAlex Richardson { 44*31914882SAlex Richardson return xflowf (sign, 0x1.4p-75f); 45*31914882SAlex Richardson } 46*31914882SAlex Richardson #endif 47*31914882SAlex Richardson 48*31914882SAlex Richardson HIDDEN float 49*31914882SAlex Richardson __math_oflowf (uint32_t sign) 50*31914882SAlex Richardson { 51*31914882SAlex Richardson return xflowf (sign, 0x1p97f); 52*31914882SAlex Richardson } 53*31914882SAlex Richardson 54*31914882SAlex Richardson HIDDEN float 55*31914882SAlex Richardson __math_divzerof (uint32_t sign) 56*31914882SAlex Richardson { 57*31914882SAlex Richardson float y = opt_barrier_float (sign ? -1.0f : 1.0f) / 0.0f; 58*31914882SAlex Richardson return with_errnof (y, ERANGE); 59*31914882SAlex Richardson } 60*31914882SAlex Richardson 61*31914882SAlex Richardson HIDDEN float 62*31914882SAlex Richardson __math_invalidf (float x) 63*31914882SAlex Richardson { 64*31914882SAlex Richardson float y = (x - x) / (x - x); 65*31914882SAlex Richardson return isnan (x) ? y : with_errnof (y, EDOM); 66*31914882SAlex Richardson } 67*31914882SAlex Richardson 68*31914882SAlex Richardson /* Check result and set errno if necessary. */ 69*31914882SAlex Richardson 70*31914882SAlex Richardson HIDDEN float 71*31914882SAlex Richardson __math_check_uflowf (float y) 72*31914882SAlex Richardson { 73*31914882SAlex Richardson return y == 0.0f ? with_errnof (y, ERANGE) : y; 74*31914882SAlex Richardson } 75*31914882SAlex Richardson 76*31914882SAlex Richardson HIDDEN float 77*31914882SAlex Richardson __math_check_oflowf (float y) 78*31914882SAlex Richardson { 79*31914882SAlex Richardson return isinf (y) ? with_errnof (y, ERANGE) : y; 80*31914882SAlex Richardson } 81