Skip to content

Commit 5b8e8fa

Browse files
authored
Merge pull request #6200 from diffblue/euclidean_mod
Introduce euclidean_mod expression
2 parents 657a891 + 2cf5418 commit 5b8e8fa

File tree

5 files changed

+75
-3
lines changed

5 files changed

+75
-3
lines changed

src/solvers/smt2/smt2_conv.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,6 +1285,10 @@ void smt2_convt::convert_expr(const exprt &expr)
12851285
{
12861286
convert_mod(to_mod_expr(expr));
12871287
}
1288+
else if(expr.id() == ID_euclidean_mod)
1289+
{
1290+
convert_euclidean_mod(to_euclidean_mod_expr(expr));
1291+
}
12881292
else if(expr.id()==ID_mult)
12891293
{
12901294
convert_mult(to_mult_expr(expr));
@@ -2988,6 +2992,21 @@ void smt2_convt::convert_constant(const constant_exprt &expr)
29882992
UNEXPECTEDCASE("unknown constant: "+expr_type.id_string());
29892993
}
29902994

2995+
void smt2_convt::convert_euclidean_mod(const euclidean_mod_exprt &expr)
2996+
{
2997+
if(expr.type().id() == ID_integer)
2998+
{
2999+
out << "(mod ";
3000+
convert_expr(expr.op0());
3001+
out << ' ';
3002+
convert_expr(expr.op1());
3003+
out << ')';
3004+
}
3005+
else
3006+
UNEXPECTEDCASE(
3007+
"unsupported type for euclidean_mod: " + expr.type().id_string());
3008+
}
3009+
29913010
void smt2_convt::convert_mod(const mod_exprt &expr)
29923011
{
29933012
if(expr.type().id()==ID_unsignedbv ||

src/solvers/smt2/smt2_conv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ class smt2_convt : public stack_decision_proceduret
120120
void convert_floatbv_div(const ieee_float_op_exprt &expr);
121121
void convert_floatbv_mult(const ieee_float_op_exprt &expr);
122122
void convert_mod(const mod_exprt &expr);
123+
void convert_euclidean_mod(const euclidean_mod_exprt &expr);
123124
void convert_index(const index_exprt &expr);
124125
void convert_member(const member_exprt &expr);
125126

src/solvers/smt2/smt2_parser.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1123,7 +1123,12 @@ void smt2_parsert::setup_expressions()
11231123
// We don't have that.
11241124
expressions["bvsmod"] = [this] { return bv_mod(operands(), true); };
11251125

1126-
expressions["%"] = [this] { return binary(ID_mod, operands()); };
1126+
expressions["mod"] = [this] {
1127+
// SMT-LIB2 uses Boute's Euclidean definition for mod,
1128+
// which is never negative and undefined when the second
1129+
// argument is zero.
1130+
return binary(ID_euclidean_mod, operands());
1131+
};
11271132

11281133
expressions["concat"] = [this] {
11291134
auto op = operands();

src/util/irep_ids.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ IREP_ID_ONE(array_equal)
235235
IREP_ID_ONE(array_set)
236236
IREP_ID_ONE(array_copy)
237237
IREP_ID_ONE(array_list)
238+
IREP_ID_ONE(euclidean_mod)
238239
IREP_ID_ONE(mod)
239240
IREP_ID_ONE(rem)
240241
IREP_ID_ONE(shr)

src/util/std_expr.h

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,8 +1043,10 @@ inline div_exprt &to_div_expr(exprt &expr)
10431043
return ret;
10441044
}
10451045

1046-
1047-
/// \brief Modulo
1046+
/// \brief Modulo defined as lhs-(rhs * truncate(lhs/rhs)).
1047+
/// The sign follows the lhs or dividend. This matches C99 and
1048+
/// SMT-LIB's bvsrem but differs from the Euclidian definition
1049+
/// and from SMT-LIB's bvsmod.
10481050
class mod_exprt:public binary_exprt
10491051
{
10501052
public:
@@ -1088,6 +1090,50 @@ inline mod_exprt &to_mod_expr(exprt &expr)
10881090
return ret;
10891091
}
10901092

1093+
/// \brief Boute's Euclidean definition of Modulo -- to match SMT-LIB2
1094+
class euclidean_mod_exprt : public binary_exprt
1095+
{
1096+
public:
1097+
euclidean_mod_exprt(exprt _lhs, exprt _rhs)
1098+
: binary_exprt(std::move(_lhs), ID_euclidean_mod, std::move(_rhs))
1099+
{
1100+
}
1101+
};
1102+
1103+
template <>
1104+
inline bool can_cast_expr<euclidean_mod_exprt>(const exprt &base)
1105+
{
1106+
return base.id() == ID_euclidean_mod;
1107+
}
1108+
1109+
inline void validate_expr(const euclidean_mod_exprt &value)
1110+
{
1111+
validate_operands(value, 2, "Modulo must have two operands");
1112+
}
1113+
1114+
/// \brief Cast an exprt to a \ref euclidean_mod_exprt
1115+
///
1116+
/// \a expr must be known to be \ref euclidean_mod_exprt.
1117+
///
1118+
/// \param expr: Source expression
1119+
/// \return Object of type \ref euclidean_mod_exprt
1120+
inline const euclidean_mod_exprt &to_euclidean_mod_expr(const exprt &expr)
1121+
{
1122+
PRECONDITION(expr.id() == ID_euclidean_mod);
1123+
const euclidean_mod_exprt &ret =
1124+
static_cast<const euclidean_mod_exprt &>(expr);
1125+
validate_expr(ret);
1126+
return ret;
1127+
}
1128+
1129+
/// \copydoc to_euclidean_mod_expr(const exprt &)
1130+
inline euclidean_mod_exprt &to_euclidean_mod_expr(exprt &expr)
1131+
{
1132+
PRECONDITION(expr.id() == ID_euclidean_mod);
1133+
euclidean_mod_exprt &ret = static_cast<euclidean_mod_exprt &>(expr);
1134+
validate_expr(ret);
1135+
return ret;
1136+
}
10911137

10921138
/// \brief Remainder of division
10931139
class rem_exprt:public binary_exprt

0 commit comments

Comments
 (0)