1 /* 2 * Double-precision math error handling. 3 * 4 * Copyright (c) 2018, Arm Limited. 5 * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception 6 */ 7 8 #include "math_config.h" 9 10 #if WANT_ERRNO 11 #include <errno.h> 12 /* NOINLINE reduces code size and avoids making math functions non-leaf 13 when the error handling is inlined. */ 14 NOINLINE static double 15 with_errno (double y, int e) 16 { 17 errno = e; 18 return y; 19 } 20 #else 21 #define with_errno(x, e) (x) 22 #endif 23 24 /* NOINLINE reduces code size. */ 25 NOINLINE static double 26 xflow (uint32_t sign, double y) 27 { 28 y = eval_as_double (opt_barrier_double (sign ? -y : y) * y); 29 return with_errno (y, ERANGE); 30 } 31 32 HIDDEN double 33 __math_uflow (uint32_t sign) 34 { 35 return xflow (sign, 0x1p-767); 36 } 37 38 #if WANT_ERRNO_UFLOW 39 /* Underflows to zero in some non-nearest rounding mode, setting errno 40 is valid even if the result is non-zero, but in the subnormal range. */ 41 HIDDEN double 42 __math_may_uflow (uint32_t sign) 43 { 44 return xflow (sign, 0x1.8p-538); 45 } 46 #endif 47 48 HIDDEN double 49 __math_oflow (uint32_t sign) 50 { 51 return xflow (sign, 0x1p769); 52 } 53 54 HIDDEN double 55 __math_divzero (uint32_t sign) 56 { 57 double y = opt_barrier_double (sign ? -1.0 : 1.0) / 0.0; 58 return with_errno (y, ERANGE); 59 } 60 61 HIDDEN double 62 __math_invalid (double x) 63 { 64 double y = (x - x) / (x - x); 65 return isnan (x) ? y : with_errno (y, EDOM); 66 } 67 68 /* Check result and set errno if necessary. */ 69 70 HIDDEN double 71 __math_check_uflow (double y) 72 { 73 return y == 0.0 ? with_errno (y, ERANGE) : y; 74 } 75 76 HIDDEN double 77 __math_check_oflow (double y) 78 { 79 return isinf (y) ? with_errno (y, ERANGE) : y; 80 } 81