diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt --- a/libc/src/__support/CMakeLists.txt +++ b/libc/src/__support/CMakeLists.txt @@ -45,6 +45,7 @@ libc.include.errno libc.src.errno.errno libc.src.__support.CPP.limits + libc.src.__support.CPP.uint128 libc.src.__support.FPUtil.fputil ) diff --git a/libc/src/__support/CPP/CMakeLists.txt b/libc/src/__support/CPP/CMakeLists.txt --- a/libc/src/__support/CPP/CMakeLists.txt +++ b/libc/src/__support/CPP/CMakeLists.txt @@ -4,6 +4,22 @@ Array.h ) +add_header_library( + uint + HDRS + UInt.h + DEPENDS + .array +) + +add_header_library( + uint128 + HDRS + UInt128.h + DEPENDS + .uint +) + add_header_library( array_ref HDRS @@ -32,6 +48,8 @@ limits HDRS Limits.h + DEPENDS + .uint ) add_header_library( @@ -44,6 +62,8 @@ type_traits HDRS TypeTraits.h + DEPENDS + .uint ) add_header_library( @@ -77,11 +97,3 @@ HDRS error.h ) - -add_header_library( - uint - HDRS - UInt.h - DEPENDS - libc.src.__support.CPP.array -) diff --git a/libc/src/__support/CPP/Limits.h b/libc/src/__support/CPP/Limits.h --- a/libc/src/__support/CPP/Limits.h +++ b/libc/src/__support/CPP/Limits.h @@ -9,6 +9,8 @@ #ifndef LLVM_LIBC_SRC_SUPPORT_CPP_LIMITS_H #define LLVM_LIBC_SRC_SUPPORT_CPP_LIMITS_H +#include "UInt.h" + #include namespace __llvm_libc { @@ -72,18 +74,26 @@ static constexpr unsigned char max() { return UCHAR_MAX; } static constexpr unsigned char min() { return 0; } }; +// This specialization enables two things: +// 1. On platforms where UInt128 resolves to UInt<128>, this specialization +// provides limits of UInt128. +// 2. On platforms where UInt128 resolves to __uint128_t, this specialization +// allows us to unittest UInt<128>. +template <> class NumericLimits> { +public: + static constexpr UInt<128> max() { return ~UInt<128>(0); } + static constexpr UInt<128> min() { return 0; } +}; #ifdef __SIZEOF_INT128__ +// On platform where UInt128 resolves to __uint128_t, this specialization +// provides the limits of UInt128. template <> class NumericLimits<__uint128_t> { public: static constexpr __uint128_t max() { return ~__uint128_t(0); } static constexpr __uint128_t min() { return 0; } }; -template <> class NumericLimits<__int128_t> { -public: - static constexpr __int128_t max() { return ~__uint128_t(0) >> 1; } - static constexpr __int128_t min() { return __int128_t(1) << 127; } -}; #endif + } // namespace cpp } // namespace __llvm_libc diff --git a/libc/src/__support/CPP/TypeTraits.h b/libc/src/__support/CPP/TypeTraits.h --- a/libc/src/__support/CPP/TypeTraits.h +++ b/libc/src/__support/CPP/TypeTraits.h @@ -56,9 +56,13 @@ IsSameV || IsSameV || IsSameV || IsSameV || IsSameV || IsSameV || - IsSameV, TypeNoCV> + // We need to include UInt<128> and __uint128_t when available because + // we want to unittest UInt<128>. If we include only UInt128, then on + // platform where it resolves to __uint128_t, we cannot unittest + // UInt<128>. + IsSameV<__llvm_libc::cpp::UInt<128>, TypeNoCV> #ifdef __SIZEOF_INT128__ - || IsSameV<__uint128_t, TypeNoCV> || IsSameV<__int128_t, TypeNoCV> + || IsSameV<__uint128_t, TypeNoCV> #endif ; }; diff --git a/libc/src/__support/CPP/UInt.h b/libc/src/__support/CPP/UInt.h --- a/libc/src/__support/CPP/UInt.h +++ b/libc/src/__support/CPP/UInt.h @@ -183,6 +183,11 @@ return result; } + constexpr UInt &operator<<=(size_t s) { + shift_left(s); + return *this; + } + constexpr void shift_right(size_t s) { const size_t drop = s / 64; // Number of words to drop const size_t shift = s % 64; // Bit shift in the remaining words. @@ -208,6 +213,11 @@ return result; } + constexpr UInt &operator>>=(size_t s) { + shift_right(s); + return *this; + } + constexpr UInt operator&(const UInt &other) const { UInt result; for (size_t i = 0; i < WordCount; ++i) @@ -229,6 +239,13 @@ return result; } + constexpr UInt operator~() const { + UInt result; + for (size_t i = 0; i < WordCount; ++i) + result.val[i] = ~val[i]; + return result; + } + constexpr bool operator==(const UInt &other) const { for (size_t i = 0; i < WordCount; ++i) { if (val[i] != other.val[i]) @@ -345,10 +362,4 @@ } // namespace cpp } // namespace __llvm_libc -/* TODO: determine the best way to support uint128 using this class. -#if !defined(__SIZEOF_INT128__) -using __uint128_t = __llvm_libc::internal::UInt<128>; -#endif // uint128 is not defined, define it with this class. -*/ - #endif // LLVM_LIBC_UTILS_CPP_UINT_H diff --git a/libc/src/__support/CPP/UInt128.h b/libc/src/__support/CPP/UInt128.h new file mode 100644 --- /dev/null +++ b/libc/src/__support/CPP/UInt128.h @@ -0,0 +1,20 @@ +//===-- A 128 bit unsigned int type -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SUPPORT_CPP_UINT128_H +#define LLVM_LIBC_SRC_SUPPORT_CPP_UINT128_H + +#include "UInt.h" + +#if !defined(__SIZEOF_INT128__) +using UInt128 = __llvm_libc::internal::UInt<128>; +#else +using UInt128 = __uint128_t; +#endif + +#endif // LLVM_LIBC_SRC_SUPPORT_CPP_UINT128_H diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt --- a/libc/src/__support/FPUtil/CMakeLists.txt +++ b/libc/src/__support/FPUtil/CMakeLists.txt @@ -12,15 +12,15 @@ NearestIntegerOperations.h NormalFloat.h PlatformDefs.h - UInt.h builtin_wrappers.h DEPENDS libc.include.math libc.include.errno libc.include.fenv libc.src.__support.common - libc.src.__support.CPP.type_traits libc.src.__support.CPP.bit + libc.src.__support.CPP.type_traits + libc.src.__support.CPP.uint128 libc.src.errno.errno ) diff --git a/libc/src/__support/FPUtil/FloatProperties.h b/libc/src/__support/FPUtil/FloatProperties.h --- a/libc/src/__support/FPUtil/FloatProperties.h +++ b/libc/src/__support/FPUtil/FloatProperties.h @@ -10,6 +10,9 @@ #define LLVM_LIBC_SRC_SUPPORT_FPUTIL_FLOAT_PROPERTIES_H #include "PlatformDefs.h" + +#include "src/__support/CPP/UInt128.h" + #include namespace __llvm_libc { @@ -104,7 +107,7 @@ // Properties for numbers represented in 80 bits long double on non-Windows x86 // platforms. template <> struct FloatProperties { - typedef __uint128_t BitsType; + typedef UInt128 BitsType; static_assert(sizeof(BitsType) == sizeof(long double), "Unexpected size of 'long double' type."); @@ -140,7 +143,7 @@ // Properties for numbers represented in 128 bits long double on non x86 // platform. template <> struct FloatProperties { - typedef __uint128_t BitsType; + typedef UInt128 BitsType; static_assert(sizeof(BitsType) == sizeof(long double), "Unexpected size of 'long double' type."); diff --git a/libc/src/__support/FPUtil/Hypot.h b/libc/src/__support/FPUtil/Hypot.h --- a/libc/src/__support/FPUtil/Hypot.h +++ b/libc/src/__support/FPUtil/Hypot.h @@ -15,6 +15,7 @@ #include "builtin_wrappers.h" #include "src/__support/CPP/Bit.h" #include "src/__support/CPP/TypeTraits.h" +#include "src/__support/CPP/UInt128.h" namespace __llvm_libc { namespace fputil { @@ -38,7 +39,9 @@ template <> struct DoubleLength { using Type = uint64_t; }; -template <> struct DoubleLength { using Type = __uint128_t; }; +template <> struct DoubleLength { + using Type = UInt128; +}; // Correctly rounded IEEE 754 HYPOT(x, y) with round to nearest, ties to even. // diff --git a/libc/src/__support/FPUtil/generic/CMakeLists.txt b/libc/src/__support/FPUtil/generic/CMakeLists.txt --- a/libc/src/__support/FPUtil/generic/CMakeLists.txt +++ b/libc/src/__support/FPUtil/generic/CMakeLists.txt @@ -3,10 +3,14 @@ HDRS sqrt.h sqrt_80_bit_long_double.h + DEPENDS + libc.src.__support.CPP.uint128 ) add_header_library( fma HDRS FMA.h + DEPENDS + libc.src.__support.CPP.uint128 ) diff --git a/libc/src/__support/FPUtil/generic/FMA.h b/libc/src/__support/FPUtil/generic/FMA.h --- a/libc/src/__support/FPUtil/generic/FMA.h +++ b/libc/src/__support/FPUtil/generic/FMA.h @@ -11,6 +11,7 @@ #include "src/__support/CPP/Bit.h" #include "src/__support/CPP/TypeTraits.h" +#include "src/__support/CPP/UInt128.h" #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/FloatProperties.h" @@ -78,12 +79,12 @@ // Extract the sticky bits and shift the `mantissa` to the right by // `shift_length`. -static inline bool shift_mantissa(int shift_length, __uint128_t &mant) { +static inline bool shift_mantissa(int shift_length, UInt128 &mant) { if (shift_length >= 128) { mant = 0; return true; // prod_mant is non-zero. } - __uint128_t mask = (__uint128_t(1) << shift_length) - 1; + UInt128 mask = (UInt128(1) << shift_length) - 1; bool sticky_bits = (mant & mask) != 0; mant >>= shift_length; return sticky_bits; @@ -131,9 +132,9 @@ return x * y + z; // Extract mantissa and append hidden leading bits. - __uint128_t x_mant = x_bits.get_mantissa() | FPBits::MIN_NORMAL; - __uint128_t y_mant = y_bits.get_mantissa() | FPBits::MIN_NORMAL; - __uint128_t z_mant = z_bits.get_mantissa() | FPBits::MIN_NORMAL; + UInt128 x_mant = x_bits.get_mantissa() | FPBits::MIN_NORMAL; + UInt128 y_mant = y_bits.get_mantissa() | FPBits::MIN_NORMAL; + UInt128 z_mant = z_bits.get_mantissa() | FPBits::MIN_NORMAL; // If the exponent of the product x*y > the exponent of z, then no extra // precision beside the entire product x*y is needed. On the other hand, when @@ -154,7 +155,7 @@ // the original mantissa as high part when constructing 128-bit z_mant. So the // mantissa of prod will be left-shifted by 64 - 54 = 10 initially. - __uint128_t prod_mant = x_mant * y_mant << 10; + UInt128 prod_mant = x_mant * y_mant << 10; int prod_lsb_exp = x_exp + y_exp - (FPBits::EXPONENT_BIAS + 2 * MantissaWidth::VALUE + 10); diff --git a/libc/src/__support/FPUtil/generic/sqrt.h b/libc/src/__support/FPUtil/generic/sqrt.h --- a/libc/src/__support/FPUtil/generic/sqrt.h +++ b/libc/src/__support/FPUtil/generic/sqrt.h @@ -12,6 +12,7 @@ #include "sqrt_80_bit_long_double.h" #include "src/__support/CPP/Bit.h" #include "src/__support/CPP/TypeTraits.h" +#include "src/__support/CPP/UInt128.h" #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/PlatformDefs.h" @@ -48,7 +49,7 @@ } #elif !defined(SPECIAL_X86_LONG_DOUBLE) template <> -inline void normalize(int &exponent, __uint128_t &mantissa) { +inline void normalize(int &exponent, UInt128 &mantissa) { const uint64_t hi_bits = static_cast(mantissa >> 64); const int shift = hi_bits ? (clz(hi_bits) - 15) : (clz(static_cast(mantissa)) + 49); diff --git a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h --- a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h +++ b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIBC_SRC_SUPPORT_FPUTIL_GENERIC_SQRT_80_BIT_LONG_DOUBLE_H #define LLVM_LIBC_SRC_SUPPORT_FPUTIL_GENERIC_SQRT_80_BIT_LONG_DOUBLE_H +#include "src/__support/CPP/UInt128.h" #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/PlatformDefs.h" @@ -18,7 +19,7 @@ namespace fputil { namespace x86 { -inline void normalize(int &exponent, __uint128_t &mantissa) { +inline void normalize(int &exponent, UInt128 &mantissa) { const int shift = clz(static_cast(mantissa)) - (8 * sizeof(uint64_t) - 1 - MantissaWidth::VALUE); diff --git a/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h b/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h --- a/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h +++ b/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h @@ -10,6 +10,7 @@ #define LLVM_LIBC_SRC_SUPPORT_FPUTIL_X86_64_LONG_DOUBLE_BITS_H #include "src/__support/CPP/Bit.h" +#include "src/__support/CPP/UInt128.h" #include "src/__support/architectures.h" #if !defined(LLVM_LIBC_ARCH_X86) @@ -32,7 +33,7 @@ template <> struct Padding<8> { static constexpr unsigned VALUE = 48; }; template <> struct FPBits { - using UIntType = __uint128_t; + using UIntType = UInt128; static constexpr int EXPONENT_BIAS = 0x3FFF; static constexpr int MAX_EXPONENT = 0x7FFF; diff --git a/libc/src/__support/str_to_float.h b/libc/src/__support/str_to_float.h --- a/libc/src/__support/str_to_float.h +++ b/libc/src/__support/str_to_float.h @@ -10,6 +10,7 @@ #define LIBC_SRC_SUPPORT_STR_TO_FLOAT_H #include "src/__support/CPP/Limits.h" +#include "src/__support/CPP/UInt128.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/builtin_wrappers.h" #include "src/__support/ctype_utils.h" @@ -58,11 +59,11 @@ return inputNumber == 0 ? 64 : fputil::clz(inputNumber); } -static inline uint64_t low64(__uint128_t num) { +static inline uint64_t low64(const UInt128 &num) { return static_cast(num & 0xffffffffffffffff); } -static inline uint64_t high64(__uint128_t num) { +static inline uint64_t high64(const UInt128 &num) { return static_cast(num >> 64); } @@ -116,11 +117,11 @@ const uint64_t *power_of_ten = DETAILED_POWERS_OF_TEN[exp10 - DETAILED_POWERS_OF_TEN_MIN_EXP_10]; - __uint128_t first_approx = static_cast<__uint128_t>(mantissa) * - static_cast<__uint128_t>(power_of_ten[1]); + UInt128 first_approx = + static_cast(mantissa) * static_cast(power_of_ten[1]); // Wider Approximation - __uint128_t final_approx; + UInt128 final_approx; // The halfway constant is used to check if the bits that will be shifted away // intially are all 1. For doubles this is 64 (bitstype size) - 52 (final // mantissa size) - 3 (we shift away the last two bits separately for @@ -132,10 +133,10 @@ 1; if ((high64(first_approx) & halfway_constant) == halfway_constant && low64(first_approx) + mantissa < mantissa) { - __uint128_t low_bits = static_cast<__uint128_t>(mantissa) * - static_cast<__uint128_t>(power_of_ten[0]); - __uint128_t second_approx = - first_approx + static_cast<__uint128_t>(high64(low_bits)); + UInt128 low_bits = + static_cast(mantissa) * static_cast(power_of_ten[0]); + UInt128 second_approx = + first_approx + static_cast(high64(low_bits)); if ((high64(second_approx) & halfway_constant) == halfway_constant && low64(second_approx) + 1 == 0 && @@ -220,31 +221,31 @@ // full 128 bits of the power of ten to get an approximation with the same // number of significant bits. This means that we only get the one // approximation, and that approximation is 256 bits long. - __uint128_t approx_upper = static_cast<__uint128_t>(high64(mantissa)) * - static_cast<__uint128_t>(power_of_ten[1]); + UInt128 approx_upper = static_cast(high64(mantissa)) * + static_cast(power_of_ten[1]); - __uint128_t approx_middle = static_cast<__uint128_t>(high64(mantissa)) * - static_cast<__uint128_t>(power_of_ten[0]) + - static_cast<__uint128_t>(low64(mantissa)) * - static_cast<__uint128_t>(power_of_ten[1]); + UInt128 approx_middle = static_cast(high64(mantissa)) * + static_cast(power_of_ten[0]) + + static_cast(low64(mantissa)) * + static_cast(power_of_ten[1]); - __uint128_t approx_lower = static_cast<__uint128_t>(low64(mantissa)) * - static_cast<__uint128_t>(power_of_ten[0]); + UInt128 approx_lower = static_cast(low64(mantissa)) * + static_cast(power_of_ten[0]); - __uint128_t final_approx_lower = - approx_lower + (static_cast<__uint128_t>(low64(approx_middle)) << 64); - __uint128_t final_approx_upper = approx_upper + high64(approx_middle) + - (final_approx_lower < approx_lower ? 1 : 0); + UInt128 final_approx_lower = + approx_lower + (static_cast(low64(approx_middle)) << 64); + UInt128 final_approx_upper = approx_upper + high64(approx_middle) + + (final_approx_lower < approx_lower ? 1 : 0); // The halfway constant is used to check if the bits that will be shifted away // intially are all 1. For 80 bit floats this is 128 (bitstype size) - 64 // (final mantissa size) - 3 (we shift away the last two bits separately for // accuracy, and the most significant bit is ignored.) = 61 bits. Similarly, // it's 12 bits for 128 bit floats in this case. - constexpr __uint128_t HALFWAY_CONSTANT = - (__uint128_t(1) << (BITS_IN_MANTISSA - - fputil::FloatProperties::MANTISSA_WIDTH - - 3)) - + constexpr UInt128 HALFWAY_CONSTANT = + (UInt128(1) << (BITS_IN_MANTISSA - + fputil::FloatProperties::MANTISSA_WIDTH - + 3)) - 1; if ((final_approx_upper & HALFWAY_CONSTANT) == HALFWAY_CONSTANT && diff --git a/libc/test/src/__support/CMakeLists.txt b/libc/test/src/__support/CMakeLists.txt --- a/libc/test/src/__support/CMakeLists.txt +++ b/libc/test/src/__support/CMakeLists.txt @@ -18,6 +18,7 @@ high_precision_decimal_test.cpp DEPENDS libc.src.__support.high_precision_decimal + libc.src.__support.CPP.uint128 ) add_libc_unittest( @@ -28,6 +29,7 @@ str_to_float_test.cpp DEPENDS libc.src.__support.str_to_float + libc.src.__support.CPP.uint128 ) add_libc_unittest( diff --git a/libc/test/src/__support/CPP/CMakeLists.txt b/libc/test/src/__support/CPP/CMakeLists.txt --- a/libc/test/src/__support/CPP/CMakeLists.txt +++ b/libc/test/src/__support/CPP/CMakeLists.txt @@ -28,6 +28,7 @@ limits_test.cpp DEPENDS libc.src.__support.CPP.limits + libc.src.__support.CPP.uint ) add_libc_unittest( diff --git a/libc/test/src/__support/CPP/limits_test.cpp b/libc/test/src/__support/CPP/limits_test.cpp --- a/libc/test/src/__support/CPP/limits_test.cpp +++ b/libc/test/src/__support/CPP/limits_test.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/CPP/Limits.h" +#include "src/__support/CPP/UInt.h" #include "utils/UnitTest/Test.h" // This just checks against the C spec, almost all implementations will surpass @@ -29,23 +30,15 @@ ULLONG_MAX); } +TEST(LlvmLibcLimitsTest, UInt128Limits) { + auto umax128 = + __llvm_libc::cpp::NumericLimits<__llvm_libc::cpp::UInt<128>>::max(); + auto umax64 = __llvm_libc::cpp::UInt<128>( + __llvm_libc::cpp::NumericLimits::max()); + EXPECT_GT(umax128, umax64); + ASSERT_EQ(~__llvm_libc::cpp::UInt<128>(0), umax128); #ifdef __SIZEOF_INT128__ -// This checks that the current environment supports 128 bit integers. -TEST(LlvmLibcLimitsTest, Int128Works) { - __int128_t max128 = ~__uint128_t(0) >> 1; - __int128_t min128 = (__int128_t(1) << 127); - EXPECT_GT(__llvm_libc::cpp::NumericLimits<__int128_t>::max(), - __int128_t(__llvm_libc::cpp::NumericLimits::max())); - ASSERT_EQ(__llvm_libc::cpp::NumericLimits<__int128_t>::max(), max128); - - EXPECT_LT(__llvm_libc::cpp::NumericLimits<__int128_t>::min(), - __int128_t(__llvm_libc::cpp::NumericLimits::min())); - ASSERT_EQ(__llvm_libc::cpp::NumericLimits<__int128_t>::min(), min128); - - __uint128_t umax128 = ~__uint128_t(0); - EXPECT_GT( - __llvm_libc::cpp::NumericLimits<__uint128_t>::max(), - __uint128_t(__llvm_libc::cpp::NumericLimits::max())); - ASSERT_EQ(__llvm_libc::cpp::NumericLimits<__uint128_t>::max(), umax128); -} + ASSERT_EQ(~__uint128_t(0), + __llvm_libc::cpp::NumericLimits<__uint128_t>::max()); #endif +} diff --git a/libc/test/src/__support/high_precision_decimal_test.cpp b/libc/test/src/__support/high_precision_decimal_test.cpp --- a/libc/test/src/__support/high_precision_decimal_test.cpp +++ b/libc/test/src/__support/high_precision_decimal_test.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "src/__support/CPP/UInt128.h" #include "src/__support/high_precision_decimal.h" #include "utils/UnitTest/Test.h" @@ -344,34 +345,26 @@ EXPECT_EQ(hpd.round_to_integer_type(), uint32_t(1)); EXPECT_EQ(hpd.round_to_integer_type(), uint64_t(1)); -#ifdef __SIZEOF_INT128__ - EXPECT_EQ(hpd.round_to_integer_type<__uint128_t>(), __uint128_t(1)); -#endif + EXPECT_EQ(hpd.round_to_integer_type(), UInt128(1)); hpd.shift(1); // shift left 1 to get 2.469 (rounds to 2) EXPECT_EQ(hpd.round_to_integer_type(), uint32_t(2)); EXPECT_EQ(hpd.round_to_integer_type(), uint64_t(2)); -#ifdef __SIZEOF_INT128__ - EXPECT_EQ(hpd.round_to_integer_type<__uint128_t>(), __uint128_t(2)); -#endif + EXPECT_EQ(hpd.round_to_integer_type(), UInt128(2)); hpd.shift(1); // shift left 1 to get 4.938 (rounds to 5) EXPECT_EQ(hpd.round_to_integer_type(), uint32_t(5)); EXPECT_EQ(hpd.round_to_integer_type(), uint64_t(5)); -#ifdef __SIZEOF_INT128__ - EXPECT_EQ(hpd.round_to_integer_type<__uint128_t>(), __uint128_t(5)); -#endif + EXPECT_EQ(hpd.round_to_integer_type(), UInt128(5)); // 2.5 is right between two integers, so we round to even (2) hpd = __llvm_libc::internal::HighPrecisionDecimal("2.5"); EXPECT_EQ(hpd.round_to_integer_type(), uint32_t(2)); EXPECT_EQ(hpd.round_to_integer_type(), uint64_t(2)); -#ifdef __SIZEOF_INT128__ - EXPECT_EQ(hpd.round_to_integer_type<__uint128_t>(), __uint128_t(2)); -#endif + EXPECT_EQ(hpd.round_to_integer_type(), UInt128(2)); // unless it's marked as having truncated, which means it's actually slightly // higher, forcing a round up (3) @@ -379,9 +372,7 @@ EXPECT_EQ(hpd.round_to_integer_type(), uint32_t(3)); EXPECT_EQ(hpd.round_to_integer_type(), uint64_t(3)); -#ifdef __SIZEOF_INT128__ - EXPECT_EQ(hpd.round_to_integer_type<__uint128_t>(), __uint128_t(3)); -#endif + EXPECT_EQ(hpd.round_to_integer_type(), UInt128(3)); // Check that the larger int types are being handled properly (overflow is not // handled, so int types that are too small are ignored for this test.) @@ -390,16 +381,13 @@ hpd = __llvm_libc::internal::HighPrecisionDecimal("1099511627776"); EXPECT_EQ(hpd.round_to_integer_type(), uint64_t(1099511627776)); -#ifdef __SIZEOF_INT128__ - EXPECT_EQ(hpd.round_to_integer_type<__uint128_t>(), - __uint128_t(1099511627776)); + EXPECT_EQ(hpd.round_to_integer_type(), UInt128(1099511627776)); // 1267650600228229401496703205376 = 2^100 hpd = __llvm_libc::internal::HighPrecisionDecimal( "1267650600228229401496703205376"); - __uint128_t result = __uint128_t(1) << 100; + UInt128 result = UInt128(1) << 100; - EXPECT_EQ(hpd.round_to_integer_type<__uint128_t>(), result); -#endif + EXPECT_EQ(hpd.round_to_integer_type(), result); } diff --git a/libc/test/src/__support/str_to_float_test.cpp b/libc/test/src/__support/str_to_float_test.cpp --- a/libc/test/src/__support/str_to_float_test.cpp +++ b/libc/test/src/__support/str_to_float_test.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "src/__support/CPP/UInt128.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/str_to_float.h" @@ -273,14 +274,14 @@ } TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat80LongerMantissa) { - eisel_lemire_test((__uint128_t(0x1234567812345678) << 64) + - __uint128_t(0x1234567812345678), + eisel_lemire_test((UInt128(0x1234567812345678) << 64) + + UInt128(0x1234567812345678), 0, 0x91a2b3c091a2b3c1, 16507); - eisel_lemire_test((__uint128_t(0x1234567812345678) << 64) + - __uint128_t(0x1234567812345678), + eisel_lemire_test((UInt128(0x1234567812345678) << 64) + + UInt128(0x1234567812345678), 300, 0xd97757de56adb65c, 17503); - eisel_lemire_test((__uint128_t(0x1234567812345678) << 64) + - __uint128_t(0x1234567812345678), + eisel_lemire_test((UInt128(0x1234567812345678) << 64) + + UInt128(0x1234567812345678), -300, 0xc30feb9a7618457d, 15510); } @@ -299,7 +300,7 @@ TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat80Fallback) { uint32_t outputExp2 = 0; - __uint128_t quadOutputMantissa = 0; + UInt128 quadOutputMantissa = 0; // This number is halfway between two possible results, and the algorithm // can't determine which is correct. @@ -313,39 +314,33 @@ ASSERT_FALSE(__llvm_libc::internal::eisel_lemire( 1, -1000, &quadOutputMantissa, &outputExp2)); } -#elif defined(__SIZEOF_INT128__) +#else // Quad precision long double TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat128Simple) { - eisel_lemire_test(123, 0, (__uint128_t(0x1ec0000000000) << 64), + eisel_lemire_test(123, 0, (UInt128(0x1ec0000000000) << 64), 16389); - eisel_lemire_test(12345678901234568192u, 0, - (__uint128_t(0x156a95319d63e) << 64) + - __uint128_t(0x1800000000000000), - 16446); + eisel_lemire_test( + 12345678901234568192u, 0, + (UInt128(0x156a95319d63e) << 64) + UInt128(0x1800000000000000), 16446); } TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat128LongerMantissa) { eisel_lemire_test( - (__uint128_t(0x1234567812345678) << 64) + __uint128_t(0x1234567812345678), - 0, (__uint128_t(0x1234567812345) << 64) + __uint128_t(0x6781234567812345), - 16507); + (UInt128(0x1234567812345678) << 64) + UInt128(0x1234567812345678), 0, + (UInt128(0x1234567812345) << 64) + UInt128(0x6781234567812345), 16507); eisel_lemire_test( - (__uint128_t(0x1234567812345678) << 64) + __uint128_t(0x1234567812345678), - 300, - (__uint128_t(0x1b2eeafbcad5b) << 64) + __uint128_t(0x6cb8b4451dfcde19), - 17503); + (UInt128(0x1234567812345678) << 64) + UInt128(0x1234567812345678), 300, + (UInt128(0x1b2eeafbcad5b) << 64) + UInt128(0x6cb8b4451dfcde19), 17503); eisel_lemire_test( - (__uint128_t(0x1234567812345678) << 64) + __uint128_t(0x1234567812345678), - -300, - (__uint128_t(0x1861fd734ec30) << 64) + __uint128_t(0x8afa7189f0f7595f), - 15510); + (UInt128(0x1234567812345678) << 64) + UInt128(0x1234567812345678), -300, + (UInt128(0x1861fd734ec30) << 64) + UInt128(0x8afa7189f0f7595f), 15510); } TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat128Fallback) { uint32_t outputExp2 = 0; - __uint128_t quadOutputMantissa = 0; + UInt128 quadOutputMantissa = 0; ASSERT_FALSE(__llvm_libc::internal::eisel_lemire( - (__uint128_t(0x5ce0e9a56015fec5) << 64) + __uint128_t(0xaadfa328ae39b333), - 1, &quadOutputMantissa, &outputExp2)); + (UInt128(0x5ce0e9a56015fec5) << 64) + UInt128(0xaadfa328ae39b333), 1, + &quadOutputMantissa, &outputExp2)); } #endif diff --git a/libc/test/src/__support/uint128_test.cpp b/libc/test/src/__support/uint128_test.cpp --- a/libc/test/src/__support/uint128_test.cpp +++ b/libc/test/src/__support/uint128_test.cpp @@ -10,56 +10,59 @@ #include "utils/UnitTest/Test.h" -using UInt128 = __llvm_libc::cpp::UInt<128>; +// We want to test __llvm_libc::cpp::UInt<128> explicitly. So, for convenience, +// we use a sugar which does not conflict with the UInt128 type which can +// resolve to __uint128_t if the platform has it. +using LL_UInt128 = __llvm_libc::cpp::UInt<128>; TEST(LlvmLibcUInt128ClassTest, BasicInit) { - UInt128 empty; - UInt128 half_val(12345); - UInt128 full_val({12345, 67890}); + LL_UInt128 empty; + LL_UInt128 half_val(12345); + LL_UInt128 full_val({12345, 67890}); ASSERT_TRUE(half_val != full_val); } TEST(LlvmLibcUInt128ClassTest, AdditionTests) { - UInt128 val1(12345); - UInt128 val2(54321); - UInt128 result1(66666); + LL_UInt128 val1(12345); + LL_UInt128 val2(54321); + LL_UInt128 result1(66666); EXPECT_EQ(val1 + val2, result1); EXPECT_EQ((val1 + val2), (val2 + val1)); // addition is reciprocal // Test overflow - UInt128 val3({0xf000000000000001, 0}); - UInt128 val4({0x100000000000000f, 0}); - UInt128 result2({0x10, 0x1}); + LL_UInt128 val3({0xf000000000000001, 0}); + LL_UInt128 val4({0x100000000000000f, 0}); + LL_UInt128 result2({0x10, 0x1}); EXPECT_EQ(val3 + val4, result2); EXPECT_EQ(val3 + val4, val4 + val3); } TEST(LlvmLibcUInt128ClassTest, MultiplicationTests) { - UInt128 val1({5, 0}); - UInt128 val2({10, 0}); - UInt128 result1({50, 0}); + LL_UInt128 val1({5, 0}); + LL_UInt128 val2({10, 0}); + LL_UInt128 result1({50, 0}); EXPECT_EQ((val1 * val2), result1); EXPECT_EQ((val1 * val2), (val2 * val1)); // multiplication is reciprocal // Check that the multiplication works accross the whole number - UInt128 val3({0xf, 0}); - UInt128 val4({0x1111111111111111, 0x1111111111111111}); - UInt128 result2({0xffffffffffffffff, 0xffffffffffffffff}); + LL_UInt128 val3({0xf, 0}); + LL_UInt128 val4({0x1111111111111111, 0x1111111111111111}); + LL_UInt128 result2({0xffffffffffffffff, 0xffffffffffffffff}); EXPECT_EQ((val3 * val4), result2); EXPECT_EQ((val3 * val4), (val4 * val3)); // Check that multiplication doesn't reorder the bits. - UInt128 val5({2, 0}); - UInt128 val6({0x1357024675316420, 0x0123456776543210}); - UInt128 result3({0x26ae048cea62c840, 0x02468aceeca86420}); + LL_UInt128 val5({2, 0}); + LL_UInt128 val6({0x1357024675316420, 0x0123456776543210}); + LL_UInt128 result3({0x26ae048cea62c840, 0x02468aceeca86420}); EXPECT_EQ((val5 * val6), result3); EXPECT_EQ((val5 * val6), (val6 * val5)); // Make sure that multiplication handles overflow correctly. - UInt128 val7(2); - UInt128 val8({0x8000800080008000, 0x8000800080008000}); - UInt128 result4({0x0001000100010000, 0x0001000100010001}); + LL_UInt128 val7(2); + LL_UInt128 val8({0x8000800080008000, 0x8000800080008000}); + LL_UInt128 result4({0x0001000100010000, 0x0001000100010001}); EXPECT_EQ((val7 * val8), result4); EXPECT_EQ((val7 * val8), (val8 * val7)); @@ -67,92 +70,98 @@ // 1e-60. They almost cancel on the high bits, but the result we're looking // for is just the low bits. The full result would be // 0x7fffffffffffffffffffffffffffffff3a4f32d17f40d08f917cf11d1e039c50 - UInt128 val9({0x01D762422C946590, 0x9F4F2726179A2245}); - UInt128 val10({0x3792F412CB06794D, 0xCDB02555653131B6}); - UInt128 result5({0x917cf11d1e039c50, 0x3a4f32d17f40d08f}); + LL_UInt128 val9({0x01D762422C946590, 0x9F4F2726179A2245}); + LL_UInt128 val10({0x3792F412CB06794D, 0xCDB02555653131B6}); + LL_UInt128 result5({0x917cf11d1e039c50, 0x3a4f32d17f40d08f}); EXPECT_EQ((val9 * val10), result5); EXPECT_EQ((val9 * val10), (val10 * val9)); } TEST(LlvmLibcUInt128ClassTest, ShiftLeftTests) { - UInt128 val1(0x0123456789abcdef); - UInt128 result1(0x123456789abcdef0); + LL_UInt128 val1(0x0123456789abcdef); + LL_UInt128 result1(0x123456789abcdef0); EXPECT_EQ((val1 << 4), result1); - UInt128 val2({0x13579bdf02468ace, 0x123456789abcdef0}); - UInt128 result2({0x02468ace00000000, 0x9abcdef013579bdf}); + LL_UInt128 val2({0x13579bdf02468ace, 0x123456789abcdef0}); + LL_UInt128 result2({0x02468ace00000000, 0x9abcdef013579bdf}); EXPECT_EQ((val2 << 32), result2); + LL_UInt128 val22 = val2; + val22 <<= 32; + EXPECT_EQ(val22, result2); - UInt128 result3({0, 0x13579bdf02468ace}); + LL_UInt128 result3({0, 0x13579bdf02468ace}); EXPECT_EQ((val2 << 64), result3); - UInt128 result4({0, 0x02468ace00000000}); + LL_UInt128 result4({0, 0x02468ace00000000}); EXPECT_EQ((val2 << 96), result4); - UInt128 result5({0, 0x2468ace000000000}); + LL_UInt128 result5({0, 0x2468ace000000000}); EXPECT_EQ((val2 << 100), result5); - UInt128 result6({0, 0}); + LL_UInt128 result6({0, 0}); EXPECT_EQ((val2 << 128), result6); EXPECT_EQ((val2 << 256), result6); } TEST(LlvmLibcUInt128ClassTest, ShiftRightTests) { - UInt128 val1(0x0123456789abcdef); - UInt128 result1(0x00123456789abcde); + LL_UInt128 val1(0x0123456789abcdef); + LL_UInt128 result1(0x00123456789abcde); EXPECT_EQ((val1 >> 4), result1); - UInt128 val2({0x13579bdf02468ace, 0x123456789abcdef0}); - UInt128 result2({0x9abcdef013579bdf, 0x0000000012345678}); + LL_UInt128 val2({0x13579bdf02468ace, 0x123456789abcdef0}); + LL_UInt128 result2({0x9abcdef013579bdf, 0x0000000012345678}); EXPECT_EQ((val2 >> 32), result2); + LL_UInt128 val22 = val2; + val22 >>= 32; + EXPECT_EQ(val22, result2); - UInt128 result3({0x123456789abcdef0, 0}); + LL_UInt128 result3({0x123456789abcdef0, 0}); EXPECT_EQ((val2 >> 64), result3); - UInt128 result4({0x0000000012345678, 0}); + LL_UInt128 result4({0x0000000012345678, 0}); EXPECT_EQ((val2 >> 96), result4); - UInt128 result5({0x0000000001234567, 0}); + LL_UInt128 result5({0x0000000001234567, 0}); EXPECT_EQ((val2 >> 100), result5); - UInt128 result6({0, 0}); + LL_UInt128 result6({0, 0}); EXPECT_EQ((val2 >> 128), result6); EXPECT_EQ((val2 >> 256), result6); } TEST(LlvmLibcUInt128ClassTest, AndTests) { - UInt128 base({0xffff00000000ffff, 0xffffffff00000000}); - UInt128 val128({0xf0f0f0f00f0f0f0f, 0xff00ff0000ff00ff}); + LL_UInt128 base({0xffff00000000ffff, 0xffffffff00000000}); + LL_UInt128 val128({0xf0f0f0f00f0f0f0f, 0xff00ff0000ff00ff}); uint64_t val64 = 0xf0f0f0f00f0f0f0f; int val32 = 0x0f0f0f0f; - UInt128 result128({0xf0f0000000000f0f, 0xff00ff0000000000}); - UInt128 result64(0xf0f0000000000f0f); - UInt128 result32(0x00000f0f); + LL_UInt128 result128({0xf0f0000000000f0f, 0xff00ff0000000000}); + LL_UInt128 result64(0xf0f0000000000f0f); + LL_UInt128 result32(0x00000f0f); EXPECT_EQ((base & val128), result128); EXPECT_EQ((base & val64), result64); EXPECT_EQ((base & val32), result32); } TEST(LlvmLibcUInt128ClassTest, OrTests) { - UInt128 base({0xffff00000000ffff, 0xffffffff00000000}); - UInt128 val128({0xf0f0f0f00f0f0f0f, 0xff00ff0000ff00ff}); + LL_UInt128 base({0xffff00000000ffff, 0xffffffff00000000}); + LL_UInt128 val128({0xf0f0f0f00f0f0f0f, 0xff00ff0000ff00ff}); uint64_t val64 = 0xf0f0f0f00f0f0f0f; int val32 = 0x0f0f0f0f; - UInt128 result128({0xfffff0f00f0fffff, 0xffffffff00ff00ff}); - UInt128 result64({0xfffff0f00f0fffff, 0xffffffff00000000}); - UInt128 result32({0xffff00000f0fffff, 0xffffffff00000000}); + LL_UInt128 result128({0xfffff0f00f0fffff, 0xffffffff00ff00ff}); + LL_UInt128 result64({0xfffff0f00f0fffff, 0xffffffff00000000}); + LL_UInt128 result32({0xffff00000f0fffff, 0xffffffff00000000}); EXPECT_EQ((base | val128), result128); EXPECT_EQ((base | val64), result64); EXPECT_EQ((base | val32), result32); } TEST(LlvmLibcUInt128ClassTest, EqualsTests) { - UInt128 a1({0xffffffff00000000, 0xffff00000000ffff}); - UInt128 a2({0xffffffff00000000, 0xffff00000000ffff}); - UInt128 b({0xff00ff0000ff00ff, 0xf0f0f0f00f0f0f0f}); - UInt128 a_reversed({0xffff00000000ffff, 0xffffffff00000000}); - UInt128 a_upper(0xffff00000000ffff); - UInt128 a_lower(0xffffffff00000000); + LL_UInt128 a1({0xffffffff00000000, 0xffff00000000ffff}); + LL_UInt128 a2({0xffffffff00000000, 0xffff00000000ffff}); + LL_UInt128 b({0xff00ff0000ff00ff, 0xf0f0f0f00f0f0f0f}); + LL_UInt128 a_reversed({0xffff00000000ffff, 0xffffffff00000000}); + LL_UInt128 a_upper(0xffff00000000ffff); + LL_UInt128 a_lower(0xffffffff00000000); ASSERT_TRUE(a1 == a1); ASSERT_TRUE(a1 == a2); ASSERT_FALSE(a1 == b); @@ -163,15 +172,15 @@ } TEST(LlvmLibcUInt128ClassTest, ComparisonTests) { - UInt128 a({0xffffffff00000000, 0xffff00000000ffff}); - UInt128 b({0xff00ff0000ff00ff, 0xf0f0f0f00f0f0f0f}); + LL_UInt128 a({0xffffffff00000000, 0xffff00000000ffff}); + LL_UInt128 b({0xff00ff0000ff00ff, 0xf0f0f0f00f0f0f0f}); EXPECT_GT(a, b); EXPECT_GE(a, b); EXPECT_LT(b, a); EXPECT_LE(b, a); - UInt128 x(0xffffffff00000000); - UInt128 y(0x00000000ffffffff); + LL_UInt128 x(0xffffffff00000000); + LL_UInt128 y(0x00000000ffffffff); EXPECT_GT(x, y); EXPECT_GE(x, y); EXPECT_LT(y, x); diff --git a/libc/test/src/stdlib/CMakeLists.txt b/libc/test/src/stdlib/CMakeLists.txt --- a/libc/test/src/stdlib/CMakeLists.txt +++ b/libc/test/src/stdlib/CMakeLists.txt @@ -77,6 +77,7 @@ SRCS strtold_test.cpp DEPENDS + libc.src.__support.CPP.uint128 libc.src.stdlib.strtold ) diff --git a/libc/test/src/stdlib/strtold_test.cpp b/libc/test/src/stdlib/strtold_test.cpp --- a/libc/test/src/stdlib/strtold_test.cpp +++ b/libc/test/src/stdlib/strtold_test.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "src/__support/CPP/UInt128.h" #include "src/__support/FPUtil/FPBits.h" #include "src/stdlib/strtold.h" @@ -30,7 +31,7 @@ const uint64_t expectedRawData, const int expectedErrno = 0) #else void run_test(const char *inputString, const ptrdiff_t expectedStrLen, - const __uint128_t expectedRawData, const int expectedErrno = 0) + const UInt128 expectedRawData, const int expectedErrno = 0) #endif { // expectedRawData64 is the expected long double result as a uint64_t, @@ -46,7 +47,7 @@ // | // +-- 11 Exponent Bits - // expectedRawData80 is the expected long double result as a __uint128_t, + // expectedRawData80 is the expected long double result as a UInt128, // organized according to the x86 extended precision format: // // +-- 1 Sign Bit @@ -59,7 +60,7 @@ // | | // +-- 15 Exponent Bits +-- 63 Mantissa bits - // expectedRawData128 is the expected long double result as a __uint128_t, + // expectedRawData128 is the expected long double result as a UInt128, // organized according to IEEE754 quadruple precision format: // // +-- 1 Sign Bit +-- 112 Mantissa bits @@ -97,73 +98,67 @@ TEST_F(LlvmLibcStrToLDTest, SimpleTest) { run_test("123", 3, SELECT_CONST(uint64_t(0x405ec00000000000), - __uint128_t(0x4005f60000) << 40, - __uint128_t(0x4005ec0000000000) << 64)); + UInt128(0x4005f60000) << 40, + UInt128(0x4005ec0000000000) << 64)); // This should fail on Eisel-Lemire, forcing a fallback to simple decimal // conversion. run_test("12345678901234549760", 20, SELECT_CONST(uint64_t(0x43e56a95319d63d8), - (__uint128_t(0x403eab54a9) << 40) + - __uint128_t(0x8ceb1ec400), - (__uint128_t(0x403e56a95319d63d) << 64) + - __uint128_t(0x8800000000000000))); + (UInt128(0x403eab54a9) << 40) + UInt128(0x8ceb1ec400), + (UInt128(0x403e56a95319d63d) << 64) + + UInt128(0x8800000000000000))); // Found while looking for difficult test cases here: // https://github.com/nigeltao/parse-number-fxx-test-data/blob/main/more-test-cases/golang-org-issue-36657.txt run_test("1090544144181609348835077142190", 31, SELECT_CONST(uint64_t(0x462b8779f2474dfb), - (__uint128_t(0x4062dc3bcf) << 40) + - __uint128_t(0x923a6fd402), - (__uint128_t(0x4062b8779f2474df) << 64) + - __uint128_t(0xa804bfd8c6d5c000))); + (UInt128(0x4062dc3bcf) << 40) + UInt128(0x923a6fd402), + (UInt128(0x4062b8779f2474df) << 64) + + UInt128(0xa804bfd8c6d5c000))); run_test("0x123", 5, SELECT_CONST(uint64_t(0x4072300000000000), - (__uint128_t(0x4007918000) << 40), - (__uint128_t(0x4007230000000000) << 64))); + (UInt128(0x4007918000) << 40), + (UInt128(0x4007230000000000) << 64))); } // These are tests that have caused problems for doubles in the past. TEST_F(LlvmLibcStrToLDTest, Float64SpecificFailures) { run_test("3E70000000000000", 16, SELECT_CONST(uint64_t(0x7FF0000000000000), - (__uint128_t(0x7fff800000) << 40), - (__uint128_t(0x7fff000000000000) << 64)), + (UInt128(0x7fff800000) << 40), + (UInt128(0x7fff000000000000) << 64)), ERANGE); run_test("358416272e-33", 13, SELECT_CONST(uint64_t(0x3adbbb2a68c9d0b9), - (__uint128_t(0x3fadddd953) << 40) + - __uint128_t(0x464e85c400), - (__uint128_t(0x3fadbbb2a68c9d0b) << 64) + - __uint128_t(0x8800e7969e1c5fc8))); + (UInt128(0x3fadddd953) << 40) + UInt128(0x464e85c400), + (UInt128(0x3fadbbb2a68c9d0b) << 64) + + UInt128(0x8800e7969e1c5fc8))); run_test("2.16656806400000023841857910156251e9", 36, SELECT_CONST(uint64_t(0x41e0246690000001), - (__uint128_t(0x401e812334) << 40) + - __uint128_t(0x8000000400), - (__uint128_t(0x401e024669000000) << 64) + - __uint128_t(0x800000000000018))); + (UInt128(0x401e812334) << 40) + UInt128(0x8000000400), + (UInt128(0x401e024669000000) << 64) + + UInt128(0x800000000000018))); run_test("27949676547093071875", 20, SELECT_CONST(uint64_t(0x43f83e132bc608c9), - (__uint128_t(0x403fc1f099) << 40) + - __uint128_t(0x5e30464402), - (__uint128_t(0x403f83e132bc608c) << 64) + - __uint128_t(0x8803000000000000))); + (UInt128(0x403fc1f099) << 40) + UInt128(0x5e30464402), + (UInt128(0x403f83e132bc608c) << 64) + + UInt128(0x8803000000000000))); } TEST_F(LlvmLibcStrToLDTest, MaxSizeNumbers) { run_test("1.1897314953572317650e4932", 26, SELECT_CONST(uint64_t(0x7FF0000000000000), - (__uint128_t(0x7ffeffffff) << 40) + - __uint128_t(0xffffffffff), - (__uint128_t(0x7ffeffffffffffff) << 64) + - __uint128_t(0xfffd57322e3f8675)), + (UInt128(0x7ffeffffff) << 40) + UInt128(0xffffffffff), + (UInt128(0x7ffeffffffffffff) << 64) + + UInt128(0xfffd57322e3f8675)), SELECT_CONST(ERANGE, 0, 0)); run_test("1.18973149535723176508e4932", 27, SELECT_CONST(uint64_t(0x7FF0000000000000), - (__uint128_t(0x7fff800000) << 40), - (__uint128_t(0x7ffeffffffffffff) << 64) + - __uint128_t(0xffffd2478338036c)), + (UInt128(0x7fff800000) << 40), + (UInt128(0x7ffeffffffffffff) << 64) + + UInt128(0xffffd2478338036c)), SELECT_CONST(ERANGE, ERANGE, 0)); } @@ -171,94 +166,86 @@ // be too small for 64 bit floats. TEST_F(LlvmLibcStrToLDTest, SubnormalTests) { run_test("1e-4950", 7, - SELECT_CONST(uint64_t(0), (__uint128_t(0x00000000000000000003)), - (__uint128_t(0x000000000000000000057c9647e1a018))), + SELECT_CONST(uint64_t(0), (UInt128(0x00000000000000000003)), + (UInt128(0x000000000000000000057c9647e1a018))), ERANGE); run_test("1.89e-4951", 10, - SELECT_CONST(uint64_t(0), (__uint128_t(0x00000000000000000001)), - (__uint128_t(0x0000000000000000000109778a006738))), + SELECT_CONST(uint64_t(0), (UInt128(0x00000000000000000001)), + (UInt128(0x0000000000000000000109778a006738))), ERANGE); run_test("4e-4966", 7, - SELECT_CONST(uint64_t(0), (__uint128_t(0)), - (__uint128_t(0x00000000000000000000000000000001))), + SELECT_CONST(uint64_t(0), (UInt128(0)), + (UInt128(0x00000000000000000000000000000001))), ERANGE); } TEST_F(LlvmLibcStrToLDTest, SmallNormalTests) { - run_test( - "3.37e-4932", 10, - SELECT_CONST(uint64_t(0), - (__uint128_t(0x1804cf7) << 40) + __uint128_t(0x908850712), - (__uint128_t(0x10099ee12110a) << 64) + - __uint128_t(0xe24b75c0f50dc0c)), - SELECT_CONST(ERANGE, 0, 0)); + run_test("3.37e-4932", 10, + SELECT_CONST( + uint64_t(0), (UInt128(0x1804cf7) << 40) + UInt128(0x908850712), + (UInt128(0x10099ee12110a) << 64) + UInt128(0xe24b75c0f50dc0c)), + SELECT_CONST(ERANGE, 0, 0)); } TEST_F(LlvmLibcStrToLDTest, ComplexHexadecimalTests) { run_test("0x1p16383", 9, - SELECT_CONST(0x7ff0000000000000, (__uint128_t(0x7ffe800000) << 40), - (__uint128_t(0x7ffe000000000000) << 64)), + SELECT_CONST(0x7ff0000000000000, (UInt128(0x7ffe800000) << 40), + (UInt128(0x7ffe000000000000) << 64)), SELECT_CONST(ERANGE, 0, 0)); run_test("0x123456789abcdef", 17, SELECT_CONST(0x43723456789abcdf, - (__uint128_t(0x403791a2b3) << 40) + - __uint128_t(0xc4d5e6f780), - (__uint128_t(0x403723456789abcd) << 64) + - __uint128_t(0xef00000000000000))); + (UInt128(0x403791a2b3) << 40) + UInt128(0xc4d5e6f780), + (UInt128(0x403723456789abcd) << 64) + + UInt128(0xef00000000000000))); run_test("0x123456789abcdef0123456789ABCDEF", 33, SELECT_CONST(0x47723456789abcdf, - (__uint128_t(0x407791a2b3) << 40) + - __uint128_t(0xc4d5e6f781), - (__uint128_t(0x407723456789abcd) << 64) + - __uint128_t(0xef0123456789abce))); + (UInt128(0x407791a2b3) << 40) + UInt128(0xc4d5e6f781), + (UInt128(0x407723456789abcd) << 64) + + UInt128(0xef0123456789abce))); } TEST_F(LlvmLibcStrToLDTest, InfTests) { run_test("INF", 3, - SELECT_CONST(0x7ff0000000000000, (__uint128_t(0x7fff800000) << 40), - (__uint128_t(0x7fff000000000000) << 64))); + SELECT_CONST(0x7ff0000000000000, (UInt128(0x7fff800000) << 40), + (UInt128(0x7fff000000000000) << 64))); run_test("INFinity", 8, - SELECT_CONST(0x7ff0000000000000, (__uint128_t(0x7fff800000) << 40), - (__uint128_t(0x7fff000000000000) << 64))); + SELECT_CONST(0x7ff0000000000000, (UInt128(0x7fff800000) << 40), + (UInt128(0x7fff000000000000) << 64))); run_test("-inf", 4, - SELECT_CONST(0xfff0000000000000, (__uint128_t(0xffff800000) << 40), - (__uint128_t(0xffff000000000000) << 64))); + SELECT_CONST(0xfff0000000000000, (UInt128(0xffff800000) << 40), + (UInt128(0xffff000000000000) << 64))); } TEST_F(LlvmLibcStrToLDTest, NaNTests) { run_test("NaN", 3, - SELECT_CONST(0x7ff8000000000000, (__uint128_t(0x7fffc00000) << 40), - (__uint128_t(0x7fff800000000000) << 64))); + SELECT_CONST(0x7ff8000000000000, (UInt128(0x7fffc00000) << 40), + (UInt128(0x7fff800000000000) << 64))); run_test("-nAn", 4, - SELECT_CONST(0xfff8000000000000, (__uint128_t(0xffffc00000) << 40), - (__uint128_t(0xffff800000000000) << 64))); + SELECT_CONST(0xfff8000000000000, (UInt128(0xffffc00000) << 40), + (UInt128(0xffff800000000000) << 64))); run_test("NaN()", 5, - SELECT_CONST(0x7ff8000000000000, (__uint128_t(0x7fffc00000) << 40), - (__uint128_t(0x7fff800000000000) << 64))); + SELECT_CONST(0x7ff8000000000000, (UInt128(0x7fffc00000) << 40), + (UInt128(0x7fff800000000000) << 64))); run_test("NaN(1234)", 9, SELECT_CONST(0x7ff80000000004d2, - (__uint128_t(0x7fffc00000) << 40) + __uint128_t(0x4d2), - (__uint128_t(0x7fff800000000000) << 64) + - __uint128_t(0x4d2))); + (UInt128(0x7fffc00000) << 40) + UInt128(0x4d2), + (UInt128(0x7fff800000000000) << 64) + UInt128(0x4d2))); run_test("NaN(0xffffffffffff)", 19, SELECT_CONST(0x7ff8ffffffffffff, - (__uint128_t(0x7fffc000ff) << 40) + - __uint128_t(0xffffffffff), - (__uint128_t(0x7fff800000000000) << 64) + - __uint128_t(0xffffffffffff))); + (UInt128(0x7fffc000ff) << 40) + UInt128(0xffffffffff), + (UInt128(0x7fff800000000000) << 64) + + UInt128(0xffffffffffff))); run_test("NaN(0xfffffffffffff)", 20, SELECT_CONST(0x7fffffffffffffff, - (__uint128_t(0x7fffc00fff) << 40) + - __uint128_t(0xffffffffff), - (__uint128_t(0x7fff800000000000) << 64) + - __uint128_t(0xfffffffffffff))); + (UInt128(0x7fffc00fff) << 40) + UInt128(0xffffffffff), + (UInt128(0x7fff800000000000) << 64) + + UInt128(0xfffffffffffff))); run_test("NaN(0xffffffffffffffff)", 23, SELECT_CONST(0x7fffffffffffffff, - (__uint128_t(0x7fffffffff) << 40) + - __uint128_t(0xffffffffff), - (__uint128_t(0x7fff800000000000) << 64) + - __uint128_t(0xffffffffffffffff))); + (UInt128(0x7fffffffff) << 40) + UInt128(0xffffffffff), + (UInt128(0x7fff800000000000) << 64) + + UInt128(0xffffffffffffffff))); run_test("NaN( 1234)", 3, - SELECT_CONST(0x7ff8000000000000, (__uint128_t(0x7fffc00000) << 40), - (__uint128_t(0x7fff800000000000) << 64))); + SELECT_CONST(0x7ff8000000000000, (UInt128(0x7fffc00000) << 40), + (UInt128(0x7fff800000000000) << 64))); } diff --git a/libc/utils/UnitTest/CMakeLists.txt b/libc/utils/UnitTest/CMakeLists.txt --- a/libc/utils/UnitTest/CMakeLists.txt +++ b/libc/utils/UnitTest/CMakeLists.txt @@ -5,7 +5,7 @@ LibcTest.h ) target_include_directories(LibcUnitTest PUBLIC ${LIBC_SOURCE_DIR}) -add_dependencies(LibcUnitTest libc.src.__support.CPP.type_traits) +add_dependencies(LibcUnitTest libc.src.__support.CPP.type_traits libc.src.__support.CPP.uint128) target_link_libraries(LibcUnitTest PUBLIC libc_test_utils) add_library( @@ -71,6 +71,7 @@ add_dependencies( LibcPrintfHelpers LibcUnitTest - libc.utils.UnitTest.string_utils + libc.src.__support.CPP.uint128 libc.src.stdio.printf_core.core_structs + libc.utils.UnitTest.string_utils ) diff --git a/libc/utils/UnitTest/LibcTest.cpp b/libc/utils/UnitTest/LibcTest.cpp --- a/libc/utils/UnitTest/LibcTest.cpp +++ b/libc/utils/UnitTest/LibcTest.cpp @@ -8,7 +8,7 @@ #include "LibcTest.h" -#include "src/__support/CPP/UInt.h" +#include "src/__support/CPP/UInt128.h" #include "utils/testutils/ExecuteFunction.h" #include #include @@ -42,11 +42,15 @@ } std::string describeValue(std::string Value) { return std::string(Value); } -#ifdef __SIZEOF_INT128__ -// When the value is __uint128_t, also show its hexadecimal digits. -// Using template to force exact match, prevent ambiguous promotion. -std::string describeValue128(__uint128_t Value) { - std::string S(sizeof(__uint128_t) * 2, '0'); + +// When the value is UInt128 or __uint128_t, show its hexadecimal digits. +// We cannot just use a UInt128 specialization as that resolves to only +// one type, UInt<128> or __uint128_t. We want both overloads as we want to +// be able to unittest UInt<128> on platforms where UInt128 resolves to +// UInt128. +template +std::string describeValue128(UInt128Type Value) { + std::string S(sizeof(UInt128) * 2, '0'); for (auto I = S.rbegin(), End = S.rend(); I != End; ++I, Value >>= 4) { unsigned char Mod = static_cast(Value) & 15; @@ -56,26 +60,16 @@ return "0x" + S; } -template <> std::string describeValue<__int128_t>(__int128_t Value) { - return describeValue128(Value); -} +#ifdef __SIZEOF_INT128__ template <> std::string describeValue<__uint128_t>(__uint128_t Value) { return describeValue128(Value); } #endif -// When the value is UInt<128>, also show its hexadecimal digits. template <> std::string describeValue<__llvm_libc::cpp::UInt<128>>(__llvm_libc::cpp::UInt<128> Value) { - std::string S(sizeof(__llvm_libc::cpp::UInt<128>) * 2, '0'); - - for (auto I = S.rbegin(), End = S.rend(); I != End; ++I, Value = Value >> 4) { - unsigned char Mod = static_cast(Value) & 15; - *I = Mod < 10 ? '0' + Mod : 'a' + Mod - 10; - } - - return "0x" + S; + return describeValue128(Value); } template @@ -234,17 +228,6 @@ const char *RHSStr, const char *File, unsigned long Line); -#ifdef __SIZEOF_INT128__ -template bool test<__int128_t>(RunContext *Ctx, TestCondition Cond, - __int128_t LHS, __int128_t RHS, - const char *LHSStr, const char *RHSStr, - const char *File, unsigned long Line); -#endif -template bool test<__llvm_libc::cpp::UInt<128>>( - RunContext *Ctx, TestCondition Cond, __llvm_libc::cpp::UInt<128> LHS, - __llvm_libc::cpp::UInt<128> RHS, const char *LHSStr, const char *RHSStr, - const char *File, unsigned long Line); - template bool test(RunContext *Ctx, TestCondition Cond, unsigned char LHS, unsigned char RHS, const char *LHSStr, const char *RHSStr, @@ -275,13 +258,24 @@ const char *LHSStr, const char *RHSStr, const char *File, unsigned long Line); +// We cannot just use a single UInt128 specialization as that resolves to only +// one type, UInt<128> or __uint128_t. We want both overloads as we want to +// be able to unittest UInt<128> on platforms where UInt128 resolves to +// UInt128. #ifdef __SIZEOF_INT128__ +// When builtin __uint128_t type is available, include its specialization +// also. template bool test<__uint128_t>(RunContext *Ctx, TestCondition Cond, __uint128_t LHS, __uint128_t RHS, const char *LHSStr, const char *RHSStr, const char *File, unsigned long Line); #endif +template bool test<__llvm_libc::cpp::UInt<128>>( + RunContext *Ctx, TestCondition Cond, __llvm_libc::cpp::UInt<128> LHS, + __llvm_libc::cpp::UInt<128> RHS, const char *LHSStr, const char *RHSStr, + const char *File, unsigned long Line); + } // namespace internal bool Test::testStrEq(const char *LHS, const char *RHS, const char *LHSStr, diff --git a/libc/utils/UnitTest/PrintfMatcher.cpp b/libc/utils/UnitTest/PrintfMatcher.cpp --- a/libc/utils/UnitTest/PrintfMatcher.cpp +++ b/libc/utils/UnitTest/PrintfMatcher.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "PrintfMatcher.h" + +#include "src/__support/CPP/UInt128.h" #include "src/stdio/printf_core/core_structs.h" #include "utils/UnitTest/StringUtils.h" @@ -70,8 +72,7 @@ reinterpret_cast(form.conv_val_ptr)) << "\n"; else if (form.conv_name != '%') - stream << "\tvalue: " << int_to_hex<__uint128_t>(form.conv_val_raw) - << "\n"; + stream << "\tvalue: " << int_to_hex(form.conv_val_raw) << "\n"; } } } // anonymous namespace diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel --- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel @@ -72,7 +72,7 @@ cc_library( name = "__support_cpp_limits", hdrs = ["src/__support/CPP/Limits.h"], - deps = [":libc_root"], + deps = [":libc_root", "__support_cpp_uint"], ) cc_library( @@ -89,6 +89,14 @@ deps = [":libc_root","__support_cpp_array"], ) +cc_library( + name = "__support_cpp_uint128", + hdrs = [ + "src/__support/CPP/UInt128.h", + ], + deps = [":libc_root",":__support_cpp_uint"], +) + cc_library( name = "__support_cpp_type_traits", hdrs = [ @@ -174,6 +182,7 @@ ":__support_common", ":__support_cpp_bit", ":__support_cpp_type_traits", + ":__support_cpp_uint128", ":libc_root", ], ) @@ -201,6 +210,7 @@ ":__support_common", ":__support_cpp_bit", ":__support_cpp_type_traits", + ":__support_cpp_uint128", ":__support_fputil", ":libc_root", ], @@ -226,6 +236,7 @@ ":__support_common", ":__support_cpp_bit", ":__support_cpp_type_traits", + ":__support_cpp_uint128", ":__support_fputil", ":libc_root", ],