ESBMC
Efficient SMT-based Context-Bounded Model Checker
Loading...
Searching...
No Matches
irep2_utils.h
Go to the documentation of this file.
1#ifndef UTIL_IREP2_UTILS_H_
2#define UTIL_IREP2_UTILS_H_
3
4#include <util/lang/c_types.h>
5
6#include <irep2/irep2_expr.h>
8#include <util/irep/migrate.h>
10
11std::string indent_str_irep2(unsigned int indent);
12
13// Parameter names are not part of a function's type (C++ [dcl.fct]p5, C11
14// 6.7.6.3p15), but irep2 type equality compares argument_names too. An
15// out-of-line virtual definition gives its parameters fresh symbol ids, so the
16// vtable slot and the function symbol end up with code types that differ in
17// nothing else -- enough for the virtual call to lose its target (#6749).
19 const type2tc &a,
20 const type2tc &b)
21{
22 if (!is_pointer_type(a) || !is_pointer_type(b))
23 return false;
24
25 const type2tc &sub_a = to_pointer_type(a).subtype;
26 const type2tc &sub_b = to_pointer_type(b).subtype;
27 if (!is_code_type(sub_a) || !is_code_type(sub_b))
28 return false;
29
30 const code_type2t &ca = to_code_type(sub_a);
31 const code_type2t &cb = to_code_type(sub_b);
32 return ca.arguments == cb.arguments && ca.ret_type == cb.ret_type &&
33 ca.ellipsis == cb.ellipsis;
34}
35
37inline bool is_bv_type(const type2tc &t)
38{
39 return t->type_id == type2t::unsignedbv_id ||
40 t->type_id == type2t::signedbv_id;
41}
42
43inline bool is_bv_type(const expr2tc &e)
44{
45 return is_bv_type(e->type);
46}
47
49inline bool is_fractional_type(const type2tc &t)
50{
51 return t->type_id == type2t::fixedbv_id || t->type_id == type2t::floatbv_id;
52}
53
55inline bool is_comparison_expr(const expr2tc &e)
56{
57 return is_equality2t(e) || is_notequal2t(e) || is_lessthan2t(e) ||
58 is_greaterthan2t(e) || is_lessthanequal2t(e) ||
59 is_greaterthanequal2t(e);
60}
61
63inline bool is_number_type(const type2tc &t)
64{
65 return t->type_id == type2t::unsignedbv_id ||
66 t->type_id == type2t::signedbv_id ||
67 t->type_id == type2t::fixedbv_id || t->type_id == type2t::floatbv_id ||
68 t->type_id == type2t::bool_id;
69}
70
71inline bool is_number_type(const expr2tc &e)
72{
73 return is_number_type(e->type);
74}
75
76inline bool is_scalar_type(const type2tc &t)
77{
78 return is_number_type(t) || is_pointer_type(t) || is_empty_type(t) ||
79 is_code_type(t);
80}
81
82inline bool is_scalar_type(const expr2tc &e)
83{
84 return is_scalar_type(e->type);
85}
86
88{
89 if (is_array_type(t))
90 return is_array_type(to_array_type(t).subtype);
91
92 return false;
93}
94
96{
97 return is_multi_dimensional_array(e->type);
98}
99
100// array_type2t and vector_type2t carry the same set of element-shape
101// fields (subtype, array_size, size_is_infinite). Callers that have a
102// type which they know is one of those two but don't care which use
103// these helpers to skip the per-kind switch.
104// Whether a type is indexed like an array: its elements sit at consecutive
105// element-sized offsets, which is all the code below an index2t needs to know.
106inline bool is_array_or_vector_type(const type2tc &t)
107{
108 return is_array_type(t) || is_vector_type(t);
109}
110
111inline bool is_array_or_vector_type(const expr2tc &e)
112{
113 return is_array_or_vector_type(e->type);
114}
115
117{
118 if (is_array_type(t))
119 return to_array_type(t).subtype;
120 if (is_vector_type(t))
121 return to_vector_type(t).subtype;
122 irep2_bad_family_cast(t->type_id, "array_or_vector_subtype");
123}
124
125inline const expr2tc &array_or_vector_size(const type2tc &t)
126{
127 if (is_array_type(t))
128 return to_array_type(t).array_size;
129 if (is_vector_type(t))
130 return to_vector_type(t).array_size;
131 irep2_bad_family_cast(t->type_id, "array_or_vector_size");
132}
133
135{
136 if (is_array_type(t))
137 return to_array_type(t).size_is_infinite;
138 if (is_vector_type(t))
139 return to_vector_type(t).size_is_infinite;
140 irep2_bad_family_cast(t->type_id, "array_or_vector_size_is_infinite");
141}
142
143inline bool is_byte_type(const type2tc &t)
144{
145 return is_bv_type(t) && t->get_width() == 8;
146}
147
148inline bool is_byte_type(const expr2tc &e)
149{
150 return is_byte_type(e->type);
151}
152
153inline bool is_constant_number(const expr2tc &t)
154{
155 return t->expr_id == expr2t::constant_int_id ||
156 t->expr_id == expr2t::constant_fixedbv_id ||
157 t->expr_id == expr2t::constant_floatbv_id ||
158 t->expr_id == expr2t::constant_bool_id;
159}
160
161inline bool is_constant_expr(const expr2tc &t)
162{
163 return is_constant_number(t) || t->expr_id == expr2t::constant_string_id ||
164 t->expr_id == expr2t::constant_struct_id ||
165 t->expr_id == expr2t::constant_union_id ||
166 t->expr_id == expr2t::constant_array_id ||
167 t->expr_id == expr2t::constant_array_of_id ||
168 t->expr_id == expr2t::constant_vector_id;
169}
170
171inline bool is_constant(const expr2tc &t)
172{
173 if (is_pointer_type(t) && is_symbol2t(t))
174 {
175 symbol2t s = to_symbol2t(t);
176 if (s.thename == "NULL")
177 return true;
178 }
179 return is_constant_expr(t);
180}
181
182inline bool is_structure_type(const type2tc &t)
183{
184 return t->type_id == type2t::struct_id || t->type_id == type2t::union_id;
185}
186
187inline bool is_structure_type(const expr2tc &e)
188{
189 return is_structure_type(e->type);
190}
191
192inline bool is_arith_expr(const expr2tc &expr)
193{
194 return expr->expr_id == expr2t::neg_id || expr->expr_id == expr2t::abs_id ||
195 expr->expr_id == expr2t::add_id || expr->expr_id == expr2t::sub_id ||
196 expr->expr_id == expr2t::mul_id || expr->expr_id == expr2t::div_id ||
197 expr->expr_id == expr2t::modulus_id;
198}
199
200inline bool is_comp_expr(const expr2tc &expr)
201{
202 return expr->expr_id == expr2t::lessthan_id ||
203 expr->expr_id == expr2t::lessthanequal_id ||
204 expr->expr_id == expr2t::greaterthan_id ||
205 expr->expr_id == expr2t::greaterthanequal_id ||
206 expr->expr_id == expr2t::equality_id ||
207 expr->expr_id == expr2t::notequal_id;
208}
209
216inline bool is_true(const expr2tc &expr)
217{
218 if (is_constant_bool2t(expr) && to_constant_bool2t(expr).value)
219 return true;
220
221 if (is_constant_int2t(expr) && !to_constant_int2t(expr).value.is_zero())
222 return true;
223
224 if (
225 is_constant_floatbv2t(expr) && !to_constant_floatbv2t(expr).value.is_zero())
226 return true;
227
228 if (
229 is_constant_fixedbv2t(expr) && !to_constant_fixedbv2t(expr).value.is_zero())
230 return true;
231
232 return false;
233}
234
241inline bool is_false(const expr2tc &expr)
242{
243 if (is_constant_bool2t(expr) && !to_constant_bool2t(expr).value)
244 return true;
245
246 if (is_constant_int2t(expr) && to_constant_int2t(expr).value.is_zero())
247 return true;
248
249 if (
250 is_constant_floatbv2t(expr) && to_constant_floatbv2t(expr).value.is_zero())
251 return true;
252
253 if (
254 is_constant_fixedbv2t(expr) && to_constant_fixedbv2t(expr).value.is_zero())
255 return true;
256
257 return false;
258}
259
260// Returning by const reference is sound here: `c` has static storage
261// duration and outlives every possible caller. Callers that bind to an
262// `expr2tc` value get the usual refcount-bump copy; callers that pass
263// the result through to a function taking `const expr2tc &` save one
264// pair of atomic refcount ops per call.
265inline const expr2tc &gen_true_expr()
266{
267 static const expr2tc c = constant_bool2tc(true);
268 return c;
269}
270
271inline const expr2tc &gen_false_expr()
272{
273 static const expr2tc c = constant_bool2tc(false);
274 return c;
275}
276
277inline expr2tc gen_long(const type2tc &type, BigInt val)
278{
279 return constant_int2tc(type, std::move(val));
280}
281
283{
284 return constant_int2tc(get_uint_type(config.ansi_c.word_size), std::move(v));
285}
286
287inline expr2tc gen_ulong(unsigned long val)
288{
289 return gen_ulong(BigInt(val));
290}
291
292inline const type2tc &get_base_array_subtype(const type2tc &type)
293{
294 const auto &subtype = to_array_type(type).subtype;
295 if (is_array_type(subtype))
296 return get_base_array_subtype(subtype);
297
298 return subtype;
299}
300
301inline bool simplify(expr2tc &expr)
302{
303 expr2tc tmp = expr->simplify();
304 if (!is_nil_expr(tmp))
305 {
306 // No verify_rewrite() here: simplify() now checks each rewrite where it is
307 // made, so a whole-expression claim would restate what is already proved,
308 // in the widest and most decline-prone query of the run (esbmc/esbmc#7260).
309 expr = tmp;
310 return true;
311 }
312
313 return false;
314}
315
320void make_not(expr2tc &expr);
321
325expr2tc conjunction(std::vector<expr2tc> cs);
326
332expr2tc disjunction(std::vector<expr2tc> cs);
333
337expr2tc gen_nondet(const type2tc &type);
338
347expr2tc gen_zero(const type2tc &type, bool array_as_array_of = false);
348
352expr2tc gen_one(const type2tc &type);
353
366template <typename Func>
367inline expr2tc
368distribute_vector_operation(Func func, const expr2tc &op1, const expr2tc &op2)
369{
370 assert(is_constant_vector2t(op1) || is_constant_vector2t(op2));
371 /*
372 * If both op1 and op2 are vectors the resulting value
373 * would be the operation over each member
374 *
375 * Example:
376 *
377 * op1 = {1,2,3,4}
378 * op2 = {1,1,1,1}
379 * func = add
380 *
381 * This would result in:
382 *
383 * { add(op1[0], op2[0]), add(op1[1], op2[1]), ...}
384 * {2,3,4,5}
385 */
386 if (is_constant_vector2t(op1) && is_constant_vector2t(op2))
387 {
388 std::vector<expr2tc> members = to_constant_vector2t(op1).datatype_members;
389 const constant_vector2t *vec2 = &to_constant_vector2t(op2);
390 for (size_t i = 0; i < members.size(); i++)
391 {
392 auto &A = members[i];
393 auto &B = vec2->datatype_members[i];
394 auto new_op = func(A->type, A, B);
395 members[i] = new_op;
396 }
397 return constant_vector2tc(op1->type, std::move(members));
398 }
399 /*
400 * If only one of the operators is a constant vector, then the result
401 * would extract each value of the vector and apply the value to
402 * the other operator, or to its matching lane when that is a vector
403 *
404 * Example:
405 *
406 * op1 = {1,2,3,4}
407 * op2 = 1
408 * func = add
409 *
410 * This would result in:
411 *
412 * { add(op1[0], 1), add(op1[1], 1), ...}
413 * {2,3,4,5}
414 */
415 else
416 {
417 bool is_op1_vec = is_constant_vector2t(op1);
418 expr2tc c = !is_op1_vec ? op1 : op2;
419 expr2tc v = is_op1_vec ? op1 : op2;
420 std::vector<expr2tc> members = to_constant_vector2t(v).datatype_members;
421 for (size_t i = 0; i < members.size(); i++)
422 {
423 auto &op = members[i];
424 // A non-constant vector operand contributes its own lane, not itself.
425 expr2tc lane = c;
426 if (is_vector_type(c))
427 lane = index2tc(
429 c,
430 constant_int2tc(get_uint32_type(), BigInt(i)));
431 auto e1 = is_op1_vec ? op : lane;
432 auto e2 = is_op1_vec ? lane : op;
433 auto new_op = func(op->type, e1, e2);
434 // do_simplify() returns nil when no per-op peephole fires. Don't
435 // store nil into the member slot — keep new_op so the lane
436 // expression survives unsimplified for the SMT layer.
437 auto folded = new_op->do_simplify();
438 if (!is_nil_expr(folded))
440 op = is_nil_expr(folded) ? new_op : folded;
441 }
442 return constant_vector2tc(v->type, std::move(members));
443 }
444}
445
457 const expr2tc &op1,
458 const expr2tc &op2 = expr2tc(),
459 const expr2tc &rm = expr2tc());
460
461// Build a comparison-category struct value with the discriminant set to v.
462// Used for the C++20 spaceship operator: strong_ordering / weak_ordering /
463// partial_ordering all layout the discriminant as the first field, so
464// writing operand[0] is enough; remaining fields (if any) are zero-filled
465// for layout safety against custom comparison-category types.
466//
467// Returns nil if @p t is not a struct or has no fields.
468expr2tc make_cmp_value(const type2tc &t, int v);
469
474void get_symbols(
475 const expr2tc &expr,
476 std::unordered_set<expr2tc, irep2_hash> &symbols);
477
483std::vector<expr2tc>
484pad_struct_operands(const struct_type2t &st, std::vector<expr2tc> ops);
485
494
498
499#endif /* UTIL_IREP2_UTILS_H_ */
type2tc get_uint_type(unsigned int sz)
Definition c_types.cpp:384
type2tc get_uint32_type()
Definition c_types.cpp:348
Definition bigint.hh:58
Type of functions.
Definition irep2_type.h:333
std::vector< type2tc > arguments
Definition irep2_type.h:367
type2tc ret_type
Definition irep2_type.h:368
bool ellipsis
Definition irep2_type.h:399
Constant vector.
Definition irep2_expr.h:578
std::vector< expr2tc > datatype_members
Definition irep2_expr.h:580
expr_ids
Enumeration identifying each sort of expr.
Definition irep2.h:730
const expr_ids expr_id
Instance of expr_ids recording tihs exprs type.
Definition irep2.h:907
const type2tc type
Type of this expr.
Definition irep2.h:910
expr2tc simplify() const
Simplify an expression.
Definition expr_simplifier.cpp:40
Definition irep_idt.h:12
Struct type.
Definition irep2_type.h:99
Symbol type.
Definition irep2_expr.h:625
irep_idt thename
Definition irep2_expr.h:629
unsigned int get_width() const
Fetch bit width of this type.
Definition irep2_type.cpp:352
const type_ids type_id
Instance of type_ids recording this types type.
Definition irep2.h:693
const typet & subtype() const
Definition type.h:17
Definition toml.hpp:1531
configt config
Definition config.cpp:8
void irep2_bad_family_cast(unsigned actual, const char *accessor)
Definition irep2_type.cpp:61
irep_container< type2t > type2tc
Definition irep2.h:430
bool is_nil_expr(const expr2tc &exp)
Definition irep2.h:916
irep_container< expr2t > expr2tc
Definition irep2.h:431
expr2tc disjunction(std::vector< expr2tc > cs)
Build the left-associative OR-chain of cs.
Definition irep2_utils.cpp:41
bool is_true(const expr2tc &expr)
Test if expr is true.
Definition irep2_utils.h:216
bool is_constant(const expr2tc &t)
Definition irep2_utils.h:171
bool is_fractional_type(const type2tc &t)
Test whether type is a float/double.
Definition irep2_utils.h:49
std::string indent_str_irep2(unsigned int indent)
Definition irep2_utils.cpp:326
bool is_constant_expr(const expr2tc &t)
Definition irep2_utils.h:161
expr2tc conjunction(std::vector< expr2tc > cs)
Build the left-associative AND-chain of cs: and(and(and(c0, c1), c2), ...).
Definition irep2_utils.cpp:29
bool is_structure_type(const type2tc &t)
Definition irep2_utils.h:182
bool is_comp_expr(const expr2tc &expr)
Definition irep2_utils.h:200
bool is_scalar_type(const type2tc &t)
Definition irep2_utils.h:76
bool is_multi_dimensional_array(const type2tc &t)
Definition irep2_utils.h:87
bool simplify(expr2tc &expr)
Definition irep2_utils.h:301
expr2tc distribute_vector_operation(Func func, const expr2tc &op1, const expr2tc &op2)
Distribute the functor func over op1 and op2 at least one of those must be a vector.
Definition irep2_utils.h:368
void make_not(expr2tc &expr)
Negate expr in place.
Definition irep2_utils.cpp:6
expr2tc gen_zero(const type2tc &type, bool array_as_array_of=false)
Build the canonical zero value of type.
Definition irep2_utils.cpp:64
bool is_number_type(const type2tc &t)
Test whether type is a number type - bv, fixedbv or floatbv.
Definition irep2_utils.h:63
expr2tc gen_ulong(BigInt v)
Definition irep2_utils.h:282
bool is_constant_number(const expr2tc &t)
Definition irep2_utils.h:153
const expr2tc & array_or_vector_size(const type2tc &t)
Definition irep2_utils.h:125
bool is_arith_expr(const expr2tc &expr)
Definition irep2_utils.h:192
bool array_or_vector_size_is_infinite(const type2tc &t)
Definition irep2_utils.h:134
const type2tc & array_or_vector_subtype(const type2tc &t)
Definition irep2_utils.h:116
bool is_bv_type(const type2tc &t)
Test whether type is an integer.
Definition irep2_utils.h:37
expr2tc gen_one(const type2tc &type)
Build the canonical one value of type.
Definition irep2_utils.cpp:157
irep_idt quantifier_direct_bound_name(const expr2tc &binder)
As quantifier_bound_name, but empty unless binder is (a typecast of) address_of(symbol),...
Definition irep2_utils.cpp:781
void get_symbols(const expr2tc &expr, std::unordered_set< expr2tc, irep2_hash > &symbols)
Collect every user-level symbol2t referenced by expr into symbols.
Definition irep2_utils.cpp:301
expr2tc gen_nondet(const type2tc &type)
Build a sideeffect2t of kind nondet of type, i.e.
Definition irep2_utils.cpp:53
bool is_false(const expr2tc &expr)
Test if expr is false.
Definition irep2_utils.h:241
const expr2tc & gen_false_expr()
Definition irep2_utils.h:271
bool is_comparison_expr(const expr2tc &e)
Test whether e is a relational comparison: ==, !=, <, >, <=, >=.
Definition irep2_utils.h:55
bool same_function_pointer_ignoring_argument_names(const type2tc &a, const type2tc &b)
Definition irep2_utils.h:18
bool is_array_or_vector_type(const type2tc &t)
Definition irep2_utils.h:106
expr2tc make_cmp_value(const type2tc &t, int v)
Definition irep2_utils.cpp:286
bool is_byte_type(const type2tc &t)
Definition irep2_utils.h:143
const type2tc & get_base_array_subtype(const type2tc &type)
Definition irep2_utils.h:292
expr2tc gen_long(const type2tc &type, BigInt val)
Definition irep2_utils.h:277
std::vector< expr2tc > pad_struct_operands(const struct_type2t &st, std::vector< expr2tc > ops)
Insert a zero operand at each reserved padding-member position so a struct literal's operand list mat...
Definition irep2_utils.cpp:757
irep_idt quantifier_bound_name(const expr2tc &binder)
Base name of the variable a forall2t/exists2t binds, or an empty id when binder holds no symbol at al...
Definition irep2_utils.cpp:773
const expr2tc & gen_true_expr()
Definition irep2_utils.h:265
#define A
Definition logf.c:22
void verify_rewrite(const expr2tc &before, const expr2tc &after)
Consult the installed checker.
Definition simplification_check.h:53
const vector_typet & to_vector_type(const typet &type)
Definition std_types.h:723
const code_typet & to_code_type(const typet &type)
Definition std_types.h:384
const array_typet & to_array_type(const typet &type)
Definition std_types.h:425
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition std_types.h:460