CBMC
simplify_utils.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module:
4 
5 Author: 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 
61 struct saj_tablet
62 {
63  const irep_idt id;
64  const irep_idt type_ids[10];
65 } const saj_table[]=
66 {
67  { ID_plus, {ID_integer ,
68  ID_natural ,
69  ID_real ,
70  ID_complex ,
71  ID_rational ,
72  ID_unsignedbv ,
73  ID_signedbv ,
74  ID_fixedbv ,
75  irep_idt() }},
76  { ID_mult, {ID_integer ,
77  ID_natural ,
78  ID_real ,
79  ID_complex ,
80  ID_rational ,
81  ID_unsignedbv ,
82  ID_signedbv ,
83  ID_fixedbv ,
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() }},
91  { ID_bitand, {ID_unsignedbv ,
92  ID_signedbv ,
93  ID_floatbv ,
94  ID_fixedbv ,
95  irep_idt() }},
96  { ID_bitor, {ID_unsignedbv ,
97  ID_signedbv ,
98  ID_floatbv ,
99  ID_fixedbv ,
100  irep_idt() }},
101  { ID_bitxor, {ID_unsignedbv ,
102  ID_signedbv ,
103  ID_floatbv ,
104  ID_fixedbv ,
105  irep_idt() }},
106  { irep_idt(), { irep_idt() }}
107 };
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 
120 static 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 
136 static 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  {
152  if(!is_associative_and_commutative_for_type(saj_entry, op.type().id()))
153  return true;
154  }
155 
156  // join expressions
157 
158  exprt::operandst new_ops;
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)
178  no_change = sort_operands(new_ops) && no_change;
179 
180  if(!no_change)
181  expr.operands().swap(new_ops);
182 
183  return no_change;
184 }
185 
186 bool sort_and_join(exprt &expr)
187 {
188  return sort_and_join(expr, true);
189 }
190 
191 bool join_operands(exprt &expr)
192 {
193  return sort_and_join(expr, false);
194 }
195 
196 std::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  {
225  return null_pointer_exprt(to_pointer_type(type));
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  {
295  const struct_typet &struct_type = to_struct_type(type);
296  const struct_typet::componentst &components = struct_type.components();
297 
298  struct_exprt result({}, type);
299  result.reserve_operands(components.size());
300 
301  mp_integer m_offset_bits = 0;
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,
309  numeric_cast_v<std::size_t>(m_offset_bits),
310  numeric_cast_v<std::size_t>(*m_size));
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 =
342  numeric_cast_v<std::size_t>(to_constant_expr(size_expr));
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);
350  result.reserve_operands(number_of_elements);
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  {
366  const vector_typet &vector_type = to_vector_type(type);
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  {
393  const complex_typet &complex_type = to_complex_type(type);
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 
398  const std::size_t sub_size = numeric_cast_v<std::size_t>(*sub_size_opt);
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 
413 std::optional<std::string>
414 expr2bits(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  {
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 
488 std::optional<std::reference_wrapper<const array_exprt>>
489 try_get_string_data_array(const exprt &content, const namespacet &ns)
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 union_tag_typet & to_union_tag_type(const typet &type)
Cast a typet to a union_tag_typet.
Definition: c_types.h:224
const union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Definition: c_types.h:184
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
Array constructor from list of elements.
Definition: std_expr.h:1616
Arrays with given size.
Definition: std_types.h:807
const typet & element_type() const
The type of the elements of the array.
Definition: std_types.h:827
const exprt & size() const
Definition: std_types.h:840
std::size_t get_width() const
Definition: std_types.h:920
Complex constructor from a pair of numbers.
Definition: std_expr.h:1911
Complex numbers made of pair of given subtype.
Definition: std_types.h:1121
struct configt::ansi_ct ansi_c
A constant literal expression.
Definition: std_expr.h:2987
const irep_idt & get_value() const
Definition: std_expr.h:2995
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
bool empty() const
Definition: dstring.h:89
size_t size() const
Definition: dstring.h:121
Union constructor to support unions without any member (a GCC/Clang feature).
Definition: std_expr.h:1829
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
typet & type()
Return the type of the expression.
Definition: expr.h:84
bool is_constant() const
Return whether the expression is a constant.
Definition: expr.h:212
operandst & operands()
Definition: expr.h:94
const irep_idt & id() const
Definition: irep.h:384
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition: namespace.cpp:63
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:148
The null pointer constant.
Definition: pointer_expr.h:909
Struct constructor from list of elements.
Definition: std_expr.h:1872
Structure type, corresponds to C style structs.
Definition: std_types.h:231
const componentst & components() const
Definition: std_types.h:147
std::vector< componentt > componentst
Definition: std_types.h:140
Symbol table entry.
Definition: symbol.h:28
exprt value
Initial value of symbol.
Definition: symbol.h:34
const typet & subtype() const
Definition: type.h:187
The type of an expression, extends irept.
Definition: type.h:29
Union constructor from single element.
Definition: std_expr.h:1765
The union type.
Definition: c_types.h:147
Vector constructor from list of elements.
Definition: std_expr.h:1729
The vector type.
Definition: std_types.h:1052
const constant_exprt & size() const
Definition: std_types.cpp:275
const typet & element_type() const
The type of the elements of the vector.
Definition: std_types.h:1068
#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...
Definition: expr_util.cpp:369
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 pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:93
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:577
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<
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.
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< std::string > expr2bits(const exprt &expr, bool little_endian, const namespacet &ns)
std::optional< exprt > bits2expr(const std::string &bits, const typet &type, bool little_endian, const namespacet &ns)
static bool sort_and_join(exprt &expr, bool do_sort)
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:80
API to expression classes.
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:3037
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const array_exprt & to_array_expr(const exprt &expr)
Cast an exprt to an array_exprt.
Definition: std_expr.h:1660
const union_exprt & to_union_expr(const exprt &expr)
Cast an exprt to a union_exprt.
Definition: std_expr.h:1811
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1533
const vector_typet & to_vector_type(const typet &type)
Cast a typet to a vector_typet.
Definition: std_types.h:1104
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:888
const complex_typet & to_complex_type(const typet &type)
Cast a typet to a complex_typet.
Definition: std_types.h:1146
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 string_constantt & to_string_constant(const exprt &expr)
bool NULL_is_zero
Definition: config.h:224
produce canonical ordering for associative and commutative binary operators
const irep_idt id
const irep_idt type_ids[10]
Symbol table entry.
#define size_type
Definition: unistd.c:347
dstringt irep_idt