Skip to content

Commit 59674e3

Browse files
authored
Merge pull request #8400 from tautschnig/bugfixes/smt2-8399
SMT2 back-end: fix inconsistent array flattening
2 parents c193c27 + af46479 commit 59674e3

File tree

3 files changed

+95
-55
lines changed

3 files changed

+95
-55
lines changed

src/solvers/flattening/arrays.cpp

+35
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Author: Daniel Kroening, [email protected]
1212
#include <util/json.h>
1313
#include <util/message.h>
1414
#include <util/replace_expr.h>
15+
#include <util/replace_symbol.h>
1516
#include <util/std_expr.h>
1617

1718
#include <solvers/prop/literal_expr.h>
@@ -237,6 +238,11 @@ void arrayst::collect_arrays(const exprt &a)
237238
else if(a.id() == ID_array_comprehension)
238239
{
239240
}
241+
else if(auto let_expr = expr_try_dynamic_cast<let_exprt>(a))
242+
{
243+
arrays.make_union(a, let_expr->where());
244+
collect_arrays(let_expr->where());
245+
}
240246
else
241247
{
242248
DATA_INVARIANT(
@@ -528,6 +534,33 @@ void arrayst::add_array_constraints(
528534
else if(expr.id()==ID_index)
529535
{
530536
}
537+
else if(auto let_expr = expr_try_dynamic_cast<let_exprt>(expr))
538+
{
539+
// we got x=let(a=e, A)
540+
// add x[i]=A[a/e][i]
541+
542+
exprt where = let_expr->where();
543+
replace_symbolt replace_symbol;
544+
for(const auto &binding :
545+
make_range(let_expr->variables()).zip(let_expr->values()))
546+
{
547+
replace_symbol.insert(binding.first, binding.second);
548+
}
549+
replace_symbol(where);
550+
551+
for(const auto &index : index_set)
552+
{
553+
index_exprt index_expr{expr, index};
554+
index_exprt where_indexed{where, index};
555+
556+
// add constraint
557+
lazy_constraintt lazy{
558+
lazy_typet::ARRAY_LET, equal_exprt{index_expr, where_indexed}};
559+
560+
add_array_constraint(lazy, false); // added immediately
561+
array_constraint_count[constraint_typet::ARRAY_LET]++;
562+
}
563+
}
531564
else
532565
{
533566
DATA_INVARIANT(
@@ -875,6 +908,8 @@ std::string arrayst::enum_to_string(constraint_typet type)
875908
return "arrayComprehension";
876909
case constraint_typet::ARRAY_EQUALITY:
877910
return "arrayEquality";
911+
case constraint_typet::ARRAY_LET:
912+
return "arrayLet";
878913
default:
879914
UNREACHABLE;
880915
}

src/solvers/flattening/arrays.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ class arrayst:public equalityt
9393
ARRAY_OF,
9494
ARRAY_TYPECAST,
9595
ARRAY_CONSTANT,
96-
ARRAY_COMPREHENSION
96+
ARRAY_COMPREHENSION,
97+
ARRAY_LET
9798
};
9899

99100
struct lazy_constraintt
@@ -124,7 +125,8 @@ class arrayst:public equalityt
124125
ARRAY_TYPECAST,
125126
ARRAY_CONSTANT,
126127
ARRAY_COMPREHENSION,
127-
ARRAY_EQUALITY
128+
ARRAY_EQUALITY,
129+
ARRAY_LET
128130
};
129131

130132
typedef std::map<constraint_typet, size_t> array_constraint_countt;

src/solvers/smt2/smt2_conv.cpp

+56-53
Original file line numberDiff line numberDiff line change
@@ -4445,15 +4445,22 @@ void smt2_convt::convert_member(const member_exprt &expr)
44454445
CHECK_RETURN_WITH_DIAGNOSTICS(
44464446
width != 0, "failed to get union member width");
44474447

4448-
unflatten(wheret::BEGIN, expr.type());
4448+
if(use_datatypes)
4449+
{
4450+
unflatten(wheret::BEGIN, expr.type());
44494451

4450-
out << "((_ extract "
4451-
<< (width-1)
4452-
<< " 0) ";
4453-
convert_expr(struct_op);
4454-
out << ")";
4452+
out << "((_ extract " << (width - 1) << " 0) ";
4453+
convert_expr(struct_op);
4454+
out << ")";
44554455

4456-
unflatten(wheret::END, expr.type());
4456+
unflatten(wheret::END, expr.type());
4457+
}
4458+
else
4459+
{
4460+
out << "((_ extract " << (width - 1) << " 0) ";
4461+
convert_expr(struct_op);
4462+
out << ")";
4463+
}
44574464
}
44584465
else
44594466
UNEXPECTEDCASE(
@@ -4565,57 +4572,50 @@ void smt2_convt::unflatten(
45654572
}
45664573
else if(type.id() == ID_array)
45674574
{
4568-
if(use_datatypes)
4575+
PRECONDITION(use_as_const);
4576+
4577+
if(where == wheret::BEGIN)
4578+
out << "(let ((?ufop" << nesting << " ";
4579+
else
45694580
{
4570-
PRECONDITION(use_as_const);
4581+
out << ")) ";
45714582

4572-
if(where == wheret::BEGIN)
4573-
out << "(let ((?ufop" << nesting << " ";
4574-
else
4575-
{
4576-
out << ")) ";
4583+
const array_typet &array_type = to_array_type(type);
45774584

4578-
const array_typet &array_type = to_array_type(type);
4585+
std::size_t subtype_width = boolbv_width(array_type.element_type());
45794586

4580-
std::size_t subtype_width = boolbv_width(array_type.element_type());
4587+
DATA_INVARIANT(
4588+
array_type.size().is_constant(),
4589+
"cannot unflatten arrays of non-constant size");
4590+
mp_integer size =
4591+
numeric_cast_v<mp_integer>(to_constant_expr(array_type.size()));
45814592

4582-
DATA_INVARIANT(
4583-
array_type.size().is_constant(),
4584-
"cannot unflatten arrays of non-constant size");
4585-
mp_integer size =
4586-
numeric_cast_v<mp_integer>(to_constant_expr(array_type.size()));
4593+
for(mp_integer i = 1; i < size; ++i)
4594+
out << "(store ";
45874595

4588-
for(mp_integer i = 1; i < size; ++i)
4589-
out << "(store ";
4596+
out << "((as const ";
4597+
convert_type(array_type);
4598+
out << ") ";
4599+
// use element at index 0 as default value
4600+
unflatten(wheret::BEGIN, array_type.element_type(), nesting + 1);
4601+
out << "((_ extract " << subtype_width - 1 << " "
4602+
<< "0) ?ufop" << nesting << ")";
4603+
unflatten(wheret::END, array_type.element_type(), nesting + 1);
4604+
out << ") ";
45904605

4591-
out << "((as const ";
4592-
convert_type(array_type);
4593-
out << ") ";
4594-
// use element at index 0 as default value
4606+
std::size_t offset = subtype_width;
4607+
for(mp_integer i = 1; i < size; ++i, offset += subtype_width)
4608+
{
4609+
convert_expr(from_integer(i, array_type.index_type()));
4610+
out << ' ';
45954611
unflatten(wheret::BEGIN, array_type.element_type(), nesting + 1);
4596-
out << "((_ extract " << subtype_width - 1 << " "
4597-
<< "0) ?ufop" << nesting << ")";
4612+
out << "((_ extract " << offset + subtype_width - 1 << " " << offset
4613+
<< ") ?ufop" << nesting << ")";
45984614
unflatten(wheret::END, array_type.element_type(), nesting + 1);
4599-
out << ") ";
4600-
4601-
std::size_t offset = subtype_width;
4602-
for(mp_integer i = 1; i < size; ++i, offset += subtype_width)
4603-
{
4604-
convert_expr(from_integer(i, array_type.index_type()));
4605-
out << ' ';
4606-
unflatten(wheret::BEGIN, array_type.element_type(), nesting + 1);
4607-
out << "((_ extract " << offset + subtype_width - 1 << " " << offset
4608-
<< ") ?ufop" << nesting << ")";
4609-
unflatten(wheret::END, array_type.element_type(), nesting + 1);
4610-
out << ")"; // store
4611-
}
4612-
4613-
out << ")"; // let
4615+
out << ")"; // store
46144616
}
4615-
}
4616-
else
4617-
{
4618-
// nop, already a bv
4617+
4618+
out << ")"; // let
46194619
}
46204620
}
46214621
else if(type.id() == ID_struct || type.id() == ID_struct_tag)
@@ -4767,19 +4767,22 @@ void smt2_convt::set_to(const exprt &expr, bool value)
47674767
{
47684768
out << "(define-fun " << smt2_identifier;
47694769
out << " () ";
4770+
convert_type(equal_expr.lhs().type());
4771+
out << ' ';
47704772
if(
47714773
equal_expr.lhs().type().id() != ID_array ||
47724774
use_array_theory(prepared_rhs))
47734775
{
4774-
convert_type(equal_expr.lhs().type());
4776+
convert_expr(prepared_rhs);
47754777
}
47764778
else
47774779
{
4778-
std::size_t width = boolbv_width(equal_expr.lhs().type());
4779-
out << "(_ BitVec " << width << ")";
4780+
unflatten(wheret::BEGIN, equal_expr.lhs().type());
4781+
4782+
convert_expr(prepared_rhs);
4783+
4784+
unflatten(wheret::END, equal_expr.lhs().type());
47804785
}
4781-
out << ' ';
4782-
convert_expr(prepared_rhs);
47834786
out << ')' << '\n';
47844787
}
47854788

0 commit comments

Comments
 (0)