Skip to content

Commit ea7b092

Browse files
authored
Merge pull request #8674 from tautschnig/three-operand-with
Restrict with_exprt to exactly three operands
2 parents f806d1e + fc5c5a0 commit ea7b092

File tree

14 files changed

+252
-302
lines changed

14 files changed

+252
-302
lines changed

src/goto-programs/graphml_witness.cpp

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -170,26 +170,24 @@ std::string graphml_witnesst::convert_assign_rec(
170170
else if(assign.rhs().id() == ID_with)
171171
{
172172
const with_exprt &with_expr = to_with_expr(assign.rhs());
173-
const auto &ops = with_expr.operands();
174173

175-
for(std::size_t i = 1; i < ops.size(); i += 2)
176-
{
177-
if(!result.empty())
178-
result += ' ';
174+
if(!result.empty())
175+
result += ' ';
179176

180-
if(ops[i].id() == ID_member_name)
181-
{
182-
const member_exprt member{
183-
assign.lhs(), ops[i].get(ID_component_name), ops[i + 1].type()};
184-
result +=
185-
convert_assign_rec(identifier, code_assignt(member, ops[i + 1]));
186-
}
187-
else
188-
{
189-
const index_exprt index{assign.lhs(), ops[i]};
190-
result +=
191-
convert_assign_rec(identifier, code_assignt(index, ops[i + 1]));
192-
}
177+
if(with_expr.where().id() == ID_member_name)
178+
{
179+
const member_exprt member{
180+
assign.lhs(),
181+
with_expr.where().get(ID_component_name),
182+
with_expr.new_value().type()};
183+
result += convert_assign_rec(
184+
identifier, code_assignt(member, with_expr.new_value()));
185+
}
186+
else
187+
{
188+
const index_exprt index{assign.lhs(), with_expr.where()};
189+
result += convert_assign_rec(
190+
identifier, code_assignt(index, with_expr.new_value()));
193191
}
194192
}
195193
else

src/solvers/flattening/arrays.cpp

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,8 @@ void arrayst::collect_arrays(const exprt &a)
145145
collect_arrays(with_expr.old());
146146

147147
// make sure this shows as an application
148-
for(std::size_t i = 1; i < with_expr.operands().size(); i += 2)
149-
{
150-
index_exprt index_expr(with_expr.old(), with_expr.operands()[i]);
151-
record_array_index(index_expr);
152-
}
148+
index_exprt index_expr(with_expr.old(), with_expr.where());
149+
record_array_index(index_expr);
153150
}
154151
else if(a.id()==ID_update)
155152
{
@@ -574,31 +571,24 @@ void arrayst::add_array_constraints_with(
574571
const index_sett &index_set,
575572
const with_exprt &expr)
576573
{
577-
// We got x=(y with [i:=v, j:=w, ...]).
578-
// First add constraints x[i]=v, x[j]=w, ...
574+
// We got x=(y with [i:=v]).
575+
// First add constraint x[i]=v
579576
std::unordered_set<exprt, irep_hash> updated_indices;
580577

581-
const exprt::operandst &operands = expr.operands();
582-
for(std::size_t i = 1; i + 1 < operands.size(); i += 2)
583-
{
584-
const exprt &index = operands[i];
585-
const exprt &value = operands[i + 1];
586-
587-
index_exprt index_expr(
588-
expr, index, to_array_type(expr.type()).element_type());
578+
index_exprt index_expr(
579+
expr, expr.where(), to_array_type(expr.type()).element_type());
589580

590-
DATA_INVARIANT_WITH_DIAGNOSTICS(
591-
index_expr.type() == value.type(),
592-
"with-expression operand should match array element type",
593-
irep_pretty_diagnosticst{expr});
581+
DATA_INVARIANT_WITH_DIAGNOSTICS(
582+
index_expr.type() == expr.new_value().type(),
583+
"with-expression operand should match array element type",
584+
irep_pretty_diagnosticst{expr});
594585

595-
lazy_constraintt lazy(
596-
lazy_typet::ARRAY_WITH, equal_exprt(index_expr, value));
597-
add_array_constraint(lazy, false); // added immediately
598-
array_constraint_count[constraint_typet::ARRAY_WITH]++;
586+
lazy_constraintt lazy(
587+
lazy_typet::ARRAY_WITH, equal_exprt(index_expr, expr.new_value()));
588+
add_array_constraint(lazy, false); // added immediately
589+
array_constraint_count[constraint_typet::ARRAY_WITH]++;
599590

600-
updated_indices.insert(index);
601-
}
591+
updated_indices.insert(expr.where());
602592

603593
// For all other indices use the existing value, i.e., add constraints
604594
// x[I]=y[I] for I!=i,j,...

src/solvers/flattening/boolbv_with.cpp

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,16 @@ Author: Daniel Kroening, [email protected]
1616

1717
bvt boolbvt::convert_with(const with_exprt &expr)
1818
{
19+
DATA_INVARIANT(
20+
expr.operands().size() == 3,
21+
"with_exprt with more than 3 operands should no longer exist");
22+
1923
auto &type = expr.type();
2024

2125
if(
2226
type.id() == ID_bv || type.id() == ID_unsignedbv ||
2327
type.id() == ID_signedbv)
2428
{
25-
if(expr.operands().size() > 3)
26-
{
27-
std::size_t s = expr.operands().size();
28-
29-
// strip off the trailing two operands
30-
with_exprt tmp = expr;
31-
tmp.operands().resize(s - 2);
32-
33-
with_exprt new_with_expr(
34-
tmp, expr.operands()[s - 2], expr.operands().back());
35-
36-
// recursive call
37-
return convert_with(new_with_expr);
38-
}
39-
40-
PRECONDITION(expr.operands().size() == 3);
4129
if(expr.new_value().type().id() == ID_bool)
4230
{
4331
return convert_bv(
@@ -50,7 +38,7 @@ bvt boolbvt::convert_with(const with_exprt &expr)
5038
}
5139
}
5240

53-
bvt bv = convert_bv(expr.old());
41+
bvt bv_old = convert_bv(expr.old());
5442

5543
std::size_t width = boolbv_width(type);
5644

@@ -61,21 +49,14 @@ bvt boolbvt::convert_with(const with_exprt &expr)
6149
}
6250

6351
DATA_INVARIANT_WITH_DIAGNOSTICS(
64-
bv.size() == width,
52+
bv_old.size() == width,
6553
"unexpected operand 0 width",
6654
irep_pretty_diagnosticst{expr});
6755

68-
bvt prev_bv;
69-
prev_bv.resize(width);
70-
71-
const exprt::operandst &ops=expr.operands();
56+
bvt bv;
57+
bv.resize(width);
7258

73-
for(std::size_t op_no=1; op_no<ops.size(); op_no+=2)
74-
{
75-
bv.swap(prev_bv);
76-
77-
convert_with(expr.old().type(), ops[op_no], ops[op_no + 1], prev_bv, bv);
78-
}
59+
convert_with(expr.old().type(), expr.where(), expr.new_value(), bv_old, bv);
7960

8061
return bv;
8162
}

src/solvers/smt2/smt2_conv.cpp

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4308,27 +4308,9 @@ void smt2_convt::convert_floatbv_rem(const binary_exprt &expr)
43084308

43094309
void smt2_convt::convert_with(const with_exprt &expr)
43104310
{
4311-
// get rid of "with" that has more than three operands
4312-
4313-
if(expr.operands().size()>3)
4314-
{
4315-
std::size_t s=expr.operands().size();
4316-
4317-
// strip off the trailing two operands
4318-
with_exprt tmp = expr;
4319-
tmp.operands().resize(s-2);
4320-
4321-
with_exprt new_with_expr(
4322-
tmp, expr.operands()[s - 2], expr.operands().back());
4323-
4324-
// recursive call
4325-
return convert_with(new_with_expr);
4326-
}
4327-
43284311
INVARIANT(
43294312
expr.operands().size() == 3,
4330-
"with expression should have been converted to a version with three "
4331-
"operands above");
4313+
"with expression should have exactly three operands");
43324314

43334315
const typet &expr_type = expr.type();
43344316

src/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,12 +1005,9 @@ static smt_termt convert_array_update_to_smt(
10051005
const sub_expression_mapt &converted)
10061006
{
10071007
smt_termt array = converted.at(with.old());
1008-
for(auto it = ++with.operands().begin(); it != with.operands().end(); it += 2)
1009-
{
1010-
const smt_termt &index_term = converted.at(it[0]);
1011-
const smt_termt &value_term = converted.at(it[1]);
1012-
array = smt_array_theoryt::store(array, index_term, value_term);
1013-
}
1008+
const smt_termt &index_term = converted.at(with.where());
1009+
const smt_termt &value_term = converted.at(with.new_value());
1010+
array = smt_array_theoryt::store(array, index_term, value_term);
10141011
return array;
10151012
}
10161013

src/solvers/smt2_incremental/encoding/struct_encoding.cpp

Lines changed: 13 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -71,52 +71,25 @@ typet struct_encodingt::encode(typet type) const
7171
return type;
7272
}
7373

74-
/// \brief Extracts the component/field names and new values from a `with_exprt`
75-
/// which expresses a new struct value where one or more members of a
76-
/// struct have had their values substituted with new values.
77-
/// \note This is implemented using direct access to the operands and other
78-
/// underlying irept interfaces, because the interface for `with_exprt`
79-
/// only supports a single `where` / `new_value` pair and does not
80-
/// support extracting the name from the `where` operand.
81-
static std::unordered_map<irep_idt, exprt>
82-
extricate_updates(const with_exprt &struct_expr)
83-
{
84-
std::unordered_map<irep_idt, exprt> pairs;
85-
auto current_operand = struct_expr.operands().begin();
86-
// Skip the struct being updated in order to begin with the pairs.
87-
current_operand++;
88-
while(current_operand != struct_expr.operands().end())
89-
{
90-
INVARIANT(
91-
current_operand->id() == ID_member_name,
92-
"operand is expected to be the name of a member");
93-
auto name = current_operand->find(ID_component_name).id();
94-
++current_operand;
95-
INVARIANT(
96-
current_operand != struct_expr.operands().end(),
97-
"every name is expected to be followed by a paired value");
98-
pairs[name] = *current_operand;
99-
++current_operand;
100-
}
101-
POSTCONDITION(!pairs.empty());
102-
return pairs;
103-
}
104-
10574
static exprt encode(const with_exprt &with, const namespacet &ns)
10675
{
10776
const auto tag_type = type_checked_cast<struct_tag_typet>(with.type());
10877
const auto struct_type = ns.follow_tag(tag_type);
109-
const auto updates = extricate_updates(with);
78+
INVARIANT(
79+
with.where().id() == ID_member_name,
80+
"operand is expected to be the name of a member");
81+
const auto update_name = with.where().find(ID_component_name).id();
11082
const auto components =
11183
make_range(struct_type.components())
112-
.map([&](const struct_union_typet::componentt &component) -> exprt {
113-
const auto &update = updates.find(component.get_name());
114-
if(update != updates.end())
115-
return update->second;
116-
else
117-
return member_exprt{
118-
with.old(), component.get_name(), component.type()};
119-
})
84+
.map(
85+
[&](const struct_union_typet::componentt &component) -> exprt
86+
{
87+
if(component.get_name() == update_name)
88+
return with.new_value();
89+
else
90+
return member_exprt{
91+
with.old(), component.get_name(), component.type()};
92+
})
12093
.collect<exprt::operandst>();
12194
return struct_exprt{components, tag_type};
12295
}

src/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -334,16 +334,14 @@ void smt2_incremental_decision_proceduret::ensure_handle_for_expr_defined(
334334
void smt2_incremental_decision_proceduret::define_index_identifiers(
335335
const exprt &expr)
336336
{
337-
expr.visit_pre([&](const exprt &expr_node) {
338-
if(!can_cast_type<array_typet>(expr_node.type()))
339-
return;
340-
if(const auto with_expr = expr_try_dynamic_cast<with_exprt>(expr_node))
337+
expr.visit_post(
338+
[&](const exprt &expr_node)
341339
{
342-
for(auto operand_ite = ++with_expr->operands().begin();
343-
operand_ite != with_expr->operands().end();
344-
operand_ite += 2)
340+
if(!can_cast_type<array_typet>(expr_node.type()))
341+
return;
342+
if(const auto with_expr = expr_try_dynamic_cast<with_exprt>(expr_node))
345343
{
346-
const auto index_expr = *operand_ite;
344+
const auto index_expr = with_expr->where();
347345
const auto index_term = convert_expr_to_smt(index_expr);
348346
const auto index_identifier =
349347
"index_" + std::to_string(index_sequence());
@@ -356,8 +354,7 @@ void smt2_incremental_decision_proceduret::define_index_identifiers(
356354
solver_process->send(
357355
smt_define_function_commandt{index_identifier, {}, index_term});
358356
}
359-
}
360-
});
357+
});
361358
}
362359

363360
exprt smt2_incremental_decision_proceduret::substitute_defined_padding(

src/util/lower_byte_operators.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,10 +1607,7 @@ static exprt lower_byte_update_byte_array_vector(
16071607
index_exprt{src.op(), where}};
16081608
}
16091609

1610-
if(result.id() != ID_with)
1611-
result = with_exprt{result, std::move(where), std::move(update_value)};
1612-
else
1613-
result.add_to_operands(std::move(where), std::move(update_value));
1610+
result = with_exprt{result, std::move(where), std::move(update_value)};
16141611
}
16151612

16161613
return simplify_expr(std::move(result), ns);
@@ -1892,7 +1889,7 @@ static exprt lower_byte_update_array_vector_non_const(
18921889
src.get_bits_per_byte()},
18931890
ns);
18941891

1895-
result.add_to_operands(std::move(where), std::move(element));
1892+
result = with_exprt{result, std::move(where), std::move(element)};
18961893
};
18971894

18981895
std::size_t i = 1;

0 commit comments

Comments
 (0)