Skip to content

Commit b5c3649

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 2168964 commit b5c3649

File tree

2 files changed

+99
-4
lines changed

2 files changed

+99
-4
lines changed

src/solvers/lowering/byte_operators.cpp

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,48 @@ static array_exprt unpack_array_vector(
116116
array_typet(unsignedbv_typet(8), from_integer(size, size_type())));
117117
}
118118

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+
119161
/// Rewrite an object into its individual bytes.
120162
/// \param src: object to unpack
121163
/// \param little_endian: true, iff assumed endianness is little-endian
@@ -180,7 +222,11 @@ static exprt unpack_rec(
180222
max_bytes,
181223
ns);
182224
}
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)
184230
{
185231
const struct_typet &struct_type=to_struct_type(ns.follow(src.type()));
186232
const struct_typet::componentst &components=struct_type.components();
@@ -338,6 +384,43 @@ static exprt unpack_rec(
338384
{}, array_typet(unsignedbv_typet(8), from_integer(0, size_type())));
339385
}
340386

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+
341424
/// rewrite byte extraction from an array to byte extraction from a
342425
/// concatenation of array index expressions
343426
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)
477560
return simplify_expr(vector_exprt(std::move(operands), vector_type), ns);
478561
}
479562
}
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)
481572
{
482573
const struct_typet &struct_type=to_struct_type(ns.follow(src.type()));
483574
const struct_typet::componentst &components=struct_type.components();

unit/solvers/lowering/byte_operators.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,12 @@ 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+
#if 0
162+
// seems to generate the correct value, but the simplifier needs to learn
163+
// about complex_exprt, complex_real_exprt, complex_imag_exprt
164+
complex_typet(s16),
165+
complex_typet(u64)
166+
#endif
163167
};
164168

165169
simplify_exprt simp(ns);

0 commit comments

Comments
 (0)