diff --git a/libc/src/__support/CPP/UInt.h b/libc/src/__support/CPP/UInt.h --- a/libc/src/__support/CPP/UInt.h +++ b/libc/src/__support/CPP/UInt.h @@ -10,6 +10,7 @@ #define LLVM_LIBC_UTILS_CPP_UINT_H #include "array.h" +#include "optional.h" #include // For size_t #include @@ -37,6 +38,31 @@ 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 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; @@ -205,6 +231,31 @@ return r1[WordCount]; } + // This multiplication is between two arbitrary length numbers, and as such + // cannot easily evaluate its overflow, so it returns true if it has any + // overflow, and relies on the client to use this information. + constexpr bool mul(const UInt &other) { + UInt result(0); + bool overflow = false; + for (size_t i = 0; i < WordCount; ++i) { + UInt row_result(*this); + overflow = overflow || (row_result.mul(other[i]) > 0); + for (size_t j = WordCount - i; !overflow && j < WordCount; ++j) { + if (row_result[j] > 0) { + overflow = true; + } + } + row_result.shift_left(64 * i); + UInt sum = result + row_result; + if (sum < result) { + overflow = true; + } + result = sum; + } + *this = result; + return overflow; + } + constexpr UInt operator*(const UInt &other) const { UInt result(0); for (size_t i = 0; i < WordCount; ++i) { @@ -216,11 +267,86 @@ return result; } + constexpr void exp(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 * 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 == UInt(1)) { + return remainder; + } + if (other == UInt(0)) { + return optional>(); + } + + UInt quotient(0); + UInt subtractor = other; + int cur_bit = subtractor.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 { + // TODO(michaelrj): use builtins? + uint64_t num = val[i - 1]; + while (num < (uint64_t(1) << ((sizeof(uint64_t) * 8) - 1))) { + num <<= 1; + ++leading_zeroes; + } + 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/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 @@ -113,6 +113,51 @@ 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); +} + +// TODO: Modulo tests +// TODO: Exponent tests + TEST(LlvmLibcUInt128ClassTest, ShiftLeftTests) { LL_UInt128 val1(0x0123456789abcdef); LL_UInt128 result1(0x123456789abcdef0);