1 | //===---- Free-standing function to detect rounding mode --------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_ROUNDING_MODE_H |
10 | #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_ROUNDING_MODE_H |
11 | |
12 | #include "hdr/fenv_macros.h" |
13 | #include "src/__support/macros/attributes.h" // LIBC_INLINE |
14 | |
15 | namespace LIBC_NAMESPACE::fputil { |
16 | |
17 | // Quick free-standing test whether fegetround() == FE_UPWARD. |
18 | // Using the following observation: |
19 | // 1.0f + 2^-25 = 1.0f for FE_TONEAREST, FE_DOWNWARD, FE_TOWARDZERO |
20 | // = 0x1.000002f for FE_UPWARD. |
21 | LIBC_INLINE bool fenv_is_round_up() { |
22 | volatile float x = 0x1.0p-25f; |
23 | return (1.0f + x != 1.0f); |
24 | } |
25 | |
26 | // Quick free-standing test whether fegetround() == FE_DOWNWARD. |
27 | // Using the following observation: |
28 | // -1.0f - 2^-25 = -1.0f for FE_TONEAREST, FE_UPWARD, FE_TOWARDZERO |
29 | // = -0x1.000002f for FE_DOWNWARD. |
30 | LIBC_INLINE bool fenv_is_round_down() { |
31 | volatile float x = 0x1.0p-25f; |
32 | return (-1.0f - x != -1.0f); |
33 | } |
34 | |
35 | // Quick free-standing test whether fegetround() == FE_TONEAREST. |
36 | // Using the following observation: |
37 | // 1.5f + 2^-24 = 1.5f for FE_TONEAREST, FE_DOWNWARD, FE_TOWARDZERO |
38 | // = 0x1.100002p0f for FE_UPWARD, |
39 | // 1.5f - 2^-24 = 1.5f for FE_TONEAREST, FE_UPWARD |
40 | // = 0x1.0ffffep-1f for FE_DOWNWARD, FE_TOWARDZERO |
41 | LIBC_INLINE bool fenv_is_round_to_nearest() { |
42 | static volatile float x = 0x1.0p-24f; |
43 | float y = x; |
44 | return (1.5f + y == 1.5f - y); |
45 | } |
46 | |
47 | // Quick free-standing test whether fegetround() == FE_TOWARDZERO. |
48 | // Using the following observation: |
49 | // 1.0f + 2^-23 + 2^-24 = 0x1.000002p0f for FE_DOWNWARD, FE_TOWARDZERO |
50 | // = 0x1.000004p0f for FE_TONEAREST, FE_UPWARD, |
51 | // -1.0f - 2^-24 = -1.0f for FE_TONEAREST, FE_UPWARD, FE_TOWARDZERO |
52 | // = -0x1.000002p0f for FE_DOWNWARD |
53 | // So: |
54 | // (0x1.000002p0f + 2^-24) + (-1.0f - 2^-24) = 2^-23 for FE_TOWARDZERO |
55 | // = 2^-22 for FE_TONEAREST, FE_UPWARD |
56 | // = 0 for FE_DOWNWARD |
57 | LIBC_INLINE bool fenv_is_round_to_zero() { |
58 | static volatile float x = 0x1.0p-24f; |
59 | float y = x; |
60 | return ((0x1.000002p0f + y) + (-1.0f - y) == 0x1.0p-23f); |
61 | } |
62 | |
63 | // Quick free standing get rounding mode based on the above observations. |
64 | LIBC_INLINE int quick_get_round() { |
65 | static volatile float x = 0x1.0p-24f; |
66 | float y = x; |
67 | float z = (0x1.000002p0f + y) + (-1.0f - y); |
68 | |
69 | if (z == 0.0f) |
70 | return FE_DOWNWARD; |
71 | if (z == 0x1.0p-23f) |
72 | return FE_TOWARDZERO; |
73 | return (2.0f + y == 2.0f) ? FE_TONEAREST : FE_UPWARD; |
74 | } |
75 | |
76 | } // namespace LIBC_NAMESPACE::fputil |
77 | |
78 | #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_ROUNDING_MODE_H |
79 | |