@@ -9,6 +9,8 @@ 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
15
#include < util/std_expr.h>
14
16
@@ -17,6 +19,27 @@ Author: Michael Tautschnig
17
19
18
20
#define ENABLE_ARRAY_FIELD_SENSITIVITY
19
21
22
+ // / Produce a `struct_exprt` or an `array_exprt` when multiple fields are
23
+ // / provided; else just return the original expression.
24
+ static exprt fields_to_expr (std::vector<exprt> &&operands, const ssa_exprt &original_ssa_expr)
25
+ {
26
+ const typet &type = original_ssa_expr.type ();
27
+ if (type.id () == ID_struct || type.id () == ID_struct_tag)
28
+ {
29
+ return struct_exprt{std::move (operands), type};
30
+ }
31
+ else if (type.id () == ID_array)
32
+ {
33
+ return array_exprt{std::move (operands), type};
34
+ }
35
+ else
36
+ {
37
+ DATA_INVARIANT (operands.size () == 1 , " only arrays or structs yield multiple fields" );
38
+ DATA_INVARIANT (operands.front () == original_ssa_expr, " expression should be unmodified" );
39
+ return std::move (operands.front ());
40
+ }
41
+ }
42
+
20
43
exprt field_sensitivityt::apply (
21
44
const namespacet &ns,
22
45
goto_symex_statet &state,
@@ -26,7 +49,7 @@ exprt field_sensitivityt::apply(
26
49
if (!run_apply || write )
27
50
return std::move (ssa_expr);
28
51
else
29
- return get_fields (ns, state, ssa_expr);
52
+ return fields_to_expr ( get_fields (ns, state, ssa_expr) , ssa_expr);
30
53
}
31
54
32
55
exprt field_sensitivityt::apply (
@@ -72,7 +95,9 @@ exprt field_sensitivityt::apply(
72
95
if (
73
96
is_ssa_expr (member.struct_op ()) &&
74
97
(member.struct_op ().type ().id () == ID_struct ||
75
- member.struct_op ().type ().id () == ID_struct_tag))
98
+ member.struct_op ().type ().id () == ID_struct_tag ||
99
+ member.struct_op ().type ().id () == ID_union ||
100
+ member.struct_op ().type ().id () == ID_union_tag))
76
101
{
77
102
// place the entire member expression, not just the struct operand, in an
78
103
// SSA expression
@@ -88,6 +113,35 @@ exprt field_sensitivityt::apply(
88
113
return std::move (tmp);
89
114
}
90
115
}
116
+ else if (
117
+ expr.id () == ID_byte_extract_little_endian ||
118
+ expr.id () == ID_byte_extract_big_endian)
119
+ {
120
+ const byte_extract_exprt &be = to_byte_extract_expr (expr);
121
+ if (
122
+ (be.op ().type ().id () == ID_union ||
123
+ be.op ().type ().id () == ID_union_tag) &&
124
+ be.offset ().is_zero ())
125
+ {
126
+ const union_typet &type = to_union_type (ns.follow (be.op ().type ()));
127
+ for (const auto &comp : type.components ())
128
+ {
129
+ if (comp.type () == be.type ())
130
+ {
131
+ ssa_exprt tmp = to_ssa_expr (be.op ());
132
+ bool was_l2 = !tmp.get_level_2 ().empty ();
133
+ tmp.remove_level_2 ();
134
+ member_exprt member{tmp.get_original_expr (), comp};
135
+ tmp.type () = be.type ();
136
+ tmp.set_expression (member);
137
+ if (was_l2)
138
+ return state.rename (std::move (tmp), ns).get ();
139
+ else
140
+ return std::move (tmp);
141
+ }
142
+ }
143
+ }
144
+ }
91
145
#ifdef ENABLE_ARRAY_FIELD_SENSITIVITY
92
146
else if (expr.id () == ID_index)
93
147
{
@@ -143,8 +197,9 @@ exprt field_sensitivityt::apply(
143
197
else if (!write )
144
198
{
145
199
// Expand the array and return `{array[0]; array[1]; ...}[index]`
200
+ const ssa_exprt &array = to_ssa_expr (index .array ());
146
201
exprt expanded_array =
147
- get_fields (ns, state, to_ssa_expr ( index . array ()) );
202
+ fields_to_expr ( get_fields (ns, state, array), array );
148
203
return index_exprt{std::move (expanded_array), index .index ()};
149
204
}
150
205
}
@@ -154,36 +209,39 @@ exprt field_sensitivityt::apply(
154
209
return expr;
155
210
}
156
211
157
- exprt field_sensitivityt::get_fields (
212
+ exprt::operandst field_sensitivityt::get_fields (
158
213
const namespacet &ns,
159
214
goto_symex_statet &state,
160
215
const ssa_exprt &ssa_expr) const
161
216
{
162
- if (ssa_expr.type ().id () == ID_struct || ssa_expr.type ().id () == ID_struct_tag)
217
+ if (ssa_expr.type ().id () == ID_struct || ssa_expr.type ().id () == ID_struct_tag ||
218
+ (do_union &&
219
+ (ssa_expr.type ().id () == ID_union || ssa_expr.type ().id () == ID_union_tag)))
163
220
{
164
- const struct_typet &type = to_struct_type (ns.follow (ssa_expr.type ()));
221
+ const struct_union_typet &type = to_struct_union_type (ns.follow (ssa_expr.type ()));
165
222
const struct_union_typet::componentst &components = type.components ();
166
223
167
- struct_exprt ::operandst fields;
224
+ exprt ::operandst fields;
168
225
fields.reserve (components.size ());
169
226
170
- const exprt &struct_op = ssa_expr.get_original_expr ();
227
+ const exprt &compound_op = ssa_expr.get_original_expr ();
171
228
172
229
for (const auto &comp : components)
173
230
{
174
231
ssa_exprt tmp = ssa_expr;
175
232
bool was_l2 = !tmp.get_level_2 ().empty ();
176
233
tmp.remove_level_2 ();
177
- tmp.set_expression (member_exprt{struct_op, comp.get_name (), comp.type ()});
234
+ tmp.set_expression (member_exprt{compound_op, comp.get_name (), comp.type ()});
235
+ exprt field = fields_to_expr (get_fields (ns, state, tmp), tmp);
178
236
if (was_l2)
179
237
{
180
- fields.push_back (state.rename (get_fields (ns, state, tmp ), ns).get ());
238
+ fields.emplace_back (state.rename (std::move (field ), ns).get ());
181
239
}
182
240
else
183
- fields.push_back ( get_fields (ns, state, tmp ));
241
+ fields.emplace_back ( std::move (field ));
184
242
}
185
243
186
- return struct_exprt ( std::move ( fields), ssa_expr. type ()) ;
244
+ return fields;
187
245
}
188
246
#ifdef ENABLE_ARRAY_FIELD_SENSITIVITY
189
247
else if (
@@ -210,19 +268,20 @@ exprt field_sensitivityt::get_fields(
210
268
bool was_l2 = !tmp.get_level_2 ().empty ();
211
269
tmp.remove_level_2 ();
212
270
tmp.set_expression (index );
271
+ exprt element = fields_to_expr (get_fields (ns, state, tmp), tmp);
213
272
if (was_l2)
214
273
{
215
- elements.push_back (state.rename (get_fields (ns, state, tmp ), ns).get ());
274
+ elements.emplace_back (state.rename (std::move (element ), ns).get ());
216
275
}
217
276
else
218
- elements.push_back ( get_fields (ns, state, tmp ));
277
+ elements.emplace_back ( std::move (element ));
219
278
}
220
279
221
- return array_exprt ( std::move ( elements), type) ;
280
+ return elements;
222
281
}
223
282
#endif // ENABLE_ARRAY_FIELD_SENSITIVITY
224
283
else
225
- return ssa_expr;
284
+ return { ssa_expr} ;
226
285
}
227
286
228
287
void field_sensitivityt::field_assignments (
@@ -233,9 +292,13 @@ void field_sensitivityt::field_assignments(
233
292
symex_targett &target,
234
293
bool allow_pointer_unsoundness)
235
294
{
236
- const exprt lhs_fs = apply (ns, state, lhs, false );
295
+ assert (run_apply);
296
+ bool do_union_bak = do_union;
297
+ do_union = true ;
298
+ const exprt::operandst lhs_fs = get_fields (ns, state, lhs);
299
+ do_union = do_union_bak;
237
300
238
- if (lhs != lhs_fs)
301
+ if (lhs_fs. empty () || lhs != lhs_fs. front () )
239
302
{
240
303
bool run_apply_bak = run_apply;
241
304
run_apply = false ;
@@ -258,16 +321,16 @@ void field_sensitivityt::field_assignments(
258
321
void field_sensitivityt::field_assignments_rec (
259
322
const namespacet &ns,
260
323
goto_symex_statet &state,
261
- const exprt &lhs_fs,
324
+ const exprt::operandst &lhs_fs,
262
325
const exprt &ssa_rhs,
263
326
symex_targett &target,
264
327
bool allow_pointer_unsoundness)
265
328
{
266
- if (is_ssa_expr (lhs_fs))
329
+ if (lhs_fs. size () == 1 && is_ssa_expr (lhs_fs. front () ))
267
330
{
268
331
const ssa_exprt ssa_lhs = state
269
332
.assignment (
270
- to_ssa_expr (lhs_fs),
333
+ to_ssa_expr (lhs_fs. front () ),
271
334
ssa_rhs,
272
335
ns,
273
336
true ,
@@ -293,15 +356,39 @@ void field_sensitivityt::field_assignments_rec(
293
356
294
357
PRECONDITION (
295
358
components.empty () ||
296
- ( lhs_fs.has_operands () && lhs_fs. operands (). size () == components.size () ));
359
+ lhs_fs.size () == components.size ());
297
360
298
- exprt::operandst::const_iterator fs_it = lhs_fs.operands (). begin ();
361
+ exprt::operandst::const_iterator fs_it = lhs_fs.begin ();
299
362
for (const auto &comp : components)
300
363
{
301
364
const exprt member_rhs =
302
365
simplify_opt (member_exprt{ssa_rhs, comp.get_name (), comp.type ()}, ns);
303
366
const exprt &member_lhs = *fs_it;
304
367
368
+ field_assignments_rec (
369
+ ns, state, member_lhs, member_rhs, target, allow_pointer_unsoundness);
370
+ ++fs_it;
371
+ }
372
+ }
373
+ else if (
374
+ ssa_rhs.type ().id () == ID_union || ssa_rhs.type ().id () == ID_union_tag)
375
+ {
376
+ const union_typet &type = to_union_type (ns.follow (ssa_rhs.type ()));
377
+ const struct_union_typet::componentst &components = type.components ();
378
+
379
+ PRECONDITION (
380
+ components.empty () ||
381
+ lhs_fs.size () == components.size ());
382
+
383
+ exprt::operandst::const_iterator fs_it = lhs_fs.begin ();
384
+ for (const auto &comp : components)
385
+ {
386
+ const exprt member_rhs = simplify_opt (
387
+ make_byte_extract (
388
+ ssa_rhs, from_integer (0 , c_index_type ()), comp.type ()),
389
+ ns);
390
+ const exprt &member_lhs = *fs_it;
391
+
305
392
field_assignments_rec (
306
393
ns, state, member_lhs, member_rhs, target, allow_pointer_unsoundness);
307
394
++fs_it;
@@ -312,12 +399,12 @@ void field_sensitivityt::field_assignments_rec(
312
399
{
313
400
const std::size_t array_size =
314
401
numeric_cast_v<std::size_t >(to_constant_expr (type->size ()));
315
- PRECONDITION (lhs_fs.operands (). size () == array_size);
402
+ PRECONDITION (lhs_fs.size () == array_size);
316
403
317
404
if (array_size > max_field_sensitivity_array_size)
318
405
return ;
319
406
320
- exprt::operandst::const_iterator fs_it = lhs_fs.operands (). begin ();
407
+ exprt::operandst::const_iterator fs_it = lhs_fs.begin ();
321
408
for (std::size_t i = 0 ; i < array_size; ++i)
322
409
{
323
410
const exprt index_rhs = simplify_opt (
@@ -330,24 +417,20 @@ void field_sensitivityt::field_assignments_rec(
330
417
}
331
418
}
332
419
#endif // ENABLE_ARRAY_FIELD_SENSITIVITY
333
- else if (lhs_fs. has_operands ())
420
+ else
334
421
{
335
422
PRECONDITION (
336
423
ssa_rhs.has_operands () &&
337
- lhs_fs.operands (). size () == ssa_rhs.operands ().size ());
424
+ lhs_fs.size () == ssa_rhs.operands ().size ());
338
425
339
- exprt::operandst::const_iterator fs_it = lhs_fs.operands (). begin ();
426
+ exprt::operandst::const_iterator fs_it = lhs_fs.begin ();
340
427
for (const exprt &op : ssa_rhs.operands ())
341
428
{
342
429
field_assignments_rec (
343
430
ns, state, *fs_it, op, target, allow_pointer_unsoundness);
344
431
++fs_it;
345
432
}
346
433
}
347
- else
348
- {
349
- UNREACHABLE;
350
- }
351
434
}
352
435
353
436
bool field_sensitivityt::is_divisible (const ssa_exprt &expr) const
@@ -366,6 +449,9 @@ bool field_sensitivityt::is_divisible(const ssa_exprt &expr) const
366
449
}
367
450
#endif
368
451
452
+ if (expr.type ().id () == ID_union || expr.type ().id () == ID_union_tag)
453
+ return true ;
454
+
369
455
return false ;
370
456
}
371
457
0 commit comments