diff --git a/libc/src/__support/UInt.h b/libc/src/__support/UInt.h index b3d8f00b9a01a..925de8764715d 100644 --- a/libc/src/__support/UInt.h +++ b/libc/src/__support/UInt.h @@ -1056,4 +1056,60 @@ rotr(T value, int rotate) { } // namespace LIBC_NAMESPACE::cpp +namespace LIBC_NAMESPACE { + +// Specialization of mask_trailing_ones ('math_extras.h') for BigInt. +template +LIBC_INLINE constexpr cpp::enable_if_t, T> +mask_trailing_ones() { + static_assert(!T::SIGNED); + if (count == 0) + return T(); + constexpr unsigned T_BITS = CHAR_BIT * sizeof(T); + static_assert(count <= T_BITS && "Invalid bit index"); + using word_type = typename T::word_type; + T out; + constexpr int CHUNK_INDEX_CONTAINING_BIT = + static_cast(count / T::WORD_SIZE); + int index = 0; + for (auto &word : out.val) { + if (index < CHUNK_INDEX_CONTAINING_BIT) + word = -1; + else if (index > CHUNK_INDEX_CONTAINING_BIT) + word = 0; + else + word = mask_trailing_ones(); + ++index; + } + return out; +} + +// Specialization of mask_leading_ones ('math_extras.h') for BigInt. +template +LIBC_INLINE constexpr cpp::enable_if_t, T> +mask_leading_ones() { + static_assert(!T::SIGNED); + if (count == 0) + return T(); + constexpr unsigned T_BITS = CHAR_BIT * sizeof(T); + static_assert(count <= T_BITS && "Invalid bit index"); + using word_type = typename T::word_type; + T out; + constexpr int CHUNK_INDEX_CONTAINING_BIT = + static_cast((T::BITS - count - 1ULL) / T::WORD_SIZE); + int index = 0; + for (auto &word : out.val) { + if (index < CHUNK_INDEX_CONTAINING_BIT) + word = 0; + else if (index > CHUNK_INDEX_CONTAINING_BIT) + word = -1; + else + word = mask_leading_ones(); + ++index; + } + return out; +} + +} // namespace LIBC_NAMESPACE + #endif // LLVM_LIBC_SRC___SUPPORT_UINT_H diff --git a/libc/src/__support/math_extras.h b/libc/src/__support/math_extras.h index 7a89fbb11b2a9..c6b458ddecdab 100644 --- a/libc/src/__support/math_extras.h +++ b/libc/src/__support/math_extras.h @@ -20,21 +20,18 @@ namespace LIBC_NAMESPACE { // Create a bitmask with the count right-most bits set to 1, and all other bits // set to 0. Only unsigned types are allowed. template -LIBC_INLINE constexpr T mask_trailing_ones() { - static_assert(cpp::is_unsigned_v); +LIBC_INLINE constexpr cpp::enable_if_t, T> +mask_trailing_ones() { constexpr unsigned T_BITS = CHAR_BIT * sizeof(T); static_assert(count <= T_BITS && "Invalid bit index"); - // It's important not to initialize T with -1, since T may be BigInt which - // will take -1 as a uint64_t and only initialize the low 64 bits. - constexpr T ALL_ZEROES(0); - constexpr T ALL_ONES(~ALL_ZEROES); // bitwise NOT performs integer promotion. - return count == 0 ? 0 : (ALL_ONES >> (T_BITS - count)); + return count == 0 ? 0 : (T(-1) >> (T_BITS - count)); } // Create a bitmask with the count left-most bits set to 1, and all other bits // set to 0. Only unsigned types are allowed. template -LIBC_INLINE constexpr T mask_leading_ones() { +LIBC_INLINE constexpr cpp::enable_if_t, T> +mask_leading_ones() { constexpr T MASK(mask_trailing_ones()); return T(~MASK); // bitwise NOT performs integer promotion. } diff --git a/libc/src/stdio/printf_core/float_dec_converter.h b/libc/src/stdio/printf_core/float_dec_converter.h index a6c68329e6602..27d229a3e42cb 100644 --- a/libc/src/stdio/printf_core/float_dec_converter.h +++ b/libc/src/stdio/printf_core/float_dec_converter.h @@ -12,6 +12,7 @@ #include "src/__support/CPP/string_view.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/UInt.h" // cpp::is_big_int_v #include "src/__support/float_to_string.h" #include "src/__support/integer_to_string.h" #include "src/__support/libc_assert.h" @@ -33,7 +34,8 @@ using ExponentString = // Returns true if value is divisible by 2^p. template -LIBC_INLINE constexpr cpp::enable_if_t, bool> +LIBC_INLINE constexpr cpp::enable_if_t< + cpp::is_integral_v || cpp::is_big_int_v, bool> multiple_of_power_of_2(T value, uint32_t p) { return (value & ((T(1) << p) - 1)) == 0; } @@ -76,7 +78,8 @@ LIBC_INLINE RoundDirection get_round_direction(int last_digit, bool truncated, } template -LIBC_INLINE constexpr cpp::enable_if_t, bool> +LIBC_INLINE constexpr cpp::enable_if_t< + cpp::is_integral_v || cpp::is_big_int_v, bool> zero_after_digits(int32_t base_2_exp, int32_t digits_after_point, T mantissa, const int32_t mant_width) { const int32_t required_twos = -base_2_exp - digits_after_point - 1; diff --git a/libc/test/UnitTest/CMakeLists.txt b/libc/test/UnitTest/CMakeLists.txt index 36837c553efce..8a35f1204eb51 100644 --- a/libc/test/UnitTest/CMakeLists.txt +++ b/libc/test/UnitTest/CMakeLists.txt @@ -104,6 +104,7 @@ add_header_library( DEPENDS libc.src.__support.CPP.string libc.src.__support.CPP.type_traits + libc.src.__support.uint ) add_unittest_framework_library( diff --git a/libc/test/UnitTest/StringUtils.h b/libc/test/UnitTest/StringUtils.h index 54cff97ceafb4..1e3ba5715d23d 100644 --- a/libc/test/UnitTest/StringUtils.h +++ b/libc/test/UnitTest/StringUtils.h @@ -11,12 +11,13 @@ #include "src/__support/CPP/string.h" #include "src/__support/CPP/type_traits.h" +#include "src/__support/UInt.h" namespace LIBC_NAMESPACE { // Return the first N hex digits of an integer as a string in upper case. template -cpp::enable_if_t, cpp::string> +cpp::enable_if_t || cpp::is_big_int_v, cpp::string> int_to_hex(T value, size_t length = sizeof(T) * 2) { cpp::string s(length, '0'); diff --git a/libc/test/src/__support/CMakeLists.txt b/libc/test/src/__support/CMakeLists.txt index 8c861b576f9b1..adbacb9728ccd 100644 --- a/libc/test/src/__support/CMakeLists.txt +++ b/libc/test/src/__support/CMakeLists.txt @@ -27,7 +27,9 @@ add_libc_test( SRCS math_extras_test.cpp DEPENDS + libc.src.__support.integer_literals libc.src.__support.math_extras + libc.src.__support.uint128 ) add_libc_test( diff --git a/libc/test/src/__support/math_extras_test.cpp b/libc/test/src/__support/math_extras_test.cpp index e55d995592cc1..ed064363d446b 100644 --- a/libc/test/src/__support/math_extras_test.cpp +++ b/libc/test/src/__support/math_extras_test.cpp @@ -6,34 +6,59 @@ // //===----------------------------------------------------------------------===// +#include "src/__support/UInt128.h" // UInt128 +#include "src/__support/integer_literals.h" #include "src/__support/math_extras.h" #include "test/UnitTest/Test.h" namespace LIBC_NAMESPACE { TEST(LlvmLibcBlockMathExtrasTest, mask_trailing_ones) { - EXPECT_EQ(uint8_t(0), (mask_leading_ones())); - EXPECT_EQ(uint8_t(0), (mask_trailing_ones())); - EXPECT_EQ(uint16_t(0), (mask_leading_ones())); - EXPECT_EQ(uint16_t(0), (mask_trailing_ones())); - EXPECT_EQ(uint32_t(0), (mask_leading_ones())); - EXPECT_EQ(uint32_t(0), (mask_trailing_ones())); - EXPECT_EQ(uint64_t(0), (mask_leading_ones())); - EXPECT_EQ(uint64_t(0), (mask_trailing_ones())); - - EXPECT_EQ(uint32_t(0x00000003), (mask_trailing_ones())); - EXPECT_EQ(uint32_t(0xC0000000), (mask_leading_ones())); - - EXPECT_EQ(uint32_t(0x000007FF), (mask_trailing_ones())); - EXPECT_EQ(uint32_t(0xFFE00000), (mask_leading_ones())); - - EXPECT_EQ(uint32_t(0xFFFFFFFF), (mask_trailing_ones())); - EXPECT_EQ(uint32_t(0xFFFFFFFF), (mask_leading_ones())); - EXPECT_EQ(uint64_t(0xFFFFFFFFFFFFFFFF), (mask_trailing_ones())); - EXPECT_EQ(uint64_t(0xFFFFFFFFFFFFFFFF), (mask_leading_ones())); - - EXPECT_EQ(uint64_t(0x0000FFFFFFFFFFFF), (mask_trailing_ones())); - EXPECT_EQ(uint64_t(0xFFFFFFFFFFFF0000), (mask_leading_ones())); + EXPECT_EQ(0_u8, (mask_leading_ones())); + EXPECT_EQ(0_u8, (mask_trailing_ones())); + EXPECT_EQ(0_u16, (mask_leading_ones())); + EXPECT_EQ(0_u16, (mask_trailing_ones())); + EXPECT_EQ(0_u32, (mask_leading_ones())); + EXPECT_EQ(0_u32, (mask_trailing_ones())); + EXPECT_EQ(0_u64, (mask_leading_ones())); + EXPECT_EQ(0_u64, (mask_trailing_ones())); + + EXPECT_EQ(0x00000003_u32, (mask_trailing_ones())); + EXPECT_EQ(0xC0000000_u32, (mask_leading_ones())); + + EXPECT_EQ(0x000007FF_u32, (mask_trailing_ones())); + EXPECT_EQ(0xFFE00000_u32, (mask_leading_ones())); + + EXPECT_EQ(0xFFFFFFFF_u32, (mask_trailing_ones())); + EXPECT_EQ(0xFFFFFFFF_u32, (mask_leading_ones())); + EXPECT_EQ(0xFFFFFFFFFFFFFFFF_u64, (mask_trailing_ones())); + EXPECT_EQ(0xFFFFFFFFFFFFFFFF_u64, (mask_leading_ones())); + + EXPECT_EQ(0x0000FFFFFFFFFFFF_u64, (mask_trailing_ones())); + EXPECT_EQ(0xFFFFFFFFFFFF0000_u64, (mask_leading_ones())); + + EXPECT_EQ(0_u128, (mask_trailing_ones())); + EXPECT_EQ(0_u128, (mask_leading_ones())); + + EXPECT_EQ(0x00000000000000007FFFFFFFFFFFFFFF_u128, + (mask_trailing_ones())); + EXPECT_EQ(0xFFFFFFFFFFFFFFFE0000000000000000_u128, + (mask_leading_ones())); + + EXPECT_EQ(0x0000000000000000FFFFFFFFFFFFFFFF_u128, + (mask_trailing_ones())); + EXPECT_EQ(0xFFFFFFFFFFFFFFFF0000000000000000_u128, + (mask_leading_ones())); + + EXPECT_EQ(0x0000000000000001FFFFFFFFFFFFFFFF_u128, + (mask_trailing_ones())); + EXPECT_EQ(0xFFFFFFFFFFFFFFFF8000000000000000_u128, + (mask_leading_ones())); + + EXPECT_EQ(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_u128, + (mask_trailing_ones())); + EXPECT_EQ(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_u128, + (mask_leading_ones())); } } // namespace LIBC_NAMESPACE diff --git a/utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel index 8e94a84f586f4..19d4c7869799a 100644 --- a/utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel @@ -13,7 +13,11 @@ licenses(["notice"]) libc_test( name = "math_extras_test", srcs = ["math_extras_test.cpp"], - deps = ["//libc:__support_math_extras"], + deps = [ + "//libc:__support_integer_literals", + "//libc:__support_math_extras", + "//libc:__support_uint128", + ], ) # This test is currently disabled because of an issue in