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

checkpoint

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2012-10-25 15:44:53 -07:00
parent 8a4f6d5719
commit 1ea606092c
50 changed files with 279 additions and 211 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,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 rewriter_exception(Z3_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 rewriter_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,134 @@
/*++
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"
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,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_ */