diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index d83b74039..276b264f6 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -33,11 +33,6 @@ Revision History: #error No multi-precision library selected. #endif -// Out-of-line definitions for static constexpr members (required for ODR-use in C++14 and earlier) -constexpr int mpz::SMALL_BITS; -constexpr int64_t mpz::SMALL_INT_MAX; -constexpr int64_t mpz::SMALL_INT_MIN; - // Available GCD algorithms // #define EUCLID_GCD // #define BINARY_GCD @@ -263,28 +258,25 @@ void mpz_manager::sub(mpz const & a, mpz const & b, mpz & c) { template void mpz_manager::set_big_i64(mpz & c, int64_t v) { -#ifndef _MP_GMP - mpz_cell* cell = c.is_small() ? nullptr : c.ptr(); - if (cell == nullptr) { - cell = allocate(m_init_cell_capacity); - c.set_ptr(cell, false, false); // Will update sign below - } - SASSERT(capacity(c) >= m_init_cell_capacity); uint64_t _v; - bool is_negative = false; + bool sign = v < 0; if (v == std::numeric_limits::min()) { // min-int is even _v = -(v/2); - is_negative = true; } else if (v < 0) { _v = -v; - is_negative = true; } else { _v = v; } - c.set_sign(is_negative ? -1 : 1); +#ifndef _MP_GMP + if (c.is_small()) { + c.set_ptr(allocate(m_init_cell_capacity), sign, false); + } else { + c.set_sign(sign ? -1 : 1); + } + SASSERT(capacity(c) >= m_init_cell_capacity); if (sizeof(digit_t) == sizeof(uint64_t)) { // 64-bit machine digits(c)[0] = static_cast(_v); @@ -297,21 +289,8 @@ void mpz_manager::set_big_i64(mpz & c, int64_t v) { c.ptr()->m_size = digits(c)[1] == 0 ? 1 : 2; } #else - mpz_t* cell = c.is_small() ? nullptr : c.ptr(); - if (cell == nullptr) { - cell = allocate(); - c.set_ptr(cell, false, false); - } - uint64_t _v; - bool sign = v < 0; - if (v == std::numeric_limits::min()) { - _v = -(v/2); - } - else if (v < 0) { - _v = -v; - } - else { - _v = v; + if (c.is_small()) { + c.set_ptr(allocate(), false, false); } mpz_set_ui(*c.ptr(), static_cast(_v)); MPZ_BEGIN_CRITICAL(); @@ -330,13 +309,12 @@ void mpz_manager::set_big_i64(mpz & c, int64_t v) { template void mpz_manager::set_big_ui64(mpz & c, uint64_t v) { #ifndef _MP_GMP - mpz_cell* cell = c.is_small() ? nullptr : c.ptr(); - if (cell == nullptr) { - cell = allocate(m_init_cell_capacity); - c.set_ptr(cell, false, false); // positive, owned + if (c.is_small()) { + c.set_ptr(allocate(m_init_cell_capacity), false, false); // positive, owned + } else { + c.set_sign(1); // positive } SASSERT(capacity(c) >= m_init_cell_capacity); - c.set_sign(1); // positive if (sizeof(digit_t) == sizeof(uint64_t)) { // 64-bit machine digits(c)[0] = static_cast(v); @@ -349,10 +327,8 @@ void mpz_manager::set_big_ui64(mpz & c, uint64_t v) { c.ptr()->m_size = digits(c)[1] == 0 ? 1 : 2; } #else - mpz_t* cell = c.is_small() ? nullptr : c.ptr(); - if (cell == nullptr) { - cell = allocate(); - c.set_ptr(cell, false, false); // positive, owned + if (c.is_small()) { + c.set_ptr(allocate(), false, false); // positive, owned } mpz_set_ui(*c.ptr(), static_cast(v)); MPZ_BEGIN_CRITICAL(); @@ -399,7 +375,7 @@ void mpz_manager::set(mpz_cell& src, mpz & a, int sign, unsigned sz) { } unsigned d = src.m_digits[0]; - if (i == 1 && d <= static_cast(mpz::SMALL_INT_MAX)) { + if (i == 1 && d <= mpz::SMALL_INT_MAX) { // src fits in small integer range a.set64(sign < 0 ? -static_cast(d) : static_cast(d)); return; @@ -447,30 +423,9 @@ void mpz_manager::set_digits(mpz & target, unsigned sz, digit_t const * d set(target, digits[0]); else { #ifndef _MP_GMP - mpz_cell* cell = target.is_small() ? nullptr : target.ptr(); - if (cell == nullptr) { - unsigned c = sz < m_init_cell_capacity ? m_init_cell_capacity : sz; - cell = allocate(c); - cell->m_size = sz; - cell->m_capacity = c; - target.set_ptr(cell, false, false); // positive, owned - memcpy(cell->m_digits, digits, sizeof(digit_t) * sz); - } - else if (capacity(target) < sz) { - SASSERT(sz > m_init_cell_capacity); - mpz_cell* ptr = allocate(sz); - memcpy(ptr->m_digits, digits, sizeof(digit_t) * sz); - ptr->m_size = sz; - ptr->m_capacity = sz; - deallocate(target); - target.set_ptr(ptr, false, false); // positive, owned - } - else { - target.ptr()->m_size = sz; - if (target.ptr()->m_digits != digits) - memcpy(target.ptr()->m_digits, digits, sizeof(digit_t) * sz); - // already large - } + allocate_if_needed(target, sz); + memcpy(target.ptr()->m_digits, digits, sizeof(digit_t) * sz); + target.set_sign(1): #else mk_big(target); // reset @@ -710,13 +665,7 @@ template void mpz_manager::neg(mpz & a) { STRACE(mpz, tout << "[mpz] 0 - " << to_string(a) << " == ";); if (is_small(a)) { - int64_t v = a.value(); - if (v == mpz::SMALL_INT_MIN) { - // neg(SMALL_INT_MIN) overflows small range - set_big_i64(a, -v); - return; - } - a.set64(-v); + a.set64(-a.value()); } #ifndef _MP_GMP else { @@ -735,12 +684,7 @@ void mpz_manager::abs(mpz & a) { if (is_small(a)) { int64_t v = a.value(); if (v < 0) { - if (v == mpz::SMALL_INT_MIN) { - // abs(SMALL_INT_MIN) overflows small range - set_big_i64(a, -v); - } - else - a.set64(-v); + a.set64(-v); } } else { @@ -948,15 +892,11 @@ void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { if (is_small(a) && is_small(b)) { int64_t _a = a.value(); int64_t _b = b.value(); - // Check if absolute values fit in uint64 (they always do for small integers) - // and won't overflow when negating - if (_a != mpz::SMALL_INT_MIN && _b != mpz::SMALL_INT_MIN) { - if (_a < 0) _a = -_a; - if (_b < 0) _b = -_b; - uint64_t r = u64_gcd(static_cast(_a), static_cast(_b)); - set(c, r); - return; - } + if (_a < 0) _a = -_a; + if (_b < 0) _b = -_b; + uint64_t r = u64_gcd(static_cast(_a), static_cast(_b)); + set(c, r); + return; } else { #ifdef _MP_GMP @@ -1202,8 +1142,8 @@ void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { } } del(a1); del(b1); del(r); del(t); del(tmp); - } #endif // LEHMER_GCD + } } template @@ -1564,28 +1504,9 @@ void mpz_manager::big_set(mpz & target, mpz const & source) { #ifndef _MP_GMP if (&target == &source) return; - int src_sign = source.sign(); - mpz_cell* target_cell = target.is_small() ? nullptr : target.ptr(); - if (target_cell == nullptr) { - mpz_cell* new_cell = allocate(capacity(source)); - new_cell->m_size = size(source); - new_cell->m_capacity = capacity(source); - memcpy(new_cell->m_digits, source.ptr()->m_digits, sizeof(digit_t) * size(source)); - target.set_ptr(new_cell, src_sign < 0, false); - } - else if (capacity(target) < size(source)) { - deallocate(target); - mpz_cell* new_cell = allocate(capacity(source)); - new_cell->m_size = size(source); - new_cell->m_capacity = capacity(source); - memcpy(new_cell->m_digits, source.ptr()->m_digits, sizeof(digit_t) * size(source)); - target.set_ptr(new_cell, src_sign < 0, false); - } - else { - target.ptr()->m_size = size(source); - memcpy(target.ptr()->m_digits, source.ptr()->m_digits, sizeof(digit_t) * size(source)); - target.set_sign(src_sign); - } + allocate_if_needed(target, capacity(source)); + memcpy(digits(target), digits(source), sizeof(digit_t) * size(source)); + target.set_sign(source.sign()); #else // GMP version mk_big(target); @@ -1637,12 +1558,7 @@ bool mpz_manager::is_uint64(mpz const & a) const { return a.value() >= 0; if (a.sign() < 0) return false; - if (sizeof(digit_t) == sizeof(uint64_t)) { - return size(a) <= 1; - } - else { - return size(a) <= 2; - } + return size(a) <= (sizeof(digit_t) == sizeof(uint64_t) ? 1 : 2); #else // GMP version if (is_small(a)) @@ -1768,15 +1684,11 @@ void mpz_manager::display(std::ostream & out, mpz const & a) const { else { #ifndef _MP_GMP if (a.sign() < 0) - out << "-"; - if (sizeof(digit_t) == 4) { - sbuffer buffer(11*size(a), 0); - out << m_mpn_manager.to_string(digits(a), size(a), buffer.begin(), buffer.size()); - } - else { - sbuffer buffer(21*size(a), 0); - out << m_mpn_manager.to_string(digits(a), size(a), buffer.begin(), buffer.size()); - } + out << '-'; + + auto sz = sizeof(digit_t) == 4 ? 11 : 21; + sbuffer buffer(sz * size(a), 0); + out << m_mpn_manager.to_string(digits(a), size(a), buffer.begin(), buffer.size()); #else // GMP version size_t sz = mpz_sizeinbase(*a.ptr(), 10) + 2; @@ -1933,8 +1845,7 @@ void mpz_manager::power(mpz const & a, unsigned p, mpz & b) { mpz_pow_ui(*b.ptr(), *a.ptr(), p); return; } -#endif -#ifndef _MP_GMP +#else if (is_small(a)) { if (a.value() == 2) { if (p < 8 * sizeof(int) - 1) { @@ -1992,8 +1903,8 @@ bool mpz_manager::is_power_of_two(mpz const & a, unsigned & shift) { return false; if (is_small(a)) { int64_t v = a.value(); - if (v > 0 && (v & (v - 1)) == 0) { // Check if power of 2 - shift = uint64_log2(static_cast(v)); + if (::is_power_of_two(v)) { + shift = log2(static_cast(v)); return true; } else { @@ -2009,7 +1920,7 @@ bool mpz_manager::is_power_of_two(mpz const & a, unsigned & shift) { return false; } digit_t v = ds[sz-1]; - if (!(v & (v - 1)) && v) { + if (::is_power_of_two(v)) { shift = log2(a); return true; } @@ -2038,59 +1949,26 @@ void mpz_manager::ensure_capacity(mpz & a, unsigned capacity) { if (is_small(a)) { int64_t val = a.value(); + uint64_t abs_val = static_cast(-val); allocate_if_needed(a, capacity); SASSERT(a.ptr()->m_capacity >= capacity); - // Check if this is SMALL_INT_MIN which needs special handling - if (val == mpz::SMALL_INT_MIN) { - // For 32-bit: SMALL_INT_MIN = -2^30, so -val = 2^30 fits in unsigned - // For 64-bit: SMALL_INT_MIN = -2^62, so -val = 2^62 fits in uint64_t - uint64_t abs_val = static_cast(-val); - if (sizeof(digit_t) == sizeof(uint64_t)) { - // 64-bit machine - a.ptr()->m_digits[0] = static_cast(abs_val); - a.ptr()->m_size = 1; - } - else { - // 32-bit machine - a.ptr()->m_digits[0] = static_cast(abs_val); - a.ptr()->m_digits[1] = static_cast(abs_val >> 32); - a.ptr()->m_size = (abs_val >> 32) == 0 ? 1 : 2; - } - a.set_sign(-1); - } - else if (val < 0) { - uint64_t abs_val = static_cast(-val); - if (sizeof(digit_t) == sizeof(uint64_t)) { - a.ptr()->m_digits[0] = static_cast(abs_val); - a.ptr()->m_size = 1; - } - else { - a.ptr()->m_digits[0] = static_cast(abs_val); - a.ptr()->m_digits[1] = static_cast(abs_val >> 32); - a.ptr()->m_size = (abs_val >> 32) == 0 ? 1 : 2; - } - a.set_sign(-1); + if (sizeof(digit_t) == sizeof(uint64_t)) { + a.ptr()->m_digits[0] = static_cast(abs_val); + a.ptr()->m_size = 1; } else { - if (sizeof(digit_t) == sizeof(uint64_t)) { - a.ptr()->m_digits[0] = static_cast(val); - a.ptr()->m_size = 1; - } - else { - a.ptr()->m_digits[0] = static_cast(val); - a.ptr()->m_digits[1] = static_cast(val >> 32); - a.ptr()->m_size = (val >> 32) == 0 ? 1 : 2; - } - a.set_sign(1); + a.ptr()->m_digits[0] = static_cast(abs_val); + a.ptr()->m_digits[1] = static_cast(abs_val >> 32); + a.ptr()->m_size = (abs_val >> 32) == 0 ? 1 : 2; } + a.set_sign(val < 0 ? -1 : 1); } else if (a.ptr()->m_capacity < capacity) { mpz_cell * new_cell = allocate(capacity); - SASSERT(new_cell->m_capacity == capacity); unsigned old_sz = a.ptr()->m_size; + SASSERT(capacity >= old_sz); new_cell->m_size = old_sz; - for (unsigned i = 0; i < old_sz; ++i) - new_cell->m_digits[i] = a.ptr()->m_digits[i]; + memcpy(new_cell->m_digits, digits(a), sizeof(digit_t) * old_sz) bool is_neg = a.sign() < 0; deallocate(a); a.set_ptr(new_cell, is_neg, false); @@ -2106,21 +1984,7 @@ void mpz_manager::normalize(mpz & a) { if (ds[i-1] != 0) break; } - - if (i == 0) { - // a is zero... - set(a, 0); - return; - } - - if (i == 1 && ds[0] <= static_cast(mpz::SMALL_INT_MAX)) { - // a fits in small integer range - int64_t val = a.sign() < 0 ? -static_cast(ds[0]) : static_cast(ds[0]); - a.set64(val); - return; - } - // adjust size - c->m_size = i; + c->m_size = std::max(1u, i); } #endif @@ -2129,21 +1993,13 @@ void mpz_manager::machine_div2k(mpz & a, unsigned k) { if (k == 0 || is_zero(a)) return; if (is_small(a)) { - if (k < 32) { - int64_t twok = 1ull << ((int64_t)k); - int64_t val = a.value(); - int64_t result = val / twok; - // Division by power of 2 should keep us in small range - SASSERT(mpz::fits_in_small(result)); - a.set64(result); - } - else if (k < 64) { + if (k < 64) { int64_t twok = 1ull << ((int64_t)k); int64_t val = a.value(); a.set64(val/twok); } else { - a.set(0); + a.set64(0); } return; } @@ -2272,48 +2128,8 @@ unsigned mpz_manager::power_of_two_multiple(mpz const & a) { if (is_zero(a)) return 0; if (is_small(a)) { - unsigned r = 0; int64_t val = a.value(); - // Count trailing zeros in 64-bit value - if (val == 0) return 0; - - // Work with absolute value for counting trailing zeros - // Handle SMALL_INT_MIN specially to avoid overflow - uint64_t v; - if (val == mpz::SMALL_INT_MIN) { - // SMALL_INT_MIN = -2^(SMALL_BITS-1), so it has (SMALL_BITS-1) trailing zeros - // On 32-bit: return 30, on 64-bit: return 62 - return (sizeof(uintptr_t) * 8 - 1) - 1; - } else if (val < 0) { - v = static_cast(-val); - } else { - v = static_cast(val); - } - - if ((v & 0xFFFFFFFF) == 0) { - r += 32; - v >>= 32; - } - if ((v & 0xFFFF) == 0) { - r += 16; - v >>= 16; - } - if ((v & 0xFF) == 0) { - r += 8; - v >>= 8; - } - if ((v & 0xF) == 0) { - r += 4; - v >>= 4; - } - if ((v & 0x3) == 0) { - r += 2; - v >>= 2; - } - if ((v & 0x1) == 0) { - r++; - } - return r; + return std::countr_zero(static_cast(val < 0 ? -val : val)); } #ifndef _MP_GMP mpz_cell * c = a.ptr(); @@ -2322,35 +2138,7 @@ unsigned mpz_manager::power_of_two_multiple(mpz const & a) { digit_t * source = c->m_digits; for (unsigned i = 0; i < sz; ++i) { if (source[i] != 0) { - digit_t v = source[i]; - if (sizeof(digit_t) == 8) { - // TODO: we can remove this if after we move to MPN - // In MPN the digit_t is always an unsigned integer - if (static_cast(v) % (static_cast(1) << 32) == 0) { - r += 32; - v = static_cast(static_cast(v) / (static_cast(1) << 32)); - } - } - // Count trailing zeros in digit_t - if (v % (1 << 16) == 0) { - r += 16; - v /= (1 << 16); - } - if (v % (1 << 8) == 0) { - r += 8; - v /= (1 << 8); - } - if (v % (1 << 4) == 0) { - r += 4; - v /= (1 << 4); - } - if (v % (1 << 2) == 0) { - r += 2; - v /= (1 << 2); - } - if (v % 2 == 0) { - r++; - } + r += std::countr_zero(source[i]); return r; } r += (8 * sizeof(digit_t)); @@ -2366,8 +2154,7 @@ unsigned mpz_manager::log2(mpz const & a) { if (is_nonpos(a)) return 0; if (is_small(a)) { - int64_t v = a.value(); - return uint64_log2(static_cast(v)); + return ::log2(static_cast(a.value())); } #ifndef _MP_GMP static_assert(sizeof(digit_t) == 8 || sizeof(digit_t) == 4, ""); @@ -2375,9 +2162,9 @@ unsigned mpz_manager::log2(mpz const & a) { unsigned sz = c->m_size; digit_t * ds = c->m_digits; if (sizeof(digit_t) == 8) - return (sz - 1)*64 + uint64_log2(ds[sz-1]); + return (sz - 1)*64 + ::log2(ds[sz-1]); else - return (sz - 1)*32 + ::log2(static_cast(ds[sz-1])); + return (sz - 1)*32 + ::log2(ds[sz-1]); #else unsigned r = mpz_sizeinbase(*a.ptr(), 2); SASSERT(r > 0); @@ -2390,14 +2177,7 @@ unsigned mpz_manager::mlog2(mpz const & a) { if (is_nonneg(a)) return 0; if (is_small(a)) { - int64_t v = a.value(); - if (v == mpz::SMALL_INT_MIN) { - // Special case: negating SMALL_INT_MIN would overflow - // For 32-bit: SMALL_INT_MIN = -2^30, so log2(2^30) = 30 - // For 64-bit: SMALL_INT_MIN = -2^62, so log2(2^62) = 62 - return (sizeof(uintptr_t) * 8 - 1) - 1; - } - return uint64_log2(static_cast(-v)); + return ::log2(static_cast(-va.value())); } #ifndef _MP_GMP static_assert(sizeof(digit_t) == 8 || sizeof(digit_t) == 4, ""); @@ -2405,9 +2185,9 @@ unsigned mpz_manager::mlog2(mpz const & a) { unsigned sz = c->m_size; digit_t * ds = c->m_digits; if (sizeof(digit_t) == 8) - return (sz - 1)*64 + uint64_log2(ds[sz-1]); + return (sz - 1)*64 + ::log2(ds[sz-1]); else - return (sz - 1)*32 + ::log2(static_cast(ds[sz-1])); + return (sz - 1)*32 + ::log2(ds[sz-1]); #else MPZ_BEGIN_CRITICAL(); mpz_neg(m_tmp, *a.ptr()); @@ -2619,7 +2399,7 @@ digit_t mpz_manager::get_least_significant(mpz const& a) { if (is_small(a)) return std::abs(a.value()); #ifndef _MP_GMP - mpz_cell* cell_a = a.ptr(); + mpz_cell* cell_a = a.ptr(); unsigned sz = cell_a->m_size; if (sz == 0) return 0; @@ -2635,11 +2415,11 @@ bool mpz_manager::decompose(mpz const & a, svector & digits) { if (is_small(a)) { int64_t v = a.value(); bool is_neg = v < 0; - uint64_t abs_v = is_neg ? static_cast(-v) : static_cast(v); - + uint64_t abs_v = static_cast(is_neg ? -v : v); + // Decompose absolute value into digits if (sizeof(digit_t) == sizeof(uint64_t)) { - digits.push_back(static_cast(abs_v)); + digits.push_back(abs_v); } else { // digit_t is 32-bit, need to split 64-bit value digits.push_back(static_cast(abs_v)); diff --git a/src/util/mpz.h b/src/util/mpz.h index 55896bbdc..c48d7e708 100644 --- a/src/util/mpz.h +++ b/src/util/mpz.h @@ -69,8 +69,8 @@ class mpz_cell { /** \brief Multi-precision integer. - m_value encodes either a small integer (if the least significant bit is 1) - or a pointer to a mpz_cell structure (if the least significant bit is 0). + m_value encodes either a small integer (if the least significant bit is 0) + or a pointer to a mpz_cell structure (if the least significant bit is 1). The last 3 bits of pointers are always 0 due to alignment, so we use them to store additional information: - bit 0: small/large info (0 = small, 1 = large) @@ -89,15 +89,15 @@ private: static constexpr uintptr_t LARGE_BIT = 0x1; static constexpr uintptr_t SIGN_BIT = 0x2; - static constexpr uintptr_t OWNER_BIT = 0x4; + static constexpr uintptr_t EXTERNAL_BIT = 0x4; static constexpr uintptr_t MPZ_PTR_MASK = ~static_cast(0x7); - // Small integers are stored shifted left by 1, so we have (sizeof(uintptr_t)*8 - 1) bits available + // Small integers are stored shifted left by 1 // This gives us: // - On 32-bit platforms: 31 bits, range [-2^30, 2^30-1] // - On 64-bit platforms: 63 bits, range [-2^62, 2^62-1] - static constexpr int SMALL_BITS = sizeof(uintptr_t) * 8 - 1; - + static constexpr unaigned SMALL_BITS = sizeof(uintptr_t) * 8 - 1; + // Maximum and minimum values that can be stored as small integers static constexpr int64_t SMALL_INT_MAX = (static_cast(1) << (SMALL_BITS - 1)) - 1; static constexpr int64_t SMALL_INT_MIN = -(static_cast(1) << (SMALL_BITS - 1)); @@ -110,14 +110,6 @@ private: return v <= static_cast(SMALL_INT_MAX); } - static bool fits_in_small(int v) { - return fits_in_small(static_cast(v)); - } - - static bool fits_in_small(unsigned int v) { - return fits_in_small(static_cast(v)); - } - mpz_type * ptr() const { SASSERT(!is_small()); return reinterpret_cast(m_value & MPZ_PTR_MASK); @@ -130,7 +122,7 @@ private: if (is_negative) m_value |= SIGN_BIT; if (is_external) - m_value |= OWNER_BIT; + m_value |= EXTERNAL_BIT; } int get_sign() const { @@ -148,7 +140,7 @@ private: bool is_external() const { SASSERT(!is_small()); - return (m_value & OWNER_BIT) != 0; + return (m_value & EXTERNAL_BIT) != 0; } protected: @@ -161,54 +153,45 @@ protected: friend class mpbq_manager; friend class mpz_stack; public: - mpz(int v = 0) noexcept : m_value(static_cast(static_cast(v)) << 1) { + mpz(int64_t v = 0) noexcept : m_value(static_cast(v) << 1) { // On 32-bit platforms, INT_MIN doesn't fit in 31 bits. This constructor should only be used // with values that fit, or the caller should use set_big_i64. SASSERT(fits_in_small(v)); } - + mpz(mpz_type* ptr) noexcept { - SASSERT(ptr); set_ptr(ptr, false, true); // external pointer, non-negative } - + mpz(mpz && other) noexcept : m_value(other.m_value) { other.m_value = 0; // reset other to small } mpz& operator=(mpz const& other) = delete; - + mpz& operator=(mpz &&other) noexcept { std::swap(m_value, other.m_value); return *this; } - void set(int v) { - SASSERT(is_small()); - m_value = static_cast(static_cast(v)) << 1; - } - void set64(int64_t v) { + SASSERT(is_small()); SASSERT(fits_in_small(v)); - m_value = static_cast(static_cast(v)) << 1; + m_value = static_cast(v) << 1; } - void swap(mpz & other) noexcept { - std::swap(m_value, other.m_value); + inline bool is_small() const { + return (m_value & LARGE_BIT) == 0; } - inline bool is_small() const { - return (m_value & LARGE_BIT) == 0; - } - - inline int64_t value() const { + inline int64_t value() const { SASSERT(is_small()); // Decode small integer: shift right by 1 (arithmetic shift to preserve sign) return static_cast(static_cast(m_value) >> 1); } - inline int sign() const { - SASSERT(!is_small()); + inline int sign() const { + SASSERT(!is_small()); return get_sign(); } }; @@ -255,11 +238,10 @@ class mpz_manager { // make sure that n is a big number and has capacity equal to at least c. void allocate_if_needed(mpz & n, unsigned c) { if (m_init_cell_capacity > c) c = m_init_cell_capacity; - if (n.is_small() || n.ptr() == nullptr || capacity(n) < c) { + if (n.is_small() || capacity(n) < c) { deallocate(n); n.set_ptr(allocate(c), false, false); // positive, owned } - // else already has enough capacity, keep as large } void deallocate(bool is_heap, mpz_cell * ptr); @@ -311,35 +293,21 @@ class mpz_manager { } } - void clear(mpz& n) { if (!n.is_small() && n.ptr()) { mpz_clear(*n.ptr()); }} + void clear(mpz& n) { if (!n.is_small()) { mpz_clear(*n.ptr()); }} #endif void deallocate(mpz& n) { if (!n.is_small()) { - auto* p = n.ptr(); - if (p) { - deallocate(!n.is_external(), p); - n.m_value = 0; // reset to small - } + deallocate(!n.is_external(), n.ptr()); + n.m_value = 0; // reset to small } } - mpz m_two64; - + mpz m_two64; static int64_t i64(mpz const & a) { return a.value(); } void set_big_i64(mpz & c, int64_t v); - - void set_i64(mpz & c, int64_t v) { - if (mpz::fits_in_small(v) && is_small(c)) { - c.set64(v); - } - else { - set_big_i64(c, v); - } - } - void set_big_ui64(mpz & c, uint64_t v); @@ -400,31 +368,19 @@ class mpz_manager { void get_sign_cell(mpz const & a, int & sign, mpz_cell * & cell, mpz_cell* reserve) { if (is_small(a)) { int64_t val = a.value(); + bool neg = val < 0; + uint64_t abs_val = static_cast(neg ? -val : val); cell = reserve; - if (val < 0) { - sign = -1; - uint64_t abs_val = static_cast(-val); - if (sizeof(digit_t) == sizeof(uint64_t)) { - cell->m_size = 1; - cell->m_digits[0] = static_cast(abs_val); - } - else { - cell->m_digits[0] = static_cast(abs_val); - cell->m_digits[1] = static_cast(abs_val >> 32); - cell->m_size = (abs_val >> 32) == 0 ? 1 : 2; - } + sign = neg ? -1 : 1; + + if (sizeof(digit_t) == sizeof(uint64_t)) { + cell->m_size = 1; + cell->m_digits[0] = static_cast(abs_val); } else { - sign = 1; - if (sizeof(digit_t) == sizeof(uint64_t)) { - cell->m_size = 1; - cell->m_digits[0] = static_cast(val); - } - else { - cell->m_digits[0] = static_cast(val); - cell->m_digits[1] = static_cast(val >> 32); - cell->m_size = (val >> 32) == 0 ? 1 : 2; - } + cell->m_digits[0] = static_cast(abs_val); + cell->m_digits[1] = static_cast(abs_val >> 32); + cell->m_size = (abs_val >> 32) == 0 ? 1 : 2; } } else { @@ -449,7 +405,6 @@ class mpz_manager { if (a.is_small()) { a.set_ptr(allocate(), false, false); // positive, owned } - // else already large with valid pointer } @@ -639,29 +594,15 @@ public: } } - void set(mpz & a, int val) { - // On 32-bit platforms, int can be outside small range - if (mpz::fits_in_small(val) && is_small(a)) { - a.set(val); - } - else { - set_i64(a, val); - } - } - - void set(mpz & a, unsigned val) { - if (mpz::fits_in_small(val) && is_small(a)) { - a.set(static_cast(val)); - } - else { - set_i64(a, static_cast(val)); - } - } - void set(mpz & a, char const * val); void set(mpz & a, int64_t val) { - set_i64(a, val); + if (mpz::fits_in_small(v) && is_small(c)) { + c.set64(v); + } + else { + set_big_i64(c, v); + } } void set(mpz & a, uint64_t val) { diff --git a/src/util/util.cpp b/src/util/util.cpp index d60f8467a..857ea71a7 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -57,60 +57,6 @@ void set_fatal_error_handler(void (*pfn)(int error_code)) { g_fatal_error_handler = pfn; } -unsigned log2(unsigned v) { - unsigned r = 0; - if (v & 0xFFFF0000) { - v >>= 16; - r |= 16; - } - if (v & 0xFF00) { - v >>= 8; - r |= 8; - } - if (v & 0xF0) { - v >>= 4; - r |= 4; - } - if (v & 0xC) { - v >>= 2; - r |= 2; - } - if (v & 0x2) { - v >>= 1; - r |= 1; - } - return r; -} - -unsigned uint64_log2(uint64_t v) { - unsigned r = 0; - if (v & 0xFFFFFFFF00000000ull) { - v >>= 32; - r |= 32; - } - if (v & 0xFFFF0000) { - v >>= 16; - r |= 16; - } - if (v & 0xFF00) { - v >>= 8; - r |= 8; - } - if (v & 0xF0) { - v >>= 4; - r |= 4; - } - if (v & 0xC) { - v >>= 2; - r |= 2; - } - if (v & 0x2) { - v >>= 1; - r |= 1; - } - return r; -} - bool product_iterator_next(unsigned n, unsigned const * sz, unsigned * it) { for (unsigned i = 0; i < n; ++i) { it[i]++; diff --git a/src/util/util.h b/src/util/util.h index d580209e9..8146ac0d2 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -21,6 +21,7 @@ Revision History: #include "util/debug.h" #include "util/memory_manager.h" #include +#include #include #include #include @@ -80,7 +81,8 @@ static_assert(sizeof(int64_t) == 8, "64 bits"); # define Z3_fallthrough #endif -static inline bool is_power_of_two(unsigned v) { return !(v & (v - 1)) && v; } +static inline bool is_power_of_two(unsigned v) { return std::has_single_bit(v); } +static inline bool is_power_of_two(uint64_t v) { return std::has_single_bit(v); } /** \brief Return the next power of two that is greater than or equal to v. @@ -101,8 +103,8 @@ static inline unsigned next_power_of_two(unsigned v) { /** \brief Return the position of the most significant bit. */ -unsigned log2(unsigned v); -unsigned uint64_log2(uint64_t v); +static inline unsigned log2(unsigned v) { return std::bit_width(x) - 1; } +static inline unsigned log2(uint64_t v) { return std::bit_width(x) - 1; } static_assert(sizeof(unsigned) == 4, "unsigned are 32 bits");