Skip to content

Commit 4996426

Browse files
Merge pull request #6744 from thomasspriggs/tas/overflow_expr_classes
Add separate overflow expr classes
2 parents f6054b5 + c0f179c commit 4996426

File tree

10 files changed

+264
-74
lines changed

10 files changed

+264
-74
lines changed

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3161,7 +3161,7 @@ exprt c_typecheck_baset::do_special_functions(
31613161

31623162
typecheck_expr_unary_arithmetic(tmp);
31633163

3164-
unary_overflow_exprt overflow{ID_unary_minus, tmp.operands().front()};
3164+
unary_minus_overflow_exprt overflow{tmp.operands().front()};
31653165
overflow.add_source_location() = tmp.source_location();
31663166
return std::move(overflow);
31673167
}

src/ansi-c/expr2c.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3921,9 +3921,8 @@ std::string expr2ct::convert_with_precedence(
39213921
return convert_cond(src, precedence);
39223922

39233923
else if(
3924-
src.id() == ID_overflow_unary_minus || src.id() == ID_overflow_minus ||
3925-
src.id() == ID_overflow_mult || src.id() == ID_overflow_plus ||
3926-
src.id() == ID_overflow_shl)
3924+
can_cast_expr<unary_minus_overflow_exprt>(src) ||
3925+
can_cast_expr<binary_overflow_exprt>(src))
39273926
{
39283927
return convert_overflow(src, precedence);
39293928
}

src/ansi-c/goto_check_c.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1052,7 +1052,7 @@ void goto_check_ct::integer_overflow_check(
10521052
std::string kind = type.id() == ID_unsignedbv ? "unsigned" : "signed";
10531053

10541054
add_guarded_property(
1055-
not_exprt{unary_overflow_exprt{expr.id(), to_unary_expr(expr).op()}},
1055+
not_exprt{unary_minus_overflow_exprt{to_unary_expr(expr).op()}},
10561056
"arithmetic overflow on " + kind + " " + expr.id_string(),
10571057
"overflow",
10581058
expr.find_source_location(),

src/solvers/flattening/boolbv.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -417,9 +417,8 @@ literalt boolbvt::convert_rest(const exprt &expr)
417417
else if(expr.id()==ID_onehot || expr.id()==ID_onehot0)
418418
return convert_onehot(to_unary_expr(expr));
419419
else if(
420-
expr.id() == ID_overflow_plus || expr.id() == ID_overflow_mult ||
421-
expr.id() == ID_overflow_minus || expr.id() == ID_overflow_shl ||
422-
expr.id() == ID_overflow_unary_minus)
420+
can_cast_expr<binary_overflow_exprt>(expr) ||
421+
can_cast_expr<unary_minus_overflow_exprt>(expr))
423422
{
424423
return convert_overflow(expr);
425424
}

src/solvers/flattening/boolbv_overflow.cpp

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,51 +6,59 @@ Author: Daniel Kroening, [email protected]
66
77
\*******************************************************************/
88

9-
#include "boolbv.h"
10-
9+
#include <util/bitvector_expr.h>
1110
#include <util/invariant.h>
1211

12+
#include "boolbv.h"
13+
1314
literalt boolbvt::convert_overflow(const exprt &expr)
1415
{
15-
if(expr.id()==ID_overflow_plus ||
16-
expr.id()==ID_overflow_minus)
16+
const auto plus_or_minus_conversion =
17+
[&](
18+
const binary_overflow_exprt &overflow_expr,
19+
const std::function<literalt(
20+
bv_utilst *, const bvt &, const bvt &, bv_utilst::representationt)>
21+
&bv_util_overflow) {
22+
const bvt &bv0 = convert_bv(overflow_expr.lhs());
23+
const bvt &bv1 = convert_bv(overflow_expr.rhs());
24+
25+
if(bv0.size() != bv1.size())
26+
return SUB::convert_rest(expr);
27+
28+
bv_utilst::representationt rep =
29+
overflow_expr.lhs().type().id() == ID_signedbv
30+
? bv_utilst::representationt::SIGNED
31+
: bv_utilst::representationt::UNSIGNED;
32+
33+
return bv_util_overflow(&bv_utils, bv0, bv1, rep);
34+
};
35+
if(
36+
const auto plus_overflow = expr_try_dynamic_cast<plus_overflow_exprt>(expr))
1737
{
18-
const auto &overflow_expr = to_binary_expr(expr);
19-
20-
const bvt &bv0 = convert_bv(overflow_expr.lhs());
21-
const bvt &bv1 = convert_bv(overflow_expr.rhs());
22-
23-
if(bv0.size()!=bv1.size())
24-
return SUB::convert_rest(expr);
25-
26-
bv_utilst::representationt rep =
27-
overflow_expr.lhs().type().id() == ID_signedbv
28-
? bv_utilst::representationt::SIGNED
29-
: bv_utilst::representationt::UNSIGNED;
30-
31-
return expr.id()==ID_overflow_minus?
32-
bv_utils.overflow_sub(bv0, bv1, rep):
33-
bv_utils.overflow_add(bv0, bv1, rep);
38+
return plus_or_minus_conversion(*plus_overflow, &bv_utilst::overflow_add);
3439
}
35-
else if(expr.id()==ID_overflow_mult)
40+
if(const auto minus = expr_try_dynamic_cast<minus_overflow_exprt>(expr))
41+
{
42+
return plus_or_minus_conversion(*minus, &bv_utilst::overflow_sub);
43+
}
44+
else if(
45+
const auto mult_overflow = expr_try_dynamic_cast<mult_overflow_exprt>(expr))
3646
{
37-
const auto &overflow_expr = to_binary_expr(expr);
38-
3947
if(
40-
overflow_expr.lhs().type().id() != ID_unsignedbv &&
41-
overflow_expr.lhs().type().id() != ID_signedbv)
48+
mult_overflow->lhs().type().id() != ID_unsignedbv &&
49+
mult_overflow->lhs().type().id() != ID_signedbv)
4250
return SUB::convert_rest(expr);
4351

44-
bvt bv0 = convert_bv(overflow_expr.lhs());
45-
bvt bv1 = convert_bv(overflow_expr.rhs(), bv0.size());
52+
bvt bv0 = convert_bv(mult_overflow->lhs());
53+
bvt bv1 = convert_bv(mult_overflow->rhs(), bv0.size());
4654

4755
bv_utilst::representationt rep =
48-
overflow_expr.lhs().type().id() == ID_signedbv
56+
mult_overflow->lhs().type().id() == ID_signedbv
4957
? bv_utilst::representationt::SIGNED
5058
: bv_utilst::representationt::UNSIGNED;
5159

5260
DATA_INVARIANT(
53-
overflow_expr.lhs().type() == overflow_expr.rhs().type(),
61+
mult_overflow->lhs().type() == mult_overflow->rhs().type(),
5462
"operands of overflow_mult expression shall have same type");
5563

5664
std::size_t old_size=bv0.size();
@@ -89,18 +97,17 @@ literalt boolbvt::convert_overflow(const exprt &expr)
8997
return !prop.lor(all_one, all_zero);
9098
}
9199
}
92-
else if(expr.id() == ID_overflow_shl)
100+
else if(
101+
const auto shl_overflow = expr_try_dynamic_cast<shl_overflow_exprt>(expr))
93102
{
94-
const auto &overflow_expr = to_binary_expr(expr);
95-
96-
const bvt &bv0 = convert_bv(overflow_expr.lhs());
97-
const bvt &bv1 = convert_bv(overflow_expr.rhs());
103+
const bvt &bv0 = convert_bv(shl_overflow->lhs());
104+
const bvt &bv1 = convert_bv(shl_overflow->rhs());
98105

99106
std::size_t old_size = bv0.size();
100107
std::size_t new_size = old_size * 2;
101108

102109
bv_utilst::representationt rep =
103-
overflow_expr.lhs().type().id() == ID_signedbv
110+
shl_overflow->lhs().type().id() == ID_signedbv
104111
? bv_utilst::representationt::SIGNED
105112
: bv_utilst::representationt::UNSIGNED;
106113

@@ -109,7 +116,7 @@ literalt boolbvt::convert_overflow(const exprt &expr)
109116
bvt result=bv_utils.shift(bv_ext, bv_utilst::shiftt::SHIFT_LEFT, bv1);
110117

111118
// a negative shift is undefined; yet this isn't an overflow
112-
literalt neg_shift = overflow_expr.lhs().type().id() == ID_unsignedbv
119+
literalt neg_shift = shl_overflow->lhs().type().id() == ID_unsignedbv
113120
? const_literal(false)
114121
: bv1.back(); // sign bit
115122

@@ -154,11 +161,11 @@ literalt boolbvt::convert_overflow(const exprt &expr)
154161
return
155162
prop.land(!neg_shift, prop.lselect(undef, prop.lor(bv0), overflow));
156163
}
157-
else if(expr.id()==ID_overflow_unary_minus)
164+
else if(
165+
const auto unary_minus_overflow =
166+
expr_try_dynamic_cast<unary_minus_overflow_exprt>(expr))
158167
{
159-
const auto &overflow_expr = to_unary_expr(expr);
160-
161-
const bvt &bv = convert_bv(overflow_expr.op());
168+
const bvt &bv = convert_bv(unary_minus_overflow->op());
162169

163170
return bv_utils.overflow_negate(bv);
164171
}

src/solvers/smt2/smt2_conv.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,8 +1856,9 @@ void smt2_convt::convert_expr(const exprt &expr)
18561856
else
18571857
UNREACHABLE;
18581858
}
1859-
else if(expr.id()==ID_overflow_plus ||
1860-
expr.id()==ID_overflow_minus)
1859+
else if(
1860+
can_cast_expr<plus_overflow_exprt>(expr) ||
1861+
can_cast_expr<minus_overflow_exprt>(expr))
18611862
{
18621863
const auto &op0 = to_binary_expr(expr).op0();
18631864
const auto &op1 = to_binary_expr(expr).op1();
@@ -1866,7 +1867,7 @@ void smt2_convt::convert_expr(const exprt &expr)
18661867
expr.type().id() == ID_bool,
18671868
"overflow plus and overflow minus expressions shall be of Boolean type");
18681869

1869-
bool subtract=expr.id()==ID_overflow_minus;
1870+
bool subtract = can_cast_expr<minus_overflow_exprt>(expr);
18701871
const typet &op_type = op0.type();
18711872
std::size_t width=boolbv_width(op_type);
18721873

@@ -1907,13 +1908,14 @@ void smt2_convt::convert_expr(const exprt &expr)
19071908
"overflow check should not be performed on unsupported type",
19081909
op_type.id_string());
19091910
}
1910-
else if(expr.id()==ID_overflow_mult)
1911+
else if(
1912+
const auto mult_overflow = expr_try_dynamic_cast<mult_overflow_exprt>(expr))
19111913
{
1912-
const auto &op0 = to_binary_expr(expr).op0();
1913-
const auto &op1 = to_binary_expr(expr).op1();
1914+
const auto &op0 = mult_overflow->op0();
1915+
const auto &op1 = mult_overflow->op1();
19141916

19151917
DATA_INVARIANT(
1916-
expr.type().id() == ID_bool,
1918+
mult_overflow->type().id() == ID_bool,
19171919
"overflow mult expression shall be of Boolean type");
19181920

19191921
// No better idea than to multiply with double the bits and then compare

src/util/bitvector_expr.h

Lines changed: 120 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -705,11 +705,12 @@ class binary_overflow_exprt : public binary_predicate_exprt
705705
{
706706
public:
707707
binary_overflow_exprt(exprt _lhs, const irep_idt &kind, exprt _rhs)
708-
: binary_predicate_exprt(
709-
std::move(_lhs),
710-
"overflow-" + id2string(kind),
711-
std::move(_rhs))
708+
: binary_predicate_exprt(std::move(_lhs), make_id(kind), std::move(_rhs))
712709
{
710+
INVARIANT(
711+
valid_id(id()),
712+
"The kind used to construct binary_overflow_exprt should be in the set "
713+
"of expected valid kinds.");
713714
}
714715

715716
static void check(
@@ -735,13 +736,28 @@ class binary_overflow_exprt : public binary_predicate_exprt
735736
{
736737
check(expr, vm);
737738
}
739+
740+
/// Returns true iff \p id is a valid identifier of a `binary_overflow_exprt`.
741+
static bool valid_id(const irep_idt &id)
742+
{
743+
return id == ID_overflow_plus || id == ID_overflow_mult ||
744+
id == ID_overflow_minus || id == ID_overflow_shl;
745+
}
746+
747+
private:
748+
static irep_idt make_id(const irep_idt &kind)
749+
{
750+
if(valid_id(kind))
751+
return kind;
752+
else
753+
return "overflow-" + id2string(kind);
754+
}
738755
};
739756

740757
template <>
741758
inline bool can_cast_expr<binary_overflow_exprt>(const exprt &base)
742759
{
743-
return base.id() == ID_overflow_plus || base.id() == ID_overflow_mult ||
744-
base.id() == ID_overflow_minus || base.id() == ID_overflow_shl;
760+
return binary_overflow_exprt::valid_id(base.id());
745761
}
746762

747763
inline void validate_expr(const binary_overflow_exprt &value)
@@ -778,6 +794,66 @@ inline binary_overflow_exprt &to_binary_overflow_expr(exprt &expr)
778794
return ret;
779795
}
780796

797+
class plus_overflow_exprt : public binary_overflow_exprt
798+
{
799+
public:
800+
plus_overflow_exprt(exprt _lhs, exprt _rhs)
801+
: binary_overflow_exprt(std::move(_lhs), ID_overflow_plus, std::move(_rhs))
802+
{
803+
}
804+
};
805+
806+
template <>
807+
inline bool can_cast_expr<plus_overflow_exprt>(const exprt &base)
808+
{
809+
return base.id() == ID_overflow_plus;
810+
}
811+
812+
class minus_overflow_exprt : public binary_overflow_exprt
813+
{
814+
public:
815+
minus_overflow_exprt(exprt _lhs, exprt _rhs)
816+
: binary_overflow_exprt(std::move(_lhs), ID_overflow_minus, std::move(_rhs))
817+
{
818+
}
819+
};
820+
821+
template <>
822+
inline bool can_cast_expr<minus_overflow_exprt>(const exprt &base)
823+
{
824+
return base.id() == ID_overflow_minus;
825+
}
826+
827+
class mult_overflow_exprt : public binary_overflow_exprt
828+
{
829+
public:
830+
mult_overflow_exprt(exprt _lhs, exprt _rhs)
831+
: binary_overflow_exprt(std::move(_lhs), ID_overflow_mult, std::move(_rhs))
832+
{
833+
}
834+
};
835+
836+
template <>
837+
inline bool can_cast_expr<mult_overflow_exprt>(const exprt &base)
838+
{
839+
return base.id() == ID_overflow_mult;
840+
}
841+
842+
class shl_overflow_exprt : public binary_overflow_exprt
843+
{
844+
public:
845+
shl_overflow_exprt(exprt _lhs, exprt _rhs)
846+
: binary_overflow_exprt(std::move(_lhs), ID_overflow_shl, std::move(_rhs))
847+
{
848+
}
849+
};
850+
851+
template <>
852+
inline bool can_cast_expr<shl_overflow_exprt>(const exprt &base)
853+
{
854+
return base.id() == ID_overflow_shl;
855+
}
856+
781857
/// \brief A Boolean expression returning true, iff operation \c kind would
782858
/// result in an overflow when applied to the (single) operand.
783859
class unary_overflow_exprt : public unary_predicate_exprt
@@ -816,6 +892,44 @@ inline void validate_expr(const unary_overflow_exprt &value)
816892
value, 1, "unary overflow expression must have one operand");
817893
}
818894

895+
/// \brief A Boolean expression returning true, iff negation would result in an
896+
/// overflow when applied to the (single) operand.
897+
class unary_minus_overflow_exprt : public unary_overflow_exprt
898+
{
899+
public:
900+
explicit unary_minus_overflow_exprt(exprt _op)
901+
: unary_overflow_exprt(ID_unary_minus, std::move(_op))
902+
{
903+
}
904+
905+
static void check(
906+
const exprt &expr,
907+
const validation_modet vm = validation_modet::INVARIANT)
908+
{
909+
unary_exprt::check(expr, vm);
910+
}
911+
912+
static void validate(
913+
const exprt &expr,
914+
const namespacet &,
915+
const validation_modet vm = validation_modet::INVARIANT)
916+
{
917+
check(expr, vm);
918+
}
919+
};
920+
921+
template <>
922+
inline bool can_cast_expr<unary_minus_overflow_exprt>(const exprt &base)
923+
{
924+
return base.id() == ID_overflow_unary_minus;
925+
}
926+
927+
inline void validate_expr(const unary_minus_overflow_exprt &value)
928+
{
929+
validate_operands(
930+
value, 1, "unary minus overflow expression must have one operand");
931+
}
932+
819933
/// \brief Cast an exprt to a \ref unary_overflow_exprt
820934
///
821935
/// \a expr must be known to be \ref unary_overflow_exprt.

0 commit comments

Comments
 (0)