diff --git a/libc/src/__support/UInt.h b/libc/src/__support/UInt.h --- a/libc/src/__support/UInt.h +++ b/libc/src/__support/UInt.h @@ -11,7 +11,9 @@ #include "src/__support/CPP/array.h" #include "src/__support/CPP/limits.h" +#include "src/__support/CPP/optional.h" #include "src/__support/CPP/type_traits.h" +#include "src/__support/builtin_wrappers.h" #include // For size_t #include @@ -38,6 +40,32 @@ val[i] = other.val[i]; } + template constexpr UInt(const UInt &other) { + if (OtherBits >= Bits) { + for (size_t i = 0; i < WordCount; ++i) + val[i] = other[i]; + } else { + size_t i = 0; + for (; i < OtherBits / 64; ++i) + val[i] = other[i]; + for (; i < WordCount; ++i) + val[i] = 0; + } + } + + // Construct a UInt from a C array. + template = 0> + constexpr UInt(const uint64_t (&nums)[N]) { + size_t min_wordcount = N < WordCount ? N : WordCount; + size_t i = 0; + for (; i < min_wordcount; ++i) + val[i] = nums[i]; + + // If nums doesn't completely fill val, then fill the rest with zeroes. + for (; i < WordCount; ++i) + val[i] = 0; + } + // Initialize the first word to |v| and the rest to 0. constexpr UInt(uint64_t v) { val[0] = v; @@ -209,6 +237,8 @@ constexpr UInt operator*(const UInt &other) const { UInt result(0); for (size_t i = 0; i < WordCount; ++i) { + if (other[i] == 0) + continue; UInt row_result(*this); row_result.mul(other[i]); row_result.shift_left(64 * i); @@ -217,11 +247,83 @@ return result; } + // pow takes a power and sets this to its starting value to that power. Zero + // to the zeroth power returns 1. + constexpr void pow_n(uint64_t power) { + UInt result = 1; + UInt cur_power = *this; + + while (power > 0) { + if ((power % 2) > 0) { + result = result * cur_power; + } + power = power >> 1; + cur_power *= cur_power; + } + *this = result; + } + + // div takes another UInt of the same size and divides this by it. The value + // of this will be set to the quotient, and the return value is the remainder. + constexpr optional> div(const UInt &other) { + UInt remainder(0); + if (*this < other) { + remainder = *this; + *this = UInt(0); + return remainder; + } + if (other == 1) { + return remainder; + } + if (other == 0) { + return nullopt; + } + + UInt quotient(0); + UInt subtractor = other; + int cur_bit = subtractor.clz() - this->clz(); + subtractor.shift_left(cur_bit); + + for (; cur_bit >= 0 && *this > 0; --cur_bit, subtractor.shift_right(1)) { + if (*this >= subtractor) { + this->sub(subtractor); + quotient = quotient | (UInt(1) << cur_bit); + } + } + remainder = *this; + *this = quotient; + return remainder; + } + + constexpr UInt operator/(const UInt &other) const { + UInt result(*this); + result.div(other); + return result; + } + + constexpr UInt operator%(const UInt &other) const { + UInt result(*this); + return *result.div(other); + } + constexpr UInt &operator*=(const UInt &other) { *this = *this * other; return *this; } + constexpr uint64_t clz() { + uint64_t leading_zeroes = 0; + for (size_t i = WordCount; i > 0; --i) { + if (val[i - 1] == 0) { + leading_zeroes += sizeof(uint64_t) * 8; + } else { + leading_zeroes += unsafe_clz(val[i - 1]); + break; + } + } + return leading_zeroes; + } + constexpr void shift_left(size_t s) { const size_t drop = s / 64; // Number of words to drop const size_t shift = s % 64; // Bits to shift in the remaining words. 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 @@ -71,6 +71,7 @@ uint128_test.cpp DEPENDS libc.src.__support.uint + libc.src.__support.CPP.optional ) add_libc_unittest( 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 @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "src/__support/CPP/optional.h" #include "src/__support/UInt.h" #include "utils/UnitTest/Test.h" @@ -113,6 +114,151 @@ EXPECT_EQ((val9 * val10), (val10 * val9)); } +TEST(LlvmLibcUInt128ClassTest, DivisionTests) { + LL_UInt128 val1({10, 0}); + LL_UInt128 val2({5, 0}); + LL_UInt128 result1({2, 0}); + EXPECT_EQ((val1 / val2), result1); + EXPECT_EQ((val1 / result1), val2); + + // Check that the division works accross the whole number + LL_UInt128 val3({0xffffffffffffffff, 0xffffffffffffffff}); + LL_UInt128 val4({0xf, 0}); + LL_UInt128 result2({0x1111111111111111, 0x1111111111111111}); + EXPECT_EQ((val3 / val4), result2); + EXPECT_EQ((val3 / result2), val4); + + // Check that division doesn't reorder the bits. + LL_UInt128 val5({0x26ae048cea62c840, 0x02468aceeca86420}); + LL_UInt128 val6({2, 0}); + LL_UInt128 result3({0x1357024675316420, 0x0123456776543210}); + EXPECT_EQ((val5 / val6), result3); + EXPECT_EQ((val5 / result3), val6); + + // Make sure that division handles inexact results correctly. + LL_UInt128 val7({1001, 0}); + LL_UInt128 val8({10, 0}); + LL_UInt128 result4({100, 0}); + EXPECT_EQ((val7 / val8), result4); + EXPECT_EQ((val7 / result4), val8); + + // Make sure that division handles divisors of one correctly. + LL_UInt128 val9({0x1234567812345678, 0x9abcdef09abcdef0}); + LL_UInt128 val10({1, 0}); + LL_UInt128 result5({0x1234567812345678, 0x9abcdef09abcdef0}); + EXPECT_EQ((val9 / val10), result5); + EXPECT_EQ((val9 / result5), val10); + + // Make sure that division handles results of slightly more than 1 correctly. + LL_UInt128 val11({1050, 0}); + LL_UInt128 val12({1030, 0}); + LL_UInt128 result6({1, 0}); + EXPECT_EQ((val11 / val12), result6); + + // Make sure that division handles dividing by zero correctly. + LL_UInt128 val13({1234, 0}); + LL_UInt128 val14({0, 0}); + EXPECT_FALSE(val13.div(val14).has_value()); +} + +TEST(LlvmLibcUInt128ClassTest, ModuloTests) { + LL_UInt128 val1({10, 0}); + LL_UInt128 val2({5, 0}); + LL_UInt128 result1({0, 0}); + EXPECT_EQ((val1 % val2), result1); + + LL_UInt128 val3({101, 0}); + LL_UInt128 val4({10, 0}); + LL_UInt128 result2({1, 0}); + EXPECT_EQ((val3 % val4), result2); + + LL_UInt128 val5({10000001, 0}); + LL_UInt128 val6({10, 0}); + LL_UInt128 result3({1, 0}); + EXPECT_EQ((val5 % val6), result3); + + LL_UInt128 val7({12345, 10}); + LL_UInt128 val8({0, 1}); + LL_UInt128 result4({12345, 0}); + EXPECT_EQ((val7 % val8), result4); + + LL_UInt128 val9({12345, 10}); + LL_UInt128 val10({0, 11}); + LL_UInt128 result5({12345, 10}); + EXPECT_EQ((val9 % val10), result5); + + LL_UInt128 val11({10, 10}); + LL_UInt128 val12({10, 10}); + LL_UInt128 result6({0, 0}); + EXPECT_EQ((val11 % val12), result6); + + LL_UInt128 val13({12345, 0}); + LL_UInt128 val14({1, 0}); + LL_UInt128 result7({0, 0}); + EXPECT_EQ((val13 % val14), result7); + + LL_UInt128 val15({0xffffffffffffffff, 0xffffffffffffffff}); + LL_UInt128 val16({0x1111111111111111, 0x111111111111111}); + LL_UInt128 result8({0xf, 0}); + EXPECT_EQ((val15 % val16), result8); + + LL_UInt128 val17({5076944270305263619, 54210108624}); // (10 ^ 30) + 3 + LL_UInt128 val18({10, 0}); + LL_UInt128 result9({3, 0}); + EXPECT_EQ((val17 % val18), result9); +} + +TEST(LlvmLibcUInt128ClassTest, PowerTests) { + LL_UInt128 val1({10, 0}); + val1.pow_n(30); + LL_UInt128 result1({5076944270305263616, 54210108624}); // (10 ^ 30) + EXPECT_EQ(val1, result1); + + LL_UInt128 val2({1, 0}); + val2.pow_n(10); + LL_UInt128 result2({1, 0}); + EXPECT_EQ(val2, result2); + + LL_UInt128 val3({0, 0}); + val3.pow_n(10); + LL_UInt128 result3({0, 0}); + EXPECT_EQ(val3, result3); + + LL_UInt128 val4({10, 0}); + val4.pow_n(0); + LL_UInt128 result4({1, 0}); + EXPECT_EQ(val4, result4); + + // Test zero to the zero. Currently it returns 1, since that's the easiest + // result. + LL_UInt128 val5({0, 0}); + val5.pow_n(0); + LL_UInt128 result5({1, 0}); + EXPECT_EQ(val5, result5); + + // Test a number that overflows. 100 ^ 20 is larger than 2 ^ 128. + LL_UInt128 val6({100, 0}); + val6.pow_n(20); + LL_UInt128 result6({0xb9f5610000000000, 0x6329f1c35ca4bfab}); + EXPECT_EQ(val6, result6); + + // Test that both halves of the number are being used. + LL_UInt128 val7({1, 1}); + val7.pow_n(2); + LL_UInt128 result7({1, 2}); + EXPECT_EQ(val7, result7); + + LL_UInt128 val_pow_two; + LL_UInt128 result_pow_two; + for (size_t i = 0; i < 128; ++i) { + val_pow_two = 2; + val_pow_two.pow_n(i); + result_pow_two = 1; + result_pow_two = result_pow_two << i; + EXPECT_EQ(val_pow_two, result_pow_two); + } +} + TEST(LlvmLibcUInt128ClassTest, ShiftLeftTests) { LL_UInt128 val1(0x0123456789abcdef); LL_UInt128 result1(0x123456789abcdef0); 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 @@ -124,6 +124,8 @@ "__support_cpp_array", "__support_cpp_limits", "__support_cpp_type_traits", + "__support_cpp_optional", + "__support_builtin_wrappers", ":libc_root", ], )