diff --git a/libc/test/src/math/LdExpTest.h b/libc/test/src/math/LdExpTest.h --- a/libc/test/src/math/LdExpTest.h +++ b/libc/test/src/math/LdExpTest.h @@ -121,7 +121,7 @@ FPBits resultBits(result); ASSERT_FALSE(resultBits.isZero()); // Verify that the result is indeed subnormal. - ASSERT_EQ(resultBits.encoding.exponent, uint16_t(0)); + ASSERT_EQ(resultBits.getUnbiasedExponent(), uint16_t(0)); // But if the exp is so less that normalization leads to zero, then // the result should be zero. result = func(x, -FPBits::maxExponent - int(mantissaWidth) - 5); diff --git a/libc/test/src/math/NextAfterTest.h b/libc/test/src/math/NextAfterTest.h --- a/libc/test/src/math/NextAfterTest.h +++ b/libc/test/src/math/NextAfterTest.h @@ -163,31 +163,29 @@ result = func(x, 0); FPBits xBits = FPBits(x); FPBits resultBits = FPBits(result); - ASSERT_EQ(resultBits.encoding.exponent, - uint16_t(xBits.encoding.exponent - 1)); - ASSERT_EQ(resultBits.encoding.mantissa, + ASSERT_EQ(resultBits.getUnbiasedExponent(), + uint16_t(xBits.getUnbiasedExponent() - 1)); + ASSERT_EQ(resultBits.getMantissa(), (UIntType(1) << MantissaWidth::value) - 1); result = func(x, T(33.0)); resultBits = FPBits(result); - ASSERT_EQ(resultBits.encoding.exponent, xBits.encoding.exponent); - ASSERT_EQ(resultBits.encoding.mantissa, - xBits.encoding.mantissa + UIntType(1)); + ASSERT_EQ(resultBits.getUnbiasedExponent(), xBits.getUnbiasedExponent()); + ASSERT_EQ(resultBits.getMantissa(), xBits.getMantissa() + UIntType(1)); x = -x; result = func(x, 0); resultBits = FPBits(result); - ASSERT_EQ(resultBits.encoding.exponent, - uint16_t(xBits.encoding.exponent - 1)); - ASSERT_EQ(resultBits.encoding.mantissa, + ASSERT_EQ(resultBits.getUnbiasedExponent(), + uint16_t(xBits.getUnbiasedExponent() - 1)); + ASSERT_EQ(resultBits.getMantissa(), (UIntType(1) << MantissaWidth::value) - 1); result = func(x, T(-33.0)); resultBits = FPBits(result); - ASSERT_EQ(resultBits.encoding.exponent, xBits.encoding.exponent); - ASSERT_EQ(resultBits.encoding.mantissa, - xBits.encoding.mantissa + UIntType(1)); + ASSERT_EQ(resultBits.getUnbiasedExponent(), xBits.getUnbiasedExponent()); + ASSERT_EQ(resultBits.getMantissa(), xBits.getMantissa() + UIntType(1)); } }; diff --git a/libc/test/src/math/RoundToIntegerTest.h b/libc/test/src/math/RoundToIntegerTest.h --- a/libc/test/src/math/RoundToIntegerTest.h +++ b/libc/test/src/math/RoundToIntegerTest.h @@ -135,9 +135,9 @@ // We start with 1.0 so that the implicit bit for x86 long doubles // is set. FPBits bits(F(1.0)); - bits.encoding.exponent = exponentLimit + FPBits::exponentBias; - bits.encoding.sign = 1; - bits.encoding.mantissa = 0; + bits.setUnbiasedExponent(exponentLimit + FPBits::exponentBias); + bits.setSign(1); + bits.setMantissa(0); F x = F(bits); long mpfrResult; @@ -199,10 +199,9 @@ // We start with 1.0 so that the implicit bit for x86 long doubles // is set. FPBits bits(F(1.0)); - bits.encoding.exponent = exponentLimit + FPBits::exponentBias; - bits.encoding.sign = 1; - bits.encoding.mantissa = - UIntType(0x1) << (__llvm_libc::fputil::MantissaWidth::value - 1); + bits.setUnbiasedExponent(exponentLimit + FPBits::exponentBias); + bits.setSign(1); + bits.setMantissa(UIntType(0x1) << (__llvm_libc::fputil::MantissaWidth::value - 1)); F x = F(bits); if (TestModes) { diff --git a/libc/test/src/math/SqrtTest.h b/libc/test/src/math/SqrtTest.h --- a/libc/test/src/math/SqrtTest.h +++ b/libc/test/src/math/SqrtTest.h @@ -39,7 +39,7 @@ void testDenormalValues(SqrtFunc func) { for (UIntType mant = 1; mant < HiddenBit; mant <<= 1) { FPBits denormal(T(0.0)); - denormal.encoding.mantissa = mant; + denormal.setMantissa(mant); ASSERT_MPFR_MATCH(mpfr::Operation::Sqrt, T(denormal), func(T(denormal)), T(0.5)); diff --git a/libc/utils/FPUtil/BasicOperations.h b/libc/utils/FPUtil/BasicOperations.h --- a/libc/utils/FPUtil/BasicOperations.h +++ b/libc/utils/FPUtil/BasicOperations.h @@ -20,7 +20,7 @@ cpp::EnableIfType::Value, int> = 0> static inline T abs(T x) { FPBits bits(x); - bits.encoding.sign = 0; + bits.setSign(0); return T(bits); } @@ -33,11 +33,11 @@ return y; } else if (bity.isNaN()) { return x; - } else if (bitx.encoding.sign != bity.encoding.sign) { + } else if (bitx.getSign() != bity.getSign()) { // To make sure that fmin(+0, -0) == -0 == fmin(-0, +0), whenever x and // y has different signs and both are not NaNs, we return the number // with negative sign. - return (bitx.encoding.sign ? x : y); + return (bitx.getSign() ? x : y); } else { return (x < y ? x : y); } @@ -52,11 +52,11 @@ return y; } else if (bity.isNaN()) { return x; - } else if (bitx.encoding.sign != bity.encoding.sign) { + } else if (bitx.getSign() != bity.getSign()) { // To make sure that fmax(+0, -0) == +0 == fmax(-0, +0), whenever x and // y has different signs and both are not NaNs, we return the number // with positive sign. - return (bitx.encoding.sign ? y : x); + return (bitx.getSign() ? y : x); } else { return (x > y ? x : y); } diff --git a/libc/utils/FPUtil/DivisionAndRemainderOperations.h b/libc/utils/FPUtil/DivisionAndRemainderOperations.h --- a/libc/utils/FPUtil/DivisionAndRemainderOperations.h +++ b/libc/utils/FPUtil/DivisionAndRemainderOperations.h @@ -43,12 +43,13 @@ return x; } - bool resultSign = (xbits.encoding.sign == ybits.encoding.sign ? false : true); + bool resultSign = (xbits.getSign() == ybits.getSign() ? false : true); // Once we know the sign of the result, we can just operate on the absolute // values. The correct sign can be applied to the result after the result // is evaluated. - xbits.encoding.sign = ybits.encoding.sign = 0; + xbits.setSign(0); + ybits.setSign(0); NormalFloat normalx(xbits), normaly(ybits); int exp = normalx.exponent - normaly.exponent; diff --git a/libc/utils/FPUtil/FPBits.h b/libc/utils/FPUtil/FPBits.h --- a/libc/utils/FPUtil/FPBits.h +++ b/libc/utils/FPUtil/FPBits.h @@ -13,48 +13,20 @@ #include "utils/CPP/TypeTraits.h" +#include "FloatProperties.h" #include namespace __llvm_libc { namespace fputil { -template struct MantissaWidth {}; -template <> struct MantissaWidth { - static constexpr unsigned value = 23; -}; -template <> struct MantissaWidth { - static constexpr unsigned value = 52; +template struct MantissaWidth { + static constexpr unsigned value = FloatProperties::mantissaWidth; }; -template struct ExponentWidth {}; -template <> struct ExponentWidth { - static constexpr unsigned value = 8; -}; -template <> struct ExponentWidth { - static constexpr unsigned value = 11; -}; -template <> struct ExponentWidth { - static constexpr unsigned value = 15; +template struct ExponentWidth { + static constexpr unsigned value = FloatProperties::exponentWidth; }; -template struct FPUIntType {}; -template <> struct FPUIntType { using Type = uint32_t; }; -template <> struct FPUIntType { using Type = uint64_t; }; - -#ifdef LONG_DOUBLE_IS_DOUBLE -template <> struct MantissaWidth { - static constexpr unsigned value = MantissaWidth::value; -}; -template <> struct FPUIntType { - using Type = FPUIntType::Type; -}; -#elif !defined(SPECIAL_X86_LONG_DOUBLE) -template <> struct MantissaWidth { - static constexpr unsigned value = 112; -}; -template <> struct FPUIntType { using Type = __uint128_t; }; -#endif - // 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 @@ -70,20 +42,44 @@ // 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 UIntType = typename FPUIntType::Type; - - struct __attribute__((packed)) { - UIntType mantissa : MantissaWidth::value; - uint16_t exponent : ExponentWidth::value; - uint8_t sign : 1; - } encoding; - UIntType integer; + using FloatProp = FloatProperties; + // TODO: Change UintType name to BitsType for consistency. + using UIntType = typename FloatProp::BitsType; + + UIntType bits; + + void setMantissa(UIntType mantVal) { + mantVal &= (FloatProp::mantissaMask); + bits &= ~(FloatProp::mantissaMask); + bits |= mantVal; + } + + UIntType getMantissa() const { return bits & FloatProp::mantissaMask; } + + void setUnbiasedExponent(UIntType expVal) { + expVal = (expVal << (FloatProp::mantissaWidth)) & FloatProp::exponentMask; + bits &= ~(FloatProp::exponentMask); + bits |= expVal; + } + + uint16_t getUnbiasedExponent() const { + return uint16_t((bits & FloatProp::exponentMask) >> + (FloatProp::mantissaWidth)); + } + + void setSign(bool signVal) { + bits &= ~(FloatProp::signMask); + UIntType sign = UIntType(signVal) << (FloatProp::bitWidth - 1); + bits |= sign; + } + + bool getSign() const { + return ((bits & FloatProp::signMask) >> (FloatProp::bitWidth - 1)); + } T val; - static_assert(sizeof(encoding) == sizeof(UIntType), - "Encoding and integral representation have different sizes."); - static_assert(sizeof(integer) == sizeof(UIntType), - "Integral representation and value type have different sizes."); + static_assert(sizeof(T) == sizeof(UIntType), + "Data type and integral representation have different sizes."); static constexpr int exponentBias = (1 << (ExponentWidth::value - 1)) - 1; static constexpr int maxExponent = (1 << ExponentWidth::value) - 1; @@ -104,29 +100,29 @@ template ::Value, int> = 0> - explicit FPBits(XType x) : integer(x) {} + explicit FPBits(XType x) : bits(x) {} - FPBits() : integer(0) {} + FPBits() : bits(0) {} explicit operator T() { return val; } - UIntType uintval() const { return integer; } + UIntType uintval() const { return bits; } - int getExponent() const { return int(encoding.exponent) - exponentBias; } + int getExponent() const { return int(getUnbiasedExponent()) - exponentBias; } bool isZero() const { - return encoding.mantissa == 0 && encoding.exponent == 0; + return getMantissa() == 0 && getUnbiasedExponent() == 0; } bool isInf() const { - return encoding.mantissa == 0 && encoding.exponent == maxExponent; + return getMantissa() == 0 && getUnbiasedExponent() == maxExponent; } bool isNaN() const { - return encoding.exponent == maxExponent && encoding.mantissa != 0; + return getUnbiasedExponent() == maxExponent && getMantissa() != 0; } - bool isInfOrNaN() const { return encoding.exponent == maxExponent; } + bool isInfOrNaN() const { return getUnbiasedExponent() == maxExponent; } static FPBits zero() { return FPBits(); } @@ -136,19 +132,19 @@ static FPBits inf() { FPBits bits; - bits.encoding.exponent = maxExponent; + bits.setUnbiasedExponent(maxExponent); return bits; } static FPBits negInf() { FPBits bits = inf(); - bits.encoding.sign = 1; + bits.setSign(1); return bits; } static T buildNaN(UIntType v) { FPBits bits = inf(); - bits.encoding.mantissa = v; + bits.setMantissa(v); return T(bits); } }; diff --git a/libc/utils/FPUtil/Hypot.h b/libc/utils/FPUtil/Hypot.h --- a/libc/utils/FPUtil/Hypot.h +++ b/libc/utils/FPUtil/Hypot.h @@ -139,27 +139,27 @@ DUIntType a_mant_sq, b_mant_sq; bool sticky_bits; - if ((x_bits.encoding.exponent >= - y_bits.encoding.exponent + MantissaWidth::value + 2) || + if ((x_bits.getUnbiasedExponent() >= + y_bits.getUnbiasedExponent() + MantissaWidth::value + 2) || (y == 0)) { return abs(x); - } else if ((y_bits.encoding.exponent >= - x_bits.encoding.exponent + MantissaWidth::value + 2) || + } else if ((y_bits.getUnbiasedExponent() >= + x_bits.getUnbiasedExponent() + MantissaWidth::value + 2) || (x == 0)) { - y_bits.encoding.sign = 0; + y_bits.setSign(0); return abs(y); } if (x >= y) { - a_exp = x_bits.encoding.exponent; - a_mant = x_bits.encoding.mantissa; - b_exp = y_bits.encoding.exponent; - b_mant = y_bits.encoding.mantissa; + a_exp = x_bits.getUnbiasedExponent(); + a_mant = x_bits.getMantissa(); + b_exp = y_bits.getUnbiasedExponent(); + b_mant = y_bits.getMantissa(); } else { - a_exp = y_bits.encoding.exponent; - a_mant = y_bits.encoding.mantissa; - b_exp = x_bits.encoding.exponent; - b_mant = x_bits.encoding.mantissa; + a_exp = y_bits.getUnbiasedExponent(); + a_mant = y_bits.getMantissa(); + b_exp = x_bits.getUnbiasedExponent(); + b_mant = x_bits.getMantissa(); } out_exp = a_exp; diff --git a/libc/utils/FPUtil/LongDoubleBitsX86.h b/libc/utils/FPUtil/LongDoubleBitsX86.h --- a/libc/utils/FPUtil/LongDoubleBitsX86.h +++ b/libc/utils/FPUtil/LongDoubleBitsX86.h @@ -16,10 +16,6 @@ namespace __llvm_libc { namespace fputil { -template <> struct MantissaWidth { - static constexpr unsigned value = 63; -}; - template struct Padding; // i386 padding. @@ -43,25 +39,61 @@ ((UIntType(maxExponent) - 1) << (MantissaWidth::value + 1)) | (UIntType(1) << MantissaWidth::value) | maxSubnormal; - struct __attribute__((packed)) { - UIntType mantissa : MantissaWidth::value; - uint8_t implicitBit : 1; - uint16_t exponent : ExponentWidth::value; - uint8_t sign : 1; - uint64_t padding : Padding::value; - } encoding; - UIntType integer; + using FloatProp = FloatProperties; + + UIntType bits; + + void setMantissa(UIntType mantVal) { + mantVal &= (FloatProp::mantissaMask); + bits &= ~(FloatProp::mantissaMask); + bits |= mantVal; + } + + UIntType getMantissa() const { return bits & FloatProp::mantissaMask; } + + void setUnbiasedExponent(UIntType expVal) { + expVal = (expVal << (FloatProp::bitWidth - 1 - FloatProp::exponentWidth)) & + FloatProp::exponentMask; + bits &= ~(FloatProp::exponentMask); + bits |= expVal; + } + + uint16_t getUnbiasedExponent() const { + return uint16_t((bits & FloatProp::exponentMask) >> + (FloatProp::bitWidth - 1 - FloatProp::exponentWidth)); + } + + void setImplicitBit(bool implicitVal) { + bits &= ~(UIntType(1) << FloatProp::mantissaWidth); + bits |= (UIntType(implicitVal) << FloatProp::mantissaWidth); + } + + bool getImplicitBit() const { + return ((bits & (UIntType(1) << FloatProp::mantissaWidth)) >> + FloatProp::mantissaWidth); + } + + void setSign(bool signVal) { + bits &= ~(FloatProp::signMask); + UIntType sign1 = UIntType(signVal) << (FloatProp::bitWidth - 1); + bits |= sign1; + } + + bool getSign() const { + return ((bits & FloatProp::signMask) >> (FloatProp::bitWidth - 1)); + } + long double val; - FPBits() : integer(0) {} + FPBits() : bits(0) {} template ::Value, int> = 0> - explicit FPBits(XType x) : val(x) {} + explicit FPBits(XType x) : val(x) {} template ::Value, int> = 0> - explicit FPBits(XType x) : integer(x) {} + explicit FPBits(XType x) : bits(x) {} operator long double() { return val; } @@ -71,37 +103,37 @@ (UIntType(1) << (sizeof(long double) * 8 - Padding::value)) - 1; - return integer & mask; + return bits & mask; } int getExponent() const { - if (encoding.exponent == 0) + if (getUnbiasedExponent() == 0) return int(1) - exponentBias; - return int(encoding.exponent) - exponentBias; + return int(getUnbiasedExponent()) - exponentBias; } bool isZero() const { - return encoding.exponent == 0 && encoding.mantissa == 0 && - encoding.implicitBit == 0; + return getUnbiasedExponent() == 0 && getMantissa() == 0 && + getImplicitBit() == 0; } bool isInf() const { - return encoding.exponent == maxExponent && encoding.mantissa == 0 && - encoding.implicitBit == 1; + return getUnbiasedExponent() == maxExponent && getMantissa() == 0 && + getImplicitBit() == 1; } bool isNaN() const { - if (encoding.exponent == maxExponent) { - return (encoding.implicitBit == 0) || encoding.mantissa != 0; - } else if (encoding.exponent != 0) { - return encoding.implicitBit == 0; + if (getUnbiasedExponent() == maxExponent) { + return (getImplicitBit() == 0) || getMantissa() != 0; + } else if (getUnbiasedExponent() != 0) { + return getImplicitBit() == 0; } return false; } bool isInfOrNaN() const { - return (encoding.exponent == maxExponent) || - (encoding.exponent != 0 && encoding.implicitBit == 0); + return (getUnbiasedExponent() == maxExponent) || + (getUnbiasedExponent() != 0 && getImplicitBit() == 0); } // Methods below this are used by tests. @@ -110,30 +142,30 @@ static FPBits negZero() { FPBits bits(0.0l); - bits.encoding.sign = 1; + bits.setSign(1); return bits; } static FPBits inf() { FPBits bits(0.0l); - bits.encoding.exponent = maxExponent; - bits.encoding.implicitBit = 1; + bits.setUnbiasedExponent(maxExponent); + bits.setImplicitBit(1); return bits; } static FPBits negInf() { FPBits bits(0.0l); - bits.encoding.exponent = maxExponent; - bits.encoding.implicitBit = 1; - bits.encoding.sign = 1; + bits.setUnbiasedExponent(maxExponent); + bits.setImplicitBit(1); + bits.setSign(1); return bits; } static long double buildNaN(UIntType v) { FPBits bits(0.0l); - bits.encoding.exponent = maxExponent; - bits.encoding.implicitBit = 1; - bits.encoding.mantissa = v; + bits.setUnbiasedExponent(maxExponent); + bits.setImplicitBit(1); + bits.setMantissa(v); return bits; } }; diff --git a/libc/utils/FPUtil/ManipulationFunctions.h b/libc/utils/FPUtil/ManipulationFunctions.h --- a/libc/utils/FPUtil/ManipulationFunctions.h +++ b/libc/utils/FPUtil/ManipulationFunctions.h @@ -48,14 +48,13 @@ return x; } else if (bits.isInf()) { iptr = x; - return bits.encoding.sign ? T(FPBits::negZero()) : T(FPBits::zero()); + return bits.getSign() ? T(FPBits::negZero()) : T(FPBits::zero()); } else { iptr = trunc(x); if (x == iptr) { // If x is already an integer value, then return zero with the right // sign. - return bits.encoding.sign ? T(FPBits::negZero()) - : T(FPBits::zero()); + return bits.getSign() ? T(FPBits::negZero()) : T(FPBits::zero()); } else { return x - iptr; } @@ -66,7 +65,7 @@ cpp::EnableIfType::Value, int> = 0> static inline T copysign(T x, T y) { FPBits xbits(x); - xbits.encoding.sign = FPBits(y).encoding.sign; + xbits.setSign(FPBits(y).getSign()); return T(xbits); } @@ -133,11 +132,11 @@ // calculating the limit. int expLimit = FPBits::maxExponent + MantissaWidth::value + 1; if (exp > expLimit) - return bits.encoding.sign ? T(FPBits::negInf()) : T(FPBits::inf()); + return bits.getSign() ? T(FPBits::negInf()) : T(FPBits::inf()); // Similarly on the negative side we return zero early if |exp| is too small. if (exp < -expLimit) - return bits.encoding.sign ? T(FPBits::negZero()) : T(FPBits::zero()); + return bits.getSign() ? T(FPBits::negZero()) : T(FPBits::zero()); // For all other values, NormalFloat to T conversion handles it the right way. NormalFloat normal(bits); diff --git a/libc/utils/FPUtil/NearestIntegerOperations.h b/libc/utils/FPUtil/NearestIntegerOperations.h --- a/libc/utils/FPUtil/NearestIntegerOperations.h +++ b/libc/utils/FPUtil/NearestIntegerOperations.h @@ -43,14 +43,14 @@ // If the exponent is such that abs(x) is less than 1, then return 0. if (exponent <= -1) { - if (bits.encoding.sign) + if (bits.getSign()) return T(-0.0); else return T(0.0); } int trimSize = MantissaWidth::value - exponent; - bits.encoding.mantissa = (bits.encoding.mantissa >> trimSize) << trimSize; + bits.setMantissa((bits.getMantissa() >> trimSize) << trimSize); return T(bits); } @@ -63,7 +63,7 @@ if (bits.isInfOrNaN() || bits.isZero()) return x; - bool isNeg = bits.encoding.sign; + bool isNeg = bits.getSign(); int exponent = bits.getExponent(); // If the exponent is greater than the most negative mantissa @@ -79,7 +79,7 @@ } uint32_t trimSize = MantissaWidth::value - exponent; - bits.encoding.mantissa = (bits.encoding.mantissa >> trimSize) << trimSize; + bits.setMantissa((bits.getMantissa() >> trimSize) << trimSize); T truncValue = T(bits); // If x is already an integer, return it. @@ -97,7 +97,7 @@ cpp::EnableIfType::Value, int> = 0> static inline T floor(T x) { FPBits bits(x); - if (bits.encoding.sign) { + if (bits.getSign()) { return -ceil(-x); } else { return trunc(x); @@ -114,7 +114,7 @@ if (bits.isInfOrNaN() || bits.isZero()) return x; - bool isNeg = bits.encoding.sign; + bool isNeg = bits.getSign(); int exponent = bits.getExponent(); // If the exponent is greater than the most negative mantissa @@ -139,8 +139,8 @@ } uint32_t trimSize = MantissaWidth::value - exponent; - bool halfBitSet = bits.encoding.mantissa & (UIntType(1) << (trimSize - 1)); - bits.encoding.mantissa = (bits.encoding.mantissa >> trimSize) << trimSize; + bool halfBitSet = bits.getMantissa() & (UIntType(1) << (trimSize - 1)); + bits.setMantissa((bits.getMantissa() >> trimSize) << trimSize); T truncValue = T(bits); // If x is already an integer, return it. @@ -166,7 +166,7 @@ if (bits.isInfOrNaN() || bits.isZero()) return x; - bool isNeg = bits.encoding.sign; + bool isNeg = bits.getSign(); int exponent = bits.getExponent(); int roundingMode = getRound(); @@ -184,7 +184,7 @@ case FE_TOWARDZERO: return isNeg ? T(-0.0) : T(0.0); case FE_TONEAREST: - if (exponent <= -2 || bits.encoding.mantissa == 0) + if (exponent <= -2 || bits.getMantissa() == 0) return isNeg ? T(-0.0) : T(0.0); // abs(x) <= 0.5 else return isNeg ? T(-1.0) : T(1.0); // abs(x) > 0.5 @@ -195,19 +195,19 @@ uint32_t trimSize = MantissaWidth::value - exponent; FPBits newBits = bits; - newBits.encoding.mantissa = (bits.encoding.mantissa >> trimSize) << trimSize; + newBits.setMantissa((bits.getMantissa() >> trimSize) << trimSize); T truncValue = T(newBits); // If x is already an integer, return it. if (truncValue == x) return x; - UIntType trimValue = bits.encoding.mantissa & ((UIntType(1) << trimSize) - 1); + UIntType trimValue = bits.getMantissa() & ((UIntType(1) << trimSize) - 1); UIntType halfValue = (UIntType(1) << (trimSize - 1)); // If exponent is 0, trimSize will be equal to the mantissa width, and // truncIsOdd` will not be correct. So, we handle it as a special case // below. - UIntType truncIsOdd = newBits.encoding.mantissa & (UIntType(1) << trimSize); + UIntType truncIsOdd = newBits.getMantissa() & (UIntType(1) << trimSize); switch (roundingMode) { case FE_DOWNWARD: @@ -255,18 +255,18 @@ if (bits.isInfOrNaN()) { setDomainErrorAndRaiseInvalid(); - return bits.encoding.sign ? IntegerMin : IntegerMax; + return bits.getSign() ? IntegerMin : IntegerMax; } int exponent = bits.getExponent(); constexpr int exponentLimit = sizeof(I) * 8 - 1; if (exponent > exponentLimit) { setDomainErrorAndRaiseInvalid(); - return bits.encoding.sign ? IntegerMin : IntegerMax; + return bits.getSign() ? IntegerMin : IntegerMax; } else if (exponent == exponentLimit) { - if (bits.encoding.sign == 0 || bits.encoding.mantissa != 0) { + if (bits.getSign() == 0 || bits.getMantissa() != 0) { setDomainErrorAndRaiseInvalid(); - return bits.encoding.sign ? IntegerMin : IntegerMax; + return bits.getSign() ? IntegerMin : IntegerMax; } // If the control reaches here, then it means that the rounded // value is the most negative number for the signed integer type I. diff --git a/libc/utils/FPUtil/NextAfterLongDoubleX86.h b/libc/utils/FPUtil/NextAfterLongDoubleX86.h --- a/libc/utils/FPUtil/NextAfterLongDoubleX86.h +++ b/libc/utils/FPUtil/NextAfterLongDoubleX86.h @@ -30,8 +30,8 @@ return to; // Convert pseudo subnormal number to normal number. - if (fromBits.encoding.implicitBit == 1 && fromBits.encoding.exponent == 0) { - fromBits.encoding.exponent = 1; + if (fromBits.getImplicitBit() == 1 && fromBits.getUnbiasedExponent() == 0) { + fromBits.setUnbiasedExponent(1); } using UIntType = FPBits::UIntType; @@ -46,11 +46,11 @@ // dealing with the implicit bit. intVal = signVal + FPBits::minNormal; } else if ((intVal & mantissaMask) == mantissaMask) { - fromBits.encoding.mantissa = 0; + fromBits.setMantissa(0); // Incrementing exponent might overflow the value to infinity, // which is what is expected. Since NaNs are handling separately, // it will never overflow "beyond" infinity. - ++fromBits.encoding.exponent; + fromBits.setUnbiasedExponent(fromBits.getUnbiasedExponent() + 1); return fromBits; } else { ++intVal; @@ -61,10 +61,10 @@ // dealing with the implicit bit. intVal = signVal + FPBits::maxSubnormal; } else if ((intVal & mantissaMask) == 0) { - fromBits.encoding.mantissa = mantissaMask; + fromBits.setMantissa(mantissaMask); // from == 0 is handled separately so decrementing the exponent will not // lead to underflow. - --fromBits.encoding.exponent; + fromBits.setUnbiasedExponent(fromBits.getUnbiasedExponent() - 1); return fromBits; } else { --intVal; @@ -80,10 +80,10 @@ if (intVal == FPBits::minNormal) { intVal = FPBits::maxSubnormal; } else if ((intVal & mantissaMask) == 0) { - fromBits.encoding.mantissa = mantissaMask; + fromBits.setMantissa(mantissaMask); // from == 0 is handled separately so decrementing the exponent will not // lead to underflow. - --fromBits.encoding.exponent; + fromBits.setUnbiasedExponent(fromBits.getUnbiasedExponent() - 1); return fromBits; } else { --intVal; @@ -92,11 +92,11 @@ if (intVal == FPBits::maxSubnormal) { intVal = FPBits::minNormal; } else if ((intVal & mantissaMask) == mantissaMask) { - fromBits.encoding.mantissa = 0; + fromBits.setMantissa(0); // Incrementing exponent might overflow the value to infinity, // which is what is expected. Since NaNs are handling separately, // it will never overflow "beyond" infinity. - ++fromBits.encoding.exponent; + fromBits.setUnbiasedExponent(fromBits.getUnbiasedExponent() + 1); return fromBits; } else { ++intVal; diff --git a/libc/utils/FPUtil/NormalFloat.h b/libc/utils/FPUtil/NormalFloat.h --- a/libc/utils/FPUtil/NormalFloat.h +++ b/libc/utils/FPUtil/NormalFloat.h @@ -97,7 +97,7 @@ } FPBits result(T(0.0)); - result.encoding.sign = sign; + result.setSign(sign); constexpr int subnormalExponent = -FPBits::exponentBias + 1; if (exponent < subnormalExponent) { @@ -110,36 +110,36 @@ const UIntType shiftOutMask = (UIntType(1) << shift) - 1; const UIntType shiftOutValue = mantissa & shiftOutMask; const UIntType halfwayValue = UIntType(1) << (shift - 1); - result.encoding.exponent = 0; - result.encoding.mantissa = mantissa >> shift; - UIntType newMantissa = result.encoding.mantissa; + result.setUnbiasedExponent(0); + result.setMantissa(mantissa >> shift); + UIntType newMantissa = result.getMantissa(); if (shiftOutValue > halfwayValue) { newMantissa += 1; } else if (shiftOutValue == halfwayValue) { // Round to even. - if (result.encoding.mantissa & 0x1) + if (result.getMantissa() & 0x1) newMantissa += 1; } - result.encoding.mantissa = newMantissa; + result.setMantissa(newMantissa); // Adding 1 to mantissa can lead to overflow. This can only happen if // mantissa was all ones (0b111..11). For such a case, we will carry // the overflow into the exponent. if (newMantissa == one) - result.encoding.exponent = 1; + result.setUnbiasedExponent(1); return T(result); } else { return T(result); } } - result.encoding.exponent = exponent + FPBits::exponentBias; - result.encoding.mantissa = mantissa; + result.setUnbiasedExponent(exponent + FPBits::exponentBias); + result.setMantissa(mantissa); return T(result); } private: void initFromBits(FPBits bits) { - sign = bits.encoding.sign; + sign = bits.getSign(); if (bits.isInfOrNaN() || bits.isZero()) { // Ignore special bit patterns. Implementations deal with them separately @@ -150,13 +150,13 @@ } // Normalize subnormal numbers. - if (bits.encoding.exponent == 0) { - unsigned shift = evaluateNormalizationShift(bits.encoding.mantissa); - mantissa = UIntType(bits.encoding.mantissa) << shift; + if (bits.getUnbiasedExponent() == 0) { + unsigned shift = evaluateNormalizationShift(bits.getMantissa()); + mantissa = UIntType(bits.getMantissa()) << shift; exponent = 1 - FPBits::exponentBias - shift; } else { - exponent = bits.encoding.exponent - FPBits::exponentBias; - mantissa = one | bits.encoding.mantissa; + exponent = bits.getUnbiasedExponent() - FPBits::exponentBias; + mantissa = one | bits.getMantissa(); } } @@ -172,7 +172,7 @@ #ifdef SPECIAL_X86_LONG_DOUBLE template <> inline void NormalFloat::initFromBits(FPBits bits) { - sign = bits.encoding.sign; + sign = bits.getSign(); if (bits.isInfOrNaN() || bits.isZero()) { // Ignore special bit patterns. Implementations deal with them separately @@ -182,25 +182,24 @@ return; } - if (bits.encoding.exponent == 0) { - if (bits.encoding.implicitBit == 0) { + if (bits.getUnbiasedExponent() == 0) { + if (bits.getImplicitBit() == 0) { // Since we ignore zero value, the mantissa in this case is non-zero. - int normalizationShift = - evaluateNormalizationShift(bits.encoding.mantissa); + int normalizationShift = evaluateNormalizationShift(bits.getMantissa()); exponent = -16382 - normalizationShift; - mantissa = (bits.encoding.mantissa << normalizationShift); + mantissa = (bits.getMantissa() << normalizationShift); } else { exponent = -16382; - mantissa = one | bits.encoding.mantissa; + mantissa = one | bits.getMantissa(); } } else { - if (bits.encoding.implicitBit == 0) { + if (bits.getImplicitBit() == 0) { // Invalid number so just store 0 similar to a NaN. exponent = 0; mantissa = 0; } else { - exponent = bits.encoding.exponent - 16383; - mantissa = one | bits.encoding.mantissa; + exponent = bits.getUnbiasedExponent() - 16383; + mantissa = one | bits.getMantissa(); } } } @@ -214,7 +213,7 @@ } FPBits result(0.0l); - result.encoding.sign = sign; + result.setSign(sign); constexpr int subnormalExponent = -FPBits::exponentBias + 1; if (exponent < subnormalExponent) { @@ -225,25 +224,25 @@ const UIntType shiftOutMask = (UIntType(1) << shift) - 1; const UIntType shiftOutValue = mantissa & shiftOutMask; const UIntType halfwayValue = UIntType(1) << (shift - 1); - result.encoding.exponent = 0; - result.encoding.mantissa = mantissa >> shift; - UIntType newMantissa = result.encoding.mantissa; + result.setUnbiasedExponent(0); + result.setMantissa(mantissa >> shift); + UIntType newMantissa = result.getMantissa(); if (shiftOutValue > halfwayValue) { newMantissa += 1; } else if (shiftOutValue == halfwayValue) { // Round to even. - if (result.encoding.mantissa & 0x1) + if (result.getMantissa() & 0x1) newMantissa += 1; } - result.encoding.mantissa = newMantissa; + result.setMantissa(newMantissa); // Adding 1 to mantissa can lead to overflow. This can only happen if // mantissa was all ones (0b111..11). For such a case, we will carry // the overflow into the exponent and set the implicit bit to 1. if (newMantissa == one) { - result.encoding.exponent = 1; - result.encoding.implicitBit = 1; + result.setUnbiasedExponent(1); + result.setImplicitBit(1); } else { - result.encoding.implicitBit = 0; + result.setImplicitBit(0); } return static_cast(result); } else { @@ -251,9 +250,9 @@ } } - result.encoding.exponent = biasedExponent; - result.encoding.mantissa = mantissa; - result.encoding.implicitBit = 1; + result.setUnbiasedExponent(biasedExponent); + result.setMantissa(mantissa); + result.setImplicitBit(1); return static_cast(result); } #endif // SPECIAL_X86_LONG_DOUBLE diff --git a/libc/utils/FPUtil/Sqrt.h b/libc/utils/FPUtil/Sqrt.h --- a/libc/utils/FPUtil/Sqrt.h +++ b/libc/utils/FPUtil/Sqrt.h @@ -102,7 +102,7 @@ FPBits bits(x); if (bits.isInfOrNaN()) { - if (bits.encoding.sign && (bits.encoding.mantissa == 0)) { + if (bits.getSign() && (bits.getMantissa() == 0)) { // sqrt(-Inf) = NaN return FPBits::buildNaN(One >> 1); } else { @@ -114,15 +114,15 @@ // sqrt(+0) = +0 // sqrt(-0) = -0 return x; - } else if (bits.encoding.sign) { + } else if (bits.getSign()) { // sqrt( negative numbers ) = NaN return FPBits::buildNaN(One >> 1); } else { int xExp = bits.getExponent(); - UIntType xMant = bits.encoding.mantissa; + UIntType xMant = bits.getMantissa(); // Step 1a: Normalize denormal input and append hiddent bit to the mantissa - if (bits.encoding.exponent == 0) { + if (bits.getUnbiasedExponent() == 0) { ++xExp; // let xExp be the correct exponent of One bit. internal::normalize(xExp, xMant); } else { diff --git a/libc/utils/FPUtil/SqrtLongDoubleX86.h b/libc/utils/FPUtil/SqrtLongDoubleX86.h --- a/libc/utils/FPUtil/SqrtLongDoubleX86.h +++ b/libc/utils/FPUtil/SqrtLongDoubleX86.h @@ -50,7 +50,7 @@ FPBits bits(x); if (bits.isInfOrNaN()) { - if (bits.encoding.sign && (bits.encoding.mantissa == 0)) { + if (bits.getSign() && (bits.getMantissa() == 0)) { // sqrt(-Inf) = NaN return FPBits::buildNaN(One >> 1); } else { @@ -62,17 +62,17 @@ // sqrt(+0) = +0 // sqrt(-0) = -0 return x; - } else if (bits.encoding.sign) { + } else if (bits.getSign()) { // sqrt( negative numbers ) = NaN return FPBits::buildNaN(One >> 1); } else { int xExp = bits.getExponent(); - UIntType xMant = bits.encoding.mantissa; + UIntType xMant = bits.getMantissa(); // Step 1a: Normalize denormal input - if (bits.encoding.implicitBit) { + if (bits.getImplicitBit()) { xMant |= One; - } else if (bits.encoding.exponent == 0) { + } else if (bits.getUnbiasedExponent() == 0) { internal::normalize(xExp, xMant); } @@ -128,9 +128,9 @@ // Extract output FPBits out(0.0L); - out.encoding.exponent = xExp; - out.encoding.implicitBit = 1; - out.encoding.mantissa = (y & (One - 1)); + out.setUnbiasedExponent(xExp); + out.setImplicitBit(1); + out.setMantissa((y & (One - 1))); return out; } diff --git a/libc/utils/FPUtil/TestHelpers.cpp b/libc/utils/FPUtil/TestHelpers.cpp --- a/libc/utils/FPUtil/TestHelpers.cpp +++ b/libc/utils/FPUtil/TestHelpers.cpp @@ -40,7 +40,7 @@ if (bits.isNaN()) { stream << "(NaN)"; } else if (bits.isInf()) { - if (bits.encoding.sign) + if (bits.getSign()) stream << "(-Infinity)"; else stream << "(+Infinity)"; @@ -50,13 +50,14 @@ constexpr int mantissaWidthInHex = (fputil::MantissaWidth::value - 1) / 4 + 1; - stream << "Sign: " << (bits.encoding.sign ? '1' : '0') << ", " + stream << "Sign: " << (bits.getSign() ? '1' : '0') << ", " << "Exponent: 0x" - << uintToHex(bits.encoding.exponent, exponentWidthInHex) + << uintToHex(bits.getUnbiasedExponent(), + exponentWidthInHex) << ", " << "Mantissa: 0x" << uintToHex::UIntType>( - bits.encoding.mantissa, mantissaWidthInHex); + bits.getMantissa(), mantissaWidthInHex); } stream << '\n'; diff --git a/libc/utils/FPUtil/generic/FMA.h b/libc/utils/FPUtil/generic/FMA.h --- a/libc/utils/FPUtil/generic/FMA.h +++ b/libc/utils/FPUtil/generic/FMA.h @@ -47,17 +47,17 @@ // bit of sum, so that the sticky bits used when rounding sum to float are // correct (when it matters). fputil::FPBits t( - (bit_prod.encoding.exponent >= bitz.encoding.exponent) + (bit_prod.getUnbiasedExponent() >= bitz.getUnbiasedExponent()) ? ((double(bit_sum) - double(bit_prod)) - double(bitz)) : ((double(bit_sum) - double(bitz)) - double(bit_prod))); // Update sticky bits if t != 0.0 and the least (52 - 23 - 1 = 28) bits are // zero. - if (!t.isZero() && ((bit_sum.encoding.mantissa & 0xfff'ffffULL) == 0)) { - if (bit_sum.encoding.sign != t.encoding.sign) { - ++bit_sum.encoding.mantissa; - } else if (bit_sum.encoding.mantissa) { - --bit_sum.encoding.mantissa; + if (!t.isZero() && ((bit_sum.getMantissa() & 0xfff'ffffULL) == 0)) { + if (bit_sum.getSign() != t.getSign()) { + bit_sum.setMantissa(bit_sum.getMantissa() + 1); + } else if (bit_sum.getMantissa()) { + bit_sum.setMantissa(bit_sum.getMantissa() - 1); } } }