Skip to content

Commit 455cf80

Browse files
author
Enrico Steffinlongo
committed
Add lowering for byte extraction and update
When the input program includes non-aligned memory accesses the decision procedure is passed expressions including byte_extract and byte_update operators. To support such programs in the decision procedure we need to lower such operators to operators we support.
1 parent 8c88392 commit 455cf80

File tree

2 files changed

+184
-11
lines changed

2 files changed

+184
-11
lines changed

src/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <util/string_utils.h>
1212
#include <util/symbol.h>
1313

14+
#include <solvers/lowering/expr_lowering.h>
1415
#include <solvers/smt2_incremental/ast/smt_commands.h>
1516
#include <solvers/smt2_incremental/ast/smt_responses.h>
1617
#include <solvers/smt2_incremental/ast/smt_terms.h>
@@ -257,19 +258,23 @@ smt2_incremental_decision_proceduret::smt2_incremental_decision_proceduret(
257258
}
258259

259260
void smt2_incremental_decision_proceduret::ensure_handle_for_expr_defined(
260-
const exprt &expr)
261+
const exprt &in_expr)
261262
{
262263
if(
263-
expression_handle_identifiers.find(expr) !=
264+
expression_handle_identifiers.find(in_expr) !=
264265
expression_handle_identifiers.cend())
265266
{
266267
return;
267268
}
268269

269-
define_dependent_functions(expr);
270+
const exprt lowered_expr = lower_byte_operators(in_expr, ns);
271+
272+
define_dependent_functions(lowered_expr);
270273
smt_define_function_commandt function{
271-
"B" + std::to_string(handle_sequence()), {}, convert_expr_to_smt(expr)};
272-
expression_handle_identifiers.emplace(expr, function.identifier());
274+
"B" + std::to_string(handle_sequence()),
275+
{},
276+
convert_expr_to_smt(lowered_expr)};
277+
expression_handle_identifiers.emplace(in_expr, function.identifier());
273278
identifier_table.emplace(
274279
function.identifier().identifier(), function.identifier());
275280
solver_process->send(function);
@@ -484,22 +489,25 @@ smt2_incremental_decision_proceduret::get_number_of_solver_calls() const
484489
return number_of_solver_calls;
485490
}
486491

487-
void smt2_incremental_decision_proceduret::set_to(const exprt &expr, bool value)
492+
void smt2_incremental_decision_proceduret::set_to(
493+
const exprt &in_expr,
494+
bool value)
488495
{
489-
PRECONDITION(can_cast_type<bool_typet>(expr.type()));
496+
const exprt lowered_expr = lower_byte_operators(in_expr, ns);
497+
PRECONDITION(can_cast_type<bool_typet>(lowered_expr.type()));
490498
log.conditional_output(log.debug(), [&](messaget::mstreamt &debug) {
491499
debug << "`set_to` (" << std::string{value ? "true" : "false"} << ") -\n "
492-
<< expr.pretty(2, 0) << messaget::eom;
500+
<< lowered_expr.pretty(2, 0) << messaget::eom;
493501
});
494502

495-
define_dependent_functions(expr);
503+
define_dependent_functions(lowered_expr);
496504
auto converted_term = [&]() -> smt_termt {
497505
const auto expression_handle_identifier =
498-
expression_handle_identifiers.find(expr);
506+
expression_handle_identifiers.find(lowered_expr);
499507
if(expression_handle_identifier != expression_handle_identifiers.cend())
500508
return expression_handle_identifier->second;
501509
else
502-
return convert_expr_to_smt(expr);
510+
return convert_expr_to_smt(lowered_expr);
503511
}();
504512
if(!value)
505513
converted_term = smt_core_theoryt::make_not(converted_term);

unit/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <solvers/smt2_incremental/smt2_incremental_decision_procedure.h>
1616
#include <solvers/smt2_incremental/smt_solver_process.h>
1717
#include <solvers/smt2_incremental/theories/smt_array_theory.h>
18+
#include <solvers/smt2_incremental/theories/smt_bit_vector_theory.h>
1819
#include <solvers/smt2_incremental/theories/smt_core_theory.h>
1920
#include <testing-utils/invariant.h>
2021
#include <testing-utils/use_catch.h>
@@ -23,6 +24,8 @@
2324
// means that we get error messages showing the smt formula expressed as SMT2
2425
// strings instead of `{?}` being printed. It works because catch uses the
2526
// appropriate overload of `operator<<` where it exists.
27+
#include <util/byte_operators.h>
28+
2629
#include <goto-symex/path_storage.h>
2730
#include <solvers/smt2_incremental/smt_to_smt2_string.h>
2831

@@ -734,3 +737,165 @@ TEST_CASE(
734737
smt_assertion};
735738
REQUIRE(test.sent_commands == expected_commands);
736739
}
740+
741+
TEST_CASE(
742+
"smt2_incremental_decision_proceduret byte update-extract commands.",
743+
"[core][smt2_incremental]")
744+
{
745+
auto test = decision_procedure_test_environmentt::make();
746+
SECTION("byte_extract - byte from int correctly extracted.")
747+
{
748+
const auto int64_type = signedbv_typet(64);
749+
const auto byte_type = signedbv_typet(8);
750+
const auto extracted_byte_symbol =
751+
make_test_symbol("extracted_byte", byte_type);
752+
const auto original_int_symbol =
753+
make_test_symbol("original_int", int64_type);
754+
const auto byte_extract = make_byte_extract(
755+
original_int_symbol.symbol_expr(),
756+
from_integer(1, int64_type),
757+
byte_type);
758+
const typecast_exprt typecast_expr{byte_extract, byte_type};
759+
const equal_exprt equal_expr{
760+
extracted_byte_symbol.symbol_expr(), typecast_expr};
761+
test.sent_commands.clear();
762+
test.procedure.set_to(equal_expr, true);
763+
const smt_bit_vector_sortt smt_int64_type{64};
764+
const smt_bit_vector_sortt smt_byte_type{8};
765+
const smt_identifier_termt extracted_byte_term{
766+
"extracted_byte", smt_byte_type};
767+
const smt_identifier_termt original_int{"original_int", smt_int64_type};
768+
const smt_termt smt_equal_term = smt_core_theoryt::equal(
769+
extracted_byte_term,
770+
smt_bit_vector_theoryt::extract(15, 8)(original_int));
771+
const auto smt_assertion = smt_assert_commandt{smt_equal_term};
772+
const std::vector<smt_commandt> expected_commands{
773+
smt_declare_function_commandt(extracted_byte_term, {}),
774+
smt_declare_function_commandt(original_int, {}),
775+
smt_assertion};
776+
REQUIRE(test.sent_commands == expected_commands);
777+
}
778+
SECTION("byte_extract - int from byte correctly extracted.")
779+
{
780+
const auto byte_type = signedbv_typet(8);
781+
const auto int16_type = signedbv_typet(16);
782+
const auto ptr_type = signedbv_typet(32);
783+
const auto extracted_int_symbol =
784+
make_test_symbol("extracted_int", int16_type);
785+
const auto original_byte_array_symbol = make_test_symbol(
786+
"original_byte_array", array_typet(byte_type, from_integer(2, ptr_type)));
787+
const auto byte_extract = make_byte_extract(
788+
original_byte_array_symbol.symbol_expr(),
789+
from_integer(0, ptr_type),
790+
int16_type);
791+
const equal_exprt equal_expr{
792+
extracted_int_symbol.symbol_expr(), byte_extract};
793+
test.sent_commands.clear();
794+
test.procedure.set_to(equal_expr, true);
795+
const smt_bit_vector_sortt smt_int16_type{16};
796+
const smt_bit_vector_sortt smt_ptr_type{32};
797+
const smt_bit_vector_sortt smt_byte_type{8};
798+
const smt_identifier_termt extracted_int_term{
799+
"extracted_int", smt_int16_type};
800+
const smt_identifier_termt original_byte_array_term{
801+
"original_byte_array", smt_array_sortt{smt_ptr_type, smt_byte_type}};
802+
const smt_termt smt_equal_term = smt_core_theoryt::equal(
803+
extracted_int_term,
804+
smt_bit_vector_theoryt::concat(
805+
smt_array_theoryt::select(
806+
original_byte_array_term,
807+
smt_bit_vector_constant_termt{1, smt_ptr_type}),
808+
smt_array_theoryt::select(
809+
original_byte_array_term,
810+
smt_bit_vector_constant_termt{0, smt_ptr_type})));
811+
const auto smt_assertion = smt_assert_commandt{smt_equal_term};
812+
const std::vector<smt_commandt> expected_commands{
813+
smt_declare_function_commandt(extracted_int_term, {}),
814+
smt_declare_function_commandt(original_byte_array_term, {}),
815+
smt_assertion};
816+
REQUIRE(test.sent_commands == expected_commands);
817+
}
818+
SECTION("byte_update - write bytes into int.")
819+
{
820+
const auto int64_type = signedbv_typet(64);
821+
const auto byte_type = signedbv_typet(8);
822+
const auto result_int_symbol = make_test_symbol("result_int", int64_type);
823+
const auto original_int_symbol =
824+
make_test_symbol("original_int", int64_type);
825+
const auto byte_update = make_byte_update(
826+
original_int_symbol.symbol_expr(),
827+
from_integer(1, int64_type),
828+
from_integer(0x0B, byte_type));
829+
const equal_exprt equal_expr{result_int_symbol.symbol_expr(), byte_update};
830+
test.sent_commands.clear();
831+
test.procedure.set_to(equal_expr, true);
832+
const smt_bit_vector_sortt smt_value_type{64};
833+
const smt_identifier_termt result_int_term{"result_int", smt_value_type};
834+
const smt_identifier_termt original_int_term{
835+
"original_int", smt_value_type};
836+
const smt_termt smt_equal_term = smt_core_theoryt::equal(
837+
result_int_term,
838+
smt_bit_vector_theoryt::make_or(
839+
smt_bit_vector_theoryt::make_and(
840+
original_int_term,
841+
smt_bit_vector_constant_termt{0xFFFFFFFFFFFF00FF, 64}),
842+
smt_bit_vector_constant_termt{0x0B00, 64}));
843+
const auto smt_assertion = smt_assert_commandt{smt_equal_term};
844+
const std::vector<smt_commandt> expected_commands{
845+
smt_declare_function_commandt{result_int_term, {}},
846+
smt_declare_function_commandt{original_int_term, {}},
847+
smt_assertion};
848+
REQUIRE(test.sent_commands == expected_commands);
849+
}
850+
SECTION("byte_update - writes int into byte array.")
851+
{
852+
const auto int32_type = signedbv_typet(32);
853+
const auto int16_type = signedbv_typet(16);
854+
const auto byte_type = signedbv_typet(8);
855+
const array_typet byte_array_type{byte_type, from_integer(2, int32_type)};
856+
const auto result_array_symbol =
857+
make_test_symbol("result_array", byte_array_type);
858+
const auto original_array_symbol =
859+
make_test_symbol("original_array", byte_array_type);
860+
const auto byte_update = make_byte_update(
861+
original_array_symbol.symbol_expr(),
862+
from_integer(0, int32_type),
863+
from_integer(0x0102, int16_type));
864+
const equal_exprt equal_expr{
865+
result_array_symbol.symbol_expr(), byte_update};
866+
test.sent_commands.clear();
867+
test.procedure.set_to(equal_expr, true);
868+
const smt_bit_vector_sortt smt_byte_type{8};
869+
const smt_bit_vector_sortt smt_index_type{32};
870+
const smt_array_sortt smt_array_type{smt_index_type, smt_byte_type};
871+
const smt_identifier_termt result_array_term{
872+
"result_array", smt_array_type};
873+
const smt_identifier_termt original_array_term{
874+
"original_array", smt_array_type};
875+
const smt_identifier_termt index_0_term{"index_0", smt_index_type};
876+
const smt_identifier_termt index_1_term{"index_1", smt_index_type};
877+
const smt_termt smt_equal_term = smt_core_theoryt::equal(
878+
result_array_term,
879+
smt_array_theoryt::store(
880+
smt_array_theoryt::store(
881+
original_array_term,
882+
index_0_term,
883+
smt_bit_vector_constant_termt{2, smt_byte_type}),
884+
index_1_term,
885+
smt_bit_vector_constant_termt{1, smt_byte_type}));
886+
const auto smt_assertion = smt_assert_commandt{smt_equal_term};
887+
const std::vector<smt_commandt> expected_commands{
888+
smt_declare_function_commandt{result_array_term, {}},
889+
smt_declare_function_commandt{original_array_term, {}},
890+
smt_define_function_commandt{
891+
index_0_term.identifier(),
892+
{},
893+
smt_bit_vector_constant_termt{0, smt_index_type}},
894+
smt_define_function_commandt{
895+
index_1_term.identifier(),
896+
{},
897+
smt_bit_vector_constant_termt{1, smt_index_type}},
898+
smt_assertion};
899+
REQUIRE(test.sent_commands == expected_commands);
900+
}
901+
}

0 commit comments

Comments
 (0)