@@ -9,8 +9,9 @@ Author: Michael Tautschnig
9
9
#include " field_sensitivity.h"
10
10
11
11
#include < util/arith_tools.h>
12
+ #include < util/byte_operators.h>
13
+ #include < util/c_types.h>
12
14
#include < util/simplify_expr.h>
13
- #include < util/std_expr.h>
14
15
15
16
#include " goto_symex_state.h"
16
17
#include " symex_target.h"
@@ -26,7 +27,7 @@ exprt field_sensitivityt::apply(
26
27
if (!run_apply || write )
27
28
return std::move (ssa_expr);
28
29
else
29
- return get_fields (ns, state, ssa_expr);
30
+ return get_fields (ns, state, ssa_expr, true );
30
31
}
31
32
32
33
exprt field_sensitivityt::apply (
@@ -72,7 +73,9 @@ exprt field_sensitivityt::apply(
72
73
if (
73
74
is_ssa_expr (member.struct_op ()) &&
74
75
(member.struct_op ().type ().id () == ID_struct ||
75
- member.struct_op ().type ().id () == ID_struct_tag))
76
+ member.struct_op ().type ().id () == ID_struct_tag ||
77
+ member.struct_op ().type ().id () == ID_union ||
78
+ member.struct_op ().type ().id () == ID_union_tag))
76
79
{
77
80
// place the entire member expression, not just the struct operand, in an
78
81
// SSA expression
@@ -88,6 +91,35 @@ exprt field_sensitivityt::apply(
88
91
return std::move (tmp);
89
92
}
90
93
}
94
+ else if (
95
+ !write && (expr.id () == ID_byte_extract_little_endian ||
96
+ expr.id () == ID_byte_extract_big_endian))
97
+ {
98
+ const byte_extract_exprt &be = to_byte_extract_expr (expr);
99
+ if (
100
+ (be.op ().type ().id () == ID_union ||
101
+ be.op ().type ().id () == ID_union_tag) &&
102
+ is_ssa_expr (be.op ()) && be.offset ().is_zero ())
103
+ {
104
+ const union_typet &type = to_union_type (ns.follow (be.op ().type ()));
105
+ for (const auto &comp : type.components ())
106
+ {
107
+ if (comp.type () == be.type ())
108
+ {
109
+ ssa_exprt tmp = to_ssa_expr (be.op ());
110
+ bool was_l2 = !tmp.get_level_2 ().empty ();
111
+ tmp.remove_level_2 ();
112
+ member_exprt member{tmp.get_original_expr (), comp};
113
+ tmp.type () = be.type ();
114
+ tmp.set_expression (member);
115
+ if (was_l2)
116
+ return state.rename (std::move (tmp), ns).get ();
117
+ else
118
+ return std::move (tmp);
119
+ }
120
+ }
121
+ }
122
+ }
91
123
#ifdef ENABLE_ARRAY_FIELD_SENSITIVITY
92
124
else if (expr.id () == ID_index)
93
125
{
@@ -144,7 +176,7 @@ exprt field_sensitivityt::apply(
144
176
{
145
177
// Expand the array and return `{array[0]; array[1]; ...}[index]`
146
178
exprt expanded_array =
147
- get_fields (ns, state, to_ssa_expr (index .array ()));
179
+ get_fields (ns, state, to_ssa_expr (index .array ()), true );
148
180
return index_exprt{std::move (expanded_array), index .index ()};
149
181
}
150
182
}
@@ -157,33 +189,48 @@ exprt field_sensitivityt::apply(
157
189
exprt field_sensitivityt::get_fields (
158
190
const namespacet &ns,
159
191
goto_symex_statet &state,
160
- const ssa_exprt &ssa_expr) const
192
+ const ssa_exprt &ssa_expr,
193
+ bool disjoined_fields_only) const
161
194
{
162
- if (ssa_expr.type ().id () == ID_struct || ssa_expr.type ().id () == ID_struct_tag)
195
+ if (
196
+ ssa_expr.type ().id () == ID_struct ||
197
+ ssa_expr.type ().id () == ID_struct_tag ||
198
+ (!disjoined_fields_only && (ssa_expr.type ().id () == ID_union ||
199
+ ssa_expr.type ().id () == ID_union_tag)))
163
200
{
164
- const struct_typet &type = to_struct_type (ns.follow (ssa_expr.type ()));
201
+ const struct_union_typet &type =
202
+ to_struct_union_type (ns.follow (ssa_expr.type ()));
165
203
const struct_union_typet::componentst &components = type.components ();
166
204
167
- struct_exprt ::operandst fields;
205
+ exprt ::operandst fields;
168
206
fields.reserve (components.size ());
169
207
170
- const exprt &struct_op = ssa_expr.get_original_expr ();
208
+ const exprt &compound_op = ssa_expr.get_original_expr ();
171
209
172
210
for (const auto &comp : components)
173
211
{
174
212
ssa_exprt tmp = ssa_expr;
175
213
bool was_l2 = !tmp.get_level_2 ().empty ();
176
214
tmp.remove_level_2 ();
177
- tmp.set_expression (member_exprt{struct_op, comp.get_name (), comp.type ()});
215
+ tmp.set_expression (
216
+ member_exprt{compound_op, comp.get_name (), comp.type ()});
217
+ exprt field = get_fields (ns, state, tmp, disjoined_fields_only);
178
218
if (was_l2)
179
219
{
180
- fields.push_back (state.rename (get_fields (ns, state, tmp ), ns).get ());
220
+ fields.emplace_back (state.rename (std::move (field ), ns).get ());
181
221
}
182
222
else
183
- fields.push_back ( get_fields (ns, state, tmp ));
223
+ fields.emplace_back ( std::move (field ));
184
224
}
185
225
186
- return struct_exprt (std::move (fields), ssa_expr.type ());
226
+ if (
227
+ disjoined_fields_only && (ssa_expr.type ().id () == ID_struct ||
228
+ ssa_expr.type ().id () == ID_struct_tag))
229
+ {
230
+ return struct_exprt{std::move (fields), ssa_expr.type ()};
231
+ }
232
+ else
233
+ return field_sensitive_ssa_exprt{ssa_expr, std::move (fields)};
187
234
}
188
235
#ifdef ENABLE_ARRAY_FIELD_SENSITIVITY
189
236
else if (
@@ -210,15 +257,19 @@ exprt field_sensitivityt::get_fields(
210
257
bool was_l2 = !tmp.get_level_2 ().empty ();
211
258
tmp.remove_level_2 ();
212
259
tmp.set_expression (index );
260
+ exprt element = get_fields (ns, state, tmp, disjoined_fields_only);
213
261
if (was_l2)
214
262
{
215
- elements.push_back (state.rename (get_fields (ns, state, tmp ), ns).get ());
263
+ elements.emplace_back (state.rename (std::move (element ), ns).get ());
216
264
}
217
265
else
218
- elements.push_back ( get_fields (ns, state, tmp ));
266
+ elements.emplace_back ( std::move (element ));
219
267
}
220
268
221
- return array_exprt (std::move (elements), type);
269
+ if (disjoined_fields_only)
270
+ return array_exprt (std::move (elements), type);
271
+ else
272
+ return field_sensitive_ssa_exprt{ssa_expr, std::move (elements)};
222
273
}
223
274
#endif // ENABLE_ARRAY_FIELD_SENSITIVITY
224
275
else
@@ -233,15 +284,15 @@ void field_sensitivityt::field_assignments(
233
284
symex_targett &target,
234
285
bool allow_pointer_unsoundness)
235
286
{
236
- const exprt lhs_fs = apply (ns, state, lhs, false );
287
+ PRECONDITION (run_apply);
288
+ const exprt lhs_fs = get_fields (ns, state, lhs, false );
237
289
238
290
if (lhs != lhs_fs)
239
291
{
240
- bool run_apply_bak = run_apply;
241
292
run_apply = false ;
242
293
field_assignments_rec (
243
294
ns, state, lhs_fs, rhs, target, allow_pointer_unsoundness);
244
- run_apply = run_apply_bak ;
295
+ run_apply = true ;
245
296
}
246
297
}
247
298
@@ -302,6 +353,43 @@ void field_sensitivityt::field_assignments_rec(
302
353
simplify_opt (member_exprt{ssa_rhs, comp.get_name (), comp.type ()}, ns);
303
354
const exprt &member_lhs = *fs_it;
304
355
356
+ field_assignments_rec (
357
+ ns, state, member_lhs, member_rhs, target, allow_pointer_unsoundness);
358
+ ++fs_it;
359
+ }
360
+ }
361
+ else if (
362
+ ssa_rhs.type ().id () == ID_union || ssa_rhs.type ().id () == ID_union_tag)
363
+ {
364
+ const union_typet &type = to_union_type (ns.follow (ssa_rhs.type ()));
365
+ const struct_union_typet::componentst &components = type.components ();
366
+
367
+ PRECONDITION (
368
+ components.empty () ||
369
+ (lhs_fs.has_operands () && lhs_fs.operands ().size () == components.size ()));
370
+
371
+ exprt::operandst::const_iterator fs_it = lhs_fs.operands ().begin ();
372
+ for (const auto &comp : components)
373
+ {
374
+ const exprt member_rhs = simplify_opt (
375
+ make_byte_extract (
376
+ ssa_rhs, from_integer (0 , c_index_type ()), comp.type ()),
377
+ ns);
378
+ const exprt &member_lhs = *fs_it;
379
+
380
+ if (
381
+ auto fs_ssa =
382
+ expr_try_dynamic_cast<field_sensitive_ssa_exprt>(member_lhs))
383
+ {
384
+ field_assignments_rec (
385
+ ns,
386
+ state,
387
+ fs_ssa->get_object_ssa (),
388
+ member_rhs,
389
+ target,
390
+ allow_pointer_unsoundness);
391
+ }
392
+
305
393
field_assignments_rec (
306
394
ns, state, member_lhs, member_rhs, target, allow_pointer_unsoundness);
307
395
++fs_it;
@@ -350,7 +438,9 @@ void field_sensitivityt::field_assignments_rec(
350
438
}
351
439
}
352
440
353
- bool field_sensitivityt::is_divisible (const ssa_exprt &expr) const
441
+ bool field_sensitivityt::is_divisible (
442
+ const ssa_exprt &expr,
443
+ bool disjoined_fields_only) const
354
444
{
355
445
if (expr.type ().id () == ID_struct || expr.type ().id () == ID_struct_tag)
356
446
return true ;
@@ -366,6 +456,13 @@ bool field_sensitivityt::is_divisible(const ssa_exprt &expr) const
366
456
}
367
457
#endif
368
458
459
+ if (
460
+ !disjoined_fields_only &&
461
+ (expr.type ().id () == ID_union || expr.type ().id () == ID_union_tag))
462
+ {
463
+ return true ;
464
+ }
465
+
369
466
return false ;
370
467
}
371
468
0 commit comments