From fa73827d9840905ac37745cae06ea82f90302fb8 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 15 Feb 2026 22:09:11 +0000 Subject: [PATCH] fixes --- src/test/memory.cpp | 2 +- src/util/mpz.cpp | 88 +++++++++++++++++---------------------------- src/util/mpz.h | 39 +++++++++----------- 3 files changed, 51 insertions(+), 78 deletions(-) diff --git a/src/test/memory.cpp b/src/test/memory.cpp index 9a8d12b5d..f6c010380 100644 --- a/src/test/memory.cpp +++ b/src/test/memory.cpp @@ -39,7 +39,7 @@ static void hit_me(char const* wm) { Z3_mk_bv_sort(ctx,i); } - catch (std::bad_alloc) { + catch (std::bad_alloc&) { std::cout << "caught\n"; } } diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index ef6f5a3c6..8445ec134 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -17,6 +17,7 @@ Revision History: --*/ #include +#include #include #include #include "util/mpz.h" @@ -25,6 +26,22 @@ Revision History: #include "util/hash.h" #include "util/bit_util.h" +static bool mul_overflows(int64_t a, int64_t b, int64_t & result) { +#if __STDC_VERSION_STDCKDINT_H__ >= 202311L + return std::ckd_mul(&result, a, b); +#elif defined(__GNUC__) + return __builtin_mul_overflow(a, b, &result); +#elif defined(_MSC_VER) + // MSVC _mul128 intrinsic + __int64 high; + result = _mul128(a, b, &high); + // Overflow if high bits are not the sign extension of result + return high != 0 && high != -1; +#else + static_assert(false); +#endif +} + #if defined(_MP_INTERNAL) #include "util/mpn.h" #elif defined(_MP_GMP) @@ -111,22 +128,6 @@ unsigned u_gcd(unsigned u, unsigned v) { return u << shift; } -uint64_t u64_gcd(uint64_t u, uint64_t v) { - if (u == 0) return v; - if (v == 0) return u; - if (u == 1 || v == 1) return 1; - auto shift = _trailing_zeros64(u | v); - u >>= _trailing_zeros64(u); - do { - v >>= _trailing_zeros64(v); - if (u > v) std::swap(u, v); - v -= u; - } - while (v != 0); - return u << shift; -} - - template mpz_manager::mpz_manager(): @@ -375,9 +376,9 @@ void mpz_manager::set(mpz_cell& src, mpz & a, int sign, unsigned sz) { } unsigned d = src.m_digits[0]; - if (i == 1 && d <= mpz::SMALL_INT_MAX) { - // src fits in small integer range - a.set(sign < 0 ? -static_cast(d) : static_cast(d)); + int64_t val = sign < 0 ? -static_cast(d) : static_cast(d); + if (i == 1 && mpz::fits_in_small(val) && a.is_small()) { + a.set(val); return; } @@ -425,6 +426,7 @@ void mpz_manager::set_digits(mpz & target, unsigned sz, digit_t const * d #ifndef _MP_GMP allocate_if_needed(target, sz); memcpy(target.ptr()->m_digits, digits, sizeof(digit_t) * sz); + target.ptr()->m_size = sz; target.set_sign(1); #else mk_big(target); @@ -446,9 +448,10 @@ void mpz_manager::set_digits(mpz & target, unsigned sz, digit_t const * d template void mpz_manager::mul(mpz const & a, mpz const & b, mpz & c) { - STRACE(mpz, tout << "[mpz] " << to_string(a) << " * " << to_string(b) << " == ";); - if (is_small(a) && is_small(b)) { - set(c, a.value() * b.value()); + STRACE(mpz, tout << "[mpz] " << to_string(a) << " * " << to_string(b) << " == ";); + int64_t result; + if (is_small(a) && is_small(b) && !mul_overflows(a.value(), b.value(), result)) { + set(c, result); } else { big_mul(a, b, c); @@ -510,7 +513,7 @@ void mpz_manager::machine_div_rem(mpz const & a, mpz const & b, mpz & q, template void mpz_manager::machine_div(mpz const & a, mpz const & b, mpz & c) { STRACE(mpz, tout << "[mpz-ext] machine-div(" << to_string(a) << ", " << to_string(b) << ") == ";); - if (is_small(b) && b.value() == 0) + if (is_zero(b)) throw default_exception("division by 0"); if (is_small(a) && is_small(b)) @@ -890,12 +893,7 @@ template void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { static_assert(sizeof(mpz) <= 16, "mpz size overflow"); if (is_small(a) && is_small(b)) { - int64_t _a = a.value(); - int64_t _b = b.value(); - if (_a < 0) _a = -_a; - if (_b < 0) _b = -_b; - uint64_t r = u64_gcd(static_cast(_a), static_cast(_b)); - set(c, r); + set(c, std::gcd(a.value(), b.value())); return; } else { @@ -975,7 +973,7 @@ void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { else { while (true) { if (is_uint64(tmp1) && is_uint64(tmp2)) { - set(c, u64_gcd(get_uint64(tmp1), get_uint64(tmp2))); + set(c, std::gcd(get_uint64(tmp1), get_uint64(tmp2))); break; } rem(tmp1, tmp2, aux); @@ -1066,8 +1064,7 @@ void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { SASSERT(ge(a1, b1)); if (is_small(b1)) { if (is_small(a1)) { - uint64_t r = u64_gcd(static_cast(a1.value()), static_cast(b1.value())); - set(c, r); + set(c, std::gcd(a1.value(), b1.value())); break; } else { @@ -1081,12 +1078,12 @@ void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { break; } } - SASSERT(!is_small(a1)); + sign_cell ca(*this, a1); SASSERT(!is_small(b1)); - a_sz = a1.ptr()->m_size; + a_sz = ca.cell()->m_size; b_sz = b1.ptr()->m_size; SASSERT(b_sz <= a_sz); - a_hat = a1.ptr()->m_digits[a_sz - 1]; + a_hat = ca.cell()->m_digits[a_sz - 1]; b_hat = (b_sz == a_sz) ? b1.ptr()->m_digits[b_sz - 1] : 0; A = 1; B = 0; @@ -1499,21 +1496,6 @@ void mpz_manager::bitwise_not(unsigned sz, mpz const & a, mpz & c) { } } -template -void mpz_manager::big_set(mpz & target, mpz const & source) { -#ifndef _MP_GMP - if (&target == &source) - return; - 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); - mpz_set(*target.ptr(), *source.ptr()); -#endif -} - template int mpz_manager::big_compare(mpz const & a, mpz const & b) { #ifndef _MP_GMP @@ -1856,12 +1838,10 @@ void mpz_manager::power(mpz const & a, unsigned p, mpz & b) { unsigned shift = p%(8 * sizeof(digit_t)); SASSERT(sz > 0); allocate_if_needed(b, sz); - SASSERT(b.ptr()->m_capacity >= sz); - b.ptr()->m_size = sz; + b.ptr()->m_size = sz; for (unsigned i = 0; i < sz - 1; ++i) b.ptr()->m_digits[i] = 0; b.ptr()->m_digits[sz-1] = 1 << shift; - // b is already large after allocate_if_needed, just ensure sign is positive b.set_sign(1); } return; @@ -1951,7 +1931,6 @@ void mpz_manager::ensure_capacity(mpz & a, unsigned capacity) { int64_t val = a.value(); uint64_t abs_val = static_cast(-val); allocate_if_needed(a, capacity); - SASSERT(a.ptr()->m_capacity >= capacity); if (sizeof(digit_t) == sizeof(uint64_t)) { a.ptr()->m_digits[0] = static_cast(abs_val); a.ptr()->m_size = 1; @@ -1966,7 +1945,6 @@ void mpz_manager::ensure_capacity(mpz & a, unsigned capacity) { else if (a.ptr()->m_capacity < capacity) { mpz_cell * new_cell = allocate(capacity); unsigned old_sz = a.ptr()->m_size; - SASSERT(capacity >= old_sz); new_cell->m_size = old_sz; memcpy(new_cell->m_digits, digits(a), sizeof(digit_t) * old_sz); bool is_neg = a.sign() < 0; diff --git a/src/util/mpz.h b/src/util/mpz.h index 1e87f29a9..e74da812a 100644 --- a/src/util/mpz.h +++ b/src/util/mpz.h @@ -28,7 +28,6 @@ Revision History: #include "util/mpn.h" unsigned u_gcd(unsigned u, unsigned v); -uint64_t u64_gcd(uint64_t u, uint64_t v); unsigned trailing_zeros(uint64_t); unsigned trailing_zeros(uint32_t); @@ -158,14 +157,8 @@ public: // with values that fit, or the caller should use set_big_i64. SASSERT(fits_in_small(v)); } - - mpz(int v) noexcept : m_value(static_cast(v) << 1) { - SASSERT(fits_in_small(v)); - } - - mpz(unsigned v) noexcept : m_value(static_cast(v) << 1) { - SASSERT(fits_in_small(v)); - } + mpz(int v) : mpz(int64_t(v)) {} + mpz(unsigned v) : mpz(int64_t(v)) {} mpz(mpz_type* ptr) noexcept { set_ptr(ptr, false, true); // external pointer, non-negative @@ -364,7 +357,7 @@ class mpz_manager { class sign_cell { static const unsigned capacity = 2; - unsigned char m_bytes[sizeof(mpz_cell) + sizeof(digit_t) * capacity]; + alignas(8) unsigned char m_bytes[sizeof(mpz_cell) + sizeof(digit_t) * capacity]; mpz m_local; mpz const& m_a; int m_sign; @@ -431,8 +424,6 @@ class mpz_manager { void big_mul(mpz const & a, mpz const & b, mpz & c); - void big_set(mpz & target, mpz const & source); - #ifndef _MP_GMP #define QUOT_ONLY 0 @@ -511,11 +502,15 @@ public: static bool is_neg(mpz const & a) { return sign(a) < 0; } - static bool is_zero(mpz const & a) { return sign(a) == 0; } + static bool is_zero(mpz const & a) { + if (a.is_small()) + return a.value() == 0; + return size(a) == 1 && digits(a)[0] == 0; + } static int sign(mpz const & a) { if (is_small(a)) { - int v = a.value(); + int64_t v = a.value(); return (v > 0) - (v < 0); // Returns -1, 0, or 1 } else @@ -597,10 +592,10 @@ public: void set(mpz & target, mpz const & source) { if (is_small(source)) { - target.set(source.value()); + set(target, source.value()); } else { - big_set(target, source); + set(*source.ptr(), target, source.sign(), size(source)); } } @@ -685,21 +680,21 @@ public: static unsigned hash(mpz const & a); static bool is_one(mpz const & a) { -#ifndef _MP_GMP - return is_small(a) && a.value() == 1; -#else if (is_small(a)) return a.value() == 1; +#ifndef _MP_GMP + return size(a) == 1 && digits(a)[0] == 1 && a.sign() > 0; +#else return mpz_cmp_si(*a.ptr(), 1) == 0; #endif } static bool is_minus_one(mpz const & a) { -#ifndef _MP_GMP - return is_small(a) && a.value() == -1; -#else if (is_small(a)) return a.value() == -1; +#ifndef _MP_GMP + return size(a) == 1 && digits(a)[0] == 1 && a.sign() < 0; +#else return mpz_cmp_si(*a.ptr(), -1) == 0; #endif }