//===-- Abstract class for bit manipulation of float numbers. ---*- 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_FP_BITS_H #define LLVM_LIBC_SRC_SUPPORT_FPUTIL_FP_BITS_H #include "PlatformDefs.h" #include "src/__support/CPP/bit.h" #include "src/__support/CPP/type_traits.h" #include "src/__support/builtin_wrappers.h" #include "src/__support/common.h" #include "FloatProperties.h" #include namespace __llvm_libc { namespace fputil { template struct MantissaWidth { static constexpr unsigned VALUE = FloatProperties::MANTISSA_WIDTH; }; template struct ExponentWidth { static constexpr unsigned VALUE = FloatProperties::EXPONENT_WIDTH; }; // A generic class to represent single precision, double precision, and quad // precision IEEE 754 floating point formats. // On most platforms, the 'float' type corresponds to single precision floating // point numbers, the 'double' type corresponds to double precision floating // point numers, and the 'long double' type corresponds to the quad precision // floating numbers. On x86 platforms however, the 'long double' type maps to // an x87 floating point format. This format is an IEEE 754 extension format. // It is handled as an explicit specialization of this class. template struct FPBits { static_assert(cpp::is_floating_point_v, "FPBits instantiated with invalid type."); // Reinterpreting bits as an integer value and interpreting the bits of an // integer value as a floating point value is used in tests. So, a convenient // type is provided for such reinterpretations. using FloatProp = FloatProperties; // TODO: Change UintType name to BitsType for consistency. using UIntType = typename FloatProp::BitsType; UIntType bits; LIBC_INLINE void set_mantissa(UIntType mantVal) { mantVal &= (FloatProp::MANTISSA_MASK); bits &= ~(FloatProp::MANTISSA_MASK); bits |= mantVal; } LIBC_INLINE UIntType get_mantissa() const { return bits & FloatProp::MANTISSA_MASK; } LIBC_INLINE void set_unbiased_exponent(UIntType expVal) { expVal = (expVal << (FloatProp::MANTISSA_WIDTH)) & FloatProp::EXPONENT_MASK; bits &= ~(FloatProp::EXPONENT_MASK); bits |= expVal; } LIBC_INLINE uint16_t get_unbiased_exponent() const { return uint16_t((bits & FloatProp::EXPONENT_MASK) >> (FloatProp::MANTISSA_WIDTH)); } // The function return mantissa with the implicit bit set iff the current // value is a valid normal number. LIBC_INLINE constexpr UIntType get_explicit_mantissa() { return ((get_unbiased_exponent() > 0 && !is_inf_or_nan()) ? (FloatProp::MANTISSA_MASK + 1) : 0) | (FloatProp::MANTISSA_MASK & bits); } LIBC_INLINE void set_sign(bool signVal) { bits |= FloatProp::SIGN_MASK; if (!signVal) bits -= FloatProp::SIGN_MASK; } LIBC_INLINE bool get_sign() const { return (bits & FloatProp::SIGN_MASK) != 0; } static_assert(sizeof(T) == sizeof(UIntType), "Data type and integral representation have different sizes."); static constexpr int EXPONENT_BIAS = (1 << (ExponentWidth::VALUE - 1)) - 1; static constexpr int MAX_EXPONENT = (1 << ExponentWidth::VALUE) - 1; static constexpr UIntType MIN_SUBNORMAL = UIntType(1); static constexpr UIntType MAX_SUBNORMAL = (UIntType(1) << MantissaWidth::VALUE) - 1; static constexpr UIntType MIN_NORMAL = (UIntType(1) << MantissaWidth::VALUE); static constexpr UIntType MAX_NORMAL = ((UIntType(MAX_EXPONENT) - 1) << MantissaWidth::VALUE) | MAX_SUBNORMAL; // We don't want accidental type promotions/conversions, so we require exact // type match. template , int> = 0> constexpr explicit FPBits(XType x) : bits(cpp::bit_cast(x)) {} template , int> = 0> constexpr explicit FPBits(XType x) : bits(x) {} FPBits() : bits(0) {} LIBC_INLINE T get_val() const { return cpp::bit_cast(bits); } LIBC_INLINE void set_val(T value) { bits = cpp::bit_cast(value); } LIBC_INLINE explicit operator T() const { return get_val(); } LIBC_INLINE UIntType uintval() const { return bits; } LIBC_INLINE int get_exponent() const { return int(get_unbiased_exponent()) - EXPONENT_BIAS; } LIBC_INLINE bool is_zero() const { // Remove sign bit by shift return (bits << 1) == 0; } LIBC_INLINE bool is_inf() const { return (bits & FloatProp::EXP_MANT_MASK) == FloatProp::EXPONENT_MASK; } LIBC_INLINE bool is_nan() const { return (bits & FloatProp::EXP_MANT_MASK) > FloatProp::EXPONENT_MASK; } LIBC_INLINE bool is_quiet_nan() const { return (bits & FloatProp::EXP_MANT_MASK) == (FloatProp::EXPONENT_MASK | FloatProp::QUIET_NAN_MASK); } LIBC_INLINE bool is_inf_or_nan() const { return (bits & FloatProp::EXPONENT_MASK) == FloatProp::EXPONENT_MASK; } LIBC_INLINE static constexpr FPBits zero(bool sign = false) { return FPBits(sign ? FloatProp::SIGN_MASK : UIntType(0)); } LIBC_INLINE static constexpr FPBits neg_zero() { return zero(true); } LIBC_INLINE static constexpr FPBits inf(bool sign = false) { FPBits bits(sign ? FloatProp::SIGN_MASK : UIntType(0)); bits.set_unbiased_exponent(MAX_EXPONENT); return bits; } LIBC_INLINE static constexpr FPBits neg_inf() { FPBits bits = inf(); bits.set_sign(1); return bits; } LIBC_INLINE static constexpr T build_nan(UIntType v) { FPBits bits = inf(); bits.set_mantissa(v); return T(bits); } LIBC_INLINE static constexpr T build_quiet_nan(UIntType v) { return build_nan(FloatProp::QUIET_NAN_MASK | v); } // The function convert integer number and unbiased exponent to proper float // T type: // Result = number * 2^(ep+1 - exponent_bias) // Be careful! // 1) "ep" is raw exponent value. // 2) The function add to +1 to ep for seamless normalized to denormalized // transition. // 3) The function did not check exponent high limit. // 4) "number" zero value is not processed correctly. // 5) Number is unsigned, so the result can be only positive. LIBC_INLINE static constexpr FPBits make_value(UIntType number, int ep) { FPBits result; // offset: +1 for sign, but -1 for implicit first bit int lz = unsafe_clz(number) - FloatProp::EXPONENT_WIDTH; number <<= lz; ep -= lz; if (LIBC_LIKELY(ep >= 0)) { // Implicit number bit will be removed by mask result.set_mantissa(number); result.set_unbiased_exponent(ep + 1); } else { result.set_mantissa(number >> -ep); } return result; } LIBC_INLINE static FPBits create_value(bool sign, UIntType unbiased_exp, UIntType mantissa) { FPBits result; result.set_sign(sign); result.set_unbiased_exponent(unbiased_exp); result.set_mantissa(mantissa); return result; } }; } // namespace fputil } // namespace __llvm_libc #ifdef SPECIAL_X86_LONG_DOUBLE #include "x86_64/LongDoubleBits.h" #endif #endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_FP_BITS_H