Skip to content

[libc] Fix forward missing BigInt specialization of mask_leading_ones / mask_trailing_ones #84325

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions libc/src/__support/UInt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename T, size_t count>
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_big_int_v<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<int>(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<word_type, count % T::WORD_SIZE>();
++index;
}
return out;
}

// Specialization of mask_leading_ones ('math_extras.h') for BigInt.
template <typename T, size_t count>
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_big_int_v<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<int>((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<word_type, count % T::WORD_SIZE>();
++index;
}
return out;
}

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC___SUPPORT_UINT_H
13 changes: 5 additions & 8 deletions libc/src/__support/math_extras.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename T, size_t count>
LIBC_INLINE constexpr T mask_trailing_ones() {
static_assert(cpp::is_unsigned_v<T>);
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<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 <typename T, size_t count>
LIBC_INLINE constexpr T mask_leading_ones() {
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T>
mask_leading_ones() {
constexpr T MASK(mask_trailing_ones<T, CHAR_BIT * sizeof(T) - count>());
return T(~MASK); // bitwise NOT performs integer promotion.
}
Expand Down
7 changes: 5 additions & 2 deletions libc/src/stdio/printf_core/float_dec_converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -33,7 +34,8 @@ using ExponentString =

// Returns true if value is divisible by 2^p.
template <typename T>
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_integral_v<T>, bool>
LIBC_INLINE constexpr cpp::enable_if_t<
cpp::is_integral_v<T> || cpp::is_big_int_v<T>, bool>
multiple_of_power_of_2(T value, uint32_t p) {
return (value & ((T(1) << p) - 1)) == 0;
}
Expand Down Expand Up @@ -76,7 +78,8 @@ LIBC_INLINE RoundDirection get_round_direction(int last_digit, bool truncated,
}

template <typename T>
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_integral_v<T>, bool>
LIBC_INLINE constexpr cpp::enable_if_t<
cpp::is_integral_v<T> || cpp::is_big_int_v<T>, 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;
Expand Down
1 change: 1 addition & 0 deletions libc/test/UnitTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
3 changes: 2 additions & 1 deletion libc/test/UnitTest/StringUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename T>
cpp::enable_if_t<cpp::is_integral_v<T>, cpp::string>
cpp::enable_if_t<cpp::is_integral_v<T> || cpp::is_big_int_v<T>, cpp::string>
int_to_hex(T value, size_t length = sizeof(T) * 2) {
cpp::string s(length, '0');

Expand Down
2 changes: 2 additions & 0 deletions libc/test/src/__support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
69 changes: 47 additions & 22 deletions libc/test/src/__support/math_extras_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t, 0>()));
EXPECT_EQ(uint8_t(0), (mask_trailing_ones<uint8_t, 0>()));
EXPECT_EQ(uint16_t(0), (mask_leading_ones<uint16_t, 0>()));
EXPECT_EQ(uint16_t(0), (mask_trailing_ones<uint16_t, 0>()));
EXPECT_EQ(uint32_t(0), (mask_leading_ones<uint32_t, 0>()));
EXPECT_EQ(uint32_t(0), (mask_trailing_ones<uint32_t, 0>()));
EXPECT_EQ(uint64_t(0), (mask_leading_ones<uint64_t, 0>()));
EXPECT_EQ(uint64_t(0), (mask_trailing_ones<uint64_t, 0>()));

EXPECT_EQ(uint32_t(0x00000003), (mask_trailing_ones<uint32_t, 2>()));
EXPECT_EQ(uint32_t(0xC0000000), (mask_leading_ones<uint32_t, 2>()));

EXPECT_EQ(uint32_t(0x000007FF), (mask_trailing_ones<uint32_t, 11>()));
EXPECT_EQ(uint32_t(0xFFE00000), (mask_leading_ones<uint32_t, 11>()));

EXPECT_EQ(uint32_t(0xFFFFFFFF), (mask_trailing_ones<uint32_t, 32>()));
EXPECT_EQ(uint32_t(0xFFFFFFFF), (mask_leading_ones<uint32_t, 32>()));
EXPECT_EQ(uint64_t(0xFFFFFFFFFFFFFFFF), (mask_trailing_ones<uint64_t, 64>()));
EXPECT_EQ(uint64_t(0xFFFFFFFFFFFFFFFF), (mask_leading_ones<uint64_t, 64>()));

EXPECT_EQ(uint64_t(0x0000FFFFFFFFFFFF), (mask_trailing_ones<uint64_t, 48>()));
EXPECT_EQ(uint64_t(0xFFFFFFFFFFFF0000), (mask_leading_ones<uint64_t, 48>()));
EXPECT_EQ(0_u8, (mask_leading_ones<uint8_t, 0>()));
EXPECT_EQ(0_u8, (mask_trailing_ones<uint8_t, 0>()));
EXPECT_EQ(0_u16, (mask_leading_ones<uint16_t, 0>()));
EXPECT_EQ(0_u16, (mask_trailing_ones<uint16_t, 0>()));
EXPECT_EQ(0_u32, (mask_leading_ones<uint32_t, 0>()));
EXPECT_EQ(0_u32, (mask_trailing_ones<uint32_t, 0>()));
EXPECT_EQ(0_u64, (mask_leading_ones<uint64_t, 0>()));
EXPECT_EQ(0_u64, (mask_trailing_ones<uint64_t, 0>()));

EXPECT_EQ(0x00000003_u32, (mask_trailing_ones<uint32_t, 2>()));
EXPECT_EQ(0xC0000000_u32, (mask_leading_ones<uint32_t, 2>()));

EXPECT_EQ(0x000007FF_u32, (mask_trailing_ones<uint32_t, 11>()));
EXPECT_EQ(0xFFE00000_u32, (mask_leading_ones<uint32_t, 11>()));

EXPECT_EQ(0xFFFFFFFF_u32, (mask_trailing_ones<uint32_t, 32>()));
EXPECT_EQ(0xFFFFFFFF_u32, (mask_leading_ones<uint32_t, 32>()));
EXPECT_EQ(0xFFFFFFFFFFFFFFFF_u64, (mask_trailing_ones<uint64_t, 64>()));
EXPECT_EQ(0xFFFFFFFFFFFFFFFF_u64, (mask_leading_ones<uint64_t, 64>()));

EXPECT_EQ(0x0000FFFFFFFFFFFF_u64, (mask_trailing_ones<uint64_t, 48>()));
EXPECT_EQ(0xFFFFFFFFFFFF0000_u64, (mask_leading_ones<uint64_t, 48>()));

EXPECT_EQ(0_u128, (mask_trailing_ones<UInt128, 0>()));
EXPECT_EQ(0_u128, (mask_leading_ones<UInt128, 0>()));

EXPECT_EQ(0x00000000000000007FFFFFFFFFFFFFFF_u128,
(mask_trailing_ones<UInt128, 63>()));
EXPECT_EQ(0xFFFFFFFFFFFFFFFE0000000000000000_u128,
(mask_leading_ones<UInt128, 63>()));

EXPECT_EQ(0x0000000000000000FFFFFFFFFFFFFFFF_u128,
(mask_trailing_ones<UInt128, 64>()));
EXPECT_EQ(0xFFFFFFFFFFFFFFFF0000000000000000_u128,
(mask_leading_ones<UInt128, 64>()));

EXPECT_EQ(0x0000000000000001FFFFFFFFFFFFFFFF_u128,
(mask_trailing_ones<UInt128, 65>()));
EXPECT_EQ(0xFFFFFFFFFFFFFFFF8000000000000000_u128,
(mask_leading_ones<UInt128, 65>()));

EXPECT_EQ(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_u128,
(mask_trailing_ones<UInt128, 128>()));
EXPECT_EQ(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_u128,
(mask_leading_ones<UInt128, 128>()));
}

} // namespace LIBC_NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down