Skip to content

Commit f259dc0

Browse files
committed
Add (unsigned) remainder (modulus) arithmetic operator bvurem.
Along with tests of its conversion and the function application factory integrity.
1 parent 0c4a39b commit f259dc0

File tree

5 files changed

+86
-3
lines changed

5 files changed

+86
-3
lines changed

src/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,9 +400,22 @@ static smt_termt convert_expr_to_smt(const ieee_float_op_exprt &float_operation)
400400

401401
static smt_termt convert_expr_to_smt(const mod_exprt &truncation_modulo)
402402
{
403-
UNIMPLEMENTED_FEATURE(
404-
"Generation of SMT formula for truncation modulo expression: " +
405-
truncation_modulo.pretty());
403+
const bool both_operands_bitvector =
404+
can_cast_type<integer_bitvector_typet>(truncation_modulo.lhs().type()) &&
405+
can_cast_type<integer_bitvector_typet>(truncation_modulo.rhs().type());
406+
407+
if(both_operands_bitvector)
408+
{
409+
return smt_bit_vector_theoryt::unsigned_remainder(
410+
convert_expr_to_smt(truncation_modulo.lhs()),
411+
convert_expr_to_smt(truncation_modulo.rhs()));
412+
}
413+
else
414+
{
415+
UNIMPLEMENTED_FEATURE(
416+
"Generation of SMT formula for remainder (modulus) expression: " +
417+
truncation_modulo.pretty());
418+
}
406419
}
407420

408421
static smt_termt

src/solvers/smt2_incremental/smt_bit_vector_theory.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,26 @@ void smt_bit_vector_theoryt::signed_dividet::validate(
319319
const smt_function_application_termt::factoryt<
320320
smt_bit_vector_theoryt::signed_dividet>
321321
smt_bit_vector_theoryt::signed_divide{};
322+
323+
const char *smt_bit_vector_theoryt::unsigned_remaindert::identifier()
324+
{
325+
return "bvurem";
326+
}
327+
328+
smt_sortt smt_bit_vector_theoryt::unsigned_remaindert::return_sort(
329+
const smt_termt &lhs,
330+
const smt_termt &rhs)
331+
{
332+
return lhs.get_sort();
333+
}
334+
335+
void smt_bit_vector_theoryt::unsigned_remaindert::validate(
336+
const smt_termt &lhs,
337+
const smt_termt &rhs)
338+
{
339+
validate_bit_vector_predicate_arguments(lhs, rhs);
340+
}
341+
342+
const smt_function_application_termt::factoryt<
343+
smt_bit_vector_theoryt::unsigned_remaindert>
344+
smt_bit_vector_theoryt::unsigned_remainder{};

src/solvers/smt2_incremental/smt_bit_vector_theory.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,15 @@ class smt_bit_vector_theoryt
126126
};
127127
static const smt_function_application_termt::factoryt<signed_dividet>
128128
signed_divide;
129+
130+
struct unsigned_remaindert final
131+
{
132+
static const char *identifier();
133+
static smt_sortt return_sort(const smt_termt &lhs, const smt_termt &rhs);
134+
static void validate(const smt_termt &lhs, const smt_termt &rhs);
135+
};
136+
static const smt_function_application_termt::factoryt<unsigned_remaindert>
137+
unsigned_remainder;
129138
};
130139

131140
#endif // CPROVER_SOLVERS_SMT2_INCREMENTAL_SMT_BIT_VECTOR_THEORY_H

unit/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,4 +372,23 @@ TEST_CASE(
372372
const cbmc_invariants_should_throwt invariants_throw;
373373
REQUIRE_THROWS(convert_expr_to_smt(div_exprt{one_bvint, false_exprt{}}));
374374
}
375+
376+
SECTION(
377+
"Unsigned remainder (modulus) from truncating division of two constant "
378+
"size bit-vectors")
379+
{
380+
const auto constructed_term =
381+
convert_expr_to_smt(mod_exprt{one_bvint_unsigned, two_bvint_unsigned});
382+
const auto expected_term =
383+
smt_bit_vector_theoryt::unsigned_remainder(smt_term_one, smt_term_two);
384+
CHECK(constructed_term == expected_term);
385+
}
386+
387+
SECTION(
388+
"Ensure that remainder (truncated modulo) node conversion fails if the "
389+
"operands are not bit-vector based")
390+
{
391+
const cbmc_invariants_should_throwt invariants_throw;
392+
REQUIRE_THROWS(convert_expr_to_smt(mod_exprt{one_bvint, false_exprt{}}));
393+
}
375394
}

unit/solvers/smt2_incremental/smt_bit_vector_theory.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,4 +271,23 @@ TEST_CASE(
271271
// A division of a bool and a bitvector should hit an invariant violation.
272272
REQUIRE_THROWS(smt_bit_vector_theoryt::signed_divide(true_val, three));
273273
}
274+
275+
SECTION("Unsigned Remainder")
276+
{
277+
const auto function_application =
278+
smt_bit_vector_theoryt::unsigned_remainder(two, three);
279+
REQUIRE(
280+
function_application.function_identifier() ==
281+
smt_identifier_termt("bvurem", smt_bit_vector_sortt{8}));
282+
REQUIRE(function_application.get_sort() == smt_bit_vector_sortt{8});
283+
REQUIRE(function_application.arguments().size() == 2);
284+
REQUIRE(function_application.arguments()[0].get() == two);
285+
REQUIRE(function_application.arguments()[1].get() == three);
286+
287+
cbmc_invariants_should_throwt invariants_throw;
288+
// Bit-vectors of mismatched sorts are going to hit an invariant violation.
289+
REQUIRE_THROWS(smt_bit_vector_theoryt::unsigned_remainder(three, four));
290+
// A remainder of a bool and a bitvector should hit an invariant violation.
291+
REQUIRE_THROWS(smt_bit_vector_theoryt::unsigned_remainder(true_val, three));
292+
}
274293
}

0 commit comments

Comments
 (0)