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