#pragma once
#include "util/rational.h"
#include "util/common_msgs.h"
#include "ast/rewriter/bit_blaster/bit_blaster_tpl.h"
#include "ast/ast_pp.h"
#include "ast/rewriter/rewriter_types.h"
template<typename Cfg>
void bit_blaster_tpl<Cfg>::checkpoint() {
if (memory::get_allocation_size() > m_max_memory || memory::above_high_watermark())
throw rewriter_exception(Z3_MAX_MEMORY_MSG);
if (!m().inc())
throw rewriter_exception(m().limit().get_cancel_msg());
}
template<typename Cfg>
bool bit_blaster_tpl<Cfg>::is_numeral(unsigned sz, expr * const * bits) const {
for (unsigned i = 0; i < sz; i++)
if (!is_bool_const(bits[i]))
return false;
return true;
}
template<typename Cfg>
bool bit_blaster_tpl<Cfg>::is_numeral(unsigned sz, expr * const * bits, numeral & r) const {
r.reset();
for (unsigned i = 0; i < sz; i++) {
if (m().is_true(bits[i]))
r += power(i);
else if (!m().is_false(bits[i]))
return false;
}
return true;
}
template<typename Cfg>
bool bit_blaster_tpl<Cfg>::is_minus_one(unsigned sz, expr * const * bits) const {
for (unsigned i = 0; i < sz; i++)
if (!m().is_true(bits[i]))
return false;
return true;
}
static void _num2bits(ast_manager & m, rational const & v, unsigned sz, expr_ref_vector & out_bits) {
SASSERT(v.is_nonneg());
rational aux = v;
rational two(2), base32(1ull << 32ull, rational::ui64());
for (unsigned i = 0; i < sz; i++) {
if (i + 32 < sz) {
unsigned u = (aux % base32).get_unsigned();
for (unsigned j = 0; j < 32; ++j) {
if (0 != (u & (1 << j))) {
out_bits.push_back(m.mk_true());
}
else {
out_bits.push_back(m.mk_false());
}
}
aux = div(aux, base32);
i += 31;
continue;
}
else if ((aux % two).is_zero())
out_bits.push_back(m.mk_false());
else
out_bits.push_back(m.mk_true());
aux = div(aux, two);
}
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::num2bits(numeral const & v, unsigned sz, expr_ref_vector & out_bits) const {
_num2bits(m(), v, sz, out_bits);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_half_adder(expr * a, expr * b, expr_ref & out, expr_ref & cout) {
mk_xor(a, b, out);
mk_and(a, b, cout);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_full_adder(expr * a, expr * b, expr * cin, expr_ref & out, expr_ref & cout) {
mk_xor3(a, b, cin, out);
mk_carry(a, b, cin, cout);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_neg(unsigned sz, expr * const * a_bits, expr_ref_vector & out_bits) {
SASSERT(sz > 0);
expr_ref cin(m()), cout(m()), out(m());
cin = m().mk_true();
for (unsigned idx = 0; idx < sz; idx++) {
expr_ref not_a(m());
mk_not(a_bits[idx], not_a);
if (idx < sz - 1)
mk_half_adder(not_a, cin, out, cout);
else
mk_xor(not_a, cin, out);
out_bits.push_back(out);
cin = cout;
}
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_adder(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
SASSERT(sz > 0);
expr_ref cin(m()), cout(m()), out(m());
cin = m().mk_false();
for (unsigned idx = 0; idx < sz; idx++) {
if (idx < sz - 1)
mk_full_adder(a_bits[idx], b_bits[idx], cin, out, cout);
else
mk_xor3(a_bits[idx], b_bits[idx], cin, out);
out_bits.push_back(out);
cin = cout;
}
#if 0#endif
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_subtracter(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits, expr_ref & cout) {
SASSERT(sz > 0);
expr_ref cin(m()), out(m());
cin = m().mk_true();
for (unsigned j = 0; j < sz; j++) {
expr_ref not_b(m());
mk_not(b_bits[j], not_b);
mk_full_adder(a_bits[j], not_b, cin, out, cout);
out_bits.push_back(out);
cin = cout;
}
#if 0#endif
SASSERT(out_bits.size() == sz);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
SASSERT(sz > 0);
numeral n_a, n_b;
out_bits.reset();
if (is_numeral(sz, a_bits, n_b))
std::swap(a_bits, b_bits);
if (is_minus_one(sz, b_bits)) {
mk_neg(sz, a_bits, out_bits);
SASSERT(sz == out_bits.size());
return;
}
if (is_numeral(sz, a_bits, n_a)) {
n_a *= n_b;
num2bits(n_a, sz, out_bits);
SASSERT(sz == out_bits.size());
return;
}
if (mk_const_case_multiplier(sz, a_bits, b_bits, out_bits)) {
SASSERT(sz == out_bits.size());
return;
}
out_bits.reset();
#if 0#endif
expr_ref_vector cins(m()), couts(m());
expr_ref out(m()), cout(m());
mk_and(a_bits[0], b_bits[0], out);
out_bits.push_back(out);
for (unsigned i = 1; i < sz; i++) {
checkpoint();
couts.reset();
expr_ref i1(m()), i2(m());
mk_and(a_bits[0], b_bits[i], i1);
mk_and(a_bits[1], b_bits[i - 1], i2);
if (i < sz - 1) {
mk_half_adder(i1, i2, out, cout);
couts.push_back(cout);
for (unsigned j = 2; j <= i; j++) {
expr_ref prev_out(m());
prev_out = out;
expr_ref i3(m());
mk_and(a_bits[j], b_bits[i - j], i3);
mk_full_adder(i3, prev_out, cins.get(j - 2), out, cout);
couts.push_back(cout);
}
out_bits.push_back(out);
cins.swap(couts);
}
else {
mk_xor(i1, i2, out);
for (unsigned j = 2; j <= i; j++) {
expr_ref i3(m());
mk_and(a_bits[j], b_bits[i - j], i3);
mk_xor3(i3, out, cins.get(j - 2), out);
}
out_bits.push_back(out);
}
}
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_umul_no_overflow(unsigned sz, expr* const* a_bits, expr* const* b_bits, expr_ref& result) {
SASSERT(sz > 0);
expr_ref zero(m());
zero = m().mk_false();
ptr_buffer<expr, 128> ext_a_bits;
ptr_buffer<expr, 128> ext_b_bits;
ext_a_bits.append(sz, a_bits);
ext_b_bits.append(sz, b_bits);
ext_a_bits.push_back(zero);
ext_b_bits.push_back(zero);
SASSERT(ext_a_bits.size() == 1 + sz);
SASSERT(ext_b_bits.size() == 1 + sz);
expr_ref_vector mult_cout(m());
mk_multiplier(1 + sz, ext_a_bits.data(), ext_b_bits.data(), mult_cout);
expr_ref overflow1(m()), overflow2(m()), overflow(m());
overflow1 = mult_cout[sz].get();
expr_ref ovf(m()), v(m()), tmp(m());
ovf = m().mk_false();
v = m().mk_false();
for (unsigned i = 1; i < sz; ++i) {
mk_or(ovf, a_bits[sz-i], ovf);
mk_and(ovf, b_bits[i], tmp);
mk_or(tmp, v, v);
}
overflow2 = v;
mk_or(overflow1, overflow2, overflow);
mk_not(overflow, result);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_smul_no_overflow_core(unsigned sz, expr * const * a_bits, expr * const * b_bits, bool is_overflow, expr_ref & result) {
SASSERT(sz > 0);
expr_ref zero(m());
zero = m().mk_false();
ptr_buffer<expr,128> ext_a_bits;
ptr_buffer<expr,128> ext_b_bits;
ext_a_bits.append(sz, a_bits);
ext_b_bits.append(sz, b_bits);
ext_a_bits.push_back(a_bits[sz-1]);
ext_b_bits.push_back(b_bits[sz-1]);
SASSERT(ext_a_bits.size() == 1 + sz);
SASSERT(ext_b_bits.size() == 1 + sz);
expr_ref_vector mult_cout(m());
mk_multiplier(1 + sz, ext_a_bits.data(), ext_b_bits.data(), mult_cout);
expr_ref overflow1(m()), overflow2(m()), overflow(m());
mk_xor(mult_cout[sz].get(), mult_cout[sz-1].get(), overflow1);
expr_ref v(m()), tmp(m()), a(m()), b(m()), a_acc(m()), sign(m());
a_acc = m().mk_false();
v = m().mk_false();
for (unsigned i = 1; i + 1 < sz; ++i) {
mk_xor(b_bits[sz-1], b_bits[i], b);
mk_xor(a_bits[sz-1], a_bits[sz-1-i], a);
mk_or(a, a_acc, a_acc);
mk_and(a_acc, b, tmp);
mk_or(tmp, v, v);
}
overflow2 = v;
mk_or(overflow1, overflow2, overflow);
if (is_overflow) {
mk_iff(a_bits[sz-1], b_bits[sz-1], sign);
}
else {
mk_xor(a_bits[sz-1], b_bits[sz-1], sign);
}
mk_and(sign, overflow, overflow);
mk_not(overflow, result);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_smul_no_overflow(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref & result) {
mk_smul_no_overflow_core(sz, a_bits, b_bits, true, result);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_smul_no_underflow(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref & result) {
mk_smul_no_overflow_core(sz, a_bits, b_bits, false, result);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_udiv_urem(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & q_bits, expr_ref_vector & r_bits) {
SASSERT(sz > 0);
expr_ref_vector & p = r_bits;
expr_ref_vector t(m());
p.push_back(a_bits[sz-1]);
for (unsigned i = 1; i < sz; i++)
p.push_back(m().mk_false());
q_bits.resize(sz);
for (unsigned i = 0; i < sz; i++) {
checkpoint();
expr_ref q(m());
t.reset();
mk_subtracter(sz, p.data(), b_bits, t, q);
q_bits.set(sz - i - 1, q);
if (i < sz - 1) {
for (unsigned j = sz - 1; j > 0; j--) {
expr_ref ie(m());
mk_ite(q, t.get(j-1), p.get(j-1), ie);
p.set(j, ie);
}
p.set(0, a_bits[sz - i - 2]);
}
else {
for (unsigned j = 0; j < sz; j++) {
expr_ref ie(m());
mk_ite(q, t.get(j), p.get(j), ie);
p.set(j, ie);
}
}
}
DEBUG_CODE({
for (unsigned i = 0; i < sz; i++) {
SASSERT(q_bits.get(i) != 0);
}});
TRACE(bit_blaster,
tout << "a: ";
for (unsigned i = 0; i < sz; ++i) tout << mk_pp(a_bits[i], m()) << " ";
tout << "\nb: ";
for (unsigned i = 0; i < sz; ++i) tout << mk_pp(b_bits[i], m()) << " ";
tout << "\nq: ";
for (unsigned i = 0; i < sz; ++i) tout << mk_pp(q_bits[i].get(), m()) << " ";
tout << "\nr: ";
for (unsigned i = 0; i < sz; ++i) tout << mk_pp(r_bits[i].get(), m()) << " ";
tout << "\n";
);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_udiv(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & q_bits) {
expr_ref_vector aux(m());
mk_udiv_urem(sz, a_bits, b_bits, q_bits, aux);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_urem(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & r_bits) {
expr_ref_vector aux(m());
mk_udiv_urem(sz, a_bits, b_bits, aux, r_bits);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_multiplexer(expr * c, unsigned sz, expr * const * t_bits, expr * const * e_bits, expr_ref_vector & out_bits) {
for (unsigned i = 0; i < sz; i++) {
expr_ref t(m());
mk_ite(c, t_bits[i], e_bits[i], t);
out_bits.push_back(t);
}
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_abs(unsigned sz, expr * const * a_bits, expr_ref_vector & out_bits) {
expr * a_msb = a_bits[sz - 1];
if (m().is_false(a_msb)) {
out_bits.append(sz, a_bits);
}
else if (m().is_true(a_msb)) {
mk_neg(sz, a_bits, out_bits);
}
else {
expr_ref_vector neg_a_bits(m());
mk_neg(sz, a_bits, neg_a_bits);
mk_multiplexer(a_msb, sz, neg_a_bits.data(), a_bits, out_bits);
}
}
#define SDIV 0
#define SREM 1
#define SMOD 2
template<typename Cfg>
template<unsigned k>
void bit_blaster_tpl<Cfg>::mk_sdiv_srem_smod(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
SASSERT(k == SDIV || k == SREM || k == SMOD);
expr * a_msb = a_bits[sz - 1];
expr * b_msb = b_bits[sz - 1];
expr_ref_vector neg_a_bits(m());
expr_ref_vector neg_b_bits(m());
mk_neg(sz, a_bits, neg_a_bits);
mk_neg(sz, b_bits, neg_b_bits);
expr_ref_vector pp_q(m()), pp_r(m()), pn_q(m()), pn_r(m()), np_q(m()), np_r(m()), nn_q(m()), nn_r(m());
if (!m().is_true(a_msb) && !m().is_true(b_msb)) {
mk_udiv_urem(sz, a_bits, b_bits, pp_q, pp_r);
}
else {
pp_q.resize(sz, m().mk_false());
pp_r.resize(sz, m().mk_false());
}
if (!m().is_false(a_msb) && !m().is_true(b_msb)) {
mk_udiv_urem(sz, neg_a_bits.data(), b_bits, np_q, np_r);
}
else {
np_q.resize(sz, m().mk_false());
np_r.resize(sz, m().mk_false());
}
if (!m().is_true(a_msb) && !m().is_false(b_msb)) {
mk_udiv_urem(sz, a_bits, neg_b_bits.data(), pn_q, pn_r);
}
else {
pn_q.resize(sz, m().mk_false());
pn_r.resize(sz, m().mk_false());
}
if (!m().is_false(a_msb) && !m().is_false(b_msb)) {
mk_udiv_urem(sz, neg_a_bits.data(), neg_b_bits.data(), nn_q, nn_r);
}
else {
nn_q.resize(sz, m().mk_false());
nn_r.resize(sz, m().mk_false());
}
expr_ref_vector ite1(m()), ite2(m());
if (k == SDIV) {
expr_ref_vector & pp_out = pp_q;
expr_ref_vector np_out(m());
expr_ref_vector pn_out(m());
expr_ref_vector & nn_out = nn_q;
if (!m().is_false(a_msb) && !m().is_true(b_msb))
mk_neg(sz, np_q.data(), np_out);
else
np_out.resize(sz, m().mk_false());
if (!m().is_true(a_msb) && !m().is_false(b_msb))
mk_neg(sz, pn_q.data(), pn_out);
else
pn_out.resize(sz, m().mk_false());
#define MK_MULTIPLEXER() \
mk_multiplexer(b_msb, sz, nn_out.data(), np_out.data(), ite1); \
mk_multiplexer(b_msb, sz, pn_out.data(), pp_out.data(), ite2); \
mk_multiplexer(a_msb, sz, ite1.data(), ite2.data(), out_bits)
MK_MULTIPLEXER();
}
else if (k == SREM) {
expr_ref_vector & pp_out = pp_r;
expr_ref_vector np_out(m());
expr_ref_vector & pn_out = pn_r;
expr_ref_vector nn_out(m());
if (!m().is_false(a_msb) && !m().is_true(b_msb))
mk_neg(sz, np_r.data(), np_out);
else
np_out.resize(sz, m().mk_false());
if (!m().is_false(a_msb) && !m().is_false(b_msb))
mk_neg(sz, nn_r.data(), nn_out);
else
nn_out.resize(sz, m().mk_false());
MK_MULTIPLEXER();
}
else {
SASSERT(k == SMOD);
expr_ref_vector & pp_out = pp_r;
expr_ref_vector np_out(m());
expr_ref_vector pn_out(m());
expr_ref_vector nn_out(m());
if (!m().is_false(a_msb) && !m().is_true(b_msb)) {
expr_ref cout(m());
mk_subtracter(sz, b_bits, np_r.data(), np_out, cout);
}
else
np_out.resize(sz, m().mk_false());
if (!m().is_true(a_msb) && !m().is_false(b_msb))
mk_adder(sz, b_bits, pn_r.data(), pn_out);
else
pn_out.resize(sz, m().mk_false());
if (!m().is_false(a_msb) && !m().is_false(b_msb))
mk_neg(sz, nn_r.data(), nn_out);
else
nn_out.resize(sz, m().mk_false());
MK_MULTIPLEXER();
}
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_sdiv(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
expr * a_msb = a_bits[sz - 1];
expr * b_msb = b_bits[sz - 1];
if (m().is_false(a_msb) && m().is_false(b_msb)) {
mk_udiv(sz, a_bits, b_bits, out_bits);
}
else if (m().is_false(a_msb) && m().is_true(b_msb)) {
expr_ref_vector neg_b_bits(m());
mk_neg(sz, b_bits, neg_b_bits);
expr_ref_vector tmp(m());
mk_udiv(sz, a_bits, neg_b_bits.data(), tmp);
mk_neg(sz, tmp.data(), out_bits);
}
else if (m().is_true(a_msb) && m().is_false(b_msb)) {
expr_ref_vector neg_a_bits(m());
mk_neg(sz, a_bits, neg_a_bits);
expr_ref_vector tmp(m());
mk_udiv(sz, neg_a_bits.data(), b_bits, tmp);
mk_neg(sz, tmp.data(), out_bits);
}
else if (m().is_true(a_msb) && m().is_true(b_msb)) {
expr_ref_vector neg_a_bits(m());
mk_neg(sz, a_bits, neg_a_bits);
expr_ref_vector neg_b_bits(m());
mk_neg(sz, b_bits, neg_b_bits);
mk_udiv(sz, neg_a_bits.data(), neg_b_bits.data(), out_bits);
}
else {
#if 0#else
expr_ref_vector abs_a_bits(m());
expr_ref_vector abs_b_bits(m());
mk_abs(sz, a_bits, abs_a_bits);
mk_abs(sz, b_bits, abs_b_bits);
expr_ref_vector udiv_bits(m());
mk_udiv(sz, abs_a_bits.data(), abs_b_bits.data(), udiv_bits);
expr_ref_vector neg_udiv_bits(m());
mk_neg(sz, udiv_bits.data(), neg_udiv_bits);
expr_ref c(m());
mk_iff(a_msb, b_msb, c);
mk_multiplexer(c, sz, udiv_bits.data(), neg_udiv_bits.data(), out_bits);
#endif
}
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_srem(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
expr * a_msb = a_bits[sz - 1];
expr * b_msb = b_bits[sz - 1];
if (m().is_false(a_msb) && m().is_false(b_msb)) {
mk_urem(sz, a_bits, b_bits, out_bits);
}
else if (m().is_false(a_msb) && m().is_true(b_msb)) {
expr_ref_vector neg_b_bits(m());
mk_neg(sz, b_bits, neg_b_bits);
mk_urem(sz, a_bits, neg_b_bits.data(), out_bits);
}
else if (m().is_true(a_msb) && m().is_false(b_msb)) {
expr_ref_vector neg_a_bits(m());
mk_neg(sz, a_bits, neg_a_bits);
expr_ref_vector tmp(m());
mk_urem(sz, neg_a_bits.data(), b_bits, tmp);
mk_neg(sz, tmp.data(), out_bits);
}
else if (m().is_true(a_msb) && m().is_true(b_msb)) {
expr_ref_vector neg_a_bits(m());
mk_neg(sz, a_bits, neg_a_bits);
expr_ref_vector neg_b_bits(m());
mk_neg(sz, b_bits, neg_b_bits);
expr_ref_vector tmp(m());
mk_urem(sz, neg_a_bits.data(), neg_b_bits.data(), tmp);
mk_neg(sz, tmp.data(), out_bits);
}
else {
#if 0#else
expr_ref_vector abs_a_bits(m());
expr_ref_vector abs_b_bits(m());
mk_abs(sz, a_bits, abs_a_bits);
mk_abs(sz, b_bits, abs_b_bits);
expr_ref_vector urem_bits(m());
numeral n_b;
unsigned shift;
if (is_numeral(sz, abs_b_bits.data(), n_b) && n_b.is_power_of_two(shift)) {
mk_zero_extend(shift, abs_a_bits.data(), sz - shift, urem_bits);
} else {
mk_urem(sz, abs_a_bits.data(), abs_b_bits.data(), urem_bits);
}
expr_ref_vector neg_urem_bits(m());
mk_neg(sz, urem_bits.data(), neg_urem_bits);
mk_multiplexer(a_msb, sz, neg_urem_bits.data(), urem_bits.data(), out_bits);
#endif
}
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_smod(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
expr * a_msb = a_bits[sz - 1];
expr * b_msb = b_bits[sz - 1];
expr_ref_vector abs_a_bits(m());
expr_ref_vector abs_b_bits(m());
mk_abs(sz, a_bits, abs_a_bits);
mk_abs(sz, b_bits, abs_b_bits);
expr_ref_vector u_bits(m());
mk_urem(sz, abs_a_bits.data(), abs_b_bits.data(), u_bits);
expr_ref_vector neg_u_bits(m());
mk_neg(sz, u_bits.data(), neg_u_bits);
expr_ref_vector neg_u_add_b(m());
mk_adder(sz, neg_u_bits.data(), b_bits, neg_u_add_b);
expr_ref_vector u_add_b(m());
mk_adder(sz, u_bits.data(), b_bits, u_add_b);
expr_ref_vector zero(m());
num2bits(numeral(0), sz, zero);
expr_ref u_eq_0(m());
mk_eq(sz, u_bits.data(), zero.data(), u_eq_0);
expr_ref_vector & pp_bits = u_bits; expr_ref_vector & pn_bits = u_add_b; expr_ref_vector & np_bits = neg_u_add_b; expr_ref_vector & nn_bits = neg_u_bits;
expr_ref_vector ite1(m());
expr_ref_vector ite2(m());
expr_ref_vector body(m());
mk_multiplexer(b_msb, sz, nn_bits.data(), np_bits.data(), ite1);
mk_multiplexer(b_msb, sz, pn_bits.data(), pp_bits.data(), ite2);
mk_multiplexer(a_msb, sz, ite1.data(), ite2.data(), body);
mk_multiplexer(u_eq_0, sz, u_bits.data(), body.data(), out_bits);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_eq(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref & out) {
expr_ref_vector out_bits(m());
for (unsigned i = 0; i < sz; i++) {
mk_iff(a_bits[i], b_bits[i], out);
out_bits.push_back(out);
}
mk_and(out_bits.size(), out_bits.data(), out);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_rotate_left(unsigned sz, expr * const * a_bits, unsigned n, expr_ref_vector & out_bits) {
TRACE(bit_blaster, tout << n << ": " << sz << " ";
for (unsigned i = 0; i < sz; ++i) {
tout << mk_pp(a_bits[i], m()) << " ";
}
tout << "\n";
);
n = n % sz;
for (unsigned i = sz - n; i < sz; i++)
out_bits.push_back(a_bits[i]);
for (unsigned i = 0 ; i < sz - n; i++)
out_bits.push_back(a_bits[i]);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_rotate_right(unsigned sz, expr * const * a_bits, unsigned n, expr_ref_vector & out_bits) {
n = n % sz;
mk_rotate_left(sz, a_bits, sz - n, out_bits);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_sign_extend(unsigned sz, expr * const * a_bits, unsigned n, expr_ref_vector & out_bits) {
for (unsigned i = 0; i < sz; i++)
out_bits.push_back(a_bits[i]);
expr * high_bit = a_bits[sz - 1];
for (unsigned i = sz; i < sz + n; i++)
out_bits.push_back(high_bit);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_zero_extend(unsigned sz, expr * const * a_bits, unsigned n, expr_ref_vector & out_bits) {
for (unsigned i = 0; i < sz; i++)
out_bits.push_back(a_bits[i]);
expr * high_bit = m().mk_false();
for (unsigned i = sz; i < sz + n; i++)
out_bits.push_back(high_bit);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_is_eq(unsigned sz, expr * const * a_bits, unsigned n, expr_ref & out) {
numeral two(2);
expr_ref_vector out_bits(m());
for (unsigned i = 0; i < sz; i++) {
if (n % 2 == 0) {
expr_ref not_a(m());
mk_not(a_bits[i], not_a);
out_bits.push_back(not_a);
}
else {
out_bits.push_back(a_bits[i]);
}
n = n / 2;
}
mk_and(out_bits.size(), out_bits.data(), out);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_eqs(unsigned sz, expr * const * a_bits, expr_ref_vector & eqs) {
for (unsigned i = 0; i < sz; i++) {
expr_ref eq(m());
mk_is_eq(sz, a_bits, i, eq);
eqs.push_back(eq);
}
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_shl(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
numeral k;
if (is_numeral(sz, b_bits, k)) {
if (k > numeral(sz)) k = numeral(sz);
unsigned n = static_cast<unsigned>(k.get_int64());
if (n >= sz) n = sz;
unsigned pos;
for (pos = 0; pos < n; pos++)
out_bits.push_back(m().mk_false());
for (unsigned i = 0; pos < sz; pos++, i++)
out_bits.push_back(a_bits[i]);
}
else {
out_bits.append(sz, a_bits);
unsigned i = 0;
expr_ref_vector new_out_bits(m());
for (; i < sz; ++i) {
checkpoint();
unsigned shift_i = 1 << i;
if (shift_i >= sz) break;
for (unsigned j = 0; j < sz; ++j) {
expr_ref new_out(m());
expr* a_j = m().mk_false();
if (shift_i <= j) a_j = out_bits[j-shift_i].get();
mk_ite(b_bits[i], a_j, out_bits[j].get(), new_out);
new_out_bits.push_back(new_out);
}
out_bits.reset();
out_bits.append(new_out_bits);
new_out_bits.reset();
}
expr_ref is_large(m());
is_large = m().mk_false();
for (; i < sz; ++i) {
mk_or(is_large, b_bits[i], is_large);
}
for (unsigned j = 0; j < sz; ++j) {
expr_ref new_out(m());
mk_ite(is_large, m().mk_false(), out_bits[j].get(), new_out);
out_bits[j] = new_out;
}
}
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_lshr(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
numeral k;
if (is_numeral(sz, b_bits, k)) {
if (k > numeral(sz)) k = numeral(sz);
unsigned n = static_cast<unsigned>(k.get_int64());
unsigned pos = 0;
for (unsigned i = n; i < sz; pos++, i++)
out_bits.push_back(a_bits[i]);
for (; pos < sz; pos++)
out_bits.push_back(m().mk_false());
}
else {
out_bits.append(sz, a_bits);
unsigned i = 0;
for (; i < sz; ++i) {
checkpoint();
expr_ref_vector new_out_bits(m());
unsigned shift_i = 1 << i;
if (shift_i >= sz) break;
for (unsigned j = 0; j < sz; ++j) {
expr_ref new_out(m());
expr* a_j = m().mk_false();
if (shift_i + j < sz) a_j = out_bits[j+shift_i].get();
mk_ite(b_bits[i], a_j, out_bits[j].get(), new_out);
new_out_bits.push_back(new_out);
}
out_bits.reset();
out_bits.append(new_out_bits);
}
expr_ref is_large(m());
is_large = m().mk_false();
for (; i < sz; ++i) {
mk_or(is_large, b_bits[i], is_large);
}
for (unsigned j = 0; j < sz; ++j) {
expr_ref new_out(m());
mk_ite(is_large, m().mk_false(), out_bits[j].get(), new_out);
out_bits[j] = new_out;
}
}
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_ashr(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
numeral k;
if (is_numeral(sz, b_bits, k)) {
if (k > numeral(sz)) k = numeral(sz);
unsigned n = static_cast<unsigned>(k.get_int64());
unsigned pos = 0;
for (unsigned i = n; i < sz; pos++, i++)
out_bits.push_back(a_bits[i]);
for (; pos < sz; pos++)
out_bits.push_back(a_bits[sz-1]);
}
else {
out_bits.append(sz, a_bits);
unsigned i = 0;
for (; i < sz; ++i) {
checkpoint();
expr_ref_vector new_out_bits(m());
unsigned shift_i = 1 << i;
if (shift_i >= sz) break;
for (unsigned j = 0; j < sz; ++j) {
expr_ref new_out(m());
expr* a_j = a_bits[sz-1];
if (shift_i + j < sz) a_j = out_bits[j+shift_i].get();
mk_ite(b_bits[i], a_j, out_bits[j].get(), new_out);
new_out_bits.push_back(new_out);
}
out_bits.reset();
out_bits.append(new_out_bits);
}
expr_ref is_large(m());
is_large = m().mk_false();
for (; i < sz; ++i) {
mk_or(is_large, b_bits[i], is_large);
}
for (unsigned j = 0; j < sz; ++j) {
expr_ref new_out(m());
mk_ite(is_large, a_bits[sz-1], out_bits[j].get(), new_out);
out_bits[j] = new_out;
}
}
}
template<typename Cfg>
template<bool Left>
void bit_blaster_tpl<Cfg>::mk_ext_rotate_left_right(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
numeral k;
if (is_numeral(sz, b_bits, k) && k.is_unsigned()) {
if (Left)
mk_rotate_left(sz, a_bits, static_cast<unsigned>(k.get_uint64()), out_bits);
else
mk_rotate_right(sz, a_bits, static_cast<unsigned>(k.get_uint64()), out_bits);
}
else {
for (unsigned j = 0; j < sz; ++j)
out_bits.push_back(a_bits[j]);
expr_ref_vector out(m());
expr_ref tmp(m());
for (unsigned i = 0, p = 1; i < sz; ++i) {
auto bit_i = b_bits[i];
if (!m().is_false(bit_i)) {
out.reset();
for (unsigned j = 0; j < sz; ++j) {
unsigned src = (Left ? (sz + j - p) : (j + p)) % sz;
mk_ite(bit_i, out_bits.get(src), out_bits.get(j), tmp);
out.push_back(tmp);
}
out_bits.reset();
out_bits.append(out);
}
p *= 2;
if (is_power_of_two(sz) && sz == p)
break;
p %= sz;
}
}
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_ext_rotate_left(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
mk_ext_rotate_left_right<true>(sz, a_bits, b_bits, out_bits);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_ext_rotate_right(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
mk_ext_rotate_left_right<false>(sz, a_bits, b_bits, out_bits);
}
template<typename Cfg>
template<bool Signed>
void bit_blaster_tpl<Cfg>::mk_le(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref & out) {
SASSERT(sz > 0);
expr_ref not_a(m());
mk_not(a_bits[0], not_a);
mk_or(not_a, b_bits[0], out);
for (unsigned idx = 1; idx < (Signed ? sz - 1 : sz); idx++) {
mk_not(a_bits[idx], not_a);
mk_ge2(not_a, b_bits[idx], out, out);
}
if (Signed) {
expr_ref not_b(m());
mk_not(b_bits[sz-1], not_b);
mk_ge2(not_b, a_bits[sz-1], out, out);
}
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_sle(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref & out) {
mk_le<true>(sz, a_bits, b_bits, out);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_ule(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref & out) {
mk_le<false>(sz, a_bits, b_bits, out);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_not(unsigned sz, expr * const * a_bits, expr_ref_vector & out_bits) {
for (unsigned i = 0; i < sz; i++) {
expr_ref t(m());
mk_not(a_bits[i], t);
out_bits.push_back(t);
}
}
#define MK_BINARY(NAME, OP) \
template<typename Cfg> \
void bit_blaster_tpl<Cfg>::NAME(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) { \
for (unsigned i = 0; i < sz; i++) { \
expr_ref t(m()); \
OP(a_bits[i], b_bits[i], t); \
out_bits.push_back(t); \
} \
}
MK_BINARY(mk_and, mk_and);
MK_BINARY(mk_or, mk_or);
MK_BINARY(mk_xor, mk_xor);
MK_BINARY(mk_xnor, mk_iff);
MK_BINARY(mk_nand, mk_nand);
MK_BINARY(mk_nor, mk_nor);
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_redand(unsigned sz, expr * const * a_bits, expr_ref_vector & out_bits) {
expr_ref tmp(m());
mk_and(sz, a_bits, tmp);
out_bits.push_back(tmp);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_redor(unsigned sz, expr * const * a_bits, expr_ref_vector & out_bits) {
expr_ref tmp(m());
mk_or(sz, a_bits, tmp);
out_bits.push_back(tmp);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_comp(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
expr_ref tmp(m());
mk_eq(sz, a_bits, b_bits, tmp);
out_bits.push_back(tmp);
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::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) {
expr_ref t(m());
for (unsigned i = 0; i < sz; i++) {
mk_xor3(a_bits[i], b_bits[i], c_bits[i], t);
sum_bits.push_back(t);
mk_carry(a_bits[i], b_bits[i], c_bits[i], t);
carry_bits.push_back(t);
}
}
template<typename Cfg>
bool bit_blaster_tpl<Cfg>::mk_const_case_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
unsigned case_size = 1;
unsigned circuit_size = sz*sz*5;
for (unsigned i = 0; case_size < circuit_size && i < sz; ++i) {
if (!is_bool_const(a_bits[i]))
case_size *= 2;
if (!is_bool_const(b_bits[i]))
case_size *= 2;
}
if (case_size >= circuit_size)
return false;
if (sz >= 100)
return false;
SASSERT(out_bits.empty());
ptr_buffer<expr, 128> na_bits;
na_bits.append(sz, a_bits);
ptr_buffer<expr, 128> nb_bits;
nb_bits.append(sz, b_bits);
mk_const_case_multiplier(true, 0, sz, na_bits, nb_bits, out_bits);
return true;
}
template<typename Cfg>
void bit_blaster_tpl<Cfg>::mk_const_case_multiplier(bool is_a, unsigned i, unsigned sz, ptr_buffer<expr, 128>& a_bits, ptr_buffer<expr, 128>& b_bits, expr_ref_vector & out_bits) {
while (is_a && i < sz && is_bool_const(a_bits[i])) ++i;
if (is_a && i == sz) {
is_a = false;
i = 0;
}
while (!is_a && i < sz && is_bool_const(b_bits[i]))
++i;
if (i < sz) {
expr_ref_vector out1(m()), out2(m());
expr_ref x(m());
x = is_a?a_bits[i]:b_bits[i];
if (is_a) a_bits[i] = m().mk_true(); else b_bits[i] = m().mk_true();
mk_const_case_multiplier(is_a, i+1, sz, a_bits, b_bits, out1);
if (is_a) a_bits[i] = m().mk_false(); else b_bits[i] = m().mk_false();
mk_const_case_multiplier(is_a, i+1, sz, a_bits, b_bits, out2);
if (is_a) a_bits[i] = x; else b_bits[i] = x;
SASSERT(out_bits.empty());
expr_ref bit(m());
for (unsigned j = 0; j < sz; ++j) {
mk_ite(x, out1.get(j), out2.get(j), bit);
out_bits.push_back(bit);
}
}
else {
numeral n_a, n_b;
SASSERT(i == sz && !is_a);
VERIFY(is_numeral(sz, a_bits.data(), n_a));
VERIFY(is_numeral(sz, b_bits.data(), n_b));
n_a *= n_b;
num2bits(n_a, sz, out_bits);
}
SASSERT(out_bits.size() == sz);
}