18
18
19
19
#include " flatten_byte_extract_exceptions.h"
20
20
21
- // clang-format off
21
+ static exprt unpack_rec (
22
+ const exprt &src,
23
+ bool little_endian,
24
+ const exprt &max_bytes,
25
+ const namespacet &ns,
26
+ bool unpack_byte_array = false );
27
+
28
+ // / rewrite an array or vector into its individual bytes
29
+ // / \param src: array/vector to unpack
30
+ // / \param src_size: array/vector size
31
+ // / \param element_width: bit width of array/vector elements
32
+ // / \param little_endian: true, iff assumed endianness is little-endian
33
+ // / \param max_bytes: if not nil, use as upper bound of the number of bytes to
34
+ // / unpack
35
+ // / \param ns: namespace for type lookups
36
+ // / \param [out] dest_array: target array_exprt to hold unpacked elements
37
+ static void unpack_array_vector (
38
+ const exprt &src,
39
+ const exprt &src_size,
40
+ const mp_integer &element_width,
41
+ bool little_endian,
42
+ const exprt &max_bytes,
43
+ const namespacet &ns,
44
+ array_exprt &dest_array)
45
+ {
46
+ auto max_bytes_int = numeric_cast<mp_integer>(max_bytes);
47
+ auto num_elements = numeric_cast<mp_integer>(src_size);
48
+
49
+ if (!max_bytes_int && !num_elements)
50
+ {
51
+ throw non_const_array_sizet (src.type (), max_bytes);
52
+ }
53
+
54
+ mp_integer first_element = 0 ;
55
+
56
+ // refine the number of elements to extract in case the element width is known
57
+ // and a multiple of bytes; otherwise we will expand the entire array/vector
58
+ if (element_width > 0 && element_width % 8 == 0 )
59
+ {
60
+ mp_integer el_bytes = element_width / 8 ;
61
+
62
+ // turn bytes into elements
63
+ if (!num_elements)
64
+ {
65
+ if (*max_bytes_int % el_bytes != 0 )
66
+ *max_bytes_int += el_bytes;
67
+
68
+ *max_bytes_int /= el_bytes;
69
+ }
70
+ }
71
+
72
+ // the maximum number of bytes is an upper bound in case the size of the
73
+ // array/vector is unknown; if the element_width was usable above this will
74
+ // have been turned into a number of elements already
75
+ if (!num_elements)
76
+ num_elements = max_bytes_int;
77
+
78
+ exprt src_simp = simplify_expr (src, ns);
79
+
80
+ for (mp_integer i = first_element; i < *num_elements; ++i)
81
+ {
82
+ exprt element;
83
+
84
+ if (src_simp.id () != ID_array || i >= src_simp.operands ().size ())
85
+ {
86
+ element = index_exprt (src_simp, from_integer (i, index_type ()));
87
+ }
88
+ else
89
+ {
90
+ const std::size_t index_int = numeric_cast_v<std::size_t >(i);
91
+ element = src_simp.operands ()[index_int];
92
+ }
93
+
94
+ exprt sub = unpack_rec (element, little_endian, max_bytes, ns, true );
95
+ dest_array.operands ().insert (
96
+ dest_array.operands ().end (),
97
+ sub.operands ().begin (),
98
+ sub.operands ().end ());
99
+ }
100
+ }
22
101
23
102
// / rewrite an object into its individual bytes
24
- // / \par parameters: src object to unpack
25
- // / little_endian true, iff assumed endianness is little-endian
26
- // / max_bytes if not nil, use as upper bound of the number of bytes to unpack
27
- // / ns namespace for type lookups
103
+ // / \param src: object to unpack
104
+ // / \param little_endian: true, iff assumed endianness is little-endian
105
+ // / \param max_bytes: if not nil, use as upper bound of the number of bytes to
106
+ // / unpack
107
+ // / \param ns: namespace for type lookups
108
+ // / \param unpack_byte_array: if true, return unmodified src iff it is a an
109
+ // array of bytes
28
110
// / \return array of bytes in the sequence found in memory
29
111
// / \throws flatten_byte_extract_exceptiont Raised is unable to unpack the
30
112
// / object because of either non constant size, byte misalignment or
@@ -34,7 +116,7 @@ static exprt unpack_rec(
34
116
bool little_endian,
35
117
const exprt &max_bytes,
36
118
const namespacet &ns,
37
- bool unpack_byte_array= false )
119
+ bool unpack_byte_array)
38
120
{
39
121
array_exprt array ({},
40
122
array_typet (unsignedbv_typet (8 ), from_integer (0 , size_type ())));
@@ -51,48 +133,37 @@ static exprt unpack_rec(
51
133
auto element_width = pointer_offset_bits (subtype, ns);
52
134
CHECK_RETURN (element_width.has_value ());
53
135
54
- // this probably doesn't really matter
55
- #if 0
56
- INVARIANT(
57
- element_width > 0,
58
- "element width of array should be constant",
59
- irep_pretty_diagnosticst(src.type()));
60
-
61
- INVARIANT(
62
- element_width % 8 == 0,
63
- "elements in array should be byte-aligned",
64
- irep_pretty_diagnosticst(src.type()));
65
- #endif
66
-
67
136
if (!unpack_byte_array && *element_width == 8 )
68
137
return src;
69
138
70
- auto num_elements = numeric_cast<mp_integer>(max_bytes);
71
- if (!num_elements.has_value ())
72
- num_elements = numeric_cast<mp_integer>(array_type.size ());
73
- if (!num_elements.has_value ())
74
- throw non_const_array_sizet (array_type, max_bytes);
139
+ unpack_array_vector (
140
+ src,
141
+ array_type.size (),
142
+ *element_width,
143
+ little_endian,
144
+ max_bytes,
145
+ ns,
146
+ array);
147
+ }
148
+ else if (src.type ().id () == ID_vector)
149
+ {
150
+ const vector_typet &vector_type = to_vector_type (src.type ());
151
+ const typet &subtype = vector_type.subtype ();
75
152
76
- // all array members will have the same structure; do this just
77
- // once and then replace the dummy symbol by a suitable index
78
- // expression in the loop below
79
- symbol_exprt dummy (ID_C_incomplete, subtype);
80
- exprt sub=unpack_rec (dummy, little_endian, max_bytes, ns, true );
153
+ auto element_width = pointer_offset_bits (subtype, ns);
154
+ CHECK_RETURN (element_width.has_value ());
81
155
82
- for (mp_integer i=0 ; i<*num_elements; ++i)
83
- {
84
- index_exprt index (src, from_integer (i, index_type ()));
85
- replace_symbolt replace;
86
- replace.insert (dummy, index );
156
+ if (!unpack_byte_array && *element_width == 8 )
157
+ return src;
87
158
88
- for ( const auto &op : sub. operands ())
89
- {
90
- exprt new_op=op;
91
- replace (new_op);
92
- simplify (new_op, ns);
93
- array. copy_to_operands (new_op);
94
- }
95
- }
159
+ unpack_array_vector (
160
+ src,
161
+ vector_type. size (),
162
+ *element_width,
163
+ little_endian,
164
+ max_bytes,
165
+ ns,
166
+ array);
96
167
}
97
168
else if (ns.follow (src.type ()).id ()==ID_struct)
98
169
{
@@ -233,12 +304,16 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
233
304
const typet &subtype=array_type.subtype ();
234
305
235
306
auto element_width = pointer_offset_bits (subtype, ns);
236
- const auto num_elements = numeric_cast<mp_integer>(array_type.size ());
237
- // TODO: consider ways of dealing with arrays of unknown subtype
238
- // size or with a subtype size that does not fit byte boundaries
307
+ auto num_elements = numeric_cast<mp_integer>(array_type.size ());
308
+ if (!num_elements.has_value ())
309
+ num_elements = mp_integer (unpacked.op ().operands ().size ());
310
+
311
+ // consider ways of dealing with arrays of unknown subtype size or with a
312
+ // subtype size that does not fit byte boundaries; currently we fall back to
313
+ // stitching together consecutive elements down below
239
314
if (
240
315
element_width.has_value () && *element_width >= 1 &&
241
- *element_width % 8 == 0 && num_elements. has_value () )
316
+ *element_width % 8 == 0 )
242
317
{
243
318
array_exprt array ({}, array_type);
244
319
@@ -258,6 +333,41 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
258
333
return simplify_expr (array, ns);
259
334
}
260
335
}
336
+ else if (src.type ().id () == ID_vector)
337
+ {
338
+ const vector_typet &vector_type = to_vector_type (src.type ());
339
+ const typet &subtype = vector_type.subtype ();
340
+
341
+ mp_integer num_elements = numeric_cast_v<mp_integer>(vector_type.size ());
342
+
343
+ auto element_width = pointer_offset_bits (subtype, ns);
344
+ CHECK_RETURN (element_width.has_value ());
345
+
346
+ // consider ways of dealing with vectors of unknown subtype size or with a
347
+ // subtype size that does not fit byte boundaries; currently we fall back to
348
+ // stitching together consecutive elements down below
349
+ if (
350
+ element_width.has_value () && *element_width >= 1 &&
351
+ *element_width % 8 == 0 )
352
+ {
353
+ vector_exprt vector (vector_type);
354
+
355
+ for (mp_integer i = 0 ; i < num_elements; ++i)
356
+ {
357
+ plus_exprt new_offset (
358
+ unpacked.offset (),
359
+ from_integer (i * (*element_width) / 8 , unpacked.offset ().type ()));
360
+
361
+ byte_extract_exprt tmp (unpacked);
362
+ tmp.type () = subtype;
363
+ tmp.offset () = simplify_expr (new_offset, ns);
364
+
365
+ vector.copy_to_operands (lower_byte_extract (tmp, ns));
366
+ }
367
+
368
+ return simplify_expr (vector, ns);
369
+ }
370
+ }
261
371
else if (ns.follow (src.type ()).id ()==ID_struct)
262
372
{
263
373
const struct_typet &struct_type=to_struct_type (ns.follow (src.type ()));
@@ -299,10 +409,13 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
299
409
const exprt &root=unpacked.op ();
300
410
const exprt &offset=unpacked.offset ();
301
411
302
- const array_typet &array_type=to_array_type (root.type ());
303
- const typet &subtype=array_type.subtype ();
412
+ optionalt<typet> subtype;
413
+ if (root.type ().id () == ID_vector)
414
+ subtype = to_vector_type (root.type ()).subtype ();
415
+ else
416
+ subtype = to_array_type (root.type ()).subtype ();
304
417
305
- auto subtype_bits = pointer_offset_bits (subtype, ns);
418
+ auto subtype_bits = pointer_offset_bits (* subtype, ns);
306
419
307
420
DATA_INVARIANT (
308
421
subtype_bits.has_value () && *subtype_bits == 8 ,
@@ -344,7 +457,7 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
344
457
else // width_bytes>=2
345
458
{
346
459
concatenation_exprt concatenation (
347
- std::move (op), bitvector_typet (subtype. id (), width_bytes * 8 ));
460
+ std::move (op), bitvector_typet (subtype-> id (), width_bytes * 8 ));
348
461
return simplify_expr (
349
462
typecast_exprt (std::move (concatenation), src.type ()), ns);
350
463
}
@@ -649,4 +762,3 @@ exprt lower_byte_operators(const exprt &src, const namespacet &ns)
649
762
else
650
763
return tmp;
651
764
}
652
- // clang-format on
0 commit comments