mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 17:15:31 +00:00
intblast with lazy expansion of shl, ashr, lshr
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
50e0fd3ba6
commit
d0a59f3740
10 changed files with 321 additions and 83 deletions
|
@ -508,6 +508,19 @@ static bool is_const_op(decl_kind k) {
|
|||
//k == OP_0_PW_0_REAL;
|
||||
}
|
||||
|
||||
symbol arith_decl_plugin::bv_symbol(decl_kind k) const {
|
||||
switch (k) {
|
||||
case OP_ARITH_BAND: return symbol("band");
|
||||
case OP_ARITH_SHL: return symbol("shl");
|
||||
case OP_ARITH_ASHR: return symbol("ashr");
|
||||
case OP_ARITH_LSHR: return symbol("lshr");
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return symbol();
|
||||
}
|
||||
|
||||
|
||||
func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
if (k == OP_NUM)
|
||||
|
@ -523,10 +536,10 @@ func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
|
|||
return m_manager->mk_func_decl(symbol("divisible"), 1, &m_int_decl, m_manager->mk_bool_sort(),
|
||||
func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||
}
|
||||
if (k == OP_ARITH_BAND) {
|
||||
if (k == OP_ARITH_BAND || k == OP_ARITH_SHL || k == OP_ARITH_ASHR || k == OP_ARITH_LSHR) {
|
||||
if (arity != 2 || domain[0] != m_int_decl || domain[1] != m_int_decl || num_parameters != 1 || !parameters[0].is_int())
|
||||
m_manager->raise_exception("invalid bitwise and application. Expects integer parameter and two arguments of sort integer");
|
||||
return m_manager->mk_func_decl(symbol("band"), 2, domain, m_int_decl,
|
||||
return m_manager->mk_func_decl(bv_symbol(k), 2, domain, m_int_decl,
|
||||
func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||
}
|
||||
|
||||
|
@ -554,11 +567,11 @@ func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
|
|||
return m_manager->mk_func_decl(symbol("divisible"), 1, &m_int_decl, m_manager->mk_bool_sort(),
|
||||
func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||
}
|
||||
if (k == OP_ARITH_BAND) {
|
||||
if (k == OP_ARITH_BAND || k == OP_ARITH_SHL || k == OP_ARITH_ASHR || k == OP_ARITH_LSHR) {
|
||||
if (num_args != 2 || args[0]->get_sort() != m_int_decl || args[1]->get_sort() != m_int_decl || num_parameters != 1 || !parameters[0].is_int())
|
||||
m_manager->raise_exception("invalid bitwise and application. Expects integer parameter and two arguments of sort integer");
|
||||
sort* domain[2] = { m_int_decl, m_int_decl };
|
||||
return m_manager->mk_func_decl(symbol("band"), 2, domain, m_int_decl,
|
||||
return m_manager->mk_func_decl(bv_symbol(k), 2, domain, m_int_decl,
|
||||
func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||
}
|
||||
|
||||
|
|
|
@ -72,6 +72,9 @@ enum arith_op_kind {
|
|||
OP_ATANH,
|
||||
// Bit-vector functions
|
||||
OP_ARITH_BAND,
|
||||
OP_ARITH_SHL,
|
||||
OP_ARITH_ASHR,
|
||||
OP_ARITH_LSHR,
|
||||
// constants
|
||||
OP_PI,
|
||||
OP_E,
|
||||
|
@ -150,6 +153,8 @@ protected:
|
|||
|
||||
bool m_convert_int_numerals_to_real;
|
||||
|
||||
symbol bv_symbol(decl_kind k) const;
|
||||
|
||||
func_decl * mk_func_decl(decl_kind k, bool is_real);
|
||||
void set_manager(ast_manager * m, family_id id) override;
|
||||
decl_kind fix_kind(decl_kind k, unsigned arity);
|
||||
|
@ -233,6 +238,14 @@ public:
|
|||
executed in different threads.
|
||||
*/
|
||||
class arith_recognizers {
|
||||
bool is_arith_op(expr const* n, decl_kind k, unsigned& sz, expr*& x, expr*& y) {
|
||||
if (!is_app_of(n, arith_family_id, k))
|
||||
return false;
|
||||
x = to_app(n)->get_arg(0);
|
||||
y = to_app(n)->get_arg(1);
|
||||
sz = to_app(n)->get_parameter(0).get_int();
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
family_id get_family_id() const { return arith_family_id; }
|
||||
|
||||
|
@ -296,14 +309,13 @@ public:
|
|||
bool is_int_real(expr const * n) const { return is_int_real(n->get_sort()); }
|
||||
|
||||
bool is_band(expr const* n) const { return is_app_of(n, arith_family_id, OP_ARITH_BAND); }
|
||||
bool is_band(expr const* n, unsigned& sz, expr*& x, expr*& y) {
|
||||
if (!is_band(n))
|
||||
return false;
|
||||
x = to_app(n)->get_arg(0);
|
||||
y = to_app(n)->get_arg(1);
|
||||
sz = to_app(n)->get_parameter(0).get_int();
|
||||
return true;
|
||||
}
|
||||
bool is_band(expr const* n, unsigned& sz, expr*& x, expr*& y) { return is_arith_op(n, OP_ARITH_BAND, sz, x, y); }
|
||||
bool is_shl(expr const* n) const { return is_app_of(n, arith_family_id, OP_ARITH_SHL); }
|
||||
bool is_shl(expr const* n, unsigned& sz, expr*& x, expr*& y) { return is_arith_op(n, OP_ARITH_SHL, sz, x, y); }
|
||||
bool is_lshr(expr const* n) const { return is_app_of(n, arith_family_id, OP_ARITH_LSHR); }
|
||||
bool is_lshr(expr const* n, unsigned& sz, expr*& x, expr*& y) { return is_arith_op(n, OP_ARITH_LSHR, sz, x, y); }
|
||||
bool is_ashr(expr const* n) const { return is_app_of(n, arith_family_id, OP_ARITH_ASHR); }
|
||||
bool is_ashr(expr const* n, unsigned& sz, expr*& x, expr*& y) { return is_arith_op(n, OP_ARITH_ASHR, sz, x, y); }
|
||||
|
||||
bool is_sin(expr const* n) const { return is_app_of(n, arith_family_id, OP_SIN); }
|
||||
bool is_cos(expr const* n) const { return is_app_of(n, arith_family_id, OP_COS); }
|
||||
|
@ -487,6 +499,9 @@ public:
|
|||
app * mk_power0(expr* arg1, expr* arg2) { return m_manager.mk_app(arith_family_id, OP_POWER0, arg1, arg2); }
|
||||
|
||||
app* mk_band(unsigned n, expr* arg1, expr* arg2) { parameter p(n); expr* args[2] = { arg1, arg2 }; return m_manager.mk_app(arith_family_id, OP_ARITH_BAND, 1, &p, 2, args); }
|
||||
app* mk_shl(unsigned n, expr* arg1, expr* arg2) { parameter p(n); expr* args[2] = { arg1, arg2 }; return m_manager.mk_app(arith_family_id, OP_ARITH_SHL, 1, &p, 2, args); }
|
||||
app* mk_ashr(unsigned n, expr* arg1, expr* arg2) { parameter p(n); expr* args[2] = { arg1, arg2 }; return m_manager.mk_app(arith_family_id, OP_ARITH_ASHR, 1, &p, 2, args); }
|
||||
app* mk_lshr(unsigned n, expr* arg1, expr* arg2) { parameter p(n); expr* args[2] = { arg1, arg2 }; return m_manager.mk_app(arith_family_id, OP_ARITH_LSHR, 1, &p, 2, args); }
|
||||
|
||||
app * mk_sin(expr * arg) { return m_manager.mk_app(arith_family_id, OP_SIN, arg); }
|
||||
app * mk_cos(expr * arg) { return m_manager.mk_app(arith_family_id, OP_COS, arg); }
|
||||
|
|
|
@ -92,6 +92,9 @@ br_status arith_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c
|
|||
case OP_COSH: SASSERT(num_args == 1); st = mk_cosh_core(args[0], result); break;
|
||||
case OP_TANH: SASSERT(num_args == 1); st = mk_tanh_core(args[0], result); break;
|
||||
case OP_ARITH_BAND: SASSERT(num_args == 2); st = mk_band_core(f->get_parameter(0).get_int(), args[0], args[1], result); break;
|
||||
case OP_ARITH_SHL: SASSERT(num_args == 2); st = mk_shl_core(f->get_parameter(0).get_int(), args[0], args[1], result); break;
|
||||
case OP_ARITH_ASHR: SASSERT(num_args == 2); st = mk_ashr_core(f->get_parameter(0).get_int(), args[0], args[1], result); break;
|
||||
case OP_ARITH_LSHR: SASSERT(num_args == 2); st = mk_lshr_core(f->get_parameter(0).get_int(), args[0], args[1], result); break;
|
||||
default: st = BR_FAILED; break;
|
||||
}
|
||||
CTRACE("arith_rewriter", st != BR_FAILED, tout << st << ": " << mk_pp(f, m);
|
||||
|
@ -1350,6 +1353,98 @@ app* arith_rewriter_core::mk_power(expr* x, rational const& r, sort* s) {
|
|||
return y;
|
||||
}
|
||||
|
||||
br_status arith_rewriter::mk_shl_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result) {
|
||||
numeral x, y, N;
|
||||
bool is_num_x = m_util.is_numeral(arg1, x);
|
||||
bool is_num_y = m_util.is_numeral(arg2, y);
|
||||
N = rational::power_of_two(sz);
|
||||
if (is_num_x)
|
||||
x = mod(x, N);
|
||||
if (is_num_y)
|
||||
y = mod(y, N);
|
||||
if (is_num_x && is_num_y) {
|
||||
if (y >= sz)
|
||||
result = m_util.mk_int(0);
|
||||
else
|
||||
result = m_util.mk_int(mod(x * rational::power_of_two(y.get_unsigned()), N));
|
||||
return BR_DONE;
|
||||
}
|
||||
if (is_num_y) {
|
||||
if (y >= sz)
|
||||
result = m_util.mk_int(0);
|
||||
else
|
||||
result = m_util.mk_mod(m_util.mk_mul(arg1, m_util.mk_int(rational::power_of_two(y.get_unsigned()))), m_util.mk_int(N));
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
if (is_num_x && x == 0) {
|
||||
result = m_util.mk_int(0);
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
br_status arith_rewriter::mk_ashr_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result) {
|
||||
numeral x, y, N;
|
||||
bool is_num_x = m_util.is_numeral(arg1, x);
|
||||
bool is_num_y = m_util.is_numeral(arg2, y);
|
||||
N = rational::power_of_two(sz);
|
||||
if (is_num_x)
|
||||
x = mod(x, N);
|
||||
if (is_num_y)
|
||||
y = mod(y, N);
|
||||
if (is_num_x && x == 0) {
|
||||
result = m_util.mk_int(0);
|
||||
return BR_DONE;
|
||||
}
|
||||
if (is_num_x && is_num_y) {
|
||||
bool signx = x >= N/2;
|
||||
rational d = div(x, rational::power_of_two(y.get_unsigned()));
|
||||
SASSERT(y >= 0);
|
||||
if (signx) {
|
||||
if (y >= sz)
|
||||
result = m_util.mk_int(N-1);
|
||||
else
|
||||
result = m_util.mk_int(d);
|
||||
}
|
||||
else {
|
||||
if (y >= sz)
|
||||
result = m_util.mk_int(0);
|
||||
else
|
||||
result = m_util.mk_int(mod(d - rational::power_of_two(sz - y.get_unsigned()), N));
|
||||
}
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
br_status arith_rewriter::mk_lshr_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result) {
|
||||
numeral x, y, N;
|
||||
bool is_num_x = m_util.is_numeral(arg1, x);
|
||||
bool is_num_y = m_util.is_numeral(arg2, y);
|
||||
N = rational::power_of_two(sz);
|
||||
if (is_num_x)
|
||||
x = mod(x, N);
|
||||
if (is_num_y)
|
||||
y = mod(y, N);
|
||||
if (is_num_x && x == 0) {
|
||||
result = m_util.mk_int(0);
|
||||
return BR_DONE;
|
||||
}
|
||||
if (is_num_y && y == 0) {
|
||||
result = arg1;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (is_num_x && is_num_y) {
|
||||
if (y >= sz)
|
||||
result = m_util.mk_int(N-1);
|
||||
else {
|
||||
rational d = div(x, rational::power_of_two(y.get_unsigned()));
|
||||
result = m_util.mk_int(d);
|
||||
}
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
br_status arith_rewriter::mk_band_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result) {
|
||||
numeral x, y, N;
|
||||
bool is_num_x = m_util.is_numeral(arg1, x);
|
||||
|
@ -1375,6 +1470,14 @@ br_status arith_rewriter::mk_band_core(unsigned sz, expr* arg1, expr* arg2, expr
|
|||
result = m_util.mk_int(r);
|
||||
return BR_DONE;
|
||||
}
|
||||
if (is_num_x && (x + 1).is_power_of_two()) {
|
||||
result = m_util.mk_mod(arg2, m_util.mk_int(x + 1));
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
if (is_num_y && (y + 1).is_power_of_two()) {
|
||||
result = m_util.mk_mod(arg1, m_util.mk_int(y + 1));
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
|
|
@ -160,6 +160,9 @@ public:
|
|||
br_status mk_rem_core(expr * arg1, expr * arg2, expr_ref & result);
|
||||
br_status mk_power_core(expr* arg1, expr* arg2, expr_ref & result);
|
||||
br_status mk_band_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result);
|
||||
br_status mk_shl_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result);
|
||||
br_status mk_lshr_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result);
|
||||
br_status mk_ashr_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result);
|
||||
void mk_div(expr * arg1, expr * arg2, expr_ref & result) {
|
||||
if (mk_div_core(arg1, arg2, result) == BR_FAILED)
|
||||
result = m.mk_app(get_fid(), OP_DIV, arg1, arg2);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue