761 changes: 407 additions & 354 deletions libc/src/__support/UInt.h

Large diffs are not rendered by default.

22 changes: 12 additions & 10 deletions libc/src/__support/float_to_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ LIBC_INLINE constexpr cpp::UInt<MID_INT_SIZE> get_table_positive(int exponent,

num = num + 1;
if (num > MOD_SIZE) {
auto rem = num.div_uint32_times_pow_2(
auto rem = num.div_uint_half_times_pow_2(
EXP10_9, CALC_SHIFT_CONST + (IDX_SIZE > 1 ? IDX_SIZE : 0))
.value();
num = rem;
Expand Down Expand Up @@ -255,8 +255,8 @@ LIBC_INLINE cpp::UInt<MID_INT_SIZE> get_table_positive_df(int exponent,
if (int_num > MOD_SIZE) {
auto rem =
int_num
.div_uint32_times_pow_2(EXP10_9, CALC_SHIFT_CONST +
(IDX_SIZE > 1 ? IDX_SIZE : 0))
.div_uint_half_times_pow_2(
EXP10_9, CALC_SHIFT_CONST + (IDX_SIZE > 1 ? IDX_SIZE : 0))
.value();
int_num = rem;
}
Expand Down Expand Up @@ -318,7 +318,7 @@ LIBC_INLINE cpp::UInt<MID_INT_SIZE> get_table_negative(int exponent, size_t i) {
num = num >> (-shift_amount);
}
if (num > MOD_SIZE) {
auto rem = num.div_uint32_times_pow_2(
auto rem = num.div_uint_half_times_pow_2(
EXP10_9, CALC_SHIFT_CONST + (IDX_SIZE > 1 ? IDX_SIZE : 0))
.value();
num = rem;
Expand Down Expand Up @@ -360,8 +360,8 @@ LIBC_INLINE cpp::UInt<MID_INT_SIZE> get_table_negative_df(int exponent,
if (int_num > MOD_SIZE) {
auto rem =
int_num
.div_uint32_times_pow_2(EXP10_9, CALC_SHIFT_CONST +
(IDX_SIZE > 1 ? IDX_SIZE : 0))
.div_uint_half_times_pow_2(
EXP10_9, CALC_SHIFT_CONST + (IDX_SIZE > 1 ? IDX_SIZE : 0))
.value();
int_num = rem;
}
Expand Down Expand Up @@ -389,7 +389,8 @@ LIBC_INLINE uint32_t mul_shift_mod_1e9(const FPBits::StorageType mantissa,
const int32_t shift_amount) {
cpp::UInt<MID_INT_SIZE + FPBits::STORAGE_LEN> val(large);
val = (val * mantissa) >> shift_amount;
return static_cast<uint32_t>(val.div_uint32_times_pow_2(EXP10_9, 0).value());
return static_cast<uint32_t>(
val.div_uint_half_times_pow_2(static_cast<uint32_t>(EXP10_9), 0).value());
}

} // namespace internal
Expand Down Expand Up @@ -658,7 +659,7 @@ template <> class FloatToString<long double> {

template <size_t Bits>
LIBC_INLINE static constexpr BlockInt grab_digits(cpp::UInt<Bits> &int_num) {
auto wide_result = int_num.div_uint32_times_pow_2(EXP5_9, 9);
auto wide_result = int_num.div_uint_half_times_pow_2(EXP5_9, 9);
// the optional only comes into effect when dividing by 0, which will
// never happen here. Thus, we just assert that it has value.
LIBC_ASSERT(wide_result.has_value());
Expand Down Expand Up @@ -695,7 +696,8 @@ template <> class FloatToString<long double> {

while (float_as_int > 0) {
LIBC_ASSERT(int_block_index < static_cast<int>(BLOCK_BUFFER_LEN));
block_buffer[int_block_index] = grab_digits(float_as_int);
block_buffer[int_block_index] =
grab_digits<FLOAT_AS_INT_WIDTH + EXTRA_INT_WIDTH>(float_as_int);
++int_block_index;
}
block_buffer_valid = int_block_index;
Expand All @@ -718,7 +720,7 @@ template <> class FloatToString<long double> {
size_t positive_int_block_index = 0;
while (above_decimal_point > 0) {
block_buffer[positive_int_block_index] =
grab_digits(above_decimal_point);
grab_digits<EXTRA_INT_WIDTH>(above_decimal_point);
++positive_int_block_index;
}
block_buffer_valid = positive_int_block_index;
Expand Down
46 changes: 24 additions & 22 deletions libc/src/__support/integer_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,28 @@

namespace LIBC_NAMESPACE {

template <typename T> NumberPair<T> full_mul(T a, T b);
template <typename T> NumberPair<T> full_mul(T a, T b) {
NumberPair<T> pa = split(a);
NumberPair<T> pb = split(b);
NumberPair<T> prod;

prod.lo = pa.lo * pb.lo; // exact
prod.hi = pa.hi * pb.hi; // exact
NumberPair<T> lo_hi = split(pa.lo * pb.hi); // exact
NumberPair<T> hi_lo = split(pa.hi * pb.lo); // exact

constexpr size_t HALF_BIT_WIDTH = sizeof(T) * CHAR_BIT / 2;

auto r1 = add_with_carry(prod.lo, lo_hi.lo << HALF_BIT_WIDTH, T(0));
prod.lo = r1.sum;
prod.hi = add_with_carry(prod.hi, lo_hi.hi, r1.carry).sum;

auto r2 = add_with_carry(prod.lo, hi_lo.lo << HALF_BIT_WIDTH, T(0));
prod.lo = r2.sum;
prod.hi = add_with_carry(prod.hi, hi_lo.hi, r2.carry).sum;

return prod;
}

template <>
LIBC_INLINE NumberPair<uint32_t> full_mul<uint32_t>(uint32_t a, uint32_t b) {
Expand All @@ -30,35 +51,16 @@ LIBC_INLINE NumberPair<uint32_t> full_mul<uint32_t>(uint32_t a, uint32_t b) {
return result;
}

#ifdef __SIZEOF_INT128__
template <>
LIBC_INLINE NumberPair<uint64_t> full_mul<uint64_t>(uint64_t a, uint64_t b) {
#ifdef __SIZEOF_INT128__
__uint128_t prod = __uint128_t(a) * __uint128_t(b);
NumberPair<uint64_t> result;
result.lo = uint64_t(prod);
result.hi = uint64_t(prod >> 64);
return result;
#else
NumberPair<uint64_t> pa = split(a);
NumberPair<uint64_t> pb = split(b);
NumberPair<uint64_t> prod;

prod.lo = pa.lo * pb.lo; // exact
prod.hi = pa.hi * pb.hi; // exact
NumberPair<uint64_t> lo_hi = split(pa.lo * pb.hi); // exact
NumberPair<uint64_t> hi_lo = split(pa.hi * pb.lo); // exact

auto r1 = add_with_carry(prod.lo, lo_hi.lo << 32, uint64_t(0));
prod.lo = r1.sum;
prod.hi = add_with_carry(prod.hi, lo_hi.hi, r1.carry).sum;

auto r2 = add_with_carry(prod.lo, hi_lo.lo << 32, uint64_t(0));
prod.lo = r2.sum;
prod.hi = add_with_carry(prod.hi, hi_lo.hi, r2.carry).sum;

return prod;
#endif // __SIZEOF_INT128__
}
#endif // __SIZEOF_INT128__

} // namespace LIBC_NAMESPACE

Expand Down
48 changes: 47 additions & 1 deletion libc/test/src/__support/uint_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ TEST(LlvmLibcUIntClassTest, ConstexprInitTests) {
d <<= e; \
LL_UInt320 q1 = y / d; \
LL_UInt320 r1 = y % d; \
LL_UInt320 r2 = *y.div_uint32_times_pow_2(x, e); \
LL_UInt320 r2 = *y.div_uint_half_times_pow_2(x, e); \
EXPECT_EQ(q1, y); \
EXPECT_EQ(r1, r2); \
} while (0)
Expand Down Expand Up @@ -676,6 +676,52 @@ TEST(LlvmLibcUIntClassTest, ConstructorFromUInt128Tests) {
ASSERT_EQ(LL_UInt192(e + f), LL_UInt192(a + b));
}

TEST(LlvmLibcUIntClassTest, WordTypeUInt128Tests) {
using LL_UInt256_128 = cpp::BigInt<256, false, __uint128_t>;
using LL_UInt128_128 = cpp::BigInt<128, false, __uint128_t>;

LL_UInt256_128 a(1);

ASSERT_EQ(static_cast<int>(a), 1);
a = (a << 128) + 2;
ASSERT_EQ(static_cast<int>(a), 2);
ASSERT_EQ(static_cast<uint64_t>(a), uint64_t(2));
a = (a << 32) + 3;
ASSERT_EQ(static_cast<int>(a), 3);
ASSERT_EQ(static_cast<uint64_t>(a), uint64_t(0x2'0000'0003));
ASSERT_EQ(static_cast<int>(a >> 32), 2);
ASSERT_EQ(static_cast<int>(a >> (128 + 32)), 1);

LL_UInt128_128 b(__uint128_t(1) << 127);
LL_UInt128_128 c(b);
a = b.ful_mul(c);

ASSERT_EQ(static_cast<int>(a >> 254), 1);

LL_UInt256_128 d = LL_UInt256_128(123) << 4;
ASSERT_EQ(static_cast<int>(d), 123 << 4);
LL_UInt256_128 e = a / d;
LL_UInt256_128 f = a % d;
LL_UInt256_128 r = *a.div_uint_half_times_pow_2(123, 4);
EXPECT_TRUE(e == a);
EXPECT_TRUE(f == r);
}

#endif // __SIZEOF_INT128__

TEST(LlvmLibcUIntClassTest, OtherWordTypeTests) {
using LL_UInt96 = cpp::BigInt<96, false, uint32_t>;

LL_UInt96 a(1);

ASSERT_EQ(static_cast<int>(a), 1);
a = (a << 32) + 2;
ASSERT_EQ(static_cast<int>(a), 2);
ASSERT_EQ(static_cast<uint64_t>(a), uint64_t(0x1'0000'0002));
a = (a << 32) + 3;
ASSERT_EQ(static_cast<int>(a), 3);
ASSERT_EQ(static_cast<int>(a >> 32), 2);
ASSERT_EQ(static_cast<int>(a >> 64), 1);
}

} // namespace LIBC_NAMESPACE