/*++ Copyright (c) 2006 Microsoft Corporation Module Name: smt_cg_table.cpp Abstract: Author: Leonardo de Moura (leonardo) 2008-02-19. Revision History: --*/ #include "smt/smt_cg_table.h" #include "ast/ast_pp.h" #include "ast/ast_ll_pp.h" namespace smt { // one table per func_decl implementation unsigned cg_table::cg_hash::operator()(enode * n) const { SASSERT(n->get_decl()->is_flat_associative() || n->get_num_args() >= 3); unsigned a, b, c; a = b = 0x9e3779b9; c = 11; unsigned i = n->get_num_args(); while (i >= 3) { i--; a += n->get_arg(i)->get_root()->hash(); i--; b += n->get_arg(i)->get_root()->hash(); i--; c += n->get_arg(i)->get_root()->hash(); mix(a, b, c); } switch (i) { case 2: b += n->get_arg(1)->get_root()->hash(); Z3_fallthrough; case 1: c += n->get_arg(0)->get_root()->hash(); } mix(a, b, c); return c; } bool cg_table::cg_eq::operator()(enode * n1, enode * n2) const { SASSERT(n1->get_decl() == n2->get_decl()); unsigned num = n1->get_num_args(); if (num != n2->get_num_args()) { return false; } for (unsigned i = 0; i < num; i++) if (n1->get_arg(i)->get_root() != n2->get_arg(i)->get_root()) return false; return true; } cg_table::cg_table(ast_manager & m): m_manager(m) { } cg_table::~cg_table() { reset(); } void * cg_table::mk_table_for(func_decl * d) { void * r; SASSERT(d->get_arity() >= 1); switch (d->get_arity()) { case 1: r = TAG(void*, alloc(unary_table), UNARY); SASSERT(GET_TAG(r) == UNARY); return r; case 2: if (d->is_flat_associative()) { // applications of declarations that are flat-assoc (e.g., +) may have many arguments. r = TAG(void*, alloc(table), NARY); SASSERT(GET_TAG(r) == NARY); return r; } else if (d->is_commutative()) { r = TAG(void*, alloc(comm_table, cg_comm_hash(), cg_comm_eq(m_commutativity)), BINARY_COMM); SASSERT(GET_TAG(r) == BINARY_COMM); return r; } else { r = TAG(void*, alloc(binary_table), BINARY); SASSERT(GET_TAG(r) == BINARY); return r; } default: r = TAG(void*, alloc(table), NARY); SASSERT(GET_TAG(r) == NARY); return r; } } unsigned cg_table::set_func_decl_id(enode * n) { func_decl * f = n->get_decl(); unsigned tid; if (!m_func_decl2id.find(f, tid)) { tid = m_tables.size(); m_func_decl2id.insert(f, tid); m_manager.inc_ref(f); SASSERT(tid <= m_tables.size()); m_tables.push_back(mk_table_for(f)); } SASSERT(tid < m_tables.size()); n->set_func_decl_id(tid); DEBUG_CODE({ unsigned tid_prime; SASSERT(m_func_decl2id.find(n->get_decl(), tid_prime) && tid == tid_prime); }); return tid; } void cg_table::reset() { for (void* t : m_tables) { switch (GET_TAG(t)) { case UNARY: dealloc(UNTAG(unary_table*, t)); break; case BINARY: dealloc(UNTAG(binary_table*, t)); break; case BINARY_COMM: dealloc(UNTAG(comm_table*, t)); break; case NARY: dealloc(UNTAG(table*, t)); break; } } m_tables.reset(); for (auto const& kv : m_func_decl2id) { m_manager.dec_ref(kv.m_key); } m_func_decl2id.reset(); } void cg_table::display(std::ostream & out) const { for (auto const& kv : m_func_decl2id) { void * t = m_tables[kv.m_value]; out << mk_pp(kv.m_key, m_manager) << ": "; switch (GET_TAG(t)) { case UNARY: display_unary(out, t); break; case BINARY: display_binary(out, t); break; case BINARY_COMM: display_binary_comm(out, t); break; case NARY: display_nary(out, t); break; } } } void cg_table::display_binary(std::ostream& out, void* t) const { binary_table* tb = UNTAG(binary_table*, t); out << "b "; for (enode* n : *tb) { out << n->get_owner_id() << " " << cg_binary_hash()(n) << " "; } out << "\n"; } void cg_table::display_binary_comm(std::ostream& out, void* t) const { comm_table* tb = UNTAG(comm_table*, t); out << "bc "; for (enode* n : *tb) { out << n->get_owner_id() << " "; } out << "\n"; } void cg_table::display_unary(std::ostream& out, void* t) const { unary_table* tb = UNTAG(unary_table*, t); out << "un "; for (enode* n : *tb) { out << n->get_owner_id() << " "; } out << "\n"; } void cg_table::display_nary(std::ostream& out, void* t) const { table* tb = UNTAG(table*, t); out << "nary "; for (enode* n : *tb) { out << n->get_owner_id() << " "; } out << "\n"; } enode_bool_pair cg_table::insert(enode * n) { // it doesn't make sense to insert a constant. SASSERT(n->get_num_args() > 0); SASSERT(!m_manager.is_and(n->get_expr())); SASSERT(!m_manager.is_or(n->get_expr())); enode * n_prime; void * t = get_table(n); switch (static_cast(GET_TAG(t))) { case UNARY: n_prime = UNTAG(unary_table*, t)->insert_if_not_there(n); return enode_bool_pair(n_prime, false); case BINARY: n_prime = UNTAG(binary_table*, t)->insert_if_not_there(n); TRACE("cg_table", tout << "insert: " << n->get_owner_id() << " " << cg_binary_hash()(n) << " inserted: " << (n == n_prime) << " " << n_prime->get_owner_id() << "\n"; display_binary(tout, t); tout << "contains_ptr: " << contains_ptr(n) << "\n";); return enode_bool_pair(n_prime, false); case BINARY_COMM: m_commutativity = false; n_prime = UNTAG(comm_table*, t)->insert_if_not_there(n); return enode_bool_pair(n_prime, m_commutativity); default: n_prime = UNTAG(table*, t)->insert_if_not_there(n); return enode_bool_pair(n_prime, false); } } void cg_table::erase(enode * n) { SASSERT(n->get_num_args() > 0); void * t = get_table(n); switch (static_cast(GET_TAG(t))) { case UNARY: UNTAG(unary_table*, t)->erase(n); break; case BINARY: TRACE("cg_table", tout << "erase: " << n->get_owner_id() << " " << cg_binary_hash()(n) << " contains: " << contains_ptr(n) << "\n";); UNTAG(binary_table*, t)->erase(n); break; case BINARY_COMM: UNTAG(comm_table*, t)->erase(n); break; default: UNTAG(table*, t)->erase(n); break; } } void cg_table::display_compact(std::ostream & out) const { } bool cg_table::check_invariant() const { return true; } };