Skip to content

Commit 8fd4d0a

Browse files
authored
Merge pull request #7345 from diffblue/smt2_saturating
SMT2 backend: implement saturating arithmetic
2 parents 7bea872 + 05d1529 commit 8fd4d0a

File tree

2 files changed

+76
-1
lines changed

2 files changed

+76
-1
lines changed

regression/cbmc/saturating_arithmetric/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE broken-smt-backend
1+
CORE
22
main.c
33

44
^EXIT=0$

src/solvers/smt2/smt2_conv.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,6 +2208,81 @@ void smt2_convt::convert_expr(const exprt &expr)
22082208
"overflow check should not be performed on unsupported type",
22092209
op_type.id_string());
22102210
}
2211+
else if(expr.id() == ID_saturating_plus || expr.id() == ID_saturating_minus)
2212+
{
2213+
const bool subtract = expr.id() == ID_saturating_minus;
2214+
const auto &op_type = expr.type();
2215+
const auto &op0 = to_binary_expr(expr).op0();
2216+
const auto &op1 = to_binary_expr(expr).op1();
2217+
2218+
if(op_type.id() == ID_signedbv)
2219+
{
2220+
auto width = to_signedbv_type(op_type).get_width();
2221+
2222+
// compute sum with one extra bit
2223+
out << "(let ((?sum (";
2224+
out << (subtract ? "bvsub" : "bvadd");
2225+
out << " ((_ sign_extend 1) ";
2226+
convert_expr(op0);
2227+
out << ")";
2228+
out << " ((_ sign_extend 1) ";
2229+
convert_expr(op1);
2230+
out << ")))) "; // sign_extend, bvadd/sub
2231+
2232+
// pick one of MAX, MIN, or the sum
2233+
out << "(ite (= "
2234+
"((_ extract "
2235+
<< width << " " << width
2236+
<< ") ?sum) "
2237+
"((_ extract "
2238+
<< (width - 1) << " " << (width - 1) << ") ?sum)";
2239+
out << ") "; // =
2240+
2241+
// no overflow and no underflow case, return the sum
2242+
out << "((_ extract " << width - 1 << " 0) ?sum) ";
2243+
2244+
// MAX
2245+
out << "(ite (= ((_ extract " << width << " " << width << ") ?sum) #b0) ";
2246+
convert_expr(to_signedbv_type(op_type).largest_expr());
2247+
2248+
// MIN
2249+
convert_expr(to_signedbv_type(op_type).smallest_expr());
2250+
out << ")))"; // ite, ite, let
2251+
}
2252+
else if(op_type.id() == ID_unsignedbv)
2253+
{
2254+
auto width = to_unsignedbv_type(op_type).get_width();
2255+
2256+
// compute sum with one extra bit
2257+
out << "(let ((?sum (" << (subtract ? "bvsub" : "bvadd");
2258+
out << " ((_ zero_extend 1) ";
2259+
convert_expr(op0);
2260+
out << ")";
2261+
out << " ((_ zero_extend 1) ";
2262+
convert_expr(op1);
2263+
out << "))))"; // zero_extend, bvsub/bvadd
2264+
2265+
// pick one of MAX, MIN, or the sum
2266+
out << "(ite (= ((_ extract " << width << " " << width << ") ?sum) #b0) ";
2267+
2268+
// no overflow and no underflow case, return the sum
2269+
out << " ((_ extract " << width - 1 << " 0) ?sum) ";
2270+
2271+
// overflow when adding, underflow when subtracting
2272+
if(subtract)
2273+
convert_expr(to_unsignedbv_type(op_type).smallest_expr());
2274+
else
2275+
convert_expr(to_unsignedbv_type(op_type).largest_expr());
2276+
2277+
// MIN
2278+
out << "))"; // ite, let
2279+
}
2280+
else
2281+
INVARIANT_WITH_DIAGNOSTICS(
2282+
false,
2283+
"saturating_plus/minus on unsupported type",
2284+
op_type.id_string());
2285+
}
22112286
else if(expr.id()==ID_array)
22122287
{
22132288
defined_expressionst::const_iterator it=defined_expressions.find(expr);

0 commit comments

Comments
 (0)