@@ -2047,6 +2047,117 @@ simplify_exprt::simplify_complex(const unary_exprt &expr)
2047
2047
return unchanged (expr);
2048
2048
}
2049
2049
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
+
2050
2161
bool simplify_exprt::simplify_node_preorder (exprt &expr)
2051
2162
{
2052
2163
bool result=true ;
@@ -2290,6 +2401,16 @@ simplify_exprt::resultt<> simplify_exprt::simplify_node(exprt node)
2290
2401
{
2291
2402
r = simplify_complex (to_unary_expr (expr));
2292
2403
}
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
+ }
2293
2414
2294
2415
if (!no_change_join_operands)
2295
2416
r = changed (r);
0 commit comments