Skip to content

Commit 1aefd22

Browse files
author
Daniel Kroening
authored
Merge pull request #4917 from smowton/smowton/cleanup/rename-lhs-rvalues-up-front-on-develop
Rename LHS rvalues up front
2 parents 103b2dc + c4bc800 commit 1aefd22

File tree

9 files changed

+242
-397
lines changed

9 files changed

+242
-397
lines changed

src/goto-symex/expr_skeleton.cpp

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -52,51 +52,3 @@ expr_skeletont expr_skeletont::compose(expr_skeletont other) const
5252
{
5353
return expr_skeletont(apply(other.skeleton));
5454
}
55-
56-
/// In the expression corresponding to a skeleton returns a pointer to the
57-
/// deepest subexpression before we encounter nil.
58-
static exprt *deepest_not_nil(exprt &e)
59-
{
60-
exprt *ptr = &e;
61-
while(!ptr->op0().is_nil())
62-
ptr = &ptr->op0();
63-
return ptr;
64-
}
65-
66-
optionalt<expr_skeletont>
67-
expr_skeletont::clear_innermost_index_expr(expr_skeletont skeleton)
68-
{
69-
exprt *to_update = deepest_not_nil(skeleton.skeleton);
70-
if(index_exprt *index_expr = expr_try_dynamic_cast<index_exprt>(*to_update))
71-
{
72-
index_expr->make_nil();
73-
return expr_skeletont{std::move(skeleton)};
74-
}
75-
return {};
76-
}
77-
78-
optionalt<expr_skeletont>
79-
expr_skeletont::clear_innermost_member_expr(expr_skeletont skeleton)
80-
{
81-
exprt *to_update = deepest_not_nil(skeleton.skeleton);
82-
if(member_exprt *member = expr_try_dynamic_cast<member_exprt>(*to_update))
83-
{
84-
member->make_nil();
85-
return expr_skeletont{std::move(skeleton)};
86-
}
87-
return {};
88-
}
89-
90-
optionalt<expr_skeletont>
91-
expr_skeletont::clear_innermost_byte_extract_expr(expr_skeletont skeleton)
92-
{
93-
exprt *to_update = deepest_not_nil(skeleton.skeleton);
94-
if(
95-
to_update->id() != ID_byte_extract_big_endian &&
96-
to_update->id() != ID_byte_extract_little_endian)
97-
{
98-
return {};
99-
}
100-
to_update->make_nil();
101-
return expr_skeletont{std::move(skeleton.skeleton)};
102-
}

src/goto-symex/expr_skeleton.h

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -43,24 +43,6 @@ class expr_skeletont final
4343
/// `array2[index]`.
4444
static expr_skeletont remove_op0(exprt e);
4545

46-
/// If the deepest subexpression in the skeleton is a member expression,
47-
/// replace it with a nil expression and return the obtained skeleton.
48-
static optionalt<expr_skeletont>
49-
clear_innermost_index_expr(expr_skeletont skeleton);
50-
51-
/// If the deepest subexpression in the skeleton is a member expression,
52-
/// replace it with a nil expression and return the obtained skeleton.
53-
static optionalt<expr_skeletont>
54-
clear_innermost_member_expr(expr_skeletont skeleton);
55-
56-
/// If the deepest subexpression in the skeleton is a byte-extract expression,
57-
/// replace it with a nil expression and return the obtained skeleton.
58-
/// For instance, for `(byte_extract(☐, 2, int)).field[index]`
59-
/// `☐.field[index]` is returned, while for `byte_extract(☐.field, 2, int)`
60-
/// an empty optional is returned.
61-
static optionalt<expr_skeletont>
62-
clear_innermost_byte_extract_expr(expr_skeletont skeleton);
63-
6446
private:
6547
/// In \c skeleton, nil_exprt is used to mark the sub expression to be
6648
/// substituted. The nil_exprt always appears recursively following the first

src/goto-symex/goto_symex.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ void goto_symext::symex_assign(statet &state, const code_assignt &code)
4141
<< messaget::eom;
4242
});
4343

44+
// rvalues present within the lhs (for example, "some_array[this_rvalue]" or
45+
// "byte_extract <type> from an_lvalue offset this_rvalue") can affect whether
46+
// we use field-sensitive symbols or not, so L2-rename them up front:
47+
lhs = state.l2_rename_rvalues(lhs, ns);
48+
do_simplify(lhs);
49+
lhs = state.field_sensitivity.apply(ns, state, std::move(lhs), true);
50+
4451
if(rhs.id() == ID_side_effect)
4552
{
4653
const side_effect_exprt &side_effect_expr = to_side_effect_expr(rhs);

src/goto-symex/goto_symex_state.cpp

Lines changed: 68 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Author: Daniel Kroening, [email protected]
1717

1818
#include <util/as_const.h>
1919
#include <util/base_exceptions.h>
20+
#include <util/byte_operators.h>
2021
#include <util/exception_utils.h>
2122
#include <util/expr_util.h>
2223
#include <util/format.h>
@@ -48,90 +49,6 @@ goto_symex_statet::goto_symex_statet(
4849

4950
goto_symex_statet::~goto_symex_statet()=default;
5051

51-
/// Check that \p expr is correctly renamed to level 2 and return true in case
52-
/// an error is detected.
53-
static bool check_renaming(const exprt &expr);
54-
55-
static bool check_renaming(const typet &type)
56-
{
57-
if(type.id()==ID_array)
58-
return check_renaming(to_array_type(type).size());
59-
else if(type.id() == ID_struct || type.id() == ID_union)
60-
{
61-
for(const auto &c : to_struct_union_type(type).components())
62-
if(check_renaming(c.type()))
63-
return true;
64-
}
65-
else if(type.has_subtype())
66-
return check_renaming(to_type_with_subtype(type).subtype());
67-
68-
return false;
69-
}
70-
71-
static bool check_renaming_l1(const exprt &expr)
72-
{
73-
if(check_renaming(expr.type()))
74-
return true;
75-
76-
if(expr.id()==ID_symbol)
77-
{
78-
const auto &type = expr.type();
79-
if(!expr.get_bool(ID_C_SSA_symbol))
80-
return type.id() != ID_code && type.id() != ID_mathematical_function;
81-
if(!to_ssa_expr(expr).get_level_2().empty())
82-
return true;
83-
if(to_ssa_expr(expr).get_original_expr().type() != type)
84-
return true;
85-
}
86-
else
87-
{
88-
forall_operands(it, expr)
89-
if(check_renaming_l1(*it))
90-
return true;
91-
}
92-
93-
return false;
94-
}
95-
96-
static bool check_renaming(const exprt &expr)
97-
{
98-
if(check_renaming(expr.type()))
99-
return true;
100-
101-
if(
102-
expr.id() == ID_address_of &&
103-
to_address_of_expr(expr).object().id() == ID_symbol)
104-
{
105-
return check_renaming_l1(to_address_of_expr(expr).object());
106-
}
107-
else if(
108-
expr.id() == ID_address_of &&
109-
to_address_of_expr(expr).object().id() == ID_index)
110-
{
111-
const auto index_expr = to_index_expr(to_address_of_expr(expr).object());
112-
return check_renaming_l1(index_expr.array()) ||
113-
check_renaming(index_expr.index());
114-
}
115-
else if(expr.id()==ID_symbol)
116-
{
117-
const auto &type = expr.type();
118-
if(!expr.get_bool(ID_C_SSA_symbol))
119-
return type.id() != ID_code && type.id() != ID_mathematical_function;
120-
if(to_ssa_expr(expr).get_level_2().empty())
121-
return true;
122-
if(to_ssa_expr(expr).get_original_expr().type() != type)
123-
return true;
124-
}
125-
else
126-
{
127-
forall_operands(it, expr)
128-
if(check_renaming(*it))
129-
return true;
130-
}
131-
132-
return false;
133-
}
134-
13552
template <>
13653
renamedt<ssa_exprt, L0>
13754
goto_symex_statet::set_indices<L0>(ssa_exprt ssa_expr, const namespacet &ns)
@@ -344,6 +261,73 @@ goto_symex_statet::rename(exprt expr, const namespacet &ns)
344261
}
345262
}
346263

264+
exprt goto_symex_statet::l2_rename_rvalues(exprt lvalue, const namespacet &ns)
265+
{
266+
rename(lvalue.type(), irep_idt(), ns);
267+
268+
if(lvalue.id() == ID_symbol)
269+
{
270+
// Nothing to do
271+
}
272+
else if(is_read_only_object(lvalue))
273+
{
274+
// Ignore apparent writes to 'NULL-object' and similar read-only objects
275+
}
276+
else if(lvalue.id() == ID_typecast)
277+
{
278+
auto &typecast_lvalue = to_typecast_expr(lvalue);
279+
typecast_lvalue.op() = l2_rename_rvalues(typecast_lvalue.op(), ns);
280+
}
281+
else if(lvalue.id() == ID_member)
282+
{
283+
auto &member_lvalue = to_member_expr(lvalue);
284+
member_lvalue.compound() = l2_rename_rvalues(member_lvalue.compound(), ns);
285+
}
286+
else if(lvalue.id() == ID_index)
287+
{
288+
// The index is an rvalue:
289+
auto &index_lvalue = to_index_expr(lvalue);
290+
index_lvalue.array() = l2_rename_rvalues(index_lvalue.array(), ns);
291+
index_lvalue.index() = rename(index_lvalue.index(), ns).get();
292+
}
293+
else if(
294+
lvalue.id() == ID_byte_extract_little_endian ||
295+
lvalue.id() == ID_byte_extract_big_endian)
296+
{
297+
// The offset is an rvalue:
298+
auto &byte_extract_lvalue = to_byte_extract_expr(lvalue);
299+
byte_extract_lvalue.op() = l2_rename_rvalues(byte_extract_lvalue.op(), ns);
300+
byte_extract_lvalue.offset() = rename(byte_extract_lvalue.offset(), ns);
301+
}
302+
else if(lvalue.id() == ID_if)
303+
{
304+
// The condition is an rvalue:
305+
auto &if_lvalue = to_if_expr(lvalue);
306+
if_lvalue.cond() = rename(if_lvalue.cond(), ns);
307+
if(!if_lvalue.cond().is_false())
308+
if_lvalue.true_case() = l2_rename_rvalues(if_lvalue.true_case(), ns);
309+
if(!if_lvalue.cond().is_true())
310+
if_lvalue.false_case() = l2_rename_rvalues(if_lvalue.false_case(), ns);
311+
}
312+
else if(lvalue.id() == ID_complex_real)
313+
{
314+
auto &complex_real_lvalue = to_complex_real_expr(lvalue);
315+
complex_real_lvalue.op() = l2_rename_rvalues(complex_real_lvalue.op(), ns);
316+
}
317+
else if(lvalue.id() == ID_complex_imag)
318+
{
319+
auto &complex_imag_lvalue = to_complex_imag_expr(lvalue);
320+
complex_imag_lvalue.op() = l2_rename_rvalues(complex_imag_lvalue.op(), ns);
321+
}
322+
else
323+
{
324+
throw unsupported_operation_exceptiont(
325+
"l2_rename_rvalues case `" + lvalue.id_string() + "' not handled");
326+
}
327+
328+
return lvalue;
329+
}
330+
347331
template renamedt<exprt, L1>
348332
goto_symex_statet::rename<L1>(exprt expr, const namespacet &ns);
349333

src/goto-symex/goto_symex_state.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ class goto_symex_statet final : public goto_statet
107107
template <levelt level = L2>
108108
void rename(typet &type, const irep_idt &l1_identifier, const namespacet &ns);
109109

110+
exprt l2_rename_rvalues(exprt lvalue, const namespacet &ns);
111+
110112
/// \return lhs renamed to level 2
111113
renamedt<ssa_exprt, L2> assignment(
112114
ssa_exprt lhs, // L0/L1
@@ -239,6 +241,14 @@ class goto_symex_statet final : public goto_statet
239241
return fresh_l2_name_provider;
240242
}
241243

244+
/// Returns true if \p lvalue is a read-only object, such as the null object
245+
static bool is_read_only_object(const exprt &lvalue)
246+
{
247+
return lvalue.id() == ID_string_constant || lvalue.id() == ID_null_object ||
248+
lvalue.id() == "zero_string" || lvalue.id() == "is_zero_string" ||
249+
lvalue.id() == "zero_string_length";
250+
}
251+
242252
private:
243253
std::function<std::size_t(const irep_idt &)> fresh_l2_name_provider;
244254

src/goto-symex/renaming_level.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,83 @@ typet get_original_name(typet type)
205205
}
206206
return type;
207207
}
208+
209+
bool check_renaming(const typet &type)
210+
{
211+
if(type.id() == ID_array)
212+
return check_renaming(to_array_type(type).size());
213+
else if(type.id() == ID_struct || type.id() == ID_union)
214+
{
215+
for(const auto &c : to_struct_union_type(type).components())
216+
if(check_renaming(c.type()))
217+
return true;
218+
}
219+
else if(type.has_subtype())
220+
return check_renaming(to_type_with_subtype(type).subtype());
221+
222+
return false;
223+
}
224+
225+
bool check_renaming_l1(const exprt &expr)
226+
{
227+
if(check_renaming(expr.type()))
228+
return true;
229+
230+
if(expr.id() == ID_symbol)
231+
{
232+
const auto &type = expr.type();
233+
if(!expr.get_bool(ID_C_SSA_symbol))
234+
return type.id() != ID_code && type.id() != ID_mathematical_function;
235+
if(!to_ssa_expr(expr).get_level_2().empty())
236+
return true;
237+
if(to_ssa_expr(expr).get_original_expr().type() != type)
238+
return true;
239+
}
240+
else
241+
{
242+
forall_operands(it, expr)
243+
if(check_renaming_l1(*it))
244+
return true;
245+
}
246+
247+
return false;
248+
}
249+
250+
bool check_renaming(const exprt &expr)
251+
{
252+
if(check_renaming(expr.type()))
253+
return true;
254+
255+
if(
256+
expr.id() == ID_address_of &&
257+
to_address_of_expr(expr).object().id() == ID_symbol)
258+
{
259+
return check_renaming_l1(to_address_of_expr(expr).object());
260+
}
261+
else if(
262+
expr.id() == ID_address_of &&
263+
to_address_of_expr(expr).object().id() == ID_index)
264+
{
265+
const auto index_expr = to_index_expr(to_address_of_expr(expr).object());
266+
return check_renaming_l1(index_expr.array()) ||
267+
check_renaming(index_expr.index());
268+
}
269+
else if(expr.id() == ID_symbol)
270+
{
271+
const auto &type = expr.type();
272+
if(!expr.get_bool(ID_C_SSA_symbol))
273+
return type.id() != ID_code && type.id() != ID_mathematical_function;
274+
if(to_ssa_expr(expr).get_level_2().empty())
275+
return true;
276+
if(to_ssa_expr(expr).get_original_expr().type() != type)
277+
return true;
278+
}
279+
else
280+
{
281+
forall_operands(it, expr)
282+
if(check_renaming(*it))
283+
return true;
284+
}
285+
286+
return false;
287+
}

src/goto-symex/renaming_level.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,16 @@ exprt get_original_name(exprt expr);
103103
/// Undo all levels of renaming
104104
typet get_original_name(typet type);
105105

106+
/// Check that \p expr is correctly renamed to level 2 and return true in case
107+
/// an error is detected.
108+
bool check_renaming(const exprt &expr);
109+
110+
/// Check that \p expr is correctly renamed to level 1 and return true in case
111+
/// an error is detected.
112+
bool check_renaming_l1(const exprt &expr);
113+
114+
/// Check that \p type is correctly renamed to level 2 and return true in case
115+
/// an error is detected.
116+
bool check_renaming(const typet &type);
117+
106118
#endif // CPROVER_GOTO_SYMEX_RENAMING_LEVEL_H

0 commit comments

Comments
 (0)