Skip to content

Commit 1d99b30

Browse files
committed
SMT back-end: fix parsing of Z3 models involving let
Z3 produces models such as ``` ((|main::1::arr!0@1#3[[1]]| (let ((a!1 (store (store (store ((as const (Array (_ BitVec 64) (_ BitVec 8))) #x00) #x0000000000000003 #x02) #x0000000000000002 #x01) #x0000000000000004 #x01))) (mk-struct.0 #x00 #x00 a!1)))) ``` (for cbmc/Array_operations2), which is a `let` around a struct. Our code previously would only handle these for arrays, and not for arrays within other compound types. Also, Z3 may use multiple bindings (observable in the same regression test), which we did not cater for at all. This commit promotes `let` parsing to the top level, expanding bindings as needed.
1 parent f6cb64a commit 1d99b30

File tree

2 files changed

+28
-8
lines changed

2 files changed

+28
-8
lines changed

src/solvers/smt2/smt2_conv.cpp

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -537,14 +537,6 @@ void smt2_convt::walk_array_tree(
537537
exprt value = parse_rec(src.get_sub()[3], type.element_type());
538538
operands_map->emplace(index, value);
539539
}
540-
else if(src.get_sub().size() == 3 && src.get_sub()[0].id() == "let")
541-
{
542-
// This is produced by Z3
543-
// (let (....) (....))
544-
walk_array_tree(
545-
operands_map, src.get_sub()[1].get_sub()[0].get_sub()[1], type);
546-
walk_array_tree(operands_map, src.get_sub()[2], type);
547-
}
548540
else if(src.get_sub().size()==2 &&
549541
src.get_sub()[0].get_sub().size()==3 &&
550542
src.get_sub()[0].get_sub()[0].id()=="as" &&
@@ -554,6 +546,12 @@ void smt2_convt::walk_array_tree(
554546
exprt default_value = parse_rec(src.get_sub()[1], type.element_type());
555547
operands_map->emplace(-1, default_value);
556548
}
549+
else
550+
{
551+
auto bindings_it = current_bindings.find(src.id());
552+
if(bindings_it != current_bindings.end())
553+
walk_array_tree(operands_map, bindings_it->second, type);
554+
}
557555
}
558556

559557
exprt smt2_convt::parse_union(
@@ -633,6 +631,27 @@ smt2_convt::parse_struct(const irept &src, const struct_typet &type)
633631

634632
exprt smt2_convt::parse_rec(const irept &src, const typet &type)
635633
{
634+
if(src.get_sub().size() == 3 && src.get_sub()[0].id() == ID_let)
635+
{
636+
// This is produced by Z3
637+
// (let (....) (....))
638+
auto previous_bindings = current_bindings;
639+
for(const auto &binding : src.get_sub()[1].get_sub())
640+
{
641+
const irep_idt &name = binding.get_sub()[0].id();
642+
current_bindings.emplace(name, binding.get_sub()[1]);
643+
}
644+
exprt result = parse_rec(src.get_sub()[2], type);
645+
current_bindings = std::move(previous_bindings);
646+
return result;
647+
}
648+
649+
auto bindings_it = current_bindings.find(src.id());
650+
if(bindings_it != current_bindings.end())
651+
{
652+
return parse_rec(bindings_it->second, type);
653+
}
654+
636655
if(
637656
type.id() == ID_signedbv || type.id() == ID_unsignedbv ||
638657
type.id() == ID_integer || type.id() == ID_rational ||

src/solvers/smt2/smt2_conv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ class smt2_convt : public stack_decision_proceduret
187187
std::unordered_map<int64_t, exprt> *operands_map,
188188
const irept &src,
189189
const array_typet &type);
190+
std::unordered_map<irep_idt, irept> current_bindings;
190191

191192
// we use this to build a bit-vector encoding of the FPA theory
192193
void convert_floatbv(const exprt &expr);

0 commit comments

Comments
 (0)