mirror of
https://github.com/Z3Prover/z3
synced 2025-04-07 01:54:08 +00:00
* na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * dbg Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * bv Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * drat and fresh Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * move ackerman functionality Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * debugability Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * towards debugability Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * missing file Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * remove csp Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
909 lines
34 KiB
C++
909 lines
34 KiB
C++
/*++
|
|
Copyright (c) 2006 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
bv_decl_plugin.cpp
|
|
|
|
Abstract:
|
|
|
|
<abstract>
|
|
|
|
Author:
|
|
|
|
Leonardo de Moura (leonardo) 2008-01-09.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include<sstream>
|
|
#include "ast/bv_decl_plugin.h"
|
|
#include "ast/arith_decl_plugin.h"
|
|
#include "util/warning.h"
|
|
#include "ast/ast_pp.h"
|
|
#include "ast/ast_smt2_pp.h"
|
|
|
|
bv_decl_plugin::bv_decl_plugin():
|
|
m_bv_sym("bv"),
|
|
m_concat_sym("concat"),
|
|
m_sign_extend_sym("sign_extend"),
|
|
m_zero_extend_sym("zero_extend"),
|
|
m_extract_sym("extract"),
|
|
m_rotate_left_sym("rotate_left"),
|
|
m_rotate_right_sym("rotate_right"),
|
|
m_repeat_sym("repeat"),
|
|
m_bit2bool_sym("bit2bool"),
|
|
m_mkbv_sym("mkbv"),
|
|
m_bit0(nullptr),
|
|
m_bit1(nullptr),
|
|
m_carry(nullptr),
|
|
m_xor3(nullptr),
|
|
m_int_sort(nullptr) {
|
|
}
|
|
|
|
void bv_decl_plugin::set_manager(ast_manager * m, family_id id) {
|
|
decl_plugin::set_manager(m, id);
|
|
|
|
for (unsigned i = 1; i <= 64; i++) {
|
|
mk_bv_sort(i);
|
|
}
|
|
m_bit0 = m->mk_const_decl(symbol("bit0"), get_bv_sort(1), func_decl_info(m_family_id, OP_BIT0));
|
|
m_bit1 = m->mk_const_decl(symbol("bit1"), get_bv_sort(1), func_decl_info(m_family_id, OP_BIT1));
|
|
m->inc_ref(m_bit0);
|
|
m->inc_ref(m_bit1);
|
|
|
|
sort * b = m->mk_bool_sort();
|
|
sort * d[3] = {b, b, b};
|
|
m_carry = m_manager->mk_func_decl(symbol("carry"), 3, d, b, func_decl_info(m_family_id, OP_CARRY));
|
|
m_manager->inc_ref(m_carry);
|
|
m_xor3 = m_manager->mk_func_decl(symbol("xor3"), 3, d, b, func_decl_info(m_family_id, OP_XOR3));
|
|
m_manager->inc_ref(m_xor3);
|
|
|
|
m_int_sort = m_manager->mk_sort(m_manager->mk_family_id("arith"), INT_SORT);
|
|
SASSERT(m_int_sort != 0); // arith_decl_plugin must be installed before bv_decl_plugin.
|
|
m_manager->inc_ref(m_int_sort);
|
|
}
|
|
|
|
void bv_decl_plugin::finalize() {
|
|
#define DEC_REF(FIELD) dec_range_ref(FIELD.begin(), FIELD.end(), *m_manager)
|
|
if (m_bit0) { m_manager->dec_ref(m_bit0); }
|
|
if (m_bit1) { m_manager->dec_ref(m_bit1); }
|
|
if (m_carry) { m_manager->dec_ref(m_carry); }
|
|
if (m_xor3) { m_manager->dec_ref(m_xor3); }
|
|
if (m_int_sort) { m_manager->dec_ref(m_int_sort); }
|
|
|
|
DEC_REF(m_bv_sorts);
|
|
|
|
DEC_REF(m_bv_neg);
|
|
DEC_REF(m_bv_add);
|
|
DEC_REF(m_bv_sub);
|
|
DEC_REF(m_bv_mul);
|
|
|
|
DEC_REF(m_bv_sdiv);
|
|
DEC_REF(m_bv_udiv);
|
|
DEC_REF(m_bv_srem);
|
|
DEC_REF(m_bv_urem);
|
|
DEC_REF(m_bv_smod);
|
|
|
|
DEC_REF(m_bv_sdiv0);
|
|
DEC_REF(m_bv_udiv0);
|
|
DEC_REF(m_bv_srem0);
|
|
DEC_REF(m_bv_urem0);
|
|
DEC_REF(m_bv_smod0);
|
|
|
|
DEC_REF(m_bv_sdiv_i);
|
|
DEC_REF(m_bv_udiv_i);
|
|
DEC_REF(m_bv_srem_i);
|
|
DEC_REF(m_bv_urem_i);
|
|
DEC_REF(m_bv_smod_i);
|
|
|
|
DEC_REF(m_bv_uleq);
|
|
DEC_REF(m_bv_sleq);
|
|
DEC_REF(m_bv_ugeq);
|
|
DEC_REF(m_bv_sgeq);
|
|
DEC_REF(m_bv_ult);
|
|
DEC_REF(m_bv_slt);
|
|
DEC_REF(m_bv_ugt);
|
|
DEC_REF(m_bv_sgt);
|
|
|
|
DEC_REF(m_bv_and);
|
|
DEC_REF(m_bv_or);
|
|
DEC_REF(m_bv_not);
|
|
DEC_REF(m_bv_xor);
|
|
DEC_REF(m_bv_nand);
|
|
DEC_REF(m_bv_nor);
|
|
DEC_REF(m_bv_xnor);
|
|
|
|
DEC_REF(m_bv_redor);
|
|
DEC_REF(m_bv_redand);
|
|
DEC_REF(m_bv_comp);
|
|
|
|
DEC_REF(m_bv_mul_ovfl);
|
|
DEC_REF(m_bv_smul_ovfl);
|
|
DEC_REF(m_bv_smul_udfl);
|
|
|
|
DEC_REF(m_bv_shl);
|
|
DEC_REF(m_bv_lshr);
|
|
DEC_REF(m_bv_ashr);
|
|
|
|
DEC_REF(m_ext_rotate_left);
|
|
DEC_REF(m_ext_rotate_right);
|
|
|
|
DEC_REF(m_int2bv);
|
|
DEC_REF(m_bv2int);
|
|
for (auto& ds : m_bit2bool)
|
|
DEC_REF(ds);
|
|
DEC_REF(m_mkbv);
|
|
}
|
|
|
|
void bv_decl_plugin::mk_bv_sort(unsigned bv_size) {
|
|
force_ptr_array_size(m_bv_sorts, bv_size + 1);
|
|
if (m_bv_sorts[bv_size] == 0) {
|
|
parameter p(bv_size);
|
|
sort_size sz;
|
|
if (sort_size::is_very_big_base2(bv_size)) {
|
|
sz = sort_size::mk_very_big();
|
|
}
|
|
else {
|
|
sz = sort_size(rational::power_of_two(bv_size));
|
|
}
|
|
m_bv_sorts[bv_size] = m_manager->mk_sort(m_bv_sym, sort_info(m_family_id, BV_SORT, sz, 1, &p));
|
|
m_manager->inc_ref(m_bv_sorts[bv_size]);
|
|
}
|
|
}
|
|
|
|
inline sort * bv_decl_plugin::get_bv_sort(unsigned bv_size) {
|
|
if (bv_size < (1 << 12)) {
|
|
mk_bv_sort(bv_size);
|
|
return m_bv_sorts[bv_size];
|
|
}
|
|
parameter p(bv_size);
|
|
sort_size sz(sort_size::mk_very_big());
|
|
return m_manager->mk_sort(m_bv_sym, sort_info(m_family_id, BV_SORT, sz, 1, &p));
|
|
}
|
|
|
|
sort * bv_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
|
|
if (!(num_parameters == 1 && parameters[0].is_int())) {
|
|
m_manager->raise_exception("expecting one integer parameter to bit-vector sort");
|
|
}
|
|
unsigned bv_size = parameters[0].get_int();
|
|
if (bv_size == 0) {
|
|
m_manager->raise_exception("bit-vector size must be greater than zero");
|
|
}
|
|
mk_bv_sort(bv_size);
|
|
return m_bv_sorts[bv_size];
|
|
}
|
|
|
|
func_decl * bv_decl_plugin::mk_binary(ptr_vector<func_decl> & decls, decl_kind k,
|
|
char const * name, unsigned bv_size, bool ac, bool idempotent) {
|
|
force_ptr_array_size(decls, bv_size + 1);
|
|
|
|
if (decls[bv_size] == 0) {
|
|
sort * s = get_bv_sort(bv_size);
|
|
func_decl_info info(m_family_id, k);
|
|
info.set_associative(ac);
|
|
info.set_flat_associative(ac);
|
|
info.set_commutative(ac);
|
|
info.set_idempotent(idempotent);
|
|
decls[bv_size] = m_manager->mk_func_decl(symbol(name), s, s, s, info);
|
|
m_manager->inc_ref(decls[bv_size]);
|
|
}
|
|
|
|
return decls[bv_size];
|
|
}
|
|
|
|
func_decl * bv_decl_plugin::mk_unary(ptr_vector<func_decl> & decls, decl_kind k, char const * name, unsigned bv_size) {
|
|
force_ptr_array_size(decls, bv_size + 1);
|
|
|
|
if (decls[bv_size] == 0) {
|
|
sort * s = get_bv_sort(bv_size);
|
|
decls[bv_size] = m_manager->mk_func_decl(symbol(name), s, s, func_decl_info(m_family_id, k));
|
|
m_manager->inc_ref(decls[bv_size]);
|
|
}
|
|
|
|
return decls[bv_size];
|
|
}
|
|
|
|
func_decl * bv_decl_plugin::mk_int2bv(unsigned bv_size, unsigned num_parameters, parameter const * parameters,
|
|
unsigned arity, sort * const * domain) {
|
|
if (bv_size == 0) {
|
|
m_manager->raise_exception("bit-vector size must be greater than zero");
|
|
}
|
|
|
|
force_ptr_array_size(m_int2bv, bv_size + 1);
|
|
|
|
if (arity != 1) {
|
|
m_manager->raise_exception("expecting one argument to int2bv");
|
|
return nullptr;
|
|
}
|
|
|
|
if (m_int2bv[bv_size] == 0) {
|
|
sort * s = get_bv_sort(bv_size);
|
|
m_int2bv[bv_size] = m_manager->mk_func_decl(symbol("int2bv"), domain[0], s,
|
|
func_decl_info(m_family_id, OP_INT2BV, num_parameters, parameters));
|
|
m_manager->inc_ref(m_int2bv[bv_size]);
|
|
}
|
|
|
|
return m_int2bv[bv_size];
|
|
}
|
|
|
|
func_decl * bv_decl_plugin::mk_bv2int(unsigned bv_size, unsigned num_parameters, parameter const * parameters,
|
|
unsigned arity, sort * const * domain) {
|
|
force_ptr_array_size(m_bv2int, bv_size + 1);
|
|
|
|
if (arity != 1) {
|
|
m_manager->raise_exception("expecting one argument to bv2int");
|
|
return nullptr;
|
|
}
|
|
|
|
if (m_bv2int[bv_size] == 0) {
|
|
m_bv2int[bv_size] = m_manager->mk_func_decl(symbol("bv2int"), domain[0], m_int_sort,
|
|
func_decl_info(m_family_id, OP_BV2INT));
|
|
m_manager->inc_ref(m_bv2int[bv_size]);
|
|
}
|
|
|
|
return m_bv2int[bv_size];
|
|
}
|
|
|
|
func_decl * bv_decl_plugin::mk_pred(ptr_vector<func_decl> & decls, decl_kind k, char const * name, unsigned bv_size) {
|
|
force_ptr_array_size(decls, bv_size + 1);
|
|
|
|
if (decls[bv_size] == 0) {
|
|
sort * s = get_bv_sort(bv_size);
|
|
decls[bv_size] = m_manager->mk_func_decl(symbol(name), s, s, m_manager->mk_bool_sort(), func_decl_info(m_family_id, k));
|
|
m_manager->inc_ref(decls[bv_size]);
|
|
}
|
|
|
|
return decls[bv_size];
|
|
}
|
|
|
|
func_decl * bv_decl_plugin::mk_reduction(ptr_vector<func_decl> & decls, decl_kind k, char const * name, unsigned bv_size) {
|
|
force_ptr_array_size(decls, bv_size + 1);
|
|
|
|
if (decls[bv_size] == 0) {
|
|
sort * d = get_bv_sort(bv_size);
|
|
sort * r = get_bv_sort(1);
|
|
decls[bv_size] = m_manager->mk_func_decl(symbol(name), d, r, func_decl_info(m_family_id, k));
|
|
m_manager->inc_ref(decls[bv_size]);
|
|
}
|
|
|
|
return decls[bv_size];
|
|
}
|
|
|
|
func_decl * bv_decl_plugin::mk_comp(unsigned bv_size) {
|
|
force_ptr_array_size(m_bv_comp, bv_size + 1);
|
|
|
|
if (m_bv_comp[bv_size] == 0) {
|
|
sort * d = get_bv_sort(bv_size);
|
|
sort * r = get_bv_sort(1);
|
|
func_decl_info info(m_family_id, OP_BCOMP);
|
|
info.set_commutative();
|
|
m_bv_comp[bv_size] = m_manager->mk_func_decl(symbol("bvcomp"), d, d, r, info);
|
|
m_manager->inc_ref(m_bv_comp[bv_size]);
|
|
}
|
|
|
|
return m_bv_comp[bv_size];
|
|
}
|
|
|
|
|
|
func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned bv_size) {
|
|
switch (k) {
|
|
case OP_BNEG: return mk_unary(m_bv_neg, k, "bvneg", bv_size);
|
|
case OP_BADD: return mk_binary(m_bv_add, k, "bvadd", bv_size, true);
|
|
case OP_BSUB: return mk_binary(m_bv_sub, k, "bvsub", bv_size, false);
|
|
case OP_BMUL: return mk_binary(m_bv_mul, k, "bvmul", bv_size, true);
|
|
case OP_BSDIV: return mk_binary(m_bv_sdiv, k, "bvsdiv", bv_size, false);
|
|
case OP_BUDIV: return mk_binary(m_bv_udiv, k, "bvudiv", bv_size, false);
|
|
case OP_BSREM: return mk_binary(m_bv_srem, k, "bvsrem", bv_size, false);
|
|
case OP_BUREM: return mk_binary(m_bv_urem, k, "bvurem", bv_size, false);
|
|
case OP_BSMOD: return mk_binary(m_bv_smod, k, "bvsmod", bv_size, false);
|
|
case OP_BSDIV0: return mk_unary(m_bv_sdiv0, k, "bvsdiv0", bv_size);
|
|
case OP_BUDIV0: return mk_unary(m_bv_udiv0, k, "bvudiv0", bv_size);
|
|
case OP_BSREM0: return mk_unary(m_bv_srem0, k, "bvsrem0", bv_size);
|
|
case OP_BUREM0: return mk_unary(m_bv_urem0, k, "bvurem0", bv_size);
|
|
case OP_BSMOD0: return mk_unary(m_bv_smod0, k, "bvsmod0", bv_size);
|
|
case OP_BSDIV_I: return mk_binary(m_bv_sdiv_i, k, "bvsdiv_i", bv_size, false);
|
|
case OP_BUDIV_I: return mk_binary(m_bv_udiv_i, k, "bvudiv_i", bv_size, false);
|
|
case OP_BSREM_I: return mk_binary(m_bv_srem_i, k, "bvsrem_i", bv_size, false);
|
|
case OP_BUREM_I: return mk_binary(m_bv_urem_i, k, "bvurem_i", bv_size, false);
|
|
case OP_BSMOD_I: return mk_binary(m_bv_smod_i, k, "bvsmod_i", bv_size, false);
|
|
case OP_ULEQ: return mk_pred(m_bv_uleq, k, "bvule", bv_size);
|
|
case OP_SLEQ: return mk_pred(m_bv_sleq, k, "bvsle", bv_size);
|
|
case OP_UGEQ: return mk_pred(m_bv_ugeq, k, "bvuge", bv_size);
|
|
case OP_SGEQ: return mk_pred(m_bv_sgeq, k, "bvsge", bv_size);
|
|
case OP_ULT: return mk_pred(m_bv_ult, k, "bvult", bv_size);
|
|
case OP_SLT: return mk_pred(m_bv_slt, k, "bvslt", bv_size);
|
|
case OP_UGT: return mk_pred(m_bv_ugt, k, "bvugt", bv_size);
|
|
case OP_SGT: return mk_pred(m_bv_sgt, k, "bvsgt", bv_size);
|
|
|
|
case OP_BAND: return mk_binary(m_bv_and, k, "bvand", bv_size, true, true);
|
|
case OP_BOR: return mk_binary(m_bv_or, k, "bvor", bv_size, true, true);
|
|
case OP_BNOT: return mk_unary(m_bv_not, k, "bvnot", bv_size);
|
|
case OP_BXOR: return mk_binary(m_bv_xor, k, "bvxor", bv_size, true);
|
|
case OP_BNAND: return mk_binary(m_bv_nand, k, "bvnand", bv_size, false);
|
|
case OP_BNOR: return mk_binary(m_bv_nor, k, "bvnor", bv_size, false);
|
|
case OP_BXNOR: return mk_binary(m_bv_xnor, k, "bvxnor", bv_size, true);
|
|
|
|
case OP_BREDOR: return mk_reduction(m_bv_redor, k, "bvredor", bv_size);
|
|
case OP_BREDAND: return mk_reduction(m_bv_redand, k, "bvredand", bv_size);
|
|
case OP_BCOMP: return mk_comp(bv_size);
|
|
case OP_BUMUL_NO_OVFL: return mk_pred(m_bv_mul_ovfl, k, "bvumul_noovfl", bv_size);
|
|
case OP_BSMUL_NO_OVFL: return mk_pred(m_bv_smul_ovfl, k, "bvsmul_noovfl", bv_size);
|
|
case OP_BSMUL_NO_UDFL: return mk_pred(m_bv_smul_udfl, k, "bvsmul_noudfl", bv_size);
|
|
|
|
case OP_BSHL: return mk_binary(m_bv_shl, k, "bvshl", bv_size, false);
|
|
case OP_BLSHR: return mk_binary(m_bv_lshr, k, "bvlshr", bv_size, false);
|
|
case OP_BASHR: return mk_binary(m_bv_ashr, k, "bvashr", bv_size, false);
|
|
|
|
case OP_EXT_ROTATE_LEFT: return mk_binary(m_ext_rotate_left, k, "ext_rotate_left", bv_size, false);
|
|
case OP_EXT_ROTATE_RIGHT: return mk_binary(m_ext_rotate_right, k, "ext_rotate_right", bv_size, false);
|
|
default: return nullptr;
|
|
}
|
|
}
|
|
|
|
inline bool bv_decl_plugin::get_bv_size(sort * s, int & result) {
|
|
if (s->get_family_id() == m_family_id && s->get_decl_kind() == BV_SORT) {
|
|
result = s->get_parameter(0).get_int();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
inline bool bv_decl_plugin::get_bv_size(expr * t, int & result) {
|
|
return get_bv_size(m_manager->get_sort(t), result);
|
|
}
|
|
|
|
bool bv_decl_plugin::get_concat_size(unsigned arity, sort * const * domain, int & result) {
|
|
result = 0;
|
|
for (unsigned i = 0; i < arity; i++) {
|
|
int sz;
|
|
if (!get_bv_size(domain[i], sz)) {
|
|
return false;
|
|
}
|
|
result += sz;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool bv_decl_plugin::get_extend_size(unsigned num_parameters, parameter const * parameters,
|
|
unsigned arity, sort * const * domain, int & result) {
|
|
int arg_sz;
|
|
if (arity != 1 || !get_bv_size(domain[0], arg_sz) ||
|
|
num_parameters != 1 || !parameters[0].is_int() || parameters[0].get_int() < 0) {
|
|
return false;
|
|
}
|
|
result = arg_sz + parameters[0].get_int();
|
|
return true;
|
|
}
|
|
|
|
bool bv_decl_plugin::get_extract_size(unsigned num_parameters, parameter const * parameters,
|
|
unsigned arity, sort * const * domain, int & result) {
|
|
int arg_sz;
|
|
if (arity != 1 ||
|
|
!get_bv_size(domain[0], arg_sz) ||
|
|
num_parameters != 2 ||
|
|
!parameters[0].is_int() ||
|
|
!parameters[1].is_int() ||
|
|
parameters[1].get_int() > parameters[0].get_int() ||
|
|
parameters[0].get_int() >= arg_sz) {
|
|
return false;
|
|
}
|
|
result = parameters[0].get_int() - parameters[1].get_int() + 1;
|
|
return true;
|
|
}
|
|
|
|
bool bv_decl_plugin::get_int2bv_size(unsigned num_parameters, parameter const * parameters, int & result) {
|
|
if (num_parameters != 1) {
|
|
m_manager->raise_exception("int2bv expects one parameter");
|
|
return false;
|
|
}
|
|
const parameter &p = parameters[0];
|
|
if (p.is_int()) {
|
|
result = p.get_int();
|
|
return true;
|
|
}
|
|
if (!p.is_ast() || !is_expr(p.get_ast())) {
|
|
m_manager->raise_exception("int2bv expects one integer parameter");
|
|
return false;
|
|
}
|
|
return get_bv_size(to_expr(p.get_ast()), result);
|
|
}
|
|
|
|
|
|
func_decl * bv_decl_plugin::mk_num_decl(unsigned num_parameters, parameter const * parameters, unsigned arity) {
|
|
if (!(num_parameters == 2 && arity == 0 && parameters[0].is_rational() && parameters[1].is_int())) {
|
|
m_manager->raise_exception("invalid bit-vector numeral declaration");
|
|
return nullptr;
|
|
}
|
|
unsigned bv_size = parameters[1].get_int();
|
|
if (bv_size == 0) {
|
|
m_manager->raise_exception("bit-vector size must be greater than zero");
|
|
}
|
|
// TODO: sign an error if the parameters[0] is out of range, that is, it is a value not in [0, 2^{bv_size})
|
|
// This cannot be enforced now, since some Z3 modules try to generate these invalid numerals.
|
|
// After SMT-COMP, I should find all offending modules.
|
|
// For now, I will just simplify the numeral here.
|
|
parameter p0(mod(parameters[0].get_rational(), rational::power_of_two(bv_size)));
|
|
parameter ps[2] = { std::move(p0), parameters[1] };
|
|
sort * bv = get_bv_sort(bv_size);
|
|
return m_manager->mk_const_decl(m_bv_sym, bv, func_decl_info(m_family_id, OP_BV_NUM, num_parameters, ps));
|
|
}
|
|
|
|
func_decl * bv_decl_plugin::mk_bit2bool(unsigned bv_size, unsigned num_parameters, parameter const * parameters,
|
|
unsigned arity, sort * const * domain) {
|
|
if (!(num_parameters == 1 && parameters[0].is_int() && arity == 1 && parameters[0].get_int() < static_cast<int>(bv_size))) {
|
|
m_manager->raise_exception("invalid bit2bool declaration");
|
|
return nullptr;
|
|
}
|
|
unsigned idx = parameters[0].get_int();
|
|
m_bit2bool.reserve(bv_size+1);
|
|
ptr_vector<func_decl> & v = m_bit2bool[bv_size];
|
|
v.reserve(bv_size, 0);
|
|
if (v[idx] == 0) {
|
|
v[idx] = m_manager->mk_func_decl(m_bit2bool_sym, domain[0], m_manager->mk_bool_sort(),
|
|
func_decl_info(m_family_id, OP_BIT2BOOL, num_parameters, parameters));
|
|
m_manager->inc_ref(v[idx]);
|
|
}
|
|
return v[idx];
|
|
}
|
|
|
|
func_decl * bv_decl_plugin::mk_mkbv(unsigned arity, sort * const * domain) {
|
|
for (unsigned i = 0; i < arity; i++) {
|
|
if (!m_manager->is_bool(domain[i])) {
|
|
m_manager->raise_exception("invalid mkbv operator");
|
|
return nullptr;
|
|
}
|
|
}
|
|
unsigned bv_size = arity;
|
|
m_mkbv.reserve(bv_size+1);
|
|
if (m_mkbv[bv_size] == 0) {
|
|
m_mkbv[bv_size] = m_manager->mk_func_decl(m_mkbv_sym, arity, domain, get_bv_sort(bv_size), func_decl_info(m_family_id, OP_MKBV));
|
|
m_manager->inc_ref(m_mkbv[bv_size]);
|
|
}
|
|
return m_mkbv[bv_size];
|
|
}
|
|
|
|
func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
|
unsigned arity, sort * const * domain, sort * range) {
|
|
int bv_size;
|
|
if (k == OP_INT2BV && get_int2bv_size(num_parameters, parameters, bv_size)) {
|
|
// bv_size is filled in.
|
|
}
|
|
else if (k == OP_BV_NUM) {
|
|
return mk_num_decl(num_parameters, parameters, arity);
|
|
}
|
|
else if (k == OP_BIT0) {
|
|
return m_bit0;
|
|
}
|
|
else if (k == OP_BIT1) {
|
|
return m_bit1;
|
|
}
|
|
else if (k == OP_CARRY) {
|
|
return m_carry;
|
|
}
|
|
else if (k == OP_XOR3) {
|
|
return m_xor3;
|
|
}
|
|
else if (k == OP_MKBV) {
|
|
return mk_mkbv(arity, domain);
|
|
}
|
|
else if (arity == 0) {
|
|
m_manager->raise_exception("no arguments supplied to bit-vector operator");
|
|
return nullptr;
|
|
}
|
|
else if (!get_bv_size(domain[0], bv_size)) {
|
|
m_manager->raise_exception("could not extract bit-vector size");
|
|
return nullptr;
|
|
}
|
|
func_decl * r = mk_func_decl(k, bv_size);
|
|
if (r != nullptr) {
|
|
if (arity != r->get_arity()) {
|
|
if (r->get_info()->is_associative())
|
|
arity = r->get_arity();
|
|
else {
|
|
m_manager->raise_exception("declared arity mismatches supplied arity");
|
|
return nullptr;
|
|
}
|
|
}
|
|
for (unsigned i = 0; i < arity; ++i) {
|
|
if (domain[i] != r->get_domain(i)) {
|
|
m_manager->raise_exception("declared sorts do not match supplied sorts");
|
|
return nullptr;
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
int r_size;
|
|
switch (k) {
|
|
case OP_BIT2BOOL:
|
|
return mk_bit2bool(bv_size, num_parameters, parameters, arity, domain);
|
|
case OP_INT2BV:
|
|
return mk_int2bv(bv_size, num_parameters, parameters, arity, domain);
|
|
case OP_BV2INT:
|
|
return mk_bv2int(bv_size, num_parameters, parameters, arity, domain);
|
|
case OP_CONCAT:
|
|
if (!get_concat_size(arity, domain, r_size))
|
|
m_manager->raise_exception("invalid concat application");
|
|
return m_manager->mk_func_decl(m_concat_sym, arity, domain, get_bv_sort(r_size),
|
|
func_decl_info(m_family_id, k));
|
|
case OP_SIGN_EXT:
|
|
if (!get_extend_size(num_parameters, parameters, arity, domain, r_size))
|
|
m_manager->raise_exception("invalid sign_extend application");
|
|
return m_manager->mk_func_decl(m_sign_extend_sym, arity, domain, get_bv_sort(r_size),
|
|
func_decl_info(m_family_id, k, num_parameters, parameters));
|
|
case OP_ZERO_EXT:
|
|
if (!get_extend_size(num_parameters, parameters, arity, domain, r_size))
|
|
m_manager->raise_exception("invalid zero_extend application");
|
|
return m_manager->mk_func_decl(m_zero_extend_sym, arity, domain, get_bv_sort(r_size),
|
|
func_decl_info(m_family_id, k, num_parameters, parameters));
|
|
case OP_EXTRACT:
|
|
if (!get_extract_size(num_parameters, parameters, arity, domain, r_size))
|
|
m_manager->raise_exception("invalid extract application");
|
|
return m_manager->mk_func_decl(m_extract_sym, arity, domain, get_bv_sort(r_size),
|
|
func_decl_info(m_family_id, k, num_parameters, parameters));
|
|
case OP_ROTATE_LEFT:
|
|
if (arity != 1)
|
|
m_manager->raise_exception("rotate left expects one argument");
|
|
if (num_parameters != 1 || !parameters[0].is_int())
|
|
m_manager->raise_exception("rotate left expects one integer parameter");
|
|
return m_manager->mk_func_decl(m_rotate_left_sym, arity, domain, domain[0],
|
|
func_decl_info(m_family_id, k, num_parameters, parameters));
|
|
case OP_ROTATE_RIGHT:
|
|
if (arity != 1)
|
|
m_manager->raise_exception("rotate right expects one argument");
|
|
if (num_parameters != 1 || !parameters[0].is_int())
|
|
m_manager->raise_exception("rotate right expects one integer parameter");
|
|
return m_manager->mk_func_decl(m_rotate_right_sym, arity, domain, domain[0],
|
|
func_decl_info(m_family_id, k, num_parameters, parameters));
|
|
case OP_REPEAT:
|
|
if (arity != 1)
|
|
m_manager->raise_exception("repeat expects one argument");
|
|
if (num_parameters != 1 || !parameters[0].is_int() || parameters[0].get_int() == 0)
|
|
m_manager->raise_exception("repeat expects one nonzero integer parameter");
|
|
if (!get_bv_size(domain[0], bv_size))
|
|
m_manager->raise_exception("repeat expects an argument with bit-vector sort");
|
|
return m_manager->mk_func_decl(m_repeat_sym, arity, domain, get_bv_sort(bv_size * parameters[0].get_int()),
|
|
func_decl_info(m_family_id, k, num_parameters, parameters));
|
|
default:
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
|
unsigned num_args, expr * const * args, sort * range) {
|
|
ast_manager& m = *m_manager;
|
|
int bv_size;
|
|
if (k == OP_INT2BV && get_int2bv_size(num_parameters, parameters, bv_size)) {
|
|
// bv_size is filled in.
|
|
}
|
|
else if (k == OP_BV_NUM) {
|
|
return mk_num_decl(num_parameters, parameters, num_args);
|
|
}
|
|
else if (k == OP_BIT0) {
|
|
return m_bit0;
|
|
}
|
|
else if (k == OP_BIT1) {
|
|
return m_bit1;
|
|
}
|
|
else if (k == OP_CARRY) {
|
|
return m_carry;
|
|
}
|
|
else if (k == OP_XOR3) {
|
|
return m_xor3;
|
|
}
|
|
else if (k == OP_MKBV) {
|
|
return decl_plugin::mk_func_decl(k, num_parameters, parameters, num_args, args, range);
|
|
}
|
|
else if (num_args == 0 || !get_bv_size(args[0], bv_size)) {
|
|
m.raise_exception("operator is applied to arguments of the wrong sort");
|
|
return nullptr;
|
|
}
|
|
func_decl * r = mk_func_decl(k, bv_size);
|
|
if (r != nullptr) {
|
|
if (num_args != r->get_arity()) {
|
|
if (r->get_info()->is_associative()) {
|
|
sort * fs = r->get_domain(0);
|
|
for (unsigned i = 0; i < num_args; ++i) {
|
|
if (m.get_sort(args[i]) != fs) {
|
|
m_manager->raise_exception("declared sorts do not match supplied sorts");
|
|
return nullptr;
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
else {
|
|
m.raise_exception("declared arity mismatches supplied arity");
|
|
return nullptr;
|
|
}
|
|
}
|
|
for (unsigned i = 0; i < num_args; ++i) {
|
|
if (m.get_sort(args[i]) != r->get_domain(i)) {
|
|
std::ostringstream buffer;
|
|
buffer << "Argument " << mk_pp(args[i], m) << " at position " << i << " does not match declaration " << mk_pp(r, m);
|
|
m.raise_exception(buffer.str());
|
|
return nullptr;
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
return decl_plugin::mk_func_decl(k, num_parameters, parameters, num_args, args, range);
|
|
}
|
|
|
|
bool bv_decl_plugin::is_value(app* e) const {
|
|
return is_app_of(e, m_family_id, OP_BV_NUM);
|
|
}
|
|
|
|
void bv_decl_plugin::get_offset_term(app * a, expr * & t, rational & offset) const {
|
|
family_id fid = get_family_id();
|
|
if (a->get_num_args() == 2 && is_app_of(a, fid, OP_BADD) && is_app_of(a->get_arg(0), fid, OP_BV_NUM)) {
|
|
unsigned sz;
|
|
func_decl * decl = to_app(a->get_arg(0))->get_decl();
|
|
offset = decl->get_parameter(0).get_rational();
|
|
sz = decl->get_parameter(1).get_int();
|
|
t = a->get_arg(1);
|
|
offset = mod(offset, rational::power_of_two(sz));
|
|
}
|
|
else {
|
|
t = a;
|
|
offset = rational(0);
|
|
}
|
|
}
|
|
|
|
bool bv_decl_plugin::are_distinct(app * a, app * b) const {
|
|
#if 1
|
|
// Check for a + k1 != a + k2 when k1 != k2
|
|
rational a_offset;
|
|
expr * a_term;
|
|
rational b_offset;
|
|
expr * b_term;
|
|
get_offset_term(a, a_term, a_offset);
|
|
get_offset_term(b, b_term, b_offset);
|
|
TRACE("bv_are_distinct",
|
|
tout << mk_ismt2_pp(a, *m_manager) << "\n" << mk_ismt2_pp(b, *m_manager) << "\n";
|
|
tout << "---->\n";
|
|
tout << "a: " << a_offset << " + " << mk_ismt2_pp(a_term, *m_manager) << "\n";
|
|
tout << "b: " << b_offset << " + " << mk_ismt2_pp(b_term, *m_manager) << "\n";);
|
|
if (a_term == b_term && a_offset != b_offset)
|
|
return true;
|
|
#endif
|
|
return decl_plugin::are_distinct(a, b);
|
|
}
|
|
|
|
void bv_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) {
|
|
if (logic == symbol::null || logic == symbol("ALL"))
|
|
sort_names.push_back(builtin_name("bv", BV_SORT));
|
|
sort_names.push_back(builtin_name("BitVec", BV_SORT));
|
|
}
|
|
|
|
void bv_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
|
|
op_names.push_back(builtin_name("bit1",OP_BIT1));
|
|
op_names.push_back(builtin_name("bit0",OP_BIT0));
|
|
op_names.push_back(builtin_name("bvneg",OP_BNEG));
|
|
op_names.push_back(builtin_name("bvadd",OP_BADD));
|
|
op_names.push_back(builtin_name("bvsub",OP_BSUB));
|
|
op_names.push_back(builtin_name("bvmul",OP_BMUL));
|
|
op_names.push_back(builtin_name("bvsdiv",OP_BSDIV));
|
|
op_names.push_back(builtin_name("bvudiv",OP_BUDIV));
|
|
op_names.push_back(builtin_name("bvsrem",OP_BSREM));
|
|
op_names.push_back(builtin_name("bvurem",OP_BUREM));
|
|
op_names.push_back(builtin_name("bvsmod",OP_BSMOD));
|
|
|
|
op_names.push_back(builtin_name("bvule",OP_ULEQ));
|
|
op_names.push_back(builtin_name("bvsle",OP_SLEQ));
|
|
op_names.push_back(builtin_name("bvuge",OP_UGEQ));
|
|
op_names.push_back(builtin_name("bvsge",OP_SGEQ));
|
|
op_names.push_back(builtin_name("bvult",OP_ULT));
|
|
op_names.push_back(builtin_name("bvslt",OP_SLT));
|
|
op_names.push_back(builtin_name("bvugt",OP_UGT));
|
|
op_names.push_back(builtin_name("bvsgt",OP_SGT));
|
|
op_names.push_back(builtin_name("bvand",OP_BAND));
|
|
op_names.push_back(builtin_name("bvor",OP_BOR));
|
|
op_names.push_back(builtin_name("bvnot",OP_BNOT));
|
|
op_names.push_back(builtin_name("bvxor",OP_BXOR));
|
|
op_names.push_back(builtin_name("bvnand",OP_BNAND));
|
|
op_names.push_back(builtin_name("bvnor",OP_BNOR));
|
|
op_names.push_back(builtin_name("bvxnor",OP_BXNOR));
|
|
op_names.push_back(builtin_name("concat",OP_CONCAT));
|
|
op_names.push_back(builtin_name("sign_extend",OP_SIGN_EXT));
|
|
op_names.push_back(builtin_name("zero_extend",OP_ZERO_EXT));
|
|
op_names.push_back(builtin_name("extract",OP_EXTRACT));
|
|
op_names.push_back(builtin_name("repeat",OP_REPEAT));
|
|
op_names.push_back(builtin_name("bvredor",OP_BREDOR));
|
|
op_names.push_back(builtin_name("bvredand",OP_BREDAND));
|
|
op_names.push_back(builtin_name("bvcomp",OP_BCOMP));
|
|
op_names.push_back(builtin_name("bvshl",OP_BSHL));
|
|
op_names.push_back(builtin_name("bvlshr",OP_BLSHR));
|
|
op_names.push_back(builtin_name("bvashr",OP_BASHR));
|
|
op_names.push_back(builtin_name("rotate_left",OP_ROTATE_LEFT));
|
|
op_names.push_back(builtin_name("rotate_right",OP_ROTATE_RIGHT));
|
|
op_names.push_back(builtin_name("bit2bool", OP_BIT2BOOL));
|
|
|
|
if (logic == symbol::null || logic == symbol("ALL") || logic == "QF_FD") {
|
|
op_names.push_back(builtin_name("bvumul_noovfl",OP_BUMUL_NO_OVFL));
|
|
op_names.push_back(builtin_name("bvsmul_noovfl",OP_BSMUL_NO_OVFL));
|
|
op_names.push_back(builtin_name("bvsmul_noudfl",OP_BSMUL_NO_UDFL));
|
|
|
|
op_names.push_back(builtin_name("bvsdiv0", OP_BSDIV0));
|
|
op_names.push_back(builtin_name("bvudiv0", OP_BUDIV0));
|
|
op_names.push_back(builtin_name("bvsrem0", OP_BSREM0));
|
|
op_names.push_back(builtin_name("bvurem0", OP_BUREM0));
|
|
op_names.push_back(builtin_name("bvsmod0", OP_BSMOD0));
|
|
|
|
op_names.push_back(builtin_name("bvsdiv_i", OP_BSDIV_I));
|
|
op_names.push_back(builtin_name("bvudiv_i", OP_BUDIV_I));
|
|
op_names.push_back(builtin_name("bvsrem_i", OP_BSREM_I));
|
|
op_names.push_back(builtin_name("bvurem_i", OP_BUREM_I));
|
|
op_names.push_back(builtin_name("bvsmod_i", OP_BSMOD_I));
|
|
|
|
op_names.push_back(builtin_name("ext_rotate_left",OP_EXT_ROTATE_LEFT));
|
|
op_names.push_back(builtin_name("ext_rotate_right",OP_EXT_ROTATE_RIGHT));
|
|
op_names.push_back(builtin_name("int2bv",OP_INT2BV));
|
|
op_names.push_back(builtin_name("bv2int",OP_BV2INT));
|
|
op_names.push_back(builtin_name("bv2nat",OP_BV2INT));
|
|
op_names.push_back(builtin_name("mkbv",OP_MKBV));
|
|
}
|
|
}
|
|
|
|
expr * bv_decl_plugin::get_some_value(sort * s) {
|
|
SASSERT(s->is_sort_of(m_family_id, BV_SORT));
|
|
unsigned bv_size = s->get_parameter(0).get_int();
|
|
parameter p[2] = { parameter(rational::zero()), parameter(static_cast<int>(bv_size)) };
|
|
return m_manager->mk_app(m_family_id, OP_BV_NUM, 2, p, 0, nullptr);
|
|
}
|
|
|
|
rational bv_recognizers::norm(rational const & val, unsigned bv_size, bool is_signed) const {
|
|
rational r = mod(val, rational::power_of_two(bv_size));
|
|
SASSERT(!r.is_neg());
|
|
if (is_signed) {
|
|
if (r >= rational::power_of_two(bv_size - 1)) {
|
|
r -= rational::power_of_two(bv_size);
|
|
}
|
|
if (r < -rational::power_of_two(bv_size - 1)) {
|
|
r += rational::power_of_two(bv_size);
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
bool bv_recognizers::has_sign_bit(rational const & n, unsigned bv_size) const {
|
|
SASSERT(bv_size > 0);
|
|
rational m = norm(n, bv_size, false);
|
|
rational p = rational::power_of_two(bv_size - 1);
|
|
return m >= p;
|
|
}
|
|
|
|
bool bv_recognizers::is_bv_sort(sort const * s) const {
|
|
return (s->get_family_id() == get_fid() && s->get_decl_kind() == BV_SORT && s->get_num_parameters() == 1);
|
|
}
|
|
|
|
bool bv_recognizers::is_numeral(expr const * n, rational & val, unsigned & bv_size) const {
|
|
if (!is_app_of(n, get_fid(), OP_BV_NUM)) {
|
|
return false;
|
|
}
|
|
func_decl * decl = to_app(n)->get_decl();
|
|
val = decl->get_parameter(0).get_rational();
|
|
bv_size = decl->get_parameter(1).get_int();
|
|
return true;
|
|
}
|
|
|
|
bool bv_recognizers::is_numeral(expr const * n, rational & val) const {
|
|
unsigned bv_size = 0;
|
|
return is_numeral(n, val, bv_size);
|
|
}
|
|
|
|
|
|
bool bv_recognizers::is_allone(expr const * e) const {
|
|
rational r;
|
|
unsigned bv_size;
|
|
if (!is_numeral(e, r, bv_size)) {
|
|
return false;
|
|
}
|
|
bool result = (r == rational::power_of_two(bv_size) - rational(1));
|
|
TRACE("is_allone", tout << r << " " << result << "\n";);
|
|
return result;
|
|
}
|
|
|
|
bool bv_recognizers::is_zero(expr const * n) const {
|
|
if (!is_app_of(n, get_fid(), OP_BV_NUM)) {
|
|
return false;
|
|
}
|
|
func_decl * decl = to_app(n)->get_decl();
|
|
return decl->get_parameter(0).get_rational().is_zero();
|
|
}
|
|
|
|
bool bv_recognizers::is_extract(expr const* e, unsigned& low, unsigned& high, expr*& b) const {
|
|
if (!is_extract(e)) return false;
|
|
low = get_extract_low(e);
|
|
high = get_extract_high(e);
|
|
b = to_app(e)->get_arg(0);
|
|
return true;
|
|
}
|
|
|
|
bool bv_recognizers::is_bv2int(expr const* e, expr*& r) const {
|
|
if (!is_bv2int(e)) return false;
|
|
r = to_app(e)->get_arg(0);
|
|
return true;
|
|
}
|
|
|
|
bool bv_recognizers::is_bit2bool(expr* e, expr*& bv, unsigned& idx) const {
|
|
if (!is_bit2bool(e))
|
|
return false;
|
|
bv = to_app(e)->get_arg(0);
|
|
idx = to_app(e)->get_parameter(0).get_int();
|
|
return true;
|
|
}
|
|
|
|
bool bv_recognizers::mult_inverse(rational const & n, unsigned bv_size, rational & result) {
|
|
if (n.is_one()) {
|
|
result = n;
|
|
return true;
|
|
}
|
|
|
|
if (!mod(n, rational(2)).is_one()) {
|
|
return false;
|
|
}
|
|
|
|
rational g;
|
|
rational x;
|
|
rational y;
|
|
g = gcd(n, rational::power_of_two(bv_size), x, y);
|
|
if (x.is_neg()) {
|
|
x = mod(x, rational::power_of_two(bv_size));
|
|
}
|
|
SASSERT(x.is_pos());
|
|
SASSERT(mod(x * n, rational::power_of_two(bv_size)).is_one());
|
|
result = x;
|
|
return true;
|
|
}
|
|
|
|
bv_util::bv_util(ast_manager & m):
|
|
bv_recognizers(m.mk_family_id(symbol("bv"))),
|
|
m_manager(m) {
|
|
m_plugin = static_cast<bv_decl_plugin*>(m.get_plugin(m.mk_family_id("bv")));
|
|
SASSERT(m.has_plugin(symbol("bv")));
|
|
}
|
|
|
|
app * bv_util::mk_numeral(rational const & val, sort* s) const {
|
|
if (!is_bv_sort(s)) {
|
|
return nullptr;
|
|
}
|
|
unsigned bv_size = get_bv_size(s);
|
|
return mk_numeral(val, bv_size);
|
|
}
|
|
|
|
app * bv_util::mk_numeral(rational const & val, unsigned bv_size) const {
|
|
parameter p[2] = { parameter(val), parameter(static_cast<int>(bv_size)) };
|
|
app * r = m_manager.mk_app(get_fid(), OP_BV_NUM, 2, p, 0, nullptr);
|
|
|
|
if (m_plugin->log_constant_meaning_prelude(r)) {
|
|
if (bv_size % 4 == 0) {
|
|
m_manager.trace_stream() << "#x";
|
|
val.display_hex(m_manager.trace_stream(), bv_size);
|
|
m_manager.trace_stream() << "\n";
|
|
} else {
|
|
m_manager.trace_stream() << "#b";
|
|
val.display_bin(m_manager.trace_stream(), bv_size);
|
|
m_manager.trace_stream() << "\n";
|
|
}
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
sort * bv_util::mk_sort(unsigned bv_size) {
|
|
parameter p[1] = { parameter(bv_size) };
|
|
return m_manager.mk_sort(get_fid(), BV_SORT, 1, p);
|
|
}
|
|
|
|
unsigned bv_util::get_int2bv_size(parameter const& p) {
|
|
int sz;
|
|
VERIFY(m_plugin->get_int2bv_size(1, &p, sz));
|
|
return static_cast<unsigned>(sz);
|
|
}
|
|
|
|
app * bv_util::mk_bv2int(expr* e) {
|
|
sort* s = m_manager.mk_sort(m_manager.mk_family_id("arith"), INT_SORT);
|
|
parameter p(s);
|
|
return m_manager.mk_app(get_fid(), OP_BV2INT, 1, &p, 1, &e);
|
|
}
|