| //===-- Definition for Float128 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_FLOAT128_H | |
| #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FLOAT128_H | |
| #include "hdr/stdint_proxy.h" | |
| #include "src/__support/CPP/limits.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/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 Float128 { | |
| UInt128 bits; | |
| LIBC_INLINE Float128() = default; | |
| LIBC_INLINE constexpr Float128(const Float128 &) = default; | |
| LIBC_INLINE constexpr Float128(Float128 &&) = default; | |
| LIBC_INLINE constexpr Float128 &operator=(const Float128 &) = default; | |
| LIBC_INLINE constexpr Float128 &operator=(Float128 &&) = default; | |
| // Floating point type and integer type | |
| template <typename T> | |
| LIBC_INLINE constexpr explicit Float128(T value) : bits(0U) { | |
| if constexpr (cpp::is_floating_point_v<T>) { | |
| bits = fputil::cast<Float128>(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<Float128>::STORAGE_LEN> xd(sign, 0, | |
| unsigned_value); | |
| bits = xd.template as<Float128, /*ShouldSignalExceptions=*/true>().bits; | |
| } else if constexpr (cpp::is_convertible_v<T, Float128>) { | |
| bits = value.operator Float128().bits; | |
| } else { | |
| bits = fputil::cast<Float128>(static_cast<float>(value)).bits; | |
| } | |
| } | |
| template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T> && | |
| !cpp::is_same_v<T, Float128>, | |
| 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<Float128> 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<Float128>::FRACTION_LEN; | |
| // sign * 2^(exp-bias) * mantissa | |
| DyadicFloat<FPBits<Float128>::STORAGE_LEN> xd( | |
| x_bits.sign(), x_bits_exp, x_bits.get_explicit_mantissa()); | |
| return static_cast<T>(xd.as_mantissa_type()); | |
| } | |
| // unary | |
| LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR Float128 operator-() const { | |
| fputil::FPBits<Float128> result(*this); | |
| result.set_sign(result.is_pos() ? Sign::NEG : Sign::POS); | |
| return result.get_val(); | |
| } | |
| // operator overloads | |
| LIBC_INLINE constexpr Float128 operator+(const Float128 &other) const { | |
| return fputil::generic::add<Float128>(*this, other); | |
| } | |
| LIBC_INLINE constexpr Float128 operator-(const Float128 &other) const { | |
| return fputil::generic::sub<Float128>(*this, other); | |
| } | |
| LIBC_INLINE constexpr Float128 operator*(const Float128 &other) const { | |
| return fputil::generic::mul<Float128>(*this, other); | |
| } | |
| LIBC_INLINE constexpr Float128 operator/(const Float128 &other) const { | |
| return fputil::generic::div<Float128>(*this, other); | |
| } | |
| LIBC_INLINE constexpr Float128 &operator*=(const Float128 &other) { | |
| *this = *this * other; | |
| return *this; | |
| } | |
| LIBC_INLINE constexpr Float128 &operator+=(const Float128 &other) { | |
| *this = *this + other; | |
| return *this; | |
| } | |
| LIBC_INLINE constexpr Float128 &operator-=(const Float128 &other) { | |
| *this = *this - other; | |
| return *this; | |
| } | |
| LIBC_INLINE constexpr Float128 &operator/=(const Float128 &other) { | |
| *this = *this / other; | |
| return *this; | |
| } | |
| LIBC_INLINE constexpr bool operator==(const Float128 &other) const { | |
| return fputil::equals(*this, other); | |
| } | |
| LIBC_INLINE constexpr bool operator!=(const Float128 &other) const { | |
| return !fputil::equals(*this, other); | |
| } | |
| LIBC_INLINE constexpr bool operator<(const Float128 &other) const { | |
| return fputil::less_than(*this, other); | |
| } | |
| LIBC_INLINE constexpr bool operator<=(const Float128 &other) const { | |
| return fputil::less_than_or_equals(*this, other); | |
| } | |
| LIBC_INLINE constexpr bool operator>(const Float128 &other) const { | |
| return fputil::greater_than(*this, other); | |
| } | |
| LIBC_INLINE constexpr bool operator>=(const Float128 &other) const { | |
| return fputil::greater_than_or_equals(*this, other); | |
| } | |
| }; | |
| static_assert(LIBC_NAMESPACE::cpp::is_trivially_constructible< | |
| LIBC_NAMESPACE::fputil::Float128>::value); | |
| static_assert(LIBC_NAMESPACE::cpp::is_trivially_copyable< | |
| LIBC_NAMESPACE::fputil::Float128>::value); | |
| } // namespace fputil | |
| } // namespace LIBC_NAMESPACE_DECL | |
| #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_FLOAT128_H |