Skip to content

Commit 43b2ccd

Browse files
committed
SMT-LIB2 parser now models bit-vector division and mod/rem by zero correctly
SMT-LIB2 defines the result of bvsdiv and bvudiv when dividing by zero to be 1...1. The result of bvurem, bvsrem and bvsmod when dividing by zero is the value of the first operand.
1 parent 9a04436 commit 43b2ccd

File tree

3 files changed

+82
-27
lines changed

3 files changed

+82
-27
lines changed

regression/smt2_solver/basic-bv1/basic-bv1.smt2

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,24 @@
88
(define-fun b03 () Bool (= (bvneg #x07) #xf9)) ; unary minus
99
(define-fun b04 () Bool (= (bvmul #x07 #x03) #x15)) ; multiplication
1010
(define-fun b05 () Bool (= (bvurem #x07 #x03) #x01)) ; unsigned remainder
11-
(define-fun b06 () Bool (= (bvsrem #x07 #x03) #x01)) ; signed remainder
12-
(define-fun b07 () Bool (= (bvsmod #x07 #x03) #x01)) ; signed modulo
13-
(define-fun b08 () Bool (= (bvshl #x07 #x03) #x38)) ; shift left
14-
(define-fun b09 () Bool (= (bvlshr #xf0 #x03) #x1e)) ; unsigned (logical) shift right
15-
(define-fun b10 () Bool (= (bvashr #xf0 #x03) #xfe)) ; signed (arithmetical) shift right#x0a
11+
(define-fun b06 () Bool (= (bvurem #x07 #x00) #x07)) ; unsigned remainder (div. by zero)
12+
(define-fun b07 () Bool (= (bvudiv #x01 #x00) #xff)) ; unsigned division (div. by zero)
13+
(define-fun b08 () Bool (= (bvsrem #x07 #x03) #x01)) ; signed remainder
14+
(define-fun b09 () Bool (= (bvsrem #x07 #x00) #x07)) ; signed remainder (div. by zero)
15+
(define-fun b10 () Bool (= (bvsmod #x07 #x03) #x01)) ; signed modulo
16+
(define-fun b11 () Bool (= (bvsmod #x07 #x00) #x07)) ; signed modulo (div. by zero)
17+
(define-fun b12 () Bool (= (bvsdiv #x01 #x00) #xff)) ; signed division (div. by zero)
18+
(define-fun b13 () Bool (= (bvshl #x07 #x03) #x38)) ; shift left
19+
(define-fun b14 () Bool (= (bvlshr #xf0 #x03) #x1e)) ; unsigned (logical) shift right
20+
(define-fun b15 () Bool (= (bvashr #xf0 #x03) #xfe)) ; signed (arithmetical) shift right#x0a
1621

1722
; Multi-ary variants, where applicable
18-
(define-fun b11 () Bool (= (bvadd #x07 #x03 #x01) #x0b)) ; addition
19-
(define-fun b12 () Bool (= (bvmul #x07 #x03 #x01) #x15)) ; multiplication
23+
(define-fun b16 () Bool (= (bvadd #x07 #x03 #x01) #x0b)) ; addition
24+
(define-fun b17 () Bool (= (bvmul #x07 #x03 #x01) #x15)) ; multiplication
2025

2126
; rotation
22-
(define-fun b13 () Bool (= ((_ rotate_left 2) #xf7) #xdf)) ; rotation left
23-
(define-fun b14 () Bool (= ((_ rotate_right 2) #x07) #xc1)) ; rotation right
27+
(define-fun b18 () Bool (= ((_ rotate_left 2) #xf7) #xdf)) ; rotation left
28+
(define-fun b19 () Bool (= ((_ rotate_right 2) #x07) #xc1)) ; rotation right
2429

2530
; Bitwise Operations
2631

@@ -67,7 +72,7 @@
6772
; all must be true
6873

6974
(assert (not (and
70-
b01 b02 b03 b04 b05 b06 b07 b08 b09 b10 b11 b12 b13 b14
75+
b01 b02 b03 b04 b05 b06 b07 b08 b09 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19
7176
d01
7277
power-test
7378
p1 p2 p3 p4 p5 p6 p7 p8)))

src/solvers/smt2/smt2_parser.cpp

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,64 @@ exprt smt2_parsert::function_application()
872872
UNREACHABLE;
873873
}
874874

875+
exprt smt2_parsert::bv_division(
876+
const exprt::operandst &operands,
877+
bool is_signed)
878+
{
879+
if(operands.size() != 2)
880+
throw error() << "bitvector division expects two operands";
881+
882+
// SMT-LIB2 defines the result of division by 0 to be 1....1
883+
auto divisor = symbol_exprt("divisor", operands[1].type());
884+
auto divisor_is_zero = equal_exprt(divisor, from_integer(0, divisor.type()));
885+
auto all_ones = to_unsignedbv_type(operands[0].type()).largest_expr();
886+
887+
exprt division_result;
888+
889+
if(is_signed)
890+
{
891+
auto signed_operands = cast_bv_to_signed({operands[0], divisor});
892+
division_result =
893+
cast_bv_to_unsigned(div_exprt(signed_operands[0], signed_operands[1]));
894+
}
895+
else
896+
division_result = div_exprt(operands[0], divisor);
897+
898+
return let_exprt(
899+
{divisor},
900+
{operands[1]},
901+
if_exprt(divisor_is_zero, all_ones, division_result));
902+
}
903+
904+
exprt smt2_parsert::bv_mod(const exprt::operandst &operands, bool is_signed)
905+
{
906+
if(operands.size() != 2)
907+
throw error() << "bitvector modulo expects two operands";
908+
909+
// SMT-LIB2 defines the result of "lhs modulo 0" to be "lhs"
910+
auto dividend = symbol_exprt("dividend", operands[0].type());
911+
auto divisor = symbol_exprt("divisor", operands[1].type());
912+
auto divisor_is_zero = equal_exprt(divisor, from_integer(0, divisor.type()));
913+
914+
exprt mod_result;
915+
916+
// bvurem and bvsrem match our mod_exprt.
917+
// bvsmod doesn't.
918+
if(is_signed)
919+
{
920+
auto signed_operands = cast_bv_to_signed({dividend, divisor});
921+
mod_result =
922+
cast_bv_to_unsigned(mod_exprt(signed_operands[0], signed_operands[1]));
923+
}
924+
else
925+
mod_result = mod_exprt(dividend, divisor);
926+
927+
return let_exprt(
928+
{dividend, divisor},
929+
{operands[0], operands[1]},
930+
if_exprt(divisor_is_zero, dividend, mod_result));
931+
}
932+
875933
exprt smt2_parsert::expression()
876934
{
877935
switch(next_token())
@@ -1045,27 +1103,17 @@ void smt2_parsert::setup_expressions()
10451103
return binary(ID_minus, op);
10461104
};
10471105

1048-
expressions["bvsdiv"] = [this] {
1049-
return cast_bv_to_unsigned(binary(ID_div, cast_bv_to_signed(operands())));
1050-
};
1051-
1052-
expressions["bvudiv"] = [this] { return binary(ID_div, operands()); };
1106+
expressions["bvsdiv"] = [this] { return bv_division(operands(), true); };
1107+
expressions["bvudiv"] = [this] { return bv_division(operands(), false); };
10531108
expressions["/"] = [this] { return binary(ID_div, operands()); };
10541109
expressions["div"] = [this] { return binary(ID_div, operands()); };
10551110

1056-
expressions["bvsrem"] = [this] {
1057-
// 2's complement signed remainder (sign follows dividend)
1058-
// This matches our ID_mod, and what C does since C99.
1059-
return cast_bv_to_unsigned(binary(ID_mod, cast_bv_to_signed(operands())));
1060-
};
1061-
1062-
expressions["bvsmod"] = [this] {
1063-
// 2's complement signed remainder (sign follows divisor)
1064-
// We don't have that.
1065-
return cast_bv_to_unsigned(binary(ID_mod, cast_bv_to_signed(operands())));
1066-
};
1111+
expressions["bvsrem"] = [this] { return bv_mod(operands(), true); };
1112+
expressions["bvurem"] = [this] { return bv_mod(operands(), false); };
10671113

1068-
expressions["bvurem"] = [this] { return binary(ID_mod, operands()); };
1114+
// 2's complement signed remainder (sign follows divisor)
1115+
// We don't have that.
1116+
expressions["bvsmod"] = [this] { return bv_mod(operands(), true); };
10691117

10701118
expressions["%"] = [this] { return binary(ID_mod, operands()); };
10711119

src/solvers/smt2/smt2_parser.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ class smt2_parsert
162162
exprt binary_predicate(irep_idt, const exprt::operandst &);
163163
exprt binary(irep_idt, const exprt::operandst &);
164164
exprt unary(irep_idt, const exprt::operandst &);
165+
exprt bv_division(const exprt::operandst &, bool is_signed);
166+
exprt bv_mod(const exprt::operandst &, bool is_signed);
165167

166168
exprt let_expression();
167169
exprt quantifier_expression(irep_idt);

0 commit comments

Comments
 (0)