@@ -351,6 +351,48 @@ static array_exprt unpack_array_vector(
351
351
array_typet (unsignedbv_typet (8 ), from_integer (size, size_type ())));
352
352
}
353
353
354
+ // / Rewrite a complex_exprt into its individual bytes.
355
+ // / \param src: complex-typed expression to unpack
356
+ // / \param little_endian: true, iff assumed endianness is little-endian
357
+ // / \param ns: namespace for type lookups
358
+ // / \return array_exprt holding unpacked elements
359
+ static array_exprt
360
+ unpack_complex (const exprt &src, bool little_endian, const namespacet &ns)
361
+ {
362
+ const complex_typet &complex_type = to_complex_type (src.type ());
363
+ const typet &subtype = complex_type.subtype ();
364
+
365
+ auto subtype_bits = pointer_offset_bits (subtype, ns);
366
+ CHECK_RETURN (subtype_bits.has_value ());
367
+ CHECK_RETURN (*subtype_bits % 8 == 0 );
368
+
369
+ exprt sub_real = unpack_rec (
370
+ complex_real_exprt{src},
371
+ little_endian,
372
+ mp_integer{0 },
373
+ *subtype_bits / 8 ,
374
+ ns,
375
+ true );
376
+ exprt::operandst byte_operands = std::move (sub_real.operands ());
377
+
378
+ exprt sub_imag = unpack_rec (
379
+ complex_imag_exprt{src},
380
+ little_endian,
381
+ mp_integer{0 },
382
+ *subtype_bits / 8 ,
383
+ ns,
384
+ true );
385
+ byte_operands.insert (
386
+ byte_operands.end (),
387
+ std::make_move_iterator (sub_imag.operands ().begin ()),
388
+ std::make_move_iterator (sub_imag.operands ().end ()));
389
+
390
+ const std::size_t size = byte_operands.size ();
391
+ return array_exprt{
392
+ std::move (byte_operands),
393
+ array_typet{unsignedbv_typet (8 ), from_integer (size, size_type ())}};
394
+ }
395
+
354
396
// / Rewrite an object into its individual bytes.
355
397
// / \param src: object to unpack
356
398
// / \param little_endian: true, iff assumed endianness is little-endian
@@ -415,7 +457,11 @@ static exprt unpack_rec(
415
457
max_bytes,
416
458
ns);
417
459
}
418
- else if (ns.follow (src.type ()).id ()==ID_struct)
460
+ else if (src.type ().id () == ID_complex)
461
+ {
462
+ return unpack_complex (src, little_endian, ns);
463
+ }
464
+ else if (src.type ().id () == ID_struct || src.type ().id () == ID_struct_tag)
419
465
{
420
466
const struct_typet &struct_type=to_struct_type (ns.follow (src.type ()));
421
467
const struct_typet::componentst &components=struct_type.components ();
@@ -573,6 +619,43 @@ static exprt unpack_rec(
573
619
{}, array_typet (unsignedbv_typet (8 ), from_integer (0 , size_type ())));
574
620
}
575
621
622
+ // / Rewrite a byte extraction of a complex-typed result to byte extraction of
623
+ // / the individual components that make up a \ref complex_exprt.
624
+ // / \param src: Original byte extract expression
625
+ // / \param unpacked: Byte extraction with root operand expanded into array (via
626
+ // / \ref unpack_rec)
627
+ // / \param ns: Namespace
628
+ // / \return An expression if the subtype size is known, else `nullopt` so that a
629
+ // / fall-back to more generic code can be used.
630
+ static optionalt<exprt> lower_byte_extract_complex (
631
+ const byte_extract_exprt &src,
632
+ const byte_extract_exprt &unpacked,
633
+ const namespacet &ns)
634
+ {
635
+ const complex_typet &complex_type = to_complex_type (src.type ());
636
+ const typet &subtype = complex_type.subtype ();
637
+
638
+ auto subtype_bits = pointer_offset_bits (subtype, ns);
639
+ if (!subtype_bits.has_value () || *subtype_bits % 8 != 0 )
640
+ return {};
641
+
642
+ // offset remains unchanged
643
+ byte_extract_exprt real{unpacked};
644
+ real.type () = subtype;
645
+
646
+ const plus_exprt new_offset{
647
+ unpacked.offset (),
648
+ from_integer (*subtype_bits / 8 , unpacked.offset ().type ())};
649
+ byte_extract_exprt imag{unpacked};
650
+ imag.type () = subtype;
651
+ imag.offset () = simplify_expr (new_offset, ns);
652
+
653
+ return simplify_expr (
654
+ complex_exprt{
655
+ lower_byte_extract (real, ns), lower_byte_extract (imag, ns), complex_type},
656
+ ns);
657
+ }
658
+
576
659
// / rewrite byte extraction from an array to byte extraction from a
577
660
// / concatenation of array index expressions
578
661
exprt lower_byte_extract (const byte_extract_exprt &src, const namespacet &ns)
@@ -712,7 +795,15 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
712
795
return simplify_expr (vector_exprt (std::move (operands), vector_type), ns);
713
796
}
714
797
}
715
- else if (ns.follow (src.type ()).id ()==ID_struct)
798
+ else if (src.type ().id () == ID_complex)
799
+ {
800
+ auto result = lower_byte_extract_complex (src, unpacked, ns);
801
+ if (result.has_value ())
802
+ return std::move (*result);
803
+
804
+ // else fall back to generic lowering that uses bit masks, below
805
+ }
806
+ else if (src.type ().id () == ID_struct || src.type ().id () == ID_struct_tag)
716
807
{
717
808
const struct_typet &struct_type=to_struct_type (ns.follow (src.type ()));
718
809
const struct_typet::componentst &components=struct_type.components ();
0 commit comments