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