Skip to content

Commit 833a714

Browse files
committed
Field-sensitive level-2 SSA renaming
1 parent 5d654d7 commit 833a714

File tree

16 files changed

+585
-21
lines changed

16 files changed

+585
-21
lines changed

regression/cbmc-concurrency/struct_and_array1/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33

44
^EXIT=0$
+21
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+
}
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
+34
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+
}
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

+1-1
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

+1
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

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

0 commit comments

Comments
 (0)