-
Notifications
You must be signed in to change notification settings - Fork 273
/
Copy pathexpr_util.cpp
329 lines (272 loc) · 8.4 KB
/
expr_util.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
/*******************************************************************\
Module:
Author: Daniel Kroening, [email protected]
\*******************************************************************/
#include "expr_util.h"
#include "arith_tools.h"
#include "bitvector_expr.h"
#include "byte_operators.h"
#include "c_types.h"
#include "config.h"
#include "expr_iterator.h"
#include "namespace.h"
#include "pointer_expr.h"
#include "pointer_offset_size.h"
#include <algorithm>
#include <unordered_set>
bool is_assignable(const exprt &expr)
{
if(expr.id() == ID_index)
return is_assignable(to_index_expr(expr).array());
else if(expr.id() == ID_member)
return is_assignable(to_member_expr(expr).compound());
else if(expr.id() == ID_dereference)
return true;
else if(expr.id() == ID_symbol)
return true;
else
return false;
}
exprt make_binary(const exprt &expr)
{
const exprt::operandst &operands=expr.operands();
if(operands.size()<=2)
return expr;
// types must be identical for make_binary to be safe to use
const typet &type=expr.type();
exprt previous=operands.front();
PRECONDITION(previous.type()==type);
for(exprt::operandst::const_iterator
it=++operands.begin();
it!=operands.end();
++it)
{
PRECONDITION(it->type()==type);
exprt tmp=expr;
tmp.operands().clear();
tmp.operands().resize(2);
to_binary_expr(tmp).op0().swap(previous);
to_binary_expr(tmp).op1() = *it;
previous.swap(tmp);
}
return previous;
}
with_exprt make_with_expr(const update_exprt &src)
{
return src.make_with_expr();
}
exprt is_not_zero(
const exprt &src,
const namespacet &ns)
{
// We frequently need to check if a numerical type is not zero.
// We replace (_Bool)x by x!=0; use ieee_float_notequal for floats.
// Note that this returns a proper bool_typet(), not a C/C++ boolean.
// To get a C/C++ boolean, add a further typecast.
const typet &src_type = src.type().id() == ID_c_enum_tag
? ns.follow_tag(to_c_enum_tag_type(src.type()))
: src.type();
if(src_type.id()==ID_bool) // already there
return src; // do nothing
irep_idt id=
src_type.id()==ID_floatbv?ID_ieee_float_notequal:ID_notequal;
exprt zero=from_integer(0, src_type);
// Use tag type if applicable:
zero.type() = src.type();
binary_relation_exprt comparison(src, id, std::move(zero));
comparison.add_source_location()=src.source_location();
return std::move(comparison);
}
exprt boolean_negate(const exprt &src)
{
if(src.id() == ID_not)
return to_not_expr(src).op();
else if(src.is_true())
return false_exprt();
else if(src.is_false())
return true_exprt();
else
return not_exprt(src);
}
bool has_subexpr(
const exprt &expr,
const std::function<bool(const exprt &)> &pred)
{
const auto it = std::find_if(expr.depth_begin(), expr.depth_end(), pred);
return it != expr.depth_end();
}
bool has_subexpr(const exprt &src, const irep_idt &id)
{
return has_subexpr(
src, [&](const exprt &subexpr) { return subexpr.id() == id; });
}
bool has_subtype(
const typet &type,
const std::function<bool(const typet &)> &pred,
const namespacet &ns)
{
std::vector<std::reference_wrapper<const typet>> stack;
std::unordered_set<typet, irep_hash> visited;
const auto push_if_not_visited = [&](const typet &t) {
if(visited.insert(t).second)
stack.emplace_back(t);
};
push_if_not_visited(type);
while(!stack.empty())
{
const typet &top = stack.back().get();
stack.pop_back();
if(pred(top))
return true;
else if(top.id() == ID_c_enum_tag)
push_if_not_visited(ns.follow_tag(to_c_enum_tag_type(top)));
else if(top.id() == ID_struct_tag)
push_if_not_visited(ns.follow_tag(to_struct_tag_type(top)));
else if(top.id() == ID_union_tag)
push_if_not_visited(ns.follow_tag(to_union_tag_type(top)));
else if(top.id() == ID_struct || top.id() == ID_union)
{
for(const auto &comp : to_struct_union_type(top).components())
push_if_not_visited(comp.type());
}
else
{
for(const auto &subtype : to_type_with_subtypes(top).subtypes())
push_if_not_visited(subtype);
}
}
return false;
}
bool has_subtype(const typet &type, const irep_idt &id, const namespacet &ns)
{
return has_subtype(
type, [&](const typet &subtype) { return subtype.id() == id; }, ns);
}
if_exprt lift_if(const exprt &src, std::size_t operand_number)
{
PRECONDITION(operand_number<src.operands().size());
PRECONDITION(src.operands()[operand_number].id()==ID_if);
const if_exprt if_expr=to_if_expr(src.operands()[operand_number]);
const exprt true_case=if_expr.true_case();
const exprt false_case=if_expr.false_case();
if_exprt result(if_expr.cond(), src, src);
result.true_case().operands()[operand_number]=true_case;
result.false_case().operands()[operand_number]=false_case;
return result;
}
const exprt &skip_typecast(const exprt &expr)
{
if(expr.id()!=ID_typecast)
return expr;
return skip_typecast(to_typecast_expr(expr).op());
}
/// This function determines what expressions are to be propagated as
/// "constants"
bool can_forward_propagatet::is_constant(const exprt &expr) const
{
if(
expr.id() == ID_symbol || expr.id() == ID_nondet_symbol ||
expr.id() == ID_side_effect)
{
return false;
}
if(expr.id() == ID_address_of)
{
return is_constant_address_of(to_address_of_expr(expr).object());
}
else if(auto index = expr_try_dynamic_cast<index_exprt>(expr))
{
if(!is_constant(index->array()) || !index->index().is_constant())
return false;
const auto &array_type = to_array_type(index->array().type());
if(!array_type.size().is_constant())
return false;
const mp_integer size =
numeric_cast_v<mp_integer>(to_constant_expr(array_type.size()));
const mp_integer index_int =
numeric_cast_v<mp_integer>(to_constant_expr(index->index()));
return index_int >= 0 && index_int < size;
}
else if(auto be = expr_try_dynamic_cast<byte_extract_exprt>(expr))
{
if(!is_constant(be->op()) || !be->offset().is_constant())
return false;
const auto op_bits = pointer_offset_bits(be->op().type(), ns);
if(!op_bits.has_value())
return false;
const auto extract_bits = pointer_offset_bits(be->type(), ns);
if(!extract_bits.has_value())
return false;
const mp_integer offset_bits =
numeric_cast_v<mp_integer>(to_constant_expr(be->offset())) *
be->get_bits_per_byte();
return offset_bits >= 0 && offset_bits + *extract_bits <= *op_bits;
}
else if(auto eb = expr_try_dynamic_cast<extractbits_exprt>(expr))
{
if(!is_constant(eb->src()) || !eb->index().is_constant())
{
return false;
}
const auto eb_bits = pointer_offset_bits(eb->type(), ns);
if(!eb_bits.has_value())
return false;
const auto src_bits = pointer_offset_bits(eb->src().type(), ns);
if(!src_bits.has_value())
return false;
const mp_integer lower_bound =
numeric_cast_v<mp_integer>(to_constant_expr(eb->index()));
const mp_integer upper_bound = lower_bound + eb_bits.value() - 1;
return lower_bound >= 0 && lower_bound <= upper_bound &&
upper_bound < src_bits.value();
}
else
{
// std::all_of returns true when there are no operands
return std::all_of(
expr.operands().begin(), expr.operands().end(), [this](const exprt &e) {
return is_constant(e);
});
}
}
/// this function determines which reference-typed expressions are constant
bool can_forward_propagatet::is_constant_address_of(const exprt &expr) const
{
if(expr.id() == ID_symbol)
{
return true;
}
else if(expr.id() == ID_index)
{
const index_exprt &index_expr = to_index_expr(expr);
return is_constant_address_of(index_expr.array()) &&
is_constant(index_expr.index());
}
else if(expr.id() == ID_member)
{
return is_constant_address_of(to_member_expr(expr).compound());
}
else if(expr.id() == ID_dereference)
{
const dereference_exprt &deref = to_dereference_expr(expr);
return is_constant(deref.pointer());
}
else if(expr.id() == ID_string_constant)
return true;
return false;
}
constant_exprt make_boolean_expr(bool value)
{
if(value)
return true_exprt();
else
return false_exprt();
}
exprt make_and(exprt a, exprt b)
{
return conjunction(a, b);
}
bool is_null_pointer(const constant_exprt &expr)
{
return expr.is_null_pointer();
}