Skip to content

Commit d0a59f3

Browse files
intblast with lazy expansion of shl, ashr, lshr
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
1 parent 50e0fd3 commit d0a59f3

10 files changed

+321
-83
lines changed

src/ast/arith_decl_plugin.cpp

+17-4
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,19 @@ static bool is_const_op(decl_kind k) {
508508
//k == OP_0_PW_0_REAL;
509509
}
510510

511+
symbol arith_decl_plugin::bv_symbol(decl_kind k) const {
512+
switch (k) {
513+
case OP_ARITH_BAND: return symbol("band");
514+
case OP_ARITH_SHL: return symbol("shl");
515+
case OP_ARITH_ASHR: return symbol("ashr");
516+
case OP_ARITH_LSHR: return symbol("lshr");
517+
default:
518+
UNREACHABLE();
519+
}
520+
return symbol();
521+
}
522+
523+
511524
func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
512525
unsigned arity, sort * const * domain, sort * range) {
513526
if (k == OP_NUM)
@@ -523,10 +536,10 @@ func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
523536
return m_manager->mk_func_decl(symbol("divisible"), 1, &m_int_decl, m_manager->mk_bool_sort(),
524537
func_decl_info(m_family_id, k, num_parameters, parameters));
525538
}
526-
if (k == OP_ARITH_BAND) {
539+
if (k == OP_ARITH_BAND || k == OP_ARITH_SHL || k == OP_ARITH_ASHR || k == OP_ARITH_LSHR) {
527540
if (arity != 2 || domain[0] != m_int_decl || domain[1] != m_int_decl || num_parameters != 1 || !parameters[0].is_int())
528541
m_manager->raise_exception("invalid bitwise and application. Expects integer parameter and two arguments of sort integer");
529-
return m_manager->mk_func_decl(symbol("band"), 2, domain, m_int_decl,
542+
return m_manager->mk_func_decl(bv_symbol(k), 2, domain, m_int_decl,
530543
func_decl_info(m_family_id, k, num_parameters, parameters));
531544
}
532545

@@ -554,11 +567,11 @@ func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
554567
return m_manager->mk_func_decl(symbol("divisible"), 1, &m_int_decl, m_manager->mk_bool_sort(),
555568
func_decl_info(m_family_id, k, num_parameters, parameters));
556569
}
557-
if (k == OP_ARITH_BAND) {
570+
if (k == OP_ARITH_BAND || k == OP_ARITH_SHL || k == OP_ARITH_ASHR || k == OP_ARITH_LSHR) {
558571
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())
559572
m_manager->raise_exception("invalid bitwise and application. Expects integer parameter and two arguments of sort integer");
560573
sort* domain[2] = { m_int_decl, m_int_decl };
561-
return m_manager->mk_func_decl(symbol("band"), 2, domain, m_int_decl,
574+
return m_manager->mk_func_decl(bv_symbol(k), 2, domain, m_int_decl,
562575
func_decl_info(m_family_id, k, num_parameters, parameters));
563576
}
564577

src/ast/arith_decl_plugin.h

+23-8
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ enum arith_op_kind {
7272
OP_ATANH,
7373
// Bit-vector functions
7474
OP_ARITH_BAND,
75+
OP_ARITH_SHL,
76+
OP_ARITH_ASHR,
77+
OP_ARITH_LSHR,
7578
// constants
7679
OP_PI,
7780
OP_E,
@@ -150,6 +153,8 @@ class arith_decl_plugin : public decl_plugin {
150153

151154
bool m_convert_int_numerals_to_real;
152155

156+
symbol bv_symbol(decl_kind k) const;
157+
153158
func_decl * mk_func_decl(decl_kind k, bool is_real);
154159
void set_manager(ast_manager * m, family_id id) override;
155160
decl_kind fix_kind(decl_kind k, unsigned arity);
@@ -233,6 +238,14 @@ class arith_decl_plugin : public decl_plugin {
233238
executed in different threads.
234239
*/
235240
class arith_recognizers {
241+
bool is_arith_op(expr const* n, decl_kind k, unsigned& sz, expr*& x, expr*& y) {
242+
if (!is_app_of(n, arith_family_id, k))
243+
return false;
244+
x = to_app(n)->get_arg(0);
245+
y = to_app(n)->get_arg(1);
246+
sz = to_app(n)->get_parameter(0).get_int();
247+
return true;
248+
}
236249
public:
237250
family_id get_family_id() const { return arith_family_id; }
238251

@@ -296,14 +309,13 @@ class arith_recognizers {
296309
bool is_int_real(expr const * n) const { return is_int_real(n->get_sort()); }
297310

298311
bool is_band(expr const* n) const { return is_app_of(n, arith_family_id, OP_ARITH_BAND); }
299-
bool is_band(expr const* n, unsigned& sz, expr*& x, expr*& y) {
300-
if (!is_band(n))
301-
return false;
302-
x = to_app(n)->get_arg(0);
303-
y = to_app(n)->get_arg(1);
304-
sz = to_app(n)->get_parameter(0).get_int();
305-
return true;
306-
}
312+
bool is_band(expr const* n, unsigned& sz, expr*& x, expr*& y) { return is_arith_op(n, OP_ARITH_BAND, sz, x, y); }
313+
bool is_shl(expr const* n) const { return is_app_of(n, arith_family_id, OP_ARITH_SHL); }
314+
bool is_shl(expr const* n, unsigned& sz, expr*& x, expr*& y) { return is_arith_op(n, OP_ARITH_SHL, sz, x, y); }
315+
bool is_lshr(expr const* n) const { return is_app_of(n, arith_family_id, OP_ARITH_LSHR); }
316+
bool is_lshr(expr const* n, unsigned& sz, expr*& x, expr*& y) { return is_arith_op(n, OP_ARITH_LSHR, sz, x, y); }
317+
bool is_ashr(expr const* n) const { return is_app_of(n, arith_family_id, OP_ARITH_ASHR); }
318+
bool is_ashr(expr const* n, unsigned& sz, expr*& x, expr*& y) { return is_arith_op(n, OP_ARITH_ASHR, sz, x, y); }
307319

308320
bool is_sin(expr const* n) const { return is_app_of(n, arith_family_id, OP_SIN); }
309321
bool is_cos(expr const* n) const { return is_app_of(n, arith_family_id, OP_COS); }
@@ -487,6 +499,9 @@ class arith_util : public arith_recognizers {
487499
app * mk_power0(expr* arg1, expr* arg2) { return m_manager.mk_app(arith_family_id, OP_POWER0, arg1, arg2); }
488500

489501
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); }
502+
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); }
503+
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); }
504+
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); }
490505

491506
app * mk_sin(expr * arg) { return m_manager.mk_app(arith_family_id, OP_SIN, arg); }
492507
app * mk_cos(expr * arg) { return m_manager.mk_app(arith_family_id, OP_COS, arg); }

src/ast/rewriter/arith_rewriter.cpp

+103
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ br_status arith_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c
9292
case OP_COSH: SASSERT(num_args == 1); st = mk_cosh_core(args[0], result); break;
9393
case OP_TANH: SASSERT(num_args == 1); st = mk_tanh_core(args[0], result); break;
9494
case OP_ARITH_BAND: SASSERT(num_args == 2); st = mk_band_core(f->get_parameter(0).get_int(), args[0], args[1], result); break;
95+
case OP_ARITH_SHL: SASSERT(num_args == 2); st = mk_shl_core(f->get_parameter(0).get_int(), args[0], args[1], result); break;
96+
case OP_ARITH_ASHR: SASSERT(num_args == 2); st = mk_ashr_core(f->get_parameter(0).get_int(), args[0], args[1], result); break;
97+
case OP_ARITH_LSHR: SASSERT(num_args == 2); st = mk_lshr_core(f->get_parameter(0).get_int(), args[0], args[1], result); break;
9598
default: st = BR_FAILED; break;
9699
}
97100
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) {
13501353
return y;
13511354
}
13521355

1356+
br_status arith_rewriter::mk_shl_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result) {
1357+
numeral x, y, N;
1358+
bool is_num_x = m_util.is_numeral(arg1, x);
1359+
bool is_num_y = m_util.is_numeral(arg2, y);
1360+
N = rational::power_of_two(sz);
1361+
if (is_num_x)
1362+
x = mod(x, N);
1363+
if (is_num_y)
1364+
y = mod(y, N);
1365+
if (is_num_x && is_num_y) {
1366+
if (y >= sz)
1367+
result = m_util.mk_int(0);
1368+
else
1369+
result = m_util.mk_int(mod(x * rational::power_of_two(y.get_unsigned()), N));
1370+
return BR_DONE;
1371+
}
1372+
if (is_num_y) {
1373+
if (y >= sz)
1374+
result = m_util.mk_int(0);
1375+
else
1376+
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));
1377+
return BR_REWRITE1;
1378+
}
1379+
if (is_num_x && x == 0) {
1380+
result = m_util.mk_int(0);
1381+
return BR_DONE;
1382+
}
1383+
return BR_FAILED;
1384+
}
1385+
br_status arith_rewriter::mk_ashr_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result) {
1386+
numeral x, y, N;
1387+
bool is_num_x = m_util.is_numeral(arg1, x);
1388+
bool is_num_y = m_util.is_numeral(arg2, y);
1389+
N = rational::power_of_two(sz);
1390+
if (is_num_x)
1391+
x = mod(x, N);
1392+
if (is_num_y)
1393+
y = mod(y, N);
1394+
if (is_num_x && x == 0) {
1395+
result = m_util.mk_int(0);
1396+
return BR_DONE;
1397+
}
1398+
if (is_num_x && is_num_y) {
1399+
bool signx = x >= N/2;
1400+
rational d = div(x, rational::power_of_two(y.get_unsigned()));
1401+
SASSERT(y >= 0);
1402+
if (signx) {
1403+
if (y >= sz)
1404+
result = m_util.mk_int(N-1);
1405+
else
1406+
result = m_util.mk_int(d);
1407+
}
1408+
else {
1409+
if (y >= sz)
1410+
result = m_util.mk_int(0);
1411+
else
1412+
result = m_util.mk_int(mod(d - rational::power_of_two(sz - y.get_unsigned()), N));
1413+
}
1414+
return BR_DONE;
1415+
}
1416+
return BR_FAILED;
1417+
}
1418+
1419+
br_status arith_rewriter::mk_lshr_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result) {
1420+
numeral x, y, N;
1421+
bool is_num_x = m_util.is_numeral(arg1, x);
1422+
bool is_num_y = m_util.is_numeral(arg2, y);
1423+
N = rational::power_of_two(sz);
1424+
if (is_num_x)
1425+
x = mod(x, N);
1426+
if (is_num_y)
1427+
y = mod(y, N);
1428+
if (is_num_x && x == 0) {
1429+
result = m_util.mk_int(0);
1430+
return BR_DONE;
1431+
}
1432+
if (is_num_y && y == 0) {
1433+
result = arg1;
1434+
return BR_DONE;
1435+
}
1436+
if (is_num_x && is_num_y) {
1437+
if (y >= sz)
1438+
result = m_util.mk_int(N-1);
1439+
else {
1440+
rational d = div(x, rational::power_of_two(y.get_unsigned()));
1441+
result = m_util.mk_int(d);
1442+
}
1443+
return BR_DONE;
1444+
}
1445+
return BR_FAILED;
1446+
}
1447+
13531448
br_status arith_rewriter::mk_band_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result) {
13541449
numeral x, y, N;
13551450
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
13751470
result = m_util.mk_int(r);
13761471
return BR_DONE;
13771472
}
1473+
if (is_num_x && (x + 1).is_power_of_two()) {
1474+
result = m_util.mk_mod(arg2, m_util.mk_int(x + 1));
1475+
return BR_REWRITE1;
1476+
}
1477+
if (is_num_y && (y + 1).is_power_of_two()) {
1478+
result = m_util.mk_mod(arg1, m_util.mk_int(y + 1));
1479+
return BR_REWRITE1;
1480+
}
13781481
return BR_FAILED;
13791482
}
13801483

src/ast/rewriter/arith_rewriter.h

+3
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ class arith_rewriter : public poly_rewriter<arith_rewriter_core> {
160160
br_status mk_rem_core(expr * arg1, expr * arg2, expr_ref & result);
161161
br_status mk_power_core(expr* arg1, expr* arg2, expr_ref & result);
162162
br_status mk_band_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result);
163+
br_status mk_shl_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result);
164+
br_status mk_lshr_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result);
165+
br_status mk_ashr_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result);
163166
void mk_div(expr * arg1, expr * arg2, expr_ref & result) {
164167
if (mk_div_core(arg1, arg2, result) == BR_FAILED)
165168
result = m.mk_app(get_fid(), OP_DIV, arg1, arg2);

src/math/lp/lp_api.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ namespace lp_api {
108108
unsigned m_gomory_cuts;
109109
unsigned m_assume_eqs;
110110
unsigned m_branch;
111-
unsigned m_band_axioms;
111+
unsigned m_bv_axioms;
112112
stats() { reset(); }
113113
void reset() {
114114
memset(this, 0, sizeof(*this));
@@ -129,7 +129,7 @@ namespace lp_api {
129129
st.update("arith-gomory-cuts", m_gomory_cuts);
130130
st.update("arith-assume-eqs", m_assume_eqs);
131131
st.update("arith-branch", m_branch);
132-
st.update("arith-band-axioms", m_band_axioms);
132+
st.update("arith-bv-axioms", m_bv_axioms);
133133
}
134134
};
135135

0 commit comments

Comments
 (0)