55#include < util/bitvector_expr.h>
66#include < util/bitvector_types.h>
77#include < util/make_unique.h>
8+ #include < util/namespace.h>
9+ #include < util/range.h>
810
911#include < solvers/flattening/boolbv_width.h>
1012
13+ #include < algorithm>
14+ #include < numeric>
1115#include < queue>
1216
1317struct_encodingt::struct_encodingt (const namespacet &ns)
14- : boolbv_width{util_make_unique<boolbv_widtht>(ns)}
18+ : boolbv_width{util_make_unique<boolbv_widtht>(ns)}, ns{ns}
1519{
1620}
1721
1822struct_encodingt::struct_encodingt (const struct_encodingt &other)
19- : boolbv_width{util_make_unique<boolbv_widtht>(*other.boolbv_width )}
23+ : boolbv_width{util_make_unique<boolbv_widtht>(*other.boolbv_width )},
24+ ns{other.ns }
2025{
2126}
2227
@@ -55,6 +60,49 @@ static exprt encode(const struct_exprt &struct_expr)
5560 return concatenation_exprt{struct_expr.operands (), struct_expr.type ()};
5661}
5762
63+ static std::size_t count_trailing_bit_width (
64+ const struct_typet &type,
65+ const irep_idt name,
66+ const boolbv_widtht &boolbv_width)
67+ {
68+ auto member_component_rit = std::find_if (
69+ type.components ().rbegin (),
70+ type.components ().rend (),
71+ [&](const struct_union_typet::componentt &component) {
72+ return component.get_name () == name;
73+ });
74+ INVARIANT (
75+ member_component_rit != type.components ().rend (),
76+ " Definition of struct type should include named component." );
77+ const auto trailing_widths =
78+ make_range (type.components ().rbegin (), member_component_rit)
79+ .map ([&](const struct_union_typet::componentt &component) -> std::size_t {
80+ return boolbv_width (component.type ());
81+ });
82+ return std::accumulate (
83+ trailing_widths.begin (), trailing_widths.end (), std::size_t {0 });
84+ }
85+
86+ // / The member expression selects the value of a field from a struct. The
87+ // / struct is encoded as a single bitvector where the first field is stored
88+ // / in the highest bits. The second field is stored in the next highest set of
89+ // / bits and so on. As offsets are indexed from the lowest bit, any field can be
90+ // / selected by extracting the range of bits starting from an offset based on
91+ // / the combined width of the fields which follow the field being selected.
92+ exprt struct_encodingt::encode_member (const member_exprt &member_expr) const
93+ {
94+ const auto &struct_type = type_checked_cast<struct_typet>(
95+ ns.get ().follow (member_expr.compound ().type ()));
96+ const std::size_t offset_bits = count_trailing_bit_width (
97+ struct_type, member_expr.get_component_name (), *boolbv_width);
98+ const auto member_bits_width = (*boolbv_width)(member_expr.type ());
99+ return extractbits_exprt{
100+ member_expr.compound (),
101+ offset_bits + member_bits_width - 1 ,
102+ offset_bits,
103+ member_expr.type ()};
104+ }
105+
58106exprt struct_encodingt::encode (exprt expr) const
59107{
60108 std::queue<exprt *> work_queue;
@@ -66,6 +114,8 @@ exprt struct_encodingt::encode(exprt expr) const
66114 current.type () = encode (current.type ());
67115 if (const auto struct_expr = expr_try_dynamic_cast<struct_exprt>(current))
68116 current = ::encode (*struct_expr);
117+ if (const auto member_expr = expr_try_dynamic_cast<member_exprt>(current))
118+ current = encode_member (*member_expr);
69119 for (auto &operand : current.operands ())
70120 work_queue.push (&operand);
71121 }
0 commit comments