Skip to content

Commit 643037e

Browse files
authored
Merge pull request #6676 from NlightNFotis/bitwise_ops
2 parents 3410558 + 05e1fd6 commit 643037e

File tree

3 files changed

+535
-49
lines changed

3 files changed

+535
-49
lines changed

src/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 113 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,47 @@
2121
#include <functional>
2222
#include <numeric>
2323

24+
/// \brief Converts operator expressions with 2 or more operands to terms
25+
/// expressed as binary operator application.
26+
/// \param expr: The expression to convert.
27+
/// \param factory: The factory function which makes applications of the
28+
/// relevant smt term, when applied to the term operands.
29+
/// \details The conversion used is left associative for instances with 3 or
30+
/// more operands. The SMT standard / core theory version 2.6 actually
31+
/// supports applying the `and`, `or` and `xor` to 3 or more operands.
32+
/// However our internal `smt_core_theoryt` does not support this currently
33+
/// and converting to binary application has the advantage of making the order
34+
/// of evaluation explicit.
35+
template <typename factoryt>
36+
static smt_termt convert_multiary_operator_to_terms(
37+
const multi_ary_exprt &expr,
38+
const factoryt &factory)
39+
{
40+
PRECONDITION(expr.operands().size() >= 2);
41+
const auto operand_terms =
42+
make_range(expr.operands()).map([](const exprt &expr) {
43+
return convert_expr_to_smt(expr);
44+
});
45+
return std::accumulate(
46+
++operand_terms.begin(),
47+
operand_terms.end(),
48+
*operand_terms.begin(),
49+
factory);
50+
}
51+
52+
/// \brief Ensures that all operands of the argument expression have related
53+
/// types.
54+
/// \param expr: The expression of which the operands we evaluate for type
55+
/// equality.
56+
template <typename target_typet>
57+
static bool operands_are_of_type(const exprt &expr)
58+
{
59+
return std::all_of(
60+
expr.operands().cbegin(), expr.operands().cend(), [](const exprt &operand) {
61+
return can_cast_type<target_typet>(operand.type());
62+
});
63+
}
64+
2465
static smt_sortt convert_type_to_smt_sort(const bool_typet &type)
2566
{
2667
return smt_bool_sortt{};
@@ -126,30 +167,64 @@ static smt_termt convert_expr_to_smt(const concatenation_exprt &concatenation)
126167

127168
static smt_termt convert_expr_to_smt(const bitand_exprt &bitwise_and_expr)
128169
{
129-
UNIMPLEMENTED_FEATURE(
130-
"Generation of SMT formula for bitwise and expression: " +
131-
bitwise_and_expr.pretty());
170+
if(operands_are_of_type<integer_bitvector_typet>(bitwise_and_expr))
171+
{
172+
return convert_multiary_operator_to_terms(
173+
bitwise_and_expr, smt_bit_vector_theoryt::make_and);
174+
}
175+
else
176+
{
177+
UNIMPLEMENTED_FEATURE(
178+
"Generation of SMT formula for bitwise and expression: " +
179+
bitwise_and_expr.pretty());
180+
}
132181
}
133182

134183
static smt_termt convert_expr_to_smt(const bitor_exprt &bitwise_or_expr)
135184
{
136-
UNIMPLEMENTED_FEATURE(
137-
"Generation of SMT formula for bitwise or expression: " +
138-
bitwise_or_expr.pretty());
185+
if(operands_are_of_type<integer_bitvector_typet>(bitwise_or_expr))
186+
{
187+
return convert_multiary_operator_to_terms(
188+
bitwise_or_expr, smt_bit_vector_theoryt::make_or);
189+
}
190+
else
191+
{
192+
UNIMPLEMENTED_FEATURE(
193+
"Generation of SMT formula for bitwise or expression: " +
194+
bitwise_or_expr.pretty());
195+
}
139196
}
140197

141198
static smt_termt convert_expr_to_smt(const bitxor_exprt &bitwise_xor)
142199
{
143-
UNIMPLEMENTED_FEATURE(
144-
"Generation of SMT formula for bitwise xor expression: " +
145-
bitwise_xor.pretty());
200+
if(operands_are_of_type<integer_bitvector_typet>(bitwise_xor))
201+
{
202+
return convert_multiary_operator_to_terms(
203+
bitwise_xor, smt_bit_vector_theoryt::make_xor);
204+
}
205+
else
206+
{
207+
UNIMPLEMENTED_FEATURE(
208+
"Generation of SMT formula for bitwise xor expression: " +
209+
bitwise_xor.pretty());
210+
}
146211
}
147212

148213
static smt_termt convert_expr_to_smt(const bitnot_exprt &bitwise_not)
149214
{
150-
UNIMPLEMENTED_FEATURE(
151-
"Generation of SMT formula for bitwise not expression: " +
152-
bitwise_not.pretty());
215+
const bool operand_is_bitvector =
216+
can_cast_type<integer_bitvector_typet>(bitwise_not.op().type());
217+
218+
if(operand_is_bitvector)
219+
{
220+
return smt_bit_vector_theoryt::make_not(
221+
convert_expr_to_smt(bitwise_not.op()));
222+
}
223+
else
224+
{
225+
UNIMPLEMENTED_FEATURE(
226+
"Generation of SMT formula for bitnot_exprt: " + bitwise_not.pretty());
227+
}
153228
}
154229

155230
static smt_termt convert_expr_to_smt(const unary_minus_exprt &unary_minus)
@@ -191,34 +266,6 @@ static smt_termt convert_expr_to_smt(const if_exprt &if_expression)
191266
convert_expr_to_smt(if_expression.false_case()));
192267
}
193268

194-
/// \brief Converts operator expressions with 2 or more operands to terms
195-
/// expressed as binary operator application.
196-
/// \param expr: The expression to convert.
197-
/// \param factory: The factory function which makes applications of the
198-
/// relevant smt term, when applied to the term operands.
199-
/// \details The conversion used is left associative for instances with 3 or
200-
/// more operands. The SMT standard / core theory version 2.6 actually
201-
/// supports applying the `and`, `or` and `xor` to 3 or more operands.
202-
/// However our internal `smt_core_theoryt` does not support this currently
203-
/// and converting to binary application has the advantage of making the order
204-
/// of evaluation explicit.
205-
template <typename factoryt>
206-
static smt_termt convert_multiary_operator_to_terms(
207-
const multi_ary_exprt &expr,
208-
const factoryt &factory)
209-
{
210-
PRECONDITION(expr.operands().size() >= 2);
211-
const auto operand_terms =
212-
make_range(expr.operands()).map([](const exprt &expr) {
213-
return convert_expr_to_smt(expr);
214-
});
215-
return std::accumulate(
216-
++operand_terms.begin(),
217-
operand_terms.end(),
218-
*operand_terms.begin(),
219-
factory);
220-
}
221-
222269
static smt_termt convert_expr_to_smt(const and_exprt &and_expression)
223270
{
224271
return convert_multiary_operator_to_terms(
@@ -498,9 +545,32 @@ static smt_termt convert_expr_to_smt(const index_exprt &index)
498545

499546
static smt_termt convert_expr_to_smt(const shift_exprt &shift)
500547
{
501-
// TODO: split into functions for separate types of shift including rotate.
502-
UNIMPLEMENTED_FEATURE(
503-
"Generation of SMT formula for shift expression: " + shift.pretty());
548+
// TODO: Dispatch into different types of shifting
549+
const auto &first_operand = shift.op0();
550+
const auto &second_operand = shift.op1();
551+
552+
if(const auto left_shift = expr_try_dynamic_cast<shl_exprt>(shift))
553+
{
554+
return smt_bit_vector_theoryt::shift_left(
555+
convert_expr_to_smt(first_operand), convert_expr_to_smt(second_operand));
556+
}
557+
else if(
558+
const auto right_logical_shift = expr_try_dynamic_cast<lshr_exprt>(shift))
559+
{
560+
return smt_bit_vector_theoryt::logical_shift_right(
561+
convert_expr_to_smt(first_operand), convert_expr_to_smt(second_operand));
562+
}
563+
else if(
564+
const auto right_arith_shift = expr_try_dynamic_cast<ashr_exprt>(shift))
565+
{
566+
return smt_bit_vector_theoryt::arithmetic_shift_right(
567+
convert_expr_to_smt(first_operand), convert_expr_to_smt(second_operand));
568+
}
569+
else
570+
{
571+
UNIMPLEMENTED_FEATURE(
572+
"Generation of SMT formula for shift expression: " + shift.pretty());
573+
}
504574
}
505575

506576
static smt_termt convert_expr_to_smt(const with_exprt &with)

src/util/bitvector_expr.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,12 @@ class shl_exprt : public shift_exprt
305305
}
306306
};
307307

308+
template <>
309+
inline bool can_cast_expr<shl_exprt>(const exprt &base)
310+
{
311+
return base.id() == ID_shl;
312+
}
313+
308314
/// \brief Cast an exprt to a \ref shl_exprt
309315
///
310316
/// \a expr must be known to be \ref shl_exprt.
@@ -343,6 +349,12 @@ class ashr_exprt : public shift_exprt
343349
}
344350
};
345351

352+
template <>
353+
inline bool can_cast_expr<ashr_exprt>(const exprt &base)
354+
{
355+
return base.id() == ID_ashr;
356+
}
357+
346358
/// \brief Logical right shift
347359
class lshr_exprt : public shift_exprt
348360
{
@@ -358,6 +370,12 @@ class lshr_exprt : public shift_exprt
358370
}
359371
};
360372

373+
template <>
374+
inline bool can_cast_expr<lshr_exprt>(const exprt &base)
375+
{
376+
return base.id() == ID_lshr;
377+
}
378+
361379
/// \brief Extracts a single bit of a bit-vector operand
362380
class extractbit_exprt : public binary_predicate_exprt
363381
{

0 commit comments

Comments
 (0)