| //===-- Definition for Float80 data type ------------------------*- C++ -*-===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_FLOAT80_H | |
| #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FLOAT80_H | |
| #include "hdr/stdint_proxy.h" | |
| #include "src/__support/CPP/type_traits.h" | |
| #include "src/__support/FPUtil/cast.h" | |
| #include "src/__support/FPUtil/comparison_operations.h" | |
| #include "src/__support/FPUtil/dyadic_float.h" | |
| #include "src/__support/FPUtil/float128.h" | |
| #include "src/__support/FPUtil/generic/add_sub.h" | |
| #include "src/__support/FPUtil/generic/div.h" | |
| #include "src/__support/FPUtil/generic/mul.h" | |
| #include "src/__support/macros/attributes.h" | |
| #include "src/__support/macros/config.h" | |
| #include "src/__support/uint128.h" | |
| namespace LIBC_NAMESPACE_DECL { | |
| namespace fputil { | |
| struct Float80 { | |
| #if __SIZEOF_LONG_DOUBLE__ == 12 | |
| UInt<96> bits; | |
| #else | |
| UInt128 bits; | |
| #endif | |
| LIBC_INLINE Float80() = default; | |
| LIBC_INLINE constexpr Float80(const Float80 &) = default; | |
| LIBC_INLINE constexpr Float80(Float80 &&) = default; | |
| LIBC_INLINE constexpr Float80 &operator=(const Float80 &) = default; | |
| LIBC_INLINE constexpr Float80 &operator=(Float80 &&) = default; | |
| // Floating point type and integer type | |
| template <typename T> | |
| LIBC_INLINE constexpr explicit Float80(T value) : bits(0U) { | |
| if constexpr (cpp::is_floating_point_v<T>) { | |
| bits = fputil::cast<Float80>(value).bits; | |
| } else if constexpr (cpp::is_integral_v<T>) { | |
| Sign sign = Sign::POS; | |
| auto unsigned_value = static_cast<cpp::make_unsigned_t<T>>(value); | |
| if constexpr (cpp::is_signed_v<T>) { | |
| if (value < 0) { | |
| sign = Sign::NEG; | |
| unsigned_value = -unsigned_value; | |
| } | |
| } | |
| fputil::DyadicFloat<FPBits<Float80>::STORAGE_LEN> xd(sign, 0, | |
| unsigned_value); | |
| bits = xd.template as<Float80, /*ShouldSignalExceptions=*/true>().bits; | |
| } else if constexpr (cpp::is_convertible_v<T, Float80>) { | |
| bits = value.operator Float80().bits; | |
| } else { | |
| bits = fputil::cast<Float80>(static_cast<float>(value)).bits; | |
| } | |
| } | |
| template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T> && | |
| !cpp::is_same_v<T, Float80>, | |
| int> = 0> | |
| LIBC_INLINE LIBC_CONSTEXPR_DEFAULT operator T() const { | |
| return fputil::cast<T>(*this); | |
| } | |
| template <typename T, cpp::enable_if_t<cpp::is_integral_v<T>, int> = 0> | |
| LIBC_INLINE constexpr explicit operator T() const { | |
| constexpr T MIN_T = cpp::numeric_limits<T>::min(); | |
| constexpr T MAX_T = cpp::numeric_limits<T>::max(); | |
| FPBits<Float80> x_bits(*this); | |
| // Raise FE_INVALID for inf and NaN | |
| if (x_bits.is_inf_or_nan()) { | |
| raise_except_if_required(FE_INVALID); | |
| return x_bits.is_neg() ? MIN_T : MAX_T; | |
| } | |
| int exponent = x_bits.get_explicit_exponent(); | |
| constexpr int EXPONENT_LIMIT = cpp::numeric_limits<T>::digits; | |
| if (exponent > EXPONENT_LIMIT) { | |
| raise_except_if_required(FE_INVALID); | |
| return x_bits.is_neg() ? MIN_T : MAX_T; | |
| } else if (exponent == EXPONENT_LIMIT) { | |
| if (x_bits.is_pos() || x_bits.get_mantissa() != 0) { | |
| raise_except_if_required(FE_INVALID); | |
| return x_bits.is_neg() ? MIN_T : MAX_T; | |
| } | |
| } | |
| int x_bits_exp = exponent - FPBits<Float80>::FRACTION_LEN; | |
| // sign * 2^(exp-bias) * mantissa | |
| DyadicFloat<FPBits<Float80>::STORAGE_LEN> xd( | |
| x_bits.sign(), x_bits_exp, x_bits.get_explicit_mantissa()); | |
| return static_cast<T>(xd.as_mantissa_type()); | |
| } | |
| // unary operator | |
| LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR Float80 operator-() const { | |
| fputil::FPBits<Float80> result(*this); | |
| result.set_sign(result.is_pos() ? Sign::NEG : Sign::POS); | |
| return result.get_val(); | |
| } | |
| LIBC_INLINE constexpr Float80 operator+(const Float80 &other) const { | |
| return fputil::generic::add<Float80>(fputil::cast<Float128>(*this), | |
| fputil::cast<Float128>(other)); | |
| } | |
| LIBC_INLINE constexpr Float80 operator-(const Float80 &other) const { | |
| return fputil::generic::sub<Float80>(fputil::cast<Float128>(*this), | |
| fputil::cast<Float128>(other)); | |
| } | |
| LIBC_INLINE constexpr Float80 operator*(const Float80 &other) const { | |
| return fputil::generic::mul<Float80>(fputil::cast<Float128>(*this), | |
| fputil::cast<Float128>(other)); | |
| } | |
| LIBC_INLINE constexpr Float80 operator/(const Float80 &other) const { | |
| return fputil::generic::div<Float80>(fputil::cast<Float128>(*this), | |
| fputil::cast<Float128>(other)); | |
| } | |
| // Comparison operators | |
| LIBC_INLINE constexpr bool operator==(const Float80 &other) const { | |
| return fputil::equals(*this, other); | |
| } | |
| LIBC_INLINE constexpr bool operator!=(const Float80 &other) const { | |
| return !fputil::equals(*this, other); | |
| } | |
| LIBC_INLINE constexpr bool operator<(const Float80 &other) const { | |
| return fputil::less_than(*this, other); | |
| } | |
| LIBC_INLINE constexpr bool operator<=(const Float80 &other) const { | |
| return fputil::less_than_or_equals(*this, other); | |
| } | |
| LIBC_INLINE constexpr bool operator>(const Float80 &other) const { | |
| return fputil::greater_than(*this, other); | |
| } | |
| LIBC_INLINE constexpr bool operator>=(const Float80 &other) const { | |
| return fputil::greater_than_or_equals(*this, other); | |
| } | |
| }; | |
| } // namespace fputil | |
| } // namespace LIBC_NAMESPACE_DECL | |
| #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_Float80_H |