Skip to content

Commit

Permalink
Add rewrite for array selects of chain of stores of a same value (#6526)
Browse files Browse the repository at this point in the history
* Add rewrite for array selects of chain of stores of a same value

Example:
```smt
(declare-fun mem () (Array (_ BitVec 4) (_ BitVec 4)))
(declare-const x (_ BitVec 4))
(declare-const y (_ BitVec 4))
; simplifies to #x1
(simplify (select (store (store (store mem #x1 #x1) y #x1) x #x1) #x1))
```

* Update array_rewriter.cpp

* Update array_rewriter.cpp
  • Loading branch information
nunoplopes committed Jan 9, 2023
1 parent 1ddef11 commit 5899fe3
Showing 1 changed file with 86 additions and 48 deletions.
134 changes: 86 additions & 48 deletions src/ast/rewriter/array_rewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,13 +198,96 @@ bool array_rewriter::squash_store(unsigned n, expr* const* args, expr_ref& resul

br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args >= 2);
expr *arg0 = args[0];
expr_ref tmp(m());
bool first = true;

#define RET(x, status) \
tmp = x; \
if (first || tmp == result) { \
result = std::move(tmp); \
return status; \
} \
goto exit

while (true) {
if (m_util.is_store(arg0)) {
SASSERT(to_app(arg0)->get_num_args() == num_args+1);
switch (compare_args(num_args - 1, args+1, to_app(arg0)->get_args()+1)) {
case l_true:
// select(store(a, I, v), I) --> v
RET(to_app(arg0)->get_arg(num_args), BR_DONE);

case l_false:
// select(store(a, I, v), J) --> select(a, J) if I != J
arg0 = to_app(arg0)->get_arg(0);
continue;

case l_undef:
// check if loading from subsequent arrays yields the same value
if (first) {
result = to_app(arg0)->get_arg(num_args);
first = false;
} else if (result != to_app(arg0)->get_arg(num_args)) {
goto exit;
}
arg0 = to_app(arg0)->get_arg(0);
continue;
}
}

if (m_util.is_const(arg0)) {
// select(const(v), I) --> v
RET(to_app(arg0)->get_arg(0), BR_DONE);
}

if (is_lambda(arg0)) {
// anywhere lambda reduction as opposed to whnf
// select(lambda(X) M, N) -> M[N/X]
quantifier* q = to_quantifier(arg0);
SASSERT(q->get_num_decls() == num_args - 1);
var_subst subst(m());
expr_ref_vector _args(m());
var_shifter sh(m());
for (unsigned i = 1; i < num_args; ++i) {
sh(args[i], num_args-1, result);
_args.push_back(result);
}
expr_ref tmp2 = subst(q->get_expr(), _args.size(), _args.data());
inv_var_shifter invsh(m());
invsh(tmp2, _args.size(), tmp2);
RET(std::move(tmp2), BR_REWRITE_FULL);
}

if (m_util.is_map(arg0)) {
app* a = to_app(arg0);
func_decl* f0 = m_util.get_map_func_decl(a);
expr_ref_vector args0(m());
for (expr* arg : *a) {
ptr_vector<expr> args1;
args1.push_back(arg);
args1.append(num_args-1, args + 1);
args0.push_back(m_util.mk_select(args1.size(), args1.data()));
}
RET(m().mk_app(f0, args0.size(), args0.data()), BR_REWRITE2);
}

if (m_util.is_as_array(arg0)) {
// select(as-array[f], I) --> f(I)
func_decl * f = m_util.get_as_array_func_decl(to_app(arg0));
RET(m().mk_app(f, num_args - 1, args + 1), BR_REWRITE1);
}
break;
}

exit:
result.reset();

if (m_util.is_store(args[0])) {
SASSERT(to_app(args[0])->get_num_args() == num_args+1);
switch (compare_args(num_args - 1, args+1, to_app(args[0])->get_args()+1)) {
case l_true:
// select(store(a, I, v), I) --> v
result = to_app(args[0])->get_arg(num_args);
return BR_DONE;
UNREACHABLE();
case l_false: {
expr* arg0 = to_app(args[0])->get_arg(0);
while (m_util.is_store(arg0) && compare_args(num_args-1, args + 1, to_app(arg0)->get_args() + 1) == l_false) {
Expand Down Expand Up @@ -261,51 +344,6 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args,
}
}

if (m_util.is_const(args[0])) {
// select(const(v), I) --> v
result = to_app(args[0])->get_arg(0);
return BR_DONE;
}

if (is_lambda(args[0])) {
// anywhere lambda reduction as opposed to whnf
// select(lambda(X) M, N) -> M[N/X]
quantifier* q = to_quantifier(args[0]);
SASSERT(q->get_num_decls() == num_args - 1);
var_subst subst(m());
expr_ref_vector _args(m());
var_shifter sh(m());
for (unsigned i = 1; i < num_args; ++i) {
sh(args[i], num_args-1, result);
_args.push_back(result);
}
result = subst(q->get_expr(), _args.size(), _args.data());
inv_var_shifter invsh(m());
invsh(result, _args.size(), result);
return BR_REWRITE_FULL;
}

if (m_util.is_map(args[0])) {
app* a = to_app(args[0]);
func_decl* f0 = m_util.get_map_func_decl(a);
expr_ref_vector args0(m());
for (expr* arg : *a) {
ptr_vector<expr> args1;
args1.push_back(arg);
args1.append(num_args-1, args + 1);
args0.push_back(m_util.mk_select(args1.size(), args1.data()));
}
result = m().mk_app(f0, args0.size(), args0.data());
return BR_REWRITE2;
}

if (m_util.is_as_array(args[0])) {
// select(as-array[f], I) --> f(I)
func_decl * f = m_util.get_as_array_func_decl(to_app(args[0]));
result = m().mk_app(f, num_args - 1, args + 1);
return BR_REWRITE1;
}

expr* c, *th, *el;
if (m().is_ite(args[0], c, th, el) && (m_expand_select_ite || (th->get_ref_count() == 1 || el->get_ref_count() == 1))) {
ptr_vector<expr> args1, args2;
Expand Down

0 comments on commit 5899fe3

Please sign in to comment.