Skip to content

Commit 71c3f5d

Browse files
authored
[reland][libc] Refactor BigInt (#87613)
This is a reland of #86137 with a fix for platforms / compiler that do not support trivially constructible int128 types.
1 parent cca9115 commit 71c3f5d

File tree

13 files changed

+1014
-762
lines changed

13 files changed

+1014
-762
lines changed

libc/fuzzing/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=fuzzer")
22
add_custom_target(libc-fuzzer)
33

4+
add_subdirectory(__support)
45
# TODO(#85680): Re-enable math fuzzing after headers are sorted out
56
# add_subdirectory(math)
67
add_subdirectory(stdlib)

libc/fuzzing/__support/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
add_libc_fuzzer(
2+
uint_fuzz
3+
SRCS
4+
uint_fuzz.cpp
5+
DEPENDS
6+
libc.src.__support.uint
7+
)

libc/fuzzing/__support/uint_fuzz.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#include "src/__support/CPP/bit.h"
2+
#include "src/__support/UInt.h"
3+
#include "src/string/memory_utils/inline_memcpy.h"
4+
5+
using namespace LIBC_NAMESPACE;
6+
7+
// Helper function when using gdb / lldb to set a breakpoint and inspect values.
8+
template <typename T> void debug_and_trap(const char *msg, T a, T b) {
9+
__builtin_trap();
10+
}
11+
12+
#define DEBUG_AND_TRAP()
13+
14+
#define TEST_BINOP(OP) \
15+
if ((a OP b) != (static_cast<T>(BigInt(a) OP BigInt(b)))) \
16+
debug_and_trap(#OP, a, b);
17+
18+
#define TEST_SHIFTOP(OP) \
19+
if ((a OP b) != (static_cast<T>(BigInt(a) OP b))) \
20+
debug_and_trap(#OP, a, b);
21+
22+
#define TEST_FUNCTION(FUN) \
23+
if (FUN(a) != FUN(BigInt(a))) \
24+
debug_and_trap(#FUN, a, b);
25+
26+
// Test that basic arithmetic operations of BigInt behave like their scalar
27+
// counterparts.
28+
template <typename T, typename BigInt> void run_tests(T a, T b) {
29+
TEST_BINOP(+)
30+
TEST_BINOP(-)
31+
TEST_BINOP(*)
32+
if (b != 0)
33+
TEST_BINOP(/)
34+
if (b >= 0 && b < cpp::numeric_limits<T>::digits) {
35+
TEST_SHIFTOP(<<)
36+
TEST_SHIFTOP(>>)
37+
}
38+
if constexpr (!BigInt::SIGNED) {
39+
TEST_FUNCTION(cpp::has_single_bit)
40+
TEST_FUNCTION(cpp::countr_zero)
41+
TEST_FUNCTION(cpp::countl_zero)
42+
TEST_FUNCTION(cpp::countl_one)
43+
TEST_FUNCTION(cpp::countr_one)
44+
}
45+
}
46+
47+
// Reads a T from libfuzzer data.
48+
template <typename T> T read(const uint8_t *data, size_t &remainder) {
49+
T out = 0;
50+
constexpr size_t T_SIZE = sizeof(T);
51+
const size_t copy_size = remainder < T_SIZE ? remainder : T_SIZE;
52+
inline_memcpy(&out, data, copy_size);
53+
remainder -= copy_size;
54+
return out;
55+
}
56+
57+
template <typename T, typename BigInt>
58+
void run_tests(const uint8_t *data, size_t size) {
59+
const auto a = read<T>(data, size);
60+
const auto b = read<T>(data, size);
61+
run_tests<T, BigInt>(a, b);
62+
}
63+
64+
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
65+
// unsigned
66+
run_tests<uint64_t, BigInt<64, false, uint16_t>>(data, size);
67+
// signed
68+
run_tests<int64_t, BigInt<64, true, uint16_t>>(data, size);
69+
return 0;
70+
}

libc/src/__support/FPUtil/dyadic_float.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ template <size_t Bits> struct DyadicFloat {
5858
// significant bit.
5959
LIBC_INLINE constexpr DyadicFloat &normalize() {
6060
if (!mantissa.is_zero()) {
61-
int shift_length = static_cast<int>(mantissa.clz());
61+
int shift_length = cpp::countl_zero(mantissa);
6262
exponent -= shift_length;
63-
mantissa.shift_left(static_cast<size_t>(shift_length));
63+
mantissa <<= static_cast<size_t>(shift_length);
6464
}
6565
return *this;
6666
}
@@ -233,7 +233,7 @@ LIBC_INLINE constexpr DyadicFloat<Bits> quick_add(DyadicFloat<Bits> a,
233233
result.sign = a.sign;
234234
result.exponent = a.exponent;
235235
result.mantissa = a.mantissa;
236-
if (result.mantissa.add(b.mantissa)) {
236+
if (result.mantissa.add_overflow(b.mantissa)) {
237237
// Mantissa addition overflow.
238238
result.shift_right(1);
239239
result.mantissa.val[DyadicFloat<Bits>::MantissaType::WORD_COUNT - 1] |=

0 commit comments

Comments
 (0)