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