CBMC
simplify_expr.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_expr.h"
10 
11 #include <algorithm>
12 
13 #include "bitvector_expr.h"
14 #include "byte_operators.h"
15 #include "c_types.h"
16 #include "config.h"
17 #include "expr_util.h"
18 #include "fixedbv.h"
19 #include "floatbv_expr.h"
20 #include "invariant.h"
21 #include "mathematical_expr.h"
22 #include "namespace.h"
23 #include "pointer_expr.h"
24 #include "pointer_offset_size.h"
25 #include "pointer_offset_sum.h"
26 #include "rational.h"
27 #include "rational_tools.h"
28 #include "simplify_utils.h"
29 #include "std_expr.h"
30 #include "string_expr.h"
31 
32 // #define DEBUGX
33 
34 #ifdef DEBUGX
35 #include "format_expr.h"
36 #include <iostream>
37 #endif
38 
39 #include "simplify_expr_class.h"
40 
41 // #define USE_CACHE
42 
43 #ifdef USE_CACHE
44 struct simplify_expr_cachet
45 {
46 public:
47  #if 1
48  typedef std::unordered_map<
49  exprt, exprt, irep_full_hash, irep_full_eq> containert;
50  #else
51  typedef std::unordered_map<exprt, exprt, irep_hash> containert;
52  #endif
53 
54  containert container_normal;
55 
56  containert &container()
57  {
58  return container_normal;
59  }
60 };
61 
62 simplify_expr_cachet simplify_expr_cache;
63 #endif
64 
66 {
67  if(expr.op().is_constant())
68  {
69  const typet &type = to_unary_expr(expr).op().type();
70 
71  if(type.id()==ID_floatbv)
72  {
73  ieee_floatt value(to_constant_expr(to_unary_expr(expr).op()));
74  value.set_sign(false);
75  return value.to_expr();
76  }
77  else if(type.id()==ID_signedbv ||
78  type.id()==ID_unsignedbv)
79  {
80  auto value = numeric_cast<mp_integer>(to_unary_expr(expr).op());
81  if(value.has_value())
82  {
83  if(*value >= 0)
84  {
85  return to_unary_expr(expr).op();
86  }
87  else
88  {
89  value->negate();
90  return from_integer(*value, type);
91  }
92  }
93  }
94  }
95 
96  return unchanged(expr);
97 }
98 
100 {
101  if(expr.op().is_constant())
102  {
103  const typet &type = expr.op().type();
104 
105  if(type.id()==ID_floatbv)
106  {
107  ieee_floatt value(to_constant_expr(expr.op()));
108  return make_boolean_expr(value.get_sign());
109  }
110  else if(type.id()==ID_signedbv ||
111  type.id()==ID_unsignedbv)
112  {
113  const auto value = numeric_cast<mp_integer>(expr.op());
114  if(value.has_value())
115  {
116  return make_boolean_expr(*value >= 0);
117  }
118  }
119  }
120 
121  return unchanged(expr);
122 }
123 
126 {
127  const exprt &op = expr.op();
128 
129  if(op.is_constant())
130  {
131  const typet &op_type = op.type();
132 
133  if(op_type.id() == ID_signedbv || op_type.id() == ID_unsignedbv)
134  {
135  const auto width = to_bitvector_type(op_type).get_width();
136  const auto &value = to_constant_expr(op).get_value();
137  std::size_t result = 0;
138 
139  for(std::size_t i = 0; i < width; i++)
140  if(get_bvrep_bit(value, width, i))
141  result++;
142 
143  return from_integer(result, expr.type());
144  }
145  }
146 
147  return unchanged(expr);
148 }
149 
152 {
153  const bool is_little_endian =
155 
156  const auto const_bits_opt = expr2bits(expr.op(), is_little_endian, ns);
157 
158  if(!const_bits_opt.has_value())
159  return unchanged(expr);
160 
161  std::size_t n_leading_zeros =
162  is_little_endian ? const_bits_opt->rfind('1') : const_bits_opt->find('1');
163  if(n_leading_zeros == std::string::npos)
164  {
165  if(!expr.zero_permitted())
166  return unchanged(expr);
167 
168  n_leading_zeros = const_bits_opt->size();
169  }
170  else if(is_little_endian)
171  n_leading_zeros = const_bits_opt->size() - n_leading_zeros - 1;
172 
173  return from_integer(n_leading_zeros, expr.type());
174 }
175 
178 {
179  const bool is_little_endian =
181 
182  const auto const_bits_opt = expr2bits(expr.op(), is_little_endian, ns);
183 
184  if(!const_bits_opt.has_value())
185  return unchanged(expr);
186 
187  std::size_t n_trailing_zeros =
188  is_little_endian ? const_bits_opt->find('1') : const_bits_opt->rfind('1');
189  if(n_trailing_zeros == std::string::npos)
190  {
191  if(!expr.zero_permitted())
192  return unchanged(expr);
193 
194  n_trailing_zeros = const_bits_opt->size();
195  }
196  else if(!is_little_endian)
197  n_trailing_zeros = const_bits_opt->size() - n_trailing_zeros - 1;
198 
199  return from_integer(n_trailing_zeros, expr.type());
200 }
201 
204 {
205  const bool is_little_endian =
207 
208  const auto const_bits_opt = expr2bits(expr.op(), is_little_endian, ns);
209 
210  if(!const_bits_opt.has_value())
211  return unchanged(expr);
212 
213  std::size_t first_one_bit =
214  is_little_endian ? const_bits_opt->find('1') : const_bits_opt->rfind('1');
215  if(first_one_bit == std::string::npos)
216  first_one_bit = 0;
217  else if(is_little_endian)
218  ++first_one_bit;
219  else
220  first_one_bit = const_bits_opt->size() - first_one_bit;
221 
222  return from_integer(first_one_bit, expr.type());
223 }
224 
230  const function_application_exprt &expr,
231  const namespacet &ns)
232 {
233  const refined_string_exprt &s1 = to_string_expr(expr.arguments().at(0));
234  const auto s1_data_opt = try_get_string_data_array(s1.content(), ns);
235 
236  if(!s1_data_opt)
237  return simplify_exprt::unchanged(expr);
238 
239  const array_exprt &s1_data = s1_data_opt->get();
240  const refined_string_exprt &s2 = to_string_expr(expr.arguments().at(1));
241  const auto s2_data_opt = try_get_string_data_array(s2.content(), ns);
242 
243  if(!s2_data_opt)
244  return simplify_exprt::unchanged(expr);
245 
246  const array_exprt &s2_data = s2_data_opt->get();
247  const bool res = s2_data.operands().size() <= s1_data.operands().size() &&
248  std::equal(
249  s2_data.operands().rbegin(),
250  s2_data.operands().rend(),
251  s1_data.operands().rbegin());
252 
253  return from_integer(res ? 1 : 0, expr.type());
254 }
255 
258  const function_application_exprt &expr,
259  const namespacet &ns)
260 {
261  // We want to get both arguments of any starts-with comparison, and
262  // trace them back to the actual string instance. All variables on the
263  // way must be constant for us to be sure this will work.
264  auto &first_argument = to_string_expr(expr.arguments().at(0));
265  auto &second_argument = to_string_expr(expr.arguments().at(1));
266 
267  const auto first_value_opt =
268  try_get_string_data_array(first_argument.content(), ns);
269 
270  if(!first_value_opt)
271  {
272  return simplify_exprt::unchanged(expr);
273  }
274 
275  const array_exprt &first_value = first_value_opt->get();
276 
277  const auto second_value_opt =
278  try_get_string_data_array(second_argument.content(), ns);
279 
280  if(!second_value_opt)
281  {
282  return simplify_exprt::unchanged(expr);
283  }
284 
285  const array_exprt &second_value = second_value_opt->get();
286 
287  // Is our 'contains' array directly contained in our target.
288  const bool includes =
289  std::search(
290  first_value.operands().begin(),
291  first_value.operands().end(),
292  second_value.operands().begin(),
293  second_value.operands().end()) != first_value.operands().end();
294 
295  return from_integer(includes ? 1 : 0, expr.type());
296 }
297 
303  const function_application_exprt &expr,
304  const namespacet &ns)
305 {
306  const function_application_exprt &function_app =
308  const refined_string_exprt &s =
309  to_string_expr(function_app.arguments().at(0));
310 
311  if(!s.length().is_constant())
312  return simplify_exprt::unchanged(expr);
313 
314  const auto numeric_length =
315  numeric_cast_v<mp_integer>(to_constant_expr(s.length()));
316 
317  return from_integer(numeric_length == 0 ? 1 : 0, expr.type());
318 }
319 
328  const function_application_exprt &expr,
329  const namespacet &ns)
330 {
331  const refined_string_exprt &s1 = to_string_expr(expr.arguments().at(0));
332  const auto s1_data_opt = try_get_string_data_array(s1.content(), ns);
333 
334  if(!s1_data_opt)
335  return simplify_exprt::unchanged(expr);
336 
337  const refined_string_exprt &s2 = to_string_expr(expr.arguments().at(1));
338  const auto s2_data_opt = try_get_string_data_array(s2.content(), ns);
339 
340  if(!s2_data_opt)
341  return simplify_exprt::unchanged(expr);
342 
343  const array_exprt &s1_data = s1_data_opt->get();
344  const array_exprt &s2_data = s2_data_opt->get();
345 
346  if(s1_data.operands() == s2_data.operands())
347  return from_integer(0, expr.type());
348 
349  const mp_integer s1_size = s1_data.operands().size();
350  const mp_integer s2_size = s2_data.operands().size();
351  const bool first_shorter = s1_size < s2_size;
352  const exprt::operandst &ops1 =
353  first_shorter ? s1_data.operands() : s2_data.operands();
354  const exprt::operandst &ops2 =
355  first_shorter ? s2_data.operands() : s1_data.operands();
356  auto it_pair = std::mismatch(ops1.begin(), ops1.end(), ops2.begin());
357 
358  if(it_pair.first == ops1.end())
359  return from_integer(s1_size - s2_size, expr.type());
360 
361  const mp_integer char1 =
362  numeric_cast_v<mp_integer>(to_constant_expr(*it_pair.first));
363  const mp_integer char2 =
364  numeric_cast_v<mp_integer>(to_constant_expr(*it_pair.second));
365 
366  return from_integer(
367  first_shorter ? char1 - char2 : char2 - char1, expr.type());
368 }
369 
377  const function_application_exprt &expr,
378  const namespacet &ns,
379  const bool search_from_end)
380 {
381  std::size_t starting_index = 0;
382 
383  // Determine starting index for the comparison (if given)
384  if(expr.arguments().size() == 3)
385  {
386  auto &starting_index_expr = expr.arguments().at(2);
387 
388  if(!starting_index_expr.is_constant())
389  {
390  return simplify_exprt::unchanged(expr);
391  }
392 
393  const mp_integer idx =
394  numeric_cast_v<mp_integer>(to_constant_expr(starting_index_expr));
395 
396  // Negative indices are treated like 0
397  if(idx > 0)
398  {
399  starting_index = numeric_cast_v<std::size_t>(idx);
400  }
401  }
402 
403  const refined_string_exprt &s1 = to_string_expr(expr.arguments().at(0));
404 
405  const auto s1_data_opt = try_get_string_data_array(s1.content(), ns);
406 
407  if(!s1_data_opt)
408  {
409  return simplify_exprt::unchanged(expr);
410  }
411 
412  const array_exprt &s1_data = s1_data_opt->get();
413 
414  const auto search_string_size = s1_data.operands().size();
415  if(starting_index >= search_string_size)
416  {
417  return from_integer(-1, expr.type());
418  }
419 
420  unsigned long starting_offset =
421  starting_index > 0 ? (search_string_size - 1) - starting_index : 0;
423  {
424  // Second argument is a string
425 
426  const refined_string_exprt &s2 = to_string_expr(expr.arguments().at(1));
427 
428  const auto s2_data_opt = try_get_string_data_array(s2.content(), ns);
429 
430  if(!s2_data_opt)
431  {
432  return simplify_exprt::unchanged(expr);
433  }
434 
435  const array_exprt &s2_data = s2_data_opt->get();
436 
437  // Searching for empty string is a special case and is simply the
438  // "always found at the first searched position. This needs to take into
439  // account starting position and if you're starting from the beginning or
440  // end.
441  if(s2_data.operands().empty())
442  return from_integer(
443  search_from_end
444  ? starting_index > 0 ? starting_index : search_string_size
445  : 0,
446  expr.type());
447 
448  if(search_from_end)
449  {
450  auto end = std::prev(s1_data.operands().end(), starting_offset);
451  auto it = std::find_end(
452  s1_data.operands().begin(),
453  end,
454  s2_data.operands().begin(),
455  s2_data.operands().end());
456  if(it != end)
457  return from_integer(
458  std::distance(s1_data.operands().begin(), it), expr.type());
459  }
460  else
461  {
462  auto it = std::search(
463  std::next(s1_data.operands().begin(), starting_index),
464  s1_data.operands().end(),
465  s2_data.operands().begin(),
466  s2_data.operands().end());
467 
468  if(it != s1_data.operands().end())
469  return from_integer(
470  std::distance(s1_data.operands().begin(), it), expr.type());
471  }
472  }
473  else if(expr.arguments().at(1).is_constant())
474  {
475  // Second argument is a constant character
476 
477  const constant_exprt &c1 = to_constant_expr(expr.arguments().at(1));
478  const auto c1_val = numeric_cast_v<mp_integer>(c1);
479 
480  auto pred = [&](const exprt &c2) {
481  const auto c2_val = numeric_cast_v<mp_integer>(to_constant_expr(c2));
482 
483  return c1_val == c2_val;
484  };
485 
486  if(search_from_end)
487  {
488  auto it = std::find_if(
489  std::next(s1_data.operands().rbegin(), starting_offset),
490  s1_data.operands().rend(),
491  pred);
492  if(it != s1_data.operands().rend())
493  return from_integer(
494  std::distance(s1_data.operands().begin(), it.base() - 1),
495  expr.type());
496  }
497  else
498  {
499  auto it = std::find_if(
500  std::next(s1_data.operands().begin(), starting_index),
501  s1_data.operands().end(),
502  pred);
503  if(it != s1_data.operands().end())
504  return from_integer(
505  std::distance(s1_data.operands().begin(), it), expr.type());
506  }
507  }
508  else
509  {
510  return simplify_exprt::unchanged(expr);
511  }
512 
513  return from_integer(-1, expr.type());
514 }
515 
522  const function_application_exprt &expr,
523  const namespacet &ns)
524 {
525  if(!expr.arguments().at(1).is_constant())
526  {
527  return simplify_exprt::unchanged(expr);
528  }
529 
530  const auto &index = to_constant_expr(expr.arguments().at(1));
531 
532  const refined_string_exprt &s = to_string_expr(expr.arguments().at(0));
533 
534  const auto char_seq_opt = try_get_string_data_array(s.content(), ns);
535 
536  if(!char_seq_opt)
537  {
538  return simplify_exprt::unchanged(expr);
539  }
540 
541  const array_exprt &char_seq = char_seq_opt->get();
542 
543  const auto i_opt = numeric_cast<std::size_t>(index);
544 
545  if(!i_opt || *i_opt >= char_seq.operands().size())
546  {
547  return simplify_exprt::unchanged(expr);
548  }
549 
550  const auto &c = to_constant_expr(char_seq.operands().at(*i_opt));
551 
552  if(c.type() != expr.type())
553  {
554  return simplify_exprt::unchanged(expr);
555  }
556 
557  return c;
558 }
559 
561 static bool lower_case_string_expression(array_exprt &string_data)
562 {
563  auto &operands = string_data.operands();
564  for(auto &operand : operands)
565  {
566  auto &constant_value = to_constant_expr(operand);
567  auto character = numeric_cast_v<unsigned int>(constant_value);
568 
569  // Can't guarantee matches against non-ASCII characters.
570  if(character >= 128)
571  return false;
572 
573  if(isalpha(character))
574  {
575  if(isupper(character))
576  constant_value =
577  from_integer(tolower(character), constant_value.type());
578  }
579  }
580 
581  return true;
582 }
583 
590  const function_application_exprt &expr,
591  const namespacet &ns)
592 {
593  // We want to get both arguments of any starts-with comparison, and
594  // trace them back to the actual string instance. All variables on the
595  // way must be constant for us to be sure this will work.
596  auto &first_argument = to_string_expr(expr.arguments().at(0));
597  auto &second_argument = to_string_expr(expr.arguments().at(1));
598 
599  const auto first_value_opt =
600  try_get_string_data_array(first_argument.content(), ns);
601 
602  if(!first_value_opt)
603  {
604  return simplify_exprt::unchanged(expr);
605  }
606 
607  array_exprt first_value = first_value_opt->get();
608 
609  const auto second_value_opt =
610  try_get_string_data_array(second_argument.content(), ns);
611 
612  if(!second_value_opt)
613  {
614  return simplify_exprt::unchanged(expr);
615  }
616 
617  array_exprt second_value = second_value_opt->get();
618 
619  // Just lower-case both expressions.
620  if(
621  !lower_case_string_expression(first_value) ||
622  !lower_case_string_expression(second_value))
623  return simplify_exprt::unchanged(expr);
624 
625  bool is_equal = first_value == second_value;
626  return from_integer(is_equal ? 1 : 0, expr.type());
627 }
628 
635  const function_application_exprt &expr,
636  const namespacet &ns)
637 {
638  // We want to get both arguments of any starts-with comparison, and
639  // trace them back to the actual string instance. All variables on the
640  // way must be constant for us to be sure this will work.
641  auto &first_argument = to_string_expr(expr.arguments().at(0));
642  auto &second_argument = to_string_expr(expr.arguments().at(1));
643 
644  const auto first_value_opt =
645  try_get_string_data_array(first_argument.content(), ns);
646 
647  if(!first_value_opt)
648  {
649  return simplify_exprt::unchanged(expr);
650  }
651 
652  const array_exprt &first_value = first_value_opt->get();
653 
654  const auto second_value_opt =
655  try_get_string_data_array(second_argument.content(), ns);
656 
657  if(!second_value_opt)
658  {
659  return simplify_exprt::unchanged(expr);
660  }
661 
662  const array_exprt &second_value = second_value_opt->get();
663 
664  mp_integer offset_int = 0;
665  if(expr.arguments().size() == 3)
666  {
667  auto &offset = expr.arguments()[2];
668  if(!offset.is_constant())
669  return simplify_exprt::unchanged(expr);
670  offset_int = numeric_cast_v<mp_integer>(to_constant_expr(offset));
671  }
672 
673  // test whether second_value is a prefix of first_value
674  bool is_prefix =
675  offset_int >= 0 && mp_integer(first_value.operands().size()) >=
676  offset_int + second_value.operands().size();
677  if(is_prefix)
678  {
679  exprt::operandst::const_iterator second_it =
680  second_value.operands().begin();
681  for(const auto &first_op : first_value.operands())
682  {
683  if(offset_int > 0)
684  --offset_int;
685  else if(second_it == second_value.operands().end())
686  break;
687  else if(first_op != *second_it)
688  {
689  is_prefix = false;
690  break;
691  }
692  else
693  ++second_it;
694  }
695  }
696 
697  return from_integer(is_prefix ? 1 : 0, expr.type());
698 }
699 
701  const function_application_exprt &expr)
702 {
703  if(expr.function().id() == ID_lambda)
704  {
705  // expand the function application
706  return to_lambda_expr(expr.function()).application(expr.arguments());
707  }
708 
709  if(expr.function().id() != ID_symbol)
710  return unchanged(expr);
711 
712  const irep_idt &func_id = to_symbol_expr(expr.function()).get_identifier();
713 
714  // String.startsWith() is used to implement String.equals() in the models
715  // library
716  if(func_id == ID_cprover_string_startswith_func)
717  {
718  return simplify_string_startswith(expr, ns);
719  }
720  else if(func_id == ID_cprover_string_endswith_func)
721  {
722  return simplify_string_endswith(expr, ns);
723  }
724  else if(func_id == ID_cprover_string_is_empty_func)
725  {
726  return simplify_string_is_empty(expr, ns);
727  }
728  else if(func_id == ID_cprover_string_compare_to_func)
729  {
730  return simplify_string_compare_to(expr, ns);
731  }
732  else if(func_id == ID_cprover_string_index_of_func)
733  {
734  return simplify_string_index_of(expr, ns, false);
735  }
736  else if(func_id == ID_cprover_string_char_at_func)
737  {
738  return simplify_string_char_at(expr, ns);
739  }
740  else if(func_id == ID_cprover_string_contains_func)
741  {
742  return simplify_string_contains(expr, ns);
743  }
744  else if(func_id == ID_cprover_string_last_index_of_func)
745  {
746  return simplify_string_index_of(expr, ns, true);
747  }
748  else if(func_id == ID_cprover_string_equals_ignore_case_func)
749  {
751  }
752 
753  return unchanged(expr);
754 }
755 
758 {
759  const typet &expr_type = expr.type();
760  const typet &op_type = expr.op().type();
761 
762  // eliminate casts of infinity
763  if(expr.op().id() == ID_infinity)
764  {
765  typet new_type=expr.type();
766  exprt tmp = expr.op();
767  tmp.type()=new_type;
768  return std::move(tmp);
769  }
770 
771  // casts from NULL to any integer
772  if(
773  op_type.id() == ID_pointer && expr.op().is_constant() &&
774  to_constant_expr(expr.op()).get_value() == ID_NULL &&
775  (expr_type.id() == ID_unsignedbv || expr_type.id() == ID_signedbv) &&
777  {
778  return from_integer(0, expr_type);
779  }
780 
781  // casts from pointer to integer
782  // where width of integer >= width of pointer
783  // (void*)(intX)expr -> (void*)expr
784  if(
785  expr_type.id() == ID_pointer && expr.op().id() == ID_typecast &&
786  (op_type.id() == ID_signedbv || op_type.id() == ID_unsignedbv ||
787  op_type.id() == ID_bv) &&
788  to_bitvector_type(op_type).get_width() >=
789  to_bitvector_type(expr_type).get_width())
790  {
791  auto new_expr = expr;
792  new_expr.op() = to_typecast_expr(expr.op()).op();
793  return changed(simplify_typecast(new_expr)); // rec. call
794  }
795 
796  // eliminate redundant typecasts
797  if(expr.type() == expr.op().type())
798  {
799  return expr.op();
800  }
801 
802  // eliminate casts to proper bool
803  if(expr_type.id()==ID_bool)
804  {
805  // rewrite (bool)x to x!=0
806  binary_relation_exprt inequality(
807  expr.op(),
808  op_type.id() == ID_floatbv ? ID_ieee_float_notequal : ID_notequal,
809  from_integer(0, op_type));
810  inequality.add_source_location()=expr.source_location();
811  return changed(simplify_node(inequality));
812  }
813 
814  // eliminate casts from proper bool
815  if(
816  op_type.id() == ID_bool &&
817  (expr_type.id() == ID_signedbv || expr_type.id() == ID_unsignedbv ||
818  expr_type.id() == ID_c_bool || expr_type.id() == ID_c_bit_field))
819  {
820  // rewrite (T)(bool) to bool?1:0
821  auto one = from_integer(1, expr_type);
822  auto zero = from_integer(0, expr_type);
824  if_exprt{expr.op(), std::move(one), std::move(zero)}));
825  }
826 
827  // circular casts through types shorter than `int`
828  // we use fixed bit widths as this is specifically for the Java bytecode
829  // front-end
830  if(op_type == signedbv_typet(32) && expr.op().id() == ID_typecast)
831  {
832  if(expr_type==c_bool_typet(8) ||
833  expr_type==signedbv_typet(8) ||
834  expr_type==signedbv_typet(16) ||
835  expr_type==unsignedbv_typet(16))
836  {
837  // We checked that the id was ID_typecast in the enclosing `if`
838  const auto &typecast = expr_checked_cast<typecast_exprt>(expr.op());
839  if(typecast.op().type()==expr_type)
840  {
841  return typecast.op();
842  }
843  }
844  }
845 
846  // eliminate casts to _Bool
847  if(expr_type.id()==ID_c_bool &&
848  op_type.id()!=ID_bool)
849  {
850  // rewrite (_Bool)x to (_Bool)(x!=0)
851  exprt inequality = is_not_zero(expr.op(), ns);
852  auto new_expr = expr;
853  new_expr.op() = simplify_node(std::move(inequality));
854  return changed(simplify_typecast(new_expr)); // recursive call
855  }
856 
857  // eliminate typecasts from NULL
858  if(
859  expr_type.id() == ID_pointer && expr.op().is_constant() &&
860  (to_constant_expr(expr.op()).get_value() == ID_NULL ||
861  (expr.op().is_zero() && config.ansi_c.NULL_is_zero)))
862  {
863  exprt tmp = expr.op();
864  tmp.type()=expr.type();
865  to_constant_expr(tmp).set_value(ID_NULL);
866  return std::move(tmp);
867  }
868 
869  // eliminate duplicate pointer typecasts
870  // (T1 *)(T2 *)x -> (T1 *)x
871  if(
872  expr_type.id() == ID_pointer && expr.op().id() == ID_typecast &&
873  op_type.id() == ID_pointer)
874  {
875  auto new_expr = expr;
876  new_expr.op() = to_typecast_expr(expr.op()).op();
877  return changed(simplify_typecast(new_expr)); // recursive call
878  }
879 
880  // casts from integer to pointer and back:
881  // (int)(void *)int -> (int)(size_t)int
882  if(
883  (expr_type.id() == ID_signedbv || expr_type.id() == ID_unsignedbv) &&
884  expr.op().id() == ID_typecast && expr.op().operands().size() == 1 &&
885  op_type.id() == ID_pointer)
886  {
887  auto inner_cast = to_typecast_expr(expr.op());
888  inner_cast.type() = size_type();
889 
890  auto outer_cast = expr;
891  outer_cast.op() = simplify_typecast(inner_cast); // rec. call
892  return changed(simplify_typecast(outer_cast)); // rec. call
893  }
894 
895  // mildly more elaborate version of the above:
896  // (int)((T*)0 + int) -> (int)(sizeof(T)*(size_t)int) if NULL is zero
897  if(
899  (expr_type.id() == ID_signedbv || expr_type.id() == ID_unsignedbv) &&
900  op_type.id() == ID_pointer && expr.op().id() == ID_plus &&
901  expr.op().operands().size() == 2)
902  {
903  const auto &op_plus_expr = to_plus_expr(expr.op());
904 
905  if(
906  (op_plus_expr.op0().id() == ID_typecast &&
907  to_typecast_expr(op_plus_expr.op0()).op().is_zero()) ||
908  (op_plus_expr.op0().is_constant() &&
909  to_constant_expr(op_plus_expr.op0()).is_null_pointer()))
910  {
911  auto sub_size =
912  pointer_offset_size(to_pointer_type(op_type).base_type(), ns);
913  if(sub_size.has_value())
914  {
915  auto new_expr = expr;
916  exprt offset_expr =
917  simplify_typecast(typecast_exprt(op_plus_expr.op1(), size_type()));
918 
919  // void*
920  if(*sub_size == 0 || *sub_size == 1)
921  new_expr.op() = offset_expr;
922  else
923  {
924  new_expr.op() = simplify_mult(
925  mult_exprt(from_integer(*sub_size, size_type()), offset_expr));
926  }
927 
928  return changed(simplify_typecast(new_expr)); // rec. call
929  }
930  }
931  }
932 
933  // Push a numerical typecast into various integer operations, i.e.,
934  // (T)(x OP y) ---> (T)x OP (T)y
935  //
936  // Doesn't work for many, e.g., pointer difference, floating-point,
937  // division, modulo.
938  // Many operations fail if the width of T
939  // is bigger than that of (x OP y). This includes ID_bitnot and
940  // anything that might overflow, e.g., ID_plus.
941  //
942  if((expr_type.id()==ID_signedbv || expr_type.id()==ID_unsignedbv) &&
943  (op_type.id()==ID_signedbv || op_type.id()==ID_unsignedbv))
944  {
945  bool enlarge=
946  to_bitvector_type(expr_type).get_width()>
947  to_bitvector_type(op_type).get_width();
948 
949  if(!enlarge)
950  {
951  irep_idt op_id = expr.op().id();
952 
953  if(
954  op_id == ID_plus || op_id == ID_minus || op_id == ID_mult ||
955  op_id == ID_unary_minus || op_id == ID_bitxor || op_id == ID_bitxnor ||
956  op_id == ID_bitor || op_id == ID_bitand)
957  {
958  exprt result = expr.op();
959 
960  if(
961  result.operands().size() >= 1 &&
962  to_multi_ary_expr(result).op0().type() == result.type())
963  {
964  result.type()=expr.type();
965 
966  Forall_operands(it, result)
967  {
968  auto new_operand = typecast_exprt(*it, expr.type());
969  *it = simplify_typecast(new_operand); // recursive call
970  }
971 
972  return changed(simplify_node(result)); // possibly recursive call
973  }
974  }
975  else if(op_id==ID_ashr || op_id==ID_lshr || op_id==ID_shl)
976  {
977  }
978  }
979  }
980 
981  // Push a numerical typecast into pointer arithmetic
982  // (T)(ptr + int) ---> (T)((size_t)ptr + sizeof(subtype)*(size_t)int)
983  //
984  if(
985  (expr_type.id() == ID_signedbv || expr_type.id() == ID_unsignedbv) &&
986  op_type.id() == ID_pointer && expr.op().id() == ID_plus)
987  {
988  const auto step =
989  pointer_offset_size(to_pointer_type(op_type).base_type(), ns);
990 
991  if(step.has_value() && *step != 0)
992  {
993  const typet size_t_type(size_type());
994  auto new_expr = expr;
995 
996  new_expr.op().type() = size_t_type;
997 
998  for(auto &op : new_expr.op().operands())
999  {
1000  exprt new_op = simplify_typecast(typecast_exprt(op, size_t_type));
1001  if(op.type().id() != ID_pointer && *step > 1)
1002  {
1003  new_op =
1004  simplify_mult(mult_exprt(from_integer(*step, size_t_type), new_op));
1005  }
1006  op = std::move(new_op);
1007  }
1008 
1009  new_expr.op() = simplify_plus(to_plus_expr(new_expr.op()));
1010 
1011  return changed(simplify_typecast(new_expr)); // recursive call
1012  }
1013  }
1014 
1015  const irep_idt &expr_type_id=expr_type.id();
1016  const exprt &operand = expr.op();
1017  const irep_idt &op_type_id=op_type.id();
1018 
1019  if(operand.is_constant())
1020  {
1021  const irep_idt &value=to_constant_expr(operand).get_value();
1022 
1023  // preserve the sizeof type annotation
1024  typet c_sizeof_type=
1025  static_cast<const typet &>(operand.find(ID_C_c_sizeof_type));
1026 
1027  if(op_type_id==ID_integer ||
1028  op_type_id==ID_natural)
1029  {
1030  // from integer to ...
1031 
1032  mp_integer int_value=string2integer(id2string(value));
1033 
1034  if(expr_type_id==ID_bool)
1035  {
1036  return make_boolean_expr(int_value != 0);
1037  }
1038 
1039  if(expr_type_id==ID_unsignedbv ||
1040  expr_type_id==ID_signedbv ||
1041  expr_type_id==ID_c_enum ||
1042  expr_type_id==ID_c_bit_field ||
1043  expr_type_id==ID_integer)
1044  {
1045  return from_integer(int_value, expr_type);
1046  }
1047  else if(expr_type_id == ID_c_enum_tag)
1048  {
1049  const auto &c_enum_type = ns.follow_tag(to_c_enum_tag_type(expr_type));
1050  if(!c_enum_type.is_incomplete()) // possibly incomplete
1051  {
1052  exprt tmp = from_integer(int_value, c_enum_type);
1053  tmp.type() = expr_type; // we maintain the tag type
1054  return std::move(tmp);
1055  }
1056  }
1057  }
1058  else if(op_type_id==ID_rational)
1059  {
1060  }
1061  else if(op_type_id==ID_real)
1062  {
1063  }
1064  else if(op_type_id==ID_bool)
1065  {
1066  if(expr_type_id==ID_unsignedbv ||
1067  expr_type_id==ID_signedbv ||
1068  expr_type_id==ID_integer ||
1069  expr_type_id==ID_natural ||
1070  expr_type_id==ID_rational ||
1071  expr_type_id==ID_c_bool ||
1072  expr_type_id==ID_c_enum ||
1073  expr_type_id==ID_c_bit_field)
1074  {
1075  if(operand.is_true())
1076  {
1077  return from_integer(1, expr_type);
1078  }
1079  else if(operand.is_false())
1080  {
1081  return from_integer(0, expr_type);
1082  }
1083  }
1084  else if(expr_type_id==ID_c_enum_tag)
1085  {
1086  const auto &c_enum_type = ns.follow_tag(to_c_enum_tag_type(expr_type));
1087  if(!c_enum_type.is_incomplete()) // possibly incomplete
1088  {
1089  unsigned int_value = operand.is_true() ? 1u : 0u;
1090  exprt tmp=from_integer(int_value, c_enum_type);
1091  tmp.type()=expr_type; // we maintain the tag type
1092  return std::move(tmp);
1093  }
1094  }
1095  else if(expr_type_id==ID_pointer &&
1096  operand.is_false() &&
1098  {
1099  return null_pointer_exprt(to_pointer_type(expr_type));
1100  }
1101  }
1102  else if(op_type_id==ID_unsignedbv ||
1103  op_type_id==ID_signedbv ||
1104  op_type_id==ID_c_bit_field ||
1105  op_type_id==ID_c_bool)
1106  {
1107  mp_integer int_value;
1108 
1109  if(to_integer(to_constant_expr(operand), int_value))
1110  return unchanged(expr);
1111 
1112  if(expr_type_id==ID_bool)
1113  {
1114  return make_boolean_expr(int_value != 0);
1115  }
1116 
1117  if(expr_type_id==ID_c_bool)
1118  {
1119  return from_integer(int_value != 0, expr_type);
1120  }
1121 
1122  if(expr_type_id==ID_integer)
1123  {
1124  return from_integer(int_value, expr_type);
1125  }
1126 
1127  if(expr_type_id==ID_natural)
1128  {
1129  if(int_value>=0)
1130  {
1131  return from_integer(int_value, expr_type);
1132  }
1133  }
1134 
1135  if(expr_type_id==ID_unsignedbv ||
1136  expr_type_id==ID_signedbv ||
1137  expr_type_id==ID_bv ||
1138  expr_type_id==ID_c_bit_field)
1139  {
1140  auto result = from_integer(int_value, expr_type);
1141 
1142  if(c_sizeof_type.is_not_nil())
1143  result.set(ID_C_c_sizeof_type, c_sizeof_type);
1144 
1145  return std::move(result);
1146  }
1147 
1148  if(expr_type_id==ID_c_enum_tag)
1149  {
1150  const auto &c_enum_type = ns.follow_tag(to_c_enum_tag_type(expr_type));
1151  if(!c_enum_type.is_incomplete()) // possibly incomplete
1152  {
1153  exprt tmp=from_integer(int_value, c_enum_type);
1154  tmp.type()=expr_type; // we maintain the tag type
1155  return std::move(tmp);
1156  }
1157  }
1158 
1159  if(expr_type_id==ID_c_enum)
1160  {
1161  return from_integer(int_value, expr_type);
1162  }
1163 
1164  if(expr_type_id==ID_fixedbv)
1165  {
1166  // int to float
1167  const fixedbv_typet &f_expr_type=
1168  to_fixedbv_type(expr_type);
1169 
1170  fixedbvt f;
1171  f.spec=fixedbv_spect(f_expr_type);
1172  f.from_integer(int_value);
1173  return f.to_expr();
1174  }
1175 
1176  if(expr_type_id==ID_floatbv)
1177  {
1178  // int to float
1179  const floatbv_typet &f_expr_type=
1180  to_floatbv_type(expr_type);
1181 
1182  ieee_floatt f(f_expr_type);
1183  f.from_integer(int_value);
1184 
1185  return f.to_expr();
1186  }
1187 
1188  if(expr_type_id==ID_rational)
1189  {
1190  rationalt r(int_value);
1191  return from_rational(r);
1192  }
1193  }
1194  else if(op_type_id==ID_fixedbv)
1195  {
1196  if(expr_type_id==ID_unsignedbv ||
1197  expr_type_id==ID_signedbv)
1198  {
1199  // cast from fixedbv to int
1200  fixedbvt f(to_constant_expr(expr.op()));
1201  return from_integer(f.to_integer(), expr_type);
1202  }
1203  else if(expr_type_id==ID_fixedbv)
1204  {
1205  // fixedbv to fixedbv
1206  fixedbvt f(to_constant_expr(expr.op()));
1207  f.round(fixedbv_spect(to_fixedbv_type(expr_type)));
1208  return f.to_expr();
1209  }
1210  else if(expr_type_id == ID_bv)
1211  {
1212  fixedbvt f{to_constant_expr(expr.op())};
1213  return from_integer(f.get_value(), expr_type);
1214  }
1215  }
1216  else if(op_type_id==ID_floatbv)
1217  {
1218  ieee_floatt f(to_constant_expr(expr.op()));
1219 
1220  if(expr_type_id==ID_unsignedbv ||
1221  expr_type_id==ID_signedbv)
1222  {
1223  // cast from float to int
1224  return from_integer(f.to_integer(), expr_type);
1225  }
1226  else if(expr_type_id==ID_floatbv)
1227  {
1228  // float to double or double to float
1230  return f.to_expr();
1231  }
1232  else if(expr_type_id==ID_fixedbv)
1233  {
1234  fixedbvt fixedbv;
1235  fixedbv.spec=fixedbv_spect(to_fixedbv_type(expr_type));
1236  ieee_floatt factor(f.spec);
1237  factor.from_integer(power(2, fixedbv.spec.get_fraction_bits()));
1238  f*=factor;
1239  fixedbv.set_value(f.to_integer());
1240  return fixedbv.to_expr();
1241  }
1242  else if(expr_type_id == ID_bv)
1243  {
1244  return from_integer(f.pack(), expr_type);
1245  }
1246  }
1247  else if(op_type_id==ID_bv)
1248  {
1249  if(
1250  expr_type_id == ID_unsignedbv || expr_type_id == ID_signedbv ||
1251  expr_type_id == ID_c_enum || expr_type_id == ID_c_enum_tag ||
1252  expr_type_id == ID_c_bit_field)
1253  {
1254  const auto width = to_bv_type(op_type).get_width();
1255  const auto int_value = bvrep2integer(value, width, false);
1256  if(expr_type_id != ID_c_enum_tag)
1257  return from_integer(int_value, expr_type);
1258  else
1259  {
1260  c_enum_tag_typet tag_type = to_c_enum_tag_type(expr_type);
1261  auto result = from_integer(int_value, ns.follow_tag(tag_type));
1262  result.type() = tag_type;
1263  return std::move(result);
1264  }
1265  }
1266  else if(expr_type_id == ID_floatbv)
1267  {
1268  const auto width = to_bv_type(op_type).get_width();
1269  const auto int_value = bvrep2integer(value, width, false);
1270  ieee_floatt ieee_float{to_floatbv_type(expr_type)};
1271  ieee_float.unpack(int_value);
1272  return ieee_float.to_expr();
1273  }
1274  else if(expr_type_id == ID_fixedbv)
1275  {
1276  const auto width = to_bv_type(op_type).get_width();
1277  const auto int_value = bvrep2integer(value, width, false);
1278  fixedbvt fixedbv{fixedbv_spect{to_fixedbv_type(expr_type)}};
1279  fixedbv.set_value(int_value);
1280  return fixedbv.to_expr();
1281  }
1282  }
1283  else if(op_type_id==ID_c_enum_tag) // enum to int
1284  {
1285  const typet &base_type =
1286  ns.follow_tag(to_c_enum_tag_type(op_type)).underlying_type();
1287  if(base_type.id()==ID_signedbv || base_type.id()==ID_unsignedbv)
1288  {
1289  // enum constants use the representation of their base type
1290  auto new_expr = expr;
1291  new_expr.op().type() = base_type;
1292  return changed(simplify_typecast(new_expr)); // recursive call
1293  }
1294  }
1295  else if(op_type_id==ID_c_enum) // enum to int
1296  {
1297  const typet &base_type = to_c_enum_type(op_type).underlying_type();
1298  if(base_type.id()==ID_signedbv || base_type.id()==ID_unsignedbv)
1299  {
1300  // enum constants use the representation of their base type
1301  auto new_expr = expr;
1302  new_expr.op().type() = base_type;
1303  return changed(simplify_typecast(new_expr)); // recursive call
1304  }
1305  }
1306  }
1307  else if(operand.id()==ID_typecast) // typecast of typecast
1308  {
1309  // (T1)(T2)x ---> (T1)
1310  // where T1 has fewer bits than T2
1311  if(
1312  op_type_id == expr_type_id &&
1313  (expr_type_id == ID_unsignedbv || expr_type_id == ID_signedbv ||
1314  expr_type_id == ID_bv) &&
1315  to_bitvector_type(expr_type).get_width() <=
1316  to_bitvector_type(operand.type()).get_width())
1317  {
1318  auto new_expr = expr;
1319  new_expr.op() = to_typecast_expr(operand).op();
1320  // might enable further simplification
1321  return changed(simplify_typecast(new_expr)); // recursive call
1322  }
1323  }
1324  else if(operand.id()==ID_address_of)
1325  {
1326  const exprt &o=to_address_of_expr(operand).object();
1327 
1328  // turn &array into &array[0] when casting to pointer-to-element-type
1329  if(
1330  o.type().id() == ID_array &&
1331  expr_type == pointer_type(to_array_type(o.type()).element_type()))
1332  {
1333  auto result =
1335 
1336  return changed(simplify_address_of(result)); // recursive call
1337  }
1338  }
1339 
1340  return unchanged(expr);
1341 }
1342 
1345 {
1346  const typet &expr_type = expr.type();
1347  const typet &op_type = expr.op().type();
1348 
1349  // (T)(a?b:c) --> a?(T)b:(T)c; don't do this for floating-point type casts as
1350  // the type cast itself may be costly
1351  if(
1352  expr.op().id() == ID_if && expr_type.id() != ID_floatbv &&
1353  op_type.id() != ID_floatbv)
1354  {
1355  if_exprt if_expr = lift_if(expr, 0);
1356  return changed(simplify_if_preorder(if_expr));
1357  }
1358  else
1359  {
1360  auto r_it = simplify_rec(expr.op()); // recursive call
1361  if(r_it.has_changed())
1362  {
1363  auto tmp = expr;
1364  tmp.op() = r_it.expr;
1365  return tmp;
1366  }
1367  }
1368 
1369  return unchanged(expr);
1370 }
1371 
1374 {
1375  const exprt &pointer = expr.pointer();
1376 
1377  if(pointer.type().id()!=ID_pointer)
1378  return unchanged(expr);
1379 
1380  if(pointer.id()==ID_address_of)
1381  {
1382  exprt tmp=to_address_of_expr(pointer).object();
1383  // one address_of is gone, try again
1384  return changed(simplify_rec(tmp));
1385  }
1386  // rewrite *(&a[0] + x) to a[x]
1387  else if(
1388  pointer.id() == ID_plus && pointer.operands().size() == 2 &&
1389  to_plus_expr(pointer).op0().id() == ID_address_of)
1390  {
1391  const auto &pointer_plus_expr = to_plus_expr(pointer);
1392 
1393  const address_of_exprt &address_of =
1394  to_address_of_expr(pointer_plus_expr.op0());
1395 
1396  if(address_of.object().id()==ID_index)
1397  {
1398  const index_exprt &old=to_index_expr(address_of.object());
1399  if(old.array().type().id() == ID_array)
1400  {
1401  index_exprt idx(
1402  old.array(),
1403  pointer_offset_sum(old.index(), pointer_plus_expr.op1()),
1404  to_array_type(old.array().type()).element_type());
1405  return changed(simplify_rec(idx));
1406  }
1407  }
1408  }
1409 
1410  return unchanged(expr);
1411 }
1412 
1415 {
1416  const exprt &pointer = expr.pointer();
1417 
1418  if(pointer.id() == ID_if)
1419  {
1420  if_exprt if_expr = lift_if(expr, 0);
1421  return changed(simplify_if_preorder(if_expr));
1422  }
1423  else
1424  {
1425  auto r_it = simplify_rec(pointer); // recursive call
1426  if(r_it.has_changed())
1427  {
1428  auto tmp = expr;
1429  tmp.pointer() = r_it.expr;
1430  return tmp;
1431  }
1432  }
1433 
1434  return unchanged(expr);
1435 }
1436 
1439 {
1440  return unchanged(expr);
1441 }
1442 
1444 {
1445  bool no_change = true;
1446 
1447  if((expr.operands().size()%2)!=1)
1448  return unchanged(expr);
1449 
1450  // copy
1451  auto with_expr = expr;
1452 
1453  // now look at first operand
1454 
1455  if(
1456  with_expr.old().type().id() == ID_struct ||
1457  with_expr.old().type().id() == ID_struct_tag)
1458  {
1459  if(with_expr.old().id() == ID_struct || with_expr.old().is_constant())
1460  {
1461  while(with_expr.operands().size() > 1)
1462  {
1463  const irep_idt &component_name =
1464  with_expr.where().get(ID_component_name);
1465 
1466  const struct_typet &old_type_followed =
1467  with_expr.old().type().id() == ID_struct_tag
1468  ? ns.follow_tag(to_struct_tag_type(with_expr.old().type()))
1469  : to_struct_type(with_expr.old().type());
1470  if(!old_type_followed.has_component(component_name))
1471  return unchanged(expr);
1472 
1473  std::size_t number = old_type_followed.component_number(component_name);
1474 
1475  if(number >= with_expr.old().operands().size())
1476  return unchanged(expr);
1477 
1478  with_expr.old().operands()[number].swap(with_expr.new_value());
1479 
1480  with_expr.operands().erase(++with_expr.operands().begin());
1481  with_expr.operands().erase(++with_expr.operands().begin());
1482 
1483  no_change = false;
1484  }
1485  }
1486  }
1487  else if(
1488  with_expr.old().type().id() == ID_array ||
1489  with_expr.old().type().id() == ID_vector)
1490  {
1491  if(
1492  with_expr.old().id() == ID_array || with_expr.old().is_constant() ||
1493  with_expr.old().id() == ID_vector)
1494  {
1495  while(with_expr.operands().size() > 1)
1496  {
1497  const auto i = numeric_cast<mp_integer>(with_expr.where());
1498 
1499  if(!i.has_value())
1500  break;
1501 
1502  if(*i < 0 || *i >= with_expr.old().operands().size())
1503  break;
1504 
1505  with_expr.old().operands()[numeric_cast_v<std::size_t>(*i)].swap(
1506  with_expr.new_value());
1507 
1508  with_expr.operands().erase(++with_expr.operands().begin());
1509  with_expr.operands().erase(++with_expr.operands().begin());
1510 
1511  no_change = false;
1512  }
1513  }
1514  }
1515 
1516  if(with_expr.operands().size() == 1)
1517  return with_expr.old();
1518 
1519  if(no_change)
1520  return unchanged(expr);
1521  else
1522  return std::move(with_expr);
1523 }
1524 
1527 {
1528  // this is to push updates into (possibly nested) constants
1529 
1530  const exprt::operandst &designator = expr.designator();
1531 
1532  exprt updated_value = expr.old();
1533  exprt *value_ptr=&updated_value;
1534 
1535  for(const auto &e : designator)
1536  {
1537  if(e.id()==ID_index_designator &&
1538  value_ptr->id()==ID_array)
1539  {
1540  const auto i = numeric_cast<mp_integer>(to_index_designator(e).index());
1541 
1542  if(!i.has_value())
1543  return unchanged(expr);
1544 
1545  if(*i < 0 || *i >= value_ptr->operands().size())
1546  return unchanged(expr);
1547 
1548  value_ptr = &value_ptr->operands()[numeric_cast_v<std::size_t>(*i)];
1549  }
1550  else if(e.id()==ID_member_designator &&
1551  value_ptr->id()==ID_struct)
1552  {
1553  const irep_idt &component_name=
1554  e.get(ID_component_name);
1555  const struct_typet &value_ptr_struct_type =
1556  value_ptr->type().id() == ID_struct_tag
1557  ? ns.follow_tag(to_struct_tag_type(value_ptr->type()))
1558  : to_struct_type(value_ptr->type());
1559  if(!value_ptr_struct_type.has_component(component_name))
1560  return unchanged(expr);
1561  auto &designator_as_struct_expr = to_struct_expr(*value_ptr);
1562  value_ptr = &designator_as_struct_expr.component(component_name, ns);
1563  CHECK_RETURN(value_ptr->is_not_nil());
1564  }
1565  else
1566  return unchanged(expr); // give up, unknown designator
1567  }
1568 
1569  // found, done
1570  *value_ptr = expr.new_value();
1571  return updated_value;
1572 }
1573 
1575 {
1576  if(expr.id()==ID_plus)
1577  {
1578  if(expr.type().id()==ID_pointer)
1579  {
1580  // kill integers from sum
1581  for(auto &op : expr.operands())
1582  if(op.type().id() == ID_pointer)
1583  return changed(simplify_object(op)); // recursive call
1584  }
1585  }
1586  else if(expr.id()==ID_typecast)
1587  {
1588  auto const &typecast_expr = to_typecast_expr(expr);
1589  const typet &op_type = typecast_expr.op().type();
1590 
1591  if(op_type.id()==ID_pointer)
1592  {
1593  // cast from pointer to pointer
1594  return changed(simplify_object(typecast_expr.op())); // recursive call
1595  }
1596  else if(op_type.id()==ID_signedbv || op_type.id()==ID_unsignedbv)
1597  {
1598  // cast from integer to pointer
1599 
1600  // We do a bit of special treatment for (TYPE *)(a+(int)&o) and
1601  // (TYPE *)(a+(int)((T*)&o+x)), which are re-written to '&o'.
1602 
1603  const exprt &casted_expr = typecast_expr.op();
1604  if(casted_expr.id() == ID_plus && casted_expr.operands().size() == 2)
1605  {
1606  const auto &plus_expr = to_plus_expr(casted_expr);
1607 
1608  const exprt &cand = plus_expr.op0().id() == ID_typecast
1609  ? plus_expr.op0()
1610  : plus_expr.op1();
1611 
1612  if(cand.id() == ID_typecast)
1613  {
1614  const auto &typecast_op = to_typecast_expr(cand).op();
1615 
1616  if(typecast_op.id() == ID_address_of)
1617  {
1618  return typecast_op;
1619  }
1620  else if(
1621  typecast_op.id() == ID_plus && typecast_op.operands().size() == 2 &&
1622  to_plus_expr(typecast_op).op0().id() == ID_typecast &&
1623  to_typecast_expr(to_plus_expr(typecast_op).op0()).op().id() ==
1624  ID_address_of)
1625  {
1626  return to_typecast_expr(to_plus_expr(typecast_op).op0()).op();
1627  }
1628  }
1629  }
1630  }
1631  }
1632  else if(expr.id()==ID_address_of)
1633  {
1634  const auto &object = to_address_of_expr(expr).object();
1635 
1636  if(object.id() == ID_index)
1637  {
1638  // &some[i] -> &some
1639  address_of_exprt new_expr(to_index_expr(object).array());
1640  return changed(simplify_object(new_expr)); // recursion
1641  }
1642  else if(object.id() == ID_member)
1643  {
1644  // &some.f -> &some
1645  address_of_exprt new_expr(to_member_expr(object).compound());
1646  return changed(simplify_object(new_expr)); // recursion
1647  }
1648  }
1649 
1650  return unchanged(expr);
1651 }
1652 
1655 {
1656  // lift up any ID_if on the object
1657  if(expr.op().id() == ID_if)
1658  {
1659  if_exprt if_expr = lift_if(expr, 0);
1660  if_expr.true_case() =
1662  if_expr.false_case() =
1664  return changed(simplify_if(if_expr));
1665  }
1666 
1667  const auto el_size = pointer_offset_bits(expr.type(), ns);
1668  if(el_size.has_value() && *el_size < 0)
1669  return unchanged(expr);
1670 
1671  // byte_extract(byte_extract(root, offset1), offset2) =>
1672  // byte_extract(root, offset1+offset2)
1673  if(expr.op().id()==expr.id())
1674  {
1675  auto tmp = expr;
1676 
1677  tmp.offset() = simplify_rec(plus_exprt(
1679  to_byte_extract_expr(expr.op()).offset(), expr.offset().type()),
1680  expr.offset()));
1681  tmp.op() = to_byte_extract_expr(expr.op()).op();
1682 
1683  return changed(simplify_byte_extract(tmp)); // recursive call
1684  }
1685 
1686  // byte_extract(byte_update(root, offset, value), offset) =>
1687  // value
1688  if(
1689  ((expr.id() == ID_byte_extract_big_endian &&
1690  expr.op().id() == ID_byte_update_big_endian) ||
1691  (expr.id() == ID_byte_extract_little_endian &&
1692  expr.op().id() == ID_byte_update_little_endian)) &&
1693  expr.offset() == to_byte_update_expr(as_const(expr).op()).offset())
1694  {
1695  const auto &op_byte_update = to_byte_update_expr(expr.op());
1696 
1697  if(expr.type() == op_byte_update.value().type())
1698  {
1699  return op_byte_update.value();
1700  }
1701  else if(el_size.has_value())
1702  {
1703  const auto update_bits_opt =
1704  pointer_offset_bits(op_byte_update.value().type(), ns);
1705 
1706  if(update_bits_opt.has_value() && *el_size <= *update_bits_opt)
1707  {
1708  auto tmp = expr;
1709  tmp.op() = op_byte_update.value();
1710  tmp.offset() = from_integer(0, expr.offset().type());
1711 
1712  return changed(simplify_byte_extract(tmp)); // recursive call
1713  }
1714  }
1715  }
1716 
1717  // the following require a constant offset
1718  auto offset = numeric_cast<mp_integer>(expr.offset());
1719  if(!offset.has_value() || *offset < 0)
1720  return unchanged(expr);
1721 
1722  // try to simplify byte_extract(byte_update(...))
1723  auto const bu = expr_try_dynamic_cast<byte_update_exprt>(expr.op());
1724  std::optional<mp_integer> update_offset;
1725  if(bu)
1726  update_offset = numeric_cast<mp_integer>(bu->offset());
1727  if(bu && el_size.has_value() && update_offset.has_value())
1728  {
1729  // byte_extract(byte_update(root, offset_u, value), offset_e) so that the
1730  // update does not affect what is being extracted simplifies to
1731  // byte_extract(root, offset_e)
1732  //
1733  // byte_extract(byte_update(root, offset_u, value), offset_e) so that the
1734  // extracted range fully lies within the update value simplifies to
1735  // byte_extract(value, offset_e - offset_u)
1736  if(
1737  *offset * expr.get_bits_per_byte() + *el_size <=
1738  *update_offset * bu->get_bits_per_byte())
1739  {
1740  // extracting before the update
1741  auto tmp = expr;
1742  tmp.op() = bu->op();
1743  return changed(simplify_byte_extract(tmp)); // recursive call
1744  }
1745  else if(
1746  const auto update_size = pointer_offset_bits(bu->value().type(), ns))
1747  {
1748  if(
1749  *offset * expr.get_bits_per_byte() >=
1750  *update_offset * bu->get_bits_per_byte() + *update_size)
1751  {
1752  // extracting after the update
1753  auto tmp = expr;
1754  tmp.op() = bu->op();
1755  return changed(simplify_byte_extract(tmp)); // recursive call
1756  }
1757  else if(
1758  *offset >= *update_offset &&
1759  *offset * expr.get_bits_per_byte() + *el_size <=
1760  *update_offset * bu->get_bits_per_byte() + *update_size)
1761  {
1762  // extracting from the update
1763  auto tmp = expr;
1764  tmp.op() = bu->value();
1765  tmp.offset() =
1766  from_integer(*offset - *update_offset, expr.offset().type());
1767  return changed(simplify_byte_extract(tmp)); // recursive call
1768  }
1769  }
1770  }
1771 
1772  // don't do any of the following if endianness doesn't match, as
1773  // bytes need to be swapped
1774  if(
1775  *offset == 0 && ((expr.id() == ID_byte_extract_little_endian &&
1778  (expr.id() == ID_byte_extract_big_endian &&
1781  {
1782  // byte extract of full object is object
1783  if(expr.type() == expr.op().type())
1784  {
1785  return expr.op();
1786  }
1787  else if(
1788  expr.type().id() == ID_pointer && expr.op().type().id() == ID_pointer)
1789  {
1790  return typecast_exprt(expr.op(), expr.type());
1791  }
1792  }
1793 
1794  if(
1795  (expr.type().id() == ID_union &&
1796  to_union_type(expr.type()).components().empty()) ||
1797  (expr.type().id() == ID_union_tag &&
1798  ns.follow_tag(to_union_tag_type(expr.type())).components().empty()))
1799  {
1800  return empty_union_exprt{expr.type()};
1801  }
1802  else if(
1803  (expr.type().id() == ID_struct &&
1804  to_struct_type(expr.type()).components().empty()) ||
1805  (expr.type().id() == ID_struct_tag &&
1806  ns.follow_tag(to_struct_tag_type(expr.type())).components().empty()))
1807  {
1808  return struct_exprt{{}, expr.type()};
1809  }
1810 
1811  // no proper simplification for expr.type()==void
1812  // or types of unknown size
1813  if(!el_size.has_value() || *el_size == 0)
1814  return unchanged(expr);
1815 
1816  if(
1817  expr.op().id() == ID_array_of &&
1818  to_array_of_expr(expr.op()).op().is_constant())
1819  {
1820  const auto const_bits_opt = expr2bits(
1821  to_array_of_expr(expr.op()).op(),
1824  ns);
1825 
1826  if(!const_bits_opt.has_value())
1827  return unchanged(expr);
1828 
1829  std::string const_bits=const_bits_opt.value();
1830 
1831  DATA_INVARIANT(!const_bits.empty(), "bit representation must be non-empty");
1832 
1833  // double the string until we have sufficiently many bits
1834  while(mp_integer(const_bits.size()) <
1835  *offset * expr.get_bits_per_byte() + *el_size)
1836  {
1837  const_bits+=const_bits;
1838  }
1839 
1840  std::string el_bits = std::string(
1841  const_bits,
1842  numeric_cast_v<std::size_t>(*offset * expr.get_bits_per_byte()),
1843  numeric_cast_v<std::size_t>(*el_size));
1844 
1845  auto tmp = bits2expr(
1846  el_bits, expr.type(), expr.id() == ID_byte_extract_little_endian, ns);
1847 
1848  if(tmp.has_value())
1849  return std::move(*tmp);
1850  }
1851 
1852  // in some cases we even handle non-const array_of
1853  if(
1854  expr.op().id() == ID_array_of &&
1855  (*offset * expr.get_bits_per_byte()) % (*el_size) == 0 &&
1856  *el_size <=
1858  {
1859  auto tmp = expr;
1860  tmp.op() = simplify_index(index_exprt(expr.op(), expr.offset()));
1861  tmp.offset() = from_integer(0, expr.offset().type());
1862  return changed(simplify_byte_extract(tmp));
1863  }
1864 
1865  // extract bits of a constant
1866  const auto bits =
1867  expr2bits(expr.op(), expr.id() == ID_byte_extract_little_endian, ns);
1868 
1869  if(
1870  bits.has_value() &&
1871  mp_integer(bits->size()) >= *el_size + *offset * expr.get_bits_per_byte())
1872  {
1873  // make sure we don't lose bits with structs containing flexible array
1874  // members
1875  const bool struct_has_flexible_array_member = has_subtype(
1876  expr.type(),
1877  [&](const typet &type) {
1878  if(type.id() != ID_struct && type.id() != ID_struct_tag)
1879  return false;
1880 
1881  const struct_typet &st = type.id() == ID_struct_tag
1882  ? ns.follow_tag(to_struct_tag_type(type))
1883  : to_struct_type(type);
1884  const auto &comps = st.components();
1885  if(comps.empty() || comps.back().type().id() != ID_array)
1886  return false;
1887 
1888  if(comps.back().type().get_bool(ID_C_flexible_array_member))
1889  return true;
1890 
1891  const auto size =
1892  numeric_cast<mp_integer>(to_array_type(comps.back().type()).size());
1893  return !size.has_value() || *size <= 1;
1894  },
1895  ns);
1896  if(!struct_has_flexible_array_member)
1897  {
1898  std::string bits_cut = std::string(
1899  bits.value(),
1900  numeric_cast_v<std::size_t>(*offset * expr.get_bits_per_byte()),
1901  numeric_cast_v<std::size_t>(*el_size));
1902 
1903  auto tmp = bits2expr(
1904  bits_cut, expr.type(), expr.id() == ID_byte_extract_little_endian, ns);
1905 
1906  if(tmp.has_value())
1907  return std::move(*tmp);
1908  }
1909  }
1910 
1911  // push byte extracts into struct or union expressions, just like
1912  // lower_byte_extract does (this is the same code, except recursive calls use
1913  // simplify rather than lower_byte_extract)
1914  if(expr.op().id() == ID_struct || expr.op().id() == ID_union)
1915  {
1916  if(expr.type().id() == ID_struct || expr.type().id() == ID_struct_tag)
1917  {
1918  const struct_typet &struct_type =
1919  expr.type().id() == ID_struct_tag
1921  : to_struct_type(expr.type());
1922  const struct_typet::componentst &components = struct_type.components();
1923 
1924  bool failed = false;
1925  struct_exprt s({}, expr.type());
1926 
1927  for(const auto &comp : components)
1928  {
1929  auto component_bits = pointer_offset_bits(comp.type(), ns);
1930 
1931  // the next member would be misaligned, abort
1932  if(
1933  !component_bits.has_value() || *component_bits == 0 ||
1934  *component_bits % expr.get_bits_per_byte() != 0)
1935  {
1936  failed = true;
1937  break;
1938  }
1939 
1940  auto member_offset_opt =
1941  member_offset_expr(struct_type, comp.get_name(), ns);
1942 
1943  if(!member_offset_opt.has_value())
1944  {
1945  failed = true;
1946  break;
1947  }
1948 
1949  exprt new_offset = simplify_rec(
1950  plus_exprt{expr.offset(),
1952  member_offset_opt.value(), expr.offset().type())});
1953 
1954  byte_extract_exprt tmp = expr;
1955  tmp.type() = comp.type();
1956  tmp.offset() = new_offset;
1957 
1959  }
1960 
1961  if(!failed)
1962  return s;
1963  }
1964  else if(expr.type().id() == ID_union || expr.type().id() == ID_union_tag)
1965  {
1966  const union_typet &union_type =
1967  expr.type().id() == ID_union_tag
1968  ? ns.follow_tag(to_union_tag_type(expr.type()))
1969  : to_union_type(expr.type());
1970  auto widest_member_opt = union_type.find_widest_union_component(ns);
1971  if(widest_member_opt.has_value())
1972  {
1973  byte_extract_exprt be = expr;
1974  be.type() = widest_member_opt->first.type();
1975  return union_exprt{widest_member_opt->first.get_name(),
1977  expr.type()};
1978  }
1979  }
1980  }
1981  else if(expr.op().id() == ID_array)
1982  {
1983  const array_typet &array_type = to_array_type(expr.op().type());
1984  const auto &element_bit_width =
1985  pointer_offset_bits(array_type.element_type(), ns);
1986  if(element_bit_width.has_value() && *element_bit_width > 0)
1987  {
1988  if(
1989  *offset > 0 &&
1990  *offset * expr.get_bits_per_byte() % *element_bit_width == 0)
1991  {
1992  const auto elements_to_erase = numeric_cast_v<std::size_t>(
1993  (*offset * expr.get_bits_per_byte()) / *element_bit_width);
1994  array_exprt slice = to_array_expr(expr.op());
1995  slice.operands().erase(
1996  slice.operands().begin(),
1997  slice.operands().begin() +
1998  std::min(elements_to_erase, slice.operands().size()));
1999  slice.type().size() =
2000  from_integer(slice.operands().size(), slice.type().size().type());
2001  byte_extract_exprt be = expr;
2002  be.op() = slice;
2003  be.offset() = from_integer(0, expr.offset().type());
2004  return changed(simplify_byte_extract(be));
2005  }
2006  else if(*offset == 0 && *el_size % *element_bit_width == 0)
2007  {
2008  const auto elements_to_keep =
2009  numeric_cast_v<std::size_t>(*el_size / *element_bit_width);
2010  array_exprt slice = to_array_expr(expr.op());
2011  if(slice.operands().size() > elements_to_keep)
2012  {
2013  slice.operands().resize(elements_to_keep);
2014  slice.type().size() =
2015  from_integer(slice.operands().size(), slice.type().size().type());
2016  byte_extract_exprt be = expr;
2017  be.op() = slice;
2018  return changed(simplify_byte_extract(be));
2019  }
2020  }
2021  }
2022  }
2023 
2024  // try to refine it down to extracting from a member or an index in an array
2025  auto subexpr =
2026  get_subexpression_at_offset(expr.op(), *offset, expr.type(), ns);
2027  if(subexpr.has_value() && subexpr.value() != expr)
2028  return changed(simplify_rec(subexpr.value())); // recursive call
2029 
2030  if(can_forward_propagatet(ns)(expr))
2031  return changed(simplify_rec(lower_byte_extract(expr, ns)));
2032 
2033  return unchanged(expr);
2034 }
2035 
2038 {
2039  // lift up any ID_if on the object
2040  if(expr.op().id() == ID_if)
2041  {
2042  if_exprt if_expr = lift_if(expr, 0);
2043  return changed(simplify_if_preorder(if_expr));
2044  }
2045  else
2046  {
2047  std::optional<exprt::operandst> new_operands;
2048 
2049  for(std::size_t i = 0; i < expr.operands().size(); ++i)
2050  {
2051  auto r_it = simplify_rec(expr.operands()[i]); // recursive call
2052  if(r_it.has_changed())
2053  {
2054  if(!new_operands.has_value())
2055  new_operands = expr.operands();
2056  (*new_operands)[i] = std::move(r_it.expr);
2057  }
2058  }
2059 
2060  if(new_operands.has_value())
2061  {
2062  exprt result = expr;
2063  std::swap(result.operands(), *new_operands);
2064  return result;
2065  }
2066  }
2067 
2068  return unchanged(expr);
2069 }
2070 
2073 {
2074  // byte_update(byte_update(root, offset, value), offset, value2) =>
2075  // byte_update(root, offset, value2)
2076  if(
2077  expr.id() == expr.op().id() &&
2078  expr.offset() == to_byte_update_expr(expr.op()).offset() &&
2079  expr.value().type() == to_byte_update_expr(expr.op()).value().type())
2080  {
2081  auto tmp = expr;
2082  tmp.set_op(to_byte_update_expr(expr.op()).op());
2083  return std::move(tmp);
2084  }
2085 
2086  const exprt &root = expr.op();
2087  const exprt &offset = expr.offset();
2088  const exprt &value = expr.value();
2089  const auto val_size = pointer_offset_bits(value.type(), ns);
2090  const auto root_size = pointer_offset_bits(root.type(), ns);
2091 
2092  const auto matching_byte_extract_id =
2093  expr.id() == ID_byte_update_little_endian ? ID_byte_extract_little_endian
2094  : ID_byte_extract_big_endian;
2095 
2096  // byte update of full object is byte_extract(new value)
2097  if(
2098  offset.is_zero() && val_size.has_value() && *val_size > 0 &&
2099  root_size.has_value() && *root_size > 0 && *val_size >= *root_size)
2100  {
2101  byte_extract_exprt be(
2102  matching_byte_extract_id,
2103  value,
2104  offset,
2105  expr.get_bits_per_byte(),
2106  expr.type());
2107 
2108  return changed(simplify_byte_extract(be));
2109  }
2110 
2111  // update bits in a constant
2112  const auto offset_int = numeric_cast<mp_integer>(offset);
2113  if(
2114  root_size.has_value() && *root_size >= 0 && val_size.has_value() &&
2115  *val_size >= 0 && offset_int.has_value() && *offset_int >= 0 &&
2116  *offset_int * expr.get_bits_per_byte() + *val_size <= *root_size)
2117  {
2118  auto root_bits =
2119  expr2bits(root, expr.id() == ID_byte_update_little_endian, ns);
2120 
2121  if(root_bits.has_value())
2122  {
2123  const auto val_bits =
2124  expr2bits(value, expr.id() == ID_byte_update_little_endian, ns);
2125 
2126  if(val_bits.has_value())
2127  {
2128  root_bits->replace(
2129  numeric_cast_v<std::size_t>(*offset_int * expr.get_bits_per_byte()),
2130  numeric_cast_v<std::size_t>(*val_size),
2131  *val_bits);
2132 
2133  auto tmp = bits2expr(
2134  *root_bits,
2135  expr.type(),
2136  expr.id() == ID_byte_update_little_endian,
2137  ns);
2138 
2139  if(tmp.has_value())
2140  return std::move(*tmp);
2141  }
2142  }
2143  }
2144 
2145  /*
2146  * byte_update(root, offset,
2147  * extract(root, offset) WITH component:=value)
2148  * =>
2149  * byte_update(root, offset + component offset,
2150  * value)
2151  */
2152 
2153  if(value.id()==ID_with)
2154  {
2155  const with_exprt &with=to_with_expr(value);
2156 
2157  if(with.old().id() == matching_byte_extract_id)
2158  {
2159  const byte_extract_exprt &extract=to_byte_extract_expr(with.old());
2160 
2161  /* the simplification can be used only if
2162  root and offset of update and extract
2163  are the same */
2164  if(!(root==extract.op()))
2165  return unchanged(expr);
2166  if(!(offset==extract.offset()))
2167  return unchanged(expr);
2168 
2169  if(with.type().id() == ID_struct || with.type().id() == ID_struct_tag)
2170  {
2171  const struct_typet &struct_type =
2172  with.type().id() == ID_struct_tag
2174  : to_struct_type(with.type());
2175  const irep_idt &component_name=with.where().get(ID_component_name);
2176  const typet &c_type = struct_type.get_component(component_name).type();
2177 
2178  // is this a bit field?
2179  if(c_type.id() == ID_c_bit_field || c_type.id() == ID_bool)
2180  {
2181  // don't touch -- might not be byte-aligned
2182  }
2183  else
2184  {
2185  // new offset = offset + component offset
2186  auto i = member_offset(struct_type, component_name, ns);
2187  if(i.has_value())
2188  {
2189  exprt compo_offset = from_integer(*i, offset.type());
2190  plus_exprt new_offset(offset, compo_offset);
2191  exprt new_value(with.new_value());
2192  auto tmp = expr;
2193  tmp.set_offset(simplify_node(std::move(new_offset)));
2194  tmp.set_value(std::move(new_value));
2195  return changed(simplify_byte_update(tmp)); // recursive call
2196  }
2197  }
2198  }
2199  else if(with.type().id() == ID_array)
2200  {
2201  auto i =
2203  if(i.has_value())
2204  {
2205  const exprt &index=with.where();
2206  exprt index_offset =
2207  simplify_mult(mult_exprt(index, from_integer(*i, index.type())));
2208 
2209  // index_offset may need a typecast
2210  if(offset.type() != index.type())
2211  {
2212  index_offset =
2213  simplify_typecast(typecast_exprt(index_offset, offset.type()));
2214  }
2215 
2216  plus_exprt new_offset(offset, index_offset);
2217  exprt new_value(with.new_value());
2218  auto tmp = expr;
2219  tmp.set_offset(simplify_plus(std::move(new_offset)));
2220  tmp.set_value(std::move(new_value));
2221  return changed(simplify_byte_update(tmp)); // recursive call
2222  }
2223  }
2224  }
2225  }
2226 
2227  // the following require a constant offset
2228  if(!offset_int.has_value() || *offset_int < 0)
2229  return unchanged(expr);
2230 
2231  // size must be known
2232  if(!val_size.has_value() || *val_size == 0)
2233  return unchanged(expr);
2234 
2235  // Are we updating (parts of) a struct? Do individual member updates
2236  // instead, unless there are non-byte-sized bit fields
2237  if(root.type().id() == ID_struct || root.type().id() == ID_struct_tag)
2238  {
2239  exprt result_expr;
2240  result_expr.make_nil();
2241 
2242  auto update_size = pointer_offset_size(value.type(), ns);
2243 
2244  const struct_typet &struct_type =
2245  root.type().id() == ID_struct_tag
2247  : to_struct_type(root.type());
2248  const struct_typet::componentst &components=
2249  struct_type.components();
2250 
2251  for(const auto &component : components)
2252  {
2253  auto m_offset = member_offset(struct_type, component.get_name(), ns);
2254 
2255  auto m_size_bits = pointer_offset_bits(component.type(), ns);
2256 
2257  // can we determine the current offset?
2258  if(!m_offset.has_value())
2259  {
2260  result_expr.make_nil();
2261  break;
2262  }
2263 
2264  // is it a byte-sized member?
2265  if(
2266  !m_size_bits.has_value() || *m_size_bits == 0 ||
2267  (*m_size_bits) % expr.get_bits_per_byte() != 0)
2268  {
2269  result_expr.make_nil();
2270  break;
2271  }
2272 
2273  mp_integer m_size_bytes = (*m_size_bits) / expr.get_bits_per_byte();
2274 
2275  // is that member part of the update?
2276  if(*m_offset + m_size_bytes <= *offset_int)
2277  continue;
2278  // are we done updating?
2279  else if(
2280  update_size.has_value() && *update_size > 0 &&
2281  *m_offset >= *offset_int + *update_size)
2282  {
2283  break;
2284  }
2285 
2286  if(result_expr.is_nil())
2287  result_expr = as_const(expr).op();
2288 
2289  exprt member_name(ID_member_name);
2290  member_name.set(ID_component_name, component.get_name());
2291  result_expr=with_exprt(result_expr, member_name, nil_exprt());
2292 
2293  // are we updating on member boundaries?
2294  if(
2295  *m_offset < *offset_int ||
2296  (*m_offset == *offset_int && update_size.has_value() &&
2297  *update_size > 0 && m_size_bytes > *update_size))
2298  {
2300  expr.id(),
2301  member_exprt(root, component.get_name(), component.type()),
2302  from_integer(*offset_int - *m_offset, offset.type()),
2303  value,
2304  expr.get_bits_per_byte());
2305 
2306  to_with_expr(result_expr).new_value().swap(v);
2307  }
2308  else if(
2309  update_size.has_value() && *update_size > 0 &&
2310  *m_offset + m_size_bytes > *offset_int + *update_size)
2311  {
2312  // we don't handle this for the moment
2313  result_expr.make_nil();
2314  break;
2315  }
2316  else
2317  {
2319  matching_byte_extract_id,
2320  value,
2321  from_integer(*m_offset - *offset_int, offset.type()),
2322  expr.get_bits_per_byte(),
2323  component.type());
2324 
2325  to_with_expr(result_expr).new_value().swap(v);
2326  }
2327  }
2328 
2329  if(result_expr.is_not_nil())
2330  return changed(simplify_rec(result_expr));
2331  }
2332 
2333  // replace elements of array or struct expressions, possibly using
2334  // byte_extract
2335  if(root.id()==ID_array)
2336  {
2337  auto el_size =
2339 
2340  if(
2341  !el_size.has_value() || *el_size == 0 ||
2342  (*el_size) % expr.get_bits_per_byte() != 0 ||
2343  (*val_size) % expr.get_bits_per_byte() != 0)
2344  {
2345  return unchanged(expr);
2346  }
2347 
2348  exprt result=root;
2349 
2350  mp_integer m_offset_bits=0, val_offset=0;
2351  Forall_operands(it, result)
2352  {
2353  if(*offset_int * expr.get_bits_per_byte() + (*val_size) <= m_offset_bits)
2354  break;
2355 
2356  if(*offset_int * expr.get_bits_per_byte() < m_offset_bits + *el_size)
2357  {
2358  mp_integer bytes_req =
2359  (m_offset_bits + *el_size) / expr.get_bits_per_byte() - *offset_int;
2360  bytes_req-=val_offset;
2361  if(val_offset + bytes_req > (*val_size) / expr.get_bits_per_byte())
2362  bytes_req = (*val_size) / expr.get_bits_per_byte() - val_offset;
2363 
2364  byte_extract_exprt new_val(
2365  matching_byte_extract_id,
2366  value,
2367  from_integer(val_offset, offset.type()),
2368  expr.get_bits_per_byte(),
2369  array_typet(
2371  from_integer(bytes_req, offset.type())));
2372 
2373  *it = byte_update_exprt(
2374  expr.id(),
2375  *it,
2376  from_integer(
2377  *offset_int + val_offset - m_offset_bits / expr.get_bits_per_byte(),
2378  offset.type()),
2379  new_val,
2380  expr.get_bits_per_byte());
2381 
2382  *it = simplify_rec(*it); // recursive call
2383 
2384  val_offset+=bytes_req;
2385  }
2386 
2387  m_offset_bits += *el_size;
2388  }
2389 
2390  return std::move(result);
2391  }
2392 
2393  return unchanged(expr);
2394 }
2395 
2398 {
2399  if(expr.id() == ID_complex_real)
2400  {
2401  auto &complex_real_expr = to_complex_real_expr(expr);
2402 
2403  if(complex_real_expr.op().id() == ID_complex)
2404  return to_complex_expr(complex_real_expr.op()).real();
2405  }
2406  else if(expr.id() == ID_complex_imag)
2407  {
2408  auto &complex_imag_expr = to_complex_imag_expr(expr);
2409 
2410  if(complex_imag_expr.op().id() == ID_complex)
2411  return to_complex_expr(complex_imag_expr.op()).imag();
2412  }
2413 
2414  return unchanged(expr);
2415 }
2416 
2419 {
2420  // When one operand is zero, an overflow can only occur for a subtraction from
2421  // zero.
2422  if(
2423  expr.op1().is_zero() ||
2424  (expr.op0().is_zero() && !can_cast_expr<minus_overflow_exprt>(expr)))
2425  {
2426  return false_exprt{};
2427  }
2428 
2429  // One is neutral element for multiplication
2430  if(
2432  (expr.op0().is_one() || expr.op1().is_one()))
2433  {
2434  return false_exprt{};
2435  }
2436 
2437  // we only handle the case of same operand types
2438  if(expr.op0().type() != expr.op1().type())
2439  return unchanged(expr);
2440 
2441  // catch some cases over mathematical types
2442  const irep_idt &op_type_id = expr.op0().type().id();
2443  if(
2444  op_type_id == ID_integer || op_type_id == ID_rational ||
2445  op_type_id == ID_real)
2446  {
2447  return false_exprt{};
2448  }
2449 
2450  if(op_type_id == ID_natural && !can_cast_expr<minus_overflow_exprt>(expr))
2451  return false_exprt{};
2452 
2453  // we only handle constants over signedbv/unsignedbv for the remaining cases
2454  if(op_type_id != ID_signedbv && op_type_id != ID_unsignedbv)
2455  return unchanged(expr);
2456 
2457  if(!expr.op0().is_constant() || !expr.op1().is_constant())
2458  return unchanged(expr);
2459 
2460  const auto op0_value = numeric_cast<mp_integer>(expr.op0());
2461  const auto op1_value = numeric_cast<mp_integer>(expr.op1());
2462  if(!op0_value.has_value() || !op1_value.has_value())
2463  return unchanged(expr);
2464 
2465  mp_integer no_overflow_result;
2467  no_overflow_result = *op0_value + *op1_value;
2469  no_overflow_result = *op0_value - *op1_value;
2470  else if(can_cast_expr<mult_overflow_exprt>(expr))
2471  no_overflow_result = *op0_value * *op1_value;
2472  else if(can_cast_expr<shl_overflow_exprt>(expr))
2473  no_overflow_result = *op0_value << *op1_value;
2474  else
2475  UNREACHABLE;
2476 
2477  const std::size_t width = to_bitvector_type(expr.op0().type()).get_width();
2478  const integer_bitvector_typet bv_type{op_type_id, width};
2479  if(
2480  no_overflow_result < bv_type.smallest() ||
2481  no_overflow_result > bv_type.largest())
2482  {
2483  return true_exprt{};
2484  }
2485  else
2486  return false_exprt{};
2487 }
2488 
2491 {
2492  // zero is a neutral element for all operations supported here
2493  if(expr.op().is_zero())
2494  return false_exprt{};
2495 
2496  // catch some cases over mathematical types
2497  const irep_idt &op_type_id = expr.op().type().id();
2498  if(
2499  op_type_id == ID_integer || op_type_id == ID_rational ||
2500  op_type_id == ID_real)
2501  {
2502  return false_exprt{};
2503  }
2504 
2505  if(op_type_id == ID_natural)
2506  return true_exprt{};
2507 
2508  // we only handle constants over signedbv/unsignedbv for the remaining cases
2509  if(op_type_id != ID_signedbv && op_type_id != ID_unsignedbv)
2510  return unchanged(expr);
2511 
2512  if(!expr.op().is_constant())
2513  return unchanged(expr);
2514 
2515  const auto op_value = numeric_cast<mp_integer>(expr.op());
2516  if(!op_value.has_value())
2517  return unchanged(expr);
2518 
2519  mp_integer no_overflow_result;
2521  no_overflow_result = -*op_value;
2522  else
2523  UNREACHABLE;
2524 
2525  const std::size_t width = to_bitvector_type(expr.op().type()).get_width();
2526  const integer_bitvector_typet bv_type{op_type_id, width};
2527  if(
2528  no_overflow_result < bv_type.smallest() ||
2529  no_overflow_result > bv_type.largest())
2530  {
2531  return true_exprt{};
2532  }
2533  else
2534  return false_exprt{};
2535 }
2536 
2539 {
2540  if(expr.id() == ID_overflow_result_unary_minus)
2541  {
2542  // zero is a neutral element
2543  if(expr.op0().is_zero())
2544  return struct_exprt{{expr.op0(), false_exprt{}}, expr.type()};
2545 
2546  // catch some cases over mathematical types
2547  const irep_idt &op_type_id = expr.op0().type().id();
2548  if(
2549  op_type_id == ID_integer || op_type_id == ID_rational ||
2550  op_type_id == ID_real)
2551  {
2552  return struct_exprt{{expr.op0(), false_exprt{}}, expr.type()};
2553  }
2554 
2555  // always an overflow for natural numbers, but the result is not
2556  // representable
2557  if(op_type_id == ID_natural)
2558  return unchanged(expr);
2559 
2560  // we only handle constants over signedbv/unsignedbv for the remaining cases
2561  if(op_type_id != ID_signedbv && op_type_id != ID_unsignedbv)
2562  return unchanged(expr);
2563 
2564  if(!expr.op0().is_constant())
2565  return unchanged(expr);
2566 
2567  const auto op_value = numeric_cast<mp_integer>(expr.op0());
2568  if(!op_value.has_value())
2569  return unchanged(expr);
2570 
2571  mp_integer no_overflow_result = -*op_value;
2572 
2573  const std::size_t width = to_bitvector_type(expr.op0().type()).get_width();
2574  const integer_bitvector_typet bv_type{op_type_id, width};
2575  if(
2576  no_overflow_result < bv_type.smallest() ||
2577  no_overflow_result > bv_type.largest())
2578  {
2579  return struct_exprt{
2580  {from_integer(no_overflow_result, expr.op0().type()), true_exprt{}},
2581  expr.type()};
2582  }
2583  else
2584  {
2585  return struct_exprt{
2586  {from_integer(no_overflow_result, expr.op0().type()), false_exprt{}},
2587  expr.type()};
2588  }
2589  }
2590  else
2591  {
2592  // When one operand is zero, an overflow can only occur for a subtraction
2593  // from zero.
2594  if(expr.op0().is_zero())
2595  {
2596  if(
2597  expr.id() == ID_overflow_result_plus ||
2598  expr.id() == ID_overflow_result_shl)
2599  {
2600  return struct_exprt{{expr.op1(), false_exprt{}}, expr.type()};
2601  }
2602  else if(expr.id() == ID_overflow_result_mult)
2603  {
2604  return struct_exprt{
2605  {from_integer(0, expr.op0().type()), false_exprt{}}, expr.type()};
2606  }
2607  }
2608  else if(expr.op1().is_zero())
2609  {
2610  if(
2611  expr.id() == ID_overflow_result_plus ||
2612  expr.id() == ID_overflow_result_minus ||
2613  expr.id() == ID_overflow_result_shl)
2614  {
2615  return struct_exprt{{expr.op0(), false_exprt{}}, expr.type()};
2616  }
2617  else
2618  {
2619  return struct_exprt{
2620  {from_integer(0, expr.op0().type()), false_exprt{}}, expr.type()};
2621  }
2622  }
2623 
2624  // One is neutral element for multiplication
2625  if(
2626  expr.id() == ID_overflow_result_mult &&
2627  (expr.op0().is_one() || expr.op1().is_one()))
2628  {
2629  return struct_exprt{
2630  {expr.op0().is_one() ? expr.op1() : expr.op0(), false_exprt{}},
2631  expr.type()};
2632  }
2633 
2634  // we only handle the case of same operand types
2635  if(
2636  expr.id() != ID_overflow_result_shl &&
2637  expr.op0().type() != expr.op1().type())
2638  {
2639  return unchanged(expr);
2640  }
2641 
2642  // catch some cases over mathematical types
2643  const irep_idt &op_type_id = expr.op0().type().id();
2644  if(
2645  expr.id() != ID_overflow_result_shl &&
2646  (op_type_id == ID_integer || op_type_id == ID_rational ||
2647  op_type_id == ID_real))
2648  {
2649  irep_idt id =
2650  expr.id() == ID_overflow_result_plus
2651  ? ID_plus
2652  : expr.id() == ID_overflow_result_minus ? ID_minus : ID_mult;
2653  return struct_exprt{
2654  {simplify_node(binary_exprt{expr.op0(), id, expr.op1()}),
2655  false_exprt{}},
2656  expr.type()};
2657  }
2658 
2659  if(
2660  (expr.id() == ID_overflow_result_plus ||
2661  expr.id() == ID_overflow_result_mult) &&
2662  op_type_id == ID_natural)
2663  {
2664  return struct_exprt{
2666  expr.op0(),
2667  expr.id() == ID_overflow_result_plus ? ID_plus : ID_mult,
2668  expr.op1()}),
2669  false_exprt{}},
2670  expr.type()};
2671  }
2672 
2673  // we only handle constants over signedbv/unsignedbv for the remaining cases
2674  if(op_type_id != ID_signedbv && op_type_id != ID_unsignedbv)
2675  return unchanged(expr);
2676 
2677  // a special case of overflow-minus checking with operands (X + n) and X
2678  if(expr.id() == ID_overflow_result_minus)
2679  {
2680  const exprt &tc_op0 = skip_typecast(expr.op0());
2681  const exprt &tc_op1 = skip_typecast(expr.op1());
2682 
2683  if(auto sum = expr_try_dynamic_cast<plus_exprt>(tc_op0))
2684  {
2685  if(skip_typecast(sum->op0()) == tc_op1 && sum->operands().size() == 2)
2686  {
2687  std::optional<exprt> offset;
2688  if(sum->type().id() == ID_pointer)
2689  {
2690  offset = std::move(simplify_pointer_offset(
2691  pointer_offset_exprt{*sum, expr.op0().type()})
2692  .expr);
2693  if(offset->id() == ID_pointer_offset)
2694  return unchanged(expr);
2695  }
2696  else
2697  offset = std::move(
2698  simplify_typecast(typecast_exprt{sum->op1(), expr.op0().type()})
2699  .expr);
2700 
2701  exprt offset_op = skip_typecast(*offset);
2702  if(
2703  offset_op.type().id() != ID_signedbv &&
2704  offset_op.type().id() != ID_unsignedbv)
2705  {
2706  return unchanged(expr);
2707  }
2708 
2709  const std::size_t width =
2710  to_bitvector_type(expr.op0().type()).get_width();
2711  const integer_bitvector_typet bv_type{op_type_id, width};
2712 
2713  or_exprt not_representable{
2715  offset_op,
2716  ID_lt,
2717  from_integer(bv_type.smallest(), offset_op.type())},
2719  offset_op,
2720  ID_gt,
2721  from_integer(bv_type.largest(), offset_op.type())}};
2722 
2723  return struct_exprt{
2724  {*offset, simplify_rec(not_representable)}, expr.type()};
2725  }
2726  }
2727  }
2728 
2729  if(!expr.op0().is_constant() || !expr.op1().is_constant())
2730  return unchanged(expr);
2731 
2732  // preserve the sizeof type annotation
2733  std::optional<typet> c_sizeof_type;
2734  for(const auto &op : expr.operands())
2735  {
2736  const typet &sizeof_type =
2737  static_cast<const typet &>(op.find(ID_C_c_sizeof_type));
2738  if(sizeof_type.is_not_nil())
2739  {
2740  c_sizeof_type = sizeof_type;
2741  break;
2742  }
2743  }
2744 
2745  const auto op0_value = numeric_cast<mp_integer>(expr.op0());
2746  const auto op1_value = numeric_cast<mp_integer>(expr.op1());
2747  if(!op0_value.has_value() || !op1_value.has_value())
2748  return unchanged(expr);
2749 
2750  mp_integer no_overflow_result;
2751  if(expr.id() == ID_overflow_result_plus)
2752  no_overflow_result = *op0_value + *op1_value;
2753  else if(expr.id() == ID_overflow_result_minus)
2754  no_overflow_result = *op0_value - *op1_value;
2755  else if(expr.id() == ID_overflow_result_mult)
2756  no_overflow_result = *op0_value * *op1_value;
2757  else if(expr.id() == ID_overflow_result_shl)
2758  no_overflow_result = *op0_value << *op1_value;
2759  else
2760  UNREACHABLE;
2761 
2762  exprt no_overflow_result_expr =
2763  from_integer(no_overflow_result, expr.op0().type());
2764  if(c_sizeof_type.has_value())
2765  no_overflow_result_expr.set(ID_C_c_sizeof_type, *c_sizeof_type);
2766 
2767  const std::size_t width = to_bitvector_type(expr.op0().type()).get_width();
2768  const integer_bitvector_typet bv_type{op_type_id, width};
2769  if(
2770  no_overflow_result < bv_type.smallest() ||
2771  no_overflow_result > bv_type.largest())
2772  {
2773  return struct_exprt{
2774  {std::move(no_overflow_result_expr), true_exprt{}}, expr.type()};
2775  }
2776  else
2777  {
2778  return struct_exprt{
2779  {std::move(no_overflow_result_expr), false_exprt{}}, expr.type()};
2780  }
2781  }
2782 }
2783 
2786 {
2787  auto result = unchanged(expr);
2788 
2789  // The ifs below could one day be replaced by a switch()
2790 
2791  if(expr.id()==ID_address_of)
2792  {
2793  // the argument of this expression needs special treatment
2794  }
2795  else if(expr.id()==ID_if)
2796  {
2797  result = simplify_if_preorder(to_if_expr(expr));
2798  }
2799  else if(expr.id() == ID_typecast)
2800  {
2802  }
2803  else if(
2804  expr.id() == ID_byte_extract_little_endian ||
2805  expr.id() == ID_byte_extract_big_endian)
2806  {
2808  }
2809  else if(expr.id() == ID_dereference)
2810  {
2812  }
2813  else if(expr.id() == ID_index)
2814  {
2815  result = simplify_index_preorder(to_index_expr(expr));
2816  }
2817  else if(expr.id() == ID_member)
2818  {
2819  result = simplify_member_preorder(to_member_expr(expr));
2820  }
2821  else if(
2822  expr.id() == ID_is_dynamic_object || expr.id() == ID_is_invalid_pointer ||
2823  expr.id() == ID_object_size || expr.id() == ID_pointer_object ||
2824  expr.id() == ID_pointer_offset)
2825  {
2827  }
2828  else if(expr.has_operands())
2829  {
2830  std::optional<exprt::operandst> new_operands;
2831 
2832  for(std::size_t i = 0; i < expr.operands().size(); ++i)
2833  {
2834  auto r_it = simplify_rec(expr.operands()[i]); // recursive call
2835  if(r_it.has_changed())
2836  {
2837  if(!new_operands.has_value())
2838  new_operands = expr.operands();
2839  (*new_operands)[i] = std::move(r_it.expr);
2840  }
2841  }
2842 
2843  if(new_operands.has_value())
2844  {
2845  std::swap(result.expr.operands(), *new_operands);
2846  result.expr_changed = resultt<>::CHANGED;
2847  }
2848  }
2849 
2850  if(as_const(result.expr).type().id() == ID_array)
2851  {
2852  const array_typet &array_type = to_array_type(as_const(result.expr).type());
2853  resultt<> simp_size = simplify_rec(array_type.size());
2854  if(simp_size.has_changed())
2855  {
2856  to_array_type(result.expr.type()).size() = simp_size.expr;
2857  result.expr_changed = resultt<>::CHANGED;
2858  }
2859  }
2860 
2861  return result;
2862 }
2863 
2865 {
2866  if(!node.has_operands())
2867  return unchanged(node); // no change
2868 
2869  // #define DEBUGX
2870 
2871 #ifdef DEBUGX
2872  exprt old(node);
2873 #endif
2874 
2875  exprt expr = node;
2876  bool no_change_join_operands = join_operands(expr);
2877 
2878  resultt<> r = unchanged(expr);
2879 
2880  if(expr.id()==ID_typecast)
2881  {
2883  }
2884  else if(expr.id()==ID_equal || expr.id()==ID_notequal ||
2885  expr.id()==ID_gt || expr.id()==ID_lt ||
2886  expr.id()==ID_ge || expr.id()==ID_le)
2887  {
2889  }
2890  else if(expr.id()==ID_if)
2891  {
2892  r = simplify_if(to_if_expr(expr));
2893  }
2894  else if(expr.id()==ID_lambda)
2895  {
2896  r = simplify_lambda(to_lambda_expr(expr));
2897  }
2898  else if(expr.id()==ID_with)
2899  {
2900  r = simplify_with(to_with_expr(expr));
2901  }
2902  else if(expr.id()==ID_update)
2903  {
2904  r = simplify_update(to_update_expr(expr));
2905  }
2906  else if(expr.id()==ID_index)
2907  {
2908  r = simplify_index(to_index_expr(expr));
2909  }
2910  else if(expr.id()==ID_member)
2911  {
2912  r = simplify_member(to_member_expr(expr));
2913  }
2914  else if(expr.id()==ID_byte_update_little_endian ||
2915  expr.id()==ID_byte_update_big_endian)
2916  {
2918  }
2919  else if(expr.id()==ID_byte_extract_little_endian ||
2920  expr.id()==ID_byte_extract_big_endian)
2921  {
2923  }
2924  else if(expr.id()==ID_pointer_object)
2925  {
2927  }
2928  else if(expr.id() == ID_is_dynamic_object)
2929  {
2931  }
2932  else if(expr.id() == ID_is_invalid_pointer)
2933  {
2935  }
2936  else if(
2937  const auto object_size = expr_try_dynamic_cast<object_size_exprt>(expr))
2938  {
2940  }
2941  else if(expr.id()==ID_div)
2942  {
2943  r = simplify_div(to_div_expr(expr));
2944  }
2945  else if(expr.id()==ID_mod)
2946  {
2947  r = simplify_mod(to_mod_expr(expr));
2948  }
2949  else if(expr.id()==ID_bitnot)
2950  {
2951  r = simplify_bitnot(to_bitnot_expr(expr));
2952  }
2953  else if(
2954  expr.id() == ID_bitand || expr.id() == ID_bitor || expr.id() == ID_bitxor ||
2955  expr.id() == ID_bitxnor)
2956  {
2958  }
2959  else if(expr.id()==ID_ashr || expr.id()==ID_lshr || expr.id()==ID_shl)
2960  {
2961  r = simplify_shifts(to_shift_expr(expr));
2962  }
2963  else if(expr.id()==ID_power)
2964  {
2965  r = simplify_power(to_power_expr(expr));
2966  }
2967  else if(expr.id()==ID_plus)
2968  {
2969  r = simplify_plus(to_plus_expr(expr));
2970  }
2971  else if(expr.id()==ID_minus)
2972  {
2973  r = simplify_minus(to_minus_expr(expr));
2974  }
2975  else if(expr.id()==ID_mult)
2976  {
2977  r = simplify_mult(to_mult_expr(expr));
2978  }
2979  else if(expr.id()==ID_floatbv_plus ||
2980  expr.id()==ID_floatbv_minus ||
2981  expr.id()==ID_floatbv_mult ||
2982  expr.id()==ID_floatbv_div)
2983  {
2985  }
2986  else if(expr.id()==ID_floatbv_typecast)
2987  {
2989  }
2990  else if(expr.id()==ID_unary_minus)
2991  {
2993  }
2994  else if(expr.id()==ID_unary_plus)
2995  {
2997  }
2998  else if(expr.id()==ID_not)
2999  {
3000  r = simplify_not(to_not_expr(expr));
3001  }
3002  else if(expr.id()==ID_implies ||
3003  expr.id()==ID_or || expr.id()==ID_xor ||
3004  expr.id()==ID_and)
3005  {
3006  r = simplify_boolean(expr);
3007  }
3008  else if(expr.id()==ID_dereference)
3009  {
3011  }
3012  else if(expr.id()==ID_address_of)
3013  {
3015  }
3016  else if(expr.id()==ID_pointer_offset)
3017  {
3019  }
3020  else if(expr.id()==ID_extractbit)
3021  {
3023  }
3024  else if(expr.id()==ID_concatenation)
3025  {
3027  }
3028  else if(expr.id()==ID_extractbits)
3029  {
3031  }
3032  else if(expr.id() == ID_zero_extend)
3033  {
3035  }
3036  else if(expr.id()==ID_ieee_float_equal ||
3037  expr.id()==ID_ieee_float_notequal)
3038  {
3040  }
3041  else if(expr.id() == ID_bswap)
3042  {
3043  r = simplify_bswap(to_bswap_expr(expr));
3044  }
3045  else if(expr.id()==ID_isinf)
3046  {
3047  r = simplify_isinf(to_unary_expr(expr));
3048  }
3049  else if(expr.id()==ID_isnan)
3050  {
3051  r = simplify_isnan(to_unary_expr(expr));
3052  }
3053  else if(expr.id()==ID_isnormal)
3054  {
3056  }
3057  else if(expr.id()==ID_abs)
3058  {
3059  r = simplify_abs(to_abs_expr(expr));
3060  }
3061  else if(expr.id()==ID_sign)
3062  {
3063  r = simplify_sign(to_sign_expr(expr));
3064  }
3065  else if(expr.id() == ID_popcount)
3066  {
3068  }
3069  else if(expr.id() == ID_count_leading_zeros)
3070  {
3072  }
3073  else if(expr.id() == ID_count_trailing_zeros)
3074  {
3076  }
3077  else if(expr.id() == ID_find_first_set)
3078  {
3080  }
3081  else if(expr.id() == ID_function_application)
3082  {
3084  }
3085  else if(expr.id() == ID_complex_real || expr.id() == ID_complex_imag)
3086  {
3087  r = simplify_complex(to_unary_expr(expr));
3088  }
3089  else if(
3090  const auto binary_overflow =
3091  expr_try_dynamic_cast<binary_overflow_exprt>(expr))
3092  {
3093  r = simplify_overflow_binary(*binary_overflow);
3094  }
3095  else if(
3096  const auto unary_overflow =
3097  expr_try_dynamic_cast<unary_overflow_exprt>(expr))
3098  {
3099  r = simplify_overflow_unary(*unary_overflow);
3100  }
3101  else if(
3102  const auto overflow_result =
3103  expr_try_dynamic_cast<overflow_result_exprt>(expr))
3104  {
3105  r = simplify_overflow_result(*overflow_result);
3106  }
3107  else if(expr.id() == ID_bitreverse)
3108  {
3110  }
3111  else if(
3112  const auto prophecy_r_or_w_ok =
3113  expr_try_dynamic_cast<prophecy_r_or_w_ok_exprt>(expr))
3114  {
3115  r = simplify_prophecy_r_or_w_ok(*prophecy_r_or_w_ok);
3116  }
3117  else if(
3118  const auto prophecy_pointer_in_range =
3119  expr_try_dynamic_cast<prophecy_pointer_in_range_exprt>(expr))
3120  {
3121  r = simplify_prophecy_pointer_in_range(*prophecy_pointer_in_range);
3122  }
3123 
3124  if(!no_change_join_operands)
3125  r = changed(r);
3126 
3127 #ifdef DEBUGX
3128  if(
3129  r.has_changed()
3130 # ifdef DEBUG_ON_DEMAND
3131  && debug_on
3132 # endif
3133  )
3134  {
3135  std::cout << "===== " << node.id() << ": " << format(node) << '\n'
3136  << " ---> " << format(r.expr) << '\n';
3137  }
3138 #endif
3139 
3140  return r;
3141 }
3142 
3144 {
3145  // look up in cache
3146 
3147  #ifdef USE_CACHE
3148  std::pair<simplify_expr_cachet::containert::iterator, bool>
3149  cache_result=simplify_expr_cache.container().
3150  insert(std::pair<exprt, exprt>(expr, exprt()));
3151 
3152  if(!cache_result.second) // found!
3153  {
3154  const exprt &new_expr=cache_result.first->second;
3155 
3156  if(new_expr.id().empty())
3157  return true; // no change
3158 
3159  expr=new_expr;
3160  return false;
3161  }
3162  #endif
3163 
3164  // We work on a copy to prevent unnecessary destruction of sharing.
3165  auto simplify_node_preorder_result = simplify_node_preorder(expr);
3166 
3167  auto simplify_node_result = simplify_node(simplify_node_preorder_result.expr);
3168 
3169  if(
3170  !simplify_node_result.has_changed() &&
3171  simplify_node_preorder_result.has_changed())
3172  {
3173  simplify_node_result.expr_changed =
3174  simplify_node_preorder_result.expr_changed;
3175  }
3176 
3177 #ifdef USE_LOCAL_REPLACE_MAP
3178  exprt tmp = simplify_node_result.expr;
3179 # if 1
3180  replace_mapt::const_iterator it =
3181  local_replace_map.find(simplify_node_result.expr);
3182  if(it!=local_replace_map.end())
3183  simplify_node_result = changed(it->second);
3184 # else
3185  if(
3186  !local_replace_map.empty() &&
3187  !replace_expr(local_replace_map, simplify_node_result.expr))
3188  {
3189  simplify_node_result = changed(simplify_rec(simplify_node_result.expr));
3190  }
3191 # endif
3192 #endif
3193 
3194  if(!simplify_node_result.has_changed())
3195  {
3196  return unchanged(expr);
3197  }
3198  else
3199  {
3201  (as_const(simplify_node_result.expr).type().id() == ID_array &&
3202  expr.type().id() == ID_array) ||
3203  as_const(simplify_node_result.expr).type() == expr.type(),
3204  simplify_node_result.expr.pretty(),
3205  expr.pretty());
3206 
3207 #ifdef USE_CACHE
3208  // save in cache
3209  cache_result.first->second = simplify_node_result.expr;
3210 #endif
3211 
3212  return simplify_node_result;
3213  }
3214 }
3215 
3218 {
3219 #ifdef DEBUG_ON_DEMAND
3220  if(debug_on)
3221  std::cout << "TO-SIMP " << format(expr) << "\n";
3222 #endif
3223  auto result = simplify_rec(expr);
3224 #ifdef DEBUG_ON_DEMAND
3225  if(debug_on)
3226  std::cout << "FULLSIMP " << format(result.expr) << "\n";
3227 #endif
3228  if(result.has_changed())
3229  {
3230  expr = result.expr;
3231  return false; // change
3232  }
3233  else
3234  return true; // no change
3235 }
3236 
3238 bool simplify(exprt &expr, const namespacet &ns)
3239 {
3240  return simplify_exprt(ns).simplify(expr);
3241 }
3242 
3244 {
3245  simplify_exprt(ns).simplify(src);
3246  return src;
3247 }
configt config
Definition: config.cpp:25
mp_integer bvrep2integer(const irep_idt &src, std::size_t width, bool is_signed)
convert a bit-vector representation (possibly signed) to integer
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:99
bool to_integer(const constant_exprt &expr, mp_integer &int_value)
Convert a constant expression expr to an arbitrary-precision integer.
Definition: arith_tools.cpp:20
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.
mp_integer power(const mp_integer &base, const mp_integer &exponent)
A multi-precision implementation of the power operator.
const T & as_const(T &value)
Return a reference to the same object but ensures the type is const.
Definition: as_const.h:14
API to expression classes for bitvectors.
bool can_cast_expr< mult_overflow_exprt >(const exprt &base)
const shift_exprt & to_shift_expr(const exprt &expr)
Cast an exprt to a shift_exprt.
bool can_cast_expr< minus_overflow_exprt >(const exprt &base)
const extractbit_exprt & to_extractbit_expr(const exprt &expr)
Cast an exprt to an extractbit_exprt.
const extractbits_exprt & to_extractbits_expr(const exprt &expr)
Cast an exprt to an extractbits_exprt.
bool can_cast_expr< shl_overflow_exprt >(const exprt &base)
const find_first_set_exprt & to_find_first_set_expr(const exprt &expr)
Cast an exprt to a find_first_set_exprt.
const bitreverse_exprt & to_bitreverse_expr(const exprt &expr)
Cast an exprt to a bitreverse_exprt.
const zero_extend_exprt & to_zero_extend_expr(const exprt &expr)
Cast an exprt to a zero_extend_exprt.
const count_trailing_zeros_exprt & to_count_trailing_zeros_expr(const exprt &expr)
Cast an exprt to a count_trailing_zeros_exprt.
bool can_cast_expr< plus_overflow_exprt >(const exprt &base)
const bitnot_exprt & to_bitnot_expr(const exprt &expr)
Cast an exprt to a bitnot_exprt.
const concatenation_exprt & to_concatenation_expr(const exprt &expr)
Cast an exprt to a concatenation_exprt.
bool can_cast_expr< unary_minus_overflow_exprt >(const exprt &base)
const bswap_exprt & to_bswap_expr(const exprt &expr)
Cast an exprt to a bswap_exprt.
const count_leading_zeros_exprt & to_count_leading_zeros_expr(const exprt &expr)
Cast an exprt to a count_leading_zeros_exprt.
const popcount_exprt & to_popcount_expr(const exprt &expr)
Cast an exprt to a popcount_exprt.
const floatbv_typet & to_floatbv_type(const typet &type)
Cast a typet to a floatbv_typet.
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
const fixedbv_typet & to_fixedbv_type(const typet &type)
Cast a typet to a fixedbv_typet.
const bv_typet & to_bv_type(const typet &type)
Cast a typet to a bv_typet.
void slice(symex_bmct &symex, symex_target_equationt &symex_target_equation, const namespacet &ns, const optionst &options, ui_message_handlert &ui_message_handler)
Definition: bmc_util.cpp:198
Expression classes for byte-level operators.
exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
Rewrite a byte extract expression to more fundamental operations.
const byte_update_exprt & to_byte_update_expr(const exprt &expr)
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
int16_t s2
Definition: bytecode_info.h:60
int8_t s1
Definition: bytecode_info.h:59
pointer_typet pointer_type(const typet &subtype)
Definition: c_types.cpp:235
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
Absolute value.
Definition: std_expr.h:442
Operator to return the address of an object.
Definition: pointer_expr.h:540
exprt & object()
Definition: pointer_expr.h:549
Array constructor from list of elements.
Definition: std_expr.h:1621
exprt & what()
Definition: std_expr.h:1575
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
A base class for binary expressions.
Definition: std_expr.h:638
exprt & op1()
Definition: expr.h:136
exprt & op0()
Definition: expr.h:133
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
std::size_t get_width() const
Definition: std_types.h:925
Expression of type type extracted from some object op starting at position offset (given in number of...
std::size_t get_bits_per_byte() const
Expression corresponding to op() where the bytes starting at position offset (given in number of byte...
const exprt & value() const
void set_offset(exprt e)
const exprt & op() const
const exprt & offset() const
void set_op(exprt e)
std::size_t get_bits_per_byte() const
The C/C++ Booleans.
Definition: c_types.h:97
C enum tag type, i.e., c_enum_typet with an identifier.
Definition: c_types.h:352
const typet & underlying_type() const
Definition: c_types.h:307
Determine whether an expression is constant.
Definition: expr_util.h:91
exprt real()
Definition: std_expr.h:1927
exprt imag()
Definition: std_expr.h:1937
struct configt::ansi_ct ansi_c
A constant literal expression.
Definition: std_expr.h:3000
const irep_idt & get_value() const
Definition: std_expr.h:3008
void set_value(const irep_idt &value)
Definition: std_expr.h:3013
bool is_null_pointer() const
Returns true if expr has a pointer type and a value NULL; it also returns true when expr has value ze...
Definition: std_expr.cpp:25
The count leading zeros (counting the number of zero bits starting from the most-significant bit) exp...
The count trailing zeros (counting the number of zero bits starting from the least-significant bit) e...
Operator to dereference a pointer.
Definition: pointer_expr.h:834
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
Union constructor to support unions without any member (a GCC/Clang feature).
Definition: std_expr.h:1834
Base class for all expressions.
Definition: expr.h:56
std::vector< exprt > operandst
Definition: expr.h:58
bool is_one() const
Return whether the expression is a constant representing 1.
Definition: expr.cpp:96
bool has_operands() const
Return true if there is at least one operand.
Definition: expr.h:91
bool is_true() const
Return whether the expression is a constant representing true.
Definition: expr.cpp:27
exprt & op1()
Definition: expr.h:136
source_locationt & add_source_location()
Definition: expr.h:236
const source_locationt & source_location() const
Definition: expr.h:231
bool is_false() const
Return whether the expression is a constant representing false.
Definition: expr.cpp:34
bool is_zero() const
Return whether the expression is a constant representing 0.
Definition: expr.cpp:47
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
exprt & op0()
Definition: expr.h:133
operandst & operands()
Definition: expr.h:94
void add_to_operands(const exprt &expr)
Add the given argument to the end of exprt's operands.
Definition: expr.h:170
The Boolean constant false.
Definition: std_expr.h:3082
Returns one plus the index of the least-significant one bit, or zero if the operand is zero.
std::size_t get_fraction_bits() const
Definition: fixedbv.h:35
Fixed-width bit-vector with signed fixed-point interpretation.
fixedbv_spect spec
Definition: fixedbv.h:44
void from_integer(const mp_integer &i)
Definition: fixedbv.cpp:32
mp_integer to_integer() const
Definition: fixedbv.cpp:37
void set_value(const mp_integer &_v)
Definition: fixedbv.h:96
void round(const fixedbv_spect &dest_spec)
Definition: fixedbv.cpp:52
constant_exprt to_expr() const
Definition: fixedbv.cpp:43
Fixed-width bit-vector with IEEE floating-point interpretation.
Application of (mathematical) function.
ieee_float_spect spec
Definition: ieee_float.h:134
mp_integer to_integer() const
constant_exprt to_expr() const
Definition: ieee_float.cpp:703
bool get_sign() const
Definition: ieee_float.h:247
void set_sign(bool _sign)
Definition: ieee_float.h:183
void from_integer(const mp_integer &i)
Definition: ieee_float.cpp:516
mp_integer pack() const
Definition: ieee_float.cpp:375
void change_spec(const ieee_float_spect &dest_spec)
The trinary if-then-else operator.
Definition: std_expr.h:2380
exprt & true_case()
Definition: std_expr.h:2407
exprt & false_case()
Definition: std_expr.h:2417
Array index operator.
Definition: std_expr.h:1470
exprt & array()
Definition: std_expr.h:1500
exprt & index()
Definition: std_expr.h:1510
Fixed-width bit-vector representing a signed or unsigned integer.
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition: irep.cpp:482
const irept & find(const irep_idt &name) const
Definition: irep.cpp:93
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:44
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:412
bool is_not_nil() const
Definition: irep.h:372
const irep_idt & id() const
Definition: irep.h:388
void make_nil()
Definition: irep.h:446
void swap(irept &irep)
Definition: irep.h:434
bool is_nil() const
Definition: irep.h:368
A (mathematical) lambda expression.
exprt application(const operandst &arguments) const
Extract member of struct or union.
Definition: std_expr.h:2854
Binary multiplication Associativity is not specified.
Definition: std_expr.h:1107
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
The NIL expression.
Definition: std_expr.h:3091
The null pointer constant.
Definition: pointer_expr.h:909
Boolean OR.
Definition: std_expr.h:2233
An expression returning both the result of the arithmetic operation under wrap-around semantics as we...
exprt & op1()
Definition: expr.h:136
exprt & op0()
Definition: expr.h:133
The plus expression Associativity is not specified.
Definition: std_expr.h:1002
The offset (in bytes) of a pointer relative to the object.
The popcount (counting the number of bits set to 1) expression.
const exprt & length() const
Definition: string_expr.h:129
const exprt & content() const
Definition: string_expr.h:139
Sign of an expression Predicate is true if _op is negative, false otherwise.
Definition: std_expr.h:596
Fixed-width bit-vector with two's complement interpretation.
resultt simplify_isnan(const unary_exprt &)
resultt simplify_bitwise(const multi_ary_exprt &)
const namespacet & ns
resultt simplify_div(const div_exprt &)
resultt simplify_byte_extract(const byte_extract_exprt &)
resultt simplify_bitreverse(const bitreverse_exprt &)
Try to simplify bit-reversing to a constant expression.
resultt simplify_abs(const abs_exprt &)
resultt simplify_isnormal(const unary_exprt &)
resultt simplify_dereference(const dereference_exprt &)
resultt simplify_bitnot(const bitnot_exprt &)
resultt simplify_zero_extend(const zero_extend_exprt &)
resultt simplify_prophecy_r_or_w_ok(const prophecy_r_or_w_ok_exprt &)
Try to simplify prophecy_{r,w,rw}_ok to a constant expression.
resultt simplify_member_preorder(const member_exprt &)
resultt simplify_popcount(const popcount_exprt &)
static resultt changed(resultt<> result)
resultt simplify_dereference_preorder(const dereference_exprt &)
resultt simplify_unary_pointer_predicate_preorder(const unary_exprt &)
resultt simplify_address_of(const address_of_exprt &)
resultt simplify_if(const if_exprt &)
resultt simplify_node(const exprt &)
resultt simplify_node_preorder(const exprt &)
resultt simplify_prophecy_pointer_in_range(const prophecy_pointer_in_range_exprt &)
Try to simplify prophecy_pointer_in_range to a constant expression.
resultt simplify_overflow_unary(const unary_overflow_exprt &)
Try to simplify overflow-unary-.
resultt simplify_minus(const minus_exprt &)
resultt simplify_extractbit(const extractbit_exprt &)
resultt simplify_rec(const exprt &)
resultt simplify_shifts(const shift_exprt &)
resultt simplify_index_preorder(const index_exprt &)
resultt simplify_typecast(const typecast_exprt &)
resultt simplify_pointer_object(const pointer_object_exprt &)
resultt simplify_boolean(const exprt &)
resultt simplify_object(const exprt &)
resultt simplify_mult(const mult_exprt &)
resultt simplify_floatbv_typecast(const floatbv_typecast_exprt &)
resultt simplify_with(const with_exprt &)
resultt simplify_inequality(const binary_relation_exprt &)
simplifies inequalities !=, <=, <, >=, >, and also ==
resultt simplify_not(const not_exprt &)
resultt simplify_isinf(const unary_exprt &)
resultt simplify_overflow_binary(const binary_overflow_exprt &)
Try to simplify overflow-+, overflow-*, overflow–, overflow-shl.
resultt simplify_function_application(const function_application_exprt &)
Attempt to simplify mathematical function applications if we have enough information to do so.
resultt simplify_index(const index_exprt &)
resultt simplify_bswap(const bswap_exprt &)
resultt simplify_member(const member_exprt &)
static resultt unchanged(exprt expr)
resultt simplify_byte_update(const byte_update_exprt &)
resultt simplify_extractbits(const extractbits_exprt &)
Simplifies extracting of bits from a constant.
resultt simplify_update(const update_exprt &)
resultt simplify_is_invalid_pointer(const unary_exprt &)
resultt simplify_mod(const mod_exprt &)
resultt simplify_complex(const unary_exprt &)
resultt simplify_pointer_offset(const pointer_offset_exprt &)
resultt simplify_plus(const plus_exprt &)
virtual bool simplify(exprt &expr)
resultt simplify_unary_plus(const unary_plus_exprt &)
resultt simplify_overflow_result(const overflow_result_exprt &)
Try to simplify overflow_result-+, overflow_result-*, overflow_result–, overflow_result-shl,...
resultt simplify_ffs(const find_first_set_exprt &)
Try to simplify find-first-set to a constant expression.
resultt simplify_if_preorder(const if_exprt &expr)
resultt simplify_byte_extract_preorder(const byte_extract_exprt &)
resultt simplify_is_dynamic_object(const unary_exprt &)
resultt simplify_power(const power_exprt &)
resultt simplify_object_size(const object_size_exprt &)
resultt simplify_lambda(const lambda_exprt &)
resultt simplify_concatenation(const concatenation_exprt &)
resultt simplify_floatbv_op(const ieee_float_op_exprt &)
resultt simplify_ctz(const count_trailing_zeros_exprt &)
Try to simplify count-trailing-zeros to a constant expression.
resultt simplify_clz(const count_leading_zeros_exprt &)
Try to simplify count-leading-zeros to a constant expression.
resultt simplify_ieee_float_relation(const binary_relation_exprt &)
resultt simplify_typecast_preorder(const typecast_exprt &)
resultt simplify_sign(const sign_exprt &)
resultt simplify_unary_minus(const unary_minus_exprt &)
Struct constructor from list of elements.
Definition: std_expr.h:1877
Structure type, corresponds to C style structs.
Definition: std_types.h:231
const componentt & get_component(const irep_idt &component_name) const
Get the reference to a component with given name.
Definition: std_types.cpp:64
bool has_component(const irep_idt &component_name) const
Definition: std_types.h:157
const componentst & components() const
Definition: std_types.h:147
std::size_t component_number(const irep_idt &component_name) const
Return the sequence number of the component with given name.
Definition: std_types.cpp:47
std::vector< componentt > componentst
Definition: std_types.h:140
const irep_idt & get_identifier() const
Definition: std_expr.h:160
The Boolean constant true.
Definition: std_expr.h:3073
const typet & subtype() const
Definition: type.h:187
Semantic type conversion.
Definition: std_expr.h:2073
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition: std_expr.h:2081
The type of an expression, extends irept.
Definition: type.h:29
Generic base class for unary expressions.
Definition: std_expr.h:361
const exprt & op1() const =delete
const exprt & op() const
Definition: std_expr.h:391
A Boolean expression returning true, iff operation kind would result in an overflow when applied to t...
Union constructor from single element.
Definition: std_expr.h:1770
The union type.
Definition: c_types.h:147
std::optional< std::pair< struct_union_typet::componentt, mp_integer > > find_widest_union_component(const namespacet &ns) const
Determine the member of maximum bit width in a union type.
Definition: c_types.cpp:300
Fixed-width bit-vector with unsigned binary interpretation.
Operator to update elements in structs and arrays.
Definition: std_expr.h:2665
exprt::operandst & designator()
Definition: std_expr.h:2691
exprt & old()
Definition: std_expr.h:2677
exprt & new_value()
Definition: std_expr.h:2701
Operator to update elements in structs and arrays.
Definition: std_expr.h:2481
exprt & old()
Definition: std_expr.h:2491
exprt & new_value()
Definition: std_expr.h:2511
exprt & where()
Definition: std_expr.h:2501
int isalpha(int c)
Definition: ctype.c:9
int tolower(int c)
Definition: ctype.c:109
int isupper(int c)
Definition: ctype.c:90
#define Forall_operands(it, expr)
Definition: expr.h:27
constant_exprt make_boolean_expr(bool value)
returns true_exprt if given true and false_exprt otherwise
Definition: expr_util.cpp:313
exprt is_not_zero(const exprt &src, const namespacet &ns)
converts a scalar/float expression to C/C++ Booleans
Definition: expr_util.cpp:74
const exprt & skip_typecast(const exprt &expr)
find the expression nested inside typecasts, if any
Definition: expr_util.cpp:193
if_exprt lift_if(const exprt &src, std::size_t operand_number)
lift up an if_exprt one level
Definition: expr_util.cpp:177
bool has_subtype(const typet &type, const std::function< bool(const typet &)> &pred, const namespacet &ns)
returns true if any of the contained types satisfies pred
Definition: expr_util.cpp:129
Deprecated expression utility functions.
API to expression classes for floating-point arithmetic.
const ieee_float_op_exprt & to_ieee_float_op_expr(const exprt &expr)
Cast an exprt to an ieee_float_op_exprt.
Definition: floatbv_expr.h:425
const floatbv_typecast_exprt & to_floatbv_typecast_expr(const exprt &expr)
Cast an exprt to a floatbv_typecast_exprt.
Definition: floatbv_expr.h:68
static format_containert< T > format(const T &o)
Definition: format.h:37
const std::string & id2string(const irep_idt &d)
Definition: irep.h:44
static int8_t r
Definition: irep_hash.h:60
API to expression classes for 'mathematical' expressions.
const lambda_exprt & to_lambda_expr(const exprt &expr)
Cast an exprt to a lambda_exprt.
const power_exprt & to_power_expr(const exprt &expr)
Cast an exprt to a power_exprt.
const function_application_exprt & to_function_application_expr(const exprt &expr)
Cast an exprt to a function_application_exprt.
const mp_integer string2integer(const std::string &n, unsigned base)
Definition: mp_arith.cpp:54
API to expression classes for Pointers.
const pointer_offset_exprt & to_pointer_offset_expr(const exprt &expr)
Cast an exprt to a pointer_offset_exprt.
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
Definition: pointer_expr.h:890
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:93
const pointer_object_exprt & to_pointer_object_expr(const exprt &expr)
Cast an exprt to a pointer_object_exprt.
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)
std::optional< mp_integer > member_offset(const struct_typet &type, const irep_idt &member, const namespacet &ns)
std::optional< exprt > get_subexpression_at_offset(const exprt &expr, const mp_integer &offset_bytes, const typet &target_type_raw, const namespacet &ns)
std::optional< exprt > member_offset_expr(const member_exprt &member_expr, const namespacet &ns)
std::optional< mp_integer > pointer_offset_size(const typet &type, const namespacet &ns)
Compute the size of a type in bytes, rounding up to full bytes.
Pointer Logic.
exprt pointer_offset_sum(const exprt &a, const exprt &b)
Pointer Dereferencing.
exprt object_size(const exprt &pointer)
constant_exprt from_rational(const rationalt &a)
bool replace_expr(const exprt &what, const exprt &by, exprt &dest)
bool simplify(exprt &expr, const namespacet &ns)
static simplify_exprt::resultt simplify_string_compare_to(const function_application_exprt &expr, const namespacet &ns)
Simplify String.compareTo function when arguments are constant.
static simplify_exprt::resultt simplify_string_contains(const function_application_exprt &expr, const namespacet &ns)
Simplify String.contains function when arguments are constant.
static simplify_exprt::resultt simplify_string_endswith(const function_application_exprt &expr, const namespacet &ns)
Simplify String.endsWith function when arguments are constant.
static simplify_exprt::resultt simplify_string_char_at(const function_application_exprt &expr, const namespacet &ns)
Simplify String.charAt function when arguments are constant.
static simplify_exprt::resultt simplify_string_startswith(const function_application_exprt &expr, const namespacet &ns)
Simplify String.startsWith function when arguments are constant.
static simplify_exprt::resultt simplify_string_is_empty(const function_application_exprt &expr, const namespacet &ns)
Simplify String.isEmpty function when arguments are constant.
static bool lower_case_string_expression(array_exprt &string_data)
Take the passed-in constant string array and lower-case every character.
static simplify_exprt::resultt simplify_string_index_of(const function_application_exprt &expr, const namespacet &ns, const bool search_from_end)
Simplify String.indexOf function when arguments are constant.
static simplify_exprt::resultt simplify_string_equals_ignore_case(const function_application_exprt &expr, const namespacet &ns)
Simplify String.equalsIgnorecase function when arguments are constant.
exprt simplify_expr(exprt src, const namespacet &ns)
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.
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)
bool join_operands(exprt &expr)
BigInt mp_integer
Definition: smt_terms.h:17
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:534
#define POSTCONDITION_WITH_DIAGNOSTICS(CONDITION,...)
Definition: invariant.h:480
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_designatort & to_index_designator(const exprt &expr)
Cast an exprt to an index_designatort.
Definition: std_expr.h:2596
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition: std_expr.h:2460
const update_exprt & to_update_expr(const exprt &expr)
Cast an exprt to an update_exprt.
Definition: std_expr.h:2748
const unary_plus_exprt & to_unary_plus_expr(const exprt &expr)
Cast an exprt to a unary_plus_exprt.
Definition: std_expr.h:556
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:3055
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const mod_exprt & to_mod_expr(const exprt &expr)
Cast an exprt to a mod_exprt.
Definition: std_expr.h:1277
const array_exprt & to_array_expr(const exprt &expr)
Cast an exprt to an array_exprt.
Definition: std_expr.h:1665
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2107
const complex_real_exprt & to_complex_real_expr(const exprt &expr)
Cast an exprt to a complex_real_exprt.
Definition: std_expr.h:2010
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
Definition: std_expr.h:2362
const unary_minus_exprt & to_unary_minus_expr(const exprt &expr)
Cast an exprt to a unary_minus_exprt.
Definition: std_expr.h:514
const div_exprt & to_div_expr(const exprt &expr)
Cast an exprt to a div_exprt.
Definition: std_expr.h:1206
const minus_exprt & to_minus_expr(const exprt &expr)
Cast an exprt to a minus_exprt.
Definition: std_expr.h:1086
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 with_exprt & to_with_expr(const exprt &expr)
Cast an exprt to a with_exprt.
Definition: std_expr.h:2543
const struct_exprt & to_struct_expr(const exprt &expr)
Cast an exprt to a struct_exprt.
Definition: std_expr.h:1900
const array_of_exprt & to_array_of_expr(const exprt &expr)
Cast an exprt to an array_of_exprt.
Definition: std_expr.h:1603
const plus_exprt & to_plus_expr(const exprt &expr)
Cast an exprt to a plus_exprt.
Definition: std_expr.h:1041
const complex_exprt & to_complex_expr(const exprt &expr)
Cast an exprt to a complex_exprt.
Definition: std_expr.h:1965
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2946
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition: std_expr.h:426
const complex_imag_exprt & to_complex_imag_expr(const exprt &expr)
Cast an exprt to a complex_imag_exprt.
Definition: std_expr.h:2053
const sign_exprt & to_sign_expr(const exprt &expr)
Cast an exprt to a sign_exprt.
Definition: std_expr.h:621
const abs_exprt & to_abs_expr(const exprt &expr)
Cast an exprt to a abs_exprt.
Definition: std_expr.h:466
const binary_relation_exprt & to_binary_relation_expr(const exprt &expr)
Cast an exprt to a binary_relation_exprt.
Definition: std_expr.h:895
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1538
const mult_exprt & to_mult_expr(const exprt &expr)
Cast an exprt to a mult_exprt.
Definition: std_expr.h:1137
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 struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition: std_types.h:518
String expressions for the string solver.
refined_string_exprt & to_string_expr(exprt &expr)
Definition: string_expr.h:151
bool can_cast_expr< refined_string_exprt >(const exprt &base)
Definition: string_expr.h:166
endiannesst endianness
Definition: config.h:209
bool NULL_is_zero
Definition: config.h:226
static bool failed(bool error_indicator)
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition: type.h:208
#define size_type
Definition: unistd.c:347