CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
simplify_utils.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module:
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
9#include "simplify_utils.h"
10
11#include "arith_tools.h"
12#include "c_types.h"
13#include "config.h"
14#include "endianness_map.h"
15#include "expr_util.h"
16#include "namespace.h"
17#include "pointer_expr.h"
18#include "pointer_offset_size.h"
19#include "std_expr.h"
20#include "string_constant.h"
21#include "symbol.h"
22
23#include <algorithm>
24
29{
30 bool do_sort=false;
31
32 forall_expr(it, operands)
33 {
34 exprt::operandst::const_iterator next_it=it;
35 next_it++;
36
37 if(next_it!=operands.end() && *next_it < *it)
38 {
39 do_sort=true;
40 break;
41 }
42 }
43
44 if(!do_sort)
45 return true;
46
47 std::sort(operands.begin(), operands.end());
48
49 return false;
50}
51
53// The entries
54// { ID_plus, ID_floatbv },
55// { ID_mult, ID_floatbv },
56// { ID_plus, ID_pointer },
57// are deliberately missing, as FP-addition and multiplication
58// aren't associative. Addition to pointers isn't really
59// associative.
60
62{
63 const irep_idt id;
64 const irep_idt type_ids[10];
65} const saj_table[]=
66{
69 ID_real ,
75 irep_idt() }},
78 ID_real ,
84 irep_idt() }},
85 { ID_and, {ID_bool ,
86 irep_idt() }},
87 { ID_or, {ID_bool ,
88 irep_idt() }},
89 { ID_xor, {ID_bool ,
90 irep_idt() }},
95 irep_idt() }},
100 irep_idt() }},
103 ID_floatbv ,
104 ID_fixedbv ,
105 irep_idt() }},
106 { irep_idt(), { irep_idt() }}
108
110 const struct saj_tablet &saj_entry,
111 const irep_idt &type_id)
112{
113 for(unsigned i=0; !saj_entry.type_ids[i].empty(); i++)
114 if(type_id==saj_entry.type_ids[i])
115 return true;
116
117 return false;
118}
119
120static const struct saj_tablet &
122{
123 unsigned i=0;
124
125 for( ; !saj_table[i].id.empty(); i++)
126 {
127 if(
128 id == saj_table[i].id &&
130 return saj_table[i];
131 }
132
133 return saj_table[i];
134}
135
136static bool sort_and_join(exprt &expr, bool do_sort)
137{
138 bool no_change = true;
139
140 if(!expr.has_operands())
141 return true;
142
143 const struct saj_tablet &saj_entry =
144 get_sort_and_join_table_entry(expr.id(), as_const(expr).type().id());
145 if(saj_entry.id.empty())
146 return true;
147
148 // check operand types
149
150 for(const auto &op : as_const(expr).operands())
151 {
153 return true;
154 }
155
156 // join expressions
157
159 new_ops.reserve(as_const(expr).operands().size());
160
161 for(const auto &op : as_const(expr).operands())
162 {
163 if(op.id() == expr.id())
164 {
165 new_ops.reserve(new_ops.capacity() + op.operands().size() - 1);
166
167 for(const auto &sub_op : op.operands())
168 new_ops.push_back(sub_op);
169
170 no_change = false;
171 }
172 else
173 new_ops.push_back(op);
174 }
175
176 // sort it
177 if(do_sort)
179
180 if(!no_change)
181 expr.operands().swap(new_ops);
182
183 return no_change;
184}
185
187{
188 return sort_and_join(expr, true);
189}
190
192{
193 return sort_and_join(expr, false);
194}
195
196std::optional<exprt> bits2expr(
197 const std::string &bits,
198 const typet &type,
199 bool little_endian,
200 const namespacet &ns)
201{
202 // bits start at lowest memory address
203 auto type_bits = pointer_offset_bits(type, ns);
204
205 if(
206 !type_bits.has_value() ||
207 (type.id() != ID_union && type.id() != ID_union_tag &&
208 *type_bits != bits.size()) ||
209 ((type.id() == ID_union || type.id() == ID_union_tag) &&
210 *type_bits < bits.size()))
211 {
212 return {};
213 }
214
215 if(
216 type.id() == ID_unsignedbv || type.id() == ID_signedbv ||
217 type.id() == ID_floatbv || type.id() == ID_fixedbv ||
218 type.id() == ID_c_bit_field || type.id() == ID_pointer ||
219 type.id() == ID_bv || type.id() == ID_c_bool)
220 {
221 if(
222 type.id() == ID_pointer && config.ansi_c.NULL_is_zero &&
223 bits.find('1') == std::string::npos)
224 {
226 }
227
228 endianness_mapt map(type, little_endian, ns);
229
230 std::string tmp = bits;
231 for(std::string::size_type i = 0; i < bits.size(); ++i)
232 tmp[i] = bits[map.map_bit(i)];
233
234 std::reverse(tmp.begin(), tmp.end());
235
236 mp_integer i = binary2integer(tmp, false);
237 return constant_exprt(integer2bvrep(i, bits.size()), type);
238 }
239 else if(type.id() == ID_c_enum)
240 {
241 auto val = bits2expr(
242 bits, to_c_enum_type(type).underlying_type(), little_endian, ns);
243 if(val.has_value())
244 {
245 val->type() = type;
246 return *val;
247 }
248 else
249 return {};
250 }
251 else if(type.id() == ID_c_enum_tag)
252 {
253 auto val = bits2expr(
254 bits, ns.follow_tag(to_c_enum_tag_type(type)), little_endian, ns);
255 if(val.has_value())
256 {
257 val->type() = type;
258 return *val;
259 }
260 else
261 return {};
262 }
263 else if(type.id() == ID_union)
264 {
265 // find a suitable member
266 const union_typet &union_type = to_union_type(type);
267 const union_typet::componentst &components = union_type.components();
268
269 if(components.empty() && bits.empty())
270 return empty_union_exprt{type};
271
272 for(const auto &component : components)
273 {
274 auto val = bits2expr(bits, component.type(), little_endian, ns);
275 if(!val.has_value())
276 continue;
277
278 return union_exprt(component.get_name(), *val, type);
279 }
280 }
281 else if(type.id() == ID_union_tag)
282 {
283 auto val = bits2expr(
284 bits, ns.follow_tag(to_union_tag_type(type)), little_endian, ns);
285 if(val.has_value())
286 {
287 val->type() = type;
288 return *val;
289 }
290 else
291 return {};
292 }
293 else if(type.id() == ID_struct)
294 {
296 const struct_typet::componentst &components = struct_type.components();
297
298 struct_exprt result({}, type);
299 result.reserve_operands(components.size());
300
302 for(const auto &component : components)
303 {
304 const auto m_size = pointer_offset_bits(component.type(), ns);
305 CHECK_RETURN(m_size.has_value() && *m_size >= 0);
306
307 std::string comp_bits = std::string(
308 bits,
311
312 auto comp = bits2expr(comp_bits, component.type(), little_endian, ns);
313 if(!comp.has_value())
314 return {};
315 result.add_to_operands(std::move(*comp));
316
317 m_offset_bits += *m_size;
318 }
319
320 return std::move(result);
321 }
322 else if(type.id() == ID_struct_tag)
323 {
324 auto val = bits2expr(
325 bits, ns.follow_tag(to_struct_tag_type(type)), little_endian, ns);
326 if(val.has_value())
327 {
328 val->type() = type;
329 return *val;
330 }
331 else
332 return {};
333 }
334 else if(type.id() == ID_array)
335 {
336 const array_typet &array_type = to_array_type(type);
337 const auto &size_expr = array_type.size();
338
339 PRECONDITION(size_expr.is_constant());
340
341 const std::size_t number_of_elements =
343
344 const auto el_size_opt = pointer_offset_bits(array_type.element_type(), ns);
345 CHECK_RETURN(el_size_opt.has_value() && *el_size_opt > 0);
346
347 const std::size_t el_size = numeric_cast_v<std::size_t>(*el_size_opt);
348
349 array_exprt result({}, array_type);
351
352 for(std::size_t i = 0; i < number_of_elements; ++i)
353 {
354 std::string el_bits = std::string(bits, i * el_size, el_size);
355 auto el =
356 bits2expr(el_bits, array_type.element_type(), little_endian, ns);
357 if(!el.has_value())
358 return {};
359 result.add_to_operands(std::move(*el));
360 }
361
362 return std::move(result);
363 }
364 else if(type.id() == ID_vector)
365 {
367
368 const std::size_t n_el = numeric_cast_v<std::size_t>(vector_type.size());
369
370 const auto el_size_opt =
371 pointer_offset_bits(vector_type.element_type(), ns);
372 CHECK_RETURN(el_size_opt.has_value() && *el_size_opt > 0);
373
374 const std::size_t el_size = numeric_cast_v<std::size_t>(*el_size_opt);
375
376 vector_exprt result({}, vector_type);
377 result.reserve_operands(n_el);
378
379 for(std::size_t i = 0; i < n_el; ++i)
380 {
381 std::string el_bits = std::string(bits, i * el_size, el_size);
382 auto el =
383 bits2expr(el_bits, vector_type.element_type(), little_endian, ns);
384 if(!el.has_value())
385 return {};
386 result.add_to_operands(std::move(*el));
387 }
388
389 return std::move(result);
390 }
391 else if(type.id() == ID_complex)
392 {
394
395 const auto sub_size_opt = pointer_offset_bits(complex_type.subtype(), ns);
396 CHECK_RETURN(sub_size_opt.has_value() && *sub_size_opt > 0);
397
399
400 auto real = bits2expr(
401 bits.substr(0, sub_size), complex_type.subtype(), little_endian, ns);
402 auto imag = bits2expr(
403 bits.substr(sub_size), complex_type.subtype(), little_endian, ns);
404 if(!real.has_value() || !imag.has_value())
405 return {};
406
407 return complex_exprt(*real, *imag, complex_type);
408 }
409
410 return {};
411}
412
413std::optional<std::string>
414expr2bits(const exprt &expr, bool little_endian, const namespacet &ns)
415{
416 // extract bits from lowest to highest memory address
417 const typet &type = expr.type();
418
419 if(expr.is_constant())
420 {
421 const auto &value = to_constant_expr(expr).get_value();
422
423 if(
424 type.id() == ID_unsignedbv || type.id() == ID_signedbv ||
425 type.id() == ID_floatbv || type.id() == ID_fixedbv ||
426 type.id() == ID_c_bit_field || type.id() == ID_bv ||
427 type.id() == ID_c_bool)
428 {
429 const auto width = to_bitvector_type(type).get_width();
430
431 endianness_mapt map(type, little_endian, ns);
432
433 std::string result(width, ' ');
434
435 for(std::string::size_type i = 0; i < width; ++i)
436 result[map.map_bit(i)] = get_bvrep_bit(value, width, i) ? '1' : '0';
437
438 return result;
439 }
440 else if(type.id() == ID_pointer)
441 {
442 if(config.ansi_c.NULL_is_zero && to_constant_expr(expr).is_null_pointer())
443 return std::string(to_bitvector_type(type).get_width(), '0');
444 else
445 return {};
446 }
447 else if(type.id() == ID_c_enum_tag)
448 {
449 const auto &c_enum_type = ns.follow_tag(to_c_enum_tag_type(type));
450 return expr2bits(constant_exprt(value, c_enum_type), little_endian, ns);
451 }
452 else if(type.id() == ID_c_enum)
453 {
454 return expr2bits(
455 constant_exprt(value, to_c_enum_type(type).underlying_type()),
456 little_endian,
457 ns);
458 }
459 }
460 else if(expr.id() == ID_string_constant)
461 {
462 return expr2bits(
463 to_string_constant(expr).to_array_expr(), little_endian, ns);
464 }
465 else if(expr.id() == ID_union)
466 {
467 return expr2bits(to_union_expr(expr).op(), little_endian, ns);
468 }
469 else if(
470 expr.id() == ID_struct || expr.id() == ID_array || expr.id() == ID_vector ||
471 expr.id() == ID_complex)
472 {
473 std::string result;
474 for(const auto &op : expr.operands())
475 {
476 auto tmp = expr2bits(op, little_endian, ns);
477 if(!tmp.has_value())
478 return {}; // failed
479 result += tmp.value();
480 }
481
482 return result;
483 }
484
485 return {};
486}
487
488std::optional<std::reference_wrapper<const array_exprt>>
490{
491 if(content.id() != ID_address_of)
492 {
493 return {};
494 }
495
496 const auto &array_pointer = to_address_of_expr(content);
497
498 if(array_pointer.object().id() != ID_index)
499 {
500 return {};
501 }
502
503 const auto &array_start = to_index_expr(array_pointer.object());
504
505 if(
506 array_start.array().id() != ID_symbol ||
507 array_start.array().type().id() != ID_array)
508 {
509 return {};
510 }
511
512 const auto &array = to_symbol_expr(array_start.array());
513
514 const symbolt *symbol_ptr = nullptr;
515
516 if(
517 ns.lookup(array.get_identifier(), symbol_ptr) ||
518 symbol_ptr->value.id() != ID_array)
519 {
520 return {};
521 }
522
523 const auto &char_seq = to_array_expr(symbol_ptr->value);
524
525 return std::optional<std::reference_wrapper<const array_exprt>>(char_seq);
526}
configt config
Definition config.cpp:25
bool get_bvrep_bit(const irep_idt &src, std::size_t width, std::size_t bit_index)
Get a bit with given index from bit-vector representation.
irep_idt integer2bvrep(const mp_integer &src, std::size_t width)
convert an integer to bit-vector representation with given width This uses two's complement for negat...
const T & as_const(T &value)
Return a reference to the same object but ensures the type is const.
Definition as_const.h:14
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
const c_enum_typet & to_c_enum_type(const typet &type)
Cast a typet to a c_enum_typet.
Definition c_types.h:335
const c_enum_tag_typet & to_c_enum_tag_type(const typet &type)
Cast a typet to a c_enum_tag_typet.
Definition c_types.h:377
const union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Definition c_types.h:184
const union_tag_typet & to_union_tag_type(const typet &type)
Cast a typet to a union_tag_typet.
Definition c_types.h:224
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
Array constructor from list of elements.
Definition std_expr.h:1621
Arrays with given size.
Definition std_types.h:807
Complex constructor from a pair of numbers.
Definition std_expr.h:1916
Complex numbers made of pair of given subtype.
Definition std_types.h:1133
struct configt::ansi_ct ansi_c
A constant literal expression.
Definition std_expr.h:3117
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
Union constructor to support unions without any member (a GCC/Clang feature).
Definition std_expr.h:1834
Maps a big-endian offset to a little-endian offset.
size_t map_bit(size_t bit) const
Base class for all expressions.
Definition expr.h:56
std::vector< exprt > operandst
Definition expr.h:58
bool has_operands() const
Return true if there is at least one operand.
Definition expr.h:91
void reserve_operands(operandst::size_type n)
Definition expr.h:158
bool is_constant() const
Return whether the expression is a constant.
Definition expr.h:212
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
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition namespace.cpp:49
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
The null pointer constant.
Struct constructor from list of elements.
Definition std_expr.h:1877
Structure type, corresponds to C style structs.
Definition std_types.h:231
std::vector< componentt > componentst
Definition std_types.h:140
Symbol table entry.
Definition symbol.h:28
The type of an expression, extends irept.
Definition type.h:29
Union constructor from single element.
Definition std_expr.h:1770
The union type.
Definition c_types.h:147
Vector constructor from list of elements.
Definition std_expr.h:1734
The vector type.
Definition std_types.h:1064
#define forall_expr(it, expr)
Definition expr.h:32
bool is_null_pointer(const constant_exprt &expr)
Returns true if expr has a pointer type and a value NULL; it also returns true when expr has value ze...
Deprecated expression utility functions.
const mp_integer binary2integer(const std::string &n, bool is_signed)
convert binary string representation to mp_integer
Definition mp_arith.cpp:117
API to expression classes for Pointers.
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
std::optional< mp_integer > pointer_offset_bits(const typet &type, const namespacet &ns)
Pointer Logic.
struct saj_tablet saj_table[]
bool sort_operands(exprt::operandst &operands)
sort operands of an expression according to ordering defined by operator<
static const struct saj_tablet & get_sort_and_join_table_entry(const irep_idt &id, const irep_idt &type_id)
static bool is_associative_and_commutative_for_type(const struct saj_tablet &saj_entry, const irep_idt &type_id)
std::optional< exprt > bits2expr(const std::string &bits, const typet &type, bool little_endian, const namespacet &ns)
std::optional< std::string > expr2bits(const exprt &expr, bool little_endian, const namespacet &ns)
static bool sort_and_join(exprt &expr, bool do_sort)
std::optional< std::reference_wrapper< const array_exprt > > try_get_string_data_array(const exprt &content, const namespacet &ns)
Get char sequence from content field of a refined string expression.
bool join_operands(exprt &expr)
BigInt mp_integer
Definition smt_terms.h:17
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#define PRECONDITION(CONDITION)
Definition invariant.h:463
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition std_expr.cpp:97
API to expression classes.
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1538
const array_exprt & to_array_expr(const exprt &expr)
Cast an exprt to an array_exprt.
Definition std_expr.h:1665
const union_exprt & to_union_expr(const exprt &expr)
Cast an exprt to a union_exprt.
Definition std_expr.h:1816
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3172
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:272
const vector_typet & to_vector_type(const typet &type)
Cast a typet to a vector_typet.
Definition std_types.h:1116
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition std_types.h:308
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition std_types.h:518
const complex_typet & to_complex_type(const typet &type)
Cast a typet to a complex_typet.
Definition std_types.h:1158
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition std_types.h:888
const string_constantt & to_string_constant(const exprt &expr)
produce canonical ordering for associative and commutative binary operators
const irep_idt id
const irep_idt type_ids[10]
Symbol table entry.
dstringt irep_idt