CBMC
Loading...
Searching...
No Matches
simplify_expr.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module:
4
5Author: 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
44struct simplify_expr_cachet
45{
46public:
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
62simplify_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 {
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 {
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 =
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 =
363 const mp_integer char2 =
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
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()).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) &&
776 config.ansi_c.NULL_is_zero)
777 {
778 return from_integer(0, expr_type);
779 }
780
781 // casts from a constant pointer that holds an integer address to an integer
782 // of the same width: the integer with the same bits, which is how the
783 // back-ends encode both (bv_pointerst::convert_pointer_type and
784 // smt2_convt::convert_constant); shadow memory of pointer-typed objects
785 // yields such casts
786 if(
787 op_type.id() == ID_pointer && expr.op().is_constant() &&
788 !to_constant_expr(expr.op()).is_null_pointer() &&
789 (expr_type.id() == ID_unsignedbv || expr_type.id() == ID_signedbv ||
790 expr_type.id() == ID_bv) &&
791 to_bitvector_type(expr_type).get_width() ==
792 to_pointer_type(op_type).get_width())
793 {
794 return constant_exprt(to_constant_expr(expr.op()).get_value(), expr_type);
795 }
796
797 // casts from pointer to integer
798 // where width of integer >= width of pointer
799 // (void*)(intX)expr -> (void*)expr
800 if(
801 expr_type.id() == ID_pointer && expr.op().id() == ID_typecast &&
802 (op_type.id() == ID_signedbv || op_type.id() == ID_unsignedbv ||
803 op_type.id() == ID_bv) &&
804 to_bitvector_type(op_type).get_width() >=
805 to_bitvector_type(expr_type).get_width())
806 {
807 auto new_expr = expr;
808 new_expr.op() = to_typecast_expr(expr.op()).op();
809 return changed(simplify_typecast(new_expr)); // rec. call
810 }
811
812 // eliminate redundant typecasts
813 if(expr.type() == expr.op().type())
814 {
815 return expr.op();
816 }
817
818 // eliminate casts to proper bool
819 if(expr_type.id()==ID_bool)
820 {
821 // rewrite (bool)x to x!=0
822 binary_relation_exprt inequality(
823 expr.op(),
824 op_type.id() == ID_floatbv ? ID_ieee_float_notequal : ID_notequal,
825 from_integer(0, op_type));
826 inequality.add_source_location()=expr.source_location();
827 return changed(simplify_node(inequality));
828 }
829
830 // eliminate casts from proper bool
831 if(
832 op_type.id() == ID_bool &&
833 (expr_type.id() == ID_signedbv || expr_type.id() == ID_unsignedbv ||
834 expr_type.id() == ID_c_bool || expr_type.id() == ID_c_bit_field))
835 {
836 // rewrite (T)(bool) to bool?1:0
837 auto one = from_integer(1, expr_type);
838 auto zero = from_integer(0, expr_type);
840 if_exprt{expr.op(), std::move(one), std::move(zero)}));
841 }
842
843 // circular casts through types shorter than `int`
844 // we use fixed bit widths as this is specifically for the Java bytecode
845 // front-end
846 if(op_type == signedbv_typet(32) && expr.op().id() == ID_typecast)
847 {
848 if(expr_type==c_bool_typet(8) ||
849 expr_type==signedbv_typet(8) ||
850 expr_type==signedbv_typet(16) ||
851 expr_type==unsignedbv_typet(16))
852 {
853 // We checked that the id was ID_typecast in the enclosing `if`
854 const auto &typecast = expr_checked_cast<typecast_exprt>(expr.op());
855 if(typecast.op().type()==expr_type)
856 {
857 return typecast.op();
858 }
859 }
860 }
861
862 // eliminate casts to _Bool
863 if(expr_type.id()==ID_c_bool &&
864 op_type.id()!=ID_bool)
865 {
866 // rewrite (_Bool)x to (_Bool)(x!=0)
867 exprt inequality = is_not_zero(expr.op(), ns);
868 auto new_expr = expr;
869 new_expr.op() = simplify_node(std::move(inequality));
870 return changed(simplify_typecast(new_expr)); // recursive call
871 }
872
873 // eliminate typecasts from NULL
874 if(
875 expr_type.id() == ID_pointer && expr.op().is_constant() &&
876 (to_constant_expr(expr.op()).get_value() == ID_NULL ||
877 (expr.op() == 0 && config.ansi_c.NULL_is_zero)))
878 {
879 exprt tmp = expr.op();
880 tmp.type()=expr.type();
881 to_constant_expr(tmp).set_value(ID_NULL);
882 return std::move(tmp);
883 }
884
885 // eliminate duplicate pointer typecasts
886 // (T1 *)(T2 *)x -> (T1 *)x
887 if(
888 expr_type.id() == ID_pointer && expr.op().id() == ID_typecast &&
889 op_type.id() == ID_pointer)
890 {
891 auto new_expr = expr;
892 new_expr.op() = to_typecast_expr(expr.op()).op();
893 return changed(simplify_typecast(new_expr)); // recursive call
894 }
895
896 // casts from integer to pointer and back:
897 // (int)(void *)int -> (int)(size_t)int
898 if(
899 (expr_type.id() == ID_signedbv || expr_type.id() == ID_unsignedbv) &&
900 expr.op().id() == ID_typecast && expr.op().operands().size() == 1 &&
901 op_type.id() == ID_pointer)
902 {
903 auto inner_cast = to_typecast_expr(expr.op());
904 inner_cast.type() = size_type();
905
906 auto outer_cast = expr;
907 outer_cast.op() = simplify_typecast(inner_cast); // rec. call
908 return changed(simplify_typecast(outer_cast)); // rec. call
909 }
910
911 // mildly more elaborate version of the above:
912 // (int)((T*)0 + int) -> (int)(sizeof(T)*(size_t)int) if NULL is zero
913 if(
914 config.ansi_c.NULL_is_zero &&
915 (expr_type.id() == ID_signedbv || expr_type.id() == ID_unsignedbv) &&
916 op_type.id() == ID_pointer && expr.op().id() == ID_plus &&
917 expr.op().operands().size() == 2)
918 {
919 const auto &op_plus_expr = to_plus_expr(expr.op());
920
921 if(
922 (op_plus_expr.op0().id() == ID_typecast &&
923 to_typecast_expr(op_plus_expr.op0()).op() == 0) ||
924 (op_plus_expr.op0().is_constant() &&
925 to_constant_expr(op_plus_expr.op0()).is_null_pointer()))
926 {
927 auto sub_size =
928 pointer_offset_size(to_pointer_type(op_type).base_type(), ns);
929 if(sub_size.has_value())
930 {
931 auto new_expr = expr;
932 exprt offset_expr =
933 simplify_typecast(typecast_exprt(op_plus_expr.op1(), size_type()));
934
935 // void*
936 if(*sub_size == 0 || *sub_size == 1)
937 new_expr.op() = offset_expr;
938 else
939 {
940 new_expr.op() = simplify_mult(
941 mult_exprt(from_integer(*sub_size, size_type()), offset_expr));
942 }
943
944 return changed(simplify_typecast(new_expr)); // rec. call
945 }
946 }
947 }
948
949 // Push a numerical typecast into various integer operations, i.e.,
950 // (T)(x OP y) ---> (T)x OP (T)y
951 //
952 // Doesn't work for many, e.g., pointer difference, floating-point,
953 // division, modulo.
954 // Many operations fail if the width of T
955 // is bigger than that of (x OP y). This includes ID_bitnot and
956 // anything that might overflow, e.g., ID_plus.
957 //
958 if((expr_type.id()==ID_signedbv || expr_type.id()==ID_unsignedbv) &&
959 (op_type.id()==ID_signedbv || op_type.id()==ID_unsignedbv))
960 {
961 bool enlarge=
962 to_bitvector_type(expr_type).get_width()>
963 to_bitvector_type(op_type).get_width();
964
965 if(!enlarge)
966 {
967 irep_idt op_id = expr.op().id();
968
969 if(
970 op_id == ID_plus || op_id == ID_minus || op_id == ID_mult ||
971 op_id == ID_unary_minus || op_id == ID_bitxor || op_id == ID_bitxnor ||
972 op_id == ID_bitor || op_id == ID_bitand)
973 {
974 exprt result = expr.op();
975
976 if(
977 result.operands().size() >= 1 &&
978 to_multi_ary_expr(result).op0().type() == result.type())
979 {
980 result.type()=expr.type();
981
982 Forall_operands(it, result)
983 {
984 auto new_operand = typecast_exprt(*it, expr.type());
985 *it = simplify_typecast(new_operand); // recursive call
986 }
987
988 return changed(simplify_node(result)); // possibly recursive call
989 }
990 }
991 else if(op_id==ID_ashr || op_id==ID_lshr || op_id==ID_shl)
992 {
993 }
994 }
995 }
996
997 // Push a numerical typecast into pointer arithmetic
998 // (T)(ptr + int) ---> (T)((size_t)ptr + sizeof(subtype)*(size_t)int)
999 //
1000 if(
1001 (expr_type.id() == ID_signedbv || expr_type.id() == ID_unsignedbv) &&
1002 op_type.id() == ID_pointer && expr.op().id() == ID_plus)
1003 {
1004 const auto step =
1005 pointer_offset_size(to_pointer_type(op_type).base_type(), ns);
1006
1007 if(step.has_value() && *step != 0)
1008 {
1009 const typet size_t_type(size_type());
1010 auto new_expr = expr;
1011
1012 new_expr.op().type() = size_t_type;
1013
1014 for(auto &op : new_expr.op().operands())
1015 {
1016 exprt new_op = simplify_typecast(typecast_exprt(op, size_t_type));
1017 if(op.type().id() != ID_pointer && *step > 1)
1018 {
1019 new_op =
1020 simplify_mult(mult_exprt(from_integer(*step, size_t_type), new_op));
1021 }
1022 op = std::move(new_op);
1023 }
1024
1025 new_expr.op() = simplify_plus(to_plus_expr(new_expr.op()));
1026
1027 return changed(simplify_typecast(new_expr)); // recursive call
1028 }
1029 }
1030
1031 // Push a pointer typecast into pointer arithmetic
1032 // (T)(ptr + int) ---> (T)ptr + sizeof(inner-st)/sizeof(outer-st)*int
1033 // when the inner subtype's size is a multiple of the outer subtype's size
1034 if(
1035 expr_type.id() == ID_pointer && op_type.id() == ID_pointer &&
1036 expr.op().id() == ID_plus)
1037 {
1038 const auto step =
1039 pointer_offset_size(to_pointer_type(op_type).base_type(), ns);
1040 const auto new_step =
1041 pointer_offset_size(to_pointer_type(expr_type).base_type(), ns);
1042
1043 if(
1044 step.has_value() && *step != 0 && new_step.has_value() &&
1045 *new_step != 0 && *step >= *new_step && *step % *new_step == 0)
1046 {
1047 auto new_expr = expr.op();
1048 new_expr.type() = expr.type();
1049
1050 for(auto &op : new_expr.operands())
1051 {
1052 if(op.type().id() == ID_pointer)
1053 {
1054 exprt new_op = simplify_typecast(typecast_exprt{op, expr.type()});
1055 op = std::move(new_op);
1056 }
1057 else if(*step > *new_step)
1058 {
1059 exprt new_op = simplify_mult(
1060 mult_exprt{from_integer(*step / *new_step, op.type()), op});
1061 op = std::move(new_op);
1062 }
1063 }
1064
1065 return changed(simplify_plus(to_plus_expr(new_expr)));
1066 }
1067 }
1068
1069 const irep_idt &expr_type_id=expr_type.id();
1070 const exprt &operand = expr.op();
1071 const irep_idt &op_type_id=op_type.id();
1072
1073 if(operand.is_constant())
1074 {
1075 const irep_idt &value=to_constant_expr(operand).get_value();
1076
1077 // preserve the sizeof type annotation
1078 typet c_sizeof_type=
1079 static_cast<const typet &>(operand.find(ID_C_c_sizeof_type));
1080
1081 if(op_type_id==ID_integer ||
1082 op_type_id==ID_natural)
1083 {
1084 // from integer to ...
1085
1086 mp_integer int_value=string2integer(id2string(value));
1087
1088 if(expr_type_id==ID_bool)
1089 {
1090 return make_boolean_expr(int_value != 0);
1091 }
1092
1093 if(
1094 expr_type_id == ID_unsignedbv || expr_type_id == ID_signedbv ||
1095 expr_type_id == ID_c_enum || expr_type_id == ID_c_bit_field ||
1096 expr_type_id == ID_integer || expr_type_id == ID_natural ||
1097 expr_type_id == ID_rational || expr_type_id == ID_real)
1098 {
1099 return from_integer(int_value, expr_type);
1100 }
1101 else if(expr_type_id == ID_c_enum_tag)
1102 {
1103 const auto &c_enum_type = ns.follow_tag(to_c_enum_tag_type(expr_type));
1104 if(!c_enum_type.is_incomplete()) // possibly incomplete
1105 {
1106 exprt tmp = from_integer(int_value, c_enum_type);
1107 tmp.type() = expr_type; // we maintain the tag type
1108 return std::move(tmp);
1109 }
1110 }
1111 }
1112 else if(op_type_id==ID_rational)
1113 {
1114 }
1115 else if(op_type_id==ID_real)
1116 {
1117 }
1118 else if(op_type_id==ID_bool)
1119 {
1120 if(expr_type_id==ID_unsignedbv ||
1121 expr_type_id==ID_signedbv ||
1122 expr_type_id==ID_integer ||
1123 expr_type_id==ID_natural ||
1124 expr_type_id==ID_rational ||
1125 expr_type_id==ID_c_bool ||
1126 expr_type_id==ID_c_enum ||
1127 expr_type_id==ID_c_bit_field)
1128 {
1129 if(operand == true)
1130 {
1131 return from_integer(1, expr_type);
1132 }
1133 else if(operand == false)
1134 {
1135 return from_integer(0, expr_type);
1136 }
1137 }
1138 else if(expr_type_id==ID_c_enum_tag)
1139 {
1140 const auto &c_enum_type = ns.follow_tag(to_c_enum_tag_type(expr_type));
1141 if(!c_enum_type.is_incomplete()) // possibly incomplete
1142 {
1143 unsigned int_value = operand == true ? 1u : 0u;
1144 exprt tmp=from_integer(int_value, c_enum_type);
1145 tmp.type()=expr_type; // we maintain the tag type
1146 return std::move(tmp);
1147 }
1148 }
1149 else if(
1150 expr_type_id == ID_pointer && operand == false &&
1151 config.ansi_c.NULL_is_zero)
1152 {
1153 return null_pointer_exprt(to_pointer_type(expr_type));
1154 }
1155 }
1156 else if(op_type_id==ID_unsignedbv ||
1157 op_type_id==ID_signedbv ||
1158 op_type_id==ID_c_bit_field ||
1159 op_type_id==ID_c_bool)
1160 {
1161 mp_integer int_value;
1162
1163 if(to_integer(to_constant_expr(operand), int_value))
1164 return unchanged(expr);
1165
1166 if(expr_type_id==ID_bool)
1167 {
1168 return make_boolean_expr(int_value != 0);
1169 }
1170
1171 if(expr_type_id==ID_c_bool)
1172 {
1173 return from_integer(int_value != 0, expr_type);
1174 }
1175
1176 if(expr_type_id==ID_integer)
1177 {
1178 return from_integer(int_value, expr_type);
1179 }
1180
1181 if(expr_type_id==ID_natural)
1182 {
1183 if(int_value>=0)
1184 {
1185 return from_integer(int_value, expr_type);
1186 }
1187 }
1188
1189 if(expr_type_id==ID_unsignedbv ||
1190 expr_type_id==ID_signedbv ||
1191 expr_type_id==ID_bv ||
1192 expr_type_id==ID_c_bit_field)
1193 {
1194 auto result = from_integer(int_value, expr_type);
1195
1196 if(c_sizeof_type.is_not_nil())
1197 result.set(ID_C_c_sizeof_type, c_sizeof_type);
1198
1199 return std::move(result);
1200 }
1201
1202 if(expr_type_id==ID_c_enum_tag)
1203 {
1204 const auto &c_enum_type = ns.follow_tag(to_c_enum_tag_type(expr_type));
1205 if(!c_enum_type.is_incomplete()) // possibly incomplete
1206 {
1207 exprt tmp=from_integer(int_value, c_enum_type);
1208 tmp.type()=expr_type; // we maintain the tag type
1209 return std::move(tmp);
1210 }
1211 }
1212
1213 if(expr_type_id==ID_c_enum)
1214 {
1215 return from_integer(int_value, expr_type);
1216 }
1217
1218 if(expr_type_id==ID_fixedbv)
1219 {
1220 // int to float
1221 const fixedbv_typet &f_expr_type=
1222 to_fixedbv_type(expr_type);
1223
1224 fixedbvt f;
1225 f.spec=fixedbv_spect(f_expr_type);
1226 f.from_integer(int_value);
1227 return f.to_expr();
1228 }
1229
1230 if(expr_type_id==ID_floatbv)
1231 {
1232 // int to float
1233 const floatbv_typet &f_expr_type=
1234 to_floatbv_type(expr_type);
1235
1237 ieee_floatt f(f_expr_type, rm);
1238 f.from_integer(int_value);
1239
1240 return f.to_expr();
1241 }
1242
1243 if(expr_type_id==ID_rational)
1244 {
1245 rationalt r(int_value);
1246 return from_rational(r);
1247 }
1248
1249 if(expr_type_id == ID_real)
1250 {
1251 return from_integer(int_value, expr_type);
1252 }
1253 }
1254 else if(op_type_id==ID_fixedbv)
1255 {
1256 if(expr_type_id==ID_unsignedbv ||
1257 expr_type_id==ID_signedbv)
1258 {
1259 // cast from fixedbv to int
1260 fixedbvt f(to_constant_expr(expr.op()));
1261 return from_integer(f.to_integer(), expr_type);
1262 }
1263 else if(expr_type_id==ID_fixedbv)
1264 {
1265 // fixedbv to fixedbv
1266 fixedbvt f(to_constant_expr(expr.op()));
1267 f.round(fixedbv_spect(to_fixedbv_type(expr_type)));
1268 return f.to_expr();
1269 }
1270 else if(expr_type_id == ID_bv)
1271 {
1272 fixedbvt f{to_constant_expr(expr.op())};
1273 return from_integer(f.get_value(), expr_type);
1274 }
1275 }
1276 else if(op_type_id==ID_floatbv)
1277 {
1278 ieee_floatt f(
1279 to_constant_expr(expr.op()),
1281
1282 if(expr_type_id==ID_unsignedbv ||
1283 expr_type_id==ID_signedbv)
1284 {
1285 // cast from float to int
1286 return from_integer(f.to_integer(), expr_type);
1287 }
1288 else if(expr_type_id==ID_floatbv)
1289 {
1290 // float to double or double to float
1292 return f.to_expr();
1293 }
1294 else if(expr_type_id==ID_fixedbv)
1295 {
1296 fixedbvt fixedbv;
1297 fixedbv.spec=fixedbv_spect(to_fixedbv_type(expr_type));
1299 factor.from_integer(power(2, fixedbv.spec.get_fraction_bits()));
1300 f*=factor;
1301 fixedbv.set_value(f.to_integer());
1302 return fixedbv.to_expr();
1303 }
1304 else if(expr_type_id == ID_bv)
1305 {
1306 return from_integer(f.pack(), expr_type);
1307 }
1308 }
1309 else if(op_type_id==ID_bv)
1310 {
1311 if(
1312 expr_type_id == ID_unsignedbv || expr_type_id == ID_signedbv ||
1313 expr_type_id == ID_c_enum || expr_type_id == ID_c_enum_tag ||
1314 expr_type_id == ID_c_bit_field)
1315 {
1316 const auto width = to_bv_type(op_type).get_width();
1317 const auto int_value = bvrep2integer(value, width, false);
1318 if(expr_type_id != ID_c_enum_tag)
1319 return from_integer(int_value, expr_type);
1320 else
1321 {
1322 c_enum_tag_typet tag_type = to_c_enum_tag_type(expr_type);
1323 auto result = from_integer(int_value, ns.follow_tag(tag_type));
1324 result.type() = tag_type;
1325 return std::move(result);
1326 }
1327 }
1328 else if(expr_type_id == ID_floatbv)
1329 {
1330 const auto width = to_bv_type(op_type).get_width();
1331 const auto int_value = bvrep2integer(value, width, false);
1332 ieee_float_valuet ieee_float{to_floatbv_type(expr_type)};
1333 ieee_float.unpack(int_value);
1334 return ieee_float.to_expr();
1335 }
1336 else if(expr_type_id == ID_fixedbv)
1337 {
1338 const auto width = to_bv_type(op_type).get_width();
1339 const auto int_value = bvrep2integer(value, width, false);
1340 fixedbvt fixedbv{fixedbv_spect{to_fixedbv_type(expr_type)}};
1341 fixedbv.set_value(int_value);
1342 return fixedbv.to_expr();
1343 }
1344 }
1345 else if(op_type_id==ID_c_enum_tag) // enum to int
1346 {
1347 const typet &base_type =
1348 ns.follow_tag(to_c_enum_tag_type(op_type)).underlying_type();
1349 if(base_type.id()==ID_signedbv || base_type.id()==ID_unsignedbv)
1350 {
1351 // enum constants use the representation of their base type
1352 auto new_expr = expr;
1353 new_expr.op().type() = base_type;
1354 return changed(simplify_typecast(new_expr)); // recursive call
1355 }
1356 }
1357 else if(op_type_id==ID_c_enum) // enum to int
1358 {
1359 const typet &base_type = to_c_enum_type(op_type).underlying_type();
1360 if(base_type.id()==ID_signedbv || base_type.id()==ID_unsignedbv)
1361 {
1362 // enum constants use the representation of their base type
1363 auto new_expr = expr;
1364 new_expr.op().type() = base_type;
1365 return changed(simplify_typecast(new_expr)); // recursive call
1366 }
1367 }
1368 }
1369 else if(operand.id()==ID_typecast) // typecast of typecast
1370 {
1371 // (T1)(T2)x ---> (T1)
1372 // where T1 has fewer bits than T2
1373 if(
1374 op_type_id == expr_type_id &&
1375 (expr_type_id == ID_unsignedbv || expr_type_id == ID_signedbv ||
1376 expr_type_id == ID_bv) &&
1377 to_bitvector_type(expr_type).get_width() <=
1378 to_bitvector_type(operand.type()).get_width())
1379 {
1380 auto new_expr = expr;
1381 new_expr.op() = to_typecast_expr(operand).op();
1382 // might enable further simplification
1383 return changed(simplify_typecast(new_expr)); // recursive call
1384 }
1385 }
1386 else if(operand.id()==ID_address_of)
1387 {
1388 const exprt &o=to_address_of_expr(operand).object();
1389
1390 // turn &array into &array[0] when casting to pointer-to-element-type
1391 if(
1392 o.type().id() == ID_array &&
1393 expr_type == pointer_type(to_array_type(o.type()).element_type()))
1394 {
1395 auto result =
1397
1398 return changed(simplify_address_of(result)); // recursive call
1399 }
1400 }
1401 else if(auto extractbits = expr_try_dynamic_cast<extractbits_exprt>(operand))
1402 {
1403 if(
1404 expr_type_id != ID_floatbv && expr_type_id != ID_pointer &&
1405 can_cast_type<bitvector_typet>(expr_type) &&
1407 to_bitvector_type(expr_type).get_width() ==
1408 to_bitvector_type(operand.type()).get_width())
1409 {
1410 extractbits_exprt result = *extractbits;
1411 result.type() = expr_type;
1412 return changed(simplify_extractbits(result));
1413 }
1414 }
1415
1416 return unchanged(expr);
1417}
1418
1421{
1422 const typet &expr_type = expr.type();
1423 const typet &op_type = expr.op().type();
1424
1425 // (T)(a?b:c) --> a?(T)b:(T)c; don't do this for floating-point type casts as
1426 // the type cast itself may be costly
1427 if(
1428 expr.op().id() == ID_if && expr_type.id() != ID_floatbv &&
1429 op_type.id() != ID_floatbv)
1430 {
1431 if_exprt if_expr = lift_if(expr, 0);
1432 return changed(simplify_if_preorder(if_expr));
1433 }
1434 else
1435 {
1436 auto r_it = simplify_rec(expr.op()); // recursive call
1437 if(r_it.has_changed())
1438 {
1439 auto tmp = expr;
1440 tmp.op() = r_it.expr;
1441 return tmp;
1442 }
1443 }
1444
1445 return unchanged(expr);
1446}
1447
1450{
1451 const exprt &pointer = expr.pointer();
1452
1453 if(pointer.type().id()!=ID_pointer)
1454 return unchanged(expr);
1455
1456 if(pointer.id()==ID_address_of)
1457 {
1458 exprt tmp=to_address_of_expr(pointer).object();
1459 // one address_of is gone, try again
1460 return changed(simplify_rec(tmp));
1461 }
1462 // rewrite *(&a[0] + x) to a[x]
1463 else if(
1464 pointer.id() == ID_plus && pointer.operands().size() == 2 &&
1465 to_plus_expr(pointer).op0().id() == ID_address_of)
1466 {
1467 const auto &pointer_plus_expr = to_plus_expr(pointer);
1468
1469 const address_of_exprt &address_of =
1470 to_address_of_expr(pointer_plus_expr.op0());
1471
1472 if(address_of.object().id()==ID_index)
1473 {
1474 const index_exprt &old=to_index_expr(address_of.object());
1475 if(old.array().type().id() == ID_array)
1476 {
1477 index_exprt idx(
1478 old.array(),
1479 pointer_offset_sum(old.index(), pointer_plus_expr.op1()),
1480 to_array_type(old.array().type()).element_type());
1481 return changed(simplify_rec(idx));
1482 }
1483 }
1484 }
1485
1486 return unchanged(expr);
1487}
1488
1491{
1492 const exprt &pointer = expr.pointer();
1493
1494 if(pointer.id() == ID_if)
1495 {
1496 if_exprt if_expr = lift_if(expr, 0);
1497 return changed(simplify_if_preorder(if_expr));
1498 }
1499 else
1500 {
1501 auto r_it = simplify_rec(pointer); // recursive call
1502 if(r_it.has_changed())
1503 {
1504 auto tmp = expr;
1505 tmp.pointer() = r_it.expr;
1506 return tmp;
1507 }
1508 }
1509
1510 return unchanged(expr);
1511}
1512
1515{
1516 return unchanged(expr);
1517}
1518
1520{
1521 // now look at first operand
1522
1523 if(
1524 expr.old().type().id() == ID_struct ||
1525 expr.old().type().id() == ID_struct_tag)
1526 {
1527 const struct_typet &old_type_followed =
1528 expr.old().type().id() == ID_struct_tag
1529 ? ns.follow_tag(to_struct_tag_type(expr.old().type()))
1530 : to_struct_type(expr.old().type());
1531 const irep_idt &component_name = expr.where().get(ID_component_name);
1532
1533 if(expr.old().id() == ID_struct || expr.old().is_constant())
1534 {
1535 if(!old_type_followed.has_component(component_name))
1536 return unchanged(expr);
1537
1538 std::size_t number = old_type_followed.component_number(component_name);
1539
1540 if(number >= expr.old().operands().size())
1541 return unchanged(expr);
1542
1543 exprt result = expr.old();
1544 result.operands()[number] = expr.new_value();
1545 return result;
1546 }
1547 else if(
1548 old_type_followed.components().size() == 1 &&
1549 old_type_followed.has_component(component_name))
1550 {
1551 return struct_exprt{{expr.new_value()}, expr.type()};
1552 }
1553 }
1554 else if(
1555 expr.old().type().id() == ID_array || expr.old().type().id() == ID_vector)
1556 {
1557 if(
1558 expr.old().id() == ID_array || expr.old().is_constant() ||
1559 expr.old().id() == ID_vector)
1560 {
1561 const auto i = numeric_cast<mp_integer>(expr.where());
1562
1563 if(i.has_value() && *i >= 0 && *i < expr.old().operands().size())
1564 {
1565 exprt result = expr.old();
1566 result.operands()[numeric_cast_v<std::size_t>(*i)] = expr.new_value();
1567 return result;
1568 }
1569 }
1570 }
1571
1572 return unchanged(expr);
1573}
1574
1577{
1578 // this is to push updates into (possibly nested) constants
1579
1580 const exprt::operandst &designator = expr.designator();
1581
1582 exprt updated_value = expr.old();
1583 exprt *value_ptr=&updated_value;
1584
1585 for(const auto &e : designator)
1586 {
1587 if(e.id()==ID_index_designator &&
1588 value_ptr->id()==ID_array)
1589 {
1590 const auto i = numeric_cast<mp_integer>(to_index_designator(e).index());
1591
1592 if(!i.has_value())
1593 return unchanged(expr);
1594
1595 if(*i < 0 || *i >= value_ptr->operands().size())
1596 return unchanged(expr);
1597
1598 value_ptr = &value_ptr->operands()[numeric_cast_v<std::size_t>(*i)];
1599 }
1600 else if(e.id()==ID_member_designator &&
1601 value_ptr->id()==ID_struct)
1602 {
1603 const irep_idt &component_name=
1604 e.get(ID_component_name);
1605 const struct_typet &value_ptr_struct_type =
1606 value_ptr->type().id() == ID_struct_tag
1607 ? ns.follow_tag(to_struct_tag_type(value_ptr->type()))
1608 : to_struct_type(value_ptr->type());
1609 if(!value_ptr_struct_type.has_component(component_name))
1610 return unchanged(expr);
1611 auto &designator_as_struct_expr = to_struct_expr(*value_ptr);
1612 value_ptr = &designator_as_struct_expr.component(component_name, ns);
1613 CHECK_RETURN(value_ptr->is_not_nil());
1614 }
1615 else
1616 return unchanged(expr); // give up, unknown designator
1617 }
1618
1619 // found, done
1620 *value_ptr = expr.new_value();
1621 return updated_value;
1622}
1623
1625{
1626 if(expr.id()==ID_plus)
1627 {
1628 if(expr.type().id()==ID_pointer)
1629 {
1630 // kill integers from sum
1631 for(auto &op : expr.operands())
1632 if(op.type().id() == ID_pointer)
1633 return changed(simplify_object(op)); // recursive call
1634 }
1635 }
1636 else if(expr.id()==ID_typecast)
1637 {
1638 auto const &typecast_expr = to_typecast_expr(expr);
1639 const typet &op_type = typecast_expr.op().type();
1640
1641 if(op_type.id()==ID_pointer)
1642 {
1643 // cast from pointer to pointer
1644 return changed(simplify_object(typecast_expr.op())); // recursive call
1645 }
1646 else if(op_type.id()==ID_signedbv || op_type.id()==ID_unsignedbv)
1647 {
1648 // cast from integer to pointer
1649
1650 // We do a bit of special treatment for (TYPE *)(a+(int)&o) and
1651 // (TYPE *)(a+(int)((T*)&o+x)), which are re-written to '&o'.
1652
1653 const exprt &casted_expr = typecast_expr.op();
1654 if(casted_expr.id() == ID_plus && casted_expr.operands().size() == 2)
1655 {
1656 const auto &plus_expr = to_plus_expr(casted_expr);
1657
1658 const exprt &cand = plus_expr.op0().id() == ID_typecast
1659 ? plus_expr.op0()
1660 : plus_expr.op1();
1661
1662 if(cand.id() == ID_typecast)
1663 {
1664 const auto &typecast_op = to_typecast_expr(cand).op();
1665
1666 if(typecast_op.id() == ID_address_of)
1667 {
1668 return typecast_op;
1669 }
1670 else if(
1671 typecast_op.id() == ID_plus && typecast_op.operands().size() == 2 &&
1672 to_plus_expr(typecast_op).op0().id() == ID_typecast &&
1673 to_typecast_expr(to_plus_expr(typecast_op).op0()).op().id() ==
1674 ID_address_of)
1675 {
1676 return to_typecast_expr(to_plus_expr(typecast_op).op0()).op();
1677 }
1678 }
1679 }
1680 }
1681 }
1682 else if(expr.id()==ID_address_of)
1683 {
1684 const auto &object = to_address_of_expr(expr).object();
1685
1686 if(object.id() == ID_index)
1687 {
1688 // &some[i] -> &some
1689 address_of_exprt new_expr(to_index_expr(object).array());
1690 return changed(simplify_object(new_expr)); // recursion
1691 }
1692 else if(object.id() == ID_member)
1693 {
1694 // &some.f -> &some
1695 address_of_exprt new_expr(to_member_expr(object).compound());
1696 return changed(simplify_object(new_expr)); // recursion
1697 }
1698 }
1699
1700 return unchanged(expr);
1701}
1702
1705{
1706 // lift up any ID_if on the object
1707 if(expr.op().id() == ID_if)
1708 {
1709 if_exprt if_expr = lift_if(expr, 0);
1710 if_expr.true_case() =
1712 if_expr.false_case() =
1714 return changed(simplify_if(if_expr));
1715 }
1716
1717 const auto el_size = pointer_offset_bits(expr.type(), ns);
1718 if(el_size.has_value() && *el_size < 0)
1719 return unchanged(expr);
1720
1721 // byte_extract(byte_extract(root, offset1), offset2) =>
1722 // byte_extract(root, offset1+offset2)
1723 if(expr.op().id()==expr.id())
1724 {
1725 auto tmp = expr;
1726
1729 to_byte_extract_expr(expr.op()).offset(), expr.offset().type()),
1730 expr.offset()));
1731 tmp.op() = to_byte_extract_expr(expr.op()).op();
1732
1733 return changed(simplify_byte_extract(tmp)); // recursive call
1734 }
1735
1736 // byte_extract(byte_update(root, offset, value), offset) =>
1737 // value
1738 if(
1739 ((expr.id() == ID_byte_extract_big_endian &&
1740 expr.op().id() == ID_byte_update_big_endian) ||
1741 (expr.id() == ID_byte_extract_little_endian &&
1742 expr.op().id() == ID_byte_update_little_endian)) &&
1743 expr.offset() == to_byte_update_expr(as_const(expr).op()).offset())
1744 {
1745 const auto &op_byte_update = to_byte_update_expr(expr.op());
1746
1747 if(expr.type() == op_byte_update.value().type())
1748 {
1749 return op_byte_update.value();
1750 }
1751 else if(el_size.has_value())
1752 {
1753 const auto update_bits_opt =
1754 pointer_offset_bits(op_byte_update.value().type(), ns);
1755
1756 if(update_bits_opt.has_value() && *el_size <= *update_bits_opt)
1757 {
1758 auto tmp = expr;
1759 tmp.op() = op_byte_update.value();
1760 tmp.offset() = from_integer(0, expr.offset().type());
1761
1762 return changed(simplify_byte_extract(tmp)); // recursive call
1763 }
1764 }
1765 }
1766
1767 auto offset = numeric_cast<mp_integer>(expr.offset());
1768 if(offset.has_value() && *offset < 0)
1769 return unchanged(expr);
1770
1771 // try to simplify byte_extract(byte_update(...))
1772 auto const bu = expr_try_dynamic_cast<byte_update_exprt>(expr.op());
1773 std::optional<mp_integer> update_offset;
1774 if(bu)
1775 update_offset = numeric_cast<mp_integer>(bu->offset());
1776 if(
1777 offset.has_value() && bu && el_size.has_value() &&
1778 update_offset.has_value())
1779 {
1780 // byte_extract(byte_update(root, offset_u, value), offset_e) so that the
1781 // update does not affect what is being extracted simplifies to
1782 // byte_extract(root, offset_e)
1783 //
1784 // byte_extract(byte_update(root, offset_u, value), offset_e) so that the
1785 // extracted range fully lies within the update value simplifies to
1786 // byte_extract(value, offset_e - offset_u)
1787 if(
1788 *offset * expr.get_bits_per_byte() + *el_size <=
1789 *update_offset * bu->get_bits_per_byte())
1790 {
1791 // extracting before the update
1792 auto tmp = expr;
1793 tmp.op() = bu->op();
1794 return changed(simplify_byte_extract(tmp)); // recursive call
1795 }
1796 else if(
1797 const auto update_size = pointer_offset_bits(bu->value().type(), ns))
1798 {
1799 if(
1800 *offset * expr.get_bits_per_byte() >=
1801 *update_offset * bu->get_bits_per_byte() + *update_size)
1802 {
1803 // extracting after the update
1804 auto tmp = expr;
1805 tmp.op() = bu->op();
1806 return changed(simplify_byte_extract(tmp)); // recursive call
1807 }
1808 else if(
1809 *offset >= *update_offset &&
1810 *offset * expr.get_bits_per_byte() + *el_size <=
1811 *update_offset * bu->get_bits_per_byte() + *update_size)
1812 {
1813 // extracting from the update
1814 auto tmp = expr;
1815 tmp.op() = bu->value();
1816 tmp.offset() =
1817 from_integer(*offset - *update_offset, expr.offset().type());
1818 return changed(simplify_byte_extract(tmp)); // recursive call
1819 }
1820 }
1821 }
1822
1823 // don't do any of the following if endianness doesn't match, as
1824 // bytes need to be swapped
1825 if(
1826 offset.has_value() && *offset == 0 &&
1827 ((expr.id() == ID_byte_extract_little_endian &&
1828 config.ansi_c.endianness ==
1830 (expr.id() == ID_byte_extract_big_endian &&
1831 config.ansi_c.endianness ==
1833 {
1834 // byte extract of full object is object
1835 if(expr.type() == expr.op().type())
1836 {
1837 return expr.op();
1838 }
1839 else if(
1840 expr.type().id() == ID_pointer && expr.op().type().id() == ID_pointer)
1841 {
1842 return typecast_exprt(expr.op(), expr.type());
1843 }
1844 }
1845
1846 if(
1847 (expr.type().id() == ID_union &&
1848 to_union_type(expr.type()).components().empty()) ||
1849 (expr.type().id() == ID_union_tag &&
1850 ns.follow_tag(to_union_tag_type(expr.type())).components().empty()))
1851 {
1852 return empty_union_exprt{expr.type()};
1853 }
1854 else if(
1855 (expr.type().id() == ID_struct &&
1856 to_struct_type(expr.type()).components().empty()) ||
1857 (expr.type().id() == ID_struct_tag &&
1858 ns.follow_tag(to_struct_tag_type(expr.type())).components().empty()))
1859 {
1860 return struct_exprt{{}, expr.type()};
1861 }
1862
1863 // no proper simplification for expr.type()==void
1864 // or types of unknown size
1865 if(!el_size.has_value() || *el_size == 0)
1866 return unchanged(expr);
1867
1868 if(
1869 offset.has_value() && expr.op().id() == ID_array_of &&
1870 to_array_of_expr(expr.op()).op().is_constant())
1871 {
1872 const auto const_bits_opt = expr2bits(
1873 to_array_of_expr(expr.op()).op(),
1874 config.ansi_c.endianness ==
1876 ns);
1877
1878 if(!const_bits_opt.has_value())
1879 return unchanged(expr);
1880
1881 std::string const_bits=const_bits_opt.value();
1882
1883 DATA_INVARIANT(!const_bits.empty(), "bit representation must be non-empty");
1884
1885 // double the string until we have sufficiently many bits
1886 while(mp_integer(const_bits.size()) <
1887 *offset * expr.get_bits_per_byte() + *el_size)
1888 {
1889 const_bits+=const_bits;
1890 }
1891
1892 std::string el_bits = std::string(
1893 const_bits,
1895 numeric_cast_v<std::size_t>(*el_size));
1896
1897 auto tmp = bits2expr(
1898 el_bits, expr.type(), expr.id() == ID_byte_extract_little_endian, ns);
1899
1900 if(tmp.has_value())
1901 return std::move(*tmp);
1902 }
1903
1904 // in some cases we even handle non-const array_of
1905 if(
1906 offset.has_value() && expr.op().id() == ID_array_of &&
1907 (*offset * expr.get_bits_per_byte()) % (*el_size) == 0 &&
1908 *el_size <=
1910 {
1911 auto tmp = expr;
1912 tmp.op() = simplify_index(index_exprt(expr.op(), expr.offset()));
1913 tmp.offset() = from_integer(0, expr.offset().type());
1914 return changed(simplify_byte_extract(tmp));
1915 }
1916
1917 // extract bits of a constant
1918 const auto bits =
1919 expr2bits(expr.op(), expr.id() == ID_byte_extract_little_endian, ns);
1920
1921 if(
1922 offset.has_value() && bits.has_value() &&
1923 mp_integer(bits->size()) >= *el_size + *offset * expr.get_bits_per_byte())
1924 {
1925 // make sure we don't lose bits with structs containing flexible array
1926 // members
1927 const bool struct_has_flexible_array_member = has_subtype(
1928 expr.type(),
1929 [&](const typet &type) {
1930 if(type.id() != ID_struct && type.id() != ID_struct_tag)
1931 return false;
1932
1933 const struct_typet &st = type.id() == ID_struct_tag
1934 ? ns.follow_tag(to_struct_tag_type(type))
1935 : to_struct_type(type);
1936 const auto &comps = st.components();
1937 if(comps.empty() || comps.back().type().id() != ID_array)
1938 return false;
1939
1940 if(comps.back().type().get_bool(ID_C_flexible_array_member))
1941 return true;
1942
1943 const auto size =
1944 numeric_cast<mp_integer>(to_array_type(comps.back().type()).size());
1945 return !size.has_value() || *size <= 1;
1946 },
1947 ns);
1948 if(!struct_has_flexible_array_member)
1949 {
1950 std::string bits_cut = std::string(
1951 bits.value(),
1953 numeric_cast_v<std::size_t>(*el_size));
1954
1955 auto tmp = bits2expr(
1956 bits_cut, expr.type(), expr.id() == ID_byte_extract_little_endian, ns);
1957
1958 if(tmp.has_value())
1959 return std::move(*tmp);
1960 }
1961 }
1962
1963 // push byte extracts into struct or union expressions, just like
1964 // lower_byte_extract does (this is the same code, except recursive calls use
1965 // simplify rather than lower_byte_extract)
1966 if(expr.op().id() == ID_struct || expr.op().id() == ID_union)
1967 {
1968 if(expr.type().id() == ID_struct || expr.type().id() == ID_struct_tag)
1969 {
1970 const struct_typet &struct_type =
1971 expr.type().id() == ID_struct_tag
1972 ? ns.follow_tag(to_struct_tag_type(expr.type()))
1973 : to_struct_type(expr.type());
1974 const struct_typet::componentst &components = struct_type.components();
1975
1976 bool failed = false;
1977 struct_exprt s({}, expr.type());
1978
1979 for(const auto &comp : components)
1980 {
1981 auto component_bits = pointer_offset_bits(comp.type(), ns);
1982
1983 // the next member would be misaligned, abort
1984 if(
1985 !component_bits.has_value() || *component_bits == 0 ||
1986 *component_bits % expr.get_bits_per_byte() != 0)
1987 {
1988 failed = true;
1989 break;
1990 }
1991
1992 auto member_offset_opt =
1993 member_offset_expr(struct_type, comp.get_name(), ns);
1994
1995 if(!member_offset_opt.has_value())
1996 {
1997 failed = true;
1998 break;
1999 }
2000
2001 exprt new_offset = simplify_rec(
2002 plus_exprt{expr.offset(),
2004 member_offset_opt.value(), expr.offset().type())});
2005
2006 byte_extract_exprt tmp = expr;
2007 tmp.type() = comp.type();
2008 tmp.offset() = new_offset;
2009
2011 }
2012
2013 if(!failed)
2014 return s;
2015 }
2016 else if(expr.type().id() == ID_union || expr.type().id() == ID_union_tag)
2017 {
2018 const union_typet &union_type =
2019 expr.type().id() == ID_union_tag
2020 ? ns.follow_tag(to_union_tag_type(expr.type()))
2021 : to_union_type(expr.type());
2022 auto widest_member_opt = union_type.find_widest_union_component(ns);
2023 if(widest_member_opt.has_value())
2024 {
2025 byte_extract_exprt be = expr;
2026 be.type() = widest_member_opt->first.type();
2027 return union_exprt{widest_member_opt->first.get_name(),
2029 expr.type()};
2030 }
2031 }
2032 }
2033 else if(expr.op().id() == ID_array)
2034 {
2035 const array_typet &array_type = to_array_type(expr.op().type());
2036 const auto &element_bit_width =
2037 pointer_offset_bits(array_type.element_type(), ns);
2038 if(
2039 offset.has_value() && element_bit_width.has_value() &&
2040 *element_bit_width > 0)
2041 {
2042 if(
2043 *offset > 0 &&
2044 *offset * expr.get_bits_per_byte() % *element_bit_width == 0)
2045 {
2046 const auto elements_to_erase = numeric_cast_v<std::size_t>(
2047 (*offset * expr.get_bits_per_byte()) / *element_bit_width);
2049 slice.operands().erase(
2050 slice.operands().begin(),
2051 slice.operands().begin() +
2052 std::min(elements_to_erase, slice.operands().size()));
2053 slice.type().size() =
2054 from_integer(slice.operands().size(), slice.type().size().type());
2055 byte_extract_exprt be = expr;
2056 be.op() = slice;
2057 be.offset() = from_integer(0, expr.offset().type());
2058 return changed(simplify_byte_extract(be));
2059 }
2060 else if(*offset == 0 && *el_size % *element_bit_width == 0)
2061 {
2062 const auto elements_to_keep =
2063 numeric_cast_v<std::size_t>(*el_size / *element_bit_width);
2065 if(slice.operands().size() > elements_to_keep)
2066 {
2067 slice.operands().resize(elements_to_keep);
2068 slice.type().size() =
2069 from_integer(slice.operands().size(), slice.type().size().type());
2070 byte_extract_exprt be = expr;
2071 be.op() = slice;
2072 return changed(simplify_byte_extract(be));
2073 }
2074 }
2075 }
2076 }
2077
2078 // try to refine it down to extracting from a member or an index in an array
2079 auto subexpr =
2080 get_subexpression_at_offset(expr.op(), expr.offset(), expr.type(), ns);
2081 if(subexpr.has_value() && subexpr.value() != expr)
2082 return changed(simplify_rec(subexpr.value())); // recursive call
2083
2084 if(can_forward_propagatet(ns)(expr))
2085 return changed(simplify_rec(lower_byte_extract(expr, ns)));
2086
2087 return unchanged(expr);
2088}
2089
2092{
2093 // lift up any ID_if on the object
2094 if(expr.op().id() == ID_if)
2095 {
2096 if_exprt if_expr = lift_if(expr, 0);
2097 return changed(simplify_if_preorder(if_expr));
2098 }
2099 else
2100 {
2101 std::optional<exprt::operandst> new_operands;
2102
2103 for(std::size_t i = 0; i < expr.operands().size(); ++i)
2104 {
2105 auto r_it = simplify_rec(expr.operands()[i]); // recursive call
2106 if(r_it.has_changed())
2107 {
2108 if(!new_operands.has_value())
2109 new_operands = expr.operands();
2110 (*new_operands)[i] = std::move(r_it.expr);
2111 }
2112 }
2113
2114 if(new_operands.has_value())
2115 {
2116 exprt result = expr;
2117 std::swap(result.operands(), *new_operands);
2118 return result;
2119 }
2120 }
2121
2122 return unchanged(expr);
2123}
2124
2127{
2128 // byte_update(byte_update(root, offset, value), offset, value2) =>
2129 // byte_update(root, offset, value2)
2130 if(
2131 expr.id() == expr.op().id() &&
2132 expr.offset() == to_byte_update_expr(expr.op()).offset() &&
2133 expr.value().type() == to_byte_update_expr(expr.op()).value().type())
2134 {
2135 auto tmp = expr;
2136 tmp.set_op(to_byte_update_expr(expr.op()).op());
2137 return std::move(tmp);
2138 }
2139
2140 const exprt &root = expr.op();
2141 const exprt &offset = expr.offset();
2142 const exprt &value = expr.value();
2143 const auto val_size = pointer_offset_bits(value.type(), ns);
2144 const auto root_size = pointer_offset_bits(root.type(), ns);
2145
2146 const auto matching_byte_extract_id =
2147 expr.id() == ID_byte_update_little_endian ? ID_byte_extract_little_endian
2148 : ID_byte_extract_big_endian;
2149
2150 // byte update of full object is byte_extract(new value)
2151 if(
2152 offset == 0 && val_size.has_value() && *val_size > 0 &&
2153 root_size.has_value() && *root_size > 0 && *val_size >= *root_size)
2154 {
2156 matching_byte_extract_id,
2157 value,
2158 offset,
2159 expr.get_bits_per_byte(),
2160 expr.type());
2161
2162 return changed(simplify_byte_extract(be));
2163 }
2164
2165 // update bits in a constant
2166 const auto offset_int = numeric_cast<mp_integer>(offset);
2167 if(
2168 root_size.has_value() && *root_size >= 0 && val_size.has_value() &&
2169 *val_size >= 0 && offset_int.has_value() && *offset_int >= 0 &&
2170 *offset_int * expr.get_bits_per_byte() + *val_size <= *root_size)
2171 {
2172 auto root_bits =
2173 expr2bits(root, expr.id() == ID_byte_update_little_endian, ns);
2174
2175 if(root_bits.has_value())
2176 {
2177 const auto val_bits =
2178 expr2bits(value, expr.id() == ID_byte_update_little_endian, ns);
2179
2180 if(val_bits.has_value())
2181 {
2182 root_bits->replace(
2183 numeric_cast_v<std::size_t>(*offset_int * expr.get_bits_per_byte()),
2184 numeric_cast_v<std::size_t>(*val_size),
2185 *val_bits);
2186
2187 auto tmp = bits2expr(
2188 *root_bits,
2189 expr.type(),
2190 expr.id() == ID_byte_update_little_endian,
2191 ns);
2192
2193 if(tmp.has_value())
2194 return std::move(*tmp);
2195 }
2196 }
2197 }
2198
2199 /*
2200 * byte_update(root, offset,
2201 * extract(root, offset) WITH component:=value)
2202 * =>
2203 * byte_update(root, offset + component offset,
2204 * value)
2205 */
2206
2207 if(value.id()==ID_with)
2208 {
2209 const with_exprt &with=to_with_expr(value);
2210
2211 if(with.old().id() == matching_byte_extract_id)
2212 {
2213 const byte_extract_exprt &extract=to_byte_extract_expr(with.old());
2214
2215 /* the simplification can be used only if
2216 root and offset of update and extract
2217 are the same */
2218 if(!(root==extract.op()))
2219 return unchanged(expr);
2220 if(!(offset==extract.offset()))
2221 return unchanged(expr);
2222
2223 if(with.type().id() == ID_struct || with.type().id() == ID_struct_tag)
2224 {
2225 const struct_typet &struct_type =
2226 with.type().id() == ID_struct_tag
2227 ? ns.follow_tag(to_struct_tag_type(with.type()))
2228 : to_struct_type(with.type());
2229 const irep_idt &component_name=with.where().get(ID_component_name);
2230 const typet &c_type = struct_type.get_component(component_name).type();
2231
2232 // is this a bit field?
2233 if(c_type.id() == ID_c_bit_field || c_type.id() == ID_bool)
2234 {
2235 // don't touch -- might not be byte-aligned
2236 }
2237 else
2238 {
2239 // new offset = offset + component offset
2240 auto i = member_offset(struct_type, component_name, ns);
2241 if(i.has_value())
2242 {
2243 exprt compo_offset = from_integer(*i, offset.type());
2244 plus_exprt new_offset(offset, compo_offset);
2245 exprt new_value(with.new_value());
2246 auto tmp = expr;
2247 tmp.set_offset(simplify_node(std::move(new_offset)));
2248 tmp.set_value(std::move(new_value));
2249 return changed(simplify_byte_update(tmp)); // recursive call
2250 }
2251 }
2252 }
2253 else if(with.type().id() == ID_array)
2254 {
2255 auto i =
2257 if(i.has_value())
2258 {
2259 const exprt &index=with.where();
2260 exprt index_offset =
2261 simplify_mult(mult_exprt(index, from_integer(*i, index.type())));
2262
2263 // index_offset may need a typecast
2264 if(offset.type() != index.type())
2265 {
2266 index_offset =
2267 simplify_typecast(typecast_exprt(index_offset, offset.type()));
2268 }
2269
2270 plus_exprt new_offset(offset, index_offset);
2271 exprt new_value(with.new_value());
2272 auto tmp = expr;
2273 tmp.set_offset(simplify_plus(std::move(new_offset)));
2274 tmp.set_value(std::move(new_value));
2275 return changed(simplify_byte_update(tmp)); // recursive call
2276 }
2277 }
2278 }
2279 }
2280
2281 // size must be known
2282 if(!val_size.has_value() || *val_size == 0)
2283 return unchanged(expr);
2284
2285 // byte_update(root, offset, value) is with(root, index, value) when root is
2286 // array-typed, the size of value matches the array-element width, and offset
2287 // is guaranteed to be a multiple of the array-element width
2288 if(auto array_type = type_try_dynamic_cast<array_typet>(root.type()))
2289 {
2290 auto el_size = pointer_offset_bits(array_type->element_type(), ns);
2291
2292 if(el_size.has_value() && *el_size > 0 && *val_size % *el_size == 0)
2293 {
2294 if(
2295 offset_int.has_value() &&
2296 (*offset_int * expr.get_bits_per_byte()) % *el_size == 0)
2297 {
2298 mp_integer base_offset =
2299 (*offset_int * expr.get_bits_per_byte()) / *el_size;
2300 with_exprt result_expr{
2301 root,
2302 from_integer(base_offset, array_type->index_type()),
2304 matching_byte_extract_id,
2305 value,
2306 from_integer(0, offset.type()),
2307 expr.get_bits_per_byte(),
2308 array_type->element_type()}};
2309 mp_integer n_elements = *val_size / *el_size;
2310
2311 for(mp_integer i = 1; i < n_elements; ++i)
2312 {
2313 result_expr = with_exprt{
2314 result_expr,
2315 from_integer(base_offset + i, array_type->index_type()),
2317 matching_byte_extract_id,
2318 value,
2320 i * (*el_size / expr.get_bits_per_byte()), offset.type()),
2321 expr.get_bits_per_byte(),
2322 array_type->element_type()}};
2323 }
2324
2325 return changed(simplify_rec(result_expr));
2326 }
2327 // if we have an offset C + x (where C is a constant) we can try to
2328 // recurse by first looking at the member at offset C
2329 else if(
2330 offset.id() == ID_plus && offset.operands().size() == 2 &&
2331 (to_multi_ary_expr(offset).op0().is_constant() ||
2332 to_multi_ary_expr(offset).op1().is_constant()))
2333 {
2334 const plus_exprt &offset_plus = to_plus_expr(offset);
2335 const auto &const_factor = offset_plus.op0().is_constant()
2336 ? offset_plus.op0()
2337 : offset_plus.op1();
2338 const exprt &other_factor = offset_plus.op0().is_constant()
2339 ? offset_plus.op1()
2340 : offset_plus.op0();
2341
2342 auto tmp = expr;
2343 tmp.set_offset(const_factor);
2344 exprt expr_at_offset_C = simplify_byte_update(tmp);
2345
2346 if(
2347 expr_at_offset_C.id() == ID_with &&
2348 to_with_expr(expr_at_offset_C).where() == 0)
2349 {
2350 tmp.set_op(to_with_expr(expr_at_offset_C).old());
2351 tmp.set_offset(other_factor);
2352 return changed(simplify_byte_update(tmp));
2353 }
2354 }
2355 else if(
2356 offset.id() == ID_mult && offset.operands().size() == 2 &&
2357 (to_multi_ary_expr(offset).op0().is_constant() ||
2358 to_multi_ary_expr(offset).op1().is_constant()))
2359 {
2360 const mult_exprt &offset_mult = to_mult_expr(offset);
2361 const auto &const_factor = numeric_cast_v<mp_integer>(to_constant_expr(
2362 offset_mult.op0().is_constant() ? offset_mult.op0()
2363 : offset_mult.op1()));
2364 const exprt &other_factor = offset_mult.op0().is_constant()
2365 ? offset_mult.op1()
2366 : offset_mult.op0();
2367
2368 if((const_factor * expr.get_bits_per_byte()) % *el_size == 0)
2369 {
2370 exprt base_offset = mult_exprt{
2371 other_factor,
2373 (const_factor * expr.get_bits_per_byte()) / *el_size,
2374 other_factor.type())};
2375 with_exprt result_expr{
2376 root,
2378 base_offset, array_type->index_type()),
2380 matching_byte_extract_id,
2381 value,
2382 from_integer(0, offset.type()),
2383 expr.get_bits_per_byte(),
2384 array_type->element_type()}};
2385 mp_integer n_elements = *val_size / *el_size;
2386 for(mp_integer i = 1; i < n_elements; ++i)
2387 {
2388 result_expr = with_exprt{
2389 result_expr,
2391 plus_exprt{base_offset, from_integer(i, base_offset.type())},
2392 array_type->index_type()),
2394 matching_byte_extract_id,
2395 value,
2397 i * (*el_size / expr.get_bits_per_byte()), offset.type()),
2398 expr.get_bits_per_byte(),
2399 array_type->element_type()}};
2400 }
2401 return changed(simplify_rec(result_expr));
2402 }
2403 }
2404 }
2405 }
2406
2407 // the following require a constant offset
2408 if(!offset_int.has_value() || *offset_int < 0)
2409 return unchanged(expr);
2410
2411 // Are we updating (parts of) a struct? Do individual member updates
2412 // instead, unless there are non-byte-sized bit fields
2413 if(root.type().id() == ID_struct || root.type().id() == ID_struct_tag)
2414 {
2415 exprt result_expr;
2416 result_expr.make_nil();
2417
2418 auto update_size = pointer_offset_size(value.type(), ns);
2419
2420 const struct_typet &struct_type =
2421 root.type().id() == ID_struct_tag
2422 ? ns.follow_tag(to_struct_tag_type(root.type()))
2423 : to_struct_type(root.type());
2424 const struct_typet::componentst &components=
2425 struct_type.components();
2426
2427 for(const auto &component : components)
2428 {
2429 auto m_offset = member_offset(struct_type, component.get_name(), ns);
2430
2431 auto m_size_bits = pointer_offset_bits(component.type(), ns);
2432
2433 // can we determine the current offset?
2434 if(!m_offset.has_value())
2435 {
2436 result_expr.make_nil();
2437 break;
2438 }
2439
2440 // is it a byte-sized member?
2441 if(
2442 !m_size_bits.has_value() || *m_size_bits == 0 ||
2443 (*m_size_bits) % expr.get_bits_per_byte() != 0)
2444 {
2445 result_expr.make_nil();
2446 break;
2447 }
2448
2449 mp_integer m_size_bytes = (*m_size_bits) / expr.get_bits_per_byte();
2450
2451 // is that member part of the update?
2452 if(*m_offset + m_size_bytes <= *offset_int)
2453 continue;
2454 // are we done updating?
2455 else if(
2456 update_size.has_value() && *update_size > 0 &&
2457 *m_offset >= *offset_int + *update_size)
2458 {
2459 break;
2460 }
2461
2462 if(result_expr.is_nil())
2463 result_expr = as_const(expr).op();
2464
2465 exprt member_name(ID_member_name);
2466 member_name.set(ID_component_name, component.get_name());
2467 result_expr=with_exprt(result_expr, member_name, nil_exprt());
2468
2469 // are we updating on member boundaries?
2470 if(
2471 *m_offset < *offset_int ||
2472 (*m_offset == *offset_int && update_size.has_value() &&
2473 *update_size > 0 && m_size_bytes > *update_size))
2474 {
2476 expr.id(),
2477 member_exprt(root, component.get_name(), component.type()),
2478 from_integer(*offset_int - *m_offset, offset.type()),
2479 value,
2480 expr.get_bits_per_byte());
2481
2482 to_with_expr(result_expr).new_value().swap(v);
2483 }
2484 else if(
2485 update_size.has_value() && *update_size > 0 &&
2486 *m_offset + m_size_bytes > *offset_int + *update_size)
2487 {
2488 // we don't handle this for the moment
2489 result_expr.make_nil();
2490 break;
2491 }
2492 else
2493 {
2495 matching_byte_extract_id,
2496 value,
2497 from_integer(*m_offset - *offset_int, offset.type()),
2498 expr.get_bits_per_byte(),
2499 component.type());
2500
2501 to_with_expr(result_expr).new_value().swap(v);
2502 }
2503 }
2504
2505 if(result_expr.is_not_nil())
2506 return changed(simplify_rec(result_expr));
2507 }
2508
2509 // replace elements of array or struct expressions, possibly using
2510 // byte_extract
2511 if(root.id()==ID_array)
2512 {
2513 auto el_size =
2515
2516 if(
2517 !el_size.has_value() || *el_size == 0 ||
2518 (*el_size) % expr.get_bits_per_byte() != 0 ||
2519 (*val_size) % expr.get_bits_per_byte() != 0)
2520 {
2521 return unchanged(expr);
2522 }
2523
2524 exprt result=root;
2525
2526 mp_integer m_offset_bits=0, val_offset=0;
2527 Forall_operands(it, result)
2528 {
2529 if(*offset_int * expr.get_bits_per_byte() + (*val_size) <= m_offset_bits)
2530 break;
2531
2532 if(*offset_int * expr.get_bits_per_byte() < m_offset_bits + *el_size)
2533 {
2534 mp_integer bytes_req =
2535 (m_offset_bits + *el_size) / expr.get_bits_per_byte() - *offset_int;
2536 bytes_req-=val_offset;
2537 if(val_offset + bytes_req > (*val_size) / expr.get_bits_per_byte())
2538 bytes_req = (*val_size) / expr.get_bits_per_byte() - val_offset;
2539
2540 byte_extract_exprt new_val(
2541 matching_byte_extract_id,
2542 value,
2543 from_integer(val_offset, offset.type()),
2544 expr.get_bits_per_byte(),
2547 from_integer(bytes_req, offset.type())));
2548
2549 *it = byte_update_exprt(
2550 expr.id(),
2551 *it,
2553 *offset_int + val_offset - m_offset_bits / expr.get_bits_per_byte(),
2554 offset.type()),
2555 new_val,
2556 expr.get_bits_per_byte());
2557
2558 *it = simplify_rec(*it); // recursive call
2559
2560 val_offset+=bytes_req;
2561 }
2562
2563 m_offset_bits += *el_size;
2564 }
2565
2566 return std::move(result);
2567 }
2568
2569 return unchanged(expr);
2570}
2571
2574{
2575 if(expr.id() == ID_complex_real)
2576 {
2577 auto &complex_real_expr = to_complex_real_expr(expr);
2578
2579 if(complex_real_expr.op().id() == ID_complex)
2580 return to_complex_expr(complex_real_expr.op()).real();
2581 }
2582 else if(expr.id() == ID_complex_imag)
2583 {
2584 auto &complex_imag_expr = to_complex_imag_expr(expr);
2585
2586 if(complex_imag_expr.op().id() == ID_complex)
2587 return to_complex_expr(complex_imag_expr.op()).imag();
2588 }
2589
2590 return unchanged(expr);
2591}
2592
2595{
2596 // When one operand is zero, an overflow can only occur for a subtraction from
2597 // zero.
2598 if(
2599 expr.op1() == 0 ||
2600 (expr.op0() == 0 && !can_cast_expr<minus_overflow_exprt>(expr)))
2601 {
2602 return false_exprt{};
2603 }
2604
2605 // One is neutral element for multiplication
2606 if(
2608 (expr.op0() == 1 || expr.op1() == 1))
2609 {
2610 return false_exprt{};
2611 }
2612
2613 // we only handle the case of same operand types
2614 if(expr.op0().type() != expr.op1().type())
2615 return unchanged(expr);
2616
2617 // catch some cases over mathematical types
2618 const irep_idt &op_type_id = expr.op0().type().id();
2619 if(
2620 op_type_id == ID_integer || op_type_id == ID_rational ||
2621 op_type_id == ID_real)
2622 {
2623 return false_exprt{};
2624 }
2625
2626 if(op_type_id == ID_natural && !can_cast_expr<minus_overflow_exprt>(expr))
2627 return false_exprt{};
2628
2629 // we only handle constants over signedbv/unsignedbv for the remaining cases
2630 if(op_type_id != ID_signedbv && op_type_id != ID_unsignedbv)
2631 return unchanged(expr);
2632
2633 if(!expr.op0().is_constant() || !expr.op1().is_constant())
2634 return unchanged(expr);
2635
2636 const auto op0_value = numeric_cast<mp_integer>(expr.op0());
2637 const auto op1_value = numeric_cast<mp_integer>(expr.op1());
2638 if(!op0_value.has_value() || !op1_value.has_value())
2639 return unchanged(expr);
2640
2641 mp_integer no_overflow_result;
2643 no_overflow_result = *op0_value + *op1_value;
2645 no_overflow_result = *op0_value - *op1_value;
2647 no_overflow_result = *op0_value * *op1_value;
2649 no_overflow_result = *op0_value << *op1_value;
2650 else
2652
2653 const std::size_t width = to_bitvector_type(expr.op0().type()).get_width();
2654 const integer_bitvector_typet bv_type{op_type_id, width};
2655 if(
2656 no_overflow_result < bv_type.smallest() ||
2657 no_overflow_result > bv_type.largest())
2658 {
2659 return true_exprt{};
2660 }
2661 else
2662 return false_exprt{};
2663}
2664
2667{
2668 // zero is a neutral element for all operations supported here
2669 if(expr.op() == 0)
2670 return false_exprt{};
2671
2672 // catch some cases over mathematical types
2673 const irep_idt &op_type_id = expr.op().type().id();
2674 if(
2675 op_type_id == ID_integer || op_type_id == ID_rational ||
2676 op_type_id == ID_real)
2677 {
2678 return false_exprt{};
2679 }
2680
2681 if(op_type_id == ID_natural)
2682 return true_exprt{};
2683
2684 // we only handle constants over signedbv/unsignedbv for the remaining cases
2685 if(op_type_id != ID_signedbv && op_type_id != ID_unsignedbv)
2686 return unchanged(expr);
2687
2688 if(!expr.op().is_constant())
2689 return unchanged(expr);
2690
2691 const auto op_value = numeric_cast<mp_integer>(expr.op());
2692 if(!op_value.has_value())
2693 return unchanged(expr);
2694
2695 mp_integer no_overflow_result;
2697 no_overflow_result = -*op_value;
2698 else
2700
2701 const std::size_t width = to_bitvector_type(expr.op().type()).get_width();
2702 const integer_bitvector_typet bv_type{op_type_id, width};
2703 if(
2704 no_overflow_result < bv_type.smallest() ||
2705 no_overflow_result > bv_type.largest())
2706 {
2707 return true_exprt{};
2708 }
2709 else
2710 return false_exprt{};
2711}
2712
2715{
2716 if(expr.id() == ID_overflow_result_unary_minus)
2717 {
2718 // zero is a neutral element
2719 if(expr.op0() == 0)
2720 return struct_exprt{{expr.op0(), false_exprt{}}, expr.type()};
2721
2722 // catch some cases over mathematical types
2723 const irep_idt &op_type_id = expr.op0().type().id();
2724 if(
2725 op_type_id == ID_integer || op_type_id == ID_rational ||
2726 op_type_id == ID_real)
2727 {
2728 return struct_exprt{{expr.op0(), false_exprt{}}, expr.type()};
2729 }
2730
2731 // always an overflow for natural numbers, but the result is not
2732 // representable
2733 if(op_type_id == ID_natural)
2734 return unchanged(expr);
2735
2736 // we only handle constants over signedbv/unsignedbv for the remaining cases
2737 if(op_type_id != ID_signedbv && op_type_id != ID_unsignedbv)
2738 return unchanged(expr);
2739
2740 if(!expr.op0().is_constant())
2741 return unchanged(expr);
2742
2743 const auto op_value = numeric_cast<mp_integer>(expr.op0());
2744 if(!op_value.has_value())
2745 return unchanged(expr);
2746
2747 mp_integer no_overflow_result = -*op_value;
2748
2749 const std::size_t width = to_bitvector_type(expr.op0().type()).get_width();
2750 const integer_bitvector_typet bv_type{op_type_id, width};
2751 if(
2752 no_overflow_result < bv_type.smallest() ||
2753 no_overflow_result > bv_type.largest())
2754 {
2755 return struct_exprt{
2756 {from_integer(no_overflow_result, expr.op0().type()), true_exprt{}},
2757 expr.type()};
2758 }
2759 else
2760 {
2761 return struct_exprt{
2762 {from_integer(no_overflow_result, expr.op0().type()), false_exprt{}},
2763 expr.type()};
2764 }
2765 }
2766 else
2767 {
2768 // When one operand is zero, an overflow can only occur for a subtraction
2769 // from zero.
2770 if(expr.op0() == 0)
2771 {
2772 if(
2773 expr.id() == ID_overflow_result_plus ||
2774 expr.id() == ID_overflow_result_shl)
2775 {
2776 return struct_exprt{{expr.op1(), false_exprt{}}, expr.type()};
2777 }
2778 else if(expr.id() == ID_overflow_result_mult)
2779 {
2780 return struct_exprt{
2781 {from_integer(0, expr.op0().type()), false_exprt{}}, expr.type()};
2782 }
2783 }
2784 else if(expr.op1() == 0)
2785 {
2786 if(
2787 expr.id() == ID_overflow_result_plus ||
2788 expr.id() == ID_overflow_result_minus ||
2789 expr.id() == ID_overflow_result_shl)
2790 {
2791 return struct_exprt{{expr.op0(), false_exprt{}}, expr.type()};
2792 }
2793 else
2794 {
2795 return struct_exprt{
2796 {from_integer(0, expr.op0().type()), false_exprt{}}, expr.type()};
2797 }
2798 }
2799
2800 // One is neutral element for multiplication
2801 if(
2802 expr.id() == ID_overflow_result_mult &&
2803 (expr.op0() == 1 || expr.op1() == 1))
2804 {
2805 return struct_exprt{
2806 {expr.op0() == 1 ? expr.op1() : expr.op0(), false_exprt{}},
2807 expr.type()};
2808 }
2809
2810 // we only handle the case of same operand types
2811 if(
2812 expr.id() != ID_overflow_result_shl &&
2813 expr.op0().type() != expr.op1().type())
2814 {
2815 return unchanged(expr);
2816 }
2817
2818 // catch some cases over mathematical types
2819 const irep_idt &op_type_id = expr.op0().type().id();
2820 if(
2821 expr.id() != ID_overflow_result_shl &&
2822 (op_type_id == ID_integer || op_type_id == ID_rational ||
2823 op_type_id == ID_real))
2824 {
2825 irep_idt id =
2826 expr.id() == ID_overflow_result_plus
2827 ? ID_plus
2828 : expr.id() == ID_overflow_result_minus ? ID_minus : ID_mult;
2829 return struct_exprt{
2830 {simplify_node(binary_exprt{expr.op0(), id, expr.op1()}),
2831 false_exprt{}},
2832 expr.type()};
2833 }
2834
2835 if(
2836 (expr.id() == ID_overflow_result_plus ||
2837 expr.id() == ID_overflow_result_mult) &&
2838 op_type_id == ID_natural)
2839 {
2840 return struct_exprt{
2842 expr.op0(),
2843 expr.id() == ID_overflow_result_plus ? ID_plus : ID_mult,
2844 expr.op1()}),
2845 false_exprt{}},
2846 expr.type()};
2847 }
2848
2849 // we only handle constants over signedbv/unsignedbv for the remaining cases
2850 if(op_type_id != ID_signedbv && op_type_id != ID_unsignedbv)
2851 return unchanged(expr);
2852
2853 // a special case of overflow-minus checking with operands (X + n) and X
2854 if(expr.id() == ID_overflow_result_minus)
2855 {
2856 const exprt &tc_op0 = skip_typecast(expr.op0());
2857 const exprt &tc_op1 = skip_typecast(expr.op1());
2858
2859 if(auto sum = expr_try_dynamic_cast<plus_exprt>(tc_op0))
2860 {
2861 if(skip_typecast(sum->op0()) == tc_op1 && sum->operands().size() == 2)
2862 {
2863 std::optional<exprt> offset;
2864 if(sum->type().id() == ID_pointer)
2865 {
2866 offset = std::move(simplify_pointer_offset(
2867 pointer_offset_exprt{*sum, expr.op0().type()})
2868 .expr);
2869 if(offset->id() == ID_pointer_offset)
2870 return unchanged(expr);
2871 }
2872 else
2873 offset = std::move(
2874 simplify_typecast(typecast_exprt{sum->op1(), expr.op0().type()})
2875 .expr);
2876
2877 exprt offset_op = skip_typecast(*offset);
2878 if(
2879 offset_op.type().id() != ID_signedbv &&
2880 offset_op.type().id() != ID_unsignedbv)
2881 {
2882 return unchanged(expr);
2883 }
2884
2885 const std::size_t width =
2886 to_bitvector_type(expr.op0().type()).get_width();
2887 const integer_bitvector_typet bv_type{op_type_id, width};
2888
2889 or_exprt not_representable{
2891 offset_op,
2892 ID_lt,
2893 from_integer(bv_type.smallest(), offset_op.type())},
2895 offset_op,
2896 ID_gt,
2897 from_integer(bv_type.largest(), offset_op.type())}};
2898
2899 return struct_exprt{
2900 {*offset, simplify_rec(not_representable)}, expr.type()};
2901 }
2902 }
2903 }
2904
2905 if(!expr.op0().is_constant() || !expr.op1().is_constant())
2906 return unchanged(expr);
2907
2908 // preserve the sizeof type annotation
2909 std::optional<typet> c_sizeof_type;
2910 for(const auto &op : expr.operands())
2911 {
2912 const typet &sizeof_type =
2913 static_cast<const typet &>(op.find(ID_C_c_sizeof_type));
2914 if(sizeof_type.is_not_nil())
2915 {
2916 c_sizeof_type = sizeof_type;
2917 break;
2918 }
2919 }
2920
2921 const auto op0_value = numeric_cast<mp_integer>(expr.op0());
2922 const auto op1_value = numeric_cast<mp_integer>(expr.op1());
2923 if(!op0_value.has_value() || !op1_value.has_value())
2924 return unchanged(expr);
2925
2926 mp_integer no_overflow_result;
2927 if(expr.id() == ID_overflow_result_plus)
2928 no_overflow_result = *op0_value + *op1_value;
2929 else if(expr.id() == ID_overflow_result_minus)
2930 no_overflow_result = *op0_value - *op1_value;
2931 else if(expr.id() == ID_overflow_result_mult)
2932 no_overflow_result = *op0_value * *op1_value;
2933 else if(expr.id() == ID_overflow_result_shl)
2934 no_overflow_result = *op0_value << *op1_value;
2935 else
2937
2938 exprt no_overflow_result_expr =
2939 from_integer(no_overflow_result, expr.op0().type());
2940 if(c_sizeof_type.has_value())
2941 no_overflow_result_expr.set(ID_C_c_sizeof_type, *c_sizeof_type);
2942
2943 const std::size_t width = to_bitvector_type(expr.op0().type()).get_width();
2944 const integer_bitvector_typet bv_type{op_type_id, width};
2945 if(
2946 no_overflow_result < bv_type.smallest() ||
2947 no_overflow_result > bv_type.largest())
2948 {
2949 return struct_exprt{
2950 {std::move(no_overflow_result_expr), true_exprt{}}, expr.type()};
2951 }
2952 else
2953 {
2954 return struct_exprt{
2955 {std::move(no_overflow_result_expr), false_exprt{}}, expr.type()};
2956 }
2957 }
2958}
2959
2962{
2963 auto result = unchanged(expr);
2964
2965 // The ifs below could one day be replaced by a switch()
2966
2967 if(expr.id()==ID_address_of)
2968 {
2969 // the argument of this expression needs special treatment
2970 }
2971 else if(expr.id()==ID_if)
2972 {
2973 result = simplify_if_preorder(to_if_expr(expr));
2974 }
2975 else if(expr.id() == ID_typecast)
2976 {
2978 }
2979 else if(
2980 expr.id() == ID_byte_extract_little_endian ||
2981 expr.id() == ID_byte_extract_big_endian)
2982 {
2984 }
2985 else if(expr.id() == ID_dereference)
2986 {
2988 }
2989 else if(expr.id() == ID_index)
2990 {
2991 result = simplify_index_preorder(to_index_expr(expr));
2992 }
2993 else if(expr.id() == ID_member)
2994 {
2996 }
2997 else if(
2998 expr.id() == ID_is_dynamic_object || expr.id() == ID_is_invalid_pointer ||
2999 expr.id() == ID_object_size || expr.id() == ID_pointer_object ||
3000 expr.id() == ID_pointer_offset)
3001 {
3003 }
3004 else if(expr.has_operands())
3005 {
3006 std::optional<exprt::operandst> new_operands;
3007
3008 for(std::size_t i = 0; i < expr.operands().size(); ++i)
3009 {
3010 auto r_it = simplify_rec(expr.operands()[i]); // recursive call
3011 if(r_it.has_changed())
3012 {
3013 if(!new_operands.has_value())
3014 new_operands = expr.operands();
3015 (*new_operands)[i] = std::move(r_it.expr);
3016 }
3017 }
3018
3019 if(new_operands.has_value())
3020 {
3021 std::swap(result.expr.operands(), *new_operands);
3022 result.expr_changed = resultt<>::CHANGED;
3023 }
3024 }
3025
3026 if(as_const(result.expr).type().id() == ID_array)
3027 {
3028 const array_typet &array_type = to_array_type(as_const(result.expr).type());
3029 resultt<> simp_size = simplify_rec(array_type.size());
3030 if(simp_size.has_changed())
3031 {
3032 to_array_type(result.expr.type()).size() = simp_size.expr;
3033 result.expr_changed = resultt<>::CHANGED;
3034 }
3035 }
3036
3037 return result;
3038}
3039
3041{
3042 if(!node.has_operands())
3043 return unchanged(node); // no change
3044
3045 // #define DEBUGX
3046
3047#ifdef DEBUGX
3048 exprt old(node);
3049#endif
3050
3051 exprt expr = node;
3052 bool no_change_join_operands = join_operands(expr);
3053
3054 resultt<> r = unchanged(expr);
3055
3056 if(expr.id()==ID_typecast)
3057 {
3059 }
3060 else if(expr.id()==ID_equal || expr.id()==ID_notequal ||
3061 expr.id()==ID_gt || expr.id()==ID_lt ||
3062 expr.id()==ID_ge || expr.id()==ID_le)
3063 {
3065 }
3066 else if(expr.id()==ID_if)
3067 {
3068 r = simplify_if(to_if_expr(expr));
3069 }
3070 else if(expr.id()==ID_lambda)
3071 {
3073 }
3074 else if(expr.id()==ID_with)
3075 {
3076 r = simplify_with(to_with_expr(expr));
3077 }
3078 else if(expr.id()==ID_update)
3079 {
3081 }
3082 else if(expr.id()==ID_index)
3083 {
3085 }
3086 else if(expr.id()==ID_member)
3087 {
3089 }
3090 else if(expr.id()==ID_byte_update_little_endian ||
3091 expr.id()==ID_byte_update_big_endian)
3092 {
3094 }
3095 else if(expr.id()==ID_byte_extract_little_endian ||
3096 expr.id()==ID_byte_extract_big_endian)
3097 {
3099 }
3100 else if(expr.id()==ID_pointer_object)
3101 {
3103 }
3104 else if(expr.id() == ID_is_dynamic_object)
3105 {
3107 }
3108 else if(expr.id() == ID_is_invalid_pointer)
3109 {
3111 }
3112 else if(
3114 {
3116 }
3117 else if(expr.id()==ID_div)
3118 {
3119 r = simplify_div(to_div_expr(expr));
3120 }
3121 else if(expr.id()==ID_mod)
3122 {
3123 r = simplify_mod(to_mod_expr(expr));
3124 }
3125 else if(expr.id()==ID_bitnot)
3126 {
3128 }
3129 else if(
3130 expr.id() == ID_bitand || expr.id() == ID_bitor || expr.id() == ID_bitxor ||
3131 expr.id() == ID_bitxnor)
3132 {
3134 }
3135 else if(expr.id()==ID_ashr || expr.id()==ID_lshr || expr.id()==ID_shl)
3136 {
3138 }
3139 else if(expr.id()==ID_power)
3140 {
3142 }
3143 else if(expr.id()==ID_plus)
3144 {
3145 r = simplify_plus(to_plus_expr(expr));
3146 }
3147 else if(expr.id()==ID_minus)
3148 {
3150 }
3151 else if(expr.id()==ID_mult)
3152 {
3153 r = simplify_mult(to_mult_expr(expr));
3154 }
3155 else if(expr.id()==ID_floatbv_plus ||
3156 expr.id()==ID_floatbv_minus ||
3157 expr.id()==ID_floatbv_mult ||
3158 expr.id()==ID_floatbv_div)
3159 {
3161 }
3162 else if(expr.id() == ID_floatbv_round_to_integral)
3163 {
3166 }
3167 else if(expr.id()==ID_floatbv_typecast)
3168 {
3170 }
3171 else if(expr.id()==ID_unary_minus)
3172 {
3174 }
3175 else if(expr.id()==ID_unary_plus)
3176 {
3178 }
3179 else if(expr.id()==ID_not)
3180 {
3181 r = simplify_not(to_not_expr(expr));
3182 }
3183 else if(expr.id()==ID_implies ||
3184 expr.id()==ID_or || expr.id()==ID_xor ||
3185 expr.id()==ID_and)
3186 {
3187 r = simplify_boolean(expr);
3188 }
3189 else if(expr.id()==ID_dereference)
3190 {
3192 }
3193 else if(expr.id()==ID_address_of)
3194 {
3196 }
3197 else if(expr.id()==ID_pointer_offset)
3198 {
3200 }
3201 else if(expr.id()==ID_extractbit)
3202 {
3204 }
3205 else if(expr.id()==ID_concatenation)
3206 {
3208 }
3209 else if(expr.id()==ID_extractbits)
3210 {
3212 }
3213 else if(expr.id() == ID_zero_extend)
3214 {
3216 }
3217 else if(expr.id()==ID_ieee_float_equal ||
3218 expr.id()==ID_ieee_float_notequal)
3219 {
3221 }
3222 else if(expr.id() == ID_bswap)
3223 {
3225 }
3226 else if(expr.id()==ID_isinf)
3227 {
3229 }
3230 else if(expr.id()==ID_isnan)
3231 {
3233 }
3234 else if(expr.id()==ID_isnormal)
3235 {
3237 }
3238 else if(expr.id()==ID_abs)
3239 {
3240 r = simplify_abs(to_abs_expr(expr));
3241 }
3242 else if(expr.id()==ID_sign)
3243 {
3244 r = simplify_sign(to_sign_expr(expr));
3245 }
3246 else if(expr.id() == ID_popcount)
3247 {
3249 }
3250 else if(expr.id() == ID_count_leading_zeros)
3251 {
3253 }
3254 else if(expr.id() == ID_count_trailing_zeros)
3255 {
3257 }
3258 else if(expr.id() == ID_find_first_set)
3259 {
3261 }
3262 else if(expr.id() == ID_function_application)
3263 {
3265 }
3266 else if(expr.id() == ID_complex_real || expr.id() == ID_complex_imag)
3267 {
3269 }
3270 else if(
3271 const auto binary_overflow =
3273 {
3274 r = simplify_overflow_binary(*binary_overflow);
3275 }
3276 else if(
3277 const auto unary_overflow =
3279 {
3280 r = simplify_overflow_unary(*unary_overflow);
3281 }
3282 else if(
3283 const auto overflow_result =
3285 {
3286 r = simplify_overflow_result(*overflow_result);
3287 }
3288 else if(expr.id() == ID_bitreverse)
3289 {
3291 }
3292 else if(
3293 const auto prophecy_r_or_w_ok =
3295 {
3296 r = simplify_prophecy_r_or_w_ok(*prophecy_r_or_w_ok);
3297 }
3298 else if(
3299 const auto prophecy_pointer_in_range =
3301 {
3302 r = simplify_prophecy_pointer_in_range(*prophecy_pointer_in_range);
3303 }
3304 else if(expr.id() == ID_exists || expr.id() == ID_forall)
3305 {
3307 }
3308
3309 if(!no_change_join_operands)
3310 r = changed(r);
3311
3312#ifdef DEBUGX
3313 if(
3314 r.has_changed()
3315# ifdef DEBUG_ON_DEMAND
3316 && debug_on
3317# endif
3318 )
3319 {
3320 std::cout << "===== " << node.id() << ": " << format(node) << '\n'
3321 << " ---> " << format(r.expr) << '\n';
3322 }
3323#endif
3324
3325 return r;
3326}
3327
3329{
3330 // look up in cache
3331
3332 #ifdef USE_CACHE
3333 std::pair<simplify_expr_cachet::containert::iterator, bool>
3334 cache_result=simplify_expr_cache.container().
3335 insert(std::pair<exprt, exprt>(expr, exprt()));
3336
3337 if(!cache_result.second) // found!
3338 {
3339 const exprt &new_expr=cache_result.first->second;
3340
3341 if(new_expr.id().empty())
3342 return true; // no change
3343
3344 expr=new_expr;
3345 return false;
3346 }
3347 #endif
3348
3349 // We work on a copy to prevent unnecessary destruction of sharing.
3350 auto simplify_node_preorder_result = simplify_node_preorder(expr);
3351
3352 auto simplify_node_result = simplify_node(simplify_node_preorder_result.expr);
3353
3354 if(
3355 !simplify_node_result.has_changed() &&
3356 simplify_node_preorder_result.has_changed())
3357 {
3358 simplify_node_result.expr_changed =
3359 simplify_node_preorder_result.expr_changed;
3360 }
3361
3362#ifdef USE_LOCAL_REPLACE_MAP
3363 exprt tmp = simplify_node_result.expr;
3364# if 1
3365 replace_mapt::const_iterator it =
3366 local_replace_map.find(simplify_node_result.expr);
3367 if(it!=local_replace_map.end())
3368 simplify_node_result = changed(it->second);
3369# else
3370 if(
3371 !local_replace_map.empty() &&
3372 !replace_expr(local_replace_map, simplify_node_result.expr))
3373 {
3374 simplify_node_result = changed(simplify_rec(simplify_node_result.expr));
3375 }
3376# endif
3377#endif
3378
3379 if(!simplify_node_result.has_changed())
3380 {
3381 return unchanged(expr);
3382 }
3383 else
3384 {
3386 (as_const(simplify_node_result.expr).type().id() == ID_array &&
3387 expr.type().id() == ID_array) ||
3388 as_const(simplify_node_result.expr).type() == expr.type(),
3389 simplify_node_result.expr.pretty(),
3390 expr.pretty());
3391
3392#ifdef USE_CACHE
3393 // save in cache
3394 cache_result.first->second = simplify_node_result.expr;
3395#endif
3396
3397 return simplify_node_result;
3398 }
3399}
3400
3403{
3404#ifdef DEBUG_ON_DEMAND
3405 if(debug_on)
3406 std::cout << "TO-SIMP " << format(expr) << "\n";
3407#endif
3408 auto result = simplify_rec(expr);
3409#ifdef DEBUG_ON_DEMAND
3410 if(debug_on)
3411 std::cout << "FULLSIMP " << format(result.expr) << "\n";
3412#endif
3413 if(result.has_changed())
3414 {
3415 expr = result.expr;
3416 return false; // change
3417 }
3418 else
3419 return true; // no change
3420}
3421
3423bool simplify(exprt &expr, const namespacet &ns)
3424{
3425 return simplify_exprt(ns).simplify(expr);
3426}
3427
3429{
3430 simplify_exprt(ns).simplify(src);
3431 return src;
3432}
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)
bool to_integer(const constant_exprt &expr, mp_integer &int_value)
Convert a constant expression expr to an arbitrary-precision integer.
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.
Target numeric_cast_v(const mp_integer &arg)
Convert an mp_integer to integral type Target An invariant will fail if the conversion is not possibl...
std::optional< Target > numeric_cast(const exprt &arg)
Converts an expression to any integral type.
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.
const shift_exprt & to_shift_expr(const exprt &expr)
Cast an exprt to a shift_exprt.
const popcount_exprt & to_popcount_expr(const exprt &expr)
Cast an exprt to a popcount_exprt.
const extractbits_exprt & to_extractbits_expr(const exprt &expr)
Cast an exprt to an extractbits_exprt.
const find_first_set_exprt & to_find_first_set_expr(const exprt &expr)
Cast an exprt to a find_first_set_exprt.
const bitnot_exprt & to_bitnot_expr(const exprt &expr)
Cast an exprt to a bitnot_exprt.
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 bitreverse_exprt & to_bitreverse_expr(const exprt &expr)
Cast an exprt to a bitreverse_exprt.
const extractbit_exprt & to_extractbit_expr(const exprt &expr)
Cast an exprt to an extractbit_exprt.
const concatenation_exprt & to_concatenation_expr(const exprt &expr)
Cast an exprt to a concatenation_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.
const bv_typet & to_bv_type(const typet &type)
Cast a typet to a bv_typet.
const fixedbv_typet & to_fixedbv_type(const typet &type)
Cast a typet to a fixedbv_typet.
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
const floatbv_typet & to_floatbv_type(const typet &type)
Cast a typet to a floatbv_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:176
Expression classes for byte-level operators.
const byte_update_exprt & to_byte_update_expr(const exprt &expr)
exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
Rewrite a byte extract expression to more fundamental operations.
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
int16_t s2
int8_t s1
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 c_enum_tag_typet & to_c_enum_tag_type(const typet &type)
Cast a typet to a c_enum_tag_typet.
Definition c_types.h:377
const union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Definition c_types.h:184
const union_tag_typet & to_union_tag_type(const typet &type)
Cast a typet to a union_tag_typet.
Definition c_types.h:224
Absolute value.
Definition std_expr.h:440
Operator to return the address of an object.
Array constructor from list of elements.
Definition std_expr.h:1570
exprt & what()
Definition std_expr.h:1529
Arrays with given size.
Definition std_types.h:806
const exprt & size() const
Definition std_types.h:839
const typet & element_type() const
The type of the elements of the array.
Definition std_types.h:826
A base class for binary expressions.
Definition std_expr.h:649
exprt & op0()
Definition expr.h:134
exprt & op1()
Definition expr.h:137
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:784
std::size_t get_width() const
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 & offset() const
void set_offset(exprt e)
const exprt & op() const
void set_op(exprt e)
std::size_t get_bits_per_byte() const
const exprt & value() 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:87
exprt real()
Definition std_expr.h:1870
exprt imag()
Definition std_expr.h:1880
A constant literal expression.
Definition std_expr.h:3007
const irep_idt & get_value() const
Definition std_expr.h:3015
void set_value(const irep_idt &value)
Definition std_expr.h:3020
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.
bool empty() const
Definition dstring.h:101
Union constructor to support unions without any member (a GCC/Clang feature).
Definition std_expr.h:1783
Base class for all expressions.
Definition expr.h:57
std::vector< exprt > operandst
Definition expr.h:59
bool has_operands() const
Return true if there is at least one operand.
Definition expr.h:92
exprt & op0()
Definition expr.h:134
exprt & op1()
Definition expr.h:137
bool is_constant() const
Return whether the expression is a constant.
Definition expr.h:213
typet & type()
Return the type of the expression.
Definition expr.h:85
operandst & operands()
Definition expr.h:95
const source_locationt & source_location() const
Definition expr.h:236
source_locationt & add_source_location()
Definition expr.h:241
void add_to_operands(const exprt &expr)
Add the given argument to the end of exprt's operands.
Definition expr.h:171
Extracts a sub-range of a bit-vector operand.
The Boolean constant false.
Definition std_expr.h:3135
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
const mp_integer & get_value() const
Definition fixedbv.h:95
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.
An IEEE 754 floating-point value, including specificiation.
Definition ieee_float.h:117
void set_sign(bool _sign)
Definition ieee_float.h:160
ieee_float_spect spec
Definition ieee_float.h:119
constant_exprt to_expr() const
mp_integer pack() const
bool get_sign() const
Definition ieee_float.h:254
mp_integer to_integer() const
Convert to an integer, always rounding towards zero (truncation), i.e.
void unpack(const mp_integer &)
An IEEE 754 value plus a rounding mode, enabling operations with rounding on values.
Definition ieee_float.h:369
void from_integer(const mp_integer &i)
void change_spec(const ieee_float_spect &dest_spec)
The trinary if-then-else operator.
Definition std_expr.h:2426
exprt & false_case()
Definition std_expr.h:2463
exprt & true_case()
Definition std_expr.h:2453
Array index operator.
Definition std_expr.h:1431
exprt & index()
Definition std_expr.h:1471
exprt & array()
Definition std_expr.h:1461
Fixed-width bit-vector representing a signed or unsigned integer.
mp_integer largest() const
Return the largest value that can be represented using this type.
mp_integer smallest() const
Return the smallest value that can be represented using this type.
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:414
bool is_not_nil() const
Definition irep.h:374
void make_nil()
Definition irep.h:448
void swap(irept &irep)
Definition irep.h:436
const irep_idt & id() const
Definition irep.h:390
bool is_nil() const
Definition irep.h:370
A (mathematical) lambda expression.
exprt application(const operandst &arguments) const
Extract member of struct or union.
Definition std_expr.h:2866
Binary multiplication Associativity is not specified.
Definition std_expr.h:1104
exprt & op1()
Definition std_expr.h:942
exprt & op0()
Definition std_expr.h:936
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
The NIL expression.
Definition std_expr.h:3144
The null pointer constant.
Boolean OR All operands must be boolean, and the result is always boolean.
Definition std_expr.h:2193
An expression returning both the result of the arithmetic operation under wrap-around semantics as we...
exprt & op0()
Definition expr.h:134
exprt & op1()
Definition expr.h:137
The plus expression Associativity is not specified.
Definition std_expr.h:1006
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
const exprt & content() const
Sign of an expression Predicate is true if _op is negative, false otherwise.
Definition std_expr.h:612
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_quantifier_expr(const quantifier_exprt &)
Try to simplify exists/forall to a constant expression.
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 &)
virtual 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 &)
virtual 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 &)
resultt simplify_floatbv_round_to_integral(const floatbv_round_to_integral_exprt &)
Struct constructor from list of elements.
Definition std_expr.h:1820
Structure type, corresponds to C style structs.
Definition std_types.h:230
const componentst & components() const
Definition std_types.h:146
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:156
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:139
void identifier(const irep_idt &identifier)
Definition std_expr.h:160
The Boolean constant true.
Definition std_expr.h:3126
const typet & subtype() const
Definition type.h:187
Semantic type conversion.
Definition std_expr.h:1995
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition std_expr.h:2003
The type of an expression, extends irept.
Definition type.h:29
Generic base class for unary expressions.
Definition std_expr.h:364
const exprt & op() const
Definition std_expr.h:394
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:1724
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:2679
exprt & old()
Definition std_expr.h:2691
exprt::operandst & designator()
Definition std_expr.h:2705
exprt & new_value()
Definition std_expr.h:2715
Operator to update elements in structs and arrays.
Definition std_expr.h:2520
exprt & new_value()
Definition std_expr.h:2550
exprt & where()
Definition std_expr.h:2540
exprt & old()
Definition std_expr.h:2530
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:28
auto expr_checked_cast(TExpr &base) -> typename detail::expr_dynamic_cast_return_typet< T, TExpr >::type
Cast a reference to a generic exprt to a specific derived class.
Definition expr_cast.h:227
bool can_cast_expr(const exprt &base)
Check whether a reference to a generic exprt is of a specific derived class.
auto type_try_dynamic_cast(TType &base) -> typename detail::expr_try_dynamic_cast_return_typet< T, TType >::type
Try to cast a reference to a generic typet to a specific derived class.
Definition expr_cast.h:135
bool can_cast_type(const typet &base)
Check whether a reference to a generic typet is of a specific derived class.
auto expr_try_dynamic_cast(TExpr &base) -> typename detail::expr_try_dynamic_cast_return_typet< T, TExpr >::type
Try to cast a reference to a generic exprt to a specific derived class.
Definition expr_cast.h:81
constant_exprt make_boolean_expr(bool value)
returns true_exprt if given true and false_exprt otherwise
exprt is_not_zero(const exprt &src, const namespacet &ns)
converts a scalar/float expression to C/C++ Booleans
Definition expr_util.cpp:69
const exprt & skip_typecast(const exprt &expr)
find the expression nested inside typecasts, if any
if_exprt lift_if(const exprt &src, std::size_t operand_number)
lift up an if_exprt one level
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
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.
const floatbv_round_to_integral_exprt & to_floatbv_round_to_integral_expr(const exprt &expr)
Cast an exprt to a floatbv_round_to_integral_exprt.
const floatbv_typecast_exprt & to_floatbv_typecast_expr(const exprt &expr)
Cast an exprt to a floatbv_typecast_exprt.
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 quantifier_exprt & to_quantifier_expr(const exprt &expr)
Cast an exprt to a quantifier_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 lambda_exprt & to_lambda_expr(const exprt &expr)
Cast an exprt to a lambda_exprt.
const mp_integer string2integer(const std::string &n, unsigned base)
Definition mp_arith.cpp:54
API to expression classes for Pointers.
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
const pointer_offset_exprt & to_pointer_offset_expr(const exprt &expr)
Cast an exprt to a pointer_offset_exprt.
const pointer_object_exprt & to_pointer_object_expr(const exprt &expr)
Cast an exprt to a pointer_object_exprt.
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.
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< 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 > member_offset_expr(const member_exprt &member_expr, const namespacet &ns)
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)
const std::size_t sharing_mapt< keyT, valueT, fail_if_equal, hashT, equalT >::bits
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< exprt > bits2expr(const std::string &bits, const typet &type, bool little_endian, const namespacet &ns)
std::optional< std::string > expr2bits(const exprt &expr, bool little_endian, const namespacet &ns)
std::optional< std::reference_wrapper< const array_exprt > > try_get_string_data_array(const exprt &content, const namespacet &ns)
Get char sequence from content field of a refined string expression.
bool join_operands(exprt &expr)
BigInt mp_integer
Definition smt_terms.h:17
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#define 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:291
API to expression classes.
const struct_exprt & to_struct_expr(const exprt &expr)
Cast an exprt to a struct_exprt.
Definition std_expr.h:1843
const array_of_exprt & to_array_of_expr(const exprt &expr)
Cast an exprt to an array_of_exprt.
Definition std_expr.h:1552
const binary_relation_exprt & to_binary_relation_expr(const exprt &expr)
Cast an exprt to a binary_relation_exprt.
Definition std_expr.h:828
const unary_plus_exprt & to_unary_plus_expr(const exprt &expr)
Cast an exprt to a unary_plus_exprt.
Definition std_expr.h:539
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1494
const mod_exprt & to_mod_expr(const exprt &expr)
Cast an exprt to a mod_exprt.
Definition std_expr.h:1260
const mult_exprt & to_mult_expr(const exprt &expr)
Cast an exprt to a mult_exprt.
Definition std_expr.h:1134
const array_exprt & to_array_expr(const exprt &expr)
Cast an exprt to an array_exprt.
Definition std_expr.h:1614
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2024
const div_exprt & to_div_expr(const exprt &expr)
Cast an exprt to a div_exprt.
Definition std_expr.h:1196
const plus_exprt & to_plus_expr(const exprt &expr)
Cast an exprt to a plus_exprt.
Definition std_expr.h:1045
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition std_expr.h:424
const multi_ary_exprt & to_multi_ary_expr(const exprt &expr)
Cast an exprt to a multi_ary_exprt.
Definition std_expr.h:991
const abs_exprt & to_abs_expr(const exprt &expr)
Cast an exprt to a abs_exprt.
Definition std_expr.h:459
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition std_expr.h:2501
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:2953
const minus_exprt & to_minus_expr(const exprt &expr)
Cast an exprt to a minus_exprt.
Definition std_expr.h:1085
const complex_imag_exprt & to_complex_imag_expr(const exprt &expr)
Cast an exprt to a complex_imag_exprt.
Definition std_expr.h:1977
const index_designatort & to_index_designator(const exprt &expr)
Cast an exprt to an index_designatort.
Definition std_expr.h:2619
const complex_real_exprt & to_complex_real_expr(const exprt &expr)
Cast an exprt to a complex_real_exprt.
Definition std_expr.h:1940
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3078
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
Definition std_expr.h:2408
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:221
const with_exprt & to_with_expr(const exprt &expr)
Cast an exprt to a with_exprt.
Definition std_expr.h:2573
const complex_exprt & to_complex_expr(const exprt &expr)
Cast an exprt to a complex_exprt.
Definition std_expr.h:1903
const update_exprt & to_update_expr(const exprt &expr)
Cast an exprt to an update_exprt.
Definition std_expr.h:2762
const unary_minus_exprt & to_unary_minus_expr(const exprt &expr)
Cast an exprt to a unary_minus_exprt.
Definition std_expr.h:502
const sign_exprt & to_sign_expr(const exprt &expr)
Cast an exprt to a sign_exprt.
Definition std_expr.h:632
bool is_constant(const typet &type)
This method tests, if the given typet is a constant.
Definition std_types.h:28
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition std_types.h:307
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition std_types.h:517
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition std_types.h:887
String expressions for the string solver.
refined_string_exprt & to_string_expr(exprt &expr)
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:186
dstringt irep_idt