Warning: This file is not a C or C++ file. It does not have highlighting.
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 | #include "src/__support/macros/config.h" |
15 | |
16 | namespace LIBC_NAMESPACE_DECL { |
17 | namespace fputil { |
18 | |
19 | // Quick free-standing test whether fegetround() == FE_UPWARD. |
20 | // Using the following observation: |
21 | // 1.0f + 2^-25 = 1.0f for FE_TONEAREST, FE_DOWNWARD, FE_TOWARDZERO |
22 | // = 0x1.000002f for FE_UPWARD. |
23 | LIBC_INLINE bool fenv_is_round_up() { |
24 | volatile float x = 0x1.0p-25f; |
25 | return (1.0f + x != 1.0f); |
26 | } |
27 | |
28 | // Quick free-standing test whether fegetround() == FE_DOWNWARD. |
29 | // Using the following observation: |
30 | // -1.0f - 2^-25 = -1.0f for FE_TONEAREST, FE_UPWARD, FE_TOWARDZERO |
31 | // = -0x1.000002f for FE_DOWNWARD. |
32 | LIBC_INLINE bool fenv_is_round_down() { |
33 | volatile float x = 0x1.0p-25f; |
34 | return (-1.0f - x != -1.0f); |
35 | } |
36 | |
37 | // Quick free-standing test whether fegetround() == FE_TONEAREST. |
38 | // Using the following observation: |
39 | // 1.5f + 2^-24 = 1.5f for FE_TONEAREST, FE_DOWNWARD, FE_TOWARDZERO |
40 | // = 0x1.100002p0f for FE_UPWARD, |
41 | // 1.5f - 2^-24 = 1.5f for FE_TONEAREST, FE_UPWARD |
42 | // = 0x1.0ffffep-1f for FE_DOWNWARD, FE_TOWARDZERO |
43 | LIBC_INLINE bool fenv_is_round_to_nearest() { |
44 | static volatile float x = 0x1.0p-24f; |
45 | float y = x; |
46 | return (1.5f + y == 1.5f - y); |
47 | } |
48 | |
49 | // Quick free-standing test whether fegetround() == FE_TOWARDZERO. |
50 | // Using the following observation: |
51 | // 1.0f + 2^-23 + 2^-24 = 0x1.000002p0f for FE_DOWNWARD, FE_TOWARDZERO |
52 | // = 0x1.000004p0f for FE_TONEAREST, FE_UPWARD, |
53 | // -1.0f - 2^-24 = -1.0f for FE_TONEAREST, FE_UPWARD, FE_TOWARDZERO |
54 | // = -0x1.000002p0f for FE_DOWNWARD |
55 | // So: |
56 | // (0x1.000002p0f + 2^-24) + (-1.0f - 2^-24) = 2^-23 for FE_TOWARDZERO |
57 | // = 2^-22 for FE_TONEAREST, FE_UPWARD |
58 | // = 0 for FE_DOWNWARD |
59 | LIBC_INLINE bool fenv_is_round_to_zero() { |
60 | static volatile float x = 0x1.0p-24f; |
61 | float y = x; |
62 | return ((0x1.000002p0f + y) + (-1.0f - y) == 0x1.0p-23f); |
63 | } |
64 | |
65 | // Quick free standing get rounding mode based on the above observations. |
66 | LIBC_INLINE int quick_get_round() { |
67 | static volatile float x = 0x1.0p-24f; |
68 | float y = x; |
69 | float z = (0x1.000002p0f + y) + (-1.0f - y); |
70 | |
71 | if (z == 0.0f) |
72 | return FE_DOWNWARD; |
73 | if (z == 0x1.0p-23f) |
74 | return FE_TOWARDZERO; |
75 | return (2.0f + y == 2.0f) ? FE_TONEAREST : FE_UPWARD; |
76 | } |
77 | |
78 | } // namespace fputil |
79 | } // namespace LIBC_NAMESPACE_DECL |
80 | |
81 | #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_ROUNDING_MODE_H |
82 |
Warning: This file is not a C or C++ file. It does not have highlighting.