CBMC
Loading...
Searching...
No Matches
simplify_expr.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module:
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
9#include "simplify_expr.h"
10
11#include <algorithm>
12
13#include "bitvector_expr.h"
14#include "byte_operators.h"
15#include "c_types.h"
16#include "config.h"
17#include "expr_util.h"
18#include "fixedbv.h"
19#include "floatbv_expr.h"
20#include "invariant.h"
21#include "mathematical_expr.h"
22#include "namespace.h"
23#include "pointer_expr.h"
24#include "pointer_offset_size.h"
25#include "pointer_offset_sum.h"
26#include "rational.h"
27#include "rational_tools.h"
28#include "simplify_utils.h"
29#include "std_expr.h"
30#include "string_expr.h"
31
32// #define DEBUGX
33
34#ifdef DEBUGX
35#include "format_expr.h"
36#include <iostream>
37#endif
38
39#include "simplify_expr_class.h"
40
41// #define USE_CACHE
42
43#ifdef USE_CACHE
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
55
56 containert &container()
57 {
58 return container_normal;
59 }
60};
61
63#endif
64
66{
67 if(expr.op().is_constant())
68 {
69 const typet &type = to_unary_expr(expr).op().type();
70
71 if(type.id()==ID_floatbv)
72 {
74 value.set_sign(false);
75 return value.to_expr();
76 }
77 else if(type.id()==ID_signedbv ||
78 type.id()==ID_unsignedbv)
79 {
80 auto value = numeric_cast<mp_integer>(to_unary_expr(expr).op());
81 if(value.has_value())
82 {
83 if(*value >= 0)
84 {
85 return to_unary_expr(expr).op();
86 }
87 else
88 {
89 value->negate();
90 return from_integer(*value, type);
91 }
92 }
93 }
94 }
95
96 return unchanged(expr);
97}
98
100{
101 if(expr.op().is_constant())
102 {
103 const typet &type = expr.op().type();
104
105 if(type.id()==ID_floatbv)
106 {
108 return make_boolean_expr(value.get_sign());
109 }
110 else if(type.id()==ID_signedbv ||
111 type.id()==ID_unsignedbv)
112 {
113 const auto value = numeric_cast<mp_integer>(expr.op());
114 if(value.has_value())
115 {
116 return make_boolean_expr(*value >= 0);
117 }
118 }
119 }
120
121 return unchanged(expr);
122}
123
126{
127 const exprt &op = expr.op();
128
129 if(op.is_constant())
130 {
131 const typet &op_type = op.type();
132
133 if(op_type.id() == ID_signedbv || op_type.id() == ID_unsignedbv)
134 {
135 const auto width = to_bitvector_type(op_type).get_width();
136 const auto &value = to_constant_expr(op).get_value();
137 std::size_t result = 0;
138
139 for(std::size_t i = 0; i < width; i++)
140 if(get_bvrep_bit(value, width, i))
141 result++;
142
143 return from_integer(result, expr.type());
144 }
145 }
146
147 return unchanged(expr);
148}
149
152{
153 const bool is_little_endian =
155
156 const auto const_bits_opt = expr2bits(expr.op(), is_little_endian, ns);
157
158 if(!const_bits_opt.has_value())
159 return unchanged(expr);
160
161 std::size_t n_leading_zeros =
162 is_little_endian ? const_bits_opt->rfind('1') : const_bits_opt->find('1');
163 if(n_leading_zeros == std::string::npos)
164 {
165 if(!expr.zero_permitted())
166 return unchanged(expr);
167
169 }
170 else if(is_little_endian)
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
195 }
196 else if(!is_little_endian)
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)
219 else
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 =
269
270 if(!first_value_opt)
271 {
272 return simplify_exprt::unchanged(expr);
273 }
274
276
277 const auto second_value_opt =
279
281 {
282 return simplify_exprt::unchanged(expr);
283 }
284
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{
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 =
395
396 // Negative indices are treated like 0
397 if(idx > 0)
398 {
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();
416 {
417 return from_integer(-1, expr.type());
418 }
419
420 unsigned long starting_offset =
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(
445 : 0,
446 expr.type());
447
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));
479
480 auto pred = [&](const exprt &c2) {
482
483 return c1_val == c2_val;
484 };
485
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 {
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))
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 =
601
602 if(!first_value_opt)
603 {
604 return simplify_exprt::unchanged(expr);
605 }
606
608
609 const auto second_value_opt =
611
613 {
614 return simplify_exprt::unchanged(expr);
615 }
616
618
619 // Just lower-case both expressions.
620 if(
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 =
646
647 if(!first_value_opt)
648 {
649 return simplify_exprt::unchanged(expr);
650 }
651
653
654 const auto second_value_opt =
656
658 {
659 return simplify_exprt::unchanged(expr);
660 }
661
663
665 if(expr.arguments().size() == 3)
666 {
667 auto &offset = expr.arguments()[2];
668 if(!offset.is_constant())
669 return simplify_exprt::unchanged(expr);
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
717 {
718 return simplify_string_startswith(expr, ns);
719 }
721 {
722 return simplify_string_endswith(expr, ns);
723 }
725 {
726 return simplify_string_is_empty(expr, ns);
727 }
729 {
730 return simplify_string_compare_to(expr, ns);
731 }
733 {
734 return simplify_string_index_of(expr, ns, false);
735 }
737 {
738 return simplify_string_char_at(expr, ns);
739 }
741 {
742 return simplify_string_contains(expr, ns);
743 }
745 {
746 return simplify_string_index_of(expr, ns, true);
747 }
749 {
751 }
752
753 return unchanged(expr);
754}
755
758{
759 const typet &expr_type = expr.type();
760 const typet &op_type = expr.op().type();
761
762 // eliminate casts of infinity
763 if(expr.op().id() == ID_infinity)
764 {
765 typet new_type=expr.type();
766 exprt tmp = expr.op();
767 tmp.type()=new_type;
768 return std::move(tmp);
769 }
770
771 // casts from NULL to any integer
772 if(
773 op_type.id() == ID_pointer && expr.op().is_constant() &&
774 to_constant_expr(expr.op()).get_value() == ID_NULL &&
775 (expr_type.id() == ID_unsignedbv || expr_type.id() == ID_signedbv) &&
776 config.ansi_c.NULL_is_zero)
777 {
778 return from_integer(0, expr_type);
779 }
780
781 // casts from 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
807 expr.op(),
810 inequality.add_source_location()=expr.source_location();
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) ||
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() == 0 && 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(
898 config.ansi_c.NULL_is_zero &&
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() == 0) ||
908 (op_plus_expr.op0().is_constant() &&
909 to_constant_expr(op_plus_expr.op0()).is_null_pointer()))
910 {
911 auto sub_size =
913 if(sub_size.has_value())
914 {
915 auto new_expr = expr;
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(
926 }
927
928 return changed(simplify_typecast(new_expr)); // rec. call
929 }
930 }
931 }
932
933 // Push a numerical typecast into various integer operations, i.e.,
934 // (T)(x OP y) ---> (T)x OP (T)y
935 //
936 // Doesn't work for many, e.g., pointer difference, floating-point,
937 // division, modulo.
938 // Many operations fail if the width of T
939 // is bigger than that of (x OP y). This includes ID_bitnot and
940 // anything that might overflow, e.g., ID_plus.
941 //
942 if((expr_type.id()==ID_signedbv || expr_type.id()==ID_unsignedbv) &&
943 (op_type.id()==ID_signedbv || op_type.id()==ID_unsignedbv))
944 {
945 bool enlarge=
946 to_bitvector_type(expr_type).get_width()>
947 to_bitvector_type(op_type).get_width();
948
949 if(!enlarge)
950 {
951 irep_idt op_id = expr.op().id();
952
953 if(
954 op_id == ID_plus || op_id == ID_minus || op_id == ID_mult ||
955 op_id == ID_unary_minus || op_id == ID_bitxor || op_id == ID_bitxnor ||
956 op_id == ID_bitor || op_id == ID_bitand)
957 {
958 exprt result = expr.op();
959
960 if(
961 result.operands().size() >= 1 &&
962 to_multi_ary_expr(result).op0().type() == result.type())
963 {
964 result.type()=expr.type();
965
966 Forall_operands(it, result)
967 {
968 auto new_operand = typecast_exprt(*it, expr.type());
969 *it = simplify_typecast(new_operand); // recursive call
970 }
971
972 return changed(simplify_node(result)); // possibly recursive call
973 }
974 }
975 else if(op_id==ID_ashr || op_id==ID_lshr || op_id==ID_shl)
976 {
977 }
978 }
979 }
980
981 // Push a numerical typecast into pointer arithmetic
982 // (T)(ptr + int) ---> (T)((size_t)ptr + sizeof(subtype)*(size_t)int)
983 //
984 if(
985 (expr_type.id() == ID_signedbv || expr_type.id() == ID_unsignedbv) &&
986 op_type.id() == ID_pointer && expr.op().id() == ID_plus)
987 {
988 const auto step =
990
991 if(step.has_value() && *step != 0)
992 {
993 const typet size_t_type(size_type());
994 auto new_expr = expr;
995
996 new_expr.op().type() = size_t_type;
997
998 for(auto &op : new_expr.op().operands())
999 {
1001 if(op.type().id() != ID_pointer && *step > 1)
1002 {
1003 new_op =
1005 }
1006 op = std::move(new_op);
1007 }
1008
1010
1011 return changed(simplify_typecast(new_expr)); // recursive call
1012 }
1013 }
1014
1015 // Push a pointer typecast into pointer arithmetic
1016 // (T)(ptr + int) ---> (T)ptr + sizeof(inner-st)/sizeof(outer-st)*int
1017 // when the inner subtype's size is a multiple of the outer subtype's size
1018 if(
1019 expr_type.id() == ID_pointer && op_type.id() == ID_pointer &&
1020 expr.op().id() == ID_plus)
1021 {
1022 const auto step =
1024 const auto new_step =
1026
1027 if(
1028 step.has_value() && *step != 0 && new_step.has_value() &&
1029 *new_step != 0 && *step >= *new_step && *step % *new_step == 0)
1030 {
1031 auto new_expr = expr.op();
1032 new_expr.type() = expr.type();
1033
1034 for(auto &op : new_expr.operands())
1035 {
1036 if(op.type().id() == ID_pointer)
1037 {
1039 op = std::move(new_op);
1040 }
1041 else if(*step > *new_step)
1042 {
1044 mult_exprt{from_integer(*step / *new_step, op.type()), op});
1045 op = std::move(new_op);
1046 }
1047 }
1048
1050 }
1051 }
1052
1053 const irep_idt &expr_type_id=expr_type.id();
1054 const exprt &operand = expr.op();
1055 const irep_idt &op_type_id=op_type.id();
1056
1057 if(operand.is_constant())
1058 {
1059 const irep_idt &value=to_constant_expr(operand).get_value();
1060
1061 // preserve the sizeof type annotation
1063 static_cast<const typet &>(operand.find(ID_C_c_sizeof_type));
1064
1065 if(op_type_id==ID_integer ||
1067 {
1068 // from integer to ...
1069
1071
1073 {
1074 return make_boolean_expr(int_value != 0);
1075 }
1076
1077 if(
1082 {
1084 }
1085 else if(expr_type_id == ID_c_enum_tag)
1086 {
1087 const auto &c_enum_type = ns.follow_tag(to_c_enum_tag_type(expr_type));
1088 if(!c_enum_type.is_incomplete()) // possibly incomplete
1089 {
1091 tmp.type() = expr_type; // we maintain the tag type
1092 return std::move(tmp);
1093 }
1094 }
1095 }
1096 else if(op_type_id==ID_rational)
1097 {
1098 }
1099 else if(op_type_id==ID_real)
1100 {
1101 }
1102 else if(op_type_id==ID_bool)
1103 {
1112 {
1113 if(operand == true)
1114 {
1115 return from_integer(1, expr_type);
1116 }
1117 else if(operand == false)
1118 {
1119 return from_integer(0, expr_type);
1120 }
1121 }
1122 else if(expr_type_id==ID_c_enum_tag)
1123 {
1124 const auto &c_enum_type = ns.follow_tag(to_c_enum_tag_type(expr_type));
1125 if(!c_enum_type.is_incomplete()) // possibly incomplete
1126 {
1127 unsigned int_value = operand == true ? 1u : 0u;
1129 tmp.type()=expr_type; // we maintain the tag type
1130 return std::move(tmp);
1131 }
1132 }
1133 else if(
1134 expr_type_id == ID_pointer && operand == false &&
1135 config.ansi_c.NULL_is_zero)
1136 {
1138 }
1139 }
1140 else if(op_type_id==ID_unsignedbv ||
1144 {
1146
1148 return unchanged(expr);
1149
1151 {
1152 return make_boolean_expr(int_value != 0);
1153 }
1154
1156 {
1157 return from_integer(int_value != 0, expr_type);
1158 }
1159
1161 {
1163 }
1164
1166 {
1167 if(int_value>=0)
1168 {
1170 }
1171 }
1172
1177 {
1178 auto result = from_integer(int_value, expr_type);
1179
1180 if(c_sizeof_type.is_not_nil())
1181 result.set(ID_C_c_sizeof_type, c_sizeof_type);
1182
1183 return std::move(result);
1184 }
1185
1187 {
1188 const auto &c_enum_type = ns.follow_tag(to_c_enum_tag_type(expr_type));
1189 if(!c_enum_type.is_incomplete()) // possibly incomplete
1190 {
1192 tmp.type()=expr_type; // we maintain the tag type
1193 return std::move(tmp);
1194 }
1195 }
1196
1198 {
1200 }
1201
1203 {
1204 // int to float
1207
1208 fixedbvt f;
1211 return f.to_expr();
1212 }
1213
1215 {
1216 // int to float
1219
1223
1224 return f.to_expr();
1225 }
1226
1228 {
1230 return from_rational(r);
1231 }
1232
1233 if(expr_type_id == ID_real)
1234 {
1236 }
1237 }
1238 else if(op_type_id==ID_fixedbv)
1239 {
1242 {
1243 // cast from fixedbv to int
1244 fixedbvt f(to_constant_expr(expr.op()));
1245 return from_integer(f.to_integer(), expr_type);
1246 }
1247 else if(expr_type_id==ID_fixedbv)
1248 {
1249 // fixedbv to fixedbv
1250 fixedbvt f(to_constant_expr(expr.op()));
1252 return f.to_expr();
1253 }
1254 else if(expr_type_id == ID_bv)
1255 {
1256 fixedbvt f{to_constant_expr(expr.op())};
1257 return from_integer(f.get_value(), expr_type);
1258 }
1259 }
1260 else if(op_type_id==ID_floatbv)
1261 {
1262 ieee_floatt f(
1263 to_constant_expr(expr.op()),
1265
1268 {
1269 // cast from float to int
1270 return from_integer(f.to_integer(), expr_type);
1271 }
1272 else if(expr_type_id==ID_floatbv)
1273 {
1274 // float to double or double to float
1276 return f.to_expr();
1277 }
1278 else if(expr_type_id==ID_fixedbv)
1279 {
1283 factor.from_integer(power(2, fixedbv.spec.get_fraction_bits()));
1284 f*=factor;
1285 fixedbv.set_value(f.to_integer());
1286 return fixedbv.to_expr();
1287 }
1288 else if(expr_type_id == ID_bv)
1289 {
1290 return from_integer(f.pack(), expr_type);
1291 }
1292 }
1293 else if(op_type_id==ID_bv)
1294 {
1295 if(
1299 {
1300 const auto width = to_bv_type(op_type).get_width();
1301 const auto int_value = bvrep2integer(value, width, false);
1304 else
1305 {
1307 auto result = from_integer(int_value, ns.follow_tag(tag_type));
1308 result.type() = tag_type;
1309 return std::move(result);
1310 }
1311 }
1312 else if(expr_type_id == ID_floatbv)
1313 {
1314 const auto width = to_bv_type(op_type).get_width();
1315 const auto int_value = bvrep2integer(value, width, false);
1317 ieee_float.unpack(int_value);
1318 return ieee_float.to_expr();
1319 }
1320 else if(expr_type_id == ID_fixedbv)
1321 {
1322 const auto width = to_bv_type(op_type).get_width();
1323 const auto int_value = bvrep2integer(value, width, false);
1325 fixedbv.set_value(int_value);
1326 return fixedbv.to_expr();
1327 }
1328 }
1329 else if(op_type_id==ID_c_enum_tag) // enum to int
1330 {
1331 const typet &base_type =
1332 ns.follow_tag(to_c_enum_tag_type(op_type)).underlying_type();
1333 if(base_type.id()==ID_signedbv || base_type.id()==ID_unsignedbv)
1334 {
1335 // enum constants use the representation of their base type
1336 auto new_expr = expr;
1337 new_expr.op().type() = base_type;
1338 return changed(simplify_typecast(new_expr)); // recursive call
1339 }
1340 }
1341 else if(op_type_id==ID_c_enum) // enum to int
1342 {
1343 const typet &base_type = to_c_enum_type(op_type).underlying_type();
1344 if(base_type.id()==ID_signedbv || base_type.id()==ID_unsignedbv)
1345 {
1346 // enum constants use the representation of their base type
1347 auto new_expr = expr;
1348 new_expr.op().type() = base_type;
1349 return changed(simplify_typecast(new_expr)); // recursive call
1350 }
1351 }
1352 }
1353 else if(operand.id()==ID_typecast) // typecast of typecast
1354 {
1355 // (T1)(T2)x ---> (T1)
1356 // where T1 has fewer bits than T2
1357 if(
1360 expr_type_id == ID_bv) &&
1361 to_bitvector_type(expr_type).get_width() <=
1362 to_bitvector_type(operand.type()).get_width())
1363 {
1364 auto new_expr = expr;
1365 new_expr.op() = to_typecast_expr(operand).op();
1366 // might enable further simplification
1367 return changed(simplify_typecast(new_expr)); // recursive call
1368 }
1369 }
1370 else if(operand.id()==ID_address_of)
1371 {
1372 const exprt &o=to_address_of_expr(operand).object();
1373
1374 // turn &array into &array[0] when casting to pointer-to-element-type
1375 if(
1376 o.type().id() == ID_array &&
1377 expr_type == pointer_type(to_array_type(o.type()).element_type()))
1378 {
1379 auto result =
1381
1382 return changed(simplify_address_of(result)); // recursive call
1383 }
1384 }
1386 {
1387 if(
1391 to_bitvector_type(expr_type).get_width() ==
1392 to_bitvector_type(operand.type()).get_width())
1393 {
1395 result.type() = expr_type;
1396 return changed(simplify_extractbits(result));
1397 }
1398 }
1399
1400 return unchanged(expr);
1401}
1402
1405{
1406 const typet &expr_type = expr.type();
1407 const typet &op_type = expr.op().type();
1408
1409 // (T)(a?b:c) --> a?(T)b:(T)c; don't do this for floating-point type casts as
1410 // the type cast itself may be costly
1411 if(
1412 expr.op().id() == ID_if && expr_type.id() != ID_floatbv &&
1413 op_type.id() != ID_floatbv)
1414 {
1415 if_exprt if_expr = lift_if(expr, 0);
1417 }
1418 else
1419 {
1420 auto r_it = simplify_rec(expr.op()); // recursive call
1421 if(r_it.has_changed())
1422 {
1423 auto tmp = expr;
1424 tmp.op() = r_it.expr;
1425 return tmp;
1426 }
1427 }
1428
1429 return unchanged(expr);
1430}
1431
1434{
1435 const exprt &pointer = expr.pointer();
1436
1437 if(pointer.type().id()!=ID_pointer)
1438 return unchanged(expr);
1439
1440 if(pointer.id()==ID_address_of)
1441 {
1442 exprt tmp=to_address_of_expr(pointer).object();
1443 // one address_of is gone, try again
1444 return changed(simplify_rec(tmp));
1445 }
1446 // rewrite *(&a[0] + x) to a[x]
1447 else if(
1448 pointer.id() == ID_plus && pointer.operands().size() == 2 &&
1449 to_plus_expr(pointer).op0().id() == ID_address_of)
1450 {
1451 const auto &pointer_plus_expr = to_plus_expr(pointer);
1452
1455
1456 if(address_of.object().id()==ID_index)
1457 {
1458 const index_exprt &old=to_index_expr(address_of.object());
1459 if(old.array().type().id() == ID_array)
1460 {
1461 index_exprt idx(
1462 old.array(),
1464 to_array_type(old.array().type()).element_type());
1465 return changed(simplify_rec(idx));
1466 }
1467 }
1468 }
1469
1470 return unchanged(expr);
1471}
1472
1475{
1476 const exprt &pointer = expr.pointer();
1477
1478 if(pointer.id() == ID_if)
1479 {
1480 if_exprt if_expr = lift_if(expr, 0);
1482 }
1483 else
1484 {
1485 auto r_it = simplify_rec(pointer); // recursive call
1486 if(r_it.has_changed())
1487 {
1488 auto tmp = expr;
1489 tmp.pointer() = r_it.expr;
1490 return tmp;
1491 }
1492 }
1493
1494 return unchanged(expr);
1495}
1496
1499{
1500 return unchanged(expr);
1501}
1502
1504{
1505 // now look at first operand
1506
1507 if(
1508 expr.old().type().id() == ID_struct ||
1509 expr.old().type().id() == ID_struct_tag)
1510 {
1512 expr.old().type().id() == ID_struct_tag
1513 ? ns.follow_tag(to_struct_tag_type(expr.old().type()))
1514 : to_struct_type(expr.old().type());
1515 const irep_idt &component_name = expr.where().get(ID_component_name);
1516
1517 if(expr.old().id() == ID_struct || expr.old().is_constant())
1518 {
1519 if(!old_type_followed.has_component(component_name))
1520 return unchanged(expr);
1521
1522 std::size_t number = old_type_followed.component_number(component_name);
1523
1524 if(number >= expr.old().operands().size())
1525 return unchanged(expr);
1526
1527 exprt result = expr.old();
1528 result.operands()[number] = expr.new_value();
1529 return result;
1530 }
1531 else if(
1532 old_type_followed.components().size() == 1 &&
1533 old_type_followed.has_component(component_name))
1534 {
1535 return struct_exprt{{expr.new_value()}, expr.type()};
1536 }
1537 }
1538 else if(
1539 expr.old().type().id() == ID_array || expr.old().type().id() == ID_vector)
1540 {
1541 if(
1542 expr.old().id() == ID_array || expr.old().is_constant() ||
1543 expr.old().id() == ID_vector)
1544 {
1545 const auto i = numeric_cast<mp_integer>(expr.where());
1546
1547 if(i.has_value() && *i >= 0 && *i < expr.old().operands().size())
1548 {
1549 exprt result = expr.old();
1550 result.operands()[numeric_cast_v<std::size_t>(*i)] = expr.new_value();
1551 return result;
1552 }
1553 }
1554 }
1555
1556 return unchanged(expr);
1557}
1558
1561{
1562 // this is to push updates into (possibly nested) constants
1563
1564 const exprt::operandst &designator = expr.designator();
1565
1566 exprt updated_value = expr.old();
1568
1569 for(const auto &e : designator)
1570 {
1571 if(e.id()==ID_index_designator &&
1572 value_ptr->id()==ID_array)
1573 {
1574 const auto i = numeric_cast<mp_integer>(to_index_designator(e).index());
1575
1576 if(!i.has_value())
1577 return unchanged(expr);
1578
1579 if(*i < 0 || *i >= value_ptr->operands().size())
1580 return unchanged(expr);
1581
1583 }
1584 else if(e.id()==ID_member_designator &&
1585 value_ptr->id()==ID_struct)
1586 {
1587 const irep_idt &component_name=
1588 e.get(ID_component_name);
1590 value_ptr->type().id() == ID_struct_tag
1591 ? ns.follow_tag(to_struct_tag_type(value_ptr->type()))
1592 : to_struct_type(value_ptr->type());
1593 if(!value_ptr_struct_type.has_component(component_name))
1594 return unchanged(expr);
1596 value_ptr = &designator_as_struct_expr.component(component_name, ns);
1597 CHECK_RETURN(value_ptr->is_not_nil());
1598 }
1599 else
1600 return unchanged(expr); // give up, unknown designator
1601 }
1602
1603 // found, done
1604 *value_ptr = expr.new_value();
1605 return updated_value;
1606}
1607
1609{
1610 if(expr.id()==ID_plus)
1611 {
1612 if(expr.type().id()==ID_pointer)
1613 {
1614 // kill integers from sum
1615 for(auto &op : expr.operands())
1616 if(op.type().id() == ID_pointer)
1617 return changed(simplify_object(op)); // recursive call
1618 }
1619 }
1620 else if(expr.id()==ID_typecast)
1621 {
1622 auto const &typecast_expr = to_typecast_expr(expr);
1623 const typet &op_type = typecast_expr.op().type();
1624
1625 if(op_type.id()==ID_pointer)
1626 {
1627 // cast from pointer to pointer
1628 return changed(simplify_object(typecast_expr.op())); // recursive call
1629 }
1630 else if(op_type.id()==ID_signedbv || op_type.id()==ID_unsignedbv)
1631 {
1632 // cast from integer to pointer
1633
1634 // We do a bit of special treatment for (TYPE *)(a+(int)&o) and
1635 // (TYPE *)(a+(int)((T*)&o+x)), which are re-written to '&o'.
1636
1637 const exprt &casted_expr = typecast_expr.op();
1638 if(casted_expr.id() == ID_plus && casted_expr.operands().size() == 2)
1639 {
1640 const auto &plus_expr = to_plus_expr(casted_expr);
1641
1642 const exprt &cand = plus_expr.op0().id() == ID_typecast
1643 ? plus_expr.op0()
1644 : plus_expr.op1();
1645
1646 if(cand.id() == ID_typecast)
1647 {
1648 const auto &typecast_op = to_typecast_expr(cand).op();
1649
1650 if(typecast_op.id() == ID_address_of)
1651 {
1652 return typecast_op;
1653 }
1654 else if(
1655 typecast_op.id() == ID_plus && typecast_op.operands().size() == 2 &&
1656 to_plus_expr(typecast_op).op0().id() == ID_typecast &&
1657 to_typecast_expr(to_plus_expr(typecast_op).op0()).op().id() ==
1659 {
1660 return to_typecast_expr(to_plus_expr(typecast_op).op0()).op();
1661 }
1662 }
1663 }
1664 }
1665 }
1666 else if(expr.id()==ID_address_of)
1667 {
1668 const auto &object = to_address_of_expr(expr).object();
1669
1670 if(object.id() == ID_index)
1671 {
1672 // &some[i] -> &some
1673 address_of_exprt new_expr(to_index_expr(object).array());
1674 return changed(simplify_object(new_expr)); // recursion
1675 }
1676 else if(object.id() == ID_member)
1677 {
1678 // &some.f -> &some
1679 address_of_exprt new_expr(to_member_expr(object).compound());
1680 return changed(simplify_object(new_expr)); // recursion
1681 }
1682 }
1683
1684 return unchanged(expr);
1685}
1686
1689{
1690 // lift up any ID_if on the object
1691 if(expr.op().id() == ID_if)
1692 {
1693 if_exprt if_expr = lift_if(expr, 0);
1694 if_expr.true_case() =
1696 if_expr.false_case() =
1698 return changed(simplify_if(if_expr));
1699 }
1700
1701 const auto el_size = pointer_offset_bits(expr.type(), ns);
1702 if(el_size.has_value() && *el_size < 0)
1703 return unchanged(expr);
1704
1705 // byte_extract(byte_extract(root, offset1), offset2) =>
1706 // byte_extract(root, offset1+offset2)
1707 if(expr.op().id()==expr.id())
1708 {
1709 auto tmp = expr;
1710
1711 tmp.offset() = simplify_rec(plus_exprt(
1713 to_byte_extract_expr(expr.op()).offset(), expr.offset().type()),
1714 expr.offset()));
1715 tmp.op() = to_byte_extract_expr(expr.op()).op();
1716
1717 return changed(simplify_byte_extract(tmp)); // recursive call
1718 }
1719
1720 // byte_extract(byte_update(root, offset, value), offset) =>
1721 // value
1722 if(
1723 ((expr.id() == ID_byte_extract_big_endian &&
1724 expr.op().id() == ID_byte_update_big_endian) ||
1725 (expr.id() == ID_byte_extract_little_endian &&
1726 expr.op().id() == ID_byte_update_little_endian)) &&
1727 expr.offset() == to_byte_update_expr(as_const(expr).op()).offset())
1728 {
1729 const auto &op_byte_update = to_byte_update_expr(expr.op());
1730
1731 if(expr.type() == op_byte_update.value().type())
1732 {
1733 return op_byte_update.value();
1734 }
1735 else if(el_size.has_value())
1736 {
1737 const auto update_bits_opt =
1738 pointer_offset_bits(op_byte_update.value().type(), ns);
1739
1740 if(update_bits_opt.has_value() && *el_size <= *update_bits_opt)
1741 {
1742 auto tmp = expr;
1743 tmp.op() = op_byte_update.value();
1744 tmp.offset() = from_integer(0, expr.offset().type());
1745
1746 return changed(simplify_byte_extract(tmp)); // recursive call
1747 }
1748 }
1749 }
1750
1751 auto offset = numeric_cast<mp_integer>(expr.offset());
1752 if(offset.has_value() && *offset < 0)
1753 return unchanged(expr);
1754
1755 // try to simplify byte_extract(byte_update(...))
1756 auto const bu = expr_try_dynamic_cast<byte_update_exprt>(expr.op());
1757 std::optional<mp_integer> update_offset;
1758 if(bu)
1760 if(
1761 offset.has_value() && bu && el_size.has_value() &&
1762 update_offset.has_value())
1763 {
1764 // byte_extract(byte_update(root, offset_u, value), offset_e) so that the
1765 // update does not affect what is being extracted simplifies to
1766 // byte_extract(root, offset_e)
1767 //
1768 // byte_extract(byte_update(root, offset_u, value), offset_e) so that the
1769 // extracted range fully lies within the update value simplifies to
1770 // byte_extract(value, offset_e - offset_u)
1771 if(
1772 *offset * expr.get_bits_per_byte() + *el_size <=
1773 *update_offset * bu->get_bits_per_byte())
1774 {
1775 // extracting before the update
1776 auto tmp = expr;
1777 tmp.op() = bu->op();
1778 return changed(simplify_byte_extract(tmp)); // recursive call
1779 }
1780 else if(
1781 const auto update_size = pointer_offset_bits(bu->value().type(), ns))
1782 {
1783 if(
1784 *offset * expr.get_bits_per_byte() >=
1785 *update_offset * bu->get_bits_per_byte() + *update_size)
1786 {
1787 // extracting after the update
1788 auto tmp = expr;
1789 tmp.op() = bu->op();
1790 return changed(simplify_byte_extract(tmp)); // recursive call
1791 }
1792 else if(
1793 *offset >= *update_offset &&
1794 *offset * expr.get_bits_per_byte() + *el_size <=
1795 *update_offset * bu->get_bits_per_byte() + *update_size)
1796 {
1797 // extracting from the update
1798 auto tmp = expr;
1799 tmp.op() = bu->value();
1800 tmp.offset() =
1801 from_integer(*offset - *update_offset, expr.offset().type());
1802 return changed(simplify_byte_extract(tmp)); // recursive call
1803 }
1804 }
1805 }
1806
1807 // don't do any of the following if endianness doesn't match, as
1808 // bytes need to be swapped
1809 if(
1810 offset.has_value() && *offset == 0 &&
1811 ((expr.id() == ID_byte_extract_little_endian &&
1812 config.ansi_c.endianness ==
1814 (expr.id() == ID_byte_extract_big_endian &&
1815 config.ansi_c.endianness ==
1817 {
1818 // byte extract of full object is object
1819 if(expr.type() == expr.op().type())
1820 {
1821 return expr.op();
1822 }
1823 else if(
1824 expr.type().id() == ID_pointer && expr.op().type().id() == ID_pointer)
1825 {
1826 return typecast_exprt(expr.op(), expr.type());
1827 }
1828 }
1829
1830 if(
1831 (expr.type().id() == ID_union &&
1832 to_union_type(expr.type()).components().empty()) ||
1833 (expr.type().id() == ID_union_tag &&
1834 ns.follow_tag(to_union_tag_type(expr.type())).components().empty()))
1835 {
1836 return empty_union_exprt{expr.type()};
1837 }
1838 else if(
1839 (expr.type().id() == ID_struct &&
1840 to_struct_type(expr.type()).components().empty()) ||
1841 (expr.type().id() == ID_struct_tag &&
1842 ns.follow_tag(to_struct_tag_type(expr.type())).components().empty()))
1843 {
1844 return struct_exprt{{}, expr.type()};
1845 }
1846
1847 // no proper simplification for expr.type()==void
1848 // or types of unknown size
1849 if(!el_size.has_value() || *el_size == 0)
1850 return unchanged(expr);
1851
1852 if(
1853 offset.has_value() && expr.op().id() == ID_array_of &&
1854 to_array_of_expr(expr.op()).op().is_constant())
1855 {
1856 const auto const_bits_opt = expr2bits(
1857 to_array_of_expr(expr.op()).op(),
1858 config.ansi_c.endianness ==
1860 ns);
1861
1862 if(!const_bits_opt.has_value())
1863 return unchanged(expr);
1864
1865 std::string const_bits=const_bits_opt.value();
1866
1867 DATA_INVARIANT(!const_bits.empty(), "bit representation must be non-empty");
1868
1869 // double the string until we have sufficiently many bits
1870 while(mp_integer(const_bits.size()) <
1871 *offset * expr.get_bits_per_byte() + *el_size)
1872 {
1874 }
1875
1876 std::string el_bits = std::string(
1877 const_bits,
1880
1881 auto tmp = bits2expr(
1882 el_bits, expr.type(), expr.id() == ID_byte_extract_little_endian, ns);
1883
1884 if(tmp.has_value())
1885 return std::move(*tmp);
1886 }
1887
1888 // in some cases we even handle non-const array_of
1889 if(
1890 offset.has_value() && expr.op().id() == ID_array_of &&
1891 (*offset * expr.get_bits_per_byte()) % (*el_size) == 0 &&
1892 *el_size <=
1893 pointer_offset_bits(to_array_of_expr(expr.op()).what().type(), ns))
1894 {
1895 auto tmp = expr;
1896 tmp.op() = simplify_index(index_exprt(expr.op(), expr.offset()));
1897 tmp.offset() = from_integer(0, expr.offset().type());
1899 }
1900
1901 // extract bits of a constant
1902 const auto bits =
1903 expr2bits(expr.op(), expr.id() == ID_byte_extract_little_endian, ns);
1904
1905 if(
1906 offset.has_value() && bits.has_value() &&
1907 mp_integer(bits->size()) >= *el_size + *offset * expr.get_bits_per_byte())
1908 {
1909 // make sure we don't lose bits with structs containing flexible array
1910 // members
1912 expr.type(),
1913 [&](const typet &type) {
1914 if(type.id() != ID_struct && type.id() != ID_struct_tag)
1915 return false;
1916
1917 const struct_typet &st = type.id() == ID_struct_tag
1918 ? ns.follow_tag(to_struct_tag_type(type))
1919 : to_struct_type(type);
1920 const auto &comps = st.components();
1921 if(comps.empty() || comps.back().type().id() != ID_array)
1922 return false;
1923
1924 if(comps.back().type().get_bool(ID_C_flexible_array_member))
1925 return true;
1926
1927 const auto size =
1928 numeric_cast<mp_integer>(to_array_type(comps.back().type()).size());
1929 return !size.has_value() || *size <= 1;
1930 },
1931 ns);
1933 {
1934 std::string bits_cut = std::string(
1935 bits.value(),
1938
1939 auto tmp = bits2expr(
1940 bits_cut, expr.type(), expr.id() == ID_byte_extract_little_endian, ns);
1941
1942 if(tmp.has_value())
1943 return std::move(*tmp);
1944 }
1945 }
1946
1947 // push byte extracts into struct or union expressions, just like
1948 // lower_byte_extract does (this is the same code, except recursive calls use
1949 // simplify rather than lower_byte_extract)
1950 if(expr.op().id() == ID_struct || expr.op().id() == ID_union)
1951 {
1952 if(expr.type().id() == ID_struct || expr.type().id() == ID_struct_tag)
1953 {
1954 const struct_typet &struct_type =
1955 expr.type().id() == ID_struct_tag
1956 ? ns.follow_tag(to_struct_tag_type(expr.type()))
1957 : to_struct_type(expr.type());
1958 const struct_typet::componentst &components = struct_type.components();
1959
1960 bool failed = false;
1961 struct_exprt s({}, expr.type());
1962
1963 for(const auto &comp : components)
1964 {
1965 auto component_bits = pointer_offset_bits(comp.type(), ns);
1966
1967 // the next member would be misaligned, abort
1968 if(
1969 !component_bits.has_value() || *component_bits == 0 ||
1970 *component_bits % expr.get_bits_per_byte() != 0)
1971 {
1972 failed = true;
1973 break;
1974 }
1975
1976 auto member_offset_opt =
1977 member_offset_expr(struct_type, comp.get_name(), ns);
1978
1979 if(!member_offset_opt.has_value())
1980 {
1981 failed = true;
1982 break;
1983 }
1984
1986 plus_exprt{expr.offset(),
1988 member_offset_opt.value(), expr.offset().type())});
1989
1990 byte_extract_exprt tmp = expr;
1991 tmp.type() = comp.type();
1992 tmp.offset() = new_offset;
1993
1995 }
1996
1997 if(!failed)
1998 return s;
1999 }
2000 else if(expr.type().id() == ID_union || expr.type().id() == ID_union_tag)
2001 {
2002 const union_typet &union_type =
2003 expr.type().id() == ID_union_tag
2004 ? ns.follow_tag(to_union_tag_type(expr.type()))
2005 : to_union_type(expr.type());
2006 auto widest_member_opt = union_type.find_widest_union_component(ns);
2007 if(widest_member_opt.has_value())
2008 {
2009 byte_extract_exprt be = expr;
2010 be.type() = widest_member_opt->first.type();
2011 return union_exprt{widest_member_opt->first.get_name(),
2013 expr.type()};
2014 }
2015 }
2016 }
2017 else if(expr.op().id() == ID_array)
2018 {
2019 const array_typet &array_type = to_array_type(expr.op().type());
2020 const auto &element_bit_width =
2021 pointer_offset_bits(array_type.element_type(), ns);
2022 if(
2023 offset.has_value() && element_bit_width.has_value() &&
2024 *element_bit_width > 0)
2025 {
2026 if(
2027 *offset > 0 &&
2028 *offset * expr.get_bits_per_byte() % *element_bit_width == 0)
2029 {
2031 (*offset * expr.get_bits_per_byte()) / *element_bit_width);
2033 slice.operands().erase(
2034 slice.operands().begin(),
2035 slice.operands().begin() +
2036 std::min(elements_to_erase, slice.operands().size()));
2037 slice.type().size() =
2038 from_integer(slice.operands().size(), slice.type().size().type());
2039 byte_extract_exprt be = expr;
2040 be.op() = slice;
2041 be.offset() = from_integer(0, expr.offset().type());
2043 }
2044 else if(*offset == 0 && *el_size % *element_bit_width == 0)
2045 {
2046 const auto elements_to_keep =
2049 if(slice.operands().size() > elements_to_keep)
2050 {
2051 slice.operands().resize(elements_to_keep);
2052 slice.type().size() =
2053 from_integer(slice.operands().size(), slice.type().size().type());
2054 byte_extract_exprt be = expr;
2055 be.op() = slice;
2057 }
2058 }
2059 }
2060 }
2061
2062 // try to refine it down to extracting from a member or an index in an array
2063 auto subexpr =
2064 get_subexpression_at_offset(expr.op(), expr.offset(), expr.type(), ns);
2065 if(subexpr.has_value() && subexpr.value() != expr)
2066 return changed(simplify_rec(subexpr.value())); // recursive call
2067
2068 if(can_forward_propagatet(ns)(expr))
2069 return changed(simplify_rec(lower_byte_extract(expr, ns)));
2070
2071 return unchanged(expr);
2072}
2073
2076{
2077 // lift up any ID_if on the object
2078 if(expr.op().id() == ID_if)
2079 {
2080 if_exprt if_expr = lift_if(expr, 0);
2082 }
2083 else
2084 {
2085 std::optional<exprt::operandst> new_operands;
2086
2087 for(std::size_t i = 0; i < expr.operands().size(); ++i)
2088 {
2089 auto r_it = simplify_rec(expr.operands()[i]); // recursive call
2090 if(r_it.has_changed())
2091 {
2092 if(!new_operands.has_value())
2093 new_operands = expr.operands();
2094 (*new_operands)[i] = std::move(r_it.expr);
2095 }
2096 }
2097
2098 if(new_operands.has_value())
2099 {
2100 exprt result = expr;
2101 std::swap(result.operands(), *new_operands);
2102 return result;
2103 }
2104 }
2105
2106 return unchanged(expr);
2107}
2108
2111{
2112 // byte_update(byte_update(root, offset, value), offset, value2) =>
2113 // byte_update(root, offset, value2)
2114 if(
2115 expr.id() == expr.op().id() &&
2116 expr.offset() == to_byte_update_expr(expr.op()).offset() &&
2117 expr.value().type() == to_byte_update_expr(expr.op()).value().type())
2118 {
2119 auto tmp = expr;
2120 tmp.set_op(to_byte_update_expr(expr.op()).op());
2121 return std::move(tmp);
2122 }
2123
2124 const exprt &root = expr.op();
2125 const exprt &offset = expr.offset();
2126 const exprt &value = expr.value();
2127 const auto val_size = pointer_offset_bits(value.type(), ns);
2128 const auto root_size = pointer_offset_bits(root.type(), ns);
2129
2130 const auto matching_byte_extract_id =
2133
2134 // byte update of full object is byte_extract(new value)
2135 if(
2136 offset == 0 && val_size.has_value() && *val_size > 0 &&
2137 root_size.has_value() && *root_size > 0 && *val_size >= *root_size)
2138 {
2141 value,
2142 offset,
2143 expr.get_bits_per_byte(),
2144 expr.type());
2145
2147 }
2148
2149 // update bits in a constant
2150 const auto offset_int = numeric_cast<mp_integer>(offset);
2151 if(
2152 root_size.has_value() && *root_size >= 0 && val_size.has_value() &&
2153 *val_size >= 0 && offset_int.has_value() && *offset_int >= 0 &&
2155 {
2156 auto root_bits =
2157 expr2bits(root, expr.id() == ID_byte_update_little_endian, ns);
2158
2159 if(root_bits.has_value())
2160 {
2161 const auto val_bits =
2162 expr2bits(value, expr.id() == ID_byte_update_little_endian, ns);
2163
2164 if(val_bits.has_value())
2165 {
2166 root_bits->replace(
2169 *val_bits);
2170
2171 auto tmp = bits2expr(
2172 *root_bits,
2173 expr.type(),
2175 ns);
2176
2177 if(tmp.has_value())
2178 return std::move(*tmp);
2179 }
2180 }
2181 }
2182
2183 /*
2184 * byte_update(root, offset,
2185 * extract(root, offset) WITH component:=value)
2186 * =>
2187 * byte_update(root, offset + component offset,
2188 * value)
2189 */
2190
2191 if(value.id()==ID_with)
2192 {
2193 const with_exprt &with=to_with_expr(value);
2194
2195 if(with.old().id() == matching_byte_extract_id)
2196 {
2197 const byte_extract_exprt &extract=to_byte_extract_expr(with.old());
2198
2199 /* the simplification can be used only if
2200 root and offset of update and extract
2201 are the same */
2202 if(!(root==extract.op()))
2203 return unchanged(expr);
2204 if(!(offset==extract.offset()))
2205 return unchanged(expr);
2206
2207 if(with.type().id() == ID_struct || with.type().id() == ID_struct_tag)
2208 {
2209 const struct_typet &struct_type =
2210 with.type().id() == ID_struct_tag
2211 ? ns.follow_tag(to_struct_tag_type(with.type()))
2212 : to_struct_type(with.type());
2213 const irep_idt &component_name=with.where().get(ID_component_name);
2214 const typet &c_type = struct_type.get_component(component_name).type();
2215
2216 // is this a bit field?
2217 if(c_type.id() == ID_c_bit_field || c_type.id() == ID_bool)
2218 {
2219 // don't touch -- might not be byte-aligned
2220 }
2221 else
2222 {
2223 // new offset = offset + component offset
2224 auto i = member_offset(struct_type, component_name, ns);
2225 if(i.has_value())
2226 {
2227 exprt compo_offset = from_integer(*i, offset.type());
2229 exprt new_value(with.new_value());
2230 auto tmp = expr;
2231 tmp.set_offset(simplify_node(std::move(new_offset)));
2232 tmp.set_value(std::move(new_value));
2233 return changed(simplify_byte_update(tmp)); // recursive call
2234 }
2235 }
2236 }
2237 else if(with.type().id() == ID_array)
2238 {
2239 auto i =
2240 pointer_offset_size(to_array_type(with.type()).element_type(), ns);
2241 if(i.has_value())
2242 {
2243 const exprt &index=with.where();
2245 simplify_mult(mult_exprt(index, from_integer(*i, index.type())));
2246
2247 // index_offset may need a typecast
2248 if(offset.type() != index.type())
2249 {
2250 index_offset =
2252 }
2253
2255 exprt new_value(with.new_value());
2256 auto tmp = expr;
2257 tmp.set_offset(simplify_plus(std::move(new_offset)));
2258 tmp.set_value(std::move(new_value));
2259 return changed(simplify_byte_update(tmp)); // recursive call
2260 }
2261 }
2262 }
2263 }
2264
2265 // size must be known
2266 if(!val_size.has_value() || *val_size == 0)
2267 return unchanged(expr);
2268
2269 // byte_update(root, offset, value) is with(root, index, value) when root is
2270 // array-typed, the size of value matches the array-element width, and offset
2271 // is guaranteed to be a multiple of the array-element width
2273 {
2274 auto el_size = pointer_offset_bits(array_type->element_type(), ns);
2275
2276 if(el_size.has_value() && *el_size > 0 && *val_size % *el_size == 0)
2277 {
2278 if(
2279 offset_int.has_value() &&
2280 (*offset_int * expr.get_bits_per_byte()) % *el_size == 0)
2281 {
2283 (*offset_int * expr.get_bits_per_byte()) / *el_size;
2285 root,
2286 from_integer(base_offset, array_type->index_type()),
2289 value,
2290 from_integer(0, offset.type()),
2291 expr.get_bits_per_byte(),
2292 array_type->element_type()}};
2294
2295 for(mp_integer i = 1; i < n_elements; ++i)
2296 {
2299 from_integer(base_offset + i, array_type->index_type()),
2302 value,
2304 i * (*el_size / expr.get_bits_per_byte()), offset.type()),
2305 expr.get_bits_per_byte(),
2306 array_type->element_type()}};
2307 }
2308
2310 }
2311 // if we have an offset C + x (where C is a constant) we can try to
2312 // recurse by first looking at the member at offset C
2313 else if(
2314 offset.id() == ID_plus && offset.operands().size() == 2 &&
2315 (to_multi_ary_expr(offset).op0().is_constant() ||
2316 to_multi_ary_expr(offset).op1().is_constant()))
2317 {
2318 const plus_exprt &offset_plus = to_plus_expr(offset);
2319 const auto &const_factor = offset_plus.op0().is_constant()
2320 ? offset_plus.op0()
2321 : offset_plus.op1();
2322 const exprt &other_factor = offset_plus.op0().is_constant()
2323 ? offset_plus.op1()
2324 : offset_plus.op0();
2325
2326 auto tmp = expr;
2327 tmp.set_offset(const_factor);
2329
2330 if(
2331 expr_at_offset_C.id() == ID_with &&
2332 to_with_expr(expr_at_offset_C).where() == 0)
2333 {
2334 tmp.set_op(to_with_expr(expr_at_offset_C).old());
2335 tmp.set_offset(other_factor);
2337 }
2338 }
2339 else if(
2340 offset.id() == ID_mult && offset.operands().size() == 2 &&
2341 (to_multi_ary_expr(offset).op0().is_constant() ||
2342 to_multi_ary_expr(offset).op1().is_constant()))
2343 {
2344 const mult_exprt &offset_mult = to_mult_expr(offset);
2346 offset_mult.op0().is_constant() ? offset_mult.op0()
2347 : offset_mult.op1()));
2348 const exprt &other_factor = offset_mult.op0().is_constant()
2349 ? offset_mult.op1()
2350 : offset_mult.op0();
2351
2352 if((const_factor * expr.get_bits_per_byte()) % *el_size == 0)
2353 {
2358 other_factor.type())};
2360 root,
2362 base_offset, array_type->index_type()),
2365 value,
2366 from_integer(0, offset.type()),
2367 expr.get_bits_per_byte(),
2368 array_type->element_type()}};
2370 for(mp_integer i = 1; i < n_elements; ++i)
2371 {
2376 array_type->index_type()),
2379 value,
2381 i * (*el_size / expr.get_bits_per_byte()), offset.type()),
2382 expr.get_bits_per_byte(),
2383 array_type->element_type()}};
2384 }
2386 }
2387 }
2388 }
2389 }
2390
2391 // the following require a constant offset
2392 if(!offset_int.has_value() || *offset_int < 0)
2393 return unchanged(expr);
2394
2395 // Are we updating (parts of) a struct? Do individual member updates
2396 // instead, unless there are non-byte-sized bit fields
2397 if(root.type().id() == ID_struct || root.type().id() == ID_struct_tag)
2398 {
2400 result_expr.make_nil();
2401
2402 auto update_size = pointer_offset_size(value.type(), ns);
2403
2404 const struct_typet &struct_type =
2405 root.type().id() == ID_struct_tag
2406 ? ns.follow_tag(to_struct_tag_type(root.type()))
2407 : to_struct_type(root.type());
2408 const struct_typet::componentst &components=
2409 struct_type.components();
2410
2411 for(const auto &component : components)
2412 {
2413 auto m_offset = member_offset(struct_type, component.get_name(), ns);
2414
2416
2417 // can we determine the current offset?
2418 if(!m_offset.has_value())
2419 {
2420 result_expr.make_nil();
2421 break;
2422 }
2423
2424 // is it a byte-sized member?
2425 if(
2426 !m_size_bits.has_value() || *m_size_bits == 0 ||
2427 (*m_size_bits) % expr.get_bits_per_byte() != 0)
2428 {
2429 result_expr.make_nil();
2430 break;
2431 }
2432
2433 mp_integer m_size_bytes = (*m_size_bits) / expr.get_bits_per_byte();
2434
2435 // is that member part of the update?
2437 continue;
2438 // are we done updating?
2439 else if(
2440 update_size.has_value() && *update_size > 0 &&
2442 {
2443 break;
2444 }
2445
2446 if(result_expr.is_nil())
2447 result_expr = as_const(expr).op();
2448
2450 member_name.set(ID_component_name, component.get_name());
2452
2453 // are we updating on member boundaries?
2454 if(
2455 *m_offset < *offset_int ||
2456 (*m_offset == *offset_int && update_size.has_value() &&
2458 {
2460 expr.id(),
2461 member_exprt(root, component.get_name(), component.type()),
2462 from_integer(*offset_int - *m_offset, offset.type()),
2463 value,
2464 expr.get_bits_per_byte());
2465
2466 to_with_expr(result_expr).new_value().swap(v);
2467 }
2468 else if(
2469 update_size.has_value() && *update_size > 0 &&
2471 {
2472 // we don't handle this for the moment
2473 result_expr.make_nil();
2474 break;
2475 }
2476 else
2477 {
2480 value,
2481 from_integer(*m_offset - *offset_int, offset.type()),
2482 expr.get_bits_per_byte(),
2483 component.type());
2484
2485 to_with_expr(result_expr).new_value().swap(v);
2486 }
2487 }
2488
2489 if(result_expr.is_not_nil())
2491 }
2492
2493 // replace elements of array or struct expressions, possibly using
2494 // byte_extract
2495 if(root.id()==ID_array)
2496 {
2497 auto el_size =
2498 pointer_offset_bits(to_type_with_subtype(root.type()).subtype(), ns);
2499
2500 if(
2501 !el_size.has_value() || *el_size == 0 ||
2502 (*el_size) % expr.get_bits_per_byte() != 0 ||
2503 (*val_size) % expr.get_bits_per_byte() != 0)
2504 {
2505 return unchanged(expr);
2506 }
2507
2508 exprt result=root;
2509
2511 Forall_operands(it, result)
2512 {
2514 break;
2515
2517 {
2523
2526 value,
2527 from_integer(val_offset, offset.type()),
2528 expr.get_bits_per_byte(),
2531 from_integer(bytes_req, offset.type())));
2532
2533 *it = byte_update_exprt(
2534 expr.id(),
2535 *it,
2538 offset.type()),
2539 new_val,
2540 expr.get_bits_per_byte());
2541
2542 *it = simplify_rec(*it); // recursive call
2543
2545 }
2546
2548 }
2549
2550 return std::move(result);
2551 }
2552
2553 return unchanged(expr);
2554}
2555
2558{
2559 if(expr.id() == ID_complex_real)
2560 {
2562
2563 if(complex_real_expr.op().id() == ID_complex)
2564 return to_complex_expr(complex_real_expr.op()).real();
2565 }
2566 else if(expr.id() == ID_complex_imag)
2567 {
2569
2570 if(complex_imag_expr.op().id() == ID_complex)
2571 return to_complex_expr(complex_imag_expr.op()).imag();
2572 }
2573
2574 return unchanged(expr);
2575}
2576
2579{
2580 // When one operand is zero, an overflow can only occur for a subtraction from
2581 // zero.
2582 if(
2583 expr.op1() == 0 ||
2584 (expr.op0() == 0 && !can_cast_expr<minus_overflow_exprt>(expr)))
2585 {
2586 return false_exprt{};
2587 }
2588
2589 // One is neutral element for multiplication
2590 if(
2592 (expr.op0() == 1 || expr.op1() == 1))
2593 {
2594 return false_exprt{};
2595 }
2596
2597 // we only handle the case of same operand types
2598 if(expr.op0().type() != expr.op1().type())
2599 return unchanged(expr);
2600
2601 // catch some cases over mathematical types
2602 const irep_idt &op_type_id = expr.op0().type().id();
2603 if(
2606 {
2607 return false_exprt{};
2608 }
2609
2611 return false_exprt{};
2612
2613 // we only handle constants over signedbv/unsignedbv for the remaining cases
2615 return unchanged(expr);
2616
2617 if(!expr.op0().is_constant() || !expr.op1().is_constant())
2618 return unchanged(expr);
2619
2620 const auto op0_value = numeric_cast<mp_integer>(expr.op0());
2621 const auto op1_value = numeric_cast<mp_integer>(expr.op1());
2622 if(!op0_value.has_value() || !op1_value.has_value())
2623 return unchanged(expr);
2624
2627 no_overflow_result = *op0_value + *op1_value;
2629 no_overflow_result = *op0_value - *op1_value;
2631 no_overflow_result = *op0_value * *op1_value;
2633 no_overflow_result = *op0_value << *op1_value;
2634 else
2636
2637 const std::size_t width = to_bitvector_type(expr.op0().type()).get_width();
2639 if(
2640 no_overflow_result < bv_type.smallest() ||
2641 no_overflow_result > bv_type.largest())
2642 {
2643 return true_exprt{};
2644 }
2645 else
2646 return false_exprt{};
2647}
2648
2651{
2652 // zero is a neutral element for all operations supported here
2653 if(expr.op() == 0)
2654 return false_exprt{};
2655
2656 // catch some cases over mathematical types
2657 const irep_idt &op_type_id = expr.op().type().id();
2658 if(
2661 {
2662 return false_exprt{};
2663 }
2664
2665 if(op_type_id == ID_natural)
2666 return true_exprt{};
2667
2668 // we only handle constants over signedbv/unsignedbv for the remaining cases
2670 return unchanged(expr);
2671
2672 if(!expr.op().is_constant())
2673 return unchanged(expr);
2674
2675 const auto op_value = numeric_cast<mp_integer>(expr.op());
2676 if(!op_value.has_value())
2677 return unchanged(expr);
2678
2682 else
2684
2685 const std::size_t width = to_bitvector_type(expr.op().type()).get_width();
2687 if(
2688 no_overflow_result < bv_type.smallest() ||
2689 no_overflow_result > bv_type.largest())
2690 {
2691 return true_exprt{};
2692 }
2693 else
2694 return false_exprt{};
2695}
2696
2699{
2701 {
2702 // zero is a neutral element
2703 if(expr.op0() == 0)
2704 return struct_exprt{{expr.op0(), false_exprt{}}, expr.type()};
2705
2706 // catch some cases over mathematical types
2707 const irep_idt &op_type_id = expr.op0().type().id();
2708 if(
2711 {
2712 return struct_exprt{{expr.op0(), false_exprt{}}, expr.type()};
2713 }
2714
2715 // always an overflow for natural numbers, but the result is not
2716 // representable
2717 if(op_type_id == ID_natural)
2718 return unchanged(expr);
2719
2720 // we only handle constants over signedbv/unsignedbv for the remaining cases
2722 return unchanged(expr);
2723
2724 if(!expr.op0().is_constant())
2725 return unchanged(expr);
2726
2727 const auto op_value = numeric_cast<mp_integer>(expr.op0());
2728 if(!op_value.has_value())
2729 return unchanged(expr);
2730
2732
2733 const std::size_t width = to_bitvector_type(expr.op0().type()).get_width();
2735 if(
2736 no_overflow_result < bv_type.smallest() ||
2737 no_overflow_result > bv_type.largest())
2738 {
2739 return struct_exprt{
2741 expr.type()};
2742 }
2743 else
2744 {
2745 return struct_exprt{
2747 expr.type()};
2748 }
2749 }
2750 else
2751 {
2752 // When one operand is zero, an overflow can only occur for a subtraction
2753 // from zero.
2754 if(expr.op0() == 0)
2755 {
2756 if(
2757 expr.id() == ID_overflow_result_plus ||
2758 expr.id() == ID_overflow_result_shl)
2759 {
2760 return struct_exprt{{expr.op1(), false_exprt{}}, expr.type()};
2761 }
2762 else if(expr.id() == ID_overflow_result_mult)
2763 {
2764 return struct_exprt{
2765 {from_integer(0, expr.op0().type()), false_exprt{}}, expr.type()};
2766 }
2767 }
2768 else if(expr.op1() == 0)
2769 {
2770 if(
2771 expr.id() == ID_overflow_result_plus ||
2772 expr.id() == ID_overflow_result_minus ||
2773 expr.id() == ID_overflow_result_shl)
2774 {
2775 return struct_exprt{{expr.op0(), false_exprt{}}, expr.type()};
2776 }
2777 else
2778 {
2779 return struct_exprt{
2780 {from_integer(0, expr.op0().type()), false_exprt{}}, expr.type()};
2781 }
2782 }
2783
2784 // One is neutral element for multiplication
2785 if(
2786 expr.id() == ID_overflow_result_mult &&
2787 (expr.op0() == 1 || expr.op1() == 1))
2788 {
2789 return struct_exprt{
2790 {expr.op0() == 1 ? expr.op1() : expr.op0(), false_exprt{}},
2791 expr.type()};
2792 }
2793
2794 // we only handle the case of same operand types
2795 if(
2796 expr.id() != ID_overflow_result_shl &&
2797 expr.op0().type() != expr.op1().type())
2798 {
2799 return unchanged(expr);
2800 }
2801
2802 // catch some cases over mathematical types
2803 const irep_idt &op_type_id = expr.op0().type().id();
2804 if(
2805 expr.id() != ID_overflow_result_shl &&
2807 op_type_id == ID_real))
2808 {
2809 irep_idt id =
2810 expr.id() == ID_overflow_result_plus
2811 ? ID_plus
2813 return struct_exprt{
2814 {simplify_node(binary_exprt{expr.op0(), id, expr.op1()}),
2815 false_exprt{}},
2816 expr.type()};
2817 }
2818
2819 if(
2820 (expr.id() == ID_overflow_result_plus ||
2821 expr.id() == ID_overflow_result_mult) &&
2823 {
2824 return struct_exprt{
2826 expr.op0(),
2828 expr.op1()}),
2829 false_exprt{}},
2830 expr.type()};
2831 }
2832
2833 // we only handle constants over signedbv/unsignedbv for the remaining cases
2835 return unchanged(expr);
2836
2837 // a special case of overflow-minus checking with operands (X + n) and X
2838 if(expr.id() == ID_overflow_result_minus)
2839 {
2840 const exprt &tc_op0 = skip_typecast(expr.op0());
2841 const exprt &tc_op1 = skip_typecast(expr.op1());
2842
2844 {
2845 if(skip_typecast(sum->op0()) == tc_op1 && sum->operands().size() == 2)
2846 {
2847 std::optional<exprt> offset;
2848 if(sum->type().id() == ID_pointer)
2849 {
2850 offset = std::move(simplify_pointer_offset(
2851 pointer_offset_exprt{*sum, expr.op0().type()})
2852 .expr);
2853 if(offset->id() == ID_pointer_offset)
2854 return unchanged(expr);
2855 }
2856 else
2857 offset = std::move(
2858 simplify_typecast(typecast_exprt{sum->op1(), expr.op0().type()})
2859 .expr);
2860
2861 exprt offset_op = skip_typecast(*offset);
2862 if(
2863 offset_op.type().id() != ID_signedbv &&
2864 offset_op.type().id() != ID_unsignedbv)
2865 {
2866 return unchanged(expr);
2867 }
2868
2869 const std::size_t width =
2870 to_bitvector_type(expr.op0().type()).get_width();
2872
2875 offset_op,
2876 ID_lt,
2877 from_integer(bv_type.smallest(), offset_op.type())},
2879 offset_op,
2880 ID_gt,
2881 from_integer(bv_type.largest(), offset_op.type())}};
2882
2883 return struct_exprt{
2884 {*offset, simplify_rec(not_representable)}, expr.type()};
2885 }
2886 }
2887 }
2888
2889 if(!expr.op0().is_constant() || !expr.op1().is_constant())
2890 return unchanged(expr);
2891
2892 // preserve the sizeof type annotation
2893 std::optional<typet> c_sizeof_type;
2894 for(const auto &op : expr.operands())
2895 {
2896 const typet &sizeof_type =
2897 static_cast<const typet &>(op.find(ID_C_c_sizeof_type));
2898 if(sizeof_type.is_not_nil())
2899 {
2901 break;
2902 }
2903 }
2904
2905 const auto op0_value = numeric_cast<mp_integer>(expr.op0());
2906 const auto op1_value = numeric_cast<mp_integer>(expr.op1());
2907 if(!op0_value.has_value() || !op1_value.has_value())
2908 return unchanged(expr);
2909
2911 if(expr.id() == ID_overflow_result_plus)
2912 no_overflow_result = *op0_value + *op1_value;
2913 else if(expr.id() == ID_overflow_result_minus)
2914 no_overflow_result = *op0_value - *op1_value;
2915 else if(expr.id() == ID_overflow_result_mult)
2916 no_overflow_result = *op0_value * *op1_value;
2917 else if(expr.id() == ID_overflow_result_shl)
2918 no_overflow_result = *op0_value << *op1_value;
2919 else
2921
2924 if(c_sizeof_type.has_value())
2926
2927 const std::size_t width = to_bitvector_type(expr.op0().type()).get_width();
2929 if(
2930 no_overflow_result < bv_type.smallest() ||
2931 no_overflow_result > bv_type.largest())
2932 {
2933 return struct_exprt{
2934 {std::move(no_overflow_result_expr), true_exprt{}}, expr.type()};
2935 }
2936 else
2937 {
2938 return struct_exprt{
2939 {std::move(no_overflow_result_expr), false_exprt{}}, expr.type()};
2940 }
2941 }
2942}
2943
2946{
2947 auto result = unchanged(expr);
2948
2949 // The ifs below could one day be replaced by a switch()
2950
2951 if(expr.id()==ID_address_of)
2952 {
2953 // the argument of this expression needs special treatment
2954 }
2955 else if(expr.id()==ID_if)
2956 {
2957 result = simplify_if_preorder(to_if_expr(expr));
2958 }
2959 else if(expr.id() == ID_typecast)
2960 {
2962 }
2963 else if(
2966 {
2968 }
2969 else if(expr.id() == ID_dereference)
2970 {
2972 }
2973 else if(expr.id() == ID_index)
2974 {
2975 result = simplify_index_preorder(to_index_expr(expr));
2976 }
2977 else if(expr.id() == ID_member)
2978 {
2980 }
2981 else if(
2982 expr.id() == ID_is_dynamic_object || expr.id() == ID_is_invalid_pointer ||
2983 expr.id() == ID_object_size || expr.id() == ID_pointer_object ||
2984 expr.id() == ID_pointer_offset)
2985 {
2987 }
2988 else if(expr.has_operands())
2989 {
2990 std::optional<exprt::operandst> new_operands;
2991
2992 for(std::size_t i = 0; i < expr.operands().size(); ++i)
2993 {
2994 auto r_it = simplify_rec(expr.operands()[i]); // recursive call
2995 if(r_it.has_changed())
2996 {
2997 if(!new_operands.has_value())
2998 new_operands = expr.operands();
2999 (*new_operands)[i] = std::move(r_it.expr);
3000 }
3001 }
3002
3003 if(new_operands.has_value())
3004 {
3005 std::swap(result.expr.operands(), *new_operands);
3006 result.expr_changed = resultt<>::CHANGED;
3007 }
3008 }
3009
3010 if(as_const(result.expr).type().id() == ID_array)
3011 {
3012 const array_typet &array_type = to_array_type(as_const(result.expr).type());
3014 if(simp_size.has_changed())
3015 {
3016 to_array_type(result.expr.type()).size() = simp_size.expr;
3017 result.expr_changed = resultt<>::CHANGED;
3018 }
3019 }
3020
3021 return result;
3022}
3023
3025{
3026 if(!node.has_operands())
3027 return unchanged(node); // no change
3028
3029 // #define DEBUGX
3030
3031#ifdef DEBUGX
3032 exprt old(node);
3033#endif
3034
3035 exprt expr = node;
3037
3038 resultt<> r = unchanged(expr);
3039
3040 if(expr.id()==ID_typecast)
3041 {
3043 }
3044 else if(expr.id()==ID_equal || expr.id()==ID_notequal ||
3045 expr.id()==ID_gt || expr.id()==ID_lt ||
3046 expr.id()==ID_ge || expr.id()==ID_le)
3047 {
3049 }
3050 else if(expr.id()==ID_if)
3051 {
3052 r = simplify_if(to_if_expr(expr));
3053 }
3054 else if(expr.id()==ID_lambda)
3055 {
3057 }
3058 else if(expr.id()==ID_with)
3059 {
3060 r = simplify_with(to_with_expr(expr));
3061 }
3062 else if(expr.id()==ID_update)
3063 {
3065 }
3066 else if(expr.id()==ID_index)
3067 {
3069 }
3070 else if(expr.id()==ID_member)
3071 {
3073 }
3074 else if(expr.id()==ID_byte_update_little_endian ||
3076 {
3078 }
3079 else if(expr.id()==ID_byte_extract_little_endian ||
3081 {
3083 }
3084 else if(expr.id()==ID_pointer_object)
3085 {
3087 }
3088 else if(expr.id() == ID_is_dynamic_object)
3089 {
3091 }
3092 else if(expr.id() == ID_is_invalid_pointer)
3093 {
3095 }
3096 else if(
3098 {
3100 }
3101 else if(expr.id()==ID_div)
3102 {
3103 r = simplify_div(to_div_expr(expr));
3104 }
3105 else if(expr.id()==ID_mod)
3106 {
3107 r = simplify_mod(to_mod_expr(expr));
3108 }
3109 else if(expr.id()==ID_bitnot)
3110 {
3112 }
3113 else if(
3114 expr.id() == ID_bitand || expr.id() == ID_bitor || expr.id() == ID_bitxor ||
3115 expr.id() == ID_bitxnor)
3116 {
3118 }
3119 else if(expr.id()==ID_ashr || expr.id()==ID_lshr || expr.id()==ID_shl)
3120 {
3122 }
3123 else if(expr.id()==ID_power)
3124 {
3126 }
3127 else if(expr.id()==ID_plus)
3128 {
3129 r = simplify_plus(to_plus_expr(expr));
3130 }
3131 else if(expr.id()==ID_minus)
3132 {
3134 }
3135 else if(expr.id()==ID_mult)
3136 {
3137 r = simplify_mult(to_mult_expr(expr));
3138 }
3139 else if(expr.id()==ID_floatbv_plus ||
3140 expr.id()==ID_floatbv_minus ||
3141 expr.id()==ID_floatbv_mult ||
3142 expr.id()==ID_floatbv_div)
3143 {
3145 }
3146 else if(expr.id() == ID_floatbv_round_to_integral)
3147 {
3150 }
3151 else if(expr.id()==ID_floatbv_typecast)
3152 {
3154 }
3155 else if(expr.id()==ID_unary_minus)
3156 {
3158 }
3159 else if(expr.id()==ID_unary_plus)
3160 {
3162 }
3163 else if(expr.id()==ID_not)
3164 {
3165 r = simplify_not(to_not_expr(expr));
3166 }
3167 else if(expr.id()==ID_implies ||
3168 expr.id()==ID_or || expr.id()==ID_xor ||
3169 expr.id()==ID_and)
3170 {
3171 r = simplify_boolean(expr);
3172 }
3173 else if(expr.id()==ID_dereference)
3174 {
3176 }
3177 else if(expr.id()==ID_address_of)
3178 {
3180 }
3181 else if(expr.id()==ID_pointer_offset)
3182 {
3184 }
3185 else if(expr.id()==ID_extractbit)
3186 {
3188 }
3189 else if(expr.id()==ID_concatenation)
3190 {
3192 }
3193 else if(expr.id()==ID_extractbits)
3194 {
3196 }
3197 else if(expr.id() == ID_zero_extend)
3198 {
3200 }
3201 else if(expr.id()==ID_ieee_float_equal ||
3202 expr.id()==ID_ieee_float_notequal)
3203 {
3205 }
3206 else if(expr.id() == ID_bswap)
3207 {
3209 }
3210 else if(expr.id()==ID_isinf)
3211 {
3213 }
3214 else if(expr.id()==ID_isnan)
3215 {
3217 }
3218 else if(expr.id()==ID_isnormal)
3219 {
3221 }
3222 else if(expr.id()==ID_abs)
3223 {
3224 r = simplify_abs(to_abs_expr(expr));
3225 }
3226 else if(expr.id()==ID_sign)
3227 {
3228 r = simplify_sign(to_sign_expr(expr));
3229 }
3230 else if(expr.id() == ID_popcount)
3231 {
3233 }
3234 else if(expr.id() == ID_count_leading_zeros)
3235 {
3237 }
3238 else if(expr.id() == ID_count_trailing_zeros)
3239 {
3241 }
3242 else if(expr.id() == ID_find_first_set)
3243 {
3245 }
3246 else if(expr.id() == ID_function_application)
3247 {
3249 }
3250 else if(expr.id() == ID_complex_real || expr.id() == ID_complex_imag)
3251 {
3253 }
3254 else if(
3255 const auto binary_overflow =
3257 {
3259 }
3260 else if(
3261 const auto unary_overflow =
3263 {
3265 }
3266 else if(
3267 const auto overflow_result =
3269 {
3271 }
3272 else if(expr.id() == ID_bitreverse)
3273 {
3275 }
3276 else if(
3277 const auto prophecy_r_or_w_ok =
3279 {
3281 }
3282 else if(
3283 const auto prophecy_pointer_in_range =
3285 {
3287 }
3288 else if(expr.id() == ID_exists || expr.id() == ID_forall)
3289 {
3291 }
3292
3294 r = changed(r);
3295
3296#ifdef DEBUGX
3297 if(
3298 r.has_changed()
3300 && debug_on
3301# endif
3302 )
3303 {
3304 std::cout << "===== " << node.id() << ": " << format(node) << '\n'
3305 << " ---> " << format(r.expr) << '\n';
3306 }
3307#endif
3308
3309 return r;
3310}
3311
3313{
3314 // look up in cache
3315
3316 #ifdef USE_CACHE
3317 std::pair<simplify_expr_cachet::containert::iterator, bool>
3319 insert(std::pair<exprt, exprt>(expr, exprt()));
3320
3321 if(!cache_result.second) // found!
3322 {
3323 const exprt &new_expr=cache_result.first->second;
3324
3325 if(new_expr.id().empty())
3326 return true; // no change
3327
3328 expr=new_expr;
3329 return false;
3330 }
3331 #endif
3332
3333 // We work on a copy to prevent unnecessary destruction of sharing.
3335
3337
3338 if(
3339 !simplify_node_result.has_changed() &&
3340 simplify_node_preorder_result.has_changed())
3341 {
3342 simplify_node_result.expr_changed =
3343 simplify_node_preorder_result.expr_changed;
3344 }
3345
3346#ifdef USE_LOCAL_REPLACE_MAP
3348# if 1
3349 replace_mapt::const_iterator it =
3351 if(it!=local_replace_map.end())
3352 simplify_node_result = changed(it->second);
3353# else
3354 if(
3355 !local_replace_map.empty() &&
3357 {
3359 }
3360# endif
3361#endif
3362
3363 if(!simplify_node_result.has_changed())
3364 {
3365 return unchanged(expr);
3366 }
3367 else
3368 {
3370 (as_const(simplify_node_result.expr).type().id() == ID_array &&
3371 expr.type().id() == ID_array) ||
3372 as_const(simplify_node_result.expr).type() == expr.type(),
3373 simplify_node_result.expr.pretty(),
3374 expr.pretty());
3375
3376#ifdef USE_CACHE
3377 // save in cache
3378 cache_result.first->second = simplify_node_result.expr;
3379#endif
3380
3381 return simplify_node_result;
3382 }
3383}
3384
3387{
3388#ifdef DEBUG_ON_DEMAND
3389 if(debug_on)
3390 std::cout << "TO-SIMP " << format(expr) << "\n";
3391#endif
3392 auto result = simplify_rec(expr);
3393#ifdef DEBUG_ON_DEMAND
3394 if(debug_on)
3395 std::cout << "FULLSIMP " << format(result.expr) << "\n";
3396#endif
3397 if(result.has_changed())
3398 {
3399 expr = result.expr;
3400 return false; // change
3401 }
3402 else
3403 return true; // no change
3404}
3405
3407bool simplify(exprt &expr, const namespacet &ns)
3408{
3409 return simplify_exprt(ns).simplify(expr);
3410}
3411
3413{
3414 simplify_exprt(ns).simplify(src);
3415 return src;
3416}
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.
const T & as_const(T &value)
Return a reference to the same object but ensures the type is const.
Definition as_const.h:14
API to expression classes for bitvectors.
const shift_exprt & to_shift_expr(const exprt &expr)
Cast an exprt to a shift_exprt.
const popcount_exprt & to_popcount_expr(const exprt &expr)
Cast an exprt to a popcount_exprt.
const extractbits_exprt & to_extractbits_expr(const exprt &expr)
Cast an exprt to an extractbits_exprt.
const find_first_set_exprt & to_find_first_set_expr(const exprt &expr)
Cast an exprt to a find_first_set_exprt.
const bitnot_exprt & to_bitnot_expr(const exprt &expr)
Cast an exprt to a bitnot_exprt.
const bswap_exprt & to_bswap_expr(const exprt &expr)
Cast an exprt to a bswap_exprt.
const count_leading_zeros_exprt & to_count_leading_zeros_expr(const exprt &expr)
Cast an exprt to a count_leading_zeros_exprt.
const bitreverse_exprt & to_bitreverse_expr(const exprt &expr)
Cast an exprt to a bitreverse_exprt.
const extractbit_exprt & to_extractbit_expr(const exprt &expr)
Cast an exprt to an extractbit_exprt.
const concatenation_exprt & to_concatenation_expr(const exprt &expr)
Cast an exprt to a concatenation_exprt.
const zero_extend_exprt & to_zero_extend_expr(const exprt &expr)
Cast an exprt to a zero_extend_exprt.
const count_trailing_zeros_exprt & to_count_trailing_zeros_expr(const exprt &expr)
Cast an exprt to a count_trailing_zeros_exprt.
const bv_typet & to_bv_type(const typet &type)
Cast a typet to a bv_typet.
const fixedbv_typet & to_fixedbv_type(const typet &type)
Cast a typet to a fixedbv_typet.
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
const floatbv_typet & to_floatbv_type(const typet &type)
Cast a typet to a floatbv_typet.
void slice(symex_bmct &symex, symex_target_equationt &symex_target_equation, const namespacet &ns, const optionst &options, ui_message_handlert &ui_message_handler)
Definition bmc_util.cpp:176
Expression classes for byte-level operators.
const byte_update_exprt & to_byte_update_expr(const exprt &expr)
exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
Rewrite a byte extract expression to more fundamental operations.
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
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:430
Operator to return the address of an object.
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:566
ait()
Definition ai.h:569
Array constructor from list of elements.
Definition std_expr.h:1560
Arrays with given size.
Definition std_types.h:807
A base class for binary expressions.
Definition std_expr.h:639
exprt & op0()
Definition expr.h:134
exprt & op1()
Definition expr.h:137
A Boolean expression returning true, iff operation kind would result in an overflow when applied to o...
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition std_expr.h:774
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
const exprt & op() const
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
Determine whether an expression is constant.
Definition expr_util.h:87
struct configt::ansi_ct ansi_c
A constant literal expression.
Definition std_expr.h:2997
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
Union constructor to support unions without any member (a GCC/Clang feature).
Definition std_expr.h:1773
Base class for all expressions.
Definition expr.h:57
std::vector< exprt > operandst
Definition expr.h:59
bool has_operands() const
Return true if there is at least one operand.
Definition expr.h:92
bool is_constant() const
Return whether the expression is a constant.
Definition expr.h:213
typet & type()
Return the type of the expression.
Definition expr.h:85
operandst & operands()
Definition expr.h:95
const source_locationt & source_location() const
Definition expr.h:236
void add_to_operands(const exprt &expr)
Add the given argument to the end of exprt's operands.
Definition expr.h:171
Extracts a sub-range of a bit-vector operand.
The Boolean constant false.
Definition std_expr.h:3125
Returns one plus the index of the least-significant one bit, or zero if the operand is zero.
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 round(const fixedbv_spect &dest_spec)
Definition fixedbv.cpp:52
constant_exprt to_expr() const
Definition fixedbv.cpp:43
Fixed-width bit-vector with IEEE floating-point interpretation.
Application of (mathematical) function.
An IEEE 754 floating-point value, including specificiation.
Definition ieee_float.h:117
void set_sign(bool _sign)
Definition ieee_float.h:160
ieee_float_spect spec
Definition ieee_float.h:119
constant_exprt to_expr() const
mp_integer pack() const
bool get_sign() const
Definition ieee_float.h:254
An IEEE 754 value plus a rounding mode, enabling operations with rounding on values.
Definition ieee_float.h:338
mp_integer to_integer() const
void from_integer(const mp_integer &i)
void change_spec(const ieee_float_spect &dest_spec)
The trinary if-then-else operator.
Definition std_expr.h:2416
Array index operator.
Definition std_expr.h:1421
exprt & index()
Definition std_expr.h:1461
exprt & array()
Definition std_expr.h:1451
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 irep_idt & get(const irep_idt &name) const
Definition irep.cpp:44
const irep_idt & id() const
Definition irep.h:388
A (mathematical) lambda expression.
Extract member of struct or union.
Definition std_expr.h:2856
Binary multiplication Associativity is not specified.
Definition std_expr.h:1094
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
The NIL expression.
Definition std_expr.h:3134
The null pointer constant.
Boolean OR All operands must be boolean, and the result is always boolean.
Definition std_expr.h:2183
An expression returning both the result of the arithmetic operation under wrap-around semantics as we...
exprt & op0()
Definition expr.h:134
exprt & op1()
Definition expr.h:137
The plus expression Associativity is not specified.
Definition std_expr.h:996
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:602
Fixed-width bit-vector with two's complement interpretation.
resultt simplify_isnan(const unary_exprt &)
resultt simplify_bitwise(const multi_ary_exprt &)
const namespacet & ns
resultt simplify_quantifier_expr(const quantifier_exprt &)
Try to simplify exists/forall to a constant expression.
resultt simplify_div(const div_exprt &)
resultt simplify_byte_extract(const byte_extract_exprt &)
resultt simplify_bitreverse(const bitreverse_exprt &)
Try to simplify bit-reversing to a constant expression.
resultt simplify_abs(const abs_exprt &)
resultt simplify_isnormal(const unary_exprt &)
resultt simplify_dereference(const dereference_exprt &)
resultt simplify_bitnot(const bitnot_exprt &)
resultt simplify_zero_extend(const zero_extend_exprt &)
resultt simplify_prophecy_r_or_w_ok(const prophecy_r_or_w_ok_exprt &)
Try to simplify prophecy_{r,w,rw}_ok to a constant expression.
resultt simplify_member_preorder(const member_exprt &)
resultt simplify_popcount(const popcount_exprt &)
static resultt changed(resultt<> result)
resultt simplify_dereference_preorder(const dereference_exprt &)
resultt simplify_unary_pointer_predicate_preorder(const unary_exprt &)
resultt simplify_address_of(const address_of_exprt &)
resultt simplify_if(const if_exprt &)
resultt simplify_node(const exprt &)
resultt simplify_node_preorder(const exprt &)
resultt simplify_prophecy_pointer_in_range(const prophecy_pointer_in_range_exprt &)
Try to simplify prophecy_pointer_in_range to a constant expression.
resultt simplify_overflow_unary(const unary_overflow_exprt &)
Try to simplify overflow-unary-.
resultt simplify_minus(const minus_exprt &)
resultt simplify_extractbit(const extractbit_exprt &)
resultt simplify_rec(const exprt &)
resultt simplify_shifts(const shift_exprt &)
resultt simplify_index_preorder(const index_exprt &)
resultt simplify_typecast(const typecast_exprt &)
resultt simplify_pointer_object(const pointer_object_exprt &)
resultt simplify_boolean(const exprt &)
resultt simplify_object(const exprt &)
resultt simplify_mult(const mult_exprt &)
resultt simplify_floatbv_typecast(const floatbv_typecast_exprt &)
resultt simplify_with(const with_exprt &)
virtual resultt simplify_inequality(const binary_relation_exprt &)
simplifies inequalities !=, <=, <, >=, >, and also ==
resultt simplify_not(const not_exprt &)
resultt simplify_isinf(const unary_exprt &)
resultt simplify_overflow_binary(const binary_overflow_exprt &)
Try to simplify overflow-+, overflow-*, overflow–, overflow-shl.
resultt simplify_function_application(const function_application_exprt &)
Attempt to simplify mathematical function applications if we have enough information to do so.
resultt simplify_index(const index_exprt &)
resultt simplify_bswap(const bswap_exprt &)
resultt simplify_member(const member_exprt &)
static resultt unchanged(exprt expr)
resultt simplify_byte_update(const byte_update_exprt &)
resultt simplify_extractbits(const extractbits_exprt &)
Simplifies extracting of bits from a constant.
resultt simplify_update(const update_exprt &)
resultt simplify_is_invalid_pointer(const unary_exprt &)
resultt simplify_mod(const mod_exprt &)
resultt simplify_complex(const unary_exprt &)
virtual resultt simplify_pointer_offset(const pointer_offset_exprt &)
resultt simplify_plus(const plus_exprt &)
virtual bool simplify(exprt &expr)
resultt simplify_unary_plus(const unary_plus_exprt &)
resultt simplify_overflow_result(const overflow_result_exprt &)
Try to simplify overflow_result-+, overflow_result-*, overflow_result–, overflow_result-shl,...
resultt simplify_ffs(const find_first_set_exprt &)
Try to simplify find-first-set to a constant expression.
resultt simplify_if_preorder(const if_exprt &expr)
resultt simplify_byte_extract_preorder(const byte_extract_exprt &)
resultt simplify_is_dynamic_object(const unary_exprt &)
resultt simplify_power(const power_exprt &)
resultt simplify_object_size(const object_size_exprt &)
resultt simplify_lambda(const lambda_exprt &)
resultt simplify_concatenation(const concatenation_exprt &)
resultt simplify_floatbv_op(const ieee_float_op_exprt &)
resultt simplify_ctz(const count_trailing_zeros_exprt &)
Try to simplify count-trailing-zeros to a constant expression.
resultt simplify_clz(const count_leading_zeros_exprt &)
Try to simplify count-leading-zeros to a constant expression.
resultt simplify_ieee_float_relation(const binary_relation_exprt &)
resultt simplify_typecast_preorder(const typecast_exprt &)
resultt simplify_sign(const sign_exprt &)
resultt simplify_unary_minus(const unary_minus_exprt &)
resultt simplify_floatbv_round_to_integral(const floatbv_round_to_integral_exprt &)
Struct constructor from list of elements.
Definition std_expr.h:1810
Structure type, corresponds to C style structs.
Definition std_types.h:231
std::vector< componentt > componentst
Definition std_types.h:140
The Boolean constant true.
Definition std_expr.h:3116
Semantic type conversion.
Definition std_expr.h:1985
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition std_expr.h:1993
The type of an expression, extends irept.
Definition type.h:29
Generic base class for unary expressions.
Definition std_expr.h:354
const exprt & op() const
Definition std_expr.h:384
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:1714
The union type.
Definition c_types.h:147
Fixed-width bit-vector with unsigned binary interpretation.
Operator to update elements in structs and arrays.
Definition std_expr.h:2669
exprt & old()
Definition std_expr.h:2681
exprt::operandst & designator()
Definition std_expr.h:2695
exprt & new_value()
Definition std_expr.h:2705
Operator to update elements in structs and arrays.
Definition std_expr.h:2510
exprt & new_value()
Definition std_expr.h:2540
exprt & where()
Definition std_expr.h:2530
exprt & old()
Definition std_expr.h:2520
int isalpha(int c)
Definition ctype.c:9
int tolower(int c)
Definition ctype.c:109
int isupper(int c)
Definition ctype.c:90
#define Forall_operands(it, expr)
Definition expr.h:28
constant_exprt make_boolean_expr(bool value)
returns true_exprt if given true and false_exprt otherwise
exprt is_not_zero(const exprt &src, const namespacet &ns)
converts a scalar/float expression to C/C++ Booleans
Definition expr_util.cpp:69
const exprt & skip_typecast(const exprt &expr)
find the expression nested inside typecasts, if any
if_exprt lift_if(const exprt &src, std::size_t operand_number)
lift up an if_exprt one level
bool has_subtype(const typet &type, const std::function< bool(const typet &)> &pred, const namespacet &ns)
returns true if any of the contained types satisfies pred
Deprecated expression utility functions.
API to expression classes for floating-point arithmetic.
const ieee_float_op_exprt & to_ieee_float_op_expr(const exprt &expr)
Cast an exprt to an ieee_float_op_exprt.
const floatbv_round_to_integral_exprt & to_floatbv_round_to_integral_expr(const exprt &expr)
Cast an exprt to a floatbv_round_to_integral_exprt.
const floatbv_typecast_exprt & to_floatbv_typecast_expr(const exprt &expr)
Cast an exprt to a floatbv_typecast_exprt.
static format_containert< T > format(const T &o)
Definition format.h:37
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
static int8_t r
Definition irep_hash.h:60
API to expression classes for 'mathematical' expressions.
const quantifier_exprt & to_quantifier_expr(const exprt &expr)
Cast an exprt to a quantifier_exprt.
const power_exprt & to_power_expr(const exprt &expr)
Cast an exprt to a power_exprt.
const function_application_exprt & to_function_application_expr(const exprt &expr)
Cast an exprt to a function_application_exprt.
const lambda_exprt & to_lambda_expr(const exprt &expr)
Cast an exprt to a lambda_exprt.
const mp_integer string2integer(const std::string &n, unsigned base)
Definition mp_arith.cpp:54
API to expression classes for Pointers.
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
const pointer_offset_exprt & to_pointer_offset_expr(const exprt &expr)
Cast an exprt to a pointer_offset_exprt.
const pointer_object_exprt & to_pointer_object_expr(const exprt &expr)
Cast an exprt to a pointer_object_exprt.
std::optional< mp_integer > pointer_offset_size(const typet &type, const namespacet &ns)
Compute the size of a type in bytes, rounding up to full bytes.
std::optional< exprt > get_subexpression_at_offset(const exprt &expr, const mp_integer &offset_bytes, const typet &target_type_raw, const namespacet &ns)
std::optional< mp_integer > pointer_offset_bits(const typet &type, const namespacet &ns)
std::optional< mp_integer > member_offset(const struct_typet &type, const irep_idt &member, const namespacet &ns)
std::optional< exprt > member_offset_expr(const member_exprt &member_expr, const namespacet &ns)
Pointer Logic.
exprt pointer_offset_sum(const exprt &a, const exprt &b)
Pointer Dereferencing.
exprt object_size(const exprt &pointer)
constant_exprt from_rational(const rationalt &a)
bool replace_expr(const exprt &what, const exprt &by, exprt &dest)
bool simplify(exprt &expr, const namespacet &ns)
static simplify_exprt::resultt simplify_string_compare_to(const function_application_exprt &expr, const namespacet &ns)
Simplify String.compareTo function when arguments are constant.
static simplify_exprt::resultt simplify_string_contains(const function_application_exprt &expr, const namespacet &ns)
Simplify String.contains function when arguments are constant.
static simplify_exprt::resultt simplify_string_endswith(const function_application_exprt &expr, const namespacet &ns)
Simplify String.endsWith function when arguments are constant.
static simplify_exprt::resultt simplify_string_char_at(const function_application_exprt &expr, const namespacet &ns)
Simplify String.charAt function when arguments are constant.
static simplify_exprt::resultt simplify_string_startswith(const function_application_exprt &expr, const namespacet &ns)
Simplify String.startsWith function when arguments are constant.
static simplify_exprt::resultt simplify_string_is_empty(const function_application_exprt &expr, const namespacet &ns)
Simplify String.isEmpty function when arguments are constant.
static bool lower_case_string_expression(array_exprt &string_data)
Take the passed-in constant string array and lower-case every character.
static simplify_exprt::resultt simplify_string_index_of(const function_application_exprt &expr, const namespacet &ns, const bool search_from_end)
Simplify String.indexOf function when arguments are constant.
static simplify_exprt::resultt simplify_string_equals_ignore_case(const function_application_exprt &expr, const namespacet &ns)
Simplify String.equalsIgnorecase function when arguments are constant.
exprt simplify_expr(exprt src, const namespacet &ns)
std::optional< exprt > bits2expr(const std::string &bits, const typet &type, bool little_endian, const namespacet &ns)
std::optional< std::string > expr2bits(const exprt &expr, bool little_endian, const namespacet &ns)
std::optional< std::reference_wrapper< const array_exprt > > try_get_string_data_array(const exprt &content, const namespacet &ns)
Get char sequence from content field of a refined string expression.
bool join_operands(exprt &expr)
BigInt mp_integer
Definition smt_terms.h:17
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#define UNREACHABLE
This should be used to mark dead code.
Definition invariant.h:525
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition invariant.h:534
#define POSTCONDITION_WITH_DIAGNOSTICS(CONDITION,...)
Definition invariant.h:480
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition std_expr.cpp:291
API to expression classes.
const struct_exprt & to_struct_expr(const exprt &expr)
Cast an exprt to a struct_exprt.
Definition std_expr.h:1833
const array_of_exprt & to_array_of_expr(const exprt &expr)
Cast an exprt to an array_of_exprt.
Definition std_expr.h:1542
const binary_relation_exprt & to_binary_relation_expr(const exprt &expr)
Cast an exprt to a binary_relation_exprt.
Definition std_expr.h:818
const unary_plus_exprt & to_unary_plus_expr(const exprt &expr)
Cast an exprt to a unary_plus_exprt.
Definition std_expr.h:529
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1484
const mod_exprt & to_mod_expr(const exprt &expr)
Cast an exprt to a mod_exprt.
Definition std_expr.h:1250
const mult_exprt & to_mult_expr(const exprt &expr)
Cast an exprt to a mult_exprt.
Definition std_expr.h:1124
const array_exprt & to_array_expr(const exprt &expr)
Cast an exprt to an array_exprt.
Definition std_expr.h:1604
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2014
const div_exprt & to_div_expr(const exprt &expr)
Cast an exprt to a div_exprt.
Definition std_expr.h:1186
const plus_exprt & to_plus_expr(const exprt &expr)
Cast an exprt to a plus_exprt.
Definition std_expr.h:1035
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition std_expr.h:414
const multi_ary_exprt & to_multi_ary_expr(const exprt &expr)
Cast an exprt to a multi_ary_exprt.
Definition std_expr.h:981
const abs_exprt & to_abs_expr(const exprt &expr)
Cast an exprt to a abs_exprt.
Definition std_expr.h:449
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition std_expr.h:2491
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:2943
const minus_exprt & to_minus_expr(const exprt &expr)
Cast an exprt to a minus_exprt.
Definition std_expr.h:1075
const complex_imag_exprt & to_complex_imag_expr(const exprt &expr)
Cast an exprt to a complex_imag_exprt.
Definition std_expr.h:1967
const index_designatort & to_index_designator(const exprt &expr)
Cast an exprt to an index_designatort.
Definition std_expr.h:2609
const complex_real_exprt & to_complex_real_expr(const exprt &expr)
Cast an exprt to a complex_real_exprt.
Definition std_expr.h:1930
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3068
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
Definition std_expr.h:2398
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:211
const with_exprt & to_with_expr(const exprt &expr)
Cast an exprt to a with_exprt.
Definition std_expr.h:2563
const complex_exprt & to_complex_expr(const exprt &expr)
Cast an exprt to a complex_exprt.
Definition std_expr.h:1893
const update_exprt & to_update_expr(const exprt &expr)
Cast an exprt to an update_exprt.
Definition std_expr.h:2752
const unary_minus_exprt & to_unary_minus_expr(const exprt &expr)
Cast an exprt to a unary_minus_exprt.
Definition std_expr.h:492
const sign_exprt & to_sign_expr(const exprt &expr)
Cast an exprt to a sign_exprt.
Definition std_expr.h:622
bool is_constant(const typet &type)
This method tests, if the given typet is a constant.
Definition std_types.h:29
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)
static bool failed(bool error_indicator)
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition type.h:208
#define size_type
Definition unistd.c:186