Skip to content

Commit ad814f9

Browse files
committed
Field-sensitive level-2 SSA renaming
1 parent bcce848 commit ad814f9

File tree

15 files changed

+549
-21
lines changed

15 files changed

+549
-21
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: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
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+
ssa_exprt tmp = to_ssa_expr(member.struct_op());
54+
55+
member.struct_op() = tmp.get_original_expr();
56+
57+
tmp.type() = member.type();
58+
tmp.set(ID_expression, member);
59+
tmp.update_identifier();
60+
61+
expr.swap(tmp);
62+
}
63+
}
64+
else if(write && expr.id() == ID_index)
65+
{
66+
index_exprt &index = to_index_expr(expr);
67+
simplify(index.index(), ns);
68+
69+
if(
70+
index.array().id() == ID_symbol &&
71+
index.array().get_bool(ID_C_SSA_symbol) &&
72+
ns.follow(index.array().type()).id() == ID_array &&
73+
index.index().id() == ID_constant &&
74+
to_array_type(ns.follow(index.array().type())).size().id() ==
75+
ID_constant &&
76+
!to_array_type(ns.follow(index.array().type())).size().is_zero())
77+
{
78+
ssa_exprt tmp = to_ssa_expr(index.array());
79+
80+
index.array() = tmp.get_original_expr();
81+
82+
tmp.type() = index.type();
83+
tmp.set(ID_expression, index);
84+
tmp.update_identifier();
85+
86+
expr.swap(tmp);
87+
}
88+
}
89+
#endif
90+
}
91+
92+
exprt field_sensitivityt::get_fields(
93+
const namespacet &ns,
94+
const ssa_exprt &ssa_expr)
95+
{
96+
#ifdef ENABLE_FIELD_SENSITIVITY
97+
const typet &followed_type = ns.follow(ssa_expr.type());
98+
99+
if(followed_type.id() == ID_struct)
100+
{
101+
const exprt &struct_op = ssa_expr.get_original_expr();
102+
103+
const struct_typet &type = to_struct_type(followed_type);
104+
105+
const struct_union_typet::componentst &components = type.components();
106+
107+
struct_exprt result(ssa_expr.type());
108+
result.reserve_operands(components.size());
109+
110+
for(const auto &comp : components)
111+
{
112+
member_exprt member(struct_op, comp.get_name(), comp.type());
113+
114+
ssa_exprt tmp = ssa_expr;
115+
116+
tmp.type() = member.type();
117+
tmp.set(ID_expression, member);
118+
tmp.update_identifier();
119+
120+
result.copy_to_operands(get_fields(ns, tmp));
121+
}
122+
123+
return result;
124+
}
125+
else if(
126+
followed_type.id() == ID_array &&
127+
to_array_type(followed_type).size().id() == ID_constant &&
128+
!to_array_type(followed_type).size().is_zero())
129+
{
130+
const exprt &array = ssa_expr.get_original_expr();
131+
132+
const array_typet &type = to_array_type(followed_type);
133+
134+
const std::size_t array_size = numeric_cast_v<std::size_t>(type.size());
135+
136+
array_exprt result(type);
137+
result.reserve_operands(array_size);
138+
index_exprt index;
139+
index.array() = array;
140+
index.type() = type.subtype();
141+
142+
for(std::size_t i = 0; i < array_size; ++i)
143+
{
144+
index.index() = from_integer(i, index_type());
145+
146+
ssa_exprt tmp = ssa_expr;
147+
148+
tmp.type() = index.type();
149+
tmp.set(ID_expression, index);
150+
tmp.update_identifier();
151+
152+
result.copy_to_operands(get_fields(ns, tmp));
153+
}
154+
155+
return result;
156+
}
157+
else
158+
#endif
159+
return ssa_expr;
160+
}
161+
162+
void field_sensitivityt::field_assignments(
163+
const namespacet &ns,
164+
goto_symex_statet &state,
165+
symex_targett &target,
166+
const exprt &lhs)
167+
{
168+
exprt lhs_fs = lhs;
169+
apply(ns, lhs_fs, false);
170+
171+
field_assignments_rec(ns, state, target, lhs_fs, lhs);
172+
}
173+
174+
void field_sensitivityt::field_assignments_rec(
175+
const namespacet &ns,
176+
goto_symex_statet &state,
177+
symex_targett &target,
178+
const exprt &lhs_fs,
179+
const exprt &lhs)
180+
{
181+
const typet &followed_type = ns.follow(lhs.type());
182+
183+
if(lhs == lhs_fs)
184+
return;
185+
else if(lhs_fs.id() == ID_symbol && lhs_fs.get_bool(ID_C_SSA_symbol))
186+
{
187+
exprt ssa_rhs = lhs;
188+
189+
state.rename(ssa_rhs, ns);
190+
simplify(ssa_rhs, ns);
191+
192+
ssa_exprt ssa_lhs = to_ssa_expr(lhs_fs);
193+
state.assignment(ssa_lhs, ssa_rhs, ns, true, true);
194+
195+
// do the assignment
196+
target.assignment(
197+
state.guard.as_expr(),
198+
ssa_lhs,
199+
ssa_lhs,
200+
ssa_lhs.get_original_expr(),
201+
ssa_rhs,
202+
state.source,
203+
symex_targett::assignment_typet::STATE);
204+
}
205+
else if(followed_type.id() == ID_struct)
206+
{
207+
const struct_typet &type = to_struct_type(followed_type);
208+
209+
const struct_union_typet::componentst &components = type.components();
210+
211+
PRECONDITION(
212+
components.empty() ||
213+
(lhs_fs.has_operands() && lhs_fs.operands().size() == components.size()));
214+
215+
std::size_t number = 0;
216+
for(const auto &comp : components)
217+
{
218+
member_exprt member_rhs(lhs, comp.get_name(), comp.type());
219+
const exprt &member_lhs = lhs_fs.operands()[number];
220+
221+
field_assignments_rec(ns, state, target, member_lhs, member_rhs);
222+
++number;
223+
}
224+
}
225+
else if(followed_type.id() == ID_array)
226+
{
227+
const array_typet &type = to_array_type(followed_type);
228+
229+
const std::size_t array_size = numeric_cast_v<std::size_t>(type.size());
230+
PRECONDITION(
231+
lhs_fs.has_operands() && lhs_fs.operands().size() == array_size);
232+
233+
index_exprt index_rhs;
234+
index_rhs.array() = lhs;
235+
index_rhs.type() = type.subtype();
236+
237+
for(std::size_t i = 0; i < array_size; ++i)
238+
{
239+
index_rhs.index() = from_integer(i, index_type());
240+
const exprt &index_lhs = lhs_fs.operands()[i];
241+
242+
field_assignments_rec(ns, state, target, index_lhs, index_rhs);
243+
}
244+
}
245+
else if(lhs_fs.has_operands())
246+
{
247+
PRECONDITION(
248+
lhs.has_operands() && lhs_fs.operands().size() == lhs.operands().size());
249+
250+
exprt::operandst::const_iterator fs_it = lhs_fs.operands().begin();
251+
for(const exprt &op : lhs.operands())
252+
{
253+
field_assignments_rec(ns, state, target, *fs_it, op);
254+
++fs_it;
255+
}
256+
}
257+
else
258+
{
259+
UNREACHABLE;
260+
}
261+
}
262+
263+
bool field_sensitivityt::is_indivisible(
264+
const namespacet &ns,
265+
const ssa_exprt &expr)
266+
{
267+
return expr == get_fields(ns, expr);
268+
}

0 commit comments

Comments
 (0)