[libc][math] Improved FBits performance and readablity.

Some function added in preparation to fmod commit.

Differential Revision: https://reviews.llvm.org/D127097
This commit is contained in:
Kirill Okhotnikov 2022-06-06 12:34:53 +02:00
parent f93dee1033
commit b03567fe2b
2 changed files with 36 additions and 22 deletions

View File

@ -57,6 +57,11 @@ template <typename T> struct FPBits {
UIntType get_mantissa() const { return bits & FloatProp::MANTISSA_MASK; }
// The function return mantissa with implicit bit set for normal values.
constexpr UIntType get_explicit_mantissa() {
return (FloatProp::MANTISSA_MASK + 1) | (FloatProp::MANTISSA_MASK & bits);
}
void set_unbiased_exponent(UIntType expVal) {
expVal = (expVal << (FloatProp::MANTISSA_WIDTH)) & FloatProp::EXPONENT_MASK;
bits &= ~(FloatProp::EXPONENT_MASK);
@ -69,14 +74,12 @@ template <typename T> struct FPBits {
}
void set_sign(bool signVal) {
bits &= ~(FloatProp::SIGN_MASK);
UIntType sign = UIntType(signVal) << (FloatProp::BIT_WIDTH - 1);
bits |= sign;
bits |= FloatProp::SIGN_MASK;
if (!signVal)
bits -= FloatProp::SIGN_MASK;
}
bool get_sign() const {
return ((bits & FloatProp::SIGN_MASK) >> (FloatProp::BIT_WIDTH - 1));
}
bool get_sign() const { return (bits & FloatProp::SIGN_MASK) != 0; }
static_assert(sizeof(T) == sizeof(UIntType),
"Data type and integral representation have different sizes.");
@ -92,7 +95,7 @@ template <typename T> struct FPBits {
static constexpr UIntType MAX_NORMAL =
((UIntType(MAX_EXPONENT) - 1) << MantissaWidth<T>::VALUE) | MAX_SUBNORMAL;
// We don't want accidental type promotions/conversions so we require exact
// We don't want accidental type promotions/conversions, so we require exact
// type match.
template <typename XType,
cpp::EnableIfType<cpp::IsSame<T, XType>::Value, int> = 0>
@ -118,38 +121,41 @@ template <typename T> struct FPBits {
}
bool is_zero() const {
return get_mantissa() == 0 && get_unbiased_exponent() == 0;
// Remove sign bit by shift
return (bits << 1) == 0;
}
bool is_inf() const {
return get_mantissa() == 0 && get_unbiased_exponent() == MAX_EXPONENT;
return (bits & FloatProp::EXP_MANT_MASK) == FloatProp::EXPONENT_MASK;
}
bool is_nan() const {
return get_unbiased_exponent() == MAX_EXPONENT && get_mantissa() != 0;
return (bits & FloatProp::EXP_MANT_MASK) > FloatProp::EXPONENT_MASK;
}
bool is_inf_or_nan() const { return get_unbiased_exponent() == MAX_EXPONENT; }
static FPBits<T> zero() { return FPBits(); }
static FPBits<T> neg_zero() {
return FPBits(UIntType(1) << (sizeof(UIntType) * 8 - 1));
bool is_inf_or_nan() const {
return (bits & FloatProp::EXPONENT_MASK) == FloatProp::EXPONENT_MASK;
}
static FPBits<T> inf() {
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 FPBits<T> neg_inf() {
static constexpr FPBits<T> neg_inf() {
FPBits<T> bits = inf();
bits.set_sign(1);
return bits;
}
static T build_nan(UIntType v) {
static constexpr T build_nan(UIntType v) {
FPBits<T> bits = inf();
bits.set_mantissa(v);
return T(bits);

View File

@ -22,7 +22,7 @@ template <> struct FloatProperties<float> {
static_assert(sizeof(BitsType) == sizeof(float),
"Unexpected size of 'float' type.");
static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) << 3;
static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) * 8;
static constexpr uint32_t MANTISSA_WIDTH = 23;
static constexpr uint32_t EXPONENT_WIDTH = 8;
@ -32,6 +32,10 @@ template <> struct FloatProperties<float> {
static constexpr BitsType EXPONENT_MASK = ~(SIGN_MASK | MANTISSA_MASK);
static constexpr uint32_t EXPONENT_BIAS = 127;
static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK + EXPONENT_MASK;
static_assert(EXP_MANT_MASK == ~SIGN_MASK,
"Exponent and mantissa masks are not as expected.");
// If a number x is a NAN, then it is a quiet NAN if:
// QuietNaNMask & bits(x) != 0
// Else, it is a signalling NAN.
@ -43,7 +47,7 @@ template <> struct FloatProperties<double> {
static_assert(sizeof(BitsType) == sizeof(double),
"Unexpected size of 'double' type.");
static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) << 3;
static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) * 8;
static constexpr uint32_t MANTISSA_WIDTH = 52;
static constexpr uint32_t EXPONENT_WIDTH = 11;
@ -53,6 +57,10 @@ template <> struct FloatProperties<double> {
static constexpr BitsType EXPONENT_MASK = ~(SIGN_MASK | MANTISSA_MASK);
static constexpr uint32_t EXPONENT_BIAS = 1023;
static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK + EXPONENT_MASK;
static_assert(EXP_MANT_MASK == ~SIGN_MASK,
"Exponent and mantissa masks are not as expected.");
// If a number x is a NAN, then it is a quiet NAN if:
// QuietNaNMask & bits(x) != 0
// Else, it is a signalling NAN.
@ -95,7 +103,7 @@ template <> struct FloatProperties<long double> {
static_assert(sizeof(BitsType) == sizeof(long double),
"Unexpected size of 'long double' type.");
static constexpr uint32_t BIT_WIDTH = (sizeof(BitsType) << 3) - 48;
static constexpr uint32_t BIT_WIDTH = (sizeof(BitsType) * 8) - 48;
static constexpr uint32_t MANTISSA_WIDTH = 63;
static constexpr uint32_t EXPONENT_WIDTH = 15;