mirror of
https://github.com/Z3Prover/z3
synced 2025-08-07 19:51:22 +00:00
adding simplifiers layer
simplifiers layer is a common substrate for global non-incremental and incremental processing. The first two layers are new, but others are to be ported form tactics. - bv::slice - rewrites equations to cut-dice-slice bit-vector extractions until they align. It creates opportunities for rewriting portions of bit-vectors to common sub-expressions, including values. - euf::completion - generalizes the KB simplifcation from asserted formulas to use the E-graph to establish a global and order-independent canonization. The interface dependent_expr_simplifier is amenable to forming tactics. Plugins for asserted-formulas is also possible but not yet realized.
This commit is contained in:
parent
1646a41b2f
commit
e57674490f
16 changed files with 1024 additions and 2 deletions
207
src/ast/simplifiers/bv_slice.cpp
Normal file
207
src/ast/simplifiers/bv_slice.cpp
Normal file
|
@ -0,0 +1,207 @@
|
|||
/*++
|
||||
Copyright (c) 2022 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
bv_slice.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
simplifier for extracting bit-vector ranges
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2022-11-2.
|
||||
|
||||
--*/
|
||||
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/simplifiers/bv_slice.h"
|
||||
|
||||
namespace bv {
|
||||
|
||||
void slice::reduce() {
|
||||
process_eqs();
|
||||
apply_subst();
|
||||
advance_qhead(m_fmls.size());
|
||||
}
|
||||
|
||||
void slice::process_eqs() {
|
||||
for (unsigned i = m_qhead; i < m_fmls.size(); ++i) {
|
||||
auto const [f, d] = m_fmls[i]();
|
||||
process_eq(f);
|
||||
}
|
||||
}
|
||||
|
||||
void slice::process_eq(expr* e) {
|
||||
expr* x, * y;
|
||||
if (!m.is_eq(e, x, y))
|
||||
return;
|
||||
if (!m_bv.is_bv(x))
|
||||
return;
|
||||
m_xs.reset();
|
||||
m_ys.reset();
|
||||
get_concats(x, m_xs);
|
||||
get_concats(y, m_ys);
|
||||
slice_eq();
|
||||
}
|
||||
|
||||
void slice::slice_eq() {
|
||||
unsigned i = m_xs.size(), j = m_ys.size();
|
||||
unsigned offx = 0, offy = 0;
|
||||
while (0 < i) {
|
||||
SASSERT(0 < j);
|
||||
expr* x = m_xs[i - 1]; // least significant bits are last
|
||||
expr* y = m_ys[j - 1];
|
||||
SASSERT(offx == 0 || offy == 0);
|
||||
unsigned szx = m_bv.get_bv_size(x);
|
||||
unsigned szy = m_bv.get_bv_size(y);
|
||||
SASSERT(offx < szx);
|
||||
SASSERT(offy < szy);
|
||||
if (szx - offx == szy - offy) {
|
||||
register_slice(offx, szx - 1, x);
|
||||
register_slice(offy, szy - 1, y);
|
||||
--i;
|
||||
--j;
|
||||
offx = 0;
|
||||
offy = 0;
|
||||
}
|
||||
else if (szx - offx < szy - offy) {
|
||||
register_slice(offx, szx - 1, x);
|
||||
register_slice(offy, offy + szx - offx - 1, y);
|
||||
offy += szx - offx;
|
||||
offx = 0;
|
||||
--i;
|
||||
}
|
||||
else {
|
||||
register_slice(offy, szy - 1, y);
|
||||
register_slice(offx, offx + szy - offy - 1, x);
|
||||
offx += szy - offy;
|
||||
offy = 0;
|
||||
--j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void slice::register_slice(unsigned lo, unsigned hi, expr* x) {
|
||||
SASSERT(lo <= hi && hi < m_bv.get_bv_size(x));
|
||||
unsigned l, h;
|
||||
while (m_bv.is_extract(x, l, h, x)) {
|
||||
// x[l:h][lo:hi] = x[l+lo:l+hi]
|
||||
hi += l;
|
||||
lo += l;
|
||||
SASSERT(lo <= hi && hi < m_bv.get_bv_size(x));
|
||||
}
|
||||
unsigned sz = m_bv.get_bv_size(x);
|
||||
if (hi - lo + 1 == sz)
|
||||
return;
|
||||
SASSERT(0 < lo || hi + 1 < sz);
|
||||
auto& b = m_boundaries.insert_if_not_there(x, uint_set());
|
||||
|
||||
struct remove_set : public trail {
|
||||
uint_set& b;
|
||||
unsigned i;
|
||||
remove_set(uint_set& b, unsigned i) :b(b), i(i) {}
|
||||
void undo() override {
|
||||
b.remove(i);
|
||||
}
|
||||
};
|
||||
if (lo > 0 && !b.contains(lo)) {
|
||||
b.insert(lo);
|
||||
if (m_num_scopes > 0)
|
||||
m_trail.push(remove_set(b, lo));
|
||||
}
|
||||
if (hi + 1 < sz && !b.contains(hi + 1)) {
|
||||
b.insert(hi + 1);
|
||||
if (m_num_scopes > 0)
|
||||
m_trail.push(remove_set(b, hi+ 1));
|
||||
}
|
||||
}
|
||||
|
||||
expr* slice::mk_extract(unsigned hi, unsigned lo, expr* x) {
|
||||
unsigned l, h;
|
||||
while (m_bv.is_extract(x, l, h, x)) {
|
||||
lo += l;
|
||||
hi += l;
|
||||
}
|
||||
if (lo == 0 && hi + 1 == m_bv.get_bv_size(x))
|
||||
return x;
|
||||
else
|
||||
return m_bv.mk_extract(hi, lo, x);
|
||||
}
|
||||
|
||||
void slice::apply_subst() {
|
||||
if (m_boundaries.empty())
|
||||
return;
|
||||
expr_ref_vector cache(m), pin(m);
|
||||
ptr_vector<expr> todo, args;
|
||||
expr* c;
|
||||
for (unsigned i = m_qhead; i < m_fmls.size(); ++i) {
|
||||
auto const [f, d] = m_fmls[i]();
|
||||
todo.push_back(f);
|
||||
pin.push_back(f);
|
||||
while (!todo.empty()) {
|
||||
expr* e = todo.back();
|
||||
c = cache.get(e->get_id(), nullptr);
|
||||
if (c) {
|
||||
todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
if (!is_app(e)) {
|
||||
cache.setx(e->get_id(), e);
|
||||
todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
args.reset();
|
||||
unsigned sz = todo.size();
|
||||
bool change = false;
|
||||
for (expr* arg : *to_app(e)) {
|
||||
c = cache.get(arg->get_id(), nullptr);
|
||||
if (c) {
|
||||
args.push_back(c);
|
||||
change |= c != arg;
|
||||
SASSERT(c->get_sort() == arg->get_sort());
|
||||
}
|
||||
else
|
||||
todo.push_back(arg);
|
||||
}
|
||||
if (sz == todo.size()) {
|
||||
todo.pop_back();
|
||||
if (change)
|
||||
cache.setx(e->get_id(), m_rewriter.mk_app(to_app(e)->get_decl(), args));
|
||||
else
|
||||
cache.setx(e->get_id(), e);
|
||||
SASSERT(e->get_sort() == cache.get(e->get_id())->get_sort());
|
||||
uint_set b;
|
||||
if (m_boundaries.find(e, b)) {
|
||||
expr* r = cache.get(e->get_id());
|
||||
expr_ref_vector xs(m);
|
||||
unsigned lo = 0;
|
||||
for (unsigned hi : b) {
|
||||
xs.push_back(mk_extract(hi - 1, lo, r));
|
||||
lo = hi;
|
||||
}
|
||||
xs.push_back(mk_extract(m_bv.get_bv_size(r) - 1, lo, r));
|
||||
xs.reverse();
|
||||
expr_ref xc(m_bv.mk_concat(xs), m);
|
||||
cache.setx(e->get_id(), xc);
|
||||
SASSERT(e->get_sort() == xc->get_sort());
|
||||
}
|
||||
}
|
||||
}
|
||||
c = cache.get(f->get_id());
|
||||
if (c != f)
|
||||
m_fmls.update(i, dependent_expr(m, c, d));
|
||||
}
|
||||
}
|
||||
|
||||
void slice::get_concats(expr* x, ptr_vector<expr>& xs) {
|
||||
while (m_bv.is_concat(x)) {
|
||||
xs.append(to_app(x)->get_num_args(), to_app(x)->get_args());
|
||||
x = xs.back();
|
||||
xs.pop_back();
|
||||
}
|
||||
xs.push_back(x);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue