@@ -116,6 +116,48 @@ static array_exprt unpack_array_vector(
116
116
array_typet (unsignedbv_typet (8 ), from_integer (size, size_type ())));
117
117
}
118
118
119
+ // / Rewrite a complex_exprt into its individual bytes.
120
+ // / \param src: complex-typed expression to unpack
121
+ // / \param little_endian: true, iff assumed endianness is little-endian
122
+ // / \param ns: namespace for type lookups
123
+ // / \return array_exprt holding unpacked elements
124
+ static array_exprt
125
+ unpack_complex (const exprt &src, bool little_endian, const namespacet &ns)
126
+ {
127
+ const complex_typet &complex_type = to_complex_type (src.type ());
128
+ const typet &subtype = complex_type.subtype ();
129
+
130
+ auto subtype_bits = pointer_offset_bits (subtype, ns);
131
+ CHECK_RETURN (subtype_bits.has_value ());
132
+ CHECK_RETURN (*subtype_bits % 8 == 0 );
133
+
134
+ exprt sub_real = unpack_rec (
135
+ complex_real_exprt{src},
136
+ little_endian,
137
+ mp_integer{0 },
138
+ *subtype_bits / 8 ,
139
+ ns,
140
+ true );
141
+ exprt::operandst byte_operands = std::move (sub_real.operands ());
142
+
143
+ exprt sub_imag = unpack_rec (
144
+ complex_imag_exprt{src},
145
+ little_endian,
146
+ mp_integer{0 },
147
+ *subtype_bits / 8 ,
148
+ ns,
149
+ true );
150
+ byte_operands.insert (
151
+ byte_operands.end (),
152
+ sub_imag.operands ().begin (),
153
+ sub_imag.operands ().end ());
154
+
155
+ const std::size_t size = byte_operands.size ();
156
+ return array_exprt{
157
+ std::move (byte_operands),
158
+ array_typet{unsignedbv_typet (8 ), from_integer (size, size_type ())}};
159
+ }
160
+
119
161
// / Rewrite an object into its individual bytes.
120
162
// / \param src: object to unpack
121
163
// / \param little_endian: true, iff assumed endianness is little-endian
@@ -180,7 +222,11 @@ static exprt unpack_rec(
180
222
max_bytes,
181
223
ns);
182
224
}
183
- else if (ns.follow (src.type ()).id ()==ID_struct)
225
+ else if (src.type ().id () == ID_complex)
226
+ {
227
+ return unpack_complex (src, little_endian, ns);
228
+ }
229
+ else if (src.type ().id () == ID_struct || src.type ().id () == ID_struct_tag)
184
230
{
185
231
const struct_typet &struct_type=to_struct_type (ns.follow (src.type ()));
186
232
const struct_typet::componentst &components=struct_type.components ();
@@ -338,6 +384,43 @@ static exprt unpack_rec(
338
384
{}, array_typet (unsignedbv_typet (8 ), from_integer (0 , size_type ())));
339
385
}
340
386
387
+ // / Rewrite a byte extraction of a complex-typed result to byte extraction of
388
+ // / the individual components that make up a \ref complex_exprt.
389
+ // / \param src: Original byte extract expression
390
+ // / \param src: Byte extraction with root operand expanded into array (via \ref
391
+ // / unpack_rec)
392
+ // / \param ns: Namespace
393
+ // / \return An expression if the subtype size is known, else `nullopt` so that a
394
+ // / fall-back to more generic code can be used.
395
+ static optionalt<exprt> lower_byte_extract_complex (
396
+ const byte_extract_exprt &src,
397
+ const byte_extract_exprt &unpacked,
398
+ const namespacet &ns)
399
+ {
400
+ const complex_typet &complex_type = to_complex_type (src.type ());
401
+ const typet &subtype = complex_type.subtype ();
402
+
403
+ auto subtype_bits = pointer_offset_bits (subtype, ns);
404
+ if (!subtype_bits.has_value () || *subtype_bits % 8 != 0 )
405
+ return {};
406
+
407
+ // offset remains unchanged
408
+ byte_extract_exprt real{unpacked};
409
+ real.type () = subtype;
410
+
411
+ const plus_exprt new_offset{
412
+ unpacked.offset (),
413
+ from_integer (*subtype_bits / 8 , unpacked.offset ().type ())};
414
+ byte_extract_exprt imag{unpacked};
415
+ imag.type () = subtype;
416
+ imag.offset () = simplify_expr (new_offset, ns);
417
+
418
+ return simplify_expr (
419
+ complex_exprt{
420
+ lower_byte_extract (real, ns), lower_byte_extract (imag, ns), complex_type},
421
+ ns);
422
+ }
423
+
341
424
// / rewrite byte extraction from an array to byte extraction from a
342
425
// / concatenation of array index expressions
343
426
exprt lower_byte_extract (const byte_extract_exprt &src, const namespacet &ns)
@@ -477,7 +560,15 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
477
560
return simplify_expr (vector_exprt (std::move (operands), vector_type), ns);
478
561
}
479
562
}
480
- else if (ns.follow (src.type ()).id ()==ID_struct)
563
+ else if (src.type ().id () == ID_complex)
564
+ {
565
+ auto result = lower_byte_extract_complex (src, unpacked, ns);
566
+ if (result.has_value ())
567
+ return std::move (*result);
568
+
569
+ // else fall back to generic lowering that uses bit masks, below
570
+ }
571
+ else if (src.type ().id () == ID_struct || src.type ().id () == ID_struct_tag)
481
572
{
482
573
const struct_typet &struct_type=to_struct_type (ns.follow (src.type ()));
483
574
const struct_typet::componentst &components=struct_type.components ();
0 commit comments