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