Skip to content

Commit 5ecedf8

Browse files
committed
Add support for converting mismatched shift operands to smt
In order to bring this conversion closer to parity with the old SMT backend. Shift operations of this kind have been seen during testing of the overflow operations, which is work which will be submitted in a following PR.
1 parent 283d3bd commit 5ecedf8

File tree

2 files changed

+116
-5
lines changed

2 files changed

+116
-5
lines changed

src/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,16 @@ static smt_termt convert_c_bool_cast(
121121
smt_bit_vector_constant_termt{0, c_bool_width});
122122
}
123123

124+
static std::function<std::function<smt_termt(smt_termt)>(std::size_t)>
125+
extension_for_type(const typet &type)
126+
{
127+
if(can_cast_type<signedbv_typet>(type))
128+
return smt_bit_vector_theoryt::sign_extend;
129+
if(can_cast_type<unsignedbv_typet>(type))
130+
return smt_bit_vector_theoryt::zero_extend;
131+
UNREACHABLE;
132+
}
133+
124134
static smt_termt make_bitvector_resize_cast(
125135
const smt_termt &from_term,
126136
const bitvector_typet &from_type,
@@ -147,10 +157,7 @@ static smt_termt make_bitvector_resize_cast(
147157
if(to_width < from_width)
148158
return smt_bit_vector_theoryt::extract(to_width - 1, 0)(from_term);
149159
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);
160+
return extension_for_type(from_type)(extension_size)(from_term);
154161
}
155162

156163
struct sort_based_cast_to_bit_vector_convertert final
@@ -658,7 +665,33 @@ convert_to_smt_shift(const factoryt &factory, const shiftt &shift)
658665
{
659666
const smt_termt first_operand = convert_expr_to_smt(shift.op0());
660667
const smt_termt second_operand = convert_expr_to_smt(shift.op1());
661-
return factory(first_operand, second_operand);
668+
const auto first_bit_vector_sort =
669+
first_operand.get_sort().cast<smt_bit_vector_sortt>();
670+
const auto second_bit_vector_sort =
671+
second_operand.get_sort().cast<smt_bit_vector_sortt>();
672+
INVARIANT(
673+
first_bit_vector_sort && second_bit_vector_sort,
674+
"Shift expressions are expected to have bit vector operands.");
675+
const std::size_t first_width = first_bit_vector_sort->bit_width();
676+
const std::size_t second_width = second_bit_vector_sort->bit_width();
677+
if(first_width > second_width)
678+
{
679+
return factory(
680+
first_operand,
681+
extension_for_type(shift.op1().type())(first_width - second_width)(
682+
second_operand));
683+
}
684+
else if(first_width < second_width)
685+
{
686+
return factory(
687+
extension_for_type(shift.op0().type())(second_width - first_width)(
688+
first_operand),
689+
second_operand);
690+
}
691+
else
692+
{
693+
return factory(first_operand, second_operand);
694+
}
662695
}
663696

664697
static smt_termt convert_expr_to_smt(const shift_exprt &shift)

unit/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,84 @@ SCENARIO(
819819
}
820820
}
821821

822+
TEST_CASE(
823+
"expr to smt conversion for shifts of mismatched operands.",
824+
"[core][smt2_incremental]")
825+
{
826+
using make_typet = std::function<typet(std::size_t)>;
827+
const make_typet make_unsigned = constructor_oft<unsignedbv_typet>{};
828+
const make_typet make_signed = constructor_oft<signedbv_typet>{};
829+
using make_extensiont =
830+
std::function<std::function<smt_termt(smt_termt)>(std::size_t)>;
831+
const make_extensiont zero_extend = smt_bit_vector_theoryt::zero_extend;
832+
const make_extensiont sign_extend = smt_bit_vector_theoryt::sign_extend;
833+
std::string type_description;
834+
make_typet make_type;
835+
make_extensiont make_extension;
836+
using type_rowt = std::tuple<std::string, make_typet, make_extensiont>;
837+
std::tie(type_description, make_type, make_extension) = GENERATE_REF(
838+
type_rowt{"Unsigned operands.", make_unsigned, zero_extend},
839+
type_rowt{"Signed operands.", make_signed, sign_extend});
840+
SECTION(type_description)
841+
{
842+
using make_shift_exprt = std::function<exprt(exprt, exprt)>;
843+
const make_shift_exprt left_shift_expr = constructor_of<shl_exprt>();
844+
const make_shift_exprt arithmetic_right_shift_expr =
845+
constructor_of<ashr_exprt>();
846+
const make_shift_exprt logical_right_shift_expr =
847+
constructor_of<lshr_exprt>();
848+
using make_shift_termt = std::function<smt_termt(smt_termt, smt_termt)>;
849+
const make_shift_termt left_shift_term = smt_bit_vector_theoryt::shift_left;
850+
const make_shift_termt arithmetic_right_shift_term =
851+
smt_bit_vector_theoryt::arithmetic_shift_right;
852+
const make_shift_termt logical_right_shift_term =
853+
smt_bit_vector_theoryt::logical_shift_right;
854+
std::string shift_description;
855+
make_shift_exprt make_shift_expr;
856+
make_shift_termt make_shift_term;
857+
using shift_rowt =
858+
std::tuple<std::string, make_shift_exprt, make_shift_termt>;
859+
std::tie(shift_description, make_shift_expr, make_shift_term) =
860+
GENERATE_REF(
861+
shift_rowt{"Left shift.", left_shift_expr, left_shift_term},
862+
shift_rowt{
863+
"Arithmetic right shift.",
864+
arithmetic_right_shift_expr,
865+
arithmetic_right_shift_term},
866+
shift_rowt{
867+
"Logical right shift.",
868+
logical_right_shift_expr,
869+
logical_right_shift_term});
870+
SECTION(shift_description)
871+
{
872+
SECTION("Wider left hand side")
873+
{
874+
const exprt input = make_shift_expr(
875+
symbol_exprt{"foo", make_type(32)},
876+
symbol_exprt{"bar", make_type(8)});
877+
INFO("Input expr: " + input.pretty(2, 0));
878+
const smt_termt expected_result = make_shift_term(
879+
smt_identifier_termt{"foo", smt_bit_vector_sortt{32}},
880+
make_extension(24)(
881+
smt_identifier_termt{"bar", smt_bit_vector_sortt{8}}));
882+
CHECK(convert_expr_to_smt(input) == expected_result);
883+
}
884+
SECTION("Wider right hand side")
885+
{
886+
const exprt input = make_shift_expr(
887+
symbol_exprt{"foo", make_type(8)},
888+
symbol_exprt{"bar", make_type(32)});
889+
INFO("Input expr: " + input.pretty(2, 0));
890+
const smt_termt expected_result = make_shift_term(
891+
make_extension(24)(
892+
smt_identifier_termt{"foo", smt_bit_vector_sortt{8}}),
893+
smt_identifier_termt{"bar", smt_bit_vector_sortt{32}});
894+
CHECK(convert_expr_to_smt(input) == expected_result);
895+
}
896+
}
897+
}
898+
}
899+
822900
TEST_CASE(
823901
"expr to smt conversion for extract bits expressions",
824902
"[core][smt2_incremental]")

0 commit comments

Comments
 (0)