Skip to content

Commit bb5433f

Browse files
committed
SMT back-end: support unflattening arrays
When data types are used, array-typed members may occur within structs. Calls to `unflatten` (as is needed for member-of-union expressions) must then restore array-typed elements and not just bitvectors for struct constructors.
1 parent f019266 commit bb5433f

File tree

1 file changed

+57
-9
lines changed

1 file changed

+57
-9
lines changed

src/solvers/smt2/smt2_conv.cpp

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4820,6 +4820,61 @@ void smt2_convt::unflatten(
48204820
// nop, already a bv
48214821
}
48224822
}
4823+
else if(type.id() == ID_array)
4824+
{
4825+
if(use_datatypes)
4826+
{
4827+
PRECONDITION(use_as_const);
4828+
4829+
if(where == wheret::BEGIN)
4830+
out << "(let ((?ufop" << nesting << " ";
4831+
else
4832+
{
4833+
out << ")) ";
4834+
4835+
const array_typet &array_type = to_array_type(type);
4836+
4837+
std::size_t subtype_width = boolbv_width(array_type.element_type());
4838+
4839+
DATA_INVARIANT(
4840+
array_type.size().is_constant(),
4841+
"cannot unflatten arrays of non-constant size");
4842+
mp_integer size =
4843+
numeric_cast_v<mp_integer>(to_constant_expr(array_type.size()));
4844+
4845+
for(mp_integer i = 1; i < size; ++i)
4846+
out << "(store ";
4847+
4848+
out << "((as const ";
4849+
convert_type(array_type);
4850+
out << ") ";
4851+
// use element at index 0 as default value
4852+
unflatten(wheret::BEGIN, array_type.element_type(), nesting + 1);
4853+
out << "((_ extract " << subtype_width - 1 << " "
4854+
<< "0) ?ufop" << nesting << ")";
4855+
unflatten(wheret::END, array_type.element_type(), nesting + 1);
4856+
out << ") ";
4857+
4858+
std::size_t offset = subtype_width;
4859+
for(mp_integer i = 1; i < size; ++i, offset += subtype_width)
4860+
{
4861+
convert_expr(from_integer(i, array_type.index_type()));
4862+
out << ' ';
4863+
unflatten(wheret::BEGIN, array_type.element_type(), nesting + 1);
4864+
out << "((_ extract " << offset + subtype_width - 1 << " " << offset
4865+
<< ") ?ufop" << nesting << ")";
4866+
unflatten(wheret::END, array_type.element_type(), nesting + 1);
4867+
out << ")"; // store
4868+
}
4869+
4870+
out << ")"; // let
4871+
}
4872+
}
4873+
else
4874+
{
4875+
// nop, already a bv
4876+
}
4877+
}
48234878
else if(type.id() == ID_struct || type.id() == ID_struct_tag)
48244879
{
48254880
if(use_datatypes)
@@ -5605,18 +5660,11 @@ bool smt2_convt::use_array_theory(const exprt &expr)
56055660
const typet &type = expr.type();
56065661
PRECONDITION(type.id()==ID_array);
56075662

5608-
// a union is always flattened; else always use array theory when we have
5609-
// datatypes
5663+
// arrays inside structs get flattened, unless we have datatypes
56105664
if(expr.id() == ID_with)
56115665
return use_array_theory(to_with_expr(expr).old());
5612-
else if(auto member = expr_try_dynamic_cast<member_exprt>(expr))
5613-
{
5614-
// arrays inside structs get flattened, unless we have datatypes
5615-
return use_datatypes && member->compound().type().id() != ID_union &&
5616-
member->compound().type().id() != ID_union_tag;
5617-
}
56185666
else
5619-
return true;
5667+
return use_datatypes || expr.id() != ID_member;
56205668
}
56215669

56225670
void smt2_convt::convert_type(const typet &type)

0 commit comments

Comments
 (0)