Skip to content

Commit d5b7a9b

Browse files
committed
Field-sensitive level-2 SSA renaming
1 parent 75bec44 commit d5b7a9b

File tree

16 files changed

+580
-20
lines changed

16 files changed

+580
-20
lines changed

regression/cbmc-concurrency/struct_and_array1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33

44
^EXIT=0$
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include <assert.h>
2+
3+
struct S
4+
{
5+
int a;
6+
};
7+
8+
int main()
9+
{
10+
struct S s;
11+
s.a = 1;
12+
13+
assert(s.a == 1);
14+
15+
int A[1];
16+
A[0] = 1;
17+
18+
assert(A[0] == 1);
19+
20+
return 0;
21+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
\(Starting CEGAR Loop\|VCC(s), 0 remaining after simplification$\)
8+
--
9+
^warning: ignoring
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
struct S
2+
{
3+
int v;
4+
struct Inner
5+
{
6+
int x;
7+
} inner;
8+
};
9+
10+
struct S works;
11+
12+
int main()
13+
{
14+
struct S fails;
15+
16+
works.v = 2;
17+
fails.v = 2;
18+
19+
while(works.v > 0)
20+
--(works.v);
21+
22+
while(fails.v > 0)
23+
--(fails.v);
24+
25+
__CPROVER_assert(works.inner.x == 0, "");
26+
27+
_Bool b;
28+
if(b)
29+
{
30+
struct S s = {42, {42}};
31+
}
32+
33+
return 0;
34+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
--unwind 5
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
\(Starting CEGAR Loop\|VCC(s), 0 remaining after simplification$\)
8+
--
9+
^warning: ignoring

regression/cbmc/variable-access-to-constant-array/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
THOROUGH
22
main.c
33

44
^EXIT=10$

src/goto-symex/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
SRC = auto_objects.cpp \
22
build_goto_trace.cpp \
3+
field_sensitivity.cpp \
34
goto_symex.cpp \
45
goto_symex_state.cpp \
56
memory_model.cpp \

src/goto-symex/field_sensitivity.cpp

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
/*******************************************************************\
2+
3+
Module: Field-sensitive SSA
4+
5+
Author: Michael Tautschnig
6+
7+
\*******************************************************************/
8+
9+
#include "field_sensitivity.h"
10+
11+
#include <util/arith_tools.h>
12+
#include <util/c_types.h>
13+
#include <util/simplify_expr.h>
14+
#include <util/std_expr.h>
15+
16+
#include "goto_symex_state.h"
17+
#include "symex_target.h"
18+
19+
#define ENABLE_FIELD_SENSITIVITY
20+
21+
void field_sensitivityt::apply(const namespacet &ns, exprt &expr, bool write)
22+
{
23+
#ifdef ENABLE_FIELD_SENSITIVITY
24+
if(expr.id() != ID_address_of)
25+
Forall_operands(it, expr)
26+
apply(ns, *it, write);
27+
28+
if(expr.id() == ID_symbol && expr.get_bool(ID_C_SSA_symbol) && !write)
29+
{
30+
expr = get_fields(ns, to_ssa_expr(expr));
31+
}
32+
else if(
33+
!write && expr.id() == ID_member &&
34+
to_member_expr(expr).struct_op().id() == ID_struct)
35+
{
36+
simplify(expr, ns);
37+
}
38+
else if(
39+
!write && expr.id() == ID_index &&
40+
to_index_expr(expr).array().id() == ID_array)
41+
{
42+
simplify(expr, ns);
43+
}
44+
else if(write && expr.id() == ID_member)
45+
{
46+
member_exprt &member = to_member_expr(expr);
47+
48+
if(
49+
member.struct_op().id() == ID_symbol &&
50+
member.struct_op().get_bool(ID_C_SSA_symbol) &&
51+
ns.follow(member.struct_op().type()).id() == ID_struct)
52+
{
53+
// place the entire member expression, not just the struct operand, in an
54+
// SSA expression
55+
ssa_exprt tmp = to_ssa_expr(member.struct_op());
56+
member.struct_op() = tmp.get_original_expr();
57+
tmp.set_expression(member);
58+
59+
expr.swap(tmp);
60+
}
61+
}
62+
else if(write && expr.id() == ID_index)
63+
{
64+
index_exprt &index = to_index_expr(expr);
65+
simplify(index.index(), ns);
66+
67+
if(
68+
index.array().id() == ID_symbol &&
69+
index.array().get_bool(ID_C_SSA_symbol) &&
70+
ns.follow(index.array().type()).id() == ID_array &&
71+
index.index().id() == ID_constant)
72+
{
73+
// place the entire index expression, not just the array operand, in an
74+
// SSA expression
75+
ssa_exprt tmp = to_ssa_expr(index.array());
76+
index.array() = tmp.get_original_expr();
77+
tmp.set_expression(index);
78+
79+
expr.swap(tmp);
80+
}
81+
}
82+
#endif
83+
}
84+
85+
exprt field_sensitivityt::get_fields(
86+
const namespacet &ns,
87+
const ssa_exprt &ssa_expr)
88+
{
89+
#ifdef ENABLE_FIELD_SENSITIVITY
90+
const typet &followed_type = ns.follow(ssa_expr.type());
91+
92+
if(followed_type.id() == ID_struct)
93+
{
94+
const exprt &struct_op = ssa_expr.get_original_expr();
95+
96+
const struct_typet &type = to_struct_type(followed_type);
97+
98+
const struct_union_typet::componentst &components = type.components();
99+
100+
struct_exprt result(ssa_expr.type());
101+
result.reserve_operands(components.size());
102+
103+
for(const auto &comp : components)
104+
{
105+
const member_exprt member(struct_op, comp.get_name(), comp.type());
106+
ssa_exprt tmp = ssa_expr;
107+
tmp.set_expression(member);
108+
result.copy_to_operands(get_fields(ns, tmp));
109+
}
110+
111+
return result;
112+
}
113+
else if(
114+
followed_type.id() == ID_array &&
115+
to_array_type(followed_type).size().id() == ID_constant)
116+
{
117+
const exprt &array = ssa_expr.get_original_expr();
118+
119+
const array_typet &type = to_array_type(followed_type);
120+
121+
const std::size_t array_size = numeric_cast_v<std::size_t>(type.size());
122+
123+
array_exprt result(type);
124+
result.reserve_operands(array_size);
125+
126+
for(std::size_t i = 0; i < array_size; ++i)
127+
{
128+
const index_exprt index(array, from_integer(i, index_type()));
129+
ssa_exprt tmp = ssa_expr;
130+
tmp.set_expression(index);
131+
result.copy_to_operands(get_fields(ns, tmp));
132+
}
133+
134+
return result;
135+
}
136+
else
137+
#endif
138+
return ssa_expr;
139+
}
140+
141+
void field_sensitivityt::field_assignments(
142+
const namespacet &ns,
143+
goto_symex_statet &state,
144+
symex_targett &target,
145+
const exprt &lhs)
146+
{
147+
exprt lhs_fs = lhs;
148+
apply(ns, lhs_fs, false);
149+
150+
field_assignments_rec(ns, state, target, lhs_fs, lhs);
151+
}
152+
153+
void field_sensitivityt::field_assignments_rec(
154+
const namespacet &ns,
155+
goto_symex_statet &state,
156+
symex_targett &target,
157+
const exprt &lhs_fs,
158+
const exprt &lhs)
159+
{
160+
const typet &followed_type = ns.follow(lhs.type());
161+
162+
if(lhs == lhs_fs)
163+
return;
164+
else if(lhs_fs.id() == ID_symbol && lhs_fs.get_bool(ID_C_SSA_symbol))
165+
{
166+
exprt ssa_rhs = lhs;
167+
168+
state.rename(ssa_rhs, ns);
169+
simplify(ssa_rhs, ns);
170+
171+
ssa_exprt ssa_lhs = to_ssa_expr(lhs_fs);
172+
state.assignment(ssa_lhs, ssa_rhs, ns, true, true);
173+
174+
// do the assignment
175+
target.assignment(
176+
state.guard.as_expr(),
177+
ssa_lhs,
178+
ssa_lhs,
179+
ssa_lhs.get_original_expr(),
180+
ssa_rhs,
181+
state.source,
182+
symex_targett::assignment_typet::STATE);
183+
}
184+
else if(followed_type.id() == ID_struct)
185+
{
186+
const struct_typet &type = to_struct_type(followed_type);
187+
188+
const struct_union_typet::componentst &components = type.components();
189+
190+
PRECONDITION(
191+
components.empty() ||
192+
(lhs_fs.has_operands() && lhs_fs.operands().size() == components.size()));
193+
194+
std::size_t number = 0;
195+
for(const auto &comp : components)
196+
{
197+
const member_exprt member_rhs(lhs, comp.get_name(), comp.type());
198+
const exprt &member_lhs = lhs_fs.operands()[number];
199+
200+
field_assignments_rec(ns, state, target, member_lhs, member_rhs);
201+
++number;
202+
}
203+
}
204+
else if(followed_type.id() == ID_array)
205+
{
206+
const array_typet &type = to_array_type(followed_type);
207+
208+
const std::size_t array_size = numeric_cast_v<std::size_t>(type.size());
209+
PRECONDITION(
210+
lhs_fs.has_operands() && lhs_fs.operands().size() == array_size);
211+
212+
for(std::size_t i = 0; i < array_size; ++i)
213+
{
214+
const index_exprt index_rhs(lhs, from_integer(i, index_type()));
215+
const exprt &index_lhs = lhs_fs.operands()[i];
216+
217+
field_assignments_rec(ns, state, target, index_lhs, index_rhs);
218+
}
219+
}
220+
else if(lhs_fs.has_operands())
221+
{
222+
PRECONDITION(
223+
lhs.has_operands() && lhs_fs.operands().size() == lhs.operands().size());
224+
225+
exprt::operandst::const_iterator fs_it = lhs_fs.operands().begin();
226+
for(const exprt &op : lhs.operands())
227+
{
228+
field_assignments_rec(ns, state, target, *fs_it, op);
229+
++fs_it;
230+
}
231+
}
232+
else
233+
{
234+
UNREACHABLE;
235+
}
236+
}
237+
238+
bool field_sensitivityt::is_indivisible(
239+
const namespacet &ns,
240+
const ssa_exprt &expr)
241+
{
242+
return expr == get_fields(ns, expr);
243+
}

0 commit comments

Comments
 (0)