Skip to content

Commit

Permalink
[libc] Fix forward missing BigInt specialization of `mask_leading_o…
Browse files Browse the repository at this point in the history
…nes` / `mask_trailing_ones` (#84325)

#84299 broke the arm32 build, this patch fixes it forward.
  • Loading branch information
gchatelet committed Mar 7, 2024
1 parent 7fc583c commit c103d57
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 34 deletions.
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

0 comments on commit c103d57

Please sign in to comment.