1*31914882SAlex Richardson /* 2*31914882SAlex Richardson * Double-precision math error handling. 3*31914882SAlex Richardson * 4*31914882SAlex Richardson * Copyright (c) 2018, 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 double 15*31914882SAlex Richardson with_errno (double 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_errno(x, e) (x) 22*31914882SAlex Richardson #endif 23*31914882SAlex Richardson 24*31914882SAlex Richardson /* NOINLINE reduces code size. */ 25*31914882SAlex Richardson NOINLINE static double 26*31914882SAlex Richardson xflow (uint32_t sign, double y) 27*31914882SAlex Richardson { 28*31914882SAlex Richardson y = eval_as_double (opt_barrier_double (sign ? -y : y) * y); 29*31914882SAlex Richardson return with_errno (y, ERANGE); 30*31914882SAlex Richardson } 31*31914882SAlex Richardson 32*31914882SAlex Richardson HIDDEN double 33*31914882SAlex Richardson __math_uflow (uint32_t sign) 34*31914882SAlex Richardson { 35*31914882SAlex Richardson return xflow (sign, 0x1p-767); 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 double 42*31914882SAlex Richardson __math_may_uflow (uint32_t sign) 43*31914882SAlex Richardson { 44*31914882SAlex Richardson return xflow (sign, 0x1.8p-538); 45*31914882SAlex Richardson } 46*31914882SAlex Richardson #endif 47*31914882SAlex Richardson 48*31914882SAlex Richardson HIDDEN double 49*31914882SAlex Richardson __math_oflow (uint32_t sign) 50*31914882SAlex Richardson { 51*31914882SAlex Richardson return xflow (sign, 0x1p769); 52*31914882SAlex Richardson } 53*31914882SAlex Richardson 54*31914882SAlex Richardson HIDDEN double 55*31914882SAlex Richardson __math_divzero (uint32_t sign) 56*31914882SAlex Richardson { 57*31914882SAlex Richardson double y = opt_barrier_double (sign ? -1.0 : 1.0) / 0.0; 58*31914882SAlex Richardson return with_errno (y, ERANGE); 59*31914882SAlex Richardson } 60*31914882SAlex Richardson 61*31914882SAlex Richardson HIDDEN double 62*31914882SAlex Richardson __math_invalid (double x) 63*31914882SAlex Richardson { 64*31914882SAlex Richardson double y = (x - x) / (x - x); 65*31914882SAlex Richardson return isnan (x) ? y : with_errno (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 double 71*31914882SAlex Richardson __math_check_uflow (double y) 72*31914882SAlex Richardson { 73*31914882SAlex Richardson return y == 0.0 ? with_errno (y, ERANGE) : y; 74*31914882SAlex Richardson } 75*31914882SAlex Richardson 76*31914882SAlex Richardson HIDDEN double 77*31914882SAlex Richardson __math_check_oflow (double y) 78*31914882SAlex Richardson { 79*31914882SAlex Richardson return isinf (y) ? with_errno (y, ERANGE) : y; 80*31914882SAlex Richardson } 81