Skip to content

Commit 307a04d

Browse files
committed
Implement conversion of bit vector casts into SMT2 terms
1 parent eb210d0 commit 307a04d

File tree

2 files changed

+155
-1
lines changed

2 files changed

+155
-1
lines changed

src/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ static smt_termt make_not_zero(const smt_termt &input, const typet &source_type)
112112
static smt_termt convert_c_bool_cast(
113113
const smt_termt &from_term,
114114
const typet &from_type,
115-
const c_bool_typet &to_type)
115+
const bitvector_typet &to_type)
116116
{
117117
const std::size_t c_bool_width = to_type.get_width();
118118
return smt_core_theoryt::if_then_else(
@@ -121,6 +121,83 @@ static smt_termt convert_c_bool_cast(
121121
smt_bit_vector_constant_termt{0, c_bool_width});
122122
}
123123

124+
static smt_termt make_bitvector_resize_cast(
125+
const smt_termt &from_term,
126+
const bitvector_typet &from_type,
127+
const bitvector_typet &to_type)
128+
{
129+
if(const auto to_fixedbv_type = type_try_dynamic_cast<fixedbv_typet>(to_type))
130+
{
131+
UNIMPLEMENTED_FEATURE(
132+
"Generation of SMT formula for type cast to fixed-point bitvector "
133+
"type: " +
134+
to_type.pretty());
135+
}
136+
if(const auto to_floatbv_type = type_try_dynamic_cast<floatbv_typet>(to_type))
137+
{
138+
UNIMPLEMENTED_FEATURE(
139+
"Generation of SMT formula for type cast to floating-point bitvector "
140+
"type: " +
141+
to_type.pretty());
142+
}
143+
const std::size_t from_width = from_type.get_width();
144+
const std::size_t to_width = to_type.get_width();
145+
if(to_width == from_width)
146+
return from_term;
147+
if(to_width < from_width)
148+
return smt_bit_vector_theoryt::extract(to_width - 1, 0)(from_term);
149+
const std::size_t extension_size = to_width - from_width;
150+
if(can_cast_type<signedbv_typet>(from_type))
151+
return smt_bit_vector_theoryt::sign_extend(extension_size)(from_term);
152+
else
153+
return smt_bit_vector_theoryt::zero_extend(extension_size)(from_term);
154+
}
155+
156+
struct sort_based_cast_to_bit_vector_convertert final
157+
: public smt_sort_const_downcast_visitort
158+
{
159+
const smt_termt &from_term;
160+
const typet &from_type;
161+
const bitvector_typet &to_type;
162+
optionalt<smt_termt> result;
163+
164+
sort_based_cast_to_bit_vector_convertert(
165+
const smt_termt &from_term,
166+
const typet &from_type,
167+
const bitvector_typet &to_type)
168+
: from_term{from_term}, from_type{from_type}, to_type{to_type}
169+
{
170+
}
171+
172+
void visit(const smt_bool_sortt &) override
173+
{
174+
result = convert_c_bool_cast(
175+
from_term, from_type, c_bool_typet{to_type.get_width()});
176+
}
177+
178+
void visit(const smt_bit_vector_sortt &) override
179+
{
180+
if(const auto bitvector = type_try_dynamic_cast<bitvector_typet>(from_type))
181+
result = make_bitvector_resize_cast(from_term, *bitvector, to_type);
182+
else
183+
UNIMPLEMENTED_FEATURE(
184+
"Generation of SMT formula for type cast to bit vector from type: " +
185+
from_type.pretty());
186+
}
187+
};
188+
189+
static smt_termt convert_bit_vector_cast(
190+
const smt_termt &from_term,
191+
const typet &from_type,
192+
const bitvector_typet &to_type)
193+
{
194+
sort_based_cast_to_bit_vector_convertert converter{
195+
from_term, from_type, to_type};
196+
from_term.get_sort().accept(converter);
197+
POSTCONDITION(converter.result);
198+
return *converter.result;
199+
}
200+
124201
static smt_termt convert_expr_to_smt(const typecast_exprt &cast)
125202
{
126203
const auto from_term = convert_expr_to_smt(cast.op());
@@ -130,6 +207,8 @@ static smt_termt convert_expr_to_smt(const typecast_exprt &cast)
130207
return make_not_zero(from_term, cast.op().type());
131208
if(const auto c_bool_type = type_try_dynamic_cast<c_bool_typet>(to_type))
132209
return convert_c_bool_cast(from_term, from_type, *c_bool_type);
210+
if(const auto bit_vector = type_try_dynamic_cast<bitvector_typet>(to_type))
211+
return convert_bit_vector_cast(from_term, from_type, *bit_vector);
133212
UNIMPLEMENTED_FEATURE(
134213
"Generation of SMT formula for type cast expression: " + cast.pretty());
135214
}

unit/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <util/bitvector_types.h>
66
#include <util/c_types.h>
77
#include <util/config.h>
8+
#include <util/constructor_of.h>
89
#include <util/format.h>
910
#include <util/std_expr.h>
1011

@@ -865,4 +866,78 @@ TEST_CASE("expr to smt conversion for type casts", "[core][smt2_incremental]")
865866
CHECK(cast_bit_vector == expected_bit_vector_conversion);
866867
}
867868
}
869+
SECTION("Casts to bit vector")
870+
{
871+
SECTION("Matched width casts")
872+
{
873+
typet from_type, to_type;
874+
using rowt = std::pair<typet, typet>;
875+
std::tie(from_type, to_type) = GENERATE(
876+
rowt{unsignedbv_typet{8}, unsignedbv_typet{8}},
877+
rowt{unsignedbv_typet{8}, signedbv_typet{8}},
878+
rowt{signedbv_typet{8}, unsignedbv_typet{8}});
879+
CHECK(
880+
convert_expr_to_smt(
881+
typecast_exprt{from_integer(1, from_type), to_type}) ==
882+
smt_bit_vector_constant_termt{1, 8});
883+
}
884+
SECTION("Narrowing casts")
885+
{
886+
CHECK(
887+
convert_expr_to_smt(typecast_exprt{bv_expr, signedbv_typet{8}}) ==
888+
smt_bit_vector_theoryt::extract(7, 0)(bv_term));
889+
CHECK(
890+
convert_expr_to_smt(typecast_exprt{
891+
from_integer(42, unsignedbv_typet{32}), unsignedbv_typet{16}}) ==
892+
smt_bit_vector_theoryt::extract(15, 0)(
893+
smt_bit_vector_constant_termt{42, 32}));
894+
}
895+
SECTION("Widening casts")
896+
{
897+
std::size_t from_width, to_width, extension_width;
898+
using size_rowt = std::tuple<std::size_t, std::size_t, std::size_t>;
899+
std::tie(from_width, to_width, extension_width) = GENERATE(
900+
size_rowt{8, 64, 56}, size_rowt{16, 32, 16}, size_rowt{16, 128, 112});
901+
PRECONDITION(from_width < to_width);
902+
PRECONDITION(to_width - from_width == extension_width);
903+
using make_typet = std::function<typet(std::size_t)>;
904+
const make_typet make_unsigned = constructor_oft<unsignedbv_typet>{};
905+
const make_typet make_signed = constructor_oft<signedbv_typet>{};
906+
using make_extensiont =
907+
std::function<std::function<smt_termt(smt_termt)>(std::size_t)>;
908+
const make_extensiont zero_extend = smt_bit_vector_theoryt::zero_extend;
909+
const make_extensiont sign_extend = smt_bit_vector_theoryt::sign_extend;
910+
make_typet make_source_type, make_destination_type;
911+
make_extensiont make_extension;
912+
using types_rowt = std::tuple<make_typet, make_typet, make_extensiont>;
913+
std::tie(make_source_type, make_destination_type, make_extension) =
914+
GENERATE_REF(
915+
types_rowt{make_unsigned, make_unsigned, zero_extend},
916+
types_rowt{make_signed, make_signed, sign_extend},
917+
types_rowt{make_signed, make_unsigned, sign_extend},
918+
types_rowt{make_unsigned, make_signed, zero_extend});
919+
const typecast_exprt cast{
920+
from_integer(42, make_source_type(from_width)),
921+
make_destination_type(to_width)};
922+
const smt_termt expected_term = make_extension(extension_width)(
923+
smt_bit_vector_constant_termt{42, from_width});
924+
CHECK(convert_expr_to_smt(cast) == expected_term);
925+
}
926+
SECTION("from bool")
927+
{
928+
const exprt from_expr = GENERATE(
929+
exprt{symbol_exprt{"baz", bool_typet{}}},
930+
exprt{true_exprt{}},
931+
exprt{false_exprt{}});
932+
const smt_termt from_term = convert_expr_to_smt(from_expr);
933+
const std::size_t width = GENERATE(1, 8, 16, 32, 64);
934+
const typecast_exprt cast{from_expr, bitvector_typet{ID_bv, width}};
935+
CHECK(
936+
convert_expr_to_smt(cast) ==
937+
smt_core_theoryt::if_then_else(
938+
from_term,
939+
smt_bit_vector_constant_termt{1, width},
940+
smt_bit_vector_constant_termt{0, width}));
941+
}
942+
}
868943
}

0 commit comments

Comments
 (0)