3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-17 08:42:15 +00:00

checkpoint

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2012-10-21 13:32:12 -07:00
parent 4722fdfca5
commit add684d8e9
377 changed files with 204 additions and 62 deletions

View file

@ -0,0 +1,128 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
bit_blaster.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-06-05.
Revision History:
--*/
#include"bit_blaster.h"
#include"bit_blaster_tpl_def.h"
#include"ast_pp.h"
#include"bv_decl_plugin.h"
bit_blaster_cfg::bit_blaster_cfg(bv_util & u, bit_blaster_params const & p, basic_simplifier_plugin & _s):
m_util(u),
m_params(p),
s(_s) {
}
static void sort_args(expr * & l1, expr * & l2, expr * & l3) {
expr * args[3] = {l1, l2, l3};
// ast_lt_proc is based on the AST ids. So, it is a total order on AST nodes.
// No need for stable_sort
std::sort(args, args+3, ast_lt_proc());
l1 = args[0]; l2 = args[1]; l3 = args[2];
}
void bit_blaster_cfg::mk_xor3(expr * l1, expr * l2, expr * l3, expr_ref & r) {
TRACE("xor3", tout << "#" << l1->get_id() << " #" << l2->get_id() << " #" << l3->get_id(););
sort_args(l1, l2, l3);
TRACE("xor3_sorted", tout << "#" << l1->get_id() << " #" << l2->get_id() << " #" << l3->get_id(););
if (m_params.m_bb_ext_gates) {
if (l1 == l2)
r = l3;
else if (l1 == l3)
r = l2;
else if (l2 == l3)
r = l1;
else if (m().is_complement(l1, l2))
s.mk_not(l3, r);
else if (m().is_complement(l1, l3))
s.mk_not(l2, r);
else if (m().is_complement(l2, l3))
s.mk_not(l1, r);
else if (m().is_true(l1))
s.mk_iff(l2, l3, r);
else if (m().is_false(l1))
s.mk_xor(l2, l3, r);
else if (m().is_true(l2))
s.mk_iff(l1, l3, r);
else if (m().is_false(l2))
s.mk_xor(l1, l3, r);
else if (m().is_true(l3))
s.mk_iff(l1, l2, r);
else if (m().is_false(l3))
s.mk_xor(l1, l2, r);
else
r = m().mk_app(m_util.get_family_id(), OP_XOR3, l1, l2, l3);
}
else {
expr_ref t(m());
s.mk_xor(l1, l2, t);
s.mk_xor(t, l3, r);
}
}
void bit_blaster_cfg::mk_carry(expr * l1, expr * l2, expr * l3, expr_ref & r) {
TRACE("carry", tout << "#" << l1->get_id() << " #" << l2->get_id() << " #" << l3->get_id(););
sort_args(l1, l2, l3);
TRACE("carry_sorted", tout << "#" << l1->get_id() << " #" << l2->get_id() << " #" << l3->get_id(););
if (m_params.m_bb_ext_gates) {
if ((m().is_false(l1) && m().is_false(l2)) ||
(m().is_false(l1) && m().is_false(l3)) ||
(m().is_false(l2) && m().is_false(l3)))
r = m().mk_false();
else if ((m().is_true(l1) && m().is_true(l2)) ||
(m().is_true(l1) && m().is_true(l3)) ||
(m().is_true(l2) && m().is_true(l3)))
r = m().mk_true();
else if (l1 == l2 && l1 == l3)
r = l1;
else if (m().is_false(l1))
s.mk_and(l2, l3, r);
else if (m().is_false(l2))
s.mk_and(l1, l3, r);
else if (m().is_false(l3))
s.mk_and(l1, l2, r);
else if (m().is_true(l1))
s.mk_or(l2, l3, r);
else if (m().is_true(l2))
s.mk_or(l1, l3, r);
else if (m().is_true(l3))
s.mk_or(l1, l2, r);
else if (m().is_complement(l1, l2))
r = l3;
else if (m().is_complement(l1, l3))
r = l2;
else if (m().is_complement(l2, l3))
r = l1;
else
r = m().mk_app(m_util.get_family_id(), OP_CARRY, l1, l2, l3);
}
else {
expr_ref t1(m()), t2(m()), t3(m());
s.mk_and(l1, l2, t1);
s.mk_and(l1, l3, t2);
s.mk_and(l2, l3, t3);
s.mk_or(t1, t2, t3, r);
}
}
template class bit_blaster_tpl<bit_blaster_cfg>;
bit_blaster::bit_blaster(ast_manager & m, bit_blaster_params const & params):
bit_blaster_tpl<bit_blaster_cfg>(bit_blaster_cfg(m_util, params, m_simp)),
m_util(m),
m_simp(m) {
}

View file

@ -0,0 +1,65 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
bit_blaster.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-06-05.
Revision History:
--*/
#ifndef _BIT_BLASTER_H_
#define _BIT_BLASTER_H_
#include"basic_simplifier_plugin.h"
#include"bit_blaster_params.h"
#include"bit_blaster_tpl.h"
#include"bv_decl_plugin.h"
#include"rational.h"
class bit_blaster_cfg {
public:
typedef rational numeral;
protected:
bv_util & m_util;
bit_blaster_params const & m_params;
basic_simplifier_plugin & s;
public:
bit_blaster_cfg(bv_util & u, bit_blaster_params const & p, basic_simplifier_plugin & _s);
ast_manager & m() const { return m_util.get_manager(); }
numeral power(unsigned n) const { return m_util.power_of_two(n); }
void mk_xor(expr * a, expr * b, expr_ref & r) { s.mk_xor(a, b, r); }
void mk_xor3(expr * a, expr * b, expr * c, expr_ref & r);
void mk_carry(expr * a, expr * b, expr * c, expr_ref & r);
void mk_iff(expr * a, expr * b, expr_ref & r) { s.mk_iff(a, b, r); }
void mk_and(expr * a, expr * b, expr_ref & r) { s.mk_and(a, b, r); }
void mk_and(expr * a, expr * b, expr * c, expr_ref & r) { s.mk_and(a, b, c, r); }
void mk_and(unsigned sz, expr * const * args, expr_ref & r) { s.mk_and(sz, args, r); }
void mk_or(expr * a, expr * b, expr_ref & r) { s.mk_or(a, b, r); }
void mk_or(expr * a, expr * b, expr * c, expr_ref & r) { s.mk_or(a, b, c, r); }
void mk_or(unsigned sz, expr * const * args, expr_ref & r) { s.mk_or(sz, args, r); }
void mk_not(expr * a, expr_ref & r) { s.mk_not(a, r); }
void mk_ite(expr * c, expr * t, expr * e, expr_ref & r) { s.mk_ite(c, t, e, r); }
void mk_nand(expr * a, expr * b, expr_ref & r) { s.mk_nand(a, b, r); }
void mk_nor(expr * a, expr * b, expr_ref & r) { s.mk_nor(a, b, r); }
};
class bit_blaster : public bit_blaster_tpl<bit_blaster_cfg> {
bv_util m_util;
basic_simplifier_plugin m_simp;
public:
bit_blaster(ast_manager & m, bit_blaster_params const & params);
bit_blaster_params const & get_params() const { return this->m_params; }
};
#endif /* _BIT_BLASTER_H_ */

View file

@ -0,0 +1,187 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
bit_blaster_model_convert.cpp
Abstract:
Model converter for bit-blasting tactics.
Author:
Leonardo (leonardo) 2011-05-09
Notes:
--*/
#include"model.h"
#include"model_pp.h"
#include"model_converter.h"
#include"bv_decl_plugin.h"
#include"ast_smt2_pp.h"
/**
If TO_BOOL == true, then bit-vectors of size n were blasted into n-tuples of Booleans.
If TO_BOOL == false, then bit-vectors of size n were blasted into n-tuples of bit-vectors of size 1.
*/
template<bool TO_BOOL>
struct bit_blaster_model_converter : public model_converter {
func_decl_ref_vector m_vars;
expr_ref_vector m_bits;
ast_manager & m() const { return m_vars.get_manager(); }
bit_blaster_model_converter(ast_manager & m, obj_map<func_decl, expr*> const & const2bits):m_vars(m), m_bits(m) {
obj_map<func_decl, expr*>::iterator it = const2bits.begin();
obj_map<func_decl, expr*>::iterator end = const2bits.end();
for (; it != end; ++it) {
func_decl * v = it->m_key;
expr * bits = it->m_value;
SASSERT(!TO_BOOL || is_app_of(bits, m.get_family_id("bv"), OP_MKBV));
SASSERT(TO_BOOL || is_app_of(bits, m.get_family_id("bv"), OP_CONCAT));
m_vars.push_back(v);
m_bits.push_back(bits);
}
}
virtual ~bit_blaster_model_converter() {
}
void collect_bits(obj_hashtable<func_decl> & bits) {
unsigned sz = m_bits.size();
for (unsigned i = 0; i < sz; i++) {
expr * bs = m_bits.get(i);
SASSERT(!TO_BOOL || is_app_of(bs, m().get_family_id("bv"), OP_MKBV));
SASSERT(TO_BOOL || is_app_of(bs, m().get_family_id("bv"), OP_CONCAT));
unsigned num_args = to_app(bs)->get_num_args();
for (unsigned j = 0; j < num_args; j++) {
expr * bit = to_app(bs)->get_arg(j);
SASSERT(!TO_BOOL || m().is_bool(bit));
SASSERT(TO_BOOL || is_sort_of(m().get_sort(bit), m().get_family_id("bv"), BV_SORT));
SASSERT(is_uninterp_const(bit));
bits.insert(to_app(bit)->get_decl());
}
}
TRACE("blaster_mc",
tout << "bits that should not be included in the model:\n";
obj_hashtable<func_decl>::iterator it = bits.begin();
obj_hashtable<func_decl>::iterator end = bits.end();
for (; it != end; ++it) {
tout << (*it)->get_name() << " ";
}
tout << "\n";);
}
void copy_non_bits(obj_hashtable<func_decl> & bits, model * old_model, model * new_model) {
unsigned num = old_model->get_num_constants();
for (unsigned i = 0; i < num; i++) {
func_decl * f = old_model->get_constant(i);
if (bits.contains(f))
continue;
TRACE("blaster_mc", tout << "non-bit: " << f->get_name() << "\n";);
expr * fi = old_model->get_const_interp(f);
new_model->register_decl(f, fi);
}
TRACE("blaster_mc", tout << "after copy non bits:\n"; model_pp(tout, *new_model););
new_model->copy_func_interps(*old_model);
new_model->copy_usort_interps(*old_model);
TRACE("blaster_mc", tout << "after copying functions and sorts:\n"; model_pp(tout, *new_model););
}
void mk_bvs(model * old_model, model * new_model) {
bv_util util(m());
rational val;
rational two(2);
SASSERT(m_vars.size() == m_bits.size());
unsigned sz = m_vars.size();
for (unsigned i = 0; i < sz; i++) {
expr * bs = m_bits.get(i);
val.reset();
unsigned bv_sz = to_app(bs)->get_num_args();
if (TO_BOOL) {
SASSERT(is_app_of(bs, m().get_family_id("bv"), OP_MKBV));
unsigned j = bv_sz;
while (j > 0) {
--j;
val *= two;
expr * bit = to_app(bs)->get_arg(j);
SASSERT(m().is_bool(bit));
SASSERT(is_uninterp_const(bit));
func_decl * bit_decl = to_app(bit)->get_decl();
expr * bit_val = old_model->get_const_interp(bit_decl);
// remark: if old_model does not assign bit_val, then assume it is false.
if (bit_val != 0 && m().is_true(bit_val))
val++;
}
}
else {
SASSERT(is_app_of(bs, m().get_family_id("bv"), OP_CONCAT));
for (unsigned j = 0; j < bv_sz; j++) {
val *= two;
expr * bit = to_app(bs)->get_arg(j);
SASSERT(util.is_bv(bit));
SASSERT(util.get_bv_size(bit) == 1);
SASSERT(is_uninterp_const(bit));
func_decl * bit_decl = to_app(bit)->get_decl();
expr * bit_val = old_model->get_const_interp(bit_decl);
// remark: if old_model does not assign bit_val, then assume it is false.
if (bit_val != 0 && !util.is_zero(bit_val))
val++;
}
}
expr * new_val = util.mk_numeral(val, bv_sz);
new_model->register_decl(m_vars.get(i), new_val);
}
}
virtual void operator()(model_ref & md, unsigned goal_idx) {
SASSERT(goal_idx == 0);
model * new_model = alloc(model, m());
obj_hashtable<func_decl> bits;
collect_bits(bits);
copy_non_bits(bits, md.get(), new_model);
mk_bvs(md.get(), new_model);
md = new_model;
}
virtual void operator()(model_ref & md) {
operator()(md, 0);
}
virtual void display(std::ostream & out) {
out << "(bit-blaster-model-converter";
unsigned sz = m_vars.size();
for (unsigned i = 0; i < sz; i++) {
out << "\n (" << m_vars.get(i)->get_name() << " ";
unsigned indent = m_vars.get(i)->get_name().size() + 4;
out << mk_ismt2_pp(m_bits.get(i), m(), indent) << ")";
}
out << ")" << std::endl;
}
protected:
bit_blaster_model_converter(ast_manager & m):m_vars(m), m_bits(m) { }
public:
virtual model_converter * translate(ast_translation & translator) {
bit_blaster_model_converter * res = alloc(bit_blaster_model_converter, translator.to());
for (unsigned i = 0; i < m_vars.size(); i++)
res->m_vars.push_back(translator(m_vars[i].get()));
for (unsigned i = 0; i < m_bits.size(); i++)
res->m_bits.push_back(translator(m_bits[i].get()));
return res;
}
};
model_converter * mk_bit_blaster_model_converter(ast_manager & m, obj_map<func_decl, expr*> const & const2bits) {
return alloc(bit_blaster_model_converter<true>, m, const2bits);
}
model_converter * mk_bv1_blaster_model_converter(ast_manager & m, obj_map<func_decl, expr*> const & const2bits) {
return alloc(bit_blaster_model_converter<false>, m, const2bits);
}

View file

@ -0,0 +1,27 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
bit_blaster_model_convert.h
Abstract:
Model converter for bit-blasting tactics.
Author:
Leonardo (leonardo) 2011-05-09
Notes:
--*/
#ifndef _BIT_BLASTER_MODEL_CONVERTER_H_
#define _BIT_BLASTER_MODEL_CONVERTER_H_
#include"model_converter.h"
model_converter * mk_bit_blaster_model_converter(ast_manager & m, obj_map<func_decl, expr*> const & const2bits);
model_converter * mk_bv1_blaster_model_converter(ast_manager & m, obj_map<func_decl, expr*> const & const2bits);
#endif

View file

@ -0,0 +1,649 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
bit_blaster_rewriter.cpp
Abstract:
Bit-blasting rewriter
Author:
Leonardo (leonardo) 2012-10-04
Notes:
--*/
#include"bit_blaster_rewriter.h"
#include"bv_decl_plugin.h"
#include"bit_blaster_tpl_def.h"
#include"rewriter_def.h"
#include"bool_rewriter.h"
#include"ref_util.h"
#include"ast_smt2_pp.h"
struct blaster_cfg {
typedef rational numeral;
bool_rewriter & m_rewriter;
bv_util & m_util;
blaster_cfg(bool_rewriter & r, bv_util & u):m_rewriter(r), m_util(u) {}
ast_manager & m() const { return m_util.get_manager(); }
numeral power(unsigned n) const { return m_util.power_of_two(n); }
void mk_xor(expr * a, expr * b, expr_ref & r) { m_rewriter.mk_xor(a, b, r); }
void mk_xor3(expr * a, expr * b, expr * c, expr_ref & r) {
expr_ref tmp(m());
mk_xor(b, c, tmp);
mk_xor(a, tmp, r);
}
void mk_iff(expr * a, expr * b, expr_ref & r) { m_rewriter.mk_iff(a, b, r); }
void mk_and(expr * a, expr * b, expr_ref & r) { m_rewriter.mk_and(a, b, r); }
void mk_and(expr * a, expr * b, expr * c, expr_ref & r) { m_rewriter.mk_and(a, b, c, r); }
void mk_and(unsigned sz, expr * const * args, expr_ref & r) { m_rewriter.mk_and(sz, args, r); }
void mk_or(expr * a, expr * b, expr_ref & r) { m_rewriter.mk_or(a, b, r); }
void mk_or(expr * a, expr * b, expr * c, expr_ref & r) { m_rewriter.mk_or(a, b, c, r); }
void mk_or(unsigned sz, expr * const * args, expr_ref & r) { m_rewriter.mk_or(sz, args, r); }
void mk_not(expr * a, expr_ref & r) { m_rewriter.mk_not(a, r); }
void mk_carry(expr * a, expr * b, expr * c, expr_ref & r) {
expr_ref t1(m()), t2(m()), t3(m());
#if 1
mk_and(a, b, t1);
mk_and(a, c, t2);
mk_and(b, c, t3);
mk_or(t1, t2, t3, r);
#else
mk_or(a, b, t1);
mk_or(a, c, t2);
mk_or(b, c, t3);
mk_and(t1, t2, t3, r);
#endif
}
void mk_ite(expr * c, expr * t, expr * e, expr_ref & r) { m_rewriter.mk_ite(c, t, e, r); }
void mk_nand(expr * a, expr * b, expr_ref & r) { m_rewriter.mk_nand(a, b, r); }
void mk_nor(expr * a, expr * b, expr_ref & r) { m_rewriter.mk_nor(a, b, r); }
};
// CMW: GCC/LLVM do not like this definition because a symbol of the same name exists in assert_set_bit_blaster.o
// template class bit_blaster_tpl<blaster_cfg>;
class blaster : public bit_blaster_tpl<blaster_cfg> {
bool_rewriter m_rewriter;
bv_util m_util;
public:
blaster(ast_manager & m):
bit_blaster_tpl<blaster_cfg>(blaster_cfg(m_rewriter, m_util)),
m_rewriter(m),
m_util(m) {
m_rewriter.set_flat(false);
m_rewriter.set_elim_and(true);
}
bv_util & butil() { return m_util; }
};
struct blaster_rewriter_cfg : public default_rewriter_cfg {
ast_manager & m_manager;
blaster & m_blaster;
expr_ref_vector m_in1;
expr_ref_vector m_in2;
expr_ref_vector m_out;
obj_map<func_decl, expr*> m_const2bits;
expr_ref_vector m_bindings;
bool m_blast_mul;
bool m_blast_add;
bool m_blast_quant;
bool m_blast_full;
unsigned long long m_max_memory;
unsigned m_max_steps;
ast_manager & m() const { return m_manager; }
bv_util & butil() { return m_blaster.butil(); }
void cleanup_buffers() {
m_in1.finalize();
m_in2.finalize();
m_out.finalize();
m_bindings.finalize();
}
blaster_rewriter_cfg(ast_manager & m, blaster & b, params_ref const & p):
m_manager(m),
m_blaster(b),
m_in1(m),
m_in2(m),
m_out(m),
m_bindings(m) {
updt_params(p);
}
~blaster_rewriter_cfg() {
dec_ref_map_key_values(m_manager, m_const2bits);
}
void updt_params(params_ref const & p) {
m_max_memory = megabytes_to_bytes(p.get_uint(":max-memory", UINT_MAX));
m_max_steps = p.get_uint(":max-steps", UINT_MAX);
m_blast_add = p.get_bool(":blast-add", true);
m_blast_mul = p.get_bool(":blast-mul", true);
m_blast_full = p.get_bool(":blast-full", false);
m_blast_quant = p.get_bool(":blast-quant", false);
m_blaster.set_max_memory(m_max_memory);
}
bool rewrite_patterns() const { return true; }
bool max_steps_exceeded(unsigned num_steps) const {
cooperate("bit blaster");
if (memory::get_allocation_size() > m_max_memory)
throw tactic_exception(TACTIC_MAX_MEMORY_MSG);
return num_steps > m_max_steps;
}
void get_bits(expr * t, expr_ref_vector & out_bits) {
if (butil().is_mkbv(t)) {
out_bits.append(to_app(t)->get_num_args(), to_app(t)->get_args());
}
else {
unsigned bv_size = butil().get_bv_size(t);
for (unsigned i = 0; i < bv_size; i++) {
parameter p(i);
out_bits.push_back(m().mk_app(butil().get_family_id(), OP_BIT2BOOL, 1, &p, 1, &t));
}
SASSERT(bv_size == out_bits.size());
}
}
template<typename V>
app * mk_mkbv(V const & bits) {
return m().mk_app(butil().get_family_id(), OP_MKBV, bits.size(), bits.c_ptr());
}
void mk_const(func_decl * f, expr_ref & result) {
SASSERT(f->get_family_id() == null_family_id);
SASSERT(f->get_arity() == 0);
expr * r;
if (m_const2bits.find(f, r)) {
result = r;
return;
}
sort * s = f->get_range();
SASSERT(butil().is_bv_sort(s));
unsigned bv_size = butil().get_bv_size(s);
sort * b = m().mk_bool_sort();
m_out.reset();
for (unsigned i = 0; i < bv_size; i++) {
m_out.push_back(m().mk_fresh_const(0, b));
}
r = mk_mkbv(m_out);
m_const2bits.insert(f, r);
m_manager.inc_ref(f);
m_manager.inc_ref(r);
result = r;
}
#define MK_UNARY_REDUCE(OP, BB_OP) \
void OP(expr * arg, expr_ref & result) { \
m_in1.reset(); \
get_bits(arg, m_in1); \
m_out.reset(); \
m_blaster.BB_OP(m_in1.size(), m_in1.c_ptr(), m_out); \
result = mk_mkbv(m_out); \
}
MK_UNARY_REDUCE(reduce_not, mk_not);
MK_UNARY_REDUCE(reduce_redor, mk_redor);
MK_UNARY_REDUCE(reduce_redand, mk_redand);
#define MK_BIN_REDUCE(OP, BB_OP) \
void OP(expr * arg1, expr * arg2, expr_ref & result) { \
m_in1.reset(); m_in2.reset(); \
get_bits(arg1, m_in1); \
get_bits(arg2, m_in2); \
m_out.reset(); \
m_blaster.BB_OP(m_in1.size(), m_in1.c_ptr(), m_in2.c_ptr(), m_out); \
result = mk_mkbv(m_out); \
}
MK_BIN_REDUCE(reduce_shl, mk_shl);
MK_BIN_REDUCE(reduce_ashr, mk_ashr);
MK_BIN_REDUCE(reduce_lshr, mk_lshr);
MK_BIN_REDUCE(reduce_udiv, mk_udiv);
MK_BIN_REDUCE(reduce_urem, mk_urem);
MK_BIN_REDUCE(reduce_sdiv, mk_sdiv);
MK_BIN_REDUCE(reduce_srem, mk_srem);
MK_BIN_REDUCE(reduce_smod, mk_smod);
MK_BIN_REDUCE(reduce_ext_rotate_left, mk_ext_rotate_left);
MK_BIN_REDUCE(reduce_ext_rotate_right, mk_ext_rotate_right);
#define MK_BIN_AC_REDUCE(OP, BIN_OP, BB_OP) \
MK_BIN_REDUCE(BIN_OP, BB_OP); \
void OP(unsigned num_args, expr * const * args, expr_ref & result) { \
SASSERT(num_args > 0); \
result = args[0]; \
expr_ref new_result(m_manager); \
for (unsigned i = 1; i < num_args; i++) { \
BIN_OP(result.get(), args[i], new_result); \
result = new_result; \
} \
}
MK_BIN_AC_REDUCE(reduce_add, reduce_bin_add, mk_adder);
MK_BIN_AC_REDUCE(reduce_mul, reduce_bin_mul, mk_multiplier);
MK_BIN_AC_REDUCE(reduce_or, reduce_bin_or, mk_or);
MK_BIN_AC_REDUCE(reduce_xor, reduce_bin_xor, mk_xor);
#define MK_BIN_PRED_REDUCE(OP, BB_OP) \
void OP(expr * arg1, expr * arg2, expr_ref & result) { \
m_in1.reset(); m_in2.reset(); \
get_bits(arg1, m_in1); \
get_bits(arg2, m_in2); \
m_blaster.BB_OP(m_in1.size(), m_in1.c_ptr(), m_in2.c_ptr(), result); \
}
MK_BIN_PRED_REDUCE(reduce_eq, mk_eq);
MK_BIN_PRED_REDUCE(reduce_sle, mk_sle);
MK_BIN_PRED_REDUCE(reduce_ule, mk_ule);
MK_BIN_PRED_REDUCE(reduce_umul_no_overflow, mk_umul_no_overflow);
MK_BIN_PRED_REDUCE(reduce_smul_no_overflow, mk_smul_no_overflow);
MK_BIN_PRED_REDUCE(reduce_smul_no_underflow, mk_smul_no_underflow);
#define MK_PARAMETRIC_UNARY_REDUCE(OP, BB_OP) \
void OP(expr * arg, unsigned n, expr_ref & result) { \
m_in1.reset(); \
get_bits(arg, m_in1); \
m_out.reset(); \
m_blaster.BB_OP(m_in1.size(), m_in1.c_ptr(), n, m_out); \
result = mk_mkbv(m_out); \
}
MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend);
void reduce_ite(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
m_in1.reset();
m_in2.reset();
get_bits(arg2, m_in1);
get_bits(arg3, m_in2);
m_out.reset();
m_blaster.mk_multiplexer(arg1, m_in1.size(), m_in1.c_ptr(), m_in2.c_ptr(), m_out);
result = mk_mkbv(m_out);
}
void reduce_concat(unsigned num_args, expr * const * args, expr_ref & result) {
m_out.reset();
unsigned i = num_args;
while (i > 0) {
i--;
m_in1.reset();
get_bits(args[i], m_in1);
m_out.append(m_in1.size(), m_in1.c_ptr());
}
result = mk_mkbv(m_out);
}
void reduce_extract(unsigned start, unsigned end, expr * arg, expr_ref & result) {
m_in1.reset();
get_bits(arg, m_in1);
m_out.reset();
for (unsigned i = start; i <= end; ++i)
m_out.push_back(m_in1.get(i));
result = mk_mkbv(m_out);
}
void reduce_num(func_decl * f, expr_ref & result) {
SASSERT(f->get_num_parameters() == 2);
SASSERT(f->get_parameter(0).is_rational());
SASSERT(f->get_parameter(1).is_int());
rational v = f->get_parameter(0).get_rational();
unsigned bv_sz = f->get_parameter(1).get_int();
m_out.reset();
m_blaster.num2bits(v, bv_sz, m_out);
result = mk_mkbv(m_out);
}
void throw_unsupported() {
throw tactic_exception("operator is not supported, you must simplify the goal before applying bit-blasting");
}
void blast_bv_term(expr * t, expr_ref & result, proof_ref & result_pr) {
ptr_buffer<expr> bits;
unsigned bv_size = butil().get_bv_size(t);
for (unsigned i = 0; i < bv_size; i++) {
parameter p(i);
bits.push_back(m().mk_app(butil().get_family_id(), OP_BIT2BOOL, 1, &p, 1, &t));
}
result = mk_mkbv(bits);
result_pr = 0;
}
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
result_pr = 0;
if (num == 0 && f->get_family_id() == null_family_id && butil().is_bv_sort(f->get_range())) {
mk_const(f, result);
return BR_DONE;
}
if (m().is_eq(f)) {
SASSERT(num == 2);
if (butil().is_bv(args[0])) {
reduce_eq(args[0], args[1], result);
return BR_DONE;
}
return BR_FAILED;
}
if (m().is_ite(f)) {
SASSERT(num == 3);
if (butil().is_bv(args[1])) {
reduce_ite(args[0], args[1], args[2], result);
return BR_DONE;
}
return BR_FAILED;
}
if (f->get_family_id() == butil().get_family_id()) {
switch (f->get_decl_kind()) {
case OP_BV_NUM:
SASSERT(num == 0);
reduce_num(f, result);
return BR_DONE;
case OP_BADD:
if (!m_blast_add)
return BR_FAILED;
reduce_add(num, args, result);
return BR_DONE;
case OP_BMUL:
if (!m_blast_mul)
return BR_FAILED;
reduce_mul(num, args, result);
return BR_DONE;
case OP_BSDIV:
case OP_BUDIV:
case OP_BSREM:
case OP_BUREM:
case OP_BSMOD:
if (m_blast_mul)
throw_unsupported(); // must simplify to DIV_I AND DIV0
return BR_FAILED; // keep them
case OP_BSDIV0:
case OP_BUDIV0:
case OP_BSREM0:
case OP_BUREM0:
case OP_BSMOD0:
return BR_FAILED;
case OP_BSDIV_I:
if (!m_blast_mul)
return BR_FAILED;
SASSERT(num == 2);
reduce_sdiv(args[0], args[1], result);
return BR_DONE;
case OP_BUDIV_I:
if (!m_blast_mul)
return BR_FAILED;
SASSERT(num == 2);
reduce_udiv(args[0], args[1], result);
return BR_DONE;
case OP_BSREM_I:
if (!m_blast_mul)
return BR_FAILED;
SASSERT(num == 2);
reduce_srem(args[0], args[1], result);
return BR_DONE;
case OP_BUREM_I:
if (!m_blast_mul)
return BR_FAILED;
SASSERT(num == 2);
reduce_urem(args[0], args[1], result);
return BR_DONE;
case OP_BSMOD_I:
if (!m_blast_mul)
return BR_FAILED;
SASSERT(num == 2);
reduce_smod(args[0], args[1], result);
return BR_DONE;
case OP_ULEQ:
SASSERT(num == 2);
reduce_ule(args[0], args[1], result);
return BR_DONE;
case OP_SLEQ:
SASSERT(num == 2);
reduce_sle(args[0], args[1], result);
return BR_DONE;
case OP_BOR:
reduce_or(num, args, result);
return BR_DONE;
case OP_BNOT:
SASSERT(num == 1);
reduce_not(args[0], result);
return BR_DONE;
case OP_BXOR:
reduce_xor(num, args, result);
return BR_DONE;
case OP_CONCAT:
reduce_concat(num, args, result);
return BR_DONE;
case OP_SIGN_EXT:
SASSERT(num == 1);
reduce_sign_extend(args[0], f->get_parameter(0).get_int(), result);
return BR_DONE;
case OP_EXTRACT:
SASSERT(num == 1);
reduce_extract(f->get_parameter(1).get_int(), f->get_parameter(0).get_int(), args[0], result);
return BR_DONE;
case OP_BREDOR:
SASSERT(num == 1);
reduce_redor(args[0], result);
return BR_DONE;
case OP_BREDAND:
SASSERT(num == 1);
reduce_redand(args[0], result);
return BR_DONE;
case OP_BSHL:
SASSERT(num == 2);
reduce_shl(args[0], args[1], result);
return BR_DONE;
case OP_BLSHR:
SASSERT(num == 2);
reduce_lshr(args[0], args[1], result);
return BR_DONE;
case OP_BASHR:
SASSERT(num == 2);
reduce_ashr(args[0], args[1], result);
return BR_DONE;
case OP_EXT_ROTATE_LEFT:
SASSERT(num == 2);
reduce_ext_rotate_left(args[0], args[1], result);
return BR_DONE;
case OP_EXT_ROTATE_RIGHT:
SASSERT(num == 2);
reduce_ext_rotate_right(args[0], args[1], result);
return BR_DONE;
case OP_BUMUL_NO_OVFL:
SASSERT(num == 2);
reduce_umul_no_overflow(args[0], args[1], result);
return BR_DONE;
case OP_BSMUL_NO_OVFL:
SASSERT(num == 2);
reduce_smul_no_overflow(args[0], args[1], result);
return BR_DONE;
case OP_BSMUL_NO_UDFL:
SASSERT(num == 2);
reduce_smul_no_underflow(args[0], args[1], result);
return BR_DONE;
case OP_BIT2BOOL:
case OP_MKBV:
case OP_INT2BV:
case OP_BV2INT:
return BR_FAILED;
default:
TRACE("bit_blaster", tout << "non-supported operator: " << f->get_name() << "\n";
for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << std::endl;);
throw_unsupported();
}
}
if (m_blast_full && butil().is_bv_sort(f->get_range())) {
blast_bv_term(m().mk_app(f, num, args), result, result_pr);
return BR_DONE;
}
return BR_FAILED;
}
bool pre_visit(expr * t) {
if (m_blast_quant && is_quantifier(t)) {
quantifier * q = to_quantifier(t);
ptr_buffer<expr> new_bindings;
ptr_buffer<expr> new_args;
unsigned i = q->get_num_decls();
unsigned j = 0;
while (i > 0) {
--i;
sort * s = q->get_decl_sort(i);
if (butil().is_bv_sort(s)) {
unsigned bv_size = butil().get_bv_size(s);
new_args.reset();
for (unsigned k = 0; k < bv_size; k++) {
new_args.push_back(m().mk_var(j, m().mk_bool_sort()));
j++;
}
new_bindings.push_back(mk_mkbv(new_args));
}
else {
new_bindings.push_back(m().mk_var(j, s));
j++;
}
}
SASSERT(new_bindings.size() == q->get_num_decls());
i = q->get_num_decls();
while (i > 0) {
i--;
m_bindings.push_back(new_bindings[i]);
}
}
return true;
}
bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr) {
if (m_blast_quant) {
if (t->get_idx() >= m_bindings.size())
return false;
result = m_bindings.get(m_bindings.size() - t->get_idx() - 1);
result_pr = 0;
return true;
}
if (m_blast_full && butil().is_bv(t)) {
blast_bv_term(t, result, result_pr);
return true;
}
return false;
}
bool reduce_quantifier(quantifier * old_q,
expr * new_body,
expr * const * new_patterns,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
if (!m_blast_quant)
return false;
unsigned curr_sz = m_bindings.size();
SASSERT(old_q->get_num_decls() <= curr_sz);
unsigned num_decls = old_q->get_num_decls();
unsigned old_sz = curr_sz - num_decls;
string_buffer<> name_buffer;
ptr_buffer<sort> new_decl_sorts;
sbuffer<symbol> new_decl_names;
for (unsigned i = 0; i < num_decls; i++) {
symbol const & n = old_q->get_decl_name(i);
sort * s = old_q->get_decl_sort(i);
if (butil().is_bv_sort(s)) {
unsigned bv_size = butil().get_bv_size(s);
for (unsigned j = 0; j < bv_size; j++) {
name_buffer.reset();
name_buffer << n << "." << j;
new_decl_names.push_back(symbol(name_buffer.c_str()));
new_decl_sorts.push_back(m().mk_bool_sort());
}
}
else {
new_decl_sorts.push_back(s);
new_decl_names.push_back(n);
}
}
result = m().mk_quantifier(old_q->is_forall(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(),
new_body, old_q->get_weight(), old_q->get_qid(), old_q->get_skid(),
old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns);
result_pr = 0;
m_bindings.shrink(old_sz);
return true;
}
};
// CMW: GCC/LLVM do not like this definition because a symbol of the same name exists in assert_set_bit_blaster.o
// template class rewriter_tpl<blaster_rewriter_cfg>;
struct bit_blaster_rewriter::imp : public rewriter_tpl<blaster_rewriter_cfg> {
blaster m_blaster;
blaster_rewriter_cfg m_cfg;
imp(ast_manager & m, params_ref const & p):
rewriter_tpl<blaster_rewriter_cfg>(m,
m.proofs_enabled(),
m_cfg),
m_blaster(m),
m_cfg(m, m_blaster, p) {
SASSERT(m_blaster.butil().get_family_id() == m.get_family_id("bv"));
}
};
bit_blaster_rewriter::bit_blaster_rewriter(ast_manager & m, params_ref const & p):
m_imp(alloc(imp, m, p)) {
}
bit_blaster_rewriter::~bit_blaster_rewriter() {
dealloc(m_imp);
}
void bit_blaster_rewriter::updt_params(params_ref const& p) {
m_imp->m_cfg.updt_params(p);
}
void bit_blaster_rewriter::set_cancel(bool f) {
m_imp->set_cancel(f);
m_imp->m_blaster.set_cancel(f);
}
ast_manager & bit_blaster_rewriter::m() const {
return m_imp->m();
}
unsigned bit_blaster_rewriter::get_num_steps() const {
return m_imp->get_num_steps();
}
void bit_blaster_rewriter::cleanup() {
m_imp->cleanup();
}
obj_map<func_decl, expr*> const & bit_blaster_rewriter::const2bits() const {
return m_imp->m_cfg.m_const2bits;
}
void bit_blaster_rewriter::operator()(expr * e, expr_ref & result, proof_ref & result_proof) {
m_imp->operator()(e, result, result_proof);
}

View file

@ -0,0 +1,42 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
bit_blaster_rewriter.h
Abstract:
Bit-blasting rewriter
Author:
Leonardo (leonardo) 2012-10-04
Notes:
--*/
#ifndef _BIT_BLASTER_REWRITER_H_
#define _BIT_BLASTER_REWRITER_H_
#include"ast.h"
#include"obj_hashtable.h"
#include"params.h"
class bit_blaster_rewriter {
struct imp;
imp * m_imp;
public:
bit_blaster_rewriter(ast_manager & m, params_ref const & p);
~bit_blaster_rewriter();
void updt_params(params_ref const & p);
void set_cancel(bool f);
ast_manager & m() const;
unsigned get_num_steps() const;
void cleanup();
obj_map<func_decl, expr*> const& const2bits() const;
void operator()(expr * e, expr_ref & result, proof_ref & result_proof);
};
#endif

View file

@ -0,0 +1,165 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
bit_blaster_tactic.cpp
Abstract:
Apply bit-blasting to a given goal
Author:
Leonardo (leonardo) 2011-10-25
Notes:
--*/
#include"tactical.h"
#include"bit_blaster_model_converter.h"
#include"bit_blaster_rewriter.h"
#include"ast_smt2_pp.h"
#include"model_pp.h"
class bit_blaster_tactic : public tactic {
struct imp {
bit_blaster_rewriter m_rewriter;
unsigned m_num_steps;
bool m_blast_quant;
imp(ast_manager & m, params_ref const & p):
m_rewriter(m, p) {
updt_params(p);
}
void updt_params_core(params_ref const & p) {
m_blast_quant = p.get_bool(":blast-quant", false);
}
void updt_params(params_ref const & p) {
m_rewriter.updt_params(p);
updt_params_core(p);
}
ast_manager & m() const { return m_rewriter.m(); }
void set_cancel(bool f) {
m_rewriter.set_cancel(f);
}
void operator()(goal_ref const & g,
goal_ref_buffer & result,
model_converter_ref & mc,
proof_converter_ref & pc,
expr_dependency_ref & core) {
mc = 0; pc = 0; core = 0;
bool proofs_enabled = g->proofs_enabled();
if (proofs_enabled && m_blast_quant)
throw tactic_exception("quantified variable blasting does not support proof generation");
tactic_report report("bit-blaster", *g);
TRACE("before_bit_blaster", g->display(tout););
m_num_steps = 0;
expr_ref new_curr(m());
proof_ref new_pr(m());
unsigned size = g->size();
for (unsigned idx = 0; idx < size; idx++) {
if (g->inconsistent())
break;
expr * curr = g->form(idx);
m_rewriter(curr, new_curr, new_pr);
m_num_steps += m_rewriter.get_num_steps();
if (proofs_enabled) {
proof * pr = g->pr(idx);
new_pr = m().mk_modus_ponens(pr, new_pr);
}
g->update(idx, new_curr, new_pr, g->dep(idx));
}
if (g->models_enabled())
mc = mk_bit_blaster_model_converter(m(), m_rewriter.const2bits());
else
mc = 0;
g->inc_depth();
result.push_back(g.get());
TRACE("after_bit_blaster", g->display(tout); if (mc) mc->display(tout); tout << "\n";);
m_rewriter.cleanup();
}
unsigned get_num_steps() const { return m_num_steps; }
};
imp * m_imp;
params_ref m_params;
public:
bit_blaster_tactic(ast_manager & m, params_ref const & p):
m_params(p){
m_imp = alloc(imp, m, p);
}
virtual tactic * translate(ast_manager & m) {
return alloc(bit_blaster_tactic, m, m_params);
}
virtual ~bit_blaster_tactic() {
dealloc(m_imp);
}
virtual void updt_params(params_ref const & p) {
m_params = p;
m_imp->updt_params(p);
}
virtual void collect_param_descrs(param_descrs & r) {
insert_max_memory(r);
insert_max_steps(r);
r.insert(":blast-mul", CPK_BOOL, "(default: true) bit-blast multipliers (and dividers, remainders).");
r.insert(":blast-add", CPK_BOOL, "(default: true) bit-blast adders.");
r.insert(":blast-quant", CPK_BOOL, "(default: false) bit-blast quantified variables.");
r.insert(":blast-full", CPK_BOOL, "(default: false) bit-blast any term with bit-vector sort, this option will make E-matching ineffective in any pattern containing bit-vector terms.");
}
virtual void operator()(goal_ref const & g,
goal_ref_buffer & result,
model_converter_ref & mc,
proof_converter_ref & pc,
expr_dependency_ref & core) {
(*m_imp)(g, result, mc, pc, core);
}
virtual void cleanup() {
ast_manager & m = m_imp->m();
imp * d = m_imp;
#pragma omp critical (tactic_cancel)
{
m_imp = 0;
}
dealloc(d);
d = alloc(imp, m, m_params);
#pragma omp critical (tactic_cancel)
{
m_imp = d;
}
}
unsigned get_num_steps() const {
return m_imp->get_num_steps();
}
protected:
virtual void set_cancel(bool f) {
if (m_imp)
m_imp->set_cancel(f);
}
};
tactic * mk_bit_blaster_tactic(ast_manager & m, params_ref const & p) {
return clean(alloc(bit_blaster_tactic, m, p));
}

View file

@ -0,0 +1,28 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
bit_blaster_tactic.h
Abstract:
Apply bit-blasting to a given goal.
Author:
Leonardo (leonardo) 2011-10-25
Notes:
--*/
#ifndef _BIT_BLASTER_TACTIC_H_
#define _BIT_BLASTER_TACTIC_H_
#include"params.h"
class ast_manager;
class tactic;
tactic * mk_bit_blaster_tactic(ast_manager & m, params_ref const & p = params_ref());
#endif

View file

@ -0,0 +1,135 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
bit_blaster_tpl.h
Abstract:
Template for bit-blaster operations
Author:
Leonardo de Moura (leonardo) 2011-05-02.
Revision History:
--*/
#ifndef _BIT_BLASTER_TPL_H_
#define _BIT_BLASTER_TPL_H_
#include"rational.h"
#include"strategy_exception.h"
template<typename Cfg>
class bit_blaster_tpl : public Cfg {
public:
typedef rational numeral;
protected:
template<bool Signed>
void mk_le(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref & out);
template<unsigned k>
void mk_sdiv_srem_smod(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
template<bool Left>
void mk_ext_rotate_left_right(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
unsigned long long m_max_memory;
volatile bool m_cancel;
bool m_use_wtm; /* Wallace Tree Multiplier */
bool m_use_bcm; /* Booth Multiplier for constants */
void checkpoint();
public:
bit_blaster_tpl(Cfg const & cfg = Cfg(), unsigned long long max_memory = UINT64_MAX, bool use_wtm = false, bool use_bcm=false):
Cfg(cfg),
m_max_memory(max_memory),
m_cancel(false),
m_use_wtm(use_wtm),
m_use_bcm(use_bcm) {
}
void set_max_memory(unsigned long long max_memory) {
m_max_memory = max_memory;
}
void set_cancel(bool f) { m_cancel = f; }
void cancel() { set_cancel(true); }
void reset_cancel() { set_cancel(false); }
// Cfg required API
ast_manager & m() const { return Cfg::m(); }
numeral power(unsigned n) const { return Cfg::power(n); }
void mk_xor(expr * a, expr * b, expr_ref & r) { Cfg::mk_xor(a, b, r); }
void mk_xor3(expr * a, expr * b, expr * c, expr_ref & r) { Cfg::mk_xor3(a, b, c, r); }
void mk_carry(expr * a, expr * b, expr * c, expr_ref & r) { Cfg::mk_carry(a, b, c, r); }
void mk_iff(expr * a, expr * b, expr_ref & r) { Cfg::mk_iff(a, b, r); }
void mk_and(expr * a, expr * b, expr_ref & r) { Cfg::mk_and(a, b, r); }
void mk_and(expr * a, expr * b, expr * c, expr_ref & r) { Cfg::mk_and(a, b, c, r); }
void mk_and(unsigned sz, expr * const * args, expr_ref & r) { Cfg::mk_and(sz, args, r); }
void mk_or(expr * a, expr * b, expr_ref & r) { Cfg::mk_or(a, b, r); }
void mk_or(expr * a, expr * b, expr * c, expr_ref & r) { Cfg::mk_or(a, b, c, r); }
void mk_or(unsigned sz, expr * const * args, expr_ref & r) { Cfg::mk_or(sz, args, r); }
void mk_not(expr * a, expr_ref & r) { Cfg::mk_not(a, r); }
void mk_ite(expr * c, expr * t, expr * e, expr_ref & r) { Cfg::mk_ite(c, t, e, r); }
void mk_nand(expr * a, expr * b, expr_ref & r) { Cfg::mk_nand(a, b, r); }
void mk_nor(expr * a, expr * b, expr_ref & r) { Cfg::mk_nor(a, b, r); }
//
bool is_numeral(unsigned sz, expr * const * bits) const;
bool is_numeral(unsigned sz, expr * const * bits, numeral & r) const;
bool is_minus_one(unsigned sz, expr * const * bits) const;
void num2bits(numeral const & v, unsigned sz, expr_ref_vector & out_bits) const;
void mk_half_adder(expr * a, expr * b, expr_ref & out, expr_ref & cout);
void mk_full_adder(expr * a, expr * b, expr * cin, expr_ref & out, expr_ref & cout);
void mk_neg(unsigned sz, expr * const * a_bits, expr_ref_vector & out_bits);
void mk_adder(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_subtracter(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits, expr_ref & cout);
void mk_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_udiv_urem(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & q_bits, expr_ref_vector & r_bits);
void mk_udiv(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & q_bits);
void mk_urem(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & r_bits);
void mk_multiplexer(expr * c, unsigned sz, expr * const * t_bits, expr * const * e_bits, expr_ref_vector & out_bits);
void mk_sdiv(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_srem(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_smod(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_rotate_left(unsigned sz, expr * const * a_bits, unsigned n, expr_ref_vector & out_bits);
void mk_rotate_right(unsigned sz, expr * const * a_bits, unsigned n, expr_ref_vector & out_bits);
void mk_ext_rotate_left(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_ext_rotate_right(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_sign_extend(unsigned sz, expr * const * a_bits, unsigned n, expr_ref_vector & out_bits);
void mk_zero_extend(unsigned sz, expr * const * a_bits, unsigned n, expr_ref_vector & out_bits);
void mk_eq(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref & out);
void mk_is_eq(unsigned sz, expr * const * a_bits, unsigned n, expr_ref & out);
void mk_eqs(unsigned sz, expr * const * a_bits, expr_ref_vector & eqs);
void mk_shl(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_lshr(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_ashr(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_sle(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref & out);
void mk_ule(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref & out);
void mk_not(unsigned sz, expr * const * a_bits, expr_ref_vector & out_bits);
void mk_and(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_or(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_xor(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_xnor(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_nand(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_nor(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_redand(unsigned sz, expr * const * a_bits, expr_ref_vector & out_bits);
void mk_redor(unsigned sz, expr * const * a_bits, expr_ref_vector & out_bits);
void mk_umul_no_overflow(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref & out);
void mk_smul_no_overflow_core(unsigned sz, expr * const * a_bits, expr * const * b_bits, bool is_overflow, expr_ref & result);
void mk_smul_no_overflow(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref & out);
void mk_smul_no_underflow(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref & out);
void mk_comp(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_carry_save_adder(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr * const * c_bits, expr_ref_vector & sum_bits, expr_ref_vector & carry_bits);
void mk_const_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_abs(unsigned sz, expr * const * a_bits, expr_ref_vector & out_bits);
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,508 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
bv1_blaster_tactic.cpp
Abstract:
Rewriter for "blasting" bit-vectors of size n into bit-vectors of size 1.
This rewriter only supports concat and extract operators.
This transformation is useful for handling benchmarks that contain
many BV equalities.
Remark: other operators can be mapped into concat/extract by using
the simplifiers.
Author:
Leonardo (leonardo) 2011-10-25
Notes:
--*/
#include"tactical.h"
#include"bit_blaster_model_converter.h"
#include"bv_decl_plugin.h"
#include"rewriter_def.h"
#include"for_each_expr.h"
#include"cooperate.h"
class bv1_blaster_tactic : public tactic {
struct rw_cfg : public default_rewriter_cfg {
ast_manager & m_manager;
bv_util m_util;
obj_map<func_decl, expr*> m_const2bits;
expr_ref_vector m_saved;
expr_ref m_bit1;
expr_ref m_bit0;
unsigned long long m_max_memory; // in bytes
unsigned m_max_steps;
bool m_produce_models;
ast_manager & m() const { return m_manager; }
bv_util & butil() { return m_util; }
bv_util const & butil() const { return m_util; }
void cleanup_buffers() {
m_saved.finalize();
}
rw_cfg(ast_manager & m, params_ref const & p):
m_manager(m),
m_util(m),
m_saved(m),
m_bit1(m),
m_bit0(m) {
m_bit1 = butil().mk_numeral(rational(1), 1);
m_bit0 = butil().mk_numeral(rational(0), 1);
updt_params(p);
}
void updt_params(params_ref const & p) {
m_max_memory = megabytes_to_bytes(p.get_uint(":max-memory", UINT_MAX));
m_max_steps = p.get_uint(":max-steps", UINT_MAX);
m_produce_models = p.get_bool(":produce-models", false);
}
bool rewrite_patterns() const { UNREACHABLE(); return false; }
bool max_steps_exceeded(unsigned num_steps) const {
cooperate("bv1 blaster");
if (memory::get_allocation_size() > m_max_memory)
throw tactic_exception(TACTIC_MAX_MEMORY_MSG);
return num_steps > m_max_steps;
}
typedef ptr_buffer<expr, 128> bit_buffer;
void get_bits(expr * arg, bit_buffer & bits) {
SASSERT(butil().is_concat(arg) || butil().get_bv_size(arg) == 1);
if (butil().is_concat(arg))
bits.append(to_app(arg)->get_num_args(), to_app(arg)->get_args());
else
bits.push_back(arg);
}
void mk_const(func_decl * f, expr_ref & result) {
SASSERT(f->get_family_id() == null_family_id);
SASSERT(f->get_arity() == 0);
expr * r;
if (m_const2bits.find(f, r)) {
result = r;
return;
}
sort * s = f->get_range();
SASSERT(butil().is_bv_sort(s));
unsigned bv_size = butil().get_bv_size(s);
if (bv_size == 1) {
result = m().mk_const(f);
return;
}
sort * b = butil().mk_sort(1);
ptr_buffer<expr> bits;
for (unsigned i = 0; i < bv_size; i++) {
bits.push_back(m().mk_fresh_const(0, b));
}
r = butil().mk_concat(bits.size(), bits.c_ptr());
m_saved.push_back(r);
m_const2bits.insert(f, r);
result = r;
}
void blast_bv_term(expr * t, expr_ref & result) {
bit_buffer bits;
unsigned bv_size = butil().get_bv_size(t);
if (bv_size == 1) {
result = t;
return;
}
unsigned i = bv_size;
while (i > 0) {
--i;
bits.push_back(butil().mk_extract(i, i, t));
}
result = butil().mk_concat(bits.size(), bits.c_ptr());
}
void reduce_eq(expr * arg1, expr * arg2, expr_ref & result) {
bit_buffer bits1;
bit_buffer bits2;
get_bits(arg1, bits1);
get_bits(arg2, bits2);
SASSERT(bits1.size() == bits2.size());
bit_buffer new_eqs;
unsigned i = bits1.size();
while (i > 0) {
--i;
new_eqs.push_back(m().mk_eq(bits1[i], bits2[i]));
}
result = m().mk_and(new_eqs.size(), new_eqs.c_ptr());
}
void reduce_ite(expr * c, expr * t, expr * e, expr_ref & result) {
bit_buffer t_bits;
bit_buffer e_bits;
get_bits(t, t_bits);
get_bits(e, e_bits);
SASSERT(t_bits.size() == e_bits.size());
bit_buffer new_ites;
unsigned num = t_bits.size();
for (unsigned i = 0; i < num; i++)
new_ites.push_back(m().mk_ite(c, t_bits[i], e_bits[i]));
result = butil().mk_concat(new_ites.size(), new_ites.c_ptr());
}
void reduce_num(func_decl * f, expr_ref & result) {
SASSERT(f->get_num_parameters() == 2);
SASSERT(f->get_parameter(0).is_rational());
SASSERT(f->get_parameter(1).is_int());
bit_buffer bits;
rational v = f->get_parameter(0).get_rational();
rational two(2);
unsigned sz = f->get_parameter(1).get_int();
for (unsigned i = 0; i < sz; i++) {
if ((v % two).is_zero())
bits.push_back(m_bit0);
else
bits.push_back(m_bit1);
v = div(v, two);
}
std::reverse(bits.begin(), bits.end());
result = butil().mk_concat(bits.size(), bits.c_ptr());
}
void reduce_extract(func_decl * f, expr * arg, expr_ref & result) {
bit_buffer arg_bits;
get_bits(arg, arg_bits);
SASSERT(arg_bits.size() == butil().get_bv_size(arg));
unsigned high = butil().get_extract_high(f);
unsigned low = butil().get_extract_low(f);
unsigned sz = arg_bits.size();
unsigned start = sz - 1 - high;
unsigned end = sz - 1 - low;
bit_buffer bits;
for (unsigned i = start; i <= end; i++) {
bits.push_back(arg_bits[i]);
}
result = butil().mk_concat(bits.size(), bits.c_ptr());
}
void reduce_concat(unsigned num, expr * const * args, expr_ref & result) {
bit_buffer bits;
bit_buffer arg_bits;
for (unsigned i = 0; i < num; i++) {
expr * arg = args[i];
arg_bits.reset();
get_bits(arg, arg_bits);
bits.append(arg_bits.size(), arg_bits.c_ptr());
}
result = butil().mk_concat(bits.size(), bits.c_ptr());
}
void reduce_bin_xor(expr * arg1, expr * arg2, expr_ref & result) {
bit_buffer bits1;
bit_buffer bits2;
get_bits(arg1, bits1);
get_bits(arg2, bits2);
SASSERT(bits1.size() == bits2.size());
bit_buffer new_bits;
unsigned num = bits1.size();
for (unsigned i = 0; i < num; i++) {
new_bits.push_back(m().mk_ite(m().mk_eq(bits1[i], bits2[i]), m_bit0, m_bit1));
}
result = butil().mk_concat(new_bits.size(), new_bits.c_ptr());
}
void reduce_xor(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args > 0);
#if 1
if (num_args == 1) {
result = args[0];
return;
}
reduce_bin_xor(args[0], args[1], result);
for (unsigned i = 2; i < num_args; i++) {
reduce_bin_xor(result, args[i], result);
}
#else
ptr_buffer<bit_buffer> args_bits;
for (unsigned i = 0; i < num_args; i++) {
bit_buffer * buff_i = alloc(bit_buffer);
get_bits(args[i], *buff_i);
args_bits.push_back(buff_i);
}
bit_buffer new_bits;
unsigned sz = butil().get_bv_size(args[0]);
for (unsigned i = 0; i < sz; i++) {
ptr_buffer<expr> eqs;
for (unsigned j = 0; j < num_args; j++) {
bit_buffer * buff_j = args_bits[j];
eqs.push_back(m().mk_eq(buff_j->get(i), m_bit1));
}
expr * cond = m().mk_xor(eqs.size(), eqs.c_ptr());
new_bits.push_back(m().mk_ite(cond, m_bit1, m_bit0));
}
result = butil().mk_concat(new_bits.size(), new_bits.c_ptr());
std::for_each(args_bits.begin(), args_bits.end(), delete_proc<bit_buffer>());
#endif
}
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
result_pr = 0;
if (num == 0 && f->get_family_id() == null_family_id && butil().is_bv_sort(f->get_range())) {
mk_const(f, result);
return BR_DONE;
}
if (m().is_eq(f)) {
SASSERT(num == 2);
if (butil().is_bv(args[0])) {
reduce_eq(args[0], args[1], result);
return BR_DONE;
}
return BR_FAILED;
}
if (m().is_ite(f)) {
SASSERT(num == 3);
if (butil().is_bv(args[1])) {
reduce_ite(args[0], args[1], args[2], result);
return BR_DONE;
}
return BR_FAILED;
}
if (f->get_family_id() == butil().get_family_id()) {
switch (f->get_decl_kind()) {
case OP_BV_NUM:
reduce_num(f, result);
return BR_DONE;
case OP_EXTRACT:
SASSERT(num == 1);
reduce_extract(f, args[0], result);
return BR_DONE;
case OP_CONCAT:
reduce_concat(num, args, result);
return BR_DONE;
case OP_BXOR:
reduce_xor(num, args, result);
return BR_DONE;
default:
UNREACHABLE();
return BR_FAILED;
}
}
if (butil().is_bv_sort(f->get_range())) {
blast_bv_term(m().mk_app(f, num, args), result);
return BR_DONE;
}
return BR_FAILED;
}
bool reduce_quantifier(quantifier * old_q,
expr * new_body,
expr * const * new_patterns,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
UNREACHABLE();
return false;
}
};
struct rw : public rewriter_tpl<rw_cfg> {
rw_cfg m_cfg;
rw(ast_manager & m, params_ref const & p):
rewriter_tpl<rw_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(m, p) {
}
};
struct imp {
rw m_rw;
unsigned m_num_steps;
imp(ast_manager & m, params_ref const & p):
m_rw(m, p) {
}
struct not_target {};
struct visitor {
family_id m_bv_fid;
visitor(family_id bv_fid):m_bv_fid(bv_fid) {}
void operator()(var const * n) { throw not_target(); }
void operator()(app const * n) {
if (n->get_family_id() == m_bv_fid) {
switch (n->get_decl_kind()) {
case OP_BV_NUM:
case OP_EXTRACT:
case OP_CONCAT:
return;
case OP_BXOR:
// it doesn't payoff to do the reduction in this case.
throw not_target();
default:
throw not_target();
}
}
}
void operator()(quantifier const * n) { throw not_target(); }
};
bool is_target(goal const & g) const {
expr_fast_mark1 visited;
unsigned sz = g.size();
visitor proc(m_rw.cfg().butil().get_family_id());
try {
for (unsigned i = 0; i < sz; i++) {
expr * f = g.form(i);
for_each_expr_core<visitor, expr_fast_mark1, false, true>(proc, visited, f);
}
}
catch (not_target) {
return false;
}
return true;
}
ast_manager & m() const { return m_rw.m(); }
void set_cancel(bool f) {
m_rw.set_cancel(f);
}
void operator()(goal_ref const & g,
goal_ref_buffer & result,
model_converter_ref & mc,
proof_converter_ref & pc,
expr_dependency_ref & core) {
mc = 0; pc = 0; core = 0;
if (!is_target(*g))
throw tactic_exception("bv1 blaster cannot be applied to goal");
tactic_report report("bv1-blaster", *g);
m_num_steps = 0;
bool proofs_enabled = g->proofs_enabled();
expr_ref new_curr(m());
proof_ref new_pr(m());
unsigned size = g->size();
for (unsigned idx = 0; idx < size; idx++) {
if (g->inconsistent())
break;
expr * curr = g->form(idx);
m_rw(curr, new_curr, new_pr);
m_num_steps += m_rw.get_num_steps();
if (proofs_enabled) {
proof * pr = g->pr(idx);
new_pr = m().mk_modus_ponens(pr, new_pr);
}
g->update(idx, new_curr, new_pr, g->dep(idx));
}
if (g->models_enabled())
mc = mk_bv1_blaster_model_converter(m(), m_rw.cfg().m_const2bits);
g->inc_depth();
result.push_back(g.get());
m_rw.cfg().cleanup();
}
unsigned get_num_steps() const { return m_num_steps; }
};
imp * m_imp;
params_ref m_params;
public:
bv1_blaster_tactic(ast_manager & m, params_ref const & p = params_ref()):
m_params(p) {
m_imp = alloc(imp, m, p);
}
virtual tactic * translate(ast_manager & m) {
return alloc(bv1_blaster_tactic, m, m_params);
}
virtual ~bv1_blaster_tactic() {
dealloc(m_imp);
}
virtual void updt_params(params_ref const & p) {
m_params = p;
m_imp->m_rw.cfg().updt_params(p);
}
virtual void collect_param_descrs(param_descrs & r) {
insert_max_memory(r);
insert_max_steps(r);
}
bool is_target(goal const & g) const {
return m_imp->is_target(g);
}
/**
\brief "Blast" bit-vectors of size n in s into bit-vectors of size 1.
If s contains other bit-vectors operators different from concat/extract, then this is method is a NO-OP.
It also does not support quantifiers.
Return a model_converter that converts any model for the updated set into a model for the old set.
*/
virtual void operator()(goal_ref const & g,
goal_ref_buffer & result,
model_converter_ref & mc,
proof_converter_ref & pc,
expr_dependency_ref & core) {
(*m_imp)(g, result, mc, pc, core);
}
virtual void cleanup() {
ast_manager & m = m_imp->m();
imp * d = m_imp;
#pragma omp critical (tactic_cancel)
{
d = m_imp;
}
dealloc(d);
d = alloc(imp, m, m_params);
#pragma omp critical (tactic_cancel)
{
m_imp = d;
}
}
unsigned get_num_steps() const {
return m_imp->get_num_steps();
}
protected:
virtual void set_cancel(bool f) {
if (m_imp)
m_imp->set_cancel(f);
}
};
tactic * mk_bv1_blaster_tactic(ast_manager & m, params_ref const & p) {
return clean(alloc(bv1_blaster_tactic, m, p));
}
class is_qfbv_eq_probe : public probe {
public:
virtual result operator()(goal const & g) {
bv1_blaster_tactic t(g.m());
return t.is_target(g);
}
};
probe * mk_is_qfbv_eq_probe() {
return alloc(is_qfbv_eq_probe);
}

View file

@ -0,0 +1,35 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
bv1_blaster_tactic.h
Abstract:
Rewriter for "blasting" bit-vectors of size n into bit-vectors of size 1.
This rewriter only supports concat and extract operators.
This transformation is useful for handling benchmarks that contain
many BV equalities.
Remark: other operators can be mapped into concat/extract by using
the simplifiers.
Author:
Leonardo (leonardo) 2011-10-25
Notes:
--*/
#ifndef _BV1_BLASTER_TACTIC_H_
#define _BV1_BLASTER_TACTIC_H_
#include"params.h"
class ast_manager;
class tactic;
tactic * mk_bv1_blaster_tactic(ast_manager & m, params_ref const & p = params_ref());
probe * mk_is_qfbv_eq_probe();
#endif

View file

@ -0,0 +1,436 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
eager_bit_blaster.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-10-02.
Revision History:
--*/
#include"ast_ll_pp.h"
#include"eager_bit_blaster.h"
eager_bit_blaster::basic_plugin::basic_plugin(ast_manager & m, eager_bit_blaster::bv_plugin & p, basic_simplifier_plugin & s):
simplifier_plugin(symbol("basic"), m),
m_main(p),
m_s(s) {
}
eager_bit_blaster::basic_plugin::~basic_plugin() {
}
bool eager_bit_blaster::basic_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
if (f->get_decl_kind() == OP_ITE) {
SASSERT(num_args == 3);
return m_main.reduce_ite(args[0], args[1], args[2], result);
}
else if (f->get_decl_kind() == OP_NOT) {
// the internalizer assumes there is not double negation (not (not x))
SASSERT(num_args == 1);
m_s.mk_not(args[0], result);
return true;
}
return false;
}
eager_bit_blaster::bv_plugin::bv_plugin(ast_manager & m, bit_blaster_params const & p):
simplifier_plugin(symbol("bv"), m),
m_util(m),
m_bb(m, p),
m_s(m) {
}
eager_bit_blaster::bv_plugin::~bv_plugin() {
}
void eager_bit_blaster::bv_plugin::get_bits(expr * n, expr_ref_vector & out_bits) {
rational val;
unsigned bv_size;
if (m_util.is_numeral(n, val, bv_size)) {
TRACE("eager_bb_bug", tout << "bv_size: " << bv_size << "\n";);
m_bb.num2bits(val, bv_size, out_bits);
SASSERT(out_bits.size() == bv_size);
}
else if (m_util.is_mkbv(n)) {
out_bits.append(to_app(n)->get_num_args(), to_app(n)->get_args());
}
else {
unsigned bv_size = m_util.get_bv_size(n);
for (unsigned i = 0; i < bv_size; i++) {
parameter p(i);
out_bits.push_back(m_manager.mk_app(get_family_id(), OP_BIT2BOOL, 1, &p, 1, &n));
}
SASSERT(bv_size == out_bits.size());
}
}
inline app * eager_bit_blaster::bv_plugin::mk_mkbv(expr_ref_vector const & bits) {
#ifdef Z3DEBUG
for (unsigned i = 0; i < bits.size(); i++) {
expr * b = bits.get(i);
SASSERT(!m_manager.is_not(b) || !m_manager.is_not(to_app(b)->get_arg(0)));
}
#endif
return m_manager.mk_app(get_family_id(), OP_MKBV, bits.size(), bits.c_ptr());
}
#define MK_UNARY_REDUCE(OP, BB_OP) \
void eager_bit_blaster::bv_plugin::OP(expr * arg, expr_ref & result) { \
expr_ref_vector bits(m_manager); \
get_bits(arg, bits); \
expr_ref_vector out_bits(m_manager); \
m_bb.BB_OP(bits.size(), bits.c_ptr(), out_bits); \
result = mk_mkbv(out_bits); \
}
#define MK_BIN_REDUCE(OP, BB_OP) \
void eager_bit_blaster::bv_plugin::OP(expr * arg1, expr * arg2, expr_ref & result) { \
expr_ref_vector bits1(m_manager); \
expr_ref_vector bits2(m_manager); \
get_bits(arg1, bits1); \
get_bits(arg2, bits2); \
expr_ref_vector out_bits(m_manager); \
m_bb.BB_OP(bits1.size(), bits1.c_ptr(), bits2.c_ptr(), out_bits); \
result = mk_mkbv(out_bits); \
}
#define MK_BIN_AC_FLAT_REDUCE(OP, BIN_OP, S_OP, BB_OP) \
MK_BIN_REDUCE(BIN_OP, BB_OP); \
void eager_bit_blaster::bv_plugin::OP(unsigned num_args, expr * const * args, expr_ref & result) { \
SASSERT(num_args > 0); \
if (num_args == 2) { \
BIN_OP(args[0], args[1], result); \
return; \
} \
\
ptr_buffer<expr_ref_vector> args_bits; \
for (unsigned i = 0; i < num_args; i++) { \
expr_ref_vector * bits = alloc(expr_ref_vector, m_manager); \
get_bits(args[i], *bits); \
args_bits.push_back(bits); \
} \
\
unsigned bv_size = m_util.get_bv_size(args[0]); \
expr_ref_vector new_bits(m_manager); \
for (unsigned i = 0; i < bv_size; i++) { \
expr_ref_vector arg_bits(m_manager); \
for (unsigned j = 0; j < num_args; j++) \
arg_bits.push_back(args_bits[j]->get(i)); \
expr_ref new_bit(m_manager); \
m_s.S_OP(arg_bits.size(), arg_bits.c_ptr(), new_bit); \
new_bits.push_back(new_bit); \
} \
result = mk_mkbv(new_bits); \
std::for_each(args_bits.begin(), args_bits.end(), delete_proc<expr_ref_vector>()); \
}
#define MK_BIN_AC_REDUCE(OP, BIN_OP, BB_OP) \
MK_BIN_REDUCE(BIN_OP, BB_OP); \
void eager_bit_blaster::bv_plugin::OP(unsigned num_args, expr * const * args, expr_ref & result) { \
SASSERT(num_args > 0); \
result = args[0]; \
for (unsigned i = 1; i < num_args; i++) { \
expr_ref new_result(m_manager); \
BIN_OP(result.get(), args[i], new_result); \
result = new_result; \
} \
}
#define MK_BIN_PRED_REDUCE(OP, BB_OP) \
void eager_bit_blaster::bv_plugin::OP(expr * arg1, expr * arg2, expr_ref & result) { \
expr_ref_vector bits1(m_manager); \
expr_ref_vector bits2(m_manager); \
get_bits(arg1, bits1); \
get_bits(arg2, bits2); \
m_bb.BB_OP(bits1.size(), bits1.c_ptr(), bits2.c_ptr(), result); \
}
#define MK_PARAMETRIC_UNARY_REDUCE(OP, BB_OP) \
void eager_bit_blaster::bv_plugin::OP(expr * arg, unsigned n, expr_ref & result) { \
expr_ref_vector bits(m_manager); \
get_bits(arg, bits); \
expr_ref_vector out_bits(m_manager); \
m_bb.BB_OP(bits.size(), bits.c_ptr(), n, out_bits); \
result = mk_mkbv(out_bits); \
}
MK_UNARY_REDUCE(reduce_not, mk_not);
MK_BIN_AC_FLAT_REDUCE(reduce_or, reduce_bin_or, mk_or, mk_or);
MK_BIN_AC_FLAT_REDUCE(reduce_and, reduce_bin_and, mk_and, mk_and);
MK_BIN_AC_FLAT_REDUCE(reduce_nor, reduce_bin_nor, mk_nor, mk_nor);
MK_BIN_AC_FLAT_REDUCE(reduce_nand, reduce_bin_nand, mk_nand, mk_nand);
MK_BIN_REDUCE(reduce_xor, mk_xor);
MK_BIN_REDUCE(reduce_xnor, mk_xnor);
MK_UNARY_REDUCE(reduce_neg, mk_neg);
MK_BIN_AC_REDUCE(reduce_add, reduce_bin_add, mk_adder);
MK_BIN_AC_REDUCE(reduce_mul, reduce_bin_mul, mk_multiplier);
MK_BIN_PRED_REDUCE(reduce_sle, mk_sle);
MK_BIN_PRED_REDUCE(reduce_ule, mk_ule);
MK_PARAMETRIC_UNARY_REDUCE(reduce_rotate_left, mk_rotate_left);
MK_PARAMETRIC_UNARY_REDUCE(reduce_rotate_right, mk_rotate_right);
MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend);
MK_PARAMETRIC_UNARY_REDUCE(reduce_zero_extend, mk_zero_extend);
MK_UNARY_REDUCE(reduce_redor, mk_redor);
MK_UNARY_REDUCE(reduce_redand, mk_redand);
MK_BIN_REDUCE(reduce_shl, mk_shl);
MK_BIN_REDUCE(reduce_ashr, mk_ashr);
MK_BIN_REDUCE(reduce_lshr, mk_lshr);
MK_BIN_REDUCE(reduce_comp, mk_comp);
MK_BIN_REDUCE(reduce_udiv, mk_udiv);
MK_BIN_REDUCE(reduce_urem, mk_urem);
MK_BIN_REDUCE(reduce_sdiv, mk_sdiv);
MK_BIN_REDUCE(reduce_srem, mk_srem);
MK_BIN_REDUCE(reduce_smod, mk_smod);
void eager_bit_blaster::bv_plugin::reduce_extract(unsigned start, unsigned end, expr * arg, expr_ref & result) {
expr_ref_vector bits(m_manager);
get_bits(arg, bits);
expr_ref_vector out_bits(m_manager);
for (unsigned i = start; i <= end; ++i)
out_bits.push_back(bits.get(i));
result = mk_mkbv(out_bits);
}
void eager_bit_blaster::bv_plugin::reduce_concat(unsigned num_args, expr * const * args, expr_ref & result) {
expr_ref_vector out_bits(m_manager);
unsigned i = num_args;
while (i > 0) {
i--;
expr_ref_vector bits(m_manager);
get_bits(args[i], bits);
out_bits.append(bits.size(), bits.c_ptr());
}
result = mk_mkbv(out_bits);
}
bool eager_bit_blaster::bv_plugin::reduce_ite(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
sort * s = m_manager.get_sort(arg2);
if (!m_util.is_bv_sort(s))
return false;
expr_ref_vector bits1(m_manager);
expr_ref_vector bits2(m_manager);
get_bits(arg2, bits1);
get_bits(arg3, bits2);
SASSERT(bits1.size() == bits2.size());
expr_ref_vector out_bits(m_manager);
unsigned bv_size = bits1.size();
for (unsigned i = 0; i < bv_size; i++) {
expr_ref new_bit(m_manager);
m_s.mk_ite(arg1, bits1.get(i), bits2.get(i), new_bit);
out_bits.push_back(new_bit);
}
result = mk_mkbv(out_bits);
return true;
}
bool eager_bit_blaster::bv_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
bv_op_kind k = static_cast<bv_op_kind>(f->get_decl_kind());
switch (k) {
case OP_BNOT:
SASSERT(num_args == 1);
reduce_not(args[0], result);
return true;
case OP_BOR:
reduce_or(num_args, args, result);
return true;
case OP_BAND:
reduce_and(num_args, args, result);
return true;
case OP_BNOR:
reduce_nor(num_args, args, result);
return true;
case OP_BNAND:
reduce_nand(num_args, args, result);
return true;
case OP_BXOR:
SASSERT(num_args == 2);
reduce_xor(args[0], args[1], result);
return true;
case OP_BXNOR:
SASSERT(num_args == 2);
reduce_xnor(args[0], args[1], result);
return true;
case OP_BNEG:
SASSERT(num_args == 1);
reduce_neg(args[0], result);
return true;
case OP_BADD:
reduce_add(num_args, args, result);
return true;
case OP_BMUL:
reduce_mul(num_args, args, result);
return true;
case OP_BIT1:
case OP_BIT0:
case OP_BSUB:
// I'm assuming the expressions were simplified before invoking this method.
UNREACHABLE();
return false;
case OP_BSDIV:
case OP_BUDIV:
case OP_BSREM:
case OP_BUREM:
case OP_BSMOD:
// I'm assuming the expressions were simplified before invoking this method.
UNREACHABLE();
return false;
case OP_BSDIV0:
case OP_BUDIV0:
case OP_BSREM0:
case OP_BUREM0:
case OP_BSMOD0:
// do nothing... these are uninterpreted
return true;
case OP_BSDIV_I:
SASSERT(num_args == 2);
reduce_sdiv(args[0], args[1], result);
return true;
case OP_BUDIV_I:
SASSERT(num_args == 2);
reduce_udiv(args[0], args[1], result);
return true;
case OP_BSREM_I:
SASSERT(num_args == 2);
reduce_srem(args[0], args[1], result);
return true;
case OP_BUREM_I:
SASSERT(num_args == 2);
reduce_urem(args[0], args[1], result);
return true;
case OP_BSMOD_I:
SASSERT(num_args == 2);
reduce_smod(args[0], args[1], result);
return true;
case OP_ULEQ:
SASSERT(num_args == 2);
reduce_ule(args[0], args[1], result);
return true;
case OP_SLEQ:
SASSERT(num_args == 2);
reduce_sle(args[0], args[1], result);
return true;
case OP_UGEQ:
case OP_SGEQ:
case OP_ULT:
case OP_SLT:
case OP_UGT:
case OP_SGT:
// I'm assuming the expressions were simplified before invoking this method.
UNREACHABLE();
return false;
case OP_EXTRACT:
SASSERT(num_args == 1);
reduce_extract(f->get_parameter(1).get_int(), f->get_parameter(0).get_int(), args[0], result);
return true;
case OP_CONCAT:
reduce_concat(num_args, args, result);
return true;
case OP_SIGN_EXT:
SASSERT(num_args == 1);
reduce_sign_extend(args[0], f->get_parameter(0).get_int(), result);
return true;
case OP_ZERO_EXT:
SASSERT(num_args == 1);
reduce_zero_extend(args[0], f->get_parameter(0).get_int(), result);
return true;
case OP_REPEAT:
UNREACHABLE();
return false;
case OP_BREDOR:
SASSERT(num_args == 1);
reduce_redor(args[0], result);
return true;
case OP_BREDAND:
SASSERT(num_args == 1);
reduce_redand(args[0], result);
return true;
case OP_BCOMP:
SASSERT(num_args == 2);
reduce_comp(args[0], args[1], result);
return true;
case OP_BSHL:
SASSERT(num_args == 2);
reduce_shl(args[0], args[1], result);
return true;
case OP_BLSHR:
SASSERT(num_args == 2);
reduce_lshr(args[0], args[1], result);
return true;
case OP_BASHR:
SASSERT(num_args == 2);
reduce_ashr(args[0], args[1], result);
return true;
case OP_ROTATE_LEFT:
SASSERT(num_args == 1);
reduce_rotate_left(args[0], f->get_parameter(0).get_int(), result);
return true;
case OP_ROTATE_RIGHT:
SASSERT(num_args == 1);
reduce_rotate_right(args[0], f->get_parameter(0).get_int(), result);
return true;
default:
return false;
}
}
bool eager_bit_blaster::bv_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) {
TRACE("eager_bb_eq", tout << mk_ll_pp(lhs, m_manager) << "\n" << mk_ll_pp(rhs, m_manager) << "\n";);
SASSERT(m_util.get_bv_size(lhs) == m_util.get_bv_size(rhs));
expr_ref_vector bits1(m_manager);
expr_ref_vector bits2(m_manager);
get_bits(lhs, bits1);
get_bits(rhs, bits2);
SASSERT(bits1.size() == bits2.size());
m_bb.mk_eq(bits1.size(), bits1.c_ptr(), bits2.c_ptr(), result);
return true;
}
bool eager_bit_blaster::bv_plugin::reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result) {
if (num_args <= 1) {
result = m_manager.mk_true();
}
if (num_args == 2) {
expr_ref tmp(m_manager);
reduce_eq(args[0], args[1], tmp);
m_s.mk_not(tmp, result);
}
else {
expr_ref_vector new_args(m_manager);
for (unsigned i = 0; i < num_args - 1; i++) {
expr * a1 = args[i];
for (unsigned j = i + 1; j < num_args; j++) {
expr * a2 = args[j];
expr_ref tmp1(m_manager);
reduce_eq(a1, a2, tmp1);
expr_ref tmp2(m_manager);
m_s.mk_not(tmp1, tmp2);
new_args.push_back(tmp2);
}
}
m_s.mk_and(new_args.size(), new_args.c_ptr(), result);
}
return true;
}
eager_bit_blaster::eager_bit_blaster(ast_manager & m, bit_blaster_params const & p):
m_simplifier(m) {
m_simplifier.enable_ac_support(false);
bv_plugin * bv_p = alloc(bv_plugin, m, p);
m_simplifier.register_plugin(bv_p);
m_simplifier.register_plugin(alloc(basic_plugin, m, *bv_p, bv_p->get_basic_simplifier()));
}
void eager_bit_blaster::operator()(expr * s, expr_ref & r, proof_ref & p) {
m_simplifier.operator()(s, r, p);
}

View file

@ -0,0 +1,107 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
eager_bit_blaster.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-10-02.
Revision History:
--*/
#ifndef _EAGER_BIT_BLASTER_H_
#define _EAGER_BIT_BLASTER_H_
#include"bv_decl_plugin.h"
#include"bit_blaster.h"
#include"simplifier.h"
#include"basic_simplifier_plugin.h"
class eager_bit_blaster {
class bv_plugin : public simplifier_plugin {
bv_util m_util;
bit_blaster m_bb;
basic_simplifier_plugin m_s;
void get_bits(expr * n, expr_ref_vector & out_bits);
app * mk_mkbv(expr_ref_vector const & bits);
void reduce_not(expr * arg, expr_ref & result);
void reduce_bin_or(expr * arg1, expr * arg2, expr_ref & result);
void reduce_or(unsigned num_args, expr * const * args, expr_ref & result);
void reduce_bin_and(expr * arg1, expr * arg2, expr_ref & result);
void reduce_and(unsigned num_args, expr * const * args, expr_ref & result);
void reduce_bin_nor(expr * arg1, expr * arg2, expr_ref & result);
void reduce_nor(unsigned num_args, expr * const * args, expr_ref & result);
void reduce_bin_nand(expr * arg1, expr * arg2, expr_ref & result);
void reduce_nand(unsigned num_args, expr * const * args, expr_ref & result);
void reduce_xor(expr * arg1, expr * arg2, expr_ref & result);
void reduce_xnor(expr * arg1, expr * arg2, expr_ref & result);
void reduce_neg(expr * arg, expr_ref & result);
void reduce_bin_add(expr * arg1, expr * arg2, expr_ref & result);
void reduce_add(unsigned num_args, expr * const * args, expr_ref & result);
void reduce_bin_mul(expr * arg1, expr * arg2, expr_ref & result);
void reduce_mul(unsigned num_args, expr * const * args, expr_ref & result);
void reduce_sdiv(expr * arg1, expr * arg2, expr_ref & result);
void reduce_udiv(expr * arg1, expr * arg2, expr_ref & result);
void reduce_srem(expr * arg1, expr * arg2, expr_ref & result);
void reduce_urem(expr * arg1, expr * arg2, expr_ref & result);
void reduce_smod(expr * arg1, expr * arg2, expr_ref & result);
void reduce_sle(expr * arg1, expr * arg2, expr_ref & result);
void reduce_ule(expr * arg1, expr * arg2, expr_ref & result);
void reduce_concat(unsigned num_args, expr * const * args, expr_ref & result);
void reduce_extract(unsigned start, unsigned end, expr * arg, expr_ref & result);
void reduce_redor(expr * arg, expr_ref & result);
void reduce_redand(expr * arg, expr_ref & result);
void reduce_comp(expr * arg1, expr * arg2, expr_ref & result);
void reduce_shl(expr * arg1, expr * arg2, expr_ref & result);
void reduce_ashr(expr * arg1, expr * arg2, expr_ref & result);
void reduce_lshr(expr * arg1, expr * arg2, expr_ref & result);
void reduce_rotate_left(expr * arg, unsigned n, expr_ref & result);
void reduce_rotate_right(expr * arg, unsigned n, expr_ref & result);
void reduce_sign_extend(expr * arg, unsigned n, expr_ref & result);
void reduce_zero_extend(expr * arg, unsigned n, expr_ref & result);
public:
bv_plugin(ast_manager & m, bit_blaster_params const & p);
virtual ~bv_plugin();
virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result);
virtual bool reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result);
basic_simplifier_plugin & get_basic_simplifier() { return m_s; }
bool reduce_ite(expr * arg1, expr * arg2, expr * arg3, expr_ref & result);
};
/**
\brief Plugin for handling the term-ite.
*/
class basic_plugin : public simplifier_plugin {
bv_plugin & m_main;
basic_simplifier_plugin & m_s;
public:
basic_plugin(ast_manager & m, bv_plugin & p, basic_simplifier_plugin & s);
virtual ~basic_plugin();
virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
};
simplifier m_simplifier;
public:
eager_bit_blaster(ast_manager & m, bit_blaster_params const & p);
void operator()(expr * s, expr_ref & r, proof_ref & p);
};
#endif /* _EAGER_BIT_BLASTER_H_ */