diff --git a/libc/fuzzing/math/Compare.h b/libc/fuzzing/math/Compare.h --- a/libc/fuzzing/math/Compare.h +++ b/libc/fuzzing/math/Compare.h @@ -23,7 +23,7 @@ return bits2.isNaN() && bits2.isNaN(); // For all other values, we want the values to be bitwise equal. - return bits1.bitsAsUInt() == bits2.bitsAsUInt(); + return bits1.uintval() == bits2.uintval(); } template diff --git a/libc/fuzzing/math/RemQuoDiff.h b/libc/fuzzing/math/RemQuoDiff.h --- a/libc/fuzzing/math/RemQuoDiff.h +++ b/libc/fuzzing/math/RemQuoDiff.h @@ -43,6 +43,6 @@ __llvm_libc::fputil::FPBits bits1(remainder1); __llvm_libc::fputil::FPBits bits2(remainder2); - if (bits1.bitsAsUInt() != bits2.bitsAsUInt()) + if (bits1.uintval() != bits2.uintval()) __builtin_trap(); } diff --git a/libc/src/math/generic/fmaf.cpp b/libc/src/math/generic/fmaf.cpp --- a/libc/src/math/generic/fmaf.cpp +++ b/libc/src/math/generic/fmaf.cpp @@ -44,17 +44,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.exponent >= bitz.exponent) - ? ((static_cast(bit_sum) - bit_prod) - bitz) - : ((static_cast(bit_sum) - bitz) - bit_prod)); + (bit_prod.encoding.exponent >= bitz.encoding.exponent) + ? ((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.mantissa & 0xfff'ffffULL) == 0)) { - if (bit_sum.sign != t.sign) { - ++bit_sum.mantissa; - } else if (bit_sum.mantissa) { - --bit_sum.mantissa; + 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; } } } 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.exponent, uint16_t(0)); + ASSERT_EQ(resultBits.encoding.exponent, 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,25 +163,31 @@ result = func(x, 0); FPBits xBits = FPBits(x); FPBits resultBits = FPBits(result); - ASSERT_EQ(resultBits.exponent, uint16_t(xBits.exponent - 1)); - ASSERT_EQ(resultBits.mantissa, (UIntType(1) << MantissaWidth::value) - 1); + ASSERT_EQ(resultBits.encoding.exponent, + uint16_t(xBits.encoding.exponent - 1)); + ASSERT_EQ(resultBits.encoding.mantissa, + (UIntType(1) << MantissaWidth::value) - 1); result = func(x, T(33.0)); resultBits = FPBits(result); - ASSERT_EQ(resultBits.exponent, xBits.exponent); - ASSERT_EQ(resultBits.mantissa, xBits.mantissa + UIntType(1)); + ASSERT_EQ(resultBits.encoding.exponent, xBits.encoding.exponent); + ASSERT_EQ(resultBits.encoding.mantissa, + xBits.encoding.mantissa + UIntType(1)); x = -x; result = func(x, 0); resultBits = FPBits(result); - ASSERT_EQ(resultBits.exponent, uint16_t(xBits.exponent - 1)); - ASSERT_EQ(resultBits.mantissa, (UIntType(1) << MantissaWidth::value) - 1); + ASSERT_EQ(resultBits.encoding.exponent, + uint16_t(xBits.encoding.exponent - 1)); + ASSERT_EQ(resultBits.encoding.mantissa, + (UIntType(1) << MantissaWidth::value) - 1); result = func(x, T(-33.0)); resultBits = FPBits(result); - ASSERT_EQ(resultBits.exponent, xBits.exponent); - ASSERT_EQ(resultBits.mantissa, xBits.mantissa + UIntType(1)); + ASSERT_EQ(resultBits.encoding.exponent, xBits.encoding.exponent); + ASSERT_EQ(resultBits.encoding.mantissa, + xBits.encoding.mantissa + 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.exponent = exponentLimit + FPBits::exponentBias; - bits.sign = 1; - bits.mantissa = 0; + bits.encoding.exponent = exponentLimit + FPBits::exponentBias; + bits.encoding.sign = 1; + bits.encoding.mantissa = 0; F x = bits; long mpfrResult; @@ -199,10 +199,10 @@ // We start with 1.0 so that the implicit bit for x86 long doubles // is set. FPBits bits(F(1.0)); - bits.exponent = exponentLimit + FPBits::exponentBias; - bits.sign = 1; - bits.mantissa = UIntType(0x1) - << (__llvm_libc::fputil::MantissaWidth::value - 1); + bits.encoding.exponent = exponentLimit + FPBits::exponentBias; + bits.encoding.sign = 1; + bits.encoding.mantissa = + UIntType(0x1) << (__llvm_libc::fputil::MantissaWidth::value - 1); F x = bits; if (TestModes) { diff --git a/libc/test/src/math/sqrt_test.cpp b/libc/test/src/math/sqrt_test.cpp --- a/libc/test/src/math/sqrt_test.cpp +++ b/libc/test/src/math/sqrt_test.cpp @@ -37,7 +37,7 @@ TEST(LlvmLibcSqrtTest, DenormalValues) { for (UIntType mant = 1; mant < HiddenBit; mant <<= 1) { FPBits denormal(0.0); - denormal.mantissa = mant; + denormal.encoding.mantissa = mant; ASSERT_MPFR_MATCH(mpfr::Operation::Sqrt, double(denormal), __llvm_libc::sqrt(denormal), 0.5); diff --git a/libc/test/src/math/sqrtf_test.cpp b/libc/test/src/math/sqrtf_test.cpp --- a/libc/test/src/math/sqrtf_test.cpp +++ b/libc/test/src/math/sqrtf_test.cpp @@ -37,7 +37,7 @@ TEST(LlvmLibcSqrtfTest, DenormalValues) { for (UIntType mant = 1; mant < HiddenBit; mant <<= 1) { FPBits denormal(0.0f); - denormal.mantissa = mant; + denormal.encoding.mantissa = mant; ASSERT_MPFR_MATCH(mpfr::Operation::Sqrt, float(denormal), __llvm_libc::sqrtf(denormal), 0.5); diff --git a/libc/test/src/math/sqrtl_test.cpp b/libc/test/src/math/sqrtl_test.cpp --- a/libc/test/src/math/sqrtl_test.cpp +++ b/libc/test/src/math/sqrtl_test.cpp @@ -37,7 +37,7 @@ TEST(LlvmLibcSqrtlTest, DenormalValues) { for (UIntType mant = 1; mant < HiddenBit; mant <<= 1) { FPBits denormal(0.0L); - denormal.mantissa = mant; + denormal.encoding.mantissa = mant; ASSERT_MPFR_MATCH(mpfr::Operation::Sqrt, static_cast(denormal), __llvm_libc::sqrtl(denormal), 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.sign = 0; + bits.encoding.sign = 0; return T(bits); } @@ -33,11 +33,11 @@ return y; } else if (bity.isNaN()) { return x; - } else if (bitx.sign != bity.sign) { + } else if (bitx.encoding.sign != bity.encoding.sign) { // 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.sign ? x : y); + return (bitx.encoding.sign ? x : y); } else { return (x < y ? x : y); } @@ -52,11 +52,11 @@ return y; } else if (bity.isNaN()) { return x; - } else if (bitx.sign != bity.sign) { + } else if (bitx.encoding.sign != bity.encoding.sign) { // 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.sign ? y : x); + return (bitx.encoding.sign ? 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,12 @@ return x; } - bool resultSign = (xbits.sign == ybits.sign ? false : true); + bool resultSign = (xbits.encoding.sign == ybits.encoding.sign ? 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.sign = ybits.sign = 0; + xbits.encoding.sign = ybits.encoding.sign = 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 @@ -57,7 +57,7 @@ // 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 __attribute__((packed)) FPBits { +template union FPBits { static_assert(cpp::IsFloatingPointType::Value, "FPBits instantiated with invalid type."); @@ -66,9 +66,18 @@ // type is provided for such reinterpretations. using UIntType = typename FPUIntType::Type; - UIntType mantissa : MantissaWidth::value; - uint16_t exponent : ExponentWidth::value; - uint8_t sign : 1; + struct __attribute__((packed)) { + UIntType mantissa : MantissaWidth::value; + uint16_t exponent : ExponentWidth::value; + uint8_t sign : 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), + "Integral representation and value type have different sizes."); static constexpr int exponentBias = (1 << (ExponentWidth::value - 1)) - 1; static constexpr int maxExponent = (1 << ExponentWidth::value) - 1; @@ -84,60 +93,56 @@ // We don't want accidental type promotions/conversions so we require exact // type match. template ::Value || - (cpp::IsIntegral::Value && - (sizeof(XType) == sizeof(UIntType))), - int> = 0> - explicit FPBits(XType x) { - *this = *reinterpret_cast *>(&x); - } + cpp::EnableIfType::Value, int> = 0> + explicit FPBits(XType x) : val(x) {} - operator T() { return *reinterpret_cast(this); } + template ::Value, int> = 0> + explicit FPBits(XType x) : integer(x) {} - int getExponent() const { return int(exponent) - exponentBias; } + FPBits() : integer(0) {} - bool isZero() const { return mantissa == 0 && exponent == 0; } + operator T() { return val; } - bool isInf() const { return mantissa == 0 && exponent == maxExponent; } + UIntType uintval() const { return integer; } - bool isNaN() const { return exponent == maxExponent && mantissa != 0; } + int getExponent() const { return int(encoding.exponent) - exponentBias; } - bool isInfOrNaN() const { return exponent == maxExponent; } + bool isZero() const { + return encoding.mantissa == 0 && encoding.exponent == 0; + } - // Methods below this are used by tests. - // The to and from integer bits converters are only used in tests. Hence, - // the potential software implementations of UIntType will not slow real - // code. + bool isInf() const { + return encoding.mantissa == 0 && encoding.exponent == maxExponent; + } - UIntType bitsAsUInt() const { - return *reinterpret_cast(this); + bool isNaN() const { + return encoding.exponent == maxExponent && encoding.mantissa != 0; } - static FPBits zero() { return FPBits(T(0.0)); } + bool isInfOrNaN() const { return encoding.exponent == maxExponent; } + + static FPBits zero() { return FPBits(); } static FPBits negZero() { - FPBits bits(T(0.0)); - bits.sign = 1; - return bits; + return FPBits(UIntType(1) << (sizeof(UIntType) * 8 - 1)); } static FPBits inf() { - FPBits bits(T(0.0)); - bits.exponent = maxExponent; + FPBits bits; + bits.encoding.exponent = maxExponent; return bits; } static FPBits negInf() { - FPBits bits(T(0.0)); - bits.exponent = maxExponent; - bits.sign = 1; + FPBits bits = inf(); + bits.encoding.sign = 1; return bits; } static T buildNaN(UIntType v) { - FPBits bits(T(0.0)); - bits.exponent = maxExponent; - bits.mantissa = v; + FPBits bits = inf(); + bits.encoding.mantissa = v; return 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,26 +139,27 @@ DUIntType a_mant_sq, b_mant_sq; bool sticky_bits; - if ((x_bits.exponent >= y_bits.exponent + MantissaWidth::value + 2) || + if ((x_bits.encoding.exponent >= + y_bits.encoding.exponent + MantissaWidth::value + 2) || (y == 0)) { return abs(x); - } else if ((y_bits.exponent >= - x_bits.exponent + MantissaWidth::value + 2) || + } else if ((y_bits.encoding.exponent >= + x_bits.encoding.exponent + MantissaWidth::value + 2) || (x == 0)) { - y_bits.sign = 0; + y_bits.encoding.sign = 0; return abs(y); } if (x >= y) { - a_exp = x_bits.exponent; - a_mant = x_bits.mantissa; - b_exp = y_bits.exponent; - b_mant = y_bits.mantissa; + a_exp = x_bits.encoding.exponent; + a_mant = x_bits.encoding.mantissa; + b_exp = y_bits.encoding.exponent; + b_mant = y_bits.encoding.mantissa; } else { - a_exp = y_bits.exponent; - a_mant = y_bits.mantissa; - b_exp = x_bits.exponent; - b_mant = x_bits.mantissa; + a_exp = y_bits.encoding.exponent; + a_mant = y_bits.encoding.mantissa; + b_exp = x_bits.encoding.exponent; + b_mant = x_bits.encoding.mantissa; } 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 @@ -28,7 +28,7 @@ // x86_64 padding. template <> struct Padding<8> { static constexpr unsigned value = 48; }; -template <> struct __attribute__((packed)) FPBits { +template <> union FPBits { using UIntType = __uint128_t; static constexpr int exponentBias = 0x3FFF; @@ -43,102 +43,97 @@ ((UIntType(maxExponent) - 1) << (MantissaWidth::value + 1)) | (UIntType(1) << MantissaWidth::value) | maxSubnormal; - UIntType mantissa : MantissaWidth::value; - uint8_t implicitBit : 1; - uint16_t exponent : ExponentWidth::value; - uint8_t sign : 1; - uint64_t padding : Padding::value; + 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; + long double val; + + FPBits() : integer(0) {} template ::Value, int> = 0> - explicit FPBits(XType x) { - *this = *reinterpret_cast *>(&x); - } + explicit FPBits(XType x) : val(x) {} + + template ::Value, int> = 0> + explicit FPBits(XType x) : integer(x) {} + + operator long double() { return val; } - operator long double() { return *reinterpret_cast(this); } + UIntType uintval() { + // We zero the padding bits as they can contain garbage. + static constexpr UIntType mask = + (UIntType(1) << (sizeof(long double) * 8 - + Padding::value)) - + 1; + return integer & mask; + } int getExponent() const { - if (exponent == 0) + if (encoding.exponent == 0) return int(1) - exponentBias; - return int(exponent) - exponentBias; + return int(encoding.exponent) - exponentBias; } bool isZero() const { - return exponent == 0 && mantissa == 0 && implicitBit == 0; + return encoding.exponent == 0 && encoding.mantissa == 0 && + encoding.implicitBit == 0; } bool isInf() const { - return exponent == maxExponent && mantissa == 0 && implicitBit == 1; + return encoding.exponent == maxExponent && encoding.mantissa == 0 && + encoding.implicitBit == 1; } bool isNaN() const { - if (exponent == maxExponent) { - return (implicitBit == 0) || mantissa != 0; - } else if (exponent != 0) { - return implicitBit == 0; + if (encoding.exponent == maxExponent) { + return (encoding.implicitBit == 0) || encoding.mantissa != 0; + } else if (encoding.exponent != 0) { + return encoding.implicitBit == 0; } return false; } bool isInfOrNaN() const { - return (exponent == maxExponent) || (exponent != 0 && implicitBit == 0); + return (encoding.exponent == maxExponent) || + (encoding.exponent != 0 && encoding.implicitBit == 0); } // Methods below this are used by tests. - template ::Value, int> = 0> - explicit FPBits(XType x) { - // The last 4 bytes of v are ignored in case of i386. - *this = *reinterpret_cast *>(&x); - } - - UIntType bitsAsUInt() const { - // We cannot just return the bits as is as it will lead to reading - // out of bounds in case of i386. So, we first copy the wider value - // before returning the value. This makes the last 4 bytes are always - // zero in case i386. - UIntType result = UIntType(0); - *reinterpret_cast *>(&result) = *this; - - // Even though we zero out |result| before copying the long double value, - // there can be garbage bits in the padding. So, we zero the padding bits - // in |result|. - static constexpr UIntType mask = - (UIntType(1) << (sizeof(long double) * 8 - - Padding::value)) - - 1; - return result & mask; - } - static FPBits zero() { return FPBits(0.0l); } static FPBits negZero() { FPBits bits(0.0l); - bits.sign = 1; + bits.encoding.sign = 1; return bits; } static FPBits inf() { FPBits bits(0.0l); - bits.exponent = maxExponent; - bits.implicitBit = 1; + bits.encoding.exponent = maxExponent; + bits.encoding.implicitBit = 1; return bits; } static FPBits negInf() { FPBits bits(0.0l); - bits.exponent = maxExponent; - bits.implicitBit = 1; - bits.sign = 1; + bits.encoding.exponent = maxExponent; + bits.encoding.implicitBit = 1; + bits.encoding.sign = 1; return bits; } static long double buildNaN(UIntType v) { FPBits bits(0.0l); - bits.exponent = maxExponent; - bits.implicitBit = 1; - bits.mantissa = v; + bits.encoding.exponent = maxExponent; + bits.encoding.implicitBit = 1; + bits.encoding.mantissa = 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 @@ -47,13 +47,13 @@ return x; } else if (bits.isInf()) { iptr = x; - return bits.sign ? FPBits::negZero() : FPBits::zero(); + return bits.encoding.sign ? FPBits::negZero() : 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.sign ? FPBits::negZero() : FPBits::zero(); + return bits.encoding.sign ? FPBits::negZero() : FPBits::zero(); } else { return x - iptr; } @@ -64,7 +64,7 @@ cpp::EnableIfType::Value, int> = 0> static inline T copysign(T x, T y) { FPBits xbits(x); - xbits.sign = FPBits(y).sign; + xbits.encoding.sign = FPBits(y).encoding.sign; return xbits; } @@ -131,11 +131,11 @@ // calculating the limit. int expLimit = FPBits::maxExponent + MantissaWidth::value + 1; if (exp > expLimit) - return bits.sign ? FPBits::negInf() : FPBits::inf(); + return bits.encoding.sign ? FPBits::negInf() : FPBits::inf(); // Similarly on the negative side we return zero early if |exp| is too small. if (exp < -expLimit) - return bits.sign ? FPBits::negZero() : FPBits::zero(); + return bits.encoding.sign ? FPBits::negZero() : FPBits::zero(); // For all other values, NormalFloat to T conversion handles it the right way. NormalFloat normal(bits); @@ -158,7 +158,7 @@ return to; using UIntType = typename FPBits::UIntType; - auto intVal = fromBits.bitsAsUInt(); + UIntType intVal = fromBits.uintval(); UIntType signMask = (UIntType(1) << (sizeof(T) * 8 - 1)); if (from != T(0.0)) { if ((from < to) == (from > T(0.0))) { @@ -167,7 +167,7 @@ --intVal; } } else { - intVal = (toBits.bitsAsUInt() & signMask) + UIntType(1); + intVal = (UIntType(toBits) & signMask) + UIntType(1); } return *reinterpret_cast(&intVal); 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.sign) + if (bits.encoding.sign) return T(-0.0); else return T(0.0); } int trimSize = MantissaWidth::value - exponent; - bits.mantissa = (bits.mantissa >> trimSize) << trimSize; + bits.encoding.mantissa = (bits.encoding.mantissa >> trimSize) << trimSize; return bits; } @@ -63,7 +63,7 @@ if (bits.isInfOrNaN() || bits.isZero()) return x; - bool isNeg = bits.sign; + bool isNeg = bits.encoding.sign; 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.mantissa = (bits.mantissa >> trimSize) << trimSize; + bits.encoding.mantissa = (bits.encoding.mantissa >> 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.sign) { + if (bits.encoding.sign) { return -ceil(-x); } else { return trunc(x); @@ -114,7 +114,7 @@ if (bits.isInfOrNaN() || bits.isZero()) return x; - bool isNeg = bits.sign; + bool isNeg = bits.encoding.sign; 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.mantissa & (UIntType(1) << (trimSize - 1)); - bits.mantissa = (bits.mantissa >> trimSize) << trimSize; + bool halfBitSet = bits.encoding.mantissa & (UIntType(1) << (trimSize - 1)); + bits.encoding.mantissa = (bits.encoding.mantissa >> 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.sign; + bool isNeg = bits.encoding.sign; 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.mantissa == 0) + if (exponent <= -2 || bits.encoding.mantissa == 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.mantissa = (bits.mantissa >> trimSize) << trimSize; + newBits.encoding.mantissa = (bits.encoding.mantissa >> trimSize) << trimSize; T truncValue = T(newBits); // If x is already an integer, return it. if (truncValue == x) return x; - UIntType trimValue = bits.mantissa & ((UIntType(1) << trimSize) - 1); + UIntType trimValue = bits.encoding.mantissa & ((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.mantissa & (UIntType(1) << trimSize); + UIntType truncIsOdd = newBits.encoding.mantissa & (UIntType(1) << trimSize); switch (roundingMode) { case FE_DOWNWARD: @@ -255,18 +255,18 @@ if (bits.isInfOrNaN()) { setDomainErrorAndRaiseInvalid(); - return bits.sign ? IntegerMin : IntegerMax; + return bits.encoding.sign ? IntegerMin : IntegerMax; } int exponent = bits.getExponent(); constexpr int exponentLimit = sizeof(I) * 8 - 1; if (exponent > exponentLimit) { setDomainErrorAndRaiseInvalid(); - return bits.sign ? IntegerMin : IntegerMax; + return bits.encoding.sign ? IntegerMin : IntegerMax; } else if (exponent == exponentLimit) { - if (bits.sign == 0 || bits.mantissa != 0) { + if (bits.encoding.sign == 0 || bits.encoding.mantissa != 0) { setDomainErrorAndRaiseInvalid(); - return bits.sign ? IntegerMin : IntegerMax; + return bits.encoding.sign ? 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,15 +30,15 @@ return to; // Convert pseudo subnormal number to normal number. - if (fromBits.implicitBit == 1 && fromBits.exponent == 0) { - fromBits.exponent = 1; + if (fromBits.encoding.implicitBit == 1 && fromBits.encoding.exponent == 0) { + fromBits.encoding.exponent = 1; } using UIntType = FPBits::UIntType; constexpr UIntType signVal = (UIntType(1) << 79); constexpr UIntType mantissaMask = (UIntType(1) << MantissaWidth::value) - 1; - auto intVal = fromBits.bitsAsUInt(); + UIntType intVal = fromBits.uintval(); if (from < 0.0l) { if (from > to) { if (intVal == (signVal + FPBits::maxSubnormal)) { @@ -46,11 +46,11 @@ // dealing with the implicit bit. intVal = signVal + FPBits::minNormal; } else if ((intVal & mantissaMask) == mantissaMask) { - fromBits.mantissa = 0; + fromBits.encoding.mantissa = 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.exponent; + ++fromBits.encoding.exponent; return fromBits; } else { ++intVal; @@ -61,10 +61,10 @@ // dealing with the implicit bit. intVal = signVal + FPBits::maxSubnormal; } else if ((intVal & mantissaMask) == 0) { - fromBits.mantissa = mantissaMask; + fromBits.encoding.mantissa = mantissaMask; // from == 0 is handled separately so decrementing the exponent will not // lead to underflow. - --fromBits.exponent; + --fromBits.encoding.exponent; return fromBits; } else { --intVal; @@ -80,10 +80,10 @@ if (intVal == FPBits::minNormal) { intVal = FPBits::maxSubnormal; } else if ((intVal & mantissaMask) == 0) { - fromBits.mantissa = mantissaMask; + fromBits.encoding.mantissa = mantissaMask; // from == 0 is handled separately so decrementing the exponent will not // lead to underflow. - --fromBits.exponent; + --fromBits.encoding.exponent; return fromBits; } else { --intVal; @@ -92,11 +92,11 @@ if (intVal == FPBits::maxSubnormal) { intVal = FPBits::minNormal; } else if ((intVal & mantissaMask) == mantissaMask) { - fromBits.mantissa = 0; + fromBits.encoding.mantissa = 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.exponent; + ++fromBits.encoding.exponent; 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.sign = sign; + result.encoding.sign = 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.exponent = 0; - result.mantissa = mantissa >> shift; - UIntType newMantissa = result.mantissa; + result.encoding.exponent = 0; + result.encoding.mantissa = mantissa >> shift; + UIntType newMantissa = result.encoding.mantissa; if (shiftOutValue > halfwayValue) { newMantissa += 1; } else if (shiftOutValue == halfwayValue) { // Round to even. - if (result.mantissa & 0x1) + if (result.encoding.mantissa & 0x1) newMantissa += 1; } - result.mantissa = newMantissa; + result.encoding.mantissa = 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.exponent = 1; + result.encoding.exponent = 1; return result; } else { return result; } } - result.exponent = exponent + FPBits::exponentBias; - result.mantissa = mantissa; + result.encoding.exponent = exponent + FPBits::exponentBias; + result.encoding.mantissa = mantissa; return result; } private: void initFromBits(FPBits bits) { - sign = bits.sign; + sign = bits.encoding.sign; if (bits.isInfOrNaN() || bits.isZero()) { // Ignore special bit patterns. Implementations deal with them separately @@ -150,13 +150,13 @@ } // Normalize subnormal numbers. - if (bits.exponent == 0) { - unsigned shift = evaluateNormalizationShift(bits.mantissa); - mantissa = UIntType(bits.mantissa) << shift; + if (bits.encoding.exponent == 0) { + unsigned shift = evaluateNormalizationShift(bits.encoding.mantissa); + mantissa = UIntType(bits.encoding.mantissa) << shift; exponent = 1 - FPBits::exponentBias - shift; } else { - exponent = bits.exponent - FPBits::exponentBias; - mantissa = one | bits.mantissa; + exponent = bits.encoding.exponent - FPBits::exponentBias; + mantissa = one | bits.encoding.mantissa; } } @@ -172,7 +172,7 @@ #if defined(__x86_64__) || defined(__i386__) template <> inline void NormalFloat::initFromBits(FPBits bits) { - sign = bits.sign; + sign = bits.encoding.sign; if (bits.isInfOrNaN() || bits.isZero()) { // Ignore special bit patterns. Implementations deal with them separately @@ -182,24 +182,25 @@ return; } - if (bits.exponent == 0) { - if (bits.implicitBit == 0) { + if (bits.encoding.exponent == 0) { + if (bits.encoding.implicitBit == 0) { // Since we ignore zero value, the mantissa in this case is non-zero. - int normalizationShift = evaluateNormalizationShift(bits.mantissa); + int normalizationShift = + evaluateNormalizationShift(bits.encoding.mantissa); exponent = -16382 - normalizationShift; - mantissa = (bits.mantissa << normalizationShift); + mantissa = (bits.encoding.mantissa << normalizationShift); } else { exponent = -16382; - mantissa = one | bits.mantissa; + mantissa = one | bits.encoding.mantissa; } } else { - if (bits.implicitBit == 0) { + if (bits.encoding.implicitBit == 0) { // Invalid number so just store 0 similar to a NaN. exponent = 0; mantissa = 0; } else { - exponent = bits.exponent - 16383; - mantissa = one | bits.mantissa; + exponent = bits.encoding.exponent - 16383; + mantissa = one | bits.encoding.mantissa; } } } @@ -213,7 +214,7 @@ } FPBits result(0.0l); - result.sign = sign; + result.encoding.sign = sign; constexpr int subnormalExponent = -FPBits::exponentBias + 1; if (exponent < subnormalExponent) { @@ -224,25 +225,25 @@ const UIntType shiftOutMask = (UIntType(1) << shift) - 1; const UIntType shiftOutValue = mantissa & shiftOutMask; const UIntType halfwayValue = UIntType(1) << (shift - 1); - result.exponent = 0; - result.mantissa = mantissa >> shift; - UIntType newMantissa = result.mantissa; + result.encoding.exponent = 0; + result.encoding.mantissa = mantissa >> shift; + UIntType newMantissa = result.encoding.mantissa; if (shiftOutValue > halfwayValue) { newMantissa += 1; } else if (shiftOutValue == halfwayValue) { // Round to even. - if (result.mantissa & 0x1) + if (result.encoding.mantissa & 0x1) newMantissa += 1; } - result.mantissa = newMantissa; + result.encoding.mantissa = 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.exponent = 1; - result.implicitBit = 1; + result.encoding.exponent = 1; + result.encoding.implicitBit = 1; } else { - result.implicitBit = 0; + result.encoding.implicitBit = 0; } return result; } else { @@ -250,9 +251,9 @@ } } - result.exponent = biasedExponent; - result.mantissa = mantissa; - result.implicitBit = 1; + result.encoding.exponent = biasedExponent; + result.encoding.mantissa = mantissa; + result.encoding.implicitBit = 1; return result; } #endif 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 @@ -96,7 +96,7 @@ FPBits bits(x); if (bits.isInfOrNaN()) { - if (bits.sign && (bits.mantissa == 0)) { + if (bits.encoding.sign && (bits.encoding.mantissa == 0)) { // sqrt(-Inf) = NaN return FPBits::buildNaN(One >> 1); } else { @@ -108,15 +108,15 @@ // sqrt(+0) = +0 // sqrt(-0) = -0 return x; - } else if (bits.sign) { + } else if (bits.encoding.sign) { // sqrt( negative numbers ) = NaN return FPBits::buildNaN(One >> 1); } else { int xExp = bits.getExponent(); - UIntType xMant = bits.mantissa; + UIntType xMant = bits.encoding.mantissa; // Step 1a: Normalize denormal input and append hiddent bit to the mantissa - if (bits.exponent == 0) { + if (bits.encoding.exponent == 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 @@ -51,7 +51,7 @@ FPBits bits(x); if (bits.isInfOrNaN()) { - if (bits.sign && (bits.mantissa == 0)) { + if (bits.encoding.sign && (bits.encoding.mantissa == 0)) { // sqrt(-Inf) = NaN return FPBits::buildNaN(One >> 1); } else { @@ -63,17 +63,17 @@ // sqrt(+0) = +0 // sqrt(-0) = -0 return x; - } else if (bits.sign) { + } else if (bits.encoding.sign) { // sqrt( negative numbers ) = NaN return FPBits::buildNaN(One >> 1); } else { int xExp = bits.getExponent(); - UIntType xMant = bits.mantissa; + UIntType xMant = bits.encoding.mantissa; // Step 1a: Normalize denormal input - if (bits.implicitBit) { + if (bits.encoding.implicitBit) { xMant |= One; - } else if (bits.exponent == 0) { + } else if (bits.encoding.exponent == 0) { internal::normalize(xExp, xMant); } @@ -129,9 +129,9 @@ // Extract output FPBits out(0.0L); - out.exponent = xExp; - out.implicitBit = 1; - out.mantissa = (y & (One - 1)); + out.encoding.exponent = xExp; + out.encoding.implicitBit = 1; + out.encoding.mantissa = (y & (One - 1)); return out; } diff --git a/libc/utils/FPUtil/TestHelpers.h b/libc/utils/FPUtil/TestHelpers.h --- a/libc/utils/FPUtil/TestHelpers.h +++ b/libc/utils/FPUtil/TestHelpers.h @@ -41,13 +41,13 @@ fputil::FPBits actualBits(actual), expectedBits(expected); if (Condition == __llvm_libc::testing::Cond_EQ) return (actualBits.isNaN() && expectedBits.isNaN()) || - (actualBits.bitsAsUInt() == expectedBits.bitsAsUInt()); + (actualBits.uintval() == expectedBits.uintval()); // If condition == Cond_NE. if (actualBits.isNaN()) return !expectedBits.isNaN(); return expectedBits.isNaN() || - (actualBits.bitsAsUInt() != expectedBits.bitsAsUInt()); + (actualBits.uintval() != expectedBits.uintval()); } void explainError(testutils::StreamWrapper &stream) override { 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.sign) + if (bits.encoding.sign) stream << "(-Infinity)"; else stream << "(+Infinity)"; @@ -50,12 +50,13 @@ constexpr int mantissaWidthInHex = (fputil::MantissaWidth::value - 1) / 4 + 1; - stream << "Sign: " << (bits.sign ? '1' : '0') << ", " + stream << "Sign: " << (bits.encoding.sign ? '1' : '0') << ", " << "Exponent: 0x" - << uintToHex(bits.exponent, exponentWidthInHex) << ", " + << uintToHex(bits.encoding.exponent, exponentWidthInHex) + << ", " << "Mantissa: 0x" << uintToHex::UIntType>( - bits.mantissa, mantissaWidthInHex); + bits.encoding.mantissa, mantissaWidthInHex); } stream << '\n'; diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -264,12 +264,12 @@ mpfr_abs(mpfrInput.value, mpfrInput.value, MPFR_RNDN); // get eps(input) - int epsExponent = bits.exponent - fputil::FPBits::exponentBias - + int epsExponent = bits.encoding.exponent - fputil::FPBits::exponentBias - fputil::MantissaWidth::value; - if (bits.exponent == 0) { + if (bits.encoding.exponent == 0) { // correcting denormal exponent ++epsExponent; - } else if ((bits.mantissa == 0) && (bits.exponent > 1) && + } else if ((bits.encoding.mantissa == 0) && (bits.encoding.exponent > 1) && mpfr_less_p(value, mpfrInput.value)) { // when the input is exactly 2^n, distance (epsilon) between the input // and the next floating point number is different from the distance to @@ -567,7 +567,7 @@ // is rounded to the nearest even. MPFRNumber mpfrResult = unaryOperation(op, input); double ulp = mpfrResult.ulp(libcResult); - bool bitsAreEven = ((FPBits(libcResult).bitsAsUInt() & 1) == 0); + bool bitsAreEven = ((FPBits(libcResult).uintval() & 1) == 0); return (ulp < ulpError) || ((ulp == ulpError) && ((ulp != 0.5) || bitsAreEven)); } @@ -592,7 +592,7 @@ if (mpfrIntResult != libcResult.i) return false; - bool bitsAreEven = ((FPBits(libcResult.f).bitsAsUInt() & 1) == 0); + bool bitsAreEven = ((FPBits(libcResult.f).uintval() & 1) == 0); return (ulp < ulpError) || ((ulp == ulpError) && ((ulp != 0.5) || bitsAreEven)); } @@ -624,7 +624,7 @@ } } - bool bitsAreEven = ((FPBits(libcResult.f).bitsAsUInt() & 1) == 0); + bool bitsAreEven = ((FPBits(libcResult.f).uintval() & 1) == 0); return (ulp < ulpError) || ((ulp == ulpError) && ((ulp != 0.5) || bitsAreEven)); } @@ -645,7 +645,7 @@ MPFRNumber mpfrResult = binaryOperationOneOutput(op, input.x, input.y); double ulp = mpfrResult.ulp(libcResult); - bool bitsAreEven = ((FPBits(libcResult).bitsAsUInt() & 1) == 0); + bool bitsAreEven = ((FPBits(libcResult).uintval() & 1) == 0); return (ulp < ulpError) || ((ulp == ulpError) && ((ulp != 0.5) || bitsAreEven)); } @@ -667,7 +667,7 @@ ternaryOperationOneOutput(op, input.x, input.y, input.z); double ulp = mpfrResult.ulp(libcResult); - bool bitsAreEven = ((FPBits(libcResult).bitsAsUInt() & 1) == 0); + bool bitsAreEven = ((FPBits(libcResult).uintval() & 1) == 0); return (ulp < ulpError) || ((ulp == ulpError) && ((ulp != 0.5) || bitsAreEven)); }