mirror of
https://github.com/Z3Prover/z3
synced 2025-06-21 13:23:39 +00:00
bv_bounds: switch from rational to uint64
this limits the analysis to 64-bit BVs, but gives a speedup of up to one order of magnitude
This commit is contained in:
parent
9efc7f4aea
commit
43202572ee
1 changed files with 51 additions and 34 deletions
|
@ -20,9 +20,11 @@ Author:
|
||||||
#include "ctx_simplify_tactic.h"
|
#include "ctx_simplify_tactic.h"
|
||||||
#include "bv_decl_plugin.h"
|
#include "bv_decl_plugin.h"
|
||||||
#include "ast_pp.h"
|
#include "ast_pp.h"
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
static rational uMaxInt(unsigned sz) {
|
static uint64_t uMaxInt(unsigned sz) {
|
||||||
return rational::power_of_two(sz) - rational::one();
|
SASSERT(sz <= 64);
|
||||||
|
return ULLONG_MAX >> (64u - sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -30,26 +32,26 @@ namespace {
|
||||||
struct interval {
|
struct interval {
|
||||||
// l < h: [l, h]
|
// l < h: [l, h]
|
||||||
// l > h: [0, h] U [l, UMAX_INT]
|
// l > h: [0, h] U [l, UMAX_INT]
|
||||||
rational l, h;
|
uint64_t l, h;
|
||||||
unsigned sz;
|
unsigned sz;
|
||||||
bool tight;
|
bool tight;
|
||||||
|
|
||||||
interval() {}
|
interval() {}
|
||||||
interval(const rational& l, const rational& h, unsigned sz, bool tight = false) : l(l), h(h), sz(sz), tight(tight) {
|
interval(uint64_t l, uint64_t h, unsigned sz, bool tight = false) : l(l), h(h), sz(sz), tight(tight) {
|
||||||
// canonicalize full set
|
// canonicalize full set
|
||||||
if (is_wrapped() && l == h + rational::one()) {
|
if (is_wrapped() && l == h + 1) {
|
||||||
this->l = rational::zero();
|
this->l = 0;
|
||||||
this->h = uMaxInt(sz);
|
this->h = uMaxInt(sz);
|
||||||
}
|
}
|
||||||
SASSERT(invariant());
|
SASSERT(invariant());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool invariant() const {
|
bool invariant() const {
|
||||||
return !l.is_neg() && !h.is_neg() && l <= uMaxInt(sz) && h <= uMaxInt(sz) &&
|
return l <= uMaxInt(sz) && h <= uMaxInt(sz) &&
|
||||||
(!is_wrapped() || l != h+rational::one());
|
(!is_wrapped() || l != h+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_full() const { return l.is_zero() && h == uMaxInt(sz); }
|
bool is_full() const { return l == 0 && h == uMaxInt(sz); }
|
||||||
bool is_wrapped() const { return l > h; }
|
bool is_wrapped() const { return l > h; }
|
||||||
bool is_singleton() const { return l == h; }
|
bool is_singleton() const { return l == h; }
|
||||||
|
|
||||||
|
@ -129,18 +131,18 @@ struct interval {
|
||||||
/// return false if negation is empty
|
/// return false if negation is empty
|
||||||
bool negate(interval& result) const {
|
bool negate(interval& result) const {
|
||||||
if (!tight) {
|
if (!tight) {
|
||||||
result = interval(rational::zero(), uMaxInt(sz), true);
|
result = interval(0, uMaxInt(sz), true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_full())
|
if (is_full())
|
||||||
return false;
|
return false;
|
||||||
if (l.is_zero()) {
|
if (l == 0) {
|
||||||
result = interval(h + rational::one(), uMaxInt(sz), sz);
|
result = interval(h + 1, uMaxInt(sz), sz);
|
||||||
} else if (uMaxInt(sz) == h) {
|
} else if (uMaxInt(sz) == h) {
|
||||||
result = interval(rational::zero(), l - rational::one(), sz);
|
result = interval(0, l - 1, sz);
|
||||||
} else {
|
} else {
|
||||||
result = interval(h + rational::one(), l - rational::one(), sz);
|
result = interval(h + 1, l - 1, sz);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -171,47 +173,57 @@ class bv_bounds_simplifier : public ctx_simplify_tactic::simplifier {
|
||||||
vector<undo_bound> m_scopes;
|
vector<undo_bound> m_scopes;
|
||||||
map m_bound;
|
map m_bound;
|
||||||
expr_list_map m_expr_vars;
|
expr_list_map m_expr_vars;
|
||||||
|
expr_set m_bound_exprs;
|
||||||
|
|
||||||
|
bool is_number(expr *e, uint64_t& n, unsigned& sz) const {
|
||||||
|
rational r;
|
||||||
|
if (m_bv.is_numeral(e, r, sz) && sz <= 64) {
|
||||||
|
n = r.get_uint64();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_bound(expr *e, expr*& v, interval& b) const {
|
bool is_bound(expr *e, expr*& v, interval& b) const {
|
||||||
rational n;
|
uint64_t n;
|
||||||
expr *lhs, *rhs;
|
expr *lhs, *rhs;
|
||||||
unsigned sz;
|
unsigned sz;
|
||||||
|
|
||||||
if (m_bv.is_bv_ule(e, lhs, rhs)) {
|
if (m_bv.is_bv_ule(e, lhs, rhs)) {
|
||||||
if (m_bv.is_numeral(lhs, n, sz)) { // C ule x <=> x uge C
|
if (is_number(lhs, n, sz)) { // C ule x <=> x uge C
|
||||||
if (m_bv.is_numeral(rhs))
|
if (m_bv.is_numeral(rhs))
|
||||||
return false;
|
return false;
|
||||||
b = interval(n, uMaxInt(sz), sz, true);
|
b = interval(n, uMaxInt(sz), sz, true);
|
||||||
v = rhs;
|
v = rhs;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (m_bv.is_numeral(rhs, n, sz)) { // x ule C
|
if (is_number(rhs, n, sz)) { // x ule C
|
||||||
b = interval(rational::zero(), n, sz, true);
|
b = interval(0, n, sz, true);
|
||||||
v = lhs;
|
v = lhs;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (m_bv.is_bv_sle(e, lhs, rhs)) {
|
} else if (m_bv.is_bv_sle(e, lhs, rhs)) {
|
||||||
if (m_bv.is_numeral(lhs, n, sz)) { // C sle x <=> x sge C
|
if (is_number(lhs, n, sz)) { // C sle x <=> x sge C
|
||||||
if (m_bv.is_numeral(rhs))
|
if (m_bv.is_numeral(rhs))
|
||||||
return false;
|
return false;
|
||||||
b = interval(n, rational::power_of_two(sz-1) - rational::one(), sz, true);
|
b = interval(n, (1ull << (sz-1)) - 1, sz, true);
|
||||||
v = rhs;
|
v = rhs;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (m_bv.is_numeral(rhs, n, sz)) { // x sle C
|
if (is_number(rhs, n, sz)) { // x sle C
|
||||||
b = interval(rational::power_of_two(sz-1), n, sz, true);
|
b = interval(1ull << (sz-1), n, sz, true);
|
||||||
v = lhs;
|
v = lhs;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (m.is_eq(e, lhs, rhs)) {
|
} else if (m.is_eq(e, lhs, rhs)) {
|
||||||
if (m_bv.is_numeral(lhs, n, sz)) {
|
if (is_number(lhs, n, sz)) {
|
||||||
if (m_bv.is_numeral(rhs))
|
if (m_bv.is_numeral(rhs))
|
||||||
return false;
|
return false;
|
||||||
b = interval(n, n, sz, true);
|
b = interval(n, n, sz, true);
|
||||||
v = rhs;
|
v = rhs;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (m_bv.is_numeral(rhs, n, sz)) {
|
if (is_number(rhs, n, sz)) {
|
||||||
b = interval(n, n, sz, true);
|
b = interval(n, n, sz, true);
|
||||||
v = lhs;
|
v = lhs;
|
||||||
return true;
|
return true;
|
||||||
|
@ -245,25 +257,29 @@ class bv_bounds_simplifier : public ctx_simplify_tactic::simplifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool expr_has_bounds(expr* t) {
|
bool expr_has_bounds(expr* t) {
|
||||||
|
bool has_bounds = false;
|
||||||
|
if (m_bound_exprs.find(t, has_bounds))
|
||||||
|
return has_bounds;
|
||||||
|
|
||||||
app* a = to_app(t);
|
app* a = to_app(t);
|
||||||
if ((m_bv.is_bv_ule(t) || m_bv.is_bv_sle(t) || m.is_eq(t)) &&
|
if ((m_bv.is_bv_ule(t) || m_bv.is_bv_sle(t) || m.is_eq(t)) &&
|
||||||
(m_bv.is_numeral(a->get_arg(0)) || m_bv.is_numeral(a->get_arg(1))))
|
(m_bv.is_numeral(a->get_arg(0)) || m_bv.is_numeral(a->get_arg(1)))) {
|
||||||
return true;
|
has_bounds = true;
|
||||||
|
|
||||||
for (unsigned i = 0; i < a->get_num_args(); ++i) {
|
|
||||||
if (expr_has_bounds(a->get_arg(i)))
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
for (unsigned i = 0; !has_bounds && i < a->get_num_args(); ++i) {
|
||||||
|
has_bounds = expr_has_bounds(a->get_arg(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bound_exprs.insert(t, has_bounds);
|
||||||
|
return has_bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
bv_bounds_simplifier(ast_manager& m, params_ref const& p) : m(m), m_params(p), m_bv(m) {
|
bv_bounds_simplifier(ast_manager& m, params_ref const& p) : m(m), m_params(p), m_bv(m) {
|
||||||
updt_params(p);
|
updt_params(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void updt_params(params_ref const & p) {
|
virtual void updt_params(params_ref const & p) {
|
||||||
m_propagate_eq = p.get_bool("propagate_eq", false);
|
m_propagate_eq = p.get_bool("propagate_eq", false);
|
||||||
}
|
}
|
||||||
|
@ -348,7 +364,8 @@ public:
|
||||||
} else if (!b.intersect(ctx, intr)) {
|
} else if (!b.intersect(ctx, intr)) {
|
||||||
result = m.mk_false();
|
result = m.mk_false();
|
||||||
} else if (m_propagate_eq && intr.is_singleton()) {
|
} else if (m_propagate_eq && intr.is_singleton()) {
|
||||||
result = m.mk_eq(t1, m_bv.mk_numeral(intr.l, m.get_sort(t1)));
|
result = m.mk_eq(t1, m_bv.mk_numeral(rational(intr.l, rational::ui64()),
|
||||||
|
m.get_sort(t1)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue