Skip to content

Commit 0af5559

Browse files
Merge pull request #6519 from thomasspriggs/tas/smt_to_expr
Add construction of value `exprt`s from smt terms.
2 parents 41f65a0 + 3055754 commit 0af5559

File tree

5 files changed

+242
-0
lines changed

5 files changed

+242
-0
lines changed

src/solvers/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ SRC = $(BOOLEFORCE_SRC) \
193193
smt2/smt2_parser.cpp \
194194
smt2/smt2_tokenizer.cpp \
195195
smt2/smt2irep.cpp \
196+
smt2_incremental/construct_value_expr_from_smt.cpp \
196197
smt2_incremental/convert_expr_to_smt.cpp \
197198
smt2_incremental/smt_bit_vector_theory.cpp \
198199
smt2_incremental/smt_commands.cpp \
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Author: Diffblue Ltd.
2+
3+
#include <solvers/smt2_incremental/construct_value_expr_from_smt.h>
4+
5+
#include <solvers/smt2_incremental/smt_terms.h>
6+
7+
#include <util/arith_tools.h>
8+
#include <util/bitvector_types.h>
9+
#include <util/std_expr.h>
10+
#include <util/std_types.h>
11+
#include <util/type.h>
12+
13+
class value_expr_from_smt_factoryt : public smt_term_const_downcast_visitort
14+
{
15+
private:
16+
const typet &type_to_construct;
17+
optionalt<exprt> result;
18+
19+
explicit value_expr_from_smt_factoryt(const typet &type_to_construct)
20+
: type_to_construct{type_to_construct}, result{}
21+
{
22+
}
23+
24+
void visit(const smt_bool_literal_termt &bool_literal) override
25+
{
26+
INVARIANT(
27+
type_to_construct == bool_typet{},
28+
"Bool terms may only be used to construct bool typed expressions.");
29+
result = bool_literal.value() ? (exprt)true_exprt{} : false_exprt{};
30+
}
31+
32+
void visit(const smt_identifier_termt &identifier_term) override
33+
{
34+
INVARIANT(
35+
false, "Unexpected conversion of identifier to value expression.");
36+
}
37+
38+
void visit(const smt_bit_vector_constant_termt &bit_vector_constant) override
39+
{
40+
if(
41+
const auto integer_type =
42+
type_try_dynamic_cast<integer_bitvector_typet>(type_to_construct))
43+
{
44+
INVARIANT(
45+
integer_type->get_width() == bit_vector_constant.get_sort().bit_width(),
46+
"Width of smt bit vector term must match the width of bit vector "
47+
"type.");
48+
result = from_integer(bit_vector_constant.value(), type_to_construct);
49+
return;
50+
}
51+
52+
INVARIANT(
53+
false,
54+
"construct_value_expr_from_smt for bit vector should not be applied to "
55+
"unsupported type " +
56+
type_to_construct.pretty());
57+
}
58+
59+
void
60+
visit(const smt_function_application_termt &function_application) override
61+
{
62+
INVARIANT(
63+
false,
64+
"Unexpected conversion of function application to value expression.");
65+
}
66+
67+
public:
68+
/// \brief This function is complete the external interface to this class. All
69+
/// construction of this class and construction of expressions should be
70+
/// carried out via this function.
71+
static exprt make(const smt_termt &value_term, const typet &type_to_construct)
72+
{
73+
value_expr_from_smt_factoryt factory{type_to_construct};
74+
value_term.accept(factory);
75+
INVARIANT(factory.result.has_value(), "Factory must result in expr value.");
76+
return *factory.result;
77+
}
78+
};
79+
80+
exprt construct_value_expr_from_smt(
81+
const smt_termt &value_term,
82+
const typet &type_to_construct)
83+
{
84+
return value_expr_from_smt_factoryt::make(value_term, type_to_construct);
85+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Author: Diffblue Ltd.
2+
3+
#ifndef CPROVER_SOLVERS_SMT2_INCREMENTAL_CONSTRUCT_VALUE_EXPR_FROM_SMT_H
4+
#define CPROVER_SOLVERS_SMT2_INCREMENTAL_CONSTRUCT_VALUE_EXPR_FROM_SMT_H
5+
6+
#include <util/expr.h>
7+
8+
class smt_termt;
9+
class typet;
10+
11+
/// \brief Given a \p value_term and a \p type_to_construct, this function
12+
/// constructs a value exprt with a value based on \p value_term and a type of
13+
/// \p type_to_construct.
14+
/// \param value_term
15+
/// This must be a "simple" term encoding a value. It must not be a term
16+
/// requiring any kind of further evaluation to get a value, such as would be
17+
/// the case for identifiers or function applications.
18+
/// \param type_to_construct
19+
/// The type which the constructed expr returned is expected to have. This
20+
/// type must be compatible with the sort of \p value_term.
21+
/// \note The type is required separately in order to carry out this conversion,
22+
/// because the smt value term does not contain all the required information.
23+
/// For example an 8 bit, bit vector with a value of 255 could be used to
24+
/// construct an `unsigned char` with the value 255 or alternatively a
25+
/// `signed char` with the value -1. So these alternatives are disambiguated
26+
/// using the type.
27+
exprt construct_value_expr_from_smt(
28+
const smt_termt &value_term,
29+
const typet &type_to_construct);
30+
31+
#endif // CPROVER_SOLVERS_SMT2_INCREMENTAL_CONSTRUCT_VALUE_EXPR_FROM_SMT_H

unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ SRC += analyses/ai/ai.cpp \
100100
solvers/sat/satcheck_minisat2.cpp \
101101
solvers/smt2/smt2_conv.cpp \
102102
solvers/smt2/smt2irep.cpp \
103+
solvers/smt2_incremental/construct_value_expr_from_smt.cpp \
103104
solvers/smt2_incremental/convert_expr_to_smt.cpp \
104105
solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp \
105106
solvers/smt2_incremental/smt_bit_vector_theory.cpp \
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// Author: Diffblue Ltd.
2+
3+
#include <testing-utils/use_catch.h>
4+
5+
#include <solvers/smt2_incremental/construct_value_expr_from_smt.h>
6+
7+
#include <solvers/smt2_incremental/smt_core_theory.h>
8+
#include <solvers/smt2_incremental/smt_terms.h>
9+
#include <solvers/smt2_incremental/smt_to_smt2_string.h>
10+
11+
#include <testing-utils/invariant.h>
12+
13+
#include <util/arith_tools.h>
14+
#include <util/bitvector_types.h>
15+
#include <util/mp_arith.h>
16+
#include <util/std_expr.h>
17+
#include <util/std_types.h>
18+
19+
#include <string>
20+
21+
static mp_integer power2(unsigned exponent)
22+
{
23+
mp_integer result;
24+
result.setPower2(exponent);
25+
return result;
26+
}
27+
28+
/// Returns the maximum integer value which can be stored in \p bits as an
29+
/// unsigned integer.
30+
static mp_integer max_int(const std::size_t bits)
31+
{
32+
return power2(bits) - 1;
33+
}
34+
35+
TEST_CASE("Value expr construction from smt.", "[core][smt2_incremental]")
36+
{
37+
optionalt<smt_termt> input_term;
38+
optionalt<exprt> expected_result;
39+
40+
using rowt = std::pair<smt_termt, exprt>;
41+
42+
// clang-format off
43+
#define UNSIGNED_BIT_VECTOR_TESTS(bits) \
44+
rowt{smt_bit_vector_constant_termt{0, (bits)}, \
45+
from_integer(0, unsignedbv_typet{(bits)})}, \
46+
rowt{smt_bit_vector_constant_termt{42, (bits)}, \
47+
from_integer(42, unsignedbv_typet{(bits)})}, \
48+
rowt{smt_bit_vector_constant_termt{max_int((bits) - 1), (bits)}, \
49+
from_integer(max_int((bits) - 1), unsignedbv_typet{(bits)})}, \
50+
rowt{smt_bit_vector_constant_termt{power2((bits) - 1), (bits)}, \
51+
from_integer(power2((bits) - 1), unsignedbv_typet{(bits)})}, \
52+
rowt{smt_bit_vector_constant_termt{max_int((bits)), (bits)}, \
53+
from_integer(max_int((bits)), unsignedbv_typet{(bits)})}
54+
55+
#define SIGNED_BIT_VECTOR_TESTS(bits) \
56+
rowt{smt_bit_vector_constant_termt{0, (bits)}, \
57+
from_integer(0, signedbv_typet{(bits)})}, \
58+
rowt{smt_bit_vector_constant_termt{42, (bits)}, \
59+
from_integer(42, signedbv_typet{(bits)})}, \
60+
rowt{smt_bit_vector_constant_termt{max_int((bits) - 1), (bits)}, \
61+
from_integer(max_int((bits) - 1), signedbv_typet{(bits)})}, \
62+
rowt{smt_bit_vector_constant_termt{power2((bits) - 1), (bits)}, \
63+
from_integer(-power2((bits) - 1), signedbv_typet{(bits)})}, \
64+
rowt{smt_bit_vector_constant_termt{max_int((bits)), (bits)}, \
65+
from_integer(-1, signedbv_typet{(bits)})}
66+
// clang-format on
67+
68+
std::tie(input_term, expected_result) = GENERATE(
69+
rowt{smt_bool_literal_termt{true}, true_exprt{}},
70+
rowt{smt_bool_literal_termt{false}, false_exprt{}},
71+
UNSIGNED_BIT_VECTOR_TESTS(8),
72+
SIGNED_BIT_VECTOR_TESTS(8),
73+
UNSIGNED_BIT_VECTOR_TESTS(16),
74+
SIGNED_BIT_VECTOR_TESTS(16),
75+
UNSIGNED_BIT_VECTOR_TESTS(32),
76+
SIGNED_BIT_VECTOR_TESTS(32),
77+
UNSIGNED_BIT_VECTOR_TESTS(64),
78+
SIGNED_BIT_VECTOR_TESTS(64));
79+
SECTION(
80+
"Construction of \"" + id2string(expected_result->type().id()) +
81+
"\" from \"" + smt_to_smt2_string(*input_term) + "\"")
82+
{
83+
REQUIRE(
84+
construct_value_expr_from_smt(*input_term, expected_result->type()) ==
85+
*expected_result);
86+
}
87+
}
88+
89+
TEST_CASE(
90+
"Invariant violations in value expr construction from smt.",
91+
"[core][smt2_incremental]")
92+
{
93+
optionalt<smt_termt> input_term;
94+
optionalt<typet> input_type;
95+
std::string invariant_reason;
96+
97+
using rowt = std::tuple<smt_termt, typet, std::string>;
98+
std::tie(input_term, input_type, invariant_reason) = GENERATE(
99+
rowt{smt_bool_literal_termt{true},
100+
unsignedbv_typet{16},
101+
"Bool terms may only be used to construct bool typed expressions."},
102+
rowt{smt_identifier_termt{"foo", smt_bit_vector_sortt{16}},
103+
unsignedbv_typet{16},
104+
"Unexpected conversion of identifier to value expression."},
105+
rowt{
106+
smt_bit_vector_constant_termt{0, 8},
107+
unsignedbv_typet{16},
108+
"Width of smt bit vector term must match the width of bit vector type."},
109+
rowt{smt_bit_vector_constant_termt{0, 8},
110+
empty_typet{},
111+
"construct_value_expr_from_smt for bit vector should not be applied "
112+
"to unsupported type empty"},
113+
rowt{smt_core_theoryt::make_not(smt_bool_literal_termt{true}),
114+
unsignedbv_typet{16},
115+
"Unexpected conversion of function application to value expression."});
116+
SECTION(invariant_reason)
117+
{
118+
const cbmc_invariants_should_throwt invariants_throw;
119+
REQUIRE_THROWS_MATCHES(
120+
construct_value_expr_from_smt(*input_term, *input_type),
121+
invariant_failedt,
122+
invariant_failure_containing(invariant_reason));
123+
}
124+
}

0 commit comments

Comments
 (0)