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