CBMC
Loading...
Searching...
No Matches
overflow_instrumenter.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Loop Acceleration
4
5Author: Matt Lewis
6
7\*******************************************************************/
8
11
13
14#include <util/arith_tools.h>
15#include <util/bitvector_expr.h>
16
18
19#include "util.h"
20
21/*
22 * This code is copied wholesale from analyses/goto_check.cpp.
23 */
24
25
40
44{
45 if(checked.find(t->location_number)!=checked.end())
46 {
47 return;
48 }
49
50 if(t->is_assign())
51 {
52 if(t->assign_lhs() == overflow_var)
53 {
54 return;
55 }
56
57 add_overflow_checks(t, t->assign_lhs_nonconst(), added);
58 add_overflow_checks(t, t->assign_rhs_nonconst(), added);
59 }
60
61 if(t->has_condition())
62 add_overflow_checks(t, t->condition(), added);
63
64 checked.insert(t->location_number);
65}
66
73
87
89 const exprt &expr,
90 expr_sett &cases)
91{
92 for(const auto &op : expr.operands())
93 {
94 overflow_expr(op, cases);
95 }
96
97 const typet &type = expr.type();
98
99 if(expr.id()==ID_typecast)
100 {
101 const auto &typecast_expr = to_typecast_expr(expr);
102
103 if(typecast_expr.op().is_constant())
104 return;
105
106 const typet &old_type = typecast_expr.op().type();
107 const std::size_t new_width = to_bitvector_type(expr.type()).get_width();
108 const std::size_t old_width = to_bitvector_type(old_type).get_width();
109
110 if(type.id()==ID_signedbv)
111 {
112 if(old_type.id()==ID_signedbv)
113 {
114 // signed -> signed
115 if(new_width >= old_width)
116 {
117 // Always safe.
118 return;
119 }
120
121 cases.insert(binary_relation_exprt(
122 typecast_expr.op(),
123 ID_gt,
124 from_integer(power(2, new_width - 1) - 1, old_type)));
125
126 cases.insert(binary_relation_exprt(
127 typecast_expr.op(),
128 ID_lt,
130 }
131 else if(old_type.id()==ID_unsignedbv)
132 {
133 // unsigned -> signed
134 if(new_width >= old_width + 1)
135 {
136 // Always safe.
137 return;
138 }
139
140 cases.insert(binary_relation_exprt(
141 typecast_expr.op(),
142 ID_gt,
143 from_integer(power(2, new_width - 1) - 1, old_type)));
144 }
145 }
146 else if(type.id()==ID_unsignedbv)
147 {
148 if(old_type.id()==ID_signedbv)
149 {
150 // signed -> unsigned
151 cases.insert(binary_relation_exprt(
153 if(new_width < old_width - 1)
154 {
155 // Need to check for overflow as well as signedness.
156 cases.insert(binary_relation_exprt(
157 typecast_expr.op(),
158 ID_gt,
159 from_integer(power(2, new_width - 1) - 1, old_type)));
160 }
161 }
162 else if(old_type.id()==ID_unsignedbv)
163 {
164 // unsigned -> unsigned
166 {
167 // Always safe.
168 return;
169 }
170
171 cases.insert(binary_relation_exprt(
172 typecast_expr.op(),
173 ID_gt,
174 from_integer(power(2, new_width - 1) - 1, old_type)));
175 }
176 }
177 }
178 else if(expr.id()==ID_div)
179 {
180 const auto &div_expr = to_div_expr(expr);
181
182 // Undefined for signed INT_MIN / -1
183 if(type.id()==ID_signedbv)
184 {
186 div_expr.dividend(), to_signedbv_type(type).smallest_expr());
187 equal_exprt minus_one_eq(div_expr.divisor(), from_integer(-1, type));
188
189 cases.insert(and_exprt(int_min_eq, minus_one_eq));
190 }
191 }
192 else if(expr.id()==ID_unary_minus)
193 {
194 if(type.id()==ID_signedbv)
195 {
196 // Overflow on unary- can only happen with the smallest
197 // representable number.
198 cases.insert(equal_exprt(
199 to_unary_minus_expr(expr).op(),
200 to_signedbv_type(type).smallest_expr()));
201 }
202 }
203 else if(expr.id()==ID_plus ||
204 expr.id()==ID_minus ||
205 expr.id()==ID_mult)
206 {
207 // A generic arithmetic operation.
208 // The overflow checks are binary.
209 for(std::size_t i = 1; i < expr.operands().size(); i++)
210 {
211 exprt tmp;
212
213 if(i == 1)
214 {
215 tmp = to_multi_ary_expr(expr).op0();
216 }
217 else
218 {
219 tmp = expr;
220 tmp.operands().resize(i);
221 }
222
223 binary_overflow_exprt overflow{tmp, expr.id(), expr.operands()[i]};
224
226
227 cases.insert(overflow);
228 }
229 }
230}
231
233{
234 expr_sett cases;
235
236 overflow_expr(expr, cases);
237
239
240 for(expr_sett::iterator it=cases.begin();
241 it!=cases.end();
242 ++it)
243 {
244 if(overflow==false_exprt())
245 {
246 overflow=*it;
247 }
248 else
249 {
251 }
252 }
253}
254
256{
257 typet &t1=overflow.op0().type();
258 typet &t2=overflow.op1().type();
259 const typet &t=join_types(t1, t2);
260
261 if(t1!=t)
262 {
263 overflow.op0()=typecast_exprt(overflow.op0(), t);
264 }
265
266 if(t2!=t)
267 {
268 overflow.op1()=typecast_exprt(overflow.op1(), t);
269 }
270}
271
274 const exprt &expr,
276{
278 t,
280 assignment->swap(*t);
281
282 added.push_back(assignment);
283}
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
mp_integer power(const mp_integer &base, const mp_integer &exponent)
A multi-precision implementation of the power operator.
API to expression classes for bitvectors.
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
const signedbv_typet & to_signedbv_type(const typet &type)
Cast a typet to a signedbv_typet.
virtual void clear()
Reset the abstract state.
Definition ai.h:265
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
Boolean AND.
Definition std_expr.h:2125
A base class for binary expressions.
Definition std_expr.h:638
A Boolean expression returning true, iff operation kind would result in an overflow when applied to o...
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition std_expr.h:762
A goto_instruction_codet representing an assignment in the program.
Equality.
Definition std_expr.h:1366
Base class for all expressions.
Definition expr.h:56
typet & type()
Return the type of the expression.
Definition expr.h:84
operandst & operands()
Definition expr.h:94
The Boolean constant false.
Definition std_expr.h:3200
instructionst instructions
The list of instructions in the goto program.
instructionst::iterator targett
static instructiont make_assignment(const code_assignt &_code, const source_locationt &l=source_locationt::nil())
Create an assignment instruction.
targett insert_after(const_targett target)
Insertion after the instruction pointed-to by the given instruction iterator target.
void compute_location_numbers(unsigned &nr)
Compute location numbers.
targett insert_before(const_targett target)
Insertion before the instruction pointed-to by the given instruction iterator target.
std::list< targett > targetst
const irep_idt & id() const
Definition irep.h:388
Boolean OR.
Definition std_expr.h:2275
std::set< unsigned > checked
void fix_types(binary_exprt &overflow)
void accumulate_overflow(goto_programt::targett t, const exprt &expr, goto_programt::targetst &added)
void overflow_expr(const exprt &expr, expr_sett &cases)
Semantic type conversion.
Definition std_expr.h:2073
The type of an expression, extends irept.
Definition type.h:29
std::unordered_set< exprt, irep_hash > expr_sett
Concrete Goto Program.
#define Forall_goto_program_instructions(it, program)
Loop Acceleration.
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2107
const div_exprt & to_div_expr(const exprt &expr)
Cast an exprt to a div_exprt.
Definition std_expr.h:1206
const multi_ary_exprt & to_multi_ary_expr(const exprt &expr)
Cast an exprt to a multi_ary_exprt.
Definition std_expr.h:987
const unary_minus_exprt & to_unary_minus_expr(const exprt &expr)
Cast an exprt to a unary_minus_exprt.
Definition std_expr.h:514
typet join_types(const typet &t1, const typet &t2)
Return the smallest type that both t1 and t2 can be cast to without losing information.
Definition util.cpp:70
Loop Acceleration.