3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-11-04 05:19:11 +00:00

fixup bv operators

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2025-11-03 07:56:42 -08:00
parent 919ac515bc
commit 88269edd4b
3 changed files with 43 additions and 10 deletions

View file

@ -636,6 +636,10 @@ void arith_decl_plugin::get_op_names(svector<builtin_name>& op_names, symbol con
op_names.push_back(builtin_name("/0",OP_DIV0)); op_names.push_back(builtin_name("/0",OP_DIV0));
op_names.push_back(builtin_name("div0",OP_IDIV0)); op_names.push_back(builtin_name("div0",OP_IDIV0));
op_names.push_back(builtin_name("mod0",OP_MOD0)); op_names.push_back(builtin_name("mod0",OP_MOD0));
op_names.push_back(builtin_name(bv_symbol(OP_ARITH_BAND).bare_str(), OP_ARITH_BAND));
op_names.push_back(builtin_name(bv_symbol(OP_ARITH_SHL).bare_str(), OP_ARITH_SHL));
op_names.push_back(builtin_name(bv_symbol(OP_ARITH_LSHR).bare_str(), OP_ARITH_LSHR));
op_names.push_back(builtin_name(bv_symbol(OP_ARITH_ASHR).bare_str(), OP_ARITH_ASHR));
} }
} }
@ -643,7 +647,7 @@ bool arith_decl_plugin::is_value(app * e) const {
return return
is_app_of(e, m_family_id, OP_NUM) || is_app_of(e, m_family_id, OP_NUM) ||
is_app_of(e, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM) || is_app_of(e, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM) ||
is_app_of(e, m_family_id, OP_PI) || is_app_of(e, m_family_id, OP_PI) ||
is_app_of(e, m_family_id, OP_E); is_app_of(e, m_family_id, OP_E);
} }

View file

@ -1600,8 +1600,13 @@ br_status arith_rewriter::mk_lshr_core(unsigned sz, expr* arg1, expr* arg2, expr
N = rational::power_of_two(sz); N = rational::power_of_two(sz);
if (is_num_x) if (is_num_x)
x = mod(x, N); x = mod(x, N);
if (is_num_y && y >= sz) {
result = m_util.mk_int(0);
return BR_DONE;
}
if (is_num_y) if (is_num_y)
y = mod(y, N); y = mod(y, N);
if (is_num_x && x == 0) { if (is_num_x && x == 0) {
result = m_util.mk_int(0); result = m_util.mk_int(0);
return BR_DONE; return BR_DONE;
@ -1619,6 +1624,13 @@ br_status arith_rewriter::mk_lshr_core(unsigned sz, expr* arg1, expr* arg2, expr
} }
return BR_DONE; return BR_DONE;
} }
if (is_num_y) {
result = m_util.mk_mod(arg1, m_util.mk_int(N));
//result = arg1; // unsound
result = m_util.mk_idiv(result, m_util.mk_int(rational::power_of_two(y.get_unsigned())));
return BR_DONE;
}
return BR_FAILED; return BR_FAILED;
} }

View file

@ -2522,11 +2522,15 @@ public:
found_unsupported(n); found_unsupported(n);
return true; return true;
} }
rational N = rational::power_of_two(sz); rational N = rational::power_of_two(sz), r;
valx = mod(valx, N); valx = mod(valx, N);
valy = mod(valy, N); valy = mod(valy, N);
expr_ref x(a.mk_mod(_x, a.mk_int(N)), m); expr_ref x(a.mk_mod(_x, a.mk_int(N)), m);
expr_ref y(a.mk_mod(_y, a.mk_int(N)), m); expr_ref y(a.mk_mod(_y, a.mk_int(N)), m);
if (a.is_numeral(_x, r))
x = a.mk_int(mod(r, N));
if (a.is_numeral(_y, r))
y = a.mk_int(mod(r, N));
SASSERT(0 <= valn && valn < N); SASSERT(0 <= valn && valn < N);
// x mod 2^{i + 1} >= 2^i means the i'th bit is 1. // x mod 2^{i + 1} >= 2^i means the i'th bit is 1.
@ -2559,9 +2563,12 @@ public:
return true; return true;
unsigned k = valy.get_unsigned(); unsigned k = valy.get_unsigned();
sat::literal eq = th.mk_eq(n, a.mk_mod(a.mk_mul(_x, a.mk_int(rational::power_of_two(k))), a.mk_int(N)), false); sat::literal eq = th.mk_eq(n, a.mk_mod(a.mk_mul(_x, a.mk_int(rational::power_of_two(k))), a.mk_int(N)), false);
ctx().mark_as_relevant(eq);
if (ctx().get_assignment(eq) == l_true) if (ctx().get_assignment(eq) == l_true)
return true; return true;
ctx().mk_th_axiom(get_id(), ~th.mk_eq(y, a.mk_int(k), false), eq); sat::literal y_eq_k = th.mk_eq(y, a.mk_int(k), false);
ctx().mark_as_relevant(y_eq_k);
ctx().mk_th_axiom(get_id(), ~y_eq_k, eq);
IF_VERBOSE(2, verbose_stream() << "shl: " << mk_bounded_pp(n, m) << " " << valn << " := " << valx << " << " << valy << "\n"); IF_VERBOSE(2, verbose_stream() << "shl: " << mk_bounded_pp(n, m) << " " << valn << " := " << valx << " << " << valy << "\n");
return false; return false;
} }
@ -2571,10 +2578,12 @@ public:
return true; return true;
unsigned k = valy.get_unsigned(); unsigned k = valy.get_unsigned();
sat::literal eq = th.mk_eq(n, a.mk_idiv(x, a.mk_int(rational::power_of_two(k))), false); sat::literal eq = th.mk_eq(n, a.mk_idiv(x, a.mk_int(rational::power_of_two(k))), false);
ctx().mark_as_relevant(eq);
if (ctx().get_assignment(eq) == l_true) if (ctx().get_assignment(eq) == l_true)
return true; return true;
ctx().mk_th_axiom(get_id(), ~th.mk_eq(y, a.mk_int(k), false), eq); sat::literal y_eq_k = th.mk_eq(y, a.mk_int(k), false);
IF_VERBOSE(2, verbose_stream() << "lshr: " << mk_bounded_pp(n, m) << " " << valn << " := " << valx << " >>l " << valy << "\n"); ctx().mark_as_relevant(y_eq_k);
ctx().mk_th_axiom(get_id(), ~y_eq_k, eq);
return false; return false;
} }
if (a.is_ashr(n)) { if (a.is_ashr(n)) {
@ -2590,6 +2599,7 @@ public:
// x < 0 & y = k -> n = (x div 2^k - 2^{N-k}) mod 2^N // x < 0 & y = k -> n = (x div 2^k - 2^{N-k}) mod 2^N
xdiv2k = a.mk_idiv(x, a.mk_int(rational::power_of_two(k))); xdiv2k = a.mk_idiv(x, a.mk_int(rational::power_of_two(k)));
eq = th.mk_eq(n, a.mk_mod(a.mk_add(xdiv2k, a.mk_int(-rational::power_of_two(sz - k))), a.mk_int(N)), false); eq = th.mk_eq(n, a.mk_mod(a.mk_add(xdiv2k, a.mk_int(-rational::power_of_two(sz - k))), a.mk_int(N)), false);
ctx().mark_as_relevant(eq);
if (ctx().get_assignment(eq) == l_true) if (ctx().get_assignment(eq) == l_true)
return true; return true;
break; break;
@ -2597,6 +2607,7 @@ public:
// x >= 0 & y = k -> n = x div 2^k // x >= 0 & y = k -> n = x div 2^k
xdiv2k = a.mk_idiv(x, a.mk_int(rational::power_of_two(k))); xdiv2k = a.mk_idiv(x, a.mk_int(rational::power_of_two(k)));
eq = th.mk_eq(n, xdiv2k, false); eq = th.mk_eq(n, xdiv2k, false);
ctx().mark_as_relevant(eq);
if (ctx().get_assignment(eq) == l_true) if (ctx().get_assignment(eq) == l_true)
return true; return true;
break; break;
@ -2604,7 +2615,9 @@ public:
ctx().mark_as_relevant(signx); ctx().mark_as_relevant(signx);
return false; return false;
} }
ctx().mk_th_axiom(get_id(), ~th.mk_eq(y, a.mk_int(k), false), ~signx, eq); sat::literal y_eq_k = th.mk_eq(y, a.mk_int(k), false);
ctx().mark_as_relevant(y_eq_k);
ctx().mk_th_axiom(get_id(), ~y_eq_k, ~signx, eq);
return false; return false;
} }
return true; return true;
@ -2622,9 +2635,13 @@ public:
unsigned sz = 0; unsigned sz = 0;
expr* _x = nullptr, * _y = nullptr; expr* _x = nullptr, * _y = nullptr;
VERIFY(a.is_band(n, sz, _x, _y) || a.is_shl(n, sz, _x, _y) || a.is_ashr(n, sz, _x, _y) || a.is_lshr(n, sz, _x, _y)); VERIFY(a.is_band(n, sz, _x, _y) || a.is_shl(n, sz, _x, _y) || a.is_ashr(n, sz, _x, _y) || a.is_lshr(n, sz, _x, _y));
rational N = rational::power_of_two(sz); rational N = rational::power_of_two(sz), r;
expr_ref x(a.mk_mod(_x, a.mk_int(N)), m); expr_ref x(a.mk_mod(_x, a.mk_int(N)), m);
expr_ref y(a.mk_mod(_y, a.mk_int(N)), m); expr_ref y(a.mk_mod(_y, a.mk_int(N)), m);
if (a.is_numeral(_x, r))
x = a.mk_int(mod(r, N));
if (a.is_numeral(_y, r))
y = a.mk_int(mod(r, N));
// 0 <= n < 2^sz // 0 <= n < 2^sz
@ -2657,9 +2674,9 @@ public:
// y >= sz & x >= 2^{sz-1} => n = -1 // y >= sz & x >= 2^{sz-1} => n = -1
// y = 0 => n = x // y = 0 => n = x
auto signx = mk_literal(a.mk_ge(x, a.mk_int(N/2))); auto signx = mk_literal(a.mk_ge(x, a.mk_int(N/2)));
ctx().mk_th_axiom(get_id(), ~mk_literal(a.mk_ge(a.mk_mod(y, a.mk_int(N)), a.mk_int(sz))), signx, mk_literal(m.mk_eq(n, a.mk_int(0)))); ctx().mk_th_axiom(get_id(), ~mk_literal(a.mk_ge(y, a.mk_int(sz))), signx, mk_literal(m.mk_eq(n, a.mk_int(0))));
ctx().mk_th_axiom(get_id(), ~mk_literal(a.mk_ge(a.mk_mod(y, a.mk_int(N)), a.mk_int(sz))), ~signx, mk_literal(m.mk_eq(n, a.mk_int(N-1)))); ctx().mk_th_axiom(get_id(), ~mk_literal(a.mk_ge(y, a.mk_int(sz))), ~signx, mk_literal(m.mk_eq(n, a.mk_int(N-1))));
ctx().mk_th_axiom(get_id(), ~mk_literal(a.mk_eq(a.mk_mod(y, a.mk_int(N)), a.mk_int(0))), mk_literal(m.mk_eq(n, x))); ctx().mk_th_axiom(get_id(), ~mk_literal(a.mk_eq(y, a.mk_int(0))), mk_literal(m.mk_eq(n, x)));
} }
else else
UNREACHABLE(); UNREACHABLE();