Skip to content

Commit 05d1529

Browse files
committed
SMT2 backend: implement saturating arithmetic
This adds support for saturating addition and subtraction to the SMT2 backend.
1 parent 7a4328a commit 05d1529

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

0 commit comments

Comments
 (0)