xref: /llvm-project/libc/src/__support/FPUtil/BasicOperations.h (revision d0b6709965f5f119c65e7d14cfc917a8f205edf0)
1c120edc7SMichael Jones //===-- Basic operations on floating point numbers --------------*- C++ -*-===//
2c120edc7SMichael Jones //
3c120edc7SMichael Jones // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c120edc7SMichael Jones // See https://llvm.org/LICENSE.txt for license information.
5c120edc7SMichael Jones // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c120edc7SMichael Jones //
7c120edc7SMichael Jones //===----------------------------------------------------------------------===//
8c120edc7SMichael Jones 
9270547f3SGuillaume Chatelet #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_BASICOPERATIONS_H
10270547f3SGuillaume Chatelet #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_BASICOPERATIONS_H
11c120edc7SMichael Jones 
1219ca79e8SShourya Goel #include "FEnvImpl.h"
13c120edc7SMichael Jones #include "FPBits.h"
1474a1ca50Slntue #include "dyadic_float.h"
15c120edc7SMichael Jones 
16f7226150SGuillaume Chatelet #include "src/__support/CPP/type_traits.h"
175c406eacSOverMighty #include "src/__support/big_int.h"
1859c809cdSSiva Chandra Reddy #include "src/__support/common.h"
195ff3ff33SPetr Hosek #include "src/__support/macros/config.h"
2019ca79e8SShourya Goel #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
21e7f8d4beSOverMighty #include "src/__support/macros/properties/architectures.h"
22e7f8d4beSOverMighty #include "src/__support/macros/properties/types.h"
2309efe848SGuillaume Chatelet #include "src/__support/uint128.h"
24c120edc7SMichael Jones 
255ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL {
26c120edc7SMichael Jones namespace fputil {
27c120edc7SMichael Jones 
28f7226150SGuillaume Chatelet template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
2959c809cdSSiva Chandra Reddy LIBC_INLINE T abs(T x) {
30f506192cSGuillaume Chatelet   return FPBits<T>(x).abs().get_val();
31c120edc7SMichael Jones }
32c120edc7SMichael Jones 
33e7f8d4beSOverMighty namespace internal {
34e7f8d4beSOverMighty 
35e7f8d4beSOverMighty template <typename T>
36e7f8d4beSOverMighty LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> max(T x, T y) {
37e7f8d4beSOverMighty   FPBits<T> x_bits(x);
38e7f8d4beSOverMighty   FPBits<T> y_bits(y);
39e7f8d4beSOverMighty 
40e7f8d4beSOverMighty   // To make sure that fmax(+0, -0) == +0 == fmax(-0, +0), whenever x and y
41e7f8d4beSOverMighty   // have different signs and both are not NaNs, we return the number with
42e7f8d4beSOverMighty   // positive sign.
43e7f8d4beSOverMighty   if (x_bits.sign() != y_bits.sign())
44e7f8d4beSOverMighty     return x_bits.is_pos() ? x : y;
45e7f8d4beSOverMighty   return x > y ? x : y;
46e7f8d4beSOverMighty }
47e7f8d4beSOverMighty 
4861dcc9feSOverMighty #ifdef LIBC_TYPES_HAS_FLOAT16
49e7f8d4beSOverMighty #if defined(__LIBC_USE_BUILTIN_FMAXF16_FMINF16)
50e7f8d4beSOverMighty template <> LIBC_INLINE float16 max(float16 x, float16 y) {
51e7f8d4beSOverMighty   return __builtin_fmaxf16(x, y);
52e7f8d4beSOverMighty }
53e7f8d4beSOverMighty #elif !defined(LIBC_TARGET_ARCH_IS_AARCH64)
54e7f8d4beSOverMighty template <> LIBC_INLINE float16 max(float16 x, float16 y) {
55e7f8d4beSOverMighty   FPBits<float16> x_bits(x);
56e7f8d4beSOverMighty   FPBits<float16> y_bits(y);
57e7f8d4beSOverMighty 
58e7f8d4beSOverMighty   int16_t xi = static_cast<int16_t>(x_bits.uintval());
59e7f8d4beSOverMighty   int16_t yi = static_cast<int16_t>(y_bits.uintval());
60e7f8d4beSOverMighty   return ((xi > yi) != (xi < 0 && yi < 0)) ? x : y;
61e7f8d4beSOverMighty }
62e7f8d4beSOverMighty #endif
6361dcc9feSOverMighty #endif // LIBC_TYPES_HAS_FLOAT16
64e7f8d4beSOverMighty 
65e7f8d4beSOverMighty #if defined(__LIBC_USE_BUILTIN_FMAX_FMIN) && !defined(LIBC_TARGET_ARCH_IS_X86)
66e7f8d4beSOverMighty template <> LIBC_INLINE float max(float x, float y) {
67e7f8d4beSOverMighty   return __builtin_fmaxf(x, y);
68e7f8d4beSOverMighty }
69e7f8d4beSOverMighty 
70e7f8d4beSOverMighty template <> LIBC_INLINE double max(double x, double y) {
71e7f8d4beSOverMighty   return __builtin_fmax(x, y);
72e7f8d4beSOverMighty }
73e7f8d4beSOverMighty #endif
74e7f8d4beSOverMighty 
75e7f8d4beSOverMighty template <typename T>
76e7f8d4beSOverMighty LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> min(T x, T y) {
77e7f8d4beSOverMighty   FPBits<T> x_bits(x);
78e7f8d4beSOverMighty   FPBits<T> y_bits(y);
79e7f8d4beSOverMighty 
80e7f8d4beSOverMighty   // To make sure that fmin(+0, -0) == -0 == fmin(-0, +0), whenever x and y have
81e7f8d4beSOverMighty   // different signs and both are not NaNs, we return the number with negative
82e7f8d4beSOverMighty   // sign.
83e7f8d4beSOverMighty   if (x_bits.sign() != y_bits.sign())
84e7f8d4beSOverMighty     return x_bits.is_neg() ? x : y;
85e7f8d4beSOverMighty   return x < y ? x : y;
86e7f8d4beSOverMighty }
87e7f8d4beSOverMighty 
8861dcc9feSOverMighty #ifdef LIBC_TYPES_HAS_FLOAT16
89e7f8d4beSOverMighty #if defined(__LIBC_USE_BUILTIN_FMAXF16_FMINF16)
90e7f8d4beSOverMighty template <> LIBC_INLINE float16 min(float16 x, float16 y) {
91e7f8d4beSOverMighty   return __builtin_fminf16(x, y);
92e7f8d4beSOverMighty }
93e7f8d4beSOverMighty #elif !defined(LIBC_TARGET_ARCH_IS_AARCH64)
94e7f8d4beSOverMighty template <> LIBC_INLINE float16 min(float16 x, float16 y) {
95e7f8d4beSOverMighty   FPBits<float16> x_bits(x);
96e7f8d4beSOverMighty   FPBits<float16> y_bits(y);
97e7f8d4beSOverMighty 
98e7f8d4beSOverMighty   int16_t xi = static_cast<int16_t>(x_bits.uintval());
99e7f8d4beSOverMighty   int16_t yi = static_cast<int16_t>(y_bits.uintval());
100e7f8d4beSOverMighty   return ((xi < yi) != (xi < 0 && yi < 0)) ? x : y;
101e7f8d4beSOverMighty }
102e7f8d4beSOverMighty #endif
10361dcc9feSOverMighty #endif // LIBC_TYPES_HAS_FLOAT16
104e7f8d4beSOverMighty 
105e7f8d4beSOverMighty #if defined(__LIBC_USE_BUILTIN_FMAX_FMIN) && !defined(LIBC_TARGET_ARCH_IS_X86)
106e7f8d4beSOverMighty template <> LIBC_INLINE float min(float x, float y) {
107e7f8d4beSOverMighty   return __builtin_fminf(x, y);
108e7f8d4beSOverMighty }
109e7f8d4beSOverMighty 
110e7f8d4beSOverMighty template <> LIBC_INLINE double min(double x, double y) {
111e7f8d4beSOverMighty   return __builtin_fmin(x, y);
112e7f8d4beSOverMighty }
113e7f8d4beSOverMighty #endif
114e7f8d4beSOverMighty 
115e7f8d4beSOverMighty } // namespace internal
116e7f8d4beSOverMighty 
117f7226150SGuillaume Chatelet template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
11859c809cdSSiva Chandra Reddy LIBC_INLINE T fmin(T x, T y) {
11911ec512fSGuillaume Chatelet   const FPBits<T> bitx(x), bity(y);
120c120edc7SMichael Jones 
121056b4043SJob Henandez Lara   if (bitx.is_nan())
122c120edc7SMichael Jones     return y;
123056b4043SJob Henandez Lara   if (bity.is_nan())
124c120edc7SMichael Jones     return x;
125e7f8d4beSOverMighty   return internal::min(x, y);
126c120edc7SMichael Jones }
127c120edc7SMichael Jones 
128f7226150SGuillaume Chatelet template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
12959c809cdSSiva Chandra Reddy LIBC_INLINE T fmax(T x, T y) {
130c120edc7SMichael Jones   FPBits<T> bitx(x), bity(y);
131c120edc7SMichael Jones 
132056b4043SJob Henandez Lara   if (bitx.is_nan())
133c120edc7SMichael Jones     return y;
134056b4043SJob Henandez Lara   if (bity.is_nan())
135c120edc7SMichael Jones     return x;
136e7f8d4beSOverMighty   return internal::max(x, y);
137c120edc7SMichael Jones }
138c120edc7SMichael Jones 
139f7226150SGuillaume Chatelet template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
1403e3f0c31SJob Henandez Lara LIBC_INLINE T fmaximum(T x, T y) {
1413e3f0c31SJob Henandez Lara   FPBits<T> bitx(x), bity(y);
1423e3f0c31SJob Henandez Lara 
1433e3f0c31SJob Henandez Lara   if (bitx.is_nan())
1443e3f0c31SJob Henandez Lara     return x;
1453e3f0c31SJob Henandez Lara   if (bity.is_nan())
1463e3f0c31SJob Henandez Lara     return y;
147e7f8d4beSOverMighty   return internal::max(x, y);
1483e3f0c31SJob Henandez Lara }
1493e3f0c31SJob Henandez Lara 
1503e3f0c31SJob Henandez Lara template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
1513e3f0c31SJob Henandez Lara LIBC_INLINE T fminimum(T x, T y) {
1523e3f0c31SJob Henandez Lara   const FPBits<T> bitx(x), bity(y);
1533e3f0c31SJob Henandez Lara 
1543e3f0c31SJob Henandez Lara   if (bitx.is_nan())
1553e3f0c31SJob Henandez Lara     return x;
1563e3f0c31SJob Henandez Lara   if (bity.is_nan())
1573e3f0c31SJob Henandez Lara     return y;
158e7f8d4beSOverMighty   return internal::min(x, y);
1593e3f0c31SJob Henandez Lara }
1603e3f0c31SJob Henandez Lara 
1613e3f0c31SJob Henandez Lara template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
1623e3f0c31SJob Henandez Lara LIBC_INLINE T fmaximum_num(T x, T y) {
1633e3f0c31SJob Henandez Lara   FPBits<T> bitx(x), bity(y);
1643e3f0c31SJob Henandez Lara   if (bitx.is_signaling_nan() || bity.is_signaling_nan()) {
1653e3f0c31SJob Henandez Lara     fputil::raise_except_if_required(FE_INVALID);
1663e3f0c31SJob Henandez Lara     if (bitx.is_nan() && bity.is_nan())
1673e3f0c31SJob Henandez Lara       return FPBits<T>::quiet_nan().get_val();
1683e3f0c31SJob Henandez Lara   }
1693e3f0c31SJob Henandez Lara   if (bitx.is_nan())
1703e3f0c31SJob Henandez Lara     return y;
1713e3f0c31SJob Henandez Lara   if (bity.is_nan())
1723e3f0c31SJob Henandez Lara     return x;
173e7f8d4beSOverMighty   return internal::max(x, y);
1743e3f0c31SJob Henandez Lara }
1753e3f0c31SJob Henandez Lara 
1763e3f0c31SJob Henandez Lara template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
1773e3f0c31SJob Henandez Lara LIBC_INLINE T fminimum_num(T x, T y) {
1783e3f0c31SJob Henandez Lara   FPBits<T> bitx(x), bity(y);
1793e3f0c31SJob Henandez Lara   if (bitx.is_signaling_nan() || bity.is_signaling_nan()) {
1803e3f0c31SJob Henandez Lara     fputil::raise_except_if_required(FE_INVALID);
1813e3f0c31SJob Henandez Lara     if (bitx.is_nan() && bity.is_nan())
1823e3f0c31SJob Henandez Lara       return FPBits<T>::quiet_nan().get_val();
1833e3f0c31SJob Henandez Lara   }
1843e3f0c31SJob Henandez Lara   if (bitx.is_nan())
1853e3f0c31SJob Henandez Lara     return y;
1863e3f0c31SJob Henandez Lara   if (bity.is_nan())
1873e3f0c31SJob Henandez Lara     return x;
188e7f8d4beSOverMighty   return internal::min(x, y);
1893e3f0c31SJob Henandez Lara }
1903e3f0c31SJob Henandez Lara 
1913e3f0c31SJob Henandez Lara template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
1923e3f0c31SJob Henandez Lara LIBC_INLINE T fmaximum_mag(T x, T y) {
1933e3f0c31SJob Henandez Lara   FPBits<T> bitx(x), bity(y);
1943e3f0c31SJob Henandez Lara 
1953e3f0c31SJob Henandez Lara   if (abs(x) > abs(y))
1963e3f0c31SJob Henandez Lara     return x;
1973e3f0c31SJob Henandez Lara   if (abs(y) > abs(x))
1983e3f0c31SJob Henandez Lara     return y;
1993e3f0c31SJob Henandez Lara   return fmaximum(x, y);
2003e3f0c31SJob Henandez Lara }
2013e3f0c31SJob Henandez Lara 
2023e3f0c31SJob Henandez Lara template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
2033e3f0c31SJob Henandez Lara LIBC_INLINE T fminimum_mag(T x, T y) {
2043e3f0c31SJob Henandez Lara   FPBits<T> bitx(x), bity(y);
2053e3f0c31SJob Henandez Lara 
2063e3f0c31SJob Henandez Lara   if (abs(x) < abs(y))
2073e3f0c31SJob Henandez Lara     return x;
2083e3f0c31SJob Henandez Lara   if (abs(y) < abs(x))
2093e3f0c31SJob Henandez Lara     return y;
2103e3f0c31SJob Henandez Lara   return fminimum(x, y);
2113e3f0c31SJob Henandez Lara }
2123e3f0c31SJob Henandez Lara 
2133e3f0c31SJob Henandez Lara template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
2143e3f0c31SJob Henandez Lara LIBC_INLINE T fmaximum_mag_num(T x, T y) {
2153e3f0c31SJob Henandez Lara   FPBits<T> bitx(x), bity(y);
2163e3f0c31SJob Henandez Lara 
2173e3f0c31SJob Henandez Lara   if (abs(x) > abs(y))
2183e3f0c31SJob Henandez Lara     return x;
2193e3f0c31SJob Henandez Lara   if (abs(y) > abs(x))
2203e3f0c31SJob Henandez Lara     return y;
2213e3f0c31SJob Henandez Lara   return fmaximum_num(x, y);
2223e3f0c31SJob Henandez Lara }
2233e3f0c31SJob Henandez Lara 
2243e3f0c31SJob Henandez Lara template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
2253e3f0c31SJob Henandez Lara LIBC_INLINE T fminimum_mag_num(T x, T y) {
2263e3f0c31SJob Henandez Lara   FPBits<T> bitx(x), bity(y);
2273e3f0c31SJob Henandez Lara 
2283e3f0c31SJob Henandez Lara   if (abs(x) < abs(y))
2293e3f0c31SJob Henandez Lara     return x;
2303e3f0c31SJob Henandez Lara   if (abs(y) < abs(x))
2313e3f0c31SJob Henandez Lara     return y;
2323e3f0c31SJob Henandez Lara   return fminimum_num(x, y);
2333e3f0c31SJob Henandez Lara }
2343e3f0c31SJob Henandez Lara 
2353e3f0c31SJob Henandez Lara template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
23659c809cdSSiva Chandra Reddy LIBC_INLINE T fdim(T x, T y) {
237c120edc7SMichael Jones   FPBits<T> bitx(x), bity(y);
238c120edc7SMichael Jones 
2391c92911eSMichael Jones   if (bitx.is_nan()) {
240c120edc7SMichael Jones     return x;
241c120edc7SMichael Jones   }
242c120edc7SMichael Jones 
2431c92911eSMichael Jones   if (bity.is_nan()) {
244c120edc7SMichael Jones     return y;
245c120edc7SMichael Jones   }
246c120edc7SMichael Jones 
247c120edc7SMichael Jones   return (x > y ? x - y : 0);
248c120edc7SMichael Jones }
249c120edc7SMichael Jones 
250*d0b67099Slntue // Avoid reusing `issignaling` macro.
25119ca79e8SShourya Goel template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
252*d0b67099Slntue LIBC_INLINE int issignaling_impl(const T &x) {
25347e3d8dcSShourya Goel   FPBits<T> sx(x);
25447e3d8dcSShourya Goel   return sx.is_signaling_nan();
25547e3d8dcSShourya Goel }
25647e3d8dcSShourya Goel 
25747e3d8dcSShourya Goel template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
25819ca79e8SShourya Goel LIBC_INLINE int canonicalize(T &cx, const T &x) {
25919ca79e8SShourya Goel   FPBits<T> sx(x);
26019ca79e8SShourya Goel   if constexpr (get_fp_type<T>() == FPType::X86_Binary80) {
26119ca79e8SShourya Goel     // All the pseudo and unnormal numbers are not canonical.
26219ca79e8SShourya Goel     // More precisely :
26319ca79e8SShourya Goel     // Exponent   |       Significand      | Meaning
26419ca79e8SShourya Goel     //            | Bits 63-62 | Bits 61-0 |
265bbb8a6c8SShourya Goel     // All Ones   |     00     |    Zero   | Pseudo Infinity, Value = SNaN
26619ca79e8SShourya Goel     // All Ones   |     00     |  Non-Zero | Pseudo NaN, Value = SNaN
26719ca79e8SShourya Goel     // All Ones   |     01     | Anything  | Pseudo NaN, Value = SNaN
26819ca79e8SShourya Goel     //            |   Bit 63   | Bits 62-0 |
26919ca79e8SShourya Goel     // All zeroes |   One      | Anything  | Pseudo Denormal, Value =
27019ca79e8SShourya Goel     //            |            |           | (−1)**s × m × 2**−16382
271bbb8a6c8SShourya Goel     // All Other  |   Zero     | Anything  | Unnormal, Value = SNaN
272bbb8a6c8SShourya Goel     //  Values    |            |           |
27319ca79e8SShourya Goel     bool bit63 = sx.get_implicit_bit();
27419ca79e8SShourya Goel     UInt128 mantissa = sx.get_explicit_mantissa();
27580bba179SNick Desaulniers     bool bit62 = static_cast<bool>((mantissa & (1ULL << 62)) >> 62);
27619ca79e8SShourya Goel     int exponent = sx.get_biased_exponent();
27719ca79e8SShourya Goel     if (exponent == 0x7FFF) {
27819ca79e8SShourya Goel       if (!bit63 && !bit62) {
279bbb8a6c8SShourya Goel         if (mantissa == 0) {
28019ca79e8SShourya Goel           cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
28119ca79e8SShourya Goel           raise_except_if_required(FE_INVALID);
28219ca79e8SShourya Goel           return 1;
28319ca79e8SShourya Goel         }
284bbb8a6c8SShourya Goel         cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
285bbb8a6c8SShourya Goel         raise_except_if_required(FE_INVALID);
286bbb8a6c8SShourya Goel         return 1;
28719ca79e8SShourya Goel       } else if (!bit63 && bit62) {
28819ca79e8SShourya Goel         cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
28919ca79e8SShourya Goel         raise_except_if_required(FE_INVALID);
29019ca79e8SShourya Goel         return 1;
29119ca79e8SShourya Goel       } else if (LIBC_UNLIKELY(sx.is_signaling_nan())) {
29219ca79e8SShourya Goel         cx = FPBits<T>::quiet_nan(sx.sign(), sx.get_explicit_mantissa())
29319ca79e8SShourya Goel                  .get_val();
29419ca79e8SShourya Goel         raise_except_if_required(FE_INVALID);
29519ca79e8SShourya Goel         return 1;
29619ca79e8SShourya Goel       } else
29719ca79e8SShourya Goel         cx = x;
29819ca79e8SShourya Goel     } else if (exponent == 0 && bit63)
29919ca79e8SShourya Goel       cx = FPBits<T>::make_value(mantissa, 0).get_val();
300bbb8a6c8SShourya Goel     else if (exponent != 0 && !bit63) {
301bbb8a6c8SShourya Goel       cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
302bbb8a6c8SShourya Goel       raise_except_if_required(FE_INVALID);
303bbb8a6c8SShourya Goel       return 1;
304bbb8a6c8SShourya Goel     } else if (LIBC_UNLIKELY(sx.is_signaling_nan())) {
30519ca79e8SShourya Goel       cx =
30619ca79e8SShourya Goel           FPBits<T>::quiet_nan(sx.sign(), sx.get_explicit_mantissa()).get_val();
30719ca79e8SShourya Goel       raise_except_if_required(FE_INVALID);
30819ca79e8SShourya Goel       return 1;
30919ca79e8SShourya Goel     } else
31019ca79e8SShourya Goel       cx = x;
31119ca79e8SShourya Goel   } else if (LIBC_UNLIKELY(sx.is_signaling_nan())) {
31219ca79e8SShourya Goel     cx = FPBits<T>::quiet_nan(sx.sign(), sx.get_explicit_mantissa()).get_val();
31319ca79e8SShourya Goel     raise_except_if_required(FE_INVALID);
31419ca79e8SShourya Goel     return 1;
31519ca79e8SShourya Goel   } else
31619ca79e8SShourya Goel     cx = x;
31719ca79e8SShourya Goel   return 0;
31819ca79e8SShourya Goel }
31919ca79e8SShourya Goel 
320f5dcfb99SOverMighty template <typename T>
321f5dcfb99SOverMighty LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
322f5dcfb99SOverMighty totalorder(T x, T y) {
323f5dcfb99SOverMighty   using FPBits = FPBits<T>;
324f5dcfb99SOverMighty   FPBits x_bits(x);
325f5dcfb99SOverMighty   FPBits y_bits(y);
326f5dcfb99SOverMighty 
327f5dcfb99SOverMighty   using StorageType = typename FPBits::StorageType;
328f5dcfb99SOverMighty   StorageType x_u = x_bits.uintval();
329f5dcfb99SOverMighty   StorageType y_u = y_bits.uintval();
330f5dcfb99SOverMighty 
331ff1cc5b9SJob Henandez Lara   bool has_neg = ((x_u | y_u) & FPBits::SIGN_MASK) != 0;
332ff1cc5b9SJob Henandez Lara   return x_u == y_u || ((x_u < y_u) != has_neg);
333f5dcfb99SOverMighty }
334f5dcfb99SOverMighty 
335f5dcfb99SOverMighty template <typename T>
336f5dcfb99SOverMighty LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
337f5dcfb99SOverMighty totalordermag(T x, T y) {
338f5dcfb99SOverMighty   return FPBits<T>(x).abs().uintval() <= FPBits<T>(y).abs().uintval();
339f5dcfb99SOverMighty }
340f5dcfb99SOverMighty 
3411107575cSOverMighty template <typename T>
3421107575cSOverMighty LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> getpayload(T x) {
3431107575cSOverMighty   using FPBits = FPBits<T>;
34474a1ca50Slntue   using StorageType = typename FPBits::StorageType;
3451107575cSOverMighty   FPBits x_bits(x);
3461107575cSOverMighty 
3471107575cSOverMighty   if (!x_bits.is_nan())
3481107575cSOverMighty     return T(-1.0);
3491107575cSOverMighty 
35074a1ca50Slntue   StorageType payload = x_bits.uintval() & (FPBits::FRACTION_MASK >> 1);
35174a1ca50Slntue 
35274a1ca50Slntue   if constexpr (is_big_int_v<StorageType>) {
35374a1ca50Slntue     DyadicFloat<FPBits::STORAGE_LEN> payload_dfloat(Sign::POS, 0, payload);
35474a1ca50Slntue 
35574a1ca50Slntue     return static_cast<T>(payload_dfloat);
35674a1ca50Slntue   } else {
35774a1ca50Slntue     return static_cast<T>(payload);
35874a1ca50Slntue   }
3591107575cSOverMighty }
3601107575cSOverMighty 
3611107575cSOverMighty template <bool IsSignaling, typename T>
3621107575cSOverMighty LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
3631107575cSOverMighty setpayload(T &res, T pl) {
3641107575cSOverMighty   using FPBits = FPBits<T>;
3651107575cSOverMighty   FPBits pl_bits(pl);
3661107575cSOverMighty 
3671107575cSOverMighty   // Signaling NaNs don't have the mantissa's MSB set to 1, so they need a
3681107575cSOverMighty   // non-zero payload to distinguish them from infinities.
3691107575cSOverMighty   if (!IsSignaling && pl_bits.is_zero()) {
3701107575cSOverMighty     res = FPBits::quiet_nan(Sign::POS).get_val();
3711107575cSOverMighty     return false;
3721107575cSOverMighty   }
3731107575cSOverMighty 
3741107575cSOverMighty   int pl_exp = pl_bits.get_exponent();
3751107575cSOverMighty 
3761107575cSOverMighty   if (pl_bits.is_neg() || pl_exp < 0 || pl_exp >= FPBits::FRACTION_LEN - 1 ||
3771107575cSOverMighty       ((pl_bits.get_mantissa() << pl_exp) & FPBits::FRACTION_MASK) != 0) {
3781107575cSOverMighty     res = T(0.0);
3791107575cSOverMighty     return true;
3801107575cSOverMighty   }
3811107575cSOverMighty 
3821107575cSOverMighty   using StorageType = typename FPBits::StorageType;
383aae7c388SJob Henandez Lara   StorageType v(pl_bits.get_explicit_mantissa() >>
384aae7c388SJob Henandez Lara                 (FPBits::FRACTION_LEN - pl_exp));
3851107575cSOverMighty 
3861107575cSOverMighty   if constexpr (IsSignaling)
3871107575cSOverMighty     res = FPBits::signaling_nan(Sign::POS, v).get_val();
3881107575cSOverMighty   else
3891107575cSOverMighty     res = FPBits::quiet_nan(Sign::POS, v).get_val();
3901107575cSOverMighty   return false;
3911107575cSOverMighty }
3921107575cSOverMighty 
393c120edc7SMichael Jones } // namespace fputil
3945ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL
395c120edc7SMichael Jones 
396270547f3SGuillaume Chatelet #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_BASICOPERATIONS_H
397