[libc-commits] [libc] 1557256 - [libc] Add Int<> type and fix (U)Int<128> compatibility issues.
Tue Ly via libc-commits
libc-commits at lists.llvm.org
Tue Jun 13 06:41:02 PDT 2023
Author: Tue Ly
Date: 2023-06-13T09:40:48-04:00
New Revision: 1557256ab02eab80557dbdb37631c7170bf46cfa
URL: https://github.com/llvm/llvm-project/commit/1557256ab02eab80557dbdb37631c7170bf46cfa
DIFF: https://github.com/llvm/llvm-project/commit/1557256ab02eab80557dbdb37631c7170bf46cfa.diff
LOG: [libc] Add Int<> type and fix (U)Int<128> compatibility issues.
Add Int<> and Int128 types to replace the usage of __int128_t in math
functions. Clean up to make sure that (U)Int128 and __(u)int128_t are
interchangeable in the code base.
Reviewed By: sivachandra, mikhail.ramalho
Differential Revision: https://reviews.llvm.org/D152459
Added:
Modified:
libc/src/__support/CMakeLists.txt
libc/src/__support/FPUtil/generic/sqrt.h
libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
libc/src/__support/UInt.h
libc/src/__support/UInt128.h
libc/src/__support/builtin_wrappers.h
libc/src/__support/float_to_string.h
libc/src/__support/integer_to_string.h
libc/src/__support/str_to_float.h
libc/src/math/generic/CMakeLists.txt
libc/src/math/generic/log_range_reduction.h
libc/src/stdio/printf_core/char_converter.h
libc/src/stdio/printf_core/float_dec_converter.h
libc/src/stdio/printf_core/float_hex_converter.h
libc/src/stdio/printf_core/float_inf_nan_converter.h
libc/src/stdio/printf_core/int_converter.h
libc/test/UnitTest/LibcTest.cpp
libc/test/src/__support/uint_test.cpp
utils/bazel/llvm-project-overlay/libc/BUILD.bazel
Removed:
################################################################################
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index 4a7b413697901..02b444905cf1a 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -134,6 +134,7 @@ add_header_library(
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.rounding_mode
+ libc.src.__support.FPUtil.dyadic_float
libc.src.__support.builtin_wrappers
libc.src.__support.common
libc.src.errno.errno
diff --git a/libc/src/__support/FPUtil/generic/sqrt.h b/libc/src/__support/FPUtil/generic/sqrt.h
index 9e9896ed185fe..d2697f8869dfe 100644
--- a/libc/src/__support/FPUtil/generic/sqrt.h
+++ b/libc/src/__support/FPUtil/generic/sqrt.h
@@ -137,7 +137,7 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> sqrt(T x) {
}
// We compute one more iteration in order to round correctly.
- bool lsb = y & 1; // Least significant bit
+ bool lsb = static_cast<bool>(y & 1); // Least significant bit
bool rb = false; // Round bit
r <<= 2;
UIntType tmp = (y << 2) + 1;
diff --git a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
index 3712012d3be8c..3ae79c2dd6cac 100644
--- a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
+++ b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
@@ -101,7 +101,7 @@ LIBC_INLINE long double sqrt(long double x) {
}
// We compute one more iteration in order to round correctly.
- bool lsb = y & 1; // Least significant bit
+ bool lsb = static_cast<bool>(y & 1); // Least significant bit
bool rb = false; // Round bit
r <<= 2;
UIntType tmp = (y << 2) + 1;
diff --git a/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h b/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
index ba2fddb2a6fed..bb03eea38be82 100644
--- a/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
+++ b/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
@@ -130,6 +130,10 @@ template <> struct FPBits<long double> {
return bits & MASK;
}
+ LIBC_INLINE long double get_val() const {
+ return cpp::bit_cast<long double>(bits);
+ }
+
LIBC_INLINE int get_exponent() const {
if (get_unbiased_exponent() == 0)
return int(1) - EXPONENT_BIAS;
diff --git a/libc/src/__support/UInt.h b/libc/src/__support/UInt.h
index d36d8f9a72993..22ee2426fd533 100644
--- a/libc/src/__support/UInt.h
+++ b/libc/src/__support/UInt.h
@@ -23,10 +23,10 @@
namespace __llvm_libc::cpp {
-template <size_t Bits> struct UInt {
+template <size_t Bits, bool Signed> struct BigInt {
static_assert(Bits > 0 && Bits % 64 == 0,
- "Number of bits in UInt should be a multiple of 64.");
+ "Number of bits in BigInt should be a multiple of 64.");
static constexpr size_t WORDCOUNT = Bits / 64;
uint64_t val[WORDCOUNT]{};
@@ -35,11 +35,12 @@ template <size_t Bits> struct UInt {
static constexpr uint64_t low(uint64_t v) { return v & MASK32; }
static constexpr uint64_t high(uint64_t v) { return (v >> 32) & MASK32; }
- constexpr UInt() = default;
+ constexpr BigInt() = default;
- constexpr UInt(const UInt<Bits> &other) = default;
+ constexpr BigInt(const BigInt<Bits, Signed> &other) = default;
- template <size_t OtherBits> constexpr UInt(const UInt<OtherBits> &other) {
+ template <size_t OtherBits, bool OtherSigned>
+ constexpr BigInt(const BigInt<OtherBits, OtherSigned> &other) {
if (OtherBits >= Bits) {
for (size_t i = 0; i < WORDCOUNT; ++i)
val[i] = other[i];
@@ -47,14 +48,19 @@ template <size_t Bits> struct UInt {
size_t i = 0;
for (; i < OtherBits / 64; ++i)
val[i] = other[i];
+ uint64_t sign = 0;
+ if constexpr (Signed && OtherSigned) {
+ sign = static_cast<uint64_t>(
+ -static_cast<int64_t>(other[OtherBits / 64 - 1] >> 63));
+ }
for (; i < WORDCOUNT; ++i)
- val[i] = 0;
+ val[i] = sign;
}
}
- // Construct a UInt from a C array.
+ // Construct a BigInt from a C array.
template <size_t N, enable_if_t<N <= WORDCOUNT, int> = 0>
- constexpr UInt(const uint64_t (&nums)[N]) {
+ constexpr BigInt(const uint64_t (&nums)[N]) {
size_t min_wordcount = N < WORDCOUNT ? N : WORDCOUNT;
size_t i = 0;
for (; i < min_wordcount; ++i)
@@ -66,40 +72,57 @@ template <size_t Bits> struct UInt {
}
// Initialize the first word to |v| and the rest to 0.
- constexpr UInt(uint64_t v) {
- val[0] = v;
- for (size_t i = 1; i < WORDCOUNT; ++i) {
- val[i] = 0;
+ template <typename T,
+ typename = cpp::enable_if_t<is_integral_v<T> && sizeof(T) <= 16>>
+ constexpr BigInt(T v) {
+ val[0] = static_cast<uint64_t>(v);
+
+ if constexpr (Bits == 64)
+ return;
+
+ // Bits is at least 128.
+ size_t i = 1;
+ if constexpr (sizeof(T) == 16) {
+ val[1] = static_cast<uint64_t>(v >> 64);
+ i = 2;
}
- }
- constexpr explicit UInt(const cpp::array<uint64_t, WORDCOUNT> &words) {
- for (size_t i = 0; i < WORDCOUNT; ++i)
- val[i] = words[i];
- }
- constexpr explicit operator unsigned long long() const {
- return static_cast<unsigned long long>(val[0]);
+ uint64_t sign = (Signed && (v < 0)) ? 0xffff'ffff'ffff'ffff : 0;
+ for (; i < WORDCOUNT; ++i) {
+ val[i] = sign;
+ }
}
- constexpr explicit operator unsigned long() const {
- return static_cast<unsigned long>(val[0]);
+ constexpr explicit BigInt(const cpp::array<uint64_t, WORDCOUNT> &words) {
+ for (size_t i = 0; i < WORDCOUNT; ++i)
+ val[i] = words[i];
}
- constexpr explicit operator unsigned int() const {
- return static_cast<unsigned int>(val[0]);
- }
+ template <typename T, typename = cpp::enable_if_t<cpp::is_integral_v<T> &&
+ sizeof(T) <= 16 &&
+ !cpp::is_same_v<T, bool>>>
+ constexpr explicit operator T() const {
+ if constexpr (sizeof(T) <= 8)
+ return static_cast<T>(val[0]);
- constexpr explicit operator unsigned short() const {
- return static_cast<unsigned short>(val[0]);
- }
+ // T is 128-bit.
+ T lo = static_cast<T>(val[0]);
- constexpr explicit operator unsigned char() const {
- return static_cast<unsigned char>(val[0]);
+ if constexpr (Bits == 64) {
+ if constexpr (Signed) {
+ // Extend sign for negative numbers.
+ return (val[0] >> 63) ? ((T(-1) << 64) + lo) : lo;
+ } else {
+ return lo;
+ }
+ } else {
+ return (static_cast<T>(val[1]) << 64) + lo;
+ }
}
constexpr explicit operator bool() const { return !is_zero(); }
- UInt<Bits> &operator=(const UInt<Bits> &other) = default;
+ BigInt<Bits, Signed> &operator=(const BigInt<Bits, Signed> &other) = default;
constexpr bool is_zero() const {
for (size_t i = 0; i < WORDCOUNT; ++i) {
@@ -111,7 +134,7 @@ template <size_t Bits> struct UInt {
// Add x to this number and store the result in this number.
// Returns the carry value produced by the addition operation.
- constexpr uint64_t add(const UInt<Bits> &x) {
+ constexpr uint64_t add(const BigInt<Bits, Signed> &x) {
SumCarry<uint64_t> s{0, 0};
for (size_t i = 0; i < WORDCOUNT; ++i) {
s = add_with_carry(val[i], x.val[i], s.carry);
@@ -120,8 +143,8 @@ template <size_t Bits> struct UInt {
return s.carry;
}
- UInt<Bits> operator+(const UInt<Bits> &other) const {
- UInt<Bits> result;
+ BigInt<Bits, Signed> operator+(const BigInt<Bits, Signed> &other) const {
+ BigInt<Bits, Signed> result;
SumCarry<uint64_t> s{0, 0};
for (size_t i = 0; i < WORDCOUNT; ++i) {
s = add_with_carry(val[i], other.val[i], s.carry);
@@ -132,8 +155,8 @@ template <size_t Bits> struct UInt {
// This will only apply when initializing a variable from constant values, so
// it will always use the constexpr version of add_with_carry.
- constexpr UInt<Bits> operator+(UInt<Bits> &&other) const {
- UInt<Bits> result;
+ constexpr BigInt<Bits, Signed> operator+(BigInt<Bits, Signed> &&other) const {
+ BigInt<Bits, Signed> result;
SumCarry<uint64_t> s{0, 0};
for (size_t i = 0; i < WORDCOUNT; ++i) {
s = add_with_carry_const(val[i], other.val[i], s.carry);
@@ -142,14 +165,15 @@ template <size_t Bits> struct UInt {
return result;
}
- constexpr UInt<Bits> &operator+=(const UInt<Bits> &other) {
+ constexpr BigInt<Bits, Signed> &
+ operator+=(const BigInt<Bits, Signed> &other) {
add(other); // Returned carry value is ignored.
return *this;
}
// Subtract x to this number and store the result in this number.
// Returns the carry value produced by the subtraction operation.
- constexpr uint64_t sub(const UInt<Bits> &x) {
+ constexpr uint64_t sub(const BigInt<Bits, Signed> &x) {
DiffBorrow<uint64_t> d{0, 0};
for (size_t i = 0; i < WORDCOUNT; ++i) {
d = sub_with_borrow(val[i], x.val[i], d.borrow);
@@ -158,8 +182,8 @@ template <size_t Bits> struct UInt {
return d.borrow;
}
- UInt<Bits> operator-(const UInt<Bits> &other) const {
- UInt<Bits> result;
+ BigInt<Bits, Signed> operator-(const BigInt<Bits, Signed> &other) const {
+ BigInt<Bits, Signed> result;
DiffBorrow<uint64_t> d{0, 0};
for (size_t i = 0; i < WORDCOUNT; ++i) {
d = sub_with_borrow(val[i], other.val[i], d.borrow);
@@ -168,8 +192,8 @@ template <size_t Bits> struct UInt {
return result;
}
- constexpr UInt<Bits> operator-(UInt<Bits> &&other) const {
- UInt<Bits> result;
+ constexpr BigInt<Bits, Signed> operator-(BigInt<Bits, Signed> &&other) const {
+ BigInt<Bits, Signed> result;
DiffBorrow<uint64_t> d{0, 0};
for (size_t i = 0; i < WORDCOUNT; ++i) {
d = sub_with_borrow_const(val[i], other.val[i], d.borrow);
@@ -178,7 +202,8 @@ template <size_t Bits> struct UInt {
return result;
}
- constexpr UInt<Bits> &operator-=(const UInt<Bits> &other) {
+ constexpr BigInt<Bits, Signed> &
+ operator-=(const BigInt<Bits, Signed> &other) {
// TODO(lntue): Set overflow flag / errno when carry is true.
sub(other);
return *this;
@@ -191,11 +216,11 @@ template <size_t Bits> struct UInt {
// carry bits.
// Returns the carry value produced by the multiplication operation.
constexpr uint64_t mul(uint64_t x) {
- UInt<128> partial_sum(0);
+ BigInt<128, Signed> partial_sum(0);
uint64_t carry = 0;
for (size_t i = 0; i < WORDCOUNT; ++i) {
NumberPair<uint64_t> prod = full_mul(val[i], x);
- UInt<128> tmp({prod.lo, prod.hi});
+ BigInt<128, Signed> tmp({prod.lo, prod.hi});
carry += partial_sum.add(tmp);
val[i] = partial_sum.val[0];
partial_sum.val[0] = partial_sum.val[1];
@@ -205,42 +230,60 @@ template <size_t Bits> struct UInt {
return partial_sum.val[1];
}
- constexpr UInt<Bits> operator*(const UInt<Bits> &other) const {
- if constexpr (WORDCOUNT == 1) {
- return {val[0] * other.val[0]};
+ constexpr BigInt<Bits, Signed>
+ operator*(const BigInt<Bits, Signed> &other) const {
+ if constexpr (Signed) {
+ BigInt<Bits, false> a(*this);
+ BigInt<Bits, false> b(other);
+ bool a_neg = (a.val[WORDCOUNT - 1] >> 63);
+ bool b_neg = (b.val[WORDCOUNT - 1] >> 63);
+ if (a_neg)
+ a = -a;
+ if (b_neg)
+ b = -b;
+ BigInt<Bits, false> prod = a * b;
+ if (a_neg != b_neg)
+ prod = -prod;
+ return static_cast<BigInt<Bits, true>>(prod);
} else {
- UInt<Bits> result(0);
- UInt<128> partial_sum(0);
- uint64_t carry = 0;
- for (size_t i = 0; i < WORDCOUNT; ++i) {
- for (size_t j = 0; j <= i; j++) {
- NumberPair<uint64_t> prod = full_mul(val[j], other.val[i - j]);
- UInt<128> tmp({prod.lo, prod.hi});
- carry += partial_sum.add(tmp);
+
+ if constexpr (WORDCOUNT == 1) {
+ return {val[0] * other.val[0]};
+ } else {
+ BigInt<Bits, Signed> result(0);
+ BigInt<128, Signed> partial_sum(0);
+ uint64_t carry = 0;
+ for (size_t i = 0; i < WORDCOUNT; ++i) {
+ for (size_t j = 0; j <= i; j++) {
+ NumberPair<uint64_t> prod = full_mul(val[j], other.val[i - j]);
+ BigInt<128, Signed> tmp({prod.lo, prod.hi});
+ carry += partial_sum.add(tmp);
+ }
+ result.val[i] = partial_sum.val[0];
+ partial_sum.val[0] = partial_sum.val[1];
+ partial_sum.val[1] = carry;
+ carry = 0;
}
- result.val[i] = partial_sum.val[0];
- partial_sum.val[0] = partial_sum.val[1];
- partial_sum.val[1] = carry;
- carry = 0;
+ return result;
}
- return result;
}
}
- // Return the full product.
+ // Return the full product, only unsigned for now.
template <size_t OtherBits>
- constexpr UInt<Bits + OtherBits> ful_mul(const UInt<OtherBits> &other) const {
- UInt<Bits + OtherBits> result(0);
- UInt<128> partial_sum(0);
+ constexpr BigInt<Bits + OtherBits, Signed>
+ ful_mul(const BigInt<OtherBits, Signed> &other) const {
+ BigInt<Bits + OtherBits, Signed> result(0);
+ BigInt<128, Signed> partial_sum(0);
uint64_t carry = 0;
- constexpr size_t OTHER_WORDCOUNT = UInt<OtherBits>::WORDCOUNT;
+ constexpr size_t OTHER_WORDCOUNT = BigInt<OtherBits, Signed>::WORDCOUNT;
for (size_t i = 0; i <= WORDCOUNT + OTHER_WORDCOUNT - 2; ++i) {
const size_t lower_idx =
i < OTHER_WORDCOUNT ? 0 : i - OTHER_WORDCOUNT + 1;
const size_t upper_idx = i < WORDCOUNT ? i : WORDCOUNT - 1;
for (size_t j = lower_idx; j <= upper_idx; ++j) {
NumberPair<uint64_t> prod = full_mul(val[j], other.val[i - j]);
- UInt<128> tmp({prod.lo, prod.hi});
+ BigInt<128, Signed> tmp({prod.lo, prod.hi});
carry += partial_sum.add(tmp);
}
result.val[i] = partial_sum.val[0];
@@ -273,16 +316,17 @@ template <size_t Bits> struct UInt {
// 196 3 9 6 2
// 256 4 16 10 3
// 512 8 64 36 7
- constexpr UInt<Bits> quick_mul_hi(const UInt<Bits> &other) const {
- UInt<Bits> result(0);
- UInt<128> partial_sum(0);
+ constexpr BigInt<Bits, Signed>
+ quick_mul_hi(const BigInt<Bits, Signed> &other) const {
+ BigInt<Bits, Signed> result(0);
+ BigInt<128, Signed> partial_sum(0);
uint64_t carry = 0;
// First round of accumulation for those at WORDCOUNT - 1 in the full
// product.
for (size_t i = 0; i < WORDCOUNT; ++i) {
NumberPair<uint64_t> prod =
full_mul(val[i], other.val[WORDCOUNT - 1 - i]);
- UInt<128> tmp({prod.lo, prod.hi});
+ BigInt<128, Signed> tmp({prod.lo, prod.hi});
carry += partial_sum.add(tmp);
}
for (size_t i = WORDCOUNT; i < 2 * WORDCOUNT - 1; ++i) {
@@ -291,7 +335,7 @@ template <size_t Bits> struct UInt {
carry = 0;
for (size_t j = i - WORDCOUNT + 1; j < WORDCOUNT; ++j) {
NumberPair<uint64_t> prod = full_mul(val[j], other.val[i - j]);
- UInt<128> tmp({prod.lo, prod.hi});
+ BigInt<128, Signed> tmp({prod.lo, prod.hi});
carry += partial_sum.add(tmp);
}
result.val[i - WORDCOUNT] = partial_sum.val[0];
@@ -303,8 +347,8 @@ template <size_t Bits> struct UInt {
// 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<Bits> result = 1;
- UInt<Bits> cur_power = *this;
+ BigInt<Bits, Signed> result = 1;
+ BigInt<Bits, Signed> cur_power = *this;
while (power > 0) {
if ((power % 2) > 0) {
@@ -316,13 +360,16 @@ template <size_t Bits> struct UInt {
*this = result;
}
- // div takes another UInt of the same size and divides this by it. The value
+ // TODO: Make division work correctly for signed integers.
+
+ // div takes another BigInt 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<UInt<Bits>> div(const UInt<Bits> &other) {
- UInt<Bits> remainder(0);
+ constexpr optional<BigInt<Bits, Signed>>
+ div(const BigInt<Bits, Signed> &other) {
+ BigInt<Bits, Signed> remainder(0);
if (*this < other) {
remainder = *this;
- *this = UInt<Bits>(0);
+ *this = BigInt<Bits, Signed>(0);
return remainder;
}
if (other == 1) {
@@ -332,15 +379,15 @@ template <size_t Bits> struct UInt {
return nullopt;
}
- UInt<Bits> quotient(0);
- UInt<Bits> subtractor = other;
+ BigInt<Bits, Signed> quotient(0);
+ BigInt<Bits, Signed> 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<Bits>(1) << cur_bit);
+ quotient = quotient | (BigInt<Bits, Signed>(1) << cur_bit);
}
}
remainder = *this;
@@ -348,9 +395,8 @@ template <size_t Bits> struct UInt {
return remainder;
}
- // Efficiently perform UInt / (x * 2^e), where x is a 32-bit unsigned integer,
- // and return the remainder.
- // The main idea is as follow:
+ // Efficiently perform BigInt / (x * 2^e), where x is a 32-bit unsigned
+ // integer, and return the remainder. The main idea is as follow:
// Let q = y / (x * 2^e) be the quotient, and
// r = y % (x * 2^e) be the remainder.
// First, notice that:
@@ -361,19 +407,20 @@ template <size_t Bits> struct UInt {
// Since the remainder of each division step < x < 2^32, the computation of
// each step is now properly contained within uint64_t.
// And finally we perform some extra alignment steps for the remaining bits.
- constexpr optional<UInt<Bits>> div_uint32_times_pow_2(uint32_t x, size_t e) {
- UInt<Bits> remainder(0);
+ constexpr optional<BigInt<Bits, Signed>> div_uint32_times_pow_2(uint32_t x,
+ size_t e) {
+ BigInt<Bits, Signed> remainder(0);
if (x == 0) {
return nullopt;
}
if (e >= Bits) {
remainder = *this;
- *this = UInt<Bits>(0);
+ *this = BigInt<Bits, false>(0);
return remainder;
}
- UInt<Bits> quotient(0);
+ BigInt<Bits, Signed> quotient(0);
uint64_t x64 = static_cast<uint64_t>(x);
// lower64 = smallest multiple of 64 that is >= e.
size_t lower64 = ((e >> 6) + ((e & 63) != 0)) << 6;
@@ -468,18 +515,27 @@ template <size_t Bits> struct UInt {
return remainder;
}
- constexpr UInt<Bits> operator/(const UInt<Bits> &other) const {
- UInt<Bits> result(*this);
+ constexpr BigInt<Bits, Signed>
+ operator/(const BigInt<Bits, Signed> &other) const {
+ BigInt<Bits, Signed> result(*this);
result.div(other);
return result;
}
- constexpr UInt<Bits> operator%(const UInt<Bits> &other) const {
- UInt<Bits> result(*this);
+ constexpr BigInt<Bits, Signed> &
+ operator/=(const BigInt<Bits, Signed> &other) {
+ div(other);
+ return *this;
+ }
+
+ constexpr BigInt<Bits, Signed>
+ operator%(const BigInt<Bits, Signed> &other) const {
+ BigInt<Bits, Signed> result(*this);
return *result.div(other);
}
- constexpr UInt<Bits> &operator*=(const UInt<Bits> &other) {
+ constexpr BigInt<Bits, Signed> &
+ operator*=(const BigInt<Bits, Signed> &other) {
*this = *this * other;
return *this;
}
@@ -540,13 +596,13 @@ template <size_t Bits> struct UInt {
}
}
- constexpr UInt<Bits> operator<<(size_t s) const {
- UInt<Bits> result(*this);
+ constexpr BigInt<Bits, Signed> operator<<(size_t s) const {
+ BigInt<Bits, Signed> result(*this);
result.shift_left(s);
return result;
}
- constexpr UInt<Bits> &operator<<=(size_t s) {
+ constexpr BigInt<Bits, Signed> &operator<<=(size_t s) {
shift_left(s);
return *this;
}
@@ -561,7 +617,11 @@ template <size_t Bits> struct UInt {
return;
}
__uint128_t tmp = __uint128_t(val[0]) + (__uint128_t(val[1]) << 64);
- tmp >>= s;
+ if constexpr (Signed) {
+ tmp = static_cast<__uint128_t>(static_cast<__int128_t>(tmp) >> s);
+ } else {
+ tmp >>= s;
+ }
val[0] = uint64_t(tmp);
val[1] = uint64_t(tmp >> 64);
return;
@@ -574,13 +634,19 @@ template <size_t Bits> struct UInt {
const size_t shift = s % 64; // Bit shift in the remaining words.
size_t i = 0;
+ uint64_t sign = Signed ? (val[WORDCOUNT - 1] >> 63) : 0;
if (drop < WORDCOUNT) {
if (shift > 0) {
for (size_t j = drop; j < WORDCOUNT - 1; ++i, ++j) {
val[i] = (val[j] >> shift) | (val[j + 1] << (64 - shift));
}
- val[i] = val[WORDCOUNT - 1] >> shift;
+ if constexpr (Signed) {
+ val[i] = static_cast<uint64_t>(
+ static_cast<int64_t>(val[WORDCOUNT - 1]) >> shift);
+ } else {
+ val[i] = val[WORDCOUNT - 1] >> shift;
+ }
++i;
} else {
for (size_t j = drop; j < WORDCOUNT; ++i, ++j) {
@@ -590,68 +656,80 @@ template <size_t Bits> struct UInt {
}
for (; i < WORDCOUNT; ++i) {
- val[i] = 0;
+ val[i] = sign;
}
}
- constexpr UInt<Bits> operator>>(size_t s) const {
- UInt<Bits> result(*this);
+ constexpr BigInt<Bits, Signed> operator>>(size_t s) const {
+ BigInt<Bits, Signed> result(*this);
result.shift_right(s);
return result;
}
- constexpr UInt<Bits> &operator>>=(size_t s) {
+ constexpr BigInt<Bits, Signed> &operator>>=(size_t s) {
shift_right(s);
return *this;
}
- constexpr UInt<Bits> operator&(const UInt<Bits> &other) const {
- UInt<Bits> result;
+ constexpr BigInt<Bits, Signed>
+ operator&(const BigInt<Bits, Signed> &other) const {
+ BigInt<Bits, Signed> result;
for (size_t i = 0; i < WORDCOUNT; ++i)
result.val[i] = val[i] & other.val[i];
return result;
}
- constexpr UInt<Bits> &operator&=(const UInt<Bits> &other) {
+ constexpr BigInt<Bits, Signed> &
+ operator&=(const BigInt<Bits, Signed> &other) {
for (size_t i = 0; i < WORDCOUNT; ++i)
val[i] &= other.val[i];
return *this;
}
- constexpr UInt<Bits> operator|(const UInt<Bits> &other) const {
- UInt<Bits> result;
+ constexpr BigInt<Bits, Signed>
+ operator|(const BigInt<Bits, Signed> &other) const {
+ BigInt<Bits, Signed> result;
for (size_t i = 0; i < WORDCOUNT; ++i)
result.val[i] = val[i] | other.val[i];
return result;
}
- constexpr UInt<Bits> &operator|=(const UInt<Bits> &other) {
+ constexpr BigInt<Bits, Signed> &
+ operator|=(const BigInt<Bits, Signed> &other) {
for (size_t i = 0; i < WORDCOUNT; ++i)
val[i] |= other.val[i];
return *this;
}
- constexpr UInt<Bits> operator^(const UInt<Bits> &other) const {
- UInt<Bits> result;
+ constexpr BigInt<Bits, Signed>
+ operator^(const BigInt<Bits, Signed> &other) const {
+ BigInt<Bits, Signed> result;
for (size_t i = 0; i < WORDCOUNT; ++i)
result.val[i] = val[i] ^ other.val[i];
return result;
}
- constexpr UInt<Bits> &operator^=(const UInt<Bits> &other) {
+ constexpr BigInt<Bits, Signed> &
+ operator^=(const BigInt<Bits, Signed> &other) {
for (size_t i = 0; i < WORDCOUNT; ++i)
val[i] ^= other.val[i];
return *this;
}
- constexpr UInt<Bits> operator~() const {
- UInt<Bits> result;
+ constexpr BigInt<Bits, Signed> operator~() const {
+ BigInt<Bits, Signed> result;
for (size_t i = 0; i < WORDCOUNT; ++i)
result.val[i] = ~val[i];
return result;
}
- constexpr bool operator==(const UInt<Bits> &other) const {
+ constexpr BigInt<Bits, Signed> operator-() const {
+ BigInt<Bits, Signed> result = ~(*this);
+ result.add(BigInt<Bits, Signed>(1));
+ return result;
+ }
+
+ constexpr bool operator==(const BigInt<Bits, Signed> &other) const {
for (size_t i = 0; i < WORDCOUNT; ++i) {
if (val[i] != other.val[i])
return false;
@@ -659,7 +737,7 @@ template <size_t Bits> struct UInt {
return true;
}
- constexpr bool operator!=(const UInt<Bits> &other) const {
+ constexpr bool operator!=(const BigInt<Bits, Signed> &other) const {
for (size_t i = 0; i < WORDCOUNT; ++i) {
if (val[i] != other.val[i])
return true;
@@ -667,7 +745,15 @@ template <size_t Bits> struct UInt {
return false;
}
- constexpr bool operator>(const UInt<Bits> &other) const {
+ constexpr bool operator>(const BigInt<Bits, Signed> &other) const {
+ if constexpr (Signed) {
+ // Check for
diff erent signs;
+ bool a_sign = val[WORDCOUNT - 1] >> 63;
+ bool b_sign = other.val[WORDCOUNT - 1] >> 63;
+ if (a_sign != b_sign) {
+ return b_sign;
+ }
+ }
for (size_t i = WORDCOUNT; i > 0; --i) {
uint64_t word = val[i - 1];
uint64_t other_word = other.val[i - 1];
@@ -680,7 +766,15 @@ template <size_t Bits> struct UInt {
return false;
}
- constexpr bool operator>=(const UInt<Bits> &other) const {
+ constexpr bool operator>=(const BigInt<Bits, Signed> &other) const {
+ if constexpr (Signed) {
+ // Check for
diff erent signs;
+ bool a_sign = val[WORDCOUNT - 1] >> 63;
+ bool b_sign = other.val[WORDCOUNT - 1] >> 63;
+ if (a_sign != b_sign) {
+ return b_sign;
+ }
+ }
for (size_t i = WORDCOUNT; i > 0; --i) {
uint64_t word = val[i - 1];
uint64_t other_word = other.val[i - 1];
@@ -693,7 +787,16 @@ template <size_t Bits> struct UInt {
return true;
}
- constexpr bool operator<(const UInt<Bits> &other) const {
+ constexpr bool operator<(const BigInt<Bits, Signed> &other) const {
+ if constexpr (Signed) {
+ // Check for
diff erent signs;
+ bool a_sign = val[WORDCOUNT - 1] >> 63;
+ bool b_sign = other.val[WORDCOUNT - 1] >> 63;
+ if (a_sign != b_sign) {
+ return a_sign;
+ }
+ }
+
for (size_t i = WORDCOUNT; i > 0; --i) {
uint64_t word = val[i - 1];
uint64_t other_word = other.val[i - 1];
@@ -706,7 +809,15 @@ template <size_t Bits> struct UInt {
return false;
}
- constexpr bool operator<=(const UInt<Bits> &other) const {
+ constexpr bool operator<=(const BigInt<Bits, Signed> &other) const {
+ if constexpr (Signed) {
+ // Check for
diff erent signs;
+ bool a_sign = val[WORDCOUNT - 1] >> 63;
+ bool b_sign = other.val[WORDCOUNT - 1] >> 63;
+ if (a_sign != b_sign) {
+ return a_sign;
+ }
+ }
for (size_t i = WORDCOUNT; i > 0; --i) {
uint64_t word = val[i - 1];
uint64_t other_word = other.val[i - 1];
@@ -719,12 +830,32 @@ template <size_t Bits> struct UInt {
return true;
}
- constexpr UInt<Bits> &operator++() {
- UInt<Bits> one(1);
+ constexpr BigInt<Bits, Signed> &operator++() {
+ BigInt<Bits, Signed> one(1);
add(one);
return *this;
}
+ constexpr BigInt<Bits, Signed> operator++(int) {
+ BigInt<Bits, Signed> oldval(*this);
+ BigInt<Bits, Signed> one(1);
+ add(one);
+ return oldval;
+ }
+
+ constexpr BigInt<Bits, Signed> &operator--() {
+ BigInt<Bits, Signed> one(1);
+ sub(one);
+ return *this;
+ }
+
+ constexpr BigInt<Bits, Signed> operator--(int) {
+ BigInt<Bits, Signed> oldval(*this);
+ BigInt<Bits, Signed> one(1);
+ sub(one);
+ return oldval;
+ }
+
// Return the i-th 64-bit word of the number.
constexpr const uint64_t &operator[](size_t i) const { return val[i]; }
@@ -736,17 +867,34 @@ template <size_t Bits> struct UInt {
const uint64_t *data() const { return val; }
};
-// Provides limits of UInt<128>.
+template <size_t Bits> using UInt = BigInt<Bits, false>;
+
+template <size_t Bits> using Int = BigInt<Bits, true>;
+
+// Provides limits of U/Int<128>.
template <> class numeric_limits<UInt<128>> {
public:
- static constexpr UInt<128> max() { return ~UInt<128>(0); }
- static constexpr UInt<128> min() { return 0; }
+ static constexpr UInt<128> max() {
+ return UInt<128>({0xffff'ffff'ffff'ffff, 0xffff'ffff'ffff'ffff});
+ }
+ static constexpr UInt<128> min() { return UInt<128>(0); }
};
-// Provides is_integral of UInt<128>, UInt<192>, UInt<256>.
-template <size_t Bits> struct is_integral<UInt<Bits>> : public cpp::true_type {
+template <> class numeric_limits<Int<128>> {
+public:
+ static constexpr Int<128> max() {
+ return Int<128>({0xffff'ffff'ffff'ffff, 0x7fff'ffff'ffff'ffff});
+ }
+ static constexpr Int<128> min() {
+ return Int<128>({0, 0x8000'0000'0000'0000});
+ }
+};
+
+// Provides is_integral of U/Int<128>, U/Int<192>, U/Int<256>.
+template <size_t Bits, bool Signed>
+struct is_integral<BigInt<Bits, Signed>> : cpp::true_type {
static_assert(Bits > 0 && Bits % 64 == 0,
- "Number of bits in UInt should be a multiple of 64.");
+ "Number of bits in BigInt should be a multiple of 64.");
};
// Provides is_unsigned of UInt<128>, UInt<192>, UInt<256>.
@@ -755,6 +903,12 @@ template <size_t Bits> struct is_unsigned<UInt<Bits>> : public cpp::true_type {
"Number of bits in UInt should be a multiple of 64.");
};
+template <size_t Bits>
+struct make_unsigned<Int<Bits>> : type_identity<UInt<Bits>> {
+ static_assert(Bits > 0 && Bits % 64 == 0,
+ "Number of bits in Int should be a multiple of 64.");
+};
+
} // namespace __llvm_libc::cpp
#endif // LLVM_LIBC_SRC_SUPPORT_UINT_H
diff --git a/libc/src/__support/UInt128.h b/libc/src/__support/UInt128.h
index 49cca7859e051..1cc86a7c3fe06 100644
--- a/libc/src/__support/UInt128.h
+++ b/libc/src/__support/UInt128.h
@@ -1,4 +1,4 @@
-//===-- A 128 bit unsigned int type -----------------------------*- C++ -*-===//
+//===-- 128-bit signed and unsigned int types -------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -13,8 +13,10 @@
#if !defined(__SIZEOF_INT128__)
using UInt128 = __llvm_libc::cpp::UInt<128>;
+using Int128 = __llvm_libc::cpp::Int<128>;
#else
using UInt128 = __uint128_t;
+using Int128 = __int128_t;
#endif
#endif // LLVM_LIBC_SRC_SUPPORT_UINT128_H
diff --git a/libc/src/__support/builtin_wrappers.h b/libc/src/__support/builtin_wrappers.h
index 7681e01f16007..a06f859aa6301 100644
--- a/libc/src/__support/builtin_wrappers.h
+++ b/libc/src/__support/builtin_wrappers.h
@@ -23,51 +23,55 @@ namespace __llvm_libc {
// compiler match for us.
namespace __internal {
-template <typename T> LIBC_INLINE int correct_zero(T val, int bits) {
+template <typename T> LIBC_INLINE int constexpr correct_zero(T val, int bits) {
if (val == T(0))
return sizeof(T(0)) * 8;
else
return bits;
}
-template <typename T> LIBC_INLINE int clz(T val);
+template <typename T> LIBC_INLINE constexpr int clz(T val);
template <> LIBC_INLINE int clz<unsigned int>(unsigned int val) {
return __builtin_clz(val);
}
-template <> LIBC_INLINE int clz<unsigned long int>(unsigned long int val) {
+template <>
+LIBC_INLINE constexpr int clz<unsigned long int>(unsigned long int val) {
return __builtin_clzl(val);
}
template <>
-LIBC_INLINE int clz<unsigned long long int>(unsigned long long int val) {
+LIBC_INLINE constexpr int
+clz<unsigned long long int>(unsigned long long int val) {
return __builtin_clzll(val);
}
-template <typename T> LIBC_INLINE int ctz(T val);
+template <typename T> LIBC_INLINE constexpr int ctz(T val);
template <> LIBC_INLINE int ctz<unsigned int>(unsigned int val) {
return __builtin_ctz(val);
}
-template <> LIBC_INLINE int ctz<unsigned long int>(unsigned long int val) {
+template <>
+LIBC_INLINE constexpr int ctz<unsigned long int>(unsigned long int val) {
return __builtin_ctzl(val);
}
template <>
-LIBC_INLINE int ctz<unsigned long long int>(unsigned long long int val) {
+LIBC_INLINE constexpr int
+ctz<unsigned long long int>(unsigned long long int val) {
return __builtin_ctzll(val);
}
} // namespace __internal
-template <typename T> LIBC_INLINE int safe_ctz(T val) {
+template <typename T> LIBC_INLINE constexpr int safe_ctz(T val) {
return __internal::correct_zero(val, __internal::ctz(val));
}
-template <typename T> LIBC_INLINE int unsafe_ctz(T val) {
+template <typename T> LIBC_INLINE constexpr int unsafe_ctz(T val) {
return __internal::ctz(val);
}
-template <typename T> LIBC_INLINE int safe_clz(T val) {
+template <typename T> LIBC_INLINE constexpr int safe_clz(T val) {
return __internal::correct_zero(val, __internal::clz(val));
}
-template <typename T> LIBC_INLINE int unsafe_clz(T val) {
+template <typename T> LIBC_INLINE constexpr int unsafe_clz(T val) {
return __internal::clz(val);
}
diff --git a/libc/src/__support/float_to_string.h b/libc/src/__support/float_to_string.h
index 18a556ca85bcf..a3d1b08f3964f 100644
--- a/libc/src/__support/float_to_string.h
+++ b/libc/src/__support/float_to_string.h
@@ -386,8 +386,8 @@ LIBC_INLINE uint32_t mul_shift_mod_1e9(const MantissaInt mantissa,
cpp::UInt<MID_INT_SIZE + MANT_INT_SIZE> val(large);
// TODO: Find a better way to force __uint128_t to be UInt<128>
cpp::UInt<MANT_INT_SIZE> wide_mant(0);
- wide_mant[0] = mantissa & (uint64_t(-1));
- wide_mant[1] = mantissa >> 64;
+ wide_mant[0] = static_cast<size_t>(mantissa & (uint64_t(-1)));
+ wide_mant[1] = static_cast<size_t>(mantissa >> 64);
val = (val * wide_mant) >> shift_amount;
return val.div_uint32_times_pow_2(1000000000, 0).value()[0];
diff --git a/libc/src/__support/integer_to_string.h b/libc/src/__support/integer_to_string.h
index 22c5acee56e65..4140da27a3990 100644
--- a/libc/src/__support/integer_to_string.h
+++ b/libc/src/__support/integer_to_string.h
@@ -165,11 +165,10 @@ class IntegerToString {
return convert<16>(val, buffer, lowercase);
}
- template <typename T,
- cpp::enable_if_t<cpp::is_integral_v<T> && cpp::is_unsigned_v<T> &&
- (sizeof(T) > sizeof(uintmax_t)) &&
- sizeof(T) % sizeof(uintmax_t) == 0,
- int> = 0>
+ template <typename T, cpp::enable_if_t<cpp::is_integral_v<T> &&
+ (sizeof(T) > sizeof(uintmax_t)) &&
+ sizeof(T) % sizeof(uintmax_t) == 0,
+ int> = 0>
LIBC_INLINE static cpp::optional<cpp::string_view>
hex(T val, cpp::span<char> buffer, bool lowercase = true) {
// We will assume the buffer is exactly sized, which will be the case if
diff --git a/libc/src/__support/str_to_float.h b/libc/src/__support/str_to_float.h
index 2ffa70f98f227..83cd420f150e8 100644
--- a/libc/src/__support/str_to_float.h
+++ b/libc/src/__support/str_to_float.h
@@ -13,6 +13,7 @@
#include "src/__support/CPP/optional.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/dyadic_float.h"
#include "src/__support/FPUtil/rounding_mode.h"
#include "src/__support/UInt128.h"
#include "src/__support/builtin_wrappers.h"
@@ -301,7 +302,8 @@ eisel_lemire<long double>(ExpandedFloat<long double> init_num,
}
// Shifting to 65 bits for 80 bit floats and 113 bits for 128 bit floats
- BitsType msb = final_approx_upper >> (BITS_IN_MANTISSA - 1);
+ uint32_t msb =
+ static_cast<uint32_t>(final_approx_upper >> (BITS_IN_MANTISSA - 1));
BitsType final_mantissa =
final_approx_upper >>
(msb + BITS_IN_MANTISSA -
@@ -571,7 +573,16 @@ clinger_fast_path(ExpandedFloat<T> init_num,
}
fputil::FPBits<T> result;
- T float_mantissa = static_cast<T>(mantissa);
+ T float_mantissa;
+ if constexpr (cpp::is_same_v<typename fputil::FPBits<T>::UIntType,
+ cpp::UInt<128>>) {
+ float_mantissa = static_cast<T>(fputil::DyadicFloat<128>(
+ false, 0,
+ fputil::DyadicFloat<128>::MantissaType(
+ {uint64_t(mantissa), uint64_t(mantissa >> 64)})));
+ } else {
+ float_mantissa = static_cast<T>(mantissa);
+ }
if (exp10 == 0) {
result = fputil::FPBits<T>(float_mantissa);
@@ -806,7 +817,7 @@ LIBC_INLINE FloatConvertReturn<T> binary_exp_to_float(ExpandedFloat<T> init_num,
BitsType round_bit_mask = BitsType(1) << (amount_to_shift_right - 1);
BitsType sticky_mask = round_bit_mask - 1;
- bool round_bit = mantissa & round_bit_mask;
+ bool round_bit = static_cast<bool>(mantissa & round_bit_mask);
bool sticky_bit = static_cast<bool>(mantissa & sticky_mask) || truncated;
if (amount_to_shift_right < NUMBITS) {
@@ -816,7 +827,7 @@ LIBC_INLINE FloatConvertReturn<T> binary_exp_to_float(ExpandedFloat<T> init_num,
} else {
mantissa = 0;
}
- bool least_significant_bit = mantissa & BitsType(1);
+ bool least_significant_bit = static_cast<bool>(mantissa & BitsType(1));
// TODO: check that this rounding behavior is correct.
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index fc833a8a71383..3d5273fa90cc1 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -780,6 +780,7 @@ add_header_library(
log_range_reduction.h
DEPENDS
.common_constants
+ libc.src.__support.uint128
libc.src.__support.FPUtil.dyadic_float
)
diff --git a/libc/src/math/generic/log_range_reduction.h b/libc/src/math/generic/log_range_reduction.h
index 2a36e4de31b5f..c4dd649cc5737 100644
--- a/libc/src/math/generic/log_range_reduction.h
+++ b/libc/src/math/generic/log_range_reduction.h
@@ -11,6 +11,7 @@
#include "common_constants.h"
#include "src/__support/FPUtil/dyadic_float.h"
+#include "src/__support/UInt128.h"
namespace __llvm_libc {
@@ -59,9 +60,9 @@ log_range_reduction(double m_x, const LogRR &log_table,
int64_t s3 = static_cast<int64_t>(S3[idx3]); // |s| < 2^-13, ulp = 2^-21
int64_t spv3 = (s3 << 55) + vv2; // |s + v| < 2^-21, ulp = 2^-76
// |s*v| < 2^-27, ulp = 2^(-76-21) = 2^-97
- __int128_t sv3 = static_cast<__int128_t>(s3) * static_cast<__int128_t>(vv2);
+ Int128 sv3 = static_cast<Int128>(s3) * static_cast<Int128>(vv2);
// |vv3| < 2^-21, ulp = 2^-97
- __int128_t vv3 = (static_cast<__int128_t>(spv3) << 21) + sv3;
+ Int128 vv3 = (static_cast<Int128>(spv3) << 21) + sv3;
// Range reduction - Step 4
// Output range: vv4 in [-0x1.0002143p-29 , 0x1p-29]
@@ -70,13 +71,13 @@ log_range_reduction(double m_x, const LogRR &log_table,
sum = fputil::quick_add(sum, log_table.step_4[idx4]);
- __int128_t s4 = static_cast<__int128_t>(S4[idx4]); // |s| < 2^-21, ulp = 2^-28
+ Int128 s4 = static_cast<Int128>(S4[idx4]); // |s| < 2^-21, ulp = 2^-28
// |s + v| < 2^-28, ulp = 2^-97
- __int128_t spv4 = (s4 << 69) + vv3;
+ Int128 spv4 = (s4 << 69) + vv3;
// |s*v| < 2^-42, ulp = 2^(-97-28) = 2^-125
- __int128_t sv4 = s4 * vv3;
+ Int128 sv4 = s4 * vv3;
// |vv4| < 2^-28, ulp = 2^-125
- __int128_t vv4 = (spv4 << 28) + sv4;
+ Int128 vv4 = (spv4 << 28) + sv4;
return (vv4 < 0) ? Float128(true, -125,
MType({static_cast<uint64_t>(-vv4),
diff --git a/libc/src/stdio/printf_core/char_converter.h b/libc/src/stdio/printf_core/char_converter.h
index 23a85eb572883..f75bc811d14b6 100644
--- a/libc/src/stdio/printf_core/char_converter.h
+++ b/libc/src/stdio/printf_core/char_converter.h
@@ -19,7 +19,7 @@ namespace __llvm_libc {
namespace printf_core {
LIBC_INLINE int convert_char(Writer *writer, const FormatSection &to_conv) {
- char c = to_conv.conv_val_raw;
+ char c = static_cast<char>(to_conv.conv_val_raw);
constexpr int string_len = 1;
diff --git a/libc/src/stdio/printf_core/float_dec_converter.h b/libc/src/stdio/printf_core/float_dec_converter.h
index be4b2831d8063..65fefdb113044 100644
--- a/libc/src/stdio/printf_core/float_dec_converter.h
+++ b/libc/src/stdio/printf_core/float_dec_converter.h
@@ -34,9 +34,10 @@ namespace printf_core {
using MantissaInt = fputil::FPBits<long double>::UIntType;
// Returns true if value is divisible by 2^p.
-LIBC_INLINE constexpr bool multiple_of_power_of_2(const uint64_t value,
- const uint32_t p) {
- return (value & ((uint64_t(1) << p) - 1)) == 0;
+template <typename T>
+LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_integral_v<T>, bool>
+multiple_of_power_of_2(T value, uint32_t p) {
+ return (value & ((T(1) << p) - 1)) == 0;
}
constexpr size_t BLOCK_SIZE = 9;
@@ -1148,7 +1149,8 @@ LIBC_INLINE int convert_float_decimal(Writer *writer,
float_bits);
}
} else {
- fputil::FPBits<double>::UIntType float_raw = to_conv.conv_val_raw;
+ fputil::FPBits<double>::UIntType float_raw =
+ static_cast<fputil::FPBits<double>::UIntType>(to_conv.conv_val_raw);
fputil::FPBits<double> float_bits(float_raw);
if (!float_bits.is_inf_or_nan()) {
return convert_float_decimal_typed<double>(writer, to_conv, float_bits);
@@ -1168,7 +1170,8 @@ LIBC_INLINE int convert_float_dec_exp(Writer *writer,
float_bits);
}
} else {
- fputil::FPBits<double>::UIntType float_raw = to_conv.conv_val_raw;
+ fputil::FPBits<double>::UIntType float_raw =
+ static_cast<fputil::FPBits<double>::UIntType>(to_conv.conv_val_raw);
fputil::FPBits<double> float_bits(float_raw);
if (!float_bits.is_inf_or_nan()) {
return convert_float_dec_exp_typed<double>(writer, to_conv, float_bits);
@@ -1188,7 +1191,8 @@ LIBC_INLINE int convert_float_dec_auto(Writer *writer,
float_bits);
}
} else {
- fputil::FPBits<double>::UIntType float_raw = to_conv.conv_val_raw;
+ fputil::FPBits<double>::UIntType float_raw =
+ static_cast<fputil::FPBits<double>::UIntType>(to_conv.conv_val_raw);
fputil::FPBits<double> float_bits(float_raw);
if (!float_bits.is_inf_or_nan()) {
return convert_float_dec_auto_typed<double>(writer, to_conv, float_bits);
diff --git a/libc/src/stdio/printf_core/float_hex_converter.h b/libc/src/stdio/printf_core/float_hex_converter.h
index ae5efbabb7045..6bb83a2a0c0ff 100644
--- a/libc/src/stdio/printf_core/float_hex_converter.h
+++ b/libc/src/stdio/printf_core/float_hex_converter.h
@@ -52,7 +52,8 @@ LIBC_INLINE int convert_float_hex_exp(Writer *writer,
} else {
mantissa_width = fputil::MantissaWidth<double>::VALUE;
exponent_bias = fputil::FPBits<double>::EXPONENT_BIAS;
- fputil::FPBits<double>::UIntType float_raw = to_conv.conv_val_raw;
+ fputil::FPBits<double>::UIntType float_raw =
+ static_cast<fputil::FPBits<double>::UIntType>(to_conv.conv_val_raw);
fputil::FPBits<double> float_bits(float_raw);
is_negative = float_bits.get_sign();
exponent = float_bits.get_exponent();
@@ -146,9 +147,10 @@ LIBC_INLINE int convert_float_hex_exp(Writer *writer,
size_t mant_cur = mant_len;
size_t first_non_zero = 1;
- for (; mant_cur > 0; --mant_cur, mantissa /= 16) {
- char new_digit = ((mantissa % 16) > 9) ? ((mantissa % 16) - 10 + a)
- : ((mantissa % 16) + '0');
+ for (; mant_cur > 0; --mant_cur, mantissa >>= 4) {
+ char mant_mod_16 = static_cast<char>(mantissa) & 15;
+ char new_digit =
+ (mant_mod_16 > 9) ? (mant_mod_16 - 10 + a) : (mant_mod_16 + '0');
mant_buffer[mant_cur - 1] = new_digit;
if (new_digit != '0' && first_non_zero < mant_cur)
first_non_zero = mant_cur;
diff --git a/libc/src/stdio/printf_core/float_inf_nan_converter.h b/libc/src/stdio/printf_core/float_inf_nan_converter.h
index b7dcf8692e975..0b7a1c3835523 100644
--- a/libc/src/stdio/printf_core/float_inf_nan_converter.h
+++ b/libc/src/stdio/printf_core/float_inf_nan_converter.h
@@ -36,7 +36,8 @@ LIBC_INLINE int convert_inf_nan(Writer *writer, const FormatSection &to_conv) {
is_negative = float_bits.get_sign();
mantissa = float_bits.get_explicit_mantissa();
} else {
- fputil::FPBits<double>::UIntType float_raw = to_conv.conv_val_raw;
+ fputil::FPBits<double>::UIntType float_raw =
+ static_cast<fputil::FPBits<double>::UIntType>(to_conv.conv_val_raw);
fputil::FPBits<double> float_bits(float_raw);
is_negative = float_bits.get_sign();
mantissa = float_bits.get_explicit_mantissa();
diff --git a/libc/src/stdio/printf_core/int_converter.h b/libc/src/stdio/printf_core/int_converter.h
index f5c849c4ef929..448fe8f8bafef 100644
--- a/libc/src/stdio/printf_core/int_converter.h
+++ b/libc/src/stdio/printf_core/int_converter.h
@@ -43,7 +43,7 @@ LIBC_INLINE int convert_int(Writer *writer, const FormatSection &to_conv) {
static constexpr size_t BITS_IN_BYTE = 8;
static constexpr size_t BITS_IN_NUM = sizeof(uintmax_t) * BITS_IN_BYTE;
- uintmax_t num = to_conv.conv_val_raw;
+ uintmax_t num = static_cast<uintmax_t>(to_conv.conv_val_raw);
bool is_negative = false;
FormatFlags flags = to_conv.flags;
diff --git a/libc/test/UnitTest/LibcTest.cpp b/libc/test/UnitTest/LibcTest.cpp
index 4570fc2b0ab2f..109006c408df4 100644
--- a/libc/test/UnitTest/LibcTest.cpp
+++ b/libc/test/UnitTest/LibcTest.cpp
@@ -31,8 +31,7 @@ TestLogger &operator<<(TestLogger &logger, Location Loc) {
// When the value is UInt128, __uint128_t or wider, show its hexadecimal digits.
template <typename T>
-cpp::enable_if_t<cpp::is_integral_v<T> && cpp::is_unsigned_v<T> &&
- (sizeof(T) > sizeof(uint64_t)),
+cpp::enable_if_t<cpp::is_integral_v<T> && (sizeof(T) > sizeof(uint64_t)),
cpp::string>
describeValue(T Value) {
static_assert(sizeof(T) % 8 == 0, "Unsupported size of UInt");
@@ -226,6 +225,13 @@ template bool test<__uint128_t>(RunContext *Ctx, TestCond Cond, __uint128_t LHS,
const char *RHSStr, Location Loc);
#endif
+template bool test<__llvm_libc::cpp::Int<128>>(RunContext *Ctx, TestCond Cond,
+ __llvm_libc::cpp::Int<128> LHS,
+ __llvm_libc::cpp::Int<128> RHS,
+ const char *LHSStr,
+ const char *RHSStr,
+ Location Loc);
+
template bool test<__llvm_libc::cpp::UInt<128>>(RunContext *Ctx, TestCond Cond,
__llvm_libc::cpp::UInt<128> LHS,
__llvm_libc::cpp::UInt<128> RHS,
diff --git a/libc/test/src/__support/uint_test.cpp b/libc/test/src/__support/uint_test.cpp
index 77a6e6b2b39bf..ad6684fb8eca0 100644
--- a/libc/test/src/__support/uint_test.cpp
+++ b/libc/test/src/__support/uint_test.cpp
@@ -21,6 +21,9 @@ using LL_UInt320 = __llvm_libc::cpp::UInt<320>;
using LL_UInt512 = __llvm_libc::cpp::UInt<512>;
using LL_UInt1024 = __llvm_libc::cpp::UInt<1024>;
+using LL_Int128 = __llvm_libc::cpp::Int<128>;
+using LL_Int192 = __llvm_libc::cpp::Int<192>;
+
TEST(LlvmLibcUIntClassTest, BasicInit) {
LL_UInt128 empty;
LL_UInt128 half_val(12345);
@@ -560,3 +563,75 @@ TEST(LlvmLibcUIntClassTest, DivUInt32TimesPow2Tests) {
TEST_QUICK_DIV_UINT32_POW2(1000000000, 75);
TEST_QUICK_DIV_UINT32_POW2(1000000000, 101);
}
+
+TEST(LlvmLibcUIntClassTest, ComparisonInt128Tests) {
+ LL_Int128 a(123);
+ LL_Int128 b(0);
+ LL_Int128 c(-1);
+
+ ASSERT_TRUE(a == a);
+ ASSERT_TRUE(b == b);
+ ASSERT_TRUE(c == c);
+
+ ASSERT_TRUE(a != b);
+ ASSERT_TRUE(a != c);
+ ASSERT_TRUE(b != a);
+ ASSERT_TRUE(b != c);
+ ASSERT_TRUE(c != a);
+ ASSERT_TRUE(c != b);
+
+ ASSERT_TRUE(a > b);
+ ASSERT_TRUE(a >= b);
+ ASSERT_TRUE(a > c);
+ ASSERT_TRUE(a >= c);
+ ASSERT_TRUE(b > c);
+ ASSERT_TRUE(b >= c);
+
+ ASSERT_TRUE(b < a);
+ ASSERT_TRUE(b <= a);
+ ASSERT_TRUE(c < a);
+ ASSERT_TRUE(c <= a);
+ ASSERT_TRUE(c < b);
+ ASSERT_TRUE(c <= b);
+}
+
+TEST(LlvmLibcUIntClassTest, BasicArithmeticInt128Tests) {
+ LL_Int128 a(123);
+ LL_Int128 b(0);
+ LL_Int128 c(-3);
+
+ ASSERT_EQ(a * a, LL_Int128(123 * 123));
+ ASSERT_EQ(a * c, LL_Int128(-369));
+ ASSERT_EQ(c * a, LL_Int128(-369));
+ ASSERT_EQ(c * c, LL_Int128(9));
+ ASSERT_EQ(a * b, b);
+ ASSERT_EQ(b * a, b);
+ ASSERT_EQ(b * c, b);
+ ASSERT_EQ(c * b, b);
+}
+
+#ifdef __SIZEOF_INT128__
+
+TEST(LlvmLibcUIntClassTest, ConstructorFromUInt128Tests) {
+ __uint128_t a = (__uint128_t(123) << 64) + 1;
+ __int128_t b = -static_cast<__int128_t>(a);
+ LL_Int128 c(a);
+ LL_Int128 d(b);
+
+ LL_Int192 e(a);
+ LL_Int192 f(b);
+
+ ASSERT_EQ(static_cast<int>(c), 1);
+ ASSERT_EQ(static_cast<int>(c >> 64), 123);
+ ASSERT_EQ(static_cast<uint64_t>(d), static_cast<uint64_t>(b));
+ ASSERT_EQ(static_cast<uint64_t>(d >> 64), static_cast<uint64_t>(b >> 64));
+ ASSERT_EQ(c + d, LL_Int128(a + b));
+
+ ASSERT_EQ(static_cast<int>(e), 1);
+ ASSERT_EQ(static_cast<int>(e >> 64), 123);
+ ASSERT_EQ(static_cast<uint64_t>(f), static_cast<uint64_t>(b));
+ ASSERT_EQ(static_cast<uint64_t>(f >> 64), static_cast<uint64_t>(b >> 64));
+ ASSERT_EQ(LL_UInt192(e + f), LL_UInt192(a + b));
+}
+
+#endif // __SIZEOF_INT128__
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 84c5c9b9ebece..58aa99d007743 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -445,6 +445,7 @@ libc_support_library(
":__support_fputil_fenv_impl",
":__support_fputil_fp_bits",
":__support_fputil_rounding_mode",
+ ":__support_fputil_dyadic_float",
":__support_str_to_integer",
":__support_str_to_num_result",
":__support_uint128",
@@ -1140,6 +1141,7 @@ libc_support_library(
hdrs = ["src/math/generic/log_range_reduction.h"],
deps = [
":__support_common",
+ ":__support_uint128",
":__support_fputil_dyadic_float",
":common_constants",
],
More information about the libc-commits
mailing list