Skip to content

Commit cf88f82

Browse files
authored
Merge pull request diffblue#5872 from tautschnig/simplify-overflow
Simplify overflow-* expressions
2 parents b26d347 + e6943df commit cf88f82

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#ifdef _MSC_VER
2+
# define _Static_assert static_assert
3+
#endif
4+
5+
int main()
6+
{
7+
_Static_assert(!__CPROVER_overflow_plus(1, 2), "");
8+
_Static_assert(__CPROVER_overflow_minus(1U, 2U), "");
9+
_Static_assert(__CPROVER_overflow_minus(0U, 2U), "");
10+
_Static_assert(!__CPROVER_overflow_mult(1U, 2U), "");
11+
_Static_assert(!__CPROVER_overflow_shl(1, 2), "");
12+
_Static_assert(!__CPROVER_overflow_unary_minus(1), "");
13+
_Static_assert(__CPROVER_overflow_unary_minus(1U), "");
14+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring

src/util/simplify_expr.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,6 +2047,117 @@ simplify_exprt::simplify_complex(const unary_exprt &expr)
20472047
return unchanged(expr);
20482048
}
20492049

2050+
simplify_exprt::resultt<>
2051+
simplify_exprt::simplify_overflow_binary(const binary_exprt &expr)
2052+
{
2053+
// zero is a neutral element for all operations supported here
2054+
if(
2055+
expr.op1().is_zero() ||
2056+
(expr.op0().is_zero() && expr.id() != ID_overflow_minus))
2057+
{
2058+
return false_exprt{};
2059+
}
2060+
2061+
// we only handle the case of same operand types
2062+
if(expr.op0().type() != expr.op1().type())
2063+
return unchanged(expr);
2064+
2065+
// catch some cases over mathematical types
2066+
const irep_idt &op_type_id = expr.op0().type().id();
2067+
if(
2068+
op_type_id == ID_integer || op_type_id == ID_rational ||
2069+
op_type_id == ID_real)
2070+
{
2071+
return false_exprt{};
2072+
}
2073+
2074+
if(op_type_id == ID_natural && expr.id() != ID_overflow_minus)
2075+
return false_exprt{};
2076+
2077+
// we only handle constants over signedbv/unsignedbv for the remaining cases
2078+
if(op_type_id != ID_signedbv && op_type_id != ID_unsignedbv)
2079+
return unchanged(expr);
2080+
2081+
if(!expr.op0().is_constant() || !expr.op1().is_constant())
2082+
return unchanged(expr);
2083+
2084+
const auto op0_value = numeric_cast<mp_integer>(expr.op0());
2085+
const auto op1_value = numeric_cast<mp_integer>(expr.op1());
2086+
if(!op0_value.has_value() || !op1_value.has_value())
2087+
return unchanged(expr);
2088+
2089+
mp_integer no_overflow_result;
2090+
if(expr.id() == ID_overflow_plus)
2091+
no_overflow_result = *op0_value + *op1_value;
2092+
else if(expr.id() == ID_overflow_minus)
2093+
no_overflow_result = *op0_value - *op1_value;
2094+
else if(expr.id() == ID_overflow_mult)
2095+
no_overflow_result = *op0_value * *op1_value;
2096+
else if(expr.id() == ID_overflow_shl)
2097+
no_overflow_result = *op0_value << *op1_value;
2098+
else
2099+
UNREACHABLE;
2100+
2101+
const std::size_t width = to_bitvector_type(expr.op0().type()).get_width();
2102+
const integer_bitvector_typet bv_type{op_type_id, width};
2103+
if(
2104+
no_overflow_result < bv_type.smallest() ||
2105+
no_overflow_result > bv_type.largest())
2106+
{
2107+
return true_exprt{};
2108+
}
2109+
else
2110+
return false_exprt{};
2111+
}
2112+
2113+
simplify_exprt::resultt<>
2114+
simplify_exprt::simplify_overflow_unary(const unary_exprt &expr)
2115+
{
2116+
// zero is a neutral element for all operations supported here
2117+
if(expr.op().is_zero())
2118+
return false_exprt{};
2119+
2120+
// catch some cases over mathematical types
2121+
const irep_idt &op_type_id = expr.op().type().id();
2122+
if(
2123+
op_type_id == ID_integer || op_type_id == ID_rational ||
2124+
op_type_id == ID_real)
2125+
{
2126+
return false_exprt{};
2127+
}
2128+
2129+
if(op_type_id == ID_natural)
2130+
return true_exprt{};
2131+
2132+
// we only handle constants over signedbv/unsignedbv for the remaining cases
2133+
if(op_type_id != ID_signedbv && op_type_id != ID_unsignedbv)
2134+
return unchanged(expr);
2135+
2136+
if(!expr.op().is_constant())
2137+
return unchanged(expr);
2138+
2139+
const auto op_value = numeric_cast<mp_integer>(expr.op());
2140+
if(!op_value.has_value())
2141+
return unchanged(expr);
2142+
2143+
mp_integer no_overflow_result;
2144+
if(expr.id() == ID_overflow_unary_minus)
2145+
no_overflow_result = -*op_value;
2146+
else
2147+
UNREACHABLE;
2148+
2149+
const std::size_t width = to_bitvector_type(expr.op().type()).get_width();
2150+
const integer_bitvector_typet bv_type{op_type_id, width};
2151+
if(
2152+
no_overflow_result < bv_type.smallest() ||
2153+
no_overflow_result > bv_type.largest())
2154+
{
2155+
return true_exprt{};
2156+
}
2157+
else
2158+
return false_exprt{};
2159+
}
2160+
20502161
bool simplify_exprt::simplify_node_preorder(exprt &expr)
20512162
{
20522163
bool result=true;
@@ -2290,6 +2401,16 @@ simplify_exprt::resultt<> simplify_exprt::simplify_node(exprt node)
22902401
{
22912402
r = simplify_complex(to_unary_expr(expr));
22922403
}
2404+
else if(
2405+
expr.id() == ID_overflow_plus || expr.id() == ID_overflow_minus ||
2406+
expr.id() == ID_overflow_mult || expr.id() == ID_overflow_shl)
2407+
{
2408+
r = simplify_overflow_binary(to_binary_expr(expr));
2409+
}
2410+
else if(expr.id() == ID_overflow_unary_minus)
2411+
{
2412+
r = simplify_overflow_unary(to_unary_expr(expr));
2413+
}
22932414

22942415
if(!no_change_join_operands)
22952416
r = changed(r);

src/util/simplify_expr_class.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,16 @@ class simplify_exprt
185185
NODISCARD resultt<> simplify_popcount(const popcount_exprt &);
186186
NODISCARD resultt<> simplify_complex(const unary_exprt &);
187187

188+
/// Try to simplify overflow-+, overflow-*, overflow--, overflow-shl.
189+
/// Simplification will be possible when the operands are constants or the
190+
/// types of the operands have infinite domains.
191+
NODISCARD resultt<> simplify_overflow_binary(const binary_exprt &);
192+
193+
/// Try to simplify overflow-unary-.
194+
/// Simplification will be possible when the operand is constants or the
195+
/// type of the operand has an infinite domain.
196+
NODISCARD resultt<> simplify_overflow_unary(const unary_exprt &);
197+
188198
/// Attempt to simplify mathematical function applications if we have
189199
/// enough information to do so. Currently focused on constant comparisons.
190200
NODISCARD resultt<>

0 commit comments

Comments
 (0)