Skip to content

Commit ec3ee8e

Browse files
committed
byte_extract lowering for complex_typet
It may have worked before via the fallback to flattening of the entire expression to a bitvector, but let's be on the safe side and construct appropriate expressions.
1 parent ff0ffa5 commit ec3ee8e

File tree

2 files changed

+95
-4
lines changed

2 files changed

+95
-4
lines changed

src/solvers/lowering/byte_operators.cpp

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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
578661
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)
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();

unit/solvers/lowering/byte_operators.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ SCENARIO("byte_extract_lowering", "[core][solvers][lowering][byte_extract]")
158158
// pointer_typet(u64, 64),
159159
vector_typet(u8, size),
160160
vector_typet(u64, size),
161-
// complex_typet(s16),
162-
// complex_typet(u64)
161+
complex_typet(s16),
162+
complex_typet(u64)
163163
};
164164

165165
simplify_exprt simp(ns);

0 commit comments

Comments
 (0)