CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
boolbv_overflow.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module:
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
9#include <util/arith_tools.h>
10#include <util/bitvector_expr.h>
12#include <util/invariant.h>
13
14#include "boolbv.h"
15
17 propt &prop,
18 const bvt &bv0,
19 const bvt &bv1,
21{
22 bv_utilst bv_utils{prop};
23
24 std::size_t old_size = bv0.size();
25 std::size_t new_size = old_size * 2;
26
27 // sign/zero extension
28 const bvt &bv0_extended = bv_utils.extension(bv0, new_size, rep);
29 const bvt &bv1_extended = bv_utils.extension(bv1, new_size, rep);
30
31 bvt result_extended = bv_utils.multiplier(bv0_extended, bv1_extended, rep);
32 bvt bv{result_extended.begin(), result_extended.begin() + old_size};
34
36 {
37 bv.push_back(prop.lor(bv_overflow));
38 }
39 else
40 {
41 // get top result bits, plus one more
42 bv_overflow.push_back(bv.back());
43
44 // these need to be either all 1's or all 0's
47 bv.push_back(!prop.lor(all_one, all_zero));
48 }
49
50 return bv;
51}
52
54 propt &prop,
55 const bvt &bv0,
56 const bvt &bv1,
59{
60 bv_utilst bv_utils{prop};
61
62 std::size_t old_size = bv0.size();
63 std::size_t new_size = old_size * 2;
64
65 bvt result_extended = bv_utils.shift(
66 bv_utils.extension(bv0, new_size, rep0),
68 bv1);
69 bvt bv{result_extended.begin(), result_extended.begin() + old_size};
71
72 // a negative shift is undefined; yet this isn't an overflow
74 ? const_literal(false)
75 : bv_utils.sign_bit(bv1);
76
77 // an undefined shift of a non-zero value always results in overflow
78 std::size_t cmp_width = std::max(bv1.size(), address_bits(old_size) + 1);
79 literalt undef = bv_utils.rel(
80 bv_utils.extension(bv1, cmp_width, rep1),
81 ID_gt,
82 bv_utils.build_constant(old_size, cmp_width),
83 rep1);
84
86 {
87 // one of the top bits is non-zero
88 bv.push_back(prop.lor(bv_overflow));
89 }
90 else
91 {
92 // get top result bits, plus one more
93 bv_overflow.push_back(bv.back());
94
95 // the sign bit has changed
97 !prop.lequal(bv_utils.sign_bit(bv0), bv_utils.sign_bit(bv));
98
99 // these need to be either all 1's or all 0's
102
103 bv.push_back(prop.lor(sign_change, !prop.lor(all_one, all_zero)));
104 }
105
106 // a negative shift isn't an overflow; else check the conditions built
107 // above
108 bv.back() =
109 prop.land(!neg_shift, prop.lselect(undef, prop.lor(bv0), bv.back()));
110
111 return bv;
112}
113
115{
116 const bvt &bv0 = convert_bv(expr.lhs());
117 const bvt &bv1 = convert_bv(
118 expr.rhs(),
120 ? std::optional<std::size_t>{bv0.size()}
121 : std::nullopt);
122
127
129 {
130 if(bv0.size() != bv1.size())
131 return SUB::convert_rest(expr);
132
133 return bv_utils.overflow_add(bv0, bv1, rep);
134 }
136 {
137 if(bv0.size() != bv1.size())
138 return SUB::convert_rest(expr);
139
140 return bv_utils.overflow_sub(bv0, bv1, rep);
141 }
142 else if(
144 {
145 if(
148 {
149 return SUB::convert_rest(expr);
150 }
151
153 mult_overflow->lhs().type() == mult_overflow->rhs().type(),
154 "operands of overflow_mult expression shall have same type");
155
156 DATA_INVARIANT(!bv0.empty(), "zero-sized operand");
157
158 return mult_overflow_result(prop, bv0, bv1, rep).back();
159 }
161 {
162 DATA_INVARIANT(!bv0.empty(), "zero-sized operand");
163
164 return shl_overflow_result(
165 prop,
166 bv0,
167 bv1,
168 rep,
172 .back();
173 }
174
175 return SUB::convert_rest(expr);
176}
177
179{
180 if(
181 const auto unary_minus_overflow =
183 {
184 const bvt &bv = convert_bv(unary_minus_overflow->op());
185
186 return bv_utils.overflow_negate(bv);
187 }
188
189 return SUB::convert_rest(expr);
190}
191
193{
194 const typet &type = expr.type();
195 const std::size_t width = boolbv_width(type);
196
198 {
199 const bvt op_bv = convert_bv(expr.op0());
200 bvt bv = bv_utils.negate(op_bv);
201 bv.push_back(bv_utils.overflow_negate(op_bv));
202 CHECK_RETURN(bv.size() == width);
203 return bv;
204 }
205 else if(expr.operands().size() != 2)
206 return conversion_failed(expr);
207
208 const bvt &bv0 = convert_bv(expr.op0());
209 const bvt &bv1 = convert_bv(expr.op1());
210 CHECK_RETURN(!bv0.empty() && !bv1.empty());
211
216
217 if(expr.id() == ID_overflow_result_plus)
218 {
219 CHECK_RETURN(bv0.size() == bv1.size());
220
222 {
223 // An overflow occurs if the signs of the two operands are the same
224 // and the sign of the sum is the opposite.
225 bvt bv = bv_utils.add(bv0, bv1);
226
230 bv.push_back(prop.land(sign_the_same, prop.lxor(new_sign, old_sign)));
231
232 CHECK_RETURN(bv.size() == width);
233 return bv;
234 }
235 else
236 {
237 // overflow is simply carry-out
238 bvt bv;
239 bv.reserve(width);
240 literalt carry = const_literal(false);
241
242 for(std::size_t i = 0; i < bv0.size(); i++)
243 bv.push_back(bv_utils.full_adder(bv0[i], bv1[i], carry, carry));
244
245 bv.push_back(carry);
246
247 CHECK_RETURN(bv.size() == width);
248 return bv;
249 }
250 }
251 else if(expr.id() == ID_overflow_result_minus)
252 {
253 CHECK_RETURN(bv0.size() == bv1.size());
254
256 {
258 bvt bv = bv_utils.add(bv0, bv1_neg);
259
260 // We special-case x-INT_MIN, which is >=0 if
261 // x is negative, always representable, and
262 // thus not an overflow.
265
270 bv.push_back(prop.lselect(
274
275 CHECK_RETURN(bv.size() == width);
276 return bv;
277 }
279 {
280 // overflow is simply _negated_ carry-out
281 bvt bv;
282 bv.reserve(width);
283 literalt carry = const_literal(true);
284
285 for(std::size_t i = 0; i < bv0.size(); i++)
286 bv.push_back(bv_utils.full_adder(bv0[i], !bv1[i], carry, carry));
287
288 bv.push_back(!carry);
289
290 CHECK_RETURN(bv.size() == width);
291 return bv;
292 }
293 else
295 }
296 else if(expr.id() == ID_overflow_result_mult)
297 {
298 CHECK_RETURN(bv0.size() == bv1.size());
299
300 bvt bv = mult_overflow_result(prop, bv0, bv1, rep);
301
302 CHECK_RETURN(bv.size() == width);
303 return bv;
304 }
305 else if(expr.id() == ID_overflow_result_shl)
306 {
308 prop,
309 bv0,
310 bv1,
311 rep,
315
316 CHECK_RETURN(bv.size() == width);
317 return bv;
318 }
319
320 return conversion_failed(expr);
321}
std::size_t address_bits(const mp_integer &size)
ceil(log2(size))
API to expression classes for bitvectors.
Pre-defined bitvector types.
bool can_cast_type< signedbv_typet >(const typet &type)
Check whether a reference to a typet is a signedbv_typet.
static bvt shl_overflow_result(propt &prop, const bvt &bv0, const bvt &bv1, bv_utilst::representationt rep0, bv_utilst::representationt rep1)
static bvt mult_overflow_result(propt &prop, const bvt &bv0, const bvt &bv1, bv_utilst::representationt rep)
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
exprt & lhs()
Definition std_expr.h:668
exprt & rhs()
Definition std_expr.h:678
exprt & op1()
Definition expr.h:136
A Boolean expression returning true, iff operation kind would result in an overflow when applied to o...
virtual const bvt & convert_bv(const exprt &expr, const std::optional< std::size_t > expected_width={})
Convert expression to vector of literalts, using an internal cache to speed up conversion if availabl...
Definition boolbv.cpp:39
virtual literalt convert_binary_overflow(const binary_overflow_exprt &expr)
bv_utilst bv_utils
Definition boolbv.h:118
virtual bvt convert_overflow_result(const overflow_result_exprt &expr)
bvt conversion_failed(const exprt &expr)
Print that the expression of x has failed conversion, then return a vector of x's width.
Definition boolbv.cpp:94
virtual literalt convert_unary_overflow(const unary_overflow_exprt &expr)
virtual std::size_t boolbv_width(const typet &type) const
Definition boolbv.h:103
literalt is_int_min(const bvt &op)
Definition bv_utils.h:149
static literalt sign_bit(const bvt &op)
Definition bv_utils.h:138
bvt add(const bvt &op0, const bvt &op1)
Definition bv_utils.h:66
literalt overflow_add(const bvt &op0, const bvt &op1, representationt rep)
Definition bv_utils.cpp:427
literalt overflow_sub(const bvt &op0, const bvt &op1, representationt rep)
Definition bv_utils.cpp:451
literalt overflow_negate(const bvt &op)
Definition bv_utils.cpp:603
representationt
Definition bv_utils.h:28
literalt full_adder(const literalt a, const literalt b, const literalt carry_in, literalt &carry_out)
Definition bv_utils.cpp:139
bvt negate(const bvt &op)
Definition bv_utils.cpp:589
typet & type()
Return the type of the expression.
Definition expr.h:84
operandst & operands()
Definition expr.h:94
const irep_idt & id() const
Definition irep.h:388
An expression returning both the result of the arithmetic operation under wrap-around semantics as we...
exprt & op0()
Definition expr.h:133
exprt & op1()
Definition expr.h:136
virtual literalt convert_rest(const exprt &expr)
TO_BE_DOCUMENTED.
Definition prop.h:25
virtual literalt land(literalt a, literalt b)=0
virtual literalt lselect(literalt a, literalt b, literalt c)=0
virtual literalt lxor(literalt a, literalt b)=0
virtual literalt lequal(literalt a, literalt b)=0
virtual literalt lor(literalt a, literalt b)=0
The type of an expression, extends irept.
Definition type.h:29
A Boolean expression returning true, iff operation kind would result in an overflow when applied to t...
std::vector< literalt > bvt
Definition literal.h:201
literalt const_literal(bool value)
Definition literal.h:188
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#define UNREACHABLE
This should be used to mark dead code.
Definition invariant.h:525
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition invariant.h:534