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.encoding.getExponent(), 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,31 @@ 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.encoding.getExponent(), + uint16_t(xBits.encoding.getExponent() - 1)); + ASSERT_EQ(resultBits.encoding.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.encoding.getExponent(), xBits.encoding.getExponent()); + ASSERT_EQ(resultBits.encoding.getMantissa(), + xBits.encoding.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.encoding.getExponent(), + uint16_t(xBits.encoding.getExponent() - 1)); + ASSERT_EQ(resultBits.encoding.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.encoding.getExponent(), xBits.encoding.getExponent()); + ASSERT_EQ(resultBits.encoding.getMantissa(), + xBits.encoding.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.encoding.setExponent(exponentLimit + FPBits::exponentBias); + bits.encoding.setSign(1); + bits.encoding.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.encoding.setExponent(exponentLimit + FPBits::exponentBias); + bits.encoding.setSign(1); + bits.encoding.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.encoding.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.encoding.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.encoding.getSign() != bity.encoding.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.encoding.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.encoding.getSign() != bity.encoding.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.encoding.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,14 @@ return x; } - bool resultSign = (xbits.encoding.sign == ybits.encoding.sign ? false : true); + bool resultSign = + (xbits.encoding.getSign() == ybits.encoding.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.encoding.setSign(0); + ybits.encoding.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,47 +13,24 @@ #include "utils/CPP/TypeTraits.h" +#include "FloatProperties.h" +#include #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; +template struct FPUIntType { + using Type = typename FloatProperties::BitsType; }; -#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. @@ -72,17 +49,55 @@ // 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; + struct { + using FloatProp = FloatProperties; + + private: + UIntType bits; + + public: + UIntType getValue() const { return bits; } + void setValue(UIntType bits) { this->bits = bits; } + + void setMantissa(UIntType mantVal) { + mantVal &= (FloatProp::mantissaMask); + assert((mantVal & ~(FloatProp::mantissaMask)) == 0); + bits &= ~(FloatProp::mantissaMask); + bits |= mantVal; + } + + UIntType getMantissa() const { return bits & FloatProp::mantissaMask; } + + void setExponent(UIntType expVal) { + expVal = + (expVal << (FloatProp::bitWidth - 1 - FloatProp::exponentWidth)) & + FloatProp::exponentMask; + assert((expVal & ~(FloatProp::exponentMask)) == 0); + bits &= ~(FloatProp::exponentMask); + bits |= expVal; + } + + uint16_t getExponent() const { + return uint16_t((bits & FloatProp::exponentMask) >> + (FloatProp::bitWidth - 1 - FloatProp::exponentWidth)); + } + + void setSign(bool signVal) { + bits &= ~(FloatProp::signMask); + UIntType sign = UIntType(signVal) << (FloatProp::bitWidth - 1); + bits |= sign; + } + + uint8_t getSign() const { + return uint8_t((bits & FloatProp::signMask) >> (FloatProp::bitWidth - 1)); + } + } encoding; - UIntType integer; T val; static_assert(sizeof(encoding) == sizeof(UIntType), "Encoding and integral representation have different sizes."); - static_assert(sizeof(integer) == sizeof(UIntType), + static_assert(sizeof(encoding.getValue()) == sizeof(UIntType), "Integral representation and value type have different sizes."); static constexpr int exponentBias = (1 << (ExponentWidth::value - 1)) - 1; @@ -104,29 +119,31 @@ template ::Value, int> = 0> - explicit FPBits(XType x) : integer(x) {} + explicit FPBits(XType x) { + encoding.setValue(x); + } - FPBits() : integer(0) {} + FPBits() { encoding.setValue(0); } explicit operator T() { return val; } - UIntType uintval() const { return integer; } + UIntType uintval() const { return encoding.getValue(); } - int getExponent() const { return int(encoding.exponent) - exponentBias; } + int getExponent() const { return int(encoding.getExponent()) - exponentBias; } bool isZero() const { - return encoding.mantissa == 0 && encoding.exponent == 0; + return encoding.getMantissa() == 0 && encoding.getExponent() == 0; } bool isInf() const { - return encoding.mantissa == 0 && encoding.exponent == maxExponent; + return encoding.getMantissa() == 0 && encoding.getExponent() == maxExponent; } bool isNaN() const { - return encoding.exponent == maxExponent && encoding.mantissa != 0; + return encoding.getExponent() == maxExponent && encoding.getMantissa() != 0; } - bool isInfOrNaN() const { return encoding.exponent == maxExponent; } + bool isInfOrNaN() const { return encoding.getExponent() == maxExponent; } static FPBits zero() { return FPBits(); } @@ -136,19 +153,19 @@ static FPBits inf() { FPBits bits; - bits.encoding.exponent = maxExponent; + bits.encoding.setExponent(maxExponent); return bits; } static FPBits negInf() { FPBits bits = inf(); - bits.encoding.sign = 1; + bits.encoding.setSign(1); return bits; } static T buildNaN(UIntType v) { FPBits bits = inf(); - bits.encoding.mantissa = v; + bits.encoding.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.encoding.getExponent() >= + y_bits.encoding.getExponent() + 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.encoding.getExponent() >= + x_bits.encoding.getExponent() + MantissaWidth::value + 2) || (x == 0)) { - y_bits.encoding.sign = 0; + y_bits.encoding.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.encoding.getExponent(); + a_mant = x_bits.encoding.getMantissa(); + b_exp = y_bits.encoding.getExponent(); + b_mant = y_bits.encoding.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.encoding.getExponent(); + a_mant = y_bits.encoding.getMantissa(); + b_exp = x_bits.encoding.getExponent(); + b_mant = x_bits.encoding.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,73 @@ ((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; + struct { + using FloatProp = FloatProperties; + + private: + UIntType bits; + + public: + UIntType getValue() const { return bits; } + void setValue(UIntType bits) { this->bits = bits; } + + void setMantissa(UIntType mantVal) { + mantVal &= (FloatProp::mantissaMask); + assert((mantVal & ~(FloatProp::mantissaMask)) == 0); + bits &= ~(FloatProp::mantissaMask); + bits |= mantVal; + } + + UIntType getMantissa() const { return bits & FloatProp::mantissaMask; } + + void setExponent(UIntType expVal) { + expVal = + (expVal << (FloatProp::bitWidth - 1 - FloatProp::exponentWidth)) & + FloatProp::exponentMask; + assert((expVal & ~(FloatProp::exponentMask)) == 0); + bits &= ~(FloatProp::exponentMask); + bits |= expVal; + } + + uint16_t getExponent() 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); + } + + uint8_t getImplicitBit() const { + return uint8_t((bits & (UIntType(1) << FloatProp::mantissaWidth)) >> + FloatProp::mantissaWidth); + } + + void setSign(bool signVal) { + bits &= ~(FloatProp::signMask); + UIntType sign1 = UIntType(signVal) << (FloatProp::bitWidth - 1); + bits |= sign1; + } + + uint8_t getSign() const { + return uint8_t((bits & FloatProp::signMask) >> (FloatProp::bitWidth - 1)); + } + } encoding; - UIntType integer; long double val; - FPBits() : integer(0) {} + FPBits() { encoding.setValue(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) { + encoding.setValue(x); + } operator long double() { return val; } @@ -71,37 +115,37 @@ (UIntType(1) << (sizeof(long double) * 8 - Padding::value)) - 1; - return integer & mask; + return encoding.getValue() & mask; } int getExponent() const { - if (encoding.exponent == 0) + if (encoding.getExponent() == 0) return int(1) - exponentBias; - return int(encoding.exponent) - exponentBias; + return int(encoding.getExponent()) - exponentBias; } bool isZero() const { - return encoding.exponent == 0 && encoding.mantissa == 0 && - encoding.implicitBit == 0; + return encoding.getExponent() == 0 && encoding.getMantissa() == 0 && + encoding.getImplicitBit() == 0; } bool isInf() const { - return encoding.exponent == maxExponent && encoding.mantissa == 0 && - encoding.implicitBit == 1; + return encoding.getExponent() == maxExponent && + encoding.getMantissa() == 0 && encoding.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 (encoding.getExponent() == maxExponent) { + return (encoding.getImplicitBit() == 0) || encoding.getMantissa() != 0; + } else if (encoding.getExponent() != 0) { + return encoding.getImplicitBit() == 0; } return false; } bool isInfOrNaN() const { - return (encoding.exponent == maxExponent) || - (encoding.exponent != 0 && encoding.implicitBit == 0); + return (encoding.getExponent() == maxExponent) || + (encoding.getExponent() != 0 && encoding.getImplicitBit() == 0); } // Methods below this are used by tests. @@ -110,30 +154,30 @@ static FPBits negZero() { FPBits bits(0.0l); - bits.encoding.sign = 1; + bits.encoding.setSign(1); return bits; } static FPBits inf() { FPBits bits(0.0l); - bits.encoding.exponent = maxExponent; - bits.encoding.implicitBit = 1; + bits.encoding.setExponent(maxExponent); + bits.encoding.setImplicitBit(1); return bits; } static FPBits negInf() { FPBits bits(0.0l); - bits.encoding.exponent = maxExponent; - bits.encoding.implicitBit = 1; - bits.encoding.sign = 1; + bits.encoding.setExponent(maxExponent); + bits.encoding.setImplicitBit(1); + bits.encoding.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.encoding.setExponent(maxExponent); + bits.encoding.setImplicitBit(1); + bits.encoding.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,15 @@ return x; } else if (bits.isInf()) { iptr = x; - return bits.encoding.sign ? T(FPBits::negZero()) : T(FPBits::zero()); + return bits.encoding.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.encoding.getSign() ? T(FPBits::negZero()) + : T(FPBits::zero()); } else { return x - iptr; } @@ -66,7 +67,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.encoding.setSign(FPBits(y).encoding.getSign()); return T(xbits); } @@ -133,11 +134,13 @@ // 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.encoding.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.encoding.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,15 @@ // If the exponent is such that abs(x) is less than 1, then return 0. if (exponent <= -1) { - if (bits.encoding.sign) + if (bits.encoding.getSign()) return T(-0.0); else return T(0.0); } int trimSize = MantissaWidth::value - exponent; - bits.encoding.mantissa = (bits.encoding.mantissa >> trimSize) << trimSize; + bits.encoding.setMantissa((bits.encoding.getMantissa() >> trimSize) + << trimSize); return T(bits); } @@ -63,7 +64,7 @@ if (bits.isInfOrNaN() || bits.isZero()) return x; - bool isNeg = bits.encoding.sign; + bool isNeg = bits.encoding.getSign(); int exponent = bits.getExponent(); // If the exponent is greater than the most negative mantissa @@ -79,7 +80,8 @@ } uint32_t trimSize = MantissaWidth::value - exponent; - bits.encoding.mantissa = (bits.encoding.mantissa >> trimSize) << trimSize; + bits.encoding.setMantissa((bits.encoding.getMantissa() >> trimSize) + << trimSize); T truncValue = T(bits); // If x is already an integer, return it. @@ -97,7 +99,7 @@ cpp::EnableIfType::Value, int> = 0> static inline T floor(T x) { FPBits bits(x); - if (bits.encoding.sign) { + if (bits.encoding.getSign()) { return -ceil(-x); } else { return trunc(x); @@ -114,7 +116,7 @@ if (bits.isInfOrNaN() || bits.isZero()) return x; - bool isNeg = bits.encoding.sign; + bool isNeg = bits.encoding.getSign(); int exponent = bits.getExponent(); // If the exponent is greater than the most negative mantissa @@ -139,8 +141,10 @@ } 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.encoding.getMantissa() & (UIntType(1) << (trimSize - 1)); + bits.encoding.setMantissa((bits.encoding.getMantissa() >> trimSize) + << trimSize); T truncValue = T(bits); // If x is already an integer, return it. @@ -166,7 +170,7 @@ if (bits.isInfOrNaN() || bits.isZero()) return x; - bool isNeg = bits.encoding.sign; + bool isNeg = bits.encoding.getSign(); int exponent = bits.getExponent(); int roundingMode = getRound(); @@ -184,7 +188,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.encoding.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 +199,22 @@ uint32_t trimSize = MantissaWidth::value - exponent; FPBits newBits = bits; - newBits.encoding.mantissa = (bits.encoding.mantissa >> trimSize) << trimSize; + newBits.encoding.setMantissa((bits.encoding.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.encoding.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.encoding.getMantissa() & (UIntType(1) << trimSize); switch (roundingMode) { case FE_DOWNWARD: @@ -255,18 +262,18 @@ if (bits.isInfOrNaN()) { setDomainErrorAndRaiseInvalid(); - return bits.encoding.sign ? IntegerMin : IntegerMax; + return bits.encoding.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.encoding.getSign() ? IntegerMin : IntegerMax; } else if (exponent == exponentLimit) { - if (bits.encoding.sign == 0 || bits.encoding.mantissa != 0) { + if (bits.encoding.getSign() == 0 || bits.encoding.getMantissa() != 0) { setDomainErrorAndRaiseInvalid(); - return bits.encoding.sign ? IntegerMin : IntegerMax; + return bits.encoding.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,9 @@ return to; // Convert pseudo subnormal number to normal number. - if (fromBits.encoding.implicitBit == 1 && fromBits.encoding.exponent == 0) { - fromBits.encoding.exponent = 1; + if (fromBits.encoding.getImplicitBit() == 1 && + fromBits.encoding.getExponent() == 0) { + fromBits.encoding.setExponent(1); } using UIntType = FPBits::UIntType; @@ -46,11 +47,11 @@ // dealing with the implicit bit. intVal = signVal + FPBits::minNormal; } else if ((intVal & mantissaMask) == mantissaMask) { - fromBits.encoding.mantissa = 0; + fromBits.encoding.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.encoding.setExponent(fromBits.encoding.getExponent() + 1); return fromBits; } else { ++intVal; @@ -61,10 +62,10 @@ // dealing with the implicit bit. intVal = signVal + FPBits::maxSubnormal; } else if ((intVal & mantissaMask) == 0) { - fromBits.encoding.mantissa = mantissaMask; + fromBits.encoding.setMantissa(mantissaMask); // from == 0 is handled separately so decrementing the exponent will not // lead to underflow. - --fromBits.encoding.exponent; + fromBits.encoding.setExponent(fromBits.encoding.getExponent() - 1); return fromBits; } else { --intVal; @@ -80,10 +81,10 @@ if (intVal == FPBits::minNormal) { intVal = FPBits::maxSubnormal; } else if ((intVal & mantissaMask) == 0) { - fromBits.encoding.mantissa = mantissaMask; + fromBits.encoding.setMantissa(mantissaMask); // from == 0 is handled separately so decrementing the exponent will not // lead to underflow. - --fromBits.encoding.exponent; + fromBits.encoding.setExponent(fromBits.encoding.getExponent() - 1); return fromBits; } else { --intVal; @@ -92,11 +93,11 @@ if (intVal == FPBits::maxSubnormal) { intVal = FPBits::minNormal; } else if ((intVal & mantissaMask) == mantissaMask) { - fromBits.encoding.mantissa = 0; + fromBits.encoding.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.encoding.setExponent(fromBits.encoding.getExponent() + 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.encoding.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.encoding.setExponent(0); + result.encoding.setMantissa(mantissa >> shift); + UIntType newMantissa = result.encoding.getMantissa(); if (shiftOutValue > halfwayValue) { newMantissa += 1; } else if (shiftOutValue == halfwayValue) { // Round to even. - if (result.encoding.mantissa & 0x1) + if (result.encoding.getMantissa() & 0x1) newMantissa += 1; } - result.encoding.mantissa = newMantissa; + result.encoding.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.encoding.setExponent(1); return T(result); } else { return T(result); } } - result.encoding.exponent = exponent + FPBits::exponentBias; - result.encoding.mantissa = mantissa; + result.encoding.setExponent(exponent + FPBits::exponentBias); + result.encoding.setMantissa(mantissa); return T(result); } private: void initFromBits(FPBits bits) { - sign = bits.encoding.sign; + sign = bits.encoding.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.encoding.getExponent() == 0) { + unsigned shift = evaluateNormalizationShift(bits.encoding.getMantissa()); + mantissa = UIntType(bits.encoding.getMantissa()) << shift; exponent = 1 - FPBits::exponentBias - shift; } else { - exponent = bits.encoding.exponent - FPBits::exponentBias; - mantissa = one | bits.encoding.mantissa; + exponent = bits.encoding.getExponent() - FPBits::exponentBias; + mantissa = one | bits.encoding.getMantissa(); } } @@ -172,7 +172,7 @@ #ifdef SPECIAL_X86_LONG_DOUBLE template <> inline void NormalFloat::initFromBits(FPBits bits) { - sign = bits.encoding.sign; + sign = bits.encoding.getSign(); if (bits.isInfOrNaN() || bits.isZero()) { // Ignore special bit patterns. Implementations deal with them separately @@ -182,25 +182,25 @@ return; } - if (bits.encoding.exponent == 0) { - if (bits.encoding.implicitBit == 0) { + if (bits.encoding.getExponent() == 0) { + if (bits.encoding.getImplicitBit() == 0) { // Since we ignore zero value, the mantissa in this case is non-zero. int normalizationShift = - evaluateNormalizationShift(bits.encoding.mantissa); + evaluateNormalizationShift(bits.encoding.getMantissa()); exponent = -16382 - normalizationShift; - mantissa = (bits.encoding.mantissa << normalizationShift); + mantissa = (bits.encoding.getMantissa() << normalizationShift); } else { exponent = -16382; - mantissa = one | bits.encoding.mantissa; + mantissa = one | bits.encoding.getMantissa(); } } else { - if (bits.encoding.implicitBit == 0) { + if (bits.encoding.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.encoding.getExponent() - 16383; + mantissa = one | bits.encoding.getMantissa(); } } } @@ -214,7 +214,7 @@ } FPBits result(0.0l); - result.encoding.sign = sign; + result.encoding.setSign(sign); constexpr int subnormalExponent = -FPBits::exponentBias + 1; if (exponent < subnormalExponent) { @@ -225,25 +225,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.encoding.setExponent(0); + result.encoding.setMantissa(mantissa >> shift); + UIntType newMantissa = result.encoding.getMantissa(); if (shiftOutValue > halfwayValue) { newMantissa += 1; } else if (shiftOutValue == halfwayValue) { // Round to even. - if (result.encoding.mantissa & 0x1) + if (result.encoding.getMantissa() & 0x1) newMantissa += 1; } - result.encoding.mantissa = newMantissa; + result.encoding.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.encoding.setExponent(1); + result.encoding.setImplicitBit(1); } else { - result.encoding.implicitBit = 0; + result.encoding.setImplicitBit(0); } return static_cast(result); } else { @@ -251,9 +251,9 @@ } } - result.encoding.exponent = biasedExponent; - result.encoding.mantissa = mantissa; - result.encoding.implicitBit = 1; + result.encoding.setExponent(biasedExponent); + result.encoding.setMantissa(mantissa); + result.encoding.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.encoding.getSign() && (bits.encoding.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.encoding.getSign()) { // sqrt( negative numbers ) = NaN return FPBits::buildNaN(One >> 1); } else { int xExp = bits.getExponent(); - UIntType xMant = bits.encoding.mantissa; + UIntType xMant = bits.encoding.getMantissa(); // Step 1a: Normalize denormal input and append hiddent bit to the mantissa - if (bits.encoding.exponent == 0) { + if (bits.encoding.getExponent() == 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.encoding.getSign() && (bits.encoding.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.encoding.getSign()) { // sqrt( negative numbers ) = NaN return FPBits::buildNaN(One >> 1); } else { int xExp = bits.getExponent(); - UIntType xMant = bits.encoding.mantissa; + UIntType xMant = bits.encoding.getMantissa(); // Step 1a: Normalize denormal input - if (bits.encoding.implicitBit) { + if (bits.encoding.getImplicitBit()) { xMant |= One; - } else if (bits.encoding.exponent == 0) { + } else if (bits.encoding.getExponent() == 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.encoding.setExponent(xExp); + out.encoding.setImplicitBit(1); + out.encoding.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.encoding.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.encoding.getSign() ? '1' : '0') << ", " << "Exponent: 0x" - << uintToHex(bits.encoding.exponent, exponentWidthInHex) + << uintToHex(bits.encoding.getExponent(), + exponentWidthInHex) << ", " << "Mantissa: 0x" << uintToHex::UIntType>( - bits.encoding.mantissa, mantissaWidthInHex); + bits.encoding.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,18 @@ // 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.encoding.getExponent() >= bitz.encoding.getExponent()) ? ((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.encoding.getMantissa() & 0xfff'ffffULL) == 0)) { + if (bit_sum.encoding.getSign() != t.encoding.getSign()) { + bit_sum.encoding.setMantissa(bit_sum.encoding.getMantissa() + 1); + } else if (bit_sum.encoding.getMantissa()) { + bit_sum.encoding.setMantissa(bit_sum.encoding.getMantissa() - 1); } } }