Skip to content

Commit af41585

Browse files
Merge pull request #7914 from thomasspriggs/tas/smt_union_tag
Encode union tag types in smt2 decision procedure
2 parents 45860b6 + bd798a1 commit af41585

File tree

2 files changed

+71
-5
lines changed

2 files changed

+71
-5
lines changed

src/solvers/smt2_incremental/encoding/struct_encoding.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <util/arith_tools.h>
66
#include <util/bitvector_expr.h>
77
#include <util/bitvector_types.h>
8+
#include <util/c_types.h>
89
#include <util/make_unique.h>
910
#include <util/namespace.h>
1011
#include <util/range.h>
@@ -29,6 +30,19 @@ struct_encodingt::struct_encodingt(const struct_encodingt &other)
2930

3031
struct_encodingt::~struct_encodingt() = default;
3132

33+
/// If the given \p type needs re-encoding as a bit-vector then this function
34+
/// \returns the width of the new bitvector type. The width calculation is
35+
/// delegated to \p boolbv_width.
36+
static optionalt<std::size_t>
37+
needs_width(const typet &type, const boolbv_widtht &boolbv_width)
38+
{
39+
if(const auto struct_tag = type_try_dynamic_cast<struct_tag_typet>(type))
40+
return boolbv_width(*struct_tag);
41+
if(const auto union_tag = type_try_dynamic_cast<union_tag_typet>(type))
42+
return boolbv_width(*union_tag);
43+
return {};
44+
}
45+
3246
typet struct_encodingt::encode(typet type) const
3347
{
3448
std::queue<typet *> work_queue;
@@ -37,17 +51,16 @@ typet struct_encodingt::encode(typet type) const
3751
{
3852
typet &current = *work_queue.front();
3953
work_queue.pop();
40-
if(const auto struct_tag = type_try_dynamic_cast<struct_tag_typet>(current))
54+
if(auto assigned_bit_width = needs_width(current, *boolbv_width))
4155
{
42-
auto width = (*boolbv_width)(*struct_tag);
4356
// The bit vector theory of SMT disallows zero bit length length bit
4457
// vectors. C++ gives a minimum size for a struct (even an empty struct)
4558
// as being one byte; in order to ensure that structs have unique memory
4659
// locations. Therefore encoding empty structs as having 8 bits / 1 byte
4760
// is a reasonable solution in this case.
48-
if(width == 0)
49-
width = 8;
50-
current = bv_typet{width};
61+
if(*assigned_bit_width == 0)
62+
assigned_bit_width = 8;
63+
current = bv_typet{*assigned_bit_width};
5164
}
5265
if(const auto array = type_try_dynamic_cast<array_typet>(current))
5366
{

unit/solvers/smt2_incremental/encoding/struct_encoding.cpp

Lines changed: 53 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/c_types.h>
67
#include <util/mathematical_types.h>
78
#include <util/namespace.h>
89
#include <util/symbol_table.h>
@@ -71,6 +72,58 @@ TEST_CASE("struct encoding of types", "[core][smt2_incremental]")
7172
}
7273
}
7374

75+
TEST_CASE("Encoding of union types", "[core][smt2_incremental]")
76+
{
77+
auto test = struct_encoding_test_environmentt::make();
78+
SECTION("Two components")
79+
{
80+
const struct_union_typet::componentst components{
81+
{"foo", unsignedbv_typet{8}}, {"bar", signedbv_typet{16}}};
82+
union_typet union_type{components};
83+
type_symbolt type_symbol{"my_uniont", union_type, ID_C};
84+
test.symbol_table.insert(type_symbol);
85+
union_tag_typet union_tag{type_symbol.name};
86+
SECTION("Direct union_tag_type encoding")
87+
{
88+
REQUIRE(test.struct_encoding.encode(union_tag) == bv_typet{16});
89+
}
90+
SECTION("Array of unions encoding")
91+
{
92+
const auto index_type = signedbv_typet{32};
93+
const auto array_size = from_integer(5, index_type);
94+
array_typet array_of_struct{union_tag, array_size};
95+
array_typet expected_encoded_array{bv_typet{16}, array_size};
96+
REQUIRE(
97+
test.struct_encoding.encode(array_of_struct) == expected_encoded_array);
98+
}
99+
SECTION("Array of array of unions encoding")
100+
{
101+
const auto index_type = signedbv_typet{32};
102+
const auto array_size_inner = from_integer(4, index_type);
103+
const auto array_size_outer = from_integer(2, index_type);
104+
array_typet array_of_struct{union_tag, array_size_inner};
105+
array_typet array_of_array_of_struct{array_of_struct, array_size_outer};
106+
array_typet expected_encoded_array{
107+
array_typet{bv_typet{16}, array_size_inner}, array_size_outer};
108+
REQUIRE(
109+
test.struct_encoding.encode(array_of_array_of_struct) ==
110+
expected_encoded_array);
111+
}
112+
}
113+
SECTION("Empty union")
114+
{
115+
const struct_union_typet::componentst components{};
116+
union_typet union_type{components};
117+
type_symbolt type_symbol{"my_empty_uniont", union_type, ID_C};
118+
test.symbol_table.insert(type_symbol);
119+
union_tag_typet union_tag{type_symbol.name};
120+
SECTION("Direct union_tag_type encoding")
121+
{
122+
REQUIRE(test.struct_encoding.encode(union_tag) == bv_typet{8});
123+
}
124+
}
125+
}
126+
74127
exprt make_member_name_expression(const irep_idt component_name)
75128
{
76129
exprt result{ID_member_name};

0 commit comments

Comments
 (0)