Skip to content

Commit 9527c69

Browse files
committed
Add encoding of member expressions in new SMT decision procedure
1 parent 396549d commit 9527c69

File tree

3 files changed

+98
-2
lines changed

3 files changed

+98
-2
lines changed

src/solvers/smt2_incremental/encoding/struct_encoding.cpp

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,23 @@
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

1317
struct_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

1822
struct_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+
58106
exprt 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
}

src/solvers/smt2_incremental/encoding/struct_encoding.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
class namespacet;
1212
class boolbv_widtht;
13+
class member_exprt;
1314

1415
/// Encodes struct types/values into non-struct expressions/types.
1516
class struct_encodingt final
@@ -24,6 +25,9 @@ class struct_encodingt final
2425

2526
private:
2627
std::unique_ptr<boolbv_widtht> boolbv_width;
28+
std::reference_wrapper<const namespacet> ns;
29+
30+
exprt encode_member(const member_exprt &member_expr) const;
2731
};
2832

2933
#endif // CPROVER_SOLVERS_SMT2_INCREMENTAL_STRUCT_ENCODING_H

unit/solvers/smt2_incremental/encoding/struct_encoding.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <util/arith_tools.h>
44
#include <util/bitvector_expr.h>
55
#include <util/bitvector_types.h>
6+
#include <util/mathematical_types.h>
67
#include <util/namespace.h>
78
#include <util/symbol_table.h>
89

@@ -108,6 +109,47 @@ TEST_CASE("struct encoding of expressions", "[core][smt2_incremental]")
108109
{green_ham.symbol_expr(), forty_two, minus_one}, bv_typet{72}};
109110
REQUIRE(test.struct_encoding.encode(struct_expr) == expected_result);
110111
}
112+
SECTION("member expression selecting a data member of a struct")
113+
{
114+
const symbolt breakfast{"breakfast", struct_tag, ID_C};
115+
test.symbol_table.insert(breakfast);
116+
SECTION("First member")
117+
{
118+
const typet field_type = signedbv_typet{32};
119+
const exprt zero = from_integer(0, field_type);
120+
const exprt input = equal_exprt{
121+
zero, member_exprt{breakfast.symbol_expr(), "green", field_type}};
122+
const exprt expected = equal_exprt{
123+
zero,
124+
extractbits_exprt{
125+
symbol_exprt{"breakfast", bv_typet{72}}, 71, 40, field_type}};
126+
REQUIRE(test.struct_encoding.encode(input) == expected);
127+
}
128+
SECTION("Second member")
129+
{
130+
const typet field_type = unsignedbv_typet{16};
131+
const exprt dozen = from_integer(12, field_type);
132+
const exprt input = equal_exprt{
133+
dozen, member_exprt{breakfast.symbol_expr(), "eggs", field_type}};
134+
const exprt expected = equal_exprt{
135+
dozen,
136+
extractbits_exprt{
137+
symbol_exprt{"breakfast", bv_typet{72}}, 39, 24, field_type}};
138+
REQUIRE(test.struct_encoding.encode(input) == expected);
139+
}
140+
SECTION("Third member")
141+
{
142+
const typet field_type = signedbv_typet{24};
143+
const exprt two = from_integer(2, field_type);
144+
const exprt input = equal_exprt{
145+
two, member_exprt{breakfast.symbol_expr(), "ham", field_type}};
146+
const exprt expected = equal_exprt{
147+
two,
148+
extractbits_exprt{
149+
symbol_exprt{"breakfast", bv_typet{72}}, 23, 0, field_type}};
150+
REQUIRE(test.struct_encoding.encode(input) == expected);
151+
}
152+
}
111153
}
112154

113155
TEST_CASE(

0 commit comments

Comments
 (0)