@@ -351,6 +351,48 @@ static array_exprt unpack_array_vector(
351351 array_typet (unsignedbv_typet (8 ), from_integer (size, size_type ())));
352352}
353353
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+
354396// / Rewrite an object into its individual bytes.
355397// / \param src: object to unpack
356398// / \param little_endian: true, iff assumed endianness is little-endian
@@ -415,7 +457,11 @@ static exprt unpack_rec(
415457 max_bytes,
416458 ns);
417459 }
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)
419465 {
420466 const struct_typet &struct_type=to_struct_type (ns.follow (src.type ()));
421467 const struct_typet::componentst &components=struct_type.components ();
@@ -573,6 +619,43 @@ static exprt unpack_rec(
573619 {}, array_typet (unsignedbv_typet (8 ), from_integer (0 , size_type ())));
574620}
575621
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+
576659// / rewrite byte extraction from an array to byte extraction from a
577660// / concatenation of array index expressions
578661exprt 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)
712795 return simplify_expr (vector_exprt (std::move (operands), vector_type), ns);
713796 }
714797 }
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)
716807 {
717808 const struct_typet &struct_type=to_struct_type (ns.follow (src.type ()));
718809 const struct_typet::componentst &components=struct_type.components ();
0 commit comments