Skip to content

Commit 358d070

Browse files
authored
Merge pull request #4228 from tautschnig/byte-op-complex_typet
byte_extract lowering for complex_typet [blocks: #2068]
2 parents 4b183ec + ec3ee8e commit 358d070

File tree

4 files changed

+132
-11
lines changed

4 files changed

+132
-11
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();

src/util/simplify_expr.cpp

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2303,6 +2303,32 @@ bool simplify_exprt::simplify_byte_update(byte_update_exprt &expr)
23032303
return true;
23042304
}
23052305

2306+
bool simplify_exprt::simplify_complex(exprt &expr)
2307+
{
2308+
if(expr.id() == ID_complex_real)
2309+
{
2310+
complex_real_exprt &complex_real_expr = to_complex_real_expr(expr);
2311+
2312+
if(complex_real_expr.op().id() == ID_complex)
2313+
{
2314+
expr = to_complex_expr(complex_real_expr.op()).real();
2315+
return false;
2316+
}
2317+
}
2318+
else if(expr.id() == ID_complex_imag)
2319+
{
2320+
complex_imag_exprt &complex_imag_expr = to_complex_imag_expr(expr);
2321+
2322+
if(complex_imag_expr.op().id() == ID_complex)
2323+
{
2324+
expr = to_complex_expr(complex_imag_expr.op()).imag();
2325+
return false;
2326+
}
2327+
}
2328+
2329+
return true;
2330+
}
2331+
23062332
bool simplify_exprt::simplify_node_preorder(exprt &expr)
23072333
{
23082334
bool result=true;
@@ -2445,18 +2471,21 @@ bool simplify_exprt::simplify_node(exprt &expr)
24452471
result = simplify_popcount(to_popcount_expr(expr)) && result;
24462472
else if(expr.id() == ID_function_application)
24472473
result = simplify_function_application(expr) && result;
2474+
else if(expr.id() == ID_complex_real || expr.id() == ID_complex_imag)
2475+
result = simplify_complex(expr) && result;
24482476

2449-
#ifdef DEBUGX
2450-
if(!result
2451-
#ifdef DEBUG_ON_DEMAND
2452-
&& debug_on
2453-
#endif
2454-
)
2477+
#ifdef DEBUGX
2478+
if(
2479+
!result
2480+
#ifdef DEBUG_ON_DEMAND
2481+
&& debug_on
2482+
#endif
2483+
)
24552484
{
24562485
std::cout << "===== " << old.id() << ": " << format(old) << '\n'
24572486
<< " ---> " << format(expr) << '\n';
24582487
}
2459-
#endif
2488+
#endif
24602489

24612490
return result;
24622491
}

src/util/simplify_expr_class.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ class simplify_exprt
113113
bool simplify_abs(exprt &expr);
114114
bool simplify_sign(exprt &expr);
115115
bool simplify_popcount(popcount_exprt &expr);
116+
bool simplify_complex(exprt &expr);
116117

117118
/// Attempt to simplify mathematical function applications if we have
118119
/// enough information to do so. Currently focused on constant comparisons.

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)