#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/TypeTraits.h"
#include "src/__support/FPUtil/builtin_wrappers.h"
#include "src/__support/common.h"
#include "FloatProperties.h"
#include <stdint.h>
namespace __llvm_libc {
namespace fputil {
template <typename T> struct MantissaWidth {
static constexpr unsigned VALUE = FloatProperties<T>::MANTISSA_WIDTH;
};
template <typename T> struct ExponentWidth {
static constexpr unsigned VALUE = FloatProperties<T>::EXPONENT_WIDTH;
};
template <typename T> struct FPBits {
static_assert(cpp::IsFloatingPointType<T>::Value,
"FPBits instantiated with invalid type.");
using FloatProp = FloatProperties<T>;
using UIntType = typename FloatProp::BitsType;
UIntType bits;
void set_mantissa(UIntType mantVal) {
mantVal &= (FloatProp::MANTISSA_MASK);
bits &= ~(FloatProp::MANTISSA_MASK);
bits |= mantVal;
}
UIntType get_mantissa() const { return bits & FloatProp::MANTISSA_MASK; }
void set_unbiased_exponent(UIntType expVal) {
expVal = (expVal << (FloatProp::MANTISSA_WIDTH)) & FloatProp::EXPONENT_MASK;
bits &= ~(FloatProp::EXPONENT_MASK);
bits |= expVal;
}
uint16_t get_unbiased_exponent() const {
return uint16_t((bits & FloatProp::EXPONENT_MASK) >>
(FloatProp::MANTISSA_WIDTH));
}
constexpr UIntType get_explicit_mantissa() {
return ((get_unbiased_exponent() > 0 && !is_inf_or_nan())
? (FloatProp::MANTISSA_MASK + 1)
: 0) |
(FloatProp::MANTISSA_MASK & bits);
}
void set_sign(bool signVal) {
bits |= FloatProp::SIGN_MASK;
if (!signVal)
bits -= FloatProp::SIGN_MASK;
}
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<T>::VALUE - 1)) - 1;
static constexpr int MAX_EXPONENT = (1 << ExponentWidth<T>::VALUE) - 1;
static constexpr UIntType MIN_SUBNORMAL = UIntType(1);
static constexpr UIntType MAX_SUBNORMAL =
(UIntType(1) << MantissaWidth<T>::VALUE) - 1;
static constexpr UIntType MIN_NORMAL =
(UIntType(1) << MantissaWidth<T>::VALUE);
static constexpr UIntType MAX_NORMAL =
((UIntType(MAX_EXPONENT) - 1) << MantissaWidth<T>::VALUE) | MAX_SUBNORMAL;
template <typename XType,
cpp::EnableIfType<cpp::IsSame<T, XType>::Value, int> = 0>
constexpr explicit FPBits(XType x)
: bits(__llvm_libc::bit_cast<UIntType>(x)) {}
template <typename XType,
cpp::EnableIfType<cpp::IsSame<XType, UIntType>::Value, int> = 0>
constexpr explicit FPBits(XType x) : bits(x) {}
FPBits() : bits(0) {}
T get_val() const { return __llvm_libc::bit_cast<T>(bits); }
void set_val(T value) { bits = __llvm_libc::bit_cast<UIntType>(value); }
explicit operator T() const { return get_val(); }
UIntType uintval() const { return bits; }
int get_exponent() const {
return int(get_unbiased_exponent()) - EXPONENT_BIAS;
}
bool is_zero() const {
return (bits << 1) == 0;
}
bool is_inf() const {
return (bits & FloatProp::EXP_MANT_MASK) == FloatProp::EXPONENT_MASK;
}
bool is_nan() const {
return (bits & FloatProp::EXP_MANT_MASK) > FloatProp::EXPONENT_MASK;
}
bool is_quiet_nan() const {
return (bits & FloatProp::EXP_MANT_MASK) ==
(FloatProp::EXPONENT_MASK | FloatProp::QUIET_NAN_MASK);
}
bool is_inf_or_nan() const {
return (bits & FloatProp::EXPONENT_MASK) == FloatProp::EXPONENT_MASK;
}
static constexpr FPBits<T> zero(bool sign = false) {
return FPBits(sign ? FloatProp::SIGN_MASK : UIntType(0));
}
static constexpr FPBits<T> neg_zero() { return zero(true); }
static constexpr FPBits<T> inf() {
FPBits<T> bits;
bits.set_unbiased_exponent(MAX_EXPONENT);
return bits;
}
static constexpr FPBits<T> neg_inf() {
FPBits<T> bits = inf();
bits.set_sign(1);
return bits;
}
static constexpr T build_nan(UIntType v) {
FPBits<T> bits = inf();
bits.set_mantissa(v);
return T(bits);
}
inline static constexpr FPBits<T> make_value(UIntType number, int ep) {
FPBits<T> result;
int lz = fputil::unsafe_clz(number) - FloatProp::EXPONENT_WIDTH;
number <<= lz;
ep -= lz;
if (likely(ep >= 0)) {
result.set_mantissa(number);
result.set_unbiased_exponent(ep + 1);
} else {
result.set_mantissa(number >> -ep);
}
return result;
}
};
}
}
#ifdef SPECIAL_X86_LONG_DOUBLE
#include "x86_64/LongDoubleBits.h"
#endif
#endif