CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
invariant_set.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Invariant Set
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
11
12#include "invariant_set.h"
13
14#include <util/arith_tools.h>
15#include <util/byte_operators.h>
16#include <util/expr_util.h>
17#include <util/namespace.h>
18#include <util/pointer_expr.h>
19#include <util/simplify_expr.h>
20#include <util/std_code_base.h>
21
23
24#include <iostream>
25
26void inv_object_storet::output(std::ostream &out) const
27{
28 for(std::size_t i=0; i<entries.size(); i++)
29 out << "STORE " << i << ": " << map[i] << '\n';
30}
31
32bool inv_object_storet::get(const exprt &expr, unsigned &n)
33{
34 std::string s=build_string(expr);
35 if(s.empty())
36 return true;
37
38 // if it's a constant, we add it in any case
39 if(is_constant(expr))
40 {
41 n=map.number(s);
42
43 if(n>=entries.size())
44 {
45 entries.resize(n+1);
46 entries[n].expr=expr;
47 entries[n].is_constant=true;
48 }
49
50 return false;
51 }
52
53 if(const auto number = map.get_number(s))
54 {
55 n = *number;
56 return false;
57 }
58 return true;
59}
60
61unsigned inv_object_storet::add(const exprt &expr)
62{
63 std::string s=build_string(expr);
64 CHECK_RETURN(!s.empty());
65
67
68 if(n>=entries.size())
69 {
70 entries.resize(n+1);
71 entries[n].expr=expr;
73 }
74
75 return n;
76}
77
79{
80 PRECONDITION(n < entries.size());
81 return entries[n].is_constant;
82}
83
85{
86 return expr.is_constant() ||
88}
89
90std::string inv_object_storet::build_string(const exprt &expr) const
91{
92 // we ignore some casts
93 if(expr.id()==ID_typecast)
94 {
95 const auto &typecast_expr = to_typecast_expr(expr);
96
97 if(
98 typecast_expr.type().id() == ID_signedbv ||
99 typecast_expr.type().id() == ID_unsignedbv)
100 {
101 const typet &op_type = typecast_expr.op().type();
102
103 if(op_type.id() == ID_signedbv || op_type.id() == ID_unsignedbv)
104 {
105 if(
106 to_bitvector_type(typecast_expr.type()).get_width() >=
107 to_bitvector_type(op_type).get_width())
108 {
109 return build_string(typecast_expr.op());
110 }
111 }
112 else if(op_type.id() == ID_bool)
113 {
114 return build_string(typecast_expr.op());
115 }
116 }
117 }
118
119 // we always track constants, but make sure they are uniquely
120 // represented
121 if(expr.is_constant())
122 {
123 // NULL?
125 return "0";
126
127 const auto i = numeric_cast<mp_integer>(expr);
128 if(i.has_value())
129 return integer2string(*i);
130 }
131
132 // we also like "address_of" if the object is constant
133 // we don't know what mode (language) we are in, so we rely on the default
134 // language to be reasonable for from_expr
135 if(is_constant_address(expr))
136 return from_expr(ns, irep_idt(), expr);
137
138 if(expr.id()==ID_member)
139 {
140 return build_string(to_member_expr(expr).compound()) + "." +
142 }
143
144 if(expr.id()==ID_symbol)
145 return id2string(to_symbol_expr(expr).get_identifier());
146
147 return "";
148}
149
151 const exprt &expr,
152 unsigned &n) const
153{
154 return object_store.get(expr, n);
155}
156
158{
159 if(expr.id()==ID_address_of)
160 return is_constant_address_rec(to_address_of_expr(expr).object());
161
162 return false;
163}
164
166{
167 if(expr.id()==ID_symbol)
168 return true;
169 else if(expr.id()==ID_member)
170 return is_constant_address_rec(to_member_expr(expr).compound());
171 else if(expr.id()==ID_index)
172 {
173 const auto &index_expr = to_index_expr(expr);
174 if(index_expr.index().is_constant())
175 return is_constant_address_rec(index_expr.array());
176 }
177
178 return false;
179}
180
182 const std::pair<unsigned, unsigned> &p,
183 ineq_sett &dest)
184{
185 eq_set.check_index(p.first);
186 eq_set.check_index(p.second);
187
188 // add all. Quadratic.
189 unsigned f_r=eq_set.find(p.first);
190 unsigned s_r=eq_set.find(p.second);
191
192 for(std::size_t f=0; f<eq_set.size(); f++)
193 {
194 if(eq_set.find(f)==f_r)
195 {
196 for(std::size_t s=0; s<eq_set.size(); s++)
197 if(eq_set.find(s)==s_r)
198 dest.insert(std::pair<unsigned, unsigned>(f, s));
199 }
200 }
201}
202
203void invariant_sett::add_eq(const std::pair<unsigned, unsigned> &p)
204{
205 eq_set.make_union(p.first, p.second);
206
207 // check if there is a contradiction with two constants
208 unsigned r=eq_set.find(p.first);
209
210 bool constant_seen=false;
212
213 for(std::size_t i=0; i<eq_set.size(); i++)
214 {
215 if(eq_set.find(i)==r)
216 {
218 {
219 if(constant_seen)
220 {
221 // contradiction
222 make_false();
223 return;
224 }
225 else
226 constant_seen=true;
227 }
228 }
229 }
230
231 // replicate <= and != constraints
232
233 for(const auto &le : le_set)
234 add_eq(le_set, p, le);
235
236 for(const auto &ne : ne_set)
237 add_eq(ne_set, p, ne);
238}
239
241 ineq_sett &dest,
242 const std::pair<unsigned, unsigned> &eq,
243 const std::pair<unsigned, unsigned> &ineq)
244{
245 std::pair<unsigned, unsigned> n;
246
247 // uhuh. Need to try all pairs
248
249 if(eq.first==ineq.first)
250 {
251 n=ineq;
252 n.first=eq.second;
253 dest.insert(n);
254 }
255
256 if(eq.first==ineq.second)
257 {
258 n=ineq;
259 n.second=eq.second;
260 dest.insert(n);
261 }
262
263 if(eq.second==ineq.first)
264 {
265 n=ineq;
266 n.first=eq.first;
267 dest.insert(n);
268 }
269
270 if(eq.second==ineq.second)
271 {
272 n=ineq;
273 n.second=eq.first;
274 dest.insert(n);
275 }
276}
277
278tvt invariant_sett::is_eq(std::pair<unsigned, unsigned> p) const
279{
280 std::pair<unsigned, unsigned> s=p;
281 std::swap(s.first, s.second);
282
283 if(has_eq(p))
284 return tvt(true);
285
286 if(has_ne(p) || has_ne(s))
287 return tvt(false);
288
289 return tvt::unknown();
290}
291
292tvt invariant_sett::is_le(std::pair<unsigned, unsigned> p) const
293{
294 std::pair<unsigned, unsigned> s=p;
295 std::swap(s.first, s.second);
296
297 if(has_eq(p))
298 return tvt(true);
299
300 if(has_le(p))
301 return tvt(true);
302
303 if(has_le(s))
304 if(has_ne(s) || has_ne(p))
305 return tvt(false);
306
307 return tvt::unknown();
308}
309
310void invariant_sett::output(std::ostream &out) const
311{
312 if(is_false)
313 {
314 out << "FALSE\n";
315 return;
316 }
317
318 for(std::size_t i=0; i<eq_set.size(); i++)
319 if(eq_set.is_root(i) &&
320 eq_set.count(i)>=2)
321 {
322 bool first=true;
323 for(std::size_t j=0; j<eq_set.size(); j++)
324 if(eq_set.find(j)==i)
325 {
326 if(first)
327 first=false;
328 else
329 out << " = ";
330
331 out << to_string(j);
332 }
333
334 out << '\n';
335 }
336
337 for(const auto &bounds : bounds_map)
338 {
339 out << to_string(bounds.first) << " in " << bounds.second << '\n';
340 }
341
342 for(const auto &le : le_set)
343 {
344 out << to_string(le.first) << " <= " << to_string(le.second) << '\n';
345 }
346
347 for(const auto &ne : ne_set)
348 {
349 out << to_string(ne.first) << " != " << to_string(ne.second) << '\n';
350 }
351}
352
353void invariant_sett::add_type_bounds(const exprt &expr, const typet &type)
354{
355 if(expr.type()==type)
356 return;
357
358 if(type.id()==ID_unsignedbv)
359 {
360 std::size_t op_width=to_unsignedbv_type(type).get_width();
361
362 // TODO - 8 appears to be a magic number here -- or perhaps this should say
363 // ">=" instead, and is meant to restrict types larger than a single byte?
364 if(op_width<=8)
365 {
366 unsigned a;
367 if(get_object(expr, a))
368 return;
369
370 add_bounds(a, boundst(0, power(2, op_width)-1));
371 }
372 }
373}
374
376{
377 exprt tmp(expr);
378 nnf(tmp);
380}
381
383{
384 if(!expr.is_boolean())
385 throw "non-Boolean argument to strengthen()";
386
387 #if 0
388 std::cout << "S: " << from_expr(*ns, irep_idt(), expr) << '\n';
389#endif
390
391 if(is_false)
392 {
393 // we can't get any stronger
394 return;
395 }
396
397 if(expr.is_true())
398 {
399 // do nothing, it's useless
400 }
401 else if(expr.is_false())
402 {
403 // wow, that's strong
404 make_false();
405 }
406 else if(expr.id()==ID_not)
407 {
408 // give up, we expect NNF
409 }
410 else if(expr.id()==ID_and)
411 {
412 for(const auto &op : expr.operands())
413 strengthen_rec(op);
414 }
415 else if(expr.id()==ID_le ||
416 expr.id()==ID_lt)
417 {
418 const auto &rel = to_binary_relation_expr(expr);
419
420 // special rule: x <= (a & b)
421 // implies: x<=a && x<=b
422
423 if(rel.rhs().id() == ID_bitand)
424 {
425 const exprt &bitand_op = rel.op1();
426
427 for(const auto &op : bitand_op.operands())
428 {
429 auto tmp(rel);
430 tmp.op1() = op;
432 }
433
434 return;
435 }
436
437 std::pair<unsigned, unsigned> p;
438
439 if(get_object(rel.op0(), p.first) || get_object(rel.op1(), p.second))
440 return;
441
442 const auto i0 = numeric_cast<mp_integer>(rel.op0());
443 const auto i1 = numeric_cast<mp_integer>(rel.op1());
444
445 if(expr.id()==ID_le)
446 {
447 if(i0.has_value())
448 add_bounds(p.second, lower_interval(*i0));
449 else if(i1.has_value())
450 add_bounds(p.first, upper_interval(*i1));
451 else
452 add_le(p);
453 }
454 else if(expr.id()==ID_lt)
455 {
456 if(i0.has_value())
457 add_bounds(p.second, lower_interval(*i0 + 1));
458 else if(i1.has_value())
459 add_bounds(p.first, upper_interval(*i1 - 1));
460 else
461 {
462 add_le(p);
463 add_ne(p);
464 }
465 }
466 else
468 }
469 else if(expr.id()==ID_equal)
470 {
471 const auto &equal_expr = to_equal_expr(expr);
472
473 const typet &op_type = equal_expr.op0().type();
474
475 if(op_type.id() == ID_struct || op_type.id() == ID_struct_tag)
476 {
479 : ns.follow_tag(to_struct_tag_type(op_type));
480
481 for(const auto &comp : struct_type.components())
482 {
484 equal_expr.op0(), comp.get_name(), comp.type());
486 equal_expr.op1(), comp.get_name(), comp.type());
487
489
490 // recursive call
491 strengthen_rec(equality);
492 }
493
494 return;
495 }
496
497 // special rule: x = (a & b)
498 // implies: x<=a && x<=b
499
500 if(equal_expr.op1().id() == ID_bitand)
501 {
502 const exprt &bitand_op = equal_expr.op1();
503
504 for(const auto &op : bitand_op.operands())
505 {
506 auto tmp(equal_expr);
507 tmp.op1() = op;
508 tmp.id(ID_le);
510 }
511
512 return;
513 }
514 else if(equal_expr.op0().id() == ID_bitand)
515 {
516 auto tmp(equal_expr);
517 std::swap(tmp.op0(), tmp.op1());
519 return;
520 }
521
522 // special rule: x = (type) y
523 if(equal_expr.op1().id() == ID_typecast)
524 {
525 const auto &typecast_expr = to_typecast_expr(equal_expr.op1());
526 add_type_bounds(equal_expr.op0(), typecast_expr.op().type());
527 }
528 else if(equal_expr.op0().id() == ID_typecast)
529 {
530 const auto &typecast_expr = to_typecast_expr(equal_expr.op0());
531 add_type_bounds(equal_expr.op1(), typecast_expr.op().type());
532 }
533
534 std::pair<unsigned, unsigned> p, s;
535
536 if(
537 get_object(equal_expr.op0(), p.first) ||
538 get_object(equal_expr.op1(), p.second))
539 {
540 return;
541 }
542
543 const auto i0 = numeric_cast<mp_integer>(equal_expr.op0());
544 const auto i1 = numeric_cast<mp_integer>(equal_expr.op1());
545 if(i0.has_value())
546 add_bounds(p.second, boundst(*i0));
547 else if(i1.has_value())
548 add_bounds(p.first, boundst(*i1));
549
550 s=p;
551 std::swap(s.first, s.second);
552
553 // contradiction?
554 if(has_ne(p) || has_ne(s))
555 make_false();
556 else if(!has_eq(p))
557 add_eq(p);
558 }
559 else if(expr.id()==ID_notequal)
560 {
561 const auto &notequal_expr = to_notequal_expr(expr);
562
563 std::pair<unsigned, unsigned> p;
564
565 if(
566 get_object(notequal_expr.op0(), p.first) ||
567 get_object(notequal_expr.op1(), p.second))
568 {
569 return;
570 }
571
572 // check if this is a contradiction
573 if(has_eq(p))
574 make_false();
575 else
576 add_ne(p);
577 }
578}
579
581{
582 exprt tmp(expr);
583 nnf(tmp);
584 return implies_rec(tmp);
585}
586
588{
589 if(!expr.is_boolean())
590 throw "implies: non-Boolean expression";
591
592 #if 0
593 std::cout << "I: " << from_expr(*ns, irep_idt(), expr) << '\n';
594#endif
595
596 if(is_false) // can't get any stronger
597 return tvt(true);
598
599 if(expr.is_true())
600 return tvt(true);
601 else if(expr.id()==ID_not)
602 {
603 // give up, we expect NNF
604 }
605 else if(expr.id()==ID_and)
606 {
607 for(const auto &op : expr.operands())
608 {
609 if(implies_rec(op) != tvt(true))
610 return tvt::unknown();
611 }
612
613 return tvt(true);
614 }
615 else if(expr.id()==ID_or)
616 {
617 for(const auto &op : expr.operands())
618 {
619 if(implies_rec(op) == tvt(true))
620 return tvt(true);
621 }
622 }
623 else if(expr.id()==ID_le ||
624 expr.id()==ID_lt ||
625 expr.id()==ID_equal ||
626 expr.id()==ID_notequal)
627 {
628 const auto &rel = to_binary_relation_expr(expr);
629
630 std::pair<unsigned, unsigned> p;
631
632 bool ob0 = get_object(rel.lhs(), p.first);
633 bool ob1 = get_object(rel.rhs(), p.second);
634
635 if(ob0 || ob1)
636 return tvt::unknown();
637
638 tvt r;
639
640 if(rel.id() == ID_le)
641 {
642 r=is_le(p);
643 if(!r.is_unknown())
644 return r;
645
646 boundst b0, b1;
647 get_bounds(p.first, b0);
648 get_bounds(p.second, b1);
649
650 return b0<=b1;
651 }
652 else if(rel.id() == ID_lt)
653 {
654 r=is_lt(p);
655 if(!r.is_unknown())
656 return r;
657
658 boundst b0, b1;
659 get_bounds(p.first, b0);
660 get_bounds(p.second, b1);
661
662 return b0<b1;
663 }
664 else if(rel.id() == ID_equal)
665 return is_eq(p);
666 else if(rel.id() == ID_notequal)
667 return is_ne(p);
668 else
670 }
671
672 return tvt::unknown();
673}
674
676{
677 // unbounded
678 bounds=boundst();
679
680 {
681 const exprt &e_a = object_store.get_expr(a);
682 const auto tmp = numeric_cast<mp_integer>(e_a);
683 if(tmp.has_value())
684 {
685 bounds = boundst(*tmp);
686 return;
687 }
688
689 if(e_a.type().id()==ID_unsignedbv)
691 }
692
693 bounds_mapt::const_iterator it=bounds_map.find(a);
694
695 if(it!=bounds_map.end())
696 bounds=it->second;
697}
698
699void invariant_sett::nnf(exprt &expr, bool negate)
700{
701 if(!expr.is_boolean())
702 throw "nnf: non-Boolean expression";
703
704 if(expr.is_true())
705 {
706 if(negate)
707 expr=false_exprt();
708 }
709 else if(expr.is_false())
710 {
711 if(negate)
712 expr=true_exprt();
713 }
714 else if(expr.id()==ID_not)
715 {
716 nnf(to_not_expr(expr).op(), !negate);
717 exprt tmp;
718 tmp.swap(to_not_expr(expr).op());
719 expr.swap(tmp);
720 }
721 else if(expr.id()==ID_and)
722 {
723 if(negate)
724 expr.id(ID_or);
725
726 Forall_operands(it, expr)
727 nnf(*it, negate);
728 }
729 else if(expr.id()==ID_or)
730 {
731 if(negate)
732 expr.id(ID_and);
733
734 Forall_operands(it, expr)
735 nnf(*it, negate);
736 }
737 else if(expr.id()==ID_typecast)
738 {
739 const auto &typecast_expr = to_typecast_expr(expr);
740
741 if(
742 typecast_expr.op().type().id() == ID_unsignedbv ||
743 typecast_expr.op().type().id() == ID_signedbv)
744 {
746 typecast_expr.op(), from_integer(0, typecast_expr.op().type()));
747 nnf(tmp, !negate);
748 expr.swap(tmp);
749 }
750 else if(negate)
751 {
752 expr = boolean_negate(expr);
753 }
754 }
755 else if(expr.id()==ID_le)
756 {
757 if(negate)
758 {
759 // !a<=b <-> !b=>a <-> b<a
760 expr.id(ID_lt);
761 auto &rel = to_binary_relation_expr(expr);
762 std::swap(rel.lhs(), rel.rhs());
763 }
764 }
765 else if(expr.id()==ID_lt)
766 {
767 if(negate)
768 {
769 // !a<b <-> !b>a <-> b<=a
770 expr.id(ID_le);
771 auto &rel = to_binary_relation_expr(expr);
772 std::swap(rel.lhs(), rel.rhs());
773 }
774 }
775 else if(expr.id()==ID_ge)
776 {
777 if(negate)
778 expr.id(ID_lt);
779 else
780 {
781 expr.id(ID_le);
782 auto &rel = to_binary_relation_expr(expr);
783 std::swap(rel.lhs(), rel.rhs());
784 }
785 }
786 else if(expr.id()==ID_gt)
787 {
788 if(negate)
789 expr.id(ID_le);
790 else
791 {
792 expr.id(ID_lt);
793 auto &rel = to_binary_relation_expr(expr);
794 std::swap(rel.lhs(), rel.rhs());
795 }
796 }
797 else if(expr.id()==ID_equal)
798 {
799 if(negate)
800 expr.id(ID_notequal);
801 }
802 else if(expr.id()==ID_notequal)
803 {
804 if(negate)
805 expr.id(ID_equal);
806 }
807 else if(negate)
808 {
809 expr = boolean_negate(expr);
810 }
811}
812
814 exprt &expr) const
815{
816 if(expr.id()==ID_address_of)
817 return;
818
819 Forall_operands(it, expr)
820 simplify(*it);
821
822 if(expr.id()==ID_symbol ||
823 expr.id()==ID_member)
824 {
825 exprt tmp=get_constant(expr);
826 if(tmp.is_not_nil())
827 expr.swap(tmp);
828 }
829}
830
832{
833 unsigned a;
834
835 if(!get_object(expr, a))
836 {
837 // bounds?
838 bounds_mapt::const_iterator it=bounds_map.find(a);
839
840 if(it!=bounds_map.end())
841 {
842 if(it->second.singleton())
843 return from_integer(it->second.get_lower(), expr.type());
844 }
845
846 unsigned r=eq_set.find(a);
847
848 // is it a constant?
849 for(std::size_t i=0; i<eq_set.size(); i++)
850 if(eq_set.find(i)==r)
851 {
852 const exprt &e = object_store.get_expr(i);
853
854 if(e.is_constant())
855 {
856 const mp_integer value =
858
859 if(expr.type().id()==ID_pointer)
860 {
861 if(value==0)
863 }
864 else
865 return from_integer(value, expr.type());
866 }
868 {
869 if(e.type()==expr.type())
870 return e;
871
872 return typecast_exprt(e, expr.type());
873 }
874 }
875 }
876
877 return static_cast<const exprt &>(get_nil_irep());
878}
879
880std::string inv_object_storet::to_string(unsigned a) const
881{
882 return id2string(map[a]);
883}
884
885std::string invariant_sett::to_string(unsigned a) const
886{
887 return object_store.to_string(a);
888}
889
891{
892 if(other.threaded &&
893 !threaded)
894 {
896 return true; // change
897 }
898
899 if(threaded)
900 return false; // no change
901
902 if(other.is_false)
903 return false; // no change
904
905 if(is_false)
906 {
907 // copy
908 is_false=false;
909 eq_set=other.eq_set;
910 le_set=other.le_set;
911 ne_set=other.ne_set;
913
914 return true; // change
915 }
916
917 // equalities first
919
921
922 // inequalities
923 std::size_t old_ne_set=ne_set.size();
924 std::size_t old_le_set=le_set.size();
925
926 intersection(ne_set, other.ne_set);
927 intersection(le_set, other.le_set);
928
929 // bounds
931 return true;
932
934 old_ne_set!=ne_set.size() ||
935 old_le_set!=le_set.size())
936 return true;
937
938 return false; // no change
939}
940
942{
943 bool changed=false;
944
945 for(bounds_mapt::iterator
946 it=bounds_map.begin();
947 it!=bounds_map.end();
948 ) // no it++
949 {
950 bounds_mapt::const_iterator o_it=other.find(it->first);
951
952 if(o_it==other.end())
953 {
954 bounds_mapt::iterator next(it);
955 next++;
956 bounds_map.erase(it);
957 it=next;
958 changed=true;
959 }
960 else
961 {
962 boundst old(it->second);
963 it->second.approx_union_with(o_it->second);
964 if(it->second!=old)
965 changed=true;
966 it++;
967 }
968 }
969
970 return changed;
971}
972
974{
976 remove(ne_set, a);
977 remove(le_set, a);
978 bounds_map.erase(a);
979}
980
982{
983 if(lhs.id()==ID_symbol ||
984 lhs.id()==ID_member)
985 {
986 unsigned a;
987 if(!get_object(lhs, a))
988 modifies(a);
989 }
990 else if(lhs.id()==ID_index)
991 {
992 // we don't track arrays
993 }
994 else if(lhs.id()==ID_dereference)
995 {
996 // be very, very conservative for now
997 make_true();
998 }
999 else if(lhs.id()=="object_value")
1000 {
1001 // be very, very conservative for now
1002 make_true();
1003 }
1004 else if(lhs.id()==ID_if)
1005 {
1006 // we just assume both are changed
1007 modifies(to_if_expr(lhs).op1());
1008 modifies(to_if_expr(lhs).op2());
1009 }
1010 else if(lhs.id()==ID_typecast)
1011 {
1012 // just go down
1013 modifies(to_typecast_expr(lhs).op());
1014 }
1015 else if(lhs.id()=="valid_object")
1016 {
1017 }
1018 else if(lhs.id()==ID_byte_extract_little_endian ||
1020 {
1021 // just go down
1022 modifies(to_byte_extract_expr(lhs).op0());
1023 }
1024 else if(lhs.id() == ID_null_object ||
1025 lhs.id() == "is_zero_string" ||
1026 lhs.id() == "zero_string" ||
1027 lhs.id() == "zero_string_length")
1028 {
1029 // ignore
1030 }
1031 else
1032 throw "modifies: unexpected lhs: "+lhs.id_string();
1033}
1034
1036 const exprt &lhs,
1037 const exprt &rhs)
1038{
1039 equal_exprt equality(lhs, rhs);
1040
1041 // first evaluate RHS
1042 simplify(equality.rhs());
1043 ::simplify(equality.rhs(), ns);
1044
1045 // now kill LHS
1046 modifies(lhs);
1047
1048 // and put it back
1049 strengthen(equality);
1050}
1051
1053{
1054 const irep_idt &statement=code.get(ID_statement);
1055
1056 if(statement==ID_block)
1057 {
1058 for(const auto &op : code.operands())
1059 apply_code(to_code(op));
1060 }
1061 else if(statement==ID_assign)
1062 {
1063 if(code.operands().size()!=2)
1064 throw "assignment expected to have two operands";
1065
1066 assignment(code.op0(), code.op1());
1067 }
1068 else if(statement==ID_decl)
1069 {
1070 if(code.operands().size()==2)
1071 assignment(code.op0(), code.op1());
1072 else
1073 modifies(code.op0());
1074 }
1075 else if(statement==ID_expression)
1076 {
1077 // this never modifies anything
1078 }
1079 else if(statement==ID_function_call)
1080 {
1081 // may be a disaster
1082 make_true();
1083 }
1084 else if(statement==ID_cpp_delete ||
1085 statement==ID_cpp_delete_array)
1086 {
1087 // does nothing
1088 }
1089 else if(statement==ID_printf)
1090 {
1091 // does nothing
1092 }
1093 else if(statement=="lock" ||
1094 statement=="unlock" ||
1095 statement==ID_asm)
1096 {
1097 // ignore for now
1098 }
1099 else
1100 {
1101 std::cerr << code.pretty() << '\n';
1102 throw "invariant_sett: unexpected statement: "+id2string(statement);
1103 }
1104}
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
mp_integer power(const mp_integer &base, const mp_integer &exponent)
A multi-precision implementation of the power operator.
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
const unsignedbv_typet & to_unsignedbv_type(const typet &type)
Cast a typet to an unsignedbv_typet.
Expression classes for byte-level operators.
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
exprt & rhs()
Definition std_expr.h:678
Data structure for representing an arbitrary statement in a program.
exprt & op0()
Definition expr.h:133
exprt & op1()
Definition expr.h:136
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
Equality.
Definition std_expr.h:1366
Base class for all expressions.
Definition expr.h:56
bool is_true() const
Return whether the expression is a constant representing true.
Definition expr.cpp:27
bool is_boolean() const
Return whether the expression represents a Boolean.
Definition expr.h:224
bool is_false() const
Return whether the expression is a constant representing false.
Definition expr.cpp:34
bool is_constant() const
Return whether the expression is a constant.
Definition expr.h:212
typet & type()
Return the type of the expression.
Definition expr.h:84
operandst & operands()
Definition expr.h:94
The Boolean constant false.
Definition std_expr.h:3199
const exprt & get_expr(unsigned n) const
void output(std::ostream &out) const
static bool is_constant_address_rec(const exprt &expr)
static bool is_constant_address(const exprt &expr)
std::string build_string(const exprt &expr) const
std::string to_string(unsigned n) const
unsigned add(const exprt &expr)
std::vector< entryt > entries
bool is_constant(unsigned n) const
bool get(const exprt &expr, unsigned &n)
const namespacet & ns
inv_object_storet & object_store
tvt is_lt(std::pair< unsigned, unsigned > p) const
tvt is_le(std::pair< unsigned, unsigned > p) const
void add_ne(const std::pair< unsigned, unsigned > &p)
bool has_le(const std::pair< unsigned, unsigned > &p) const
tvt implies_rec(const exprt &expr) const
void apply_code(const codet &code)
unsigned_union_find eq_set
std::map< unsigned, boundst > bounds_mapt
ineq_sett ne_set
exprt get_constant(const exprt &expr) const
tvt is_ne(std::pair< unsigned, unsigned > p) const
interval_templatet< mp_integer > boundst
ineq_sett le_set
void simplify(exprt &expr) const
void output(std::ostream &out) const
void add_bounds(unsigned a, const boundst &bound)
bool make_union(const invariant_sett &other_invariants)
void strengthen(const exprt &expr)
void assignment(const exprt &lhs, const exprt &rhs)
void add_eq(const std::pair< unsigned, unsigned > &eq)
static void intersection(ineq_sett &dest, const ineq_sett &other)
bounds_mapt bounds_map
std::set< std::pair< unsigned, unsigned > > ineq_sett
static void nnf(exprt &expr, bool negate=false)
const namespacet & ns
void get_bounds(unsigned a, boundst &dest) const
static void remove(ineq_sett &dest, unsigned a)
tvt implies(const exprt &expr) const
void add(const std::pair< unsigned, unsigned > &p, ineq_sett &dest)
void add_type_bounds(const exprt &expr, const typet &type)
void add_le(const std::pair< unsigned, unsigned > &p)
bool has_ne(const std::pair< unsigned, unsigned > &p) const
bool get_object(const exprt &expr, unsigned &n) const
bool make_union_bounds_map(const bounds_mapt &other)
std::string to_string(unsigned a) const
void modifies(const exprt &lhs)
void strengthen_rec(const exprt &expr)
bool has_eq(const std::pair< unsigned, unsigned > &p) const
tvt is_eq(std::pair< unsigned, unsigned > p) const
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 std::string & id_string() const
Definition irep.h:391
void swap(irept &irep)
Definition irep.h:434
const irep_idt & id() const
Definition irep.h:388
const std::string & get_string(const irep_idt &name) const
Definition irep.h:401
Extract member of struct or union.
Definition std_expr.h:2971
The null pointer constant.
number_type number(const key_type &a)
Definition numbering.h:37
std::optional< number_type > get_number(const key_type &a) const
Definition numbering.h:50
std::size_t number_type
Definition numbering.h:24
Structure type, corresponds to C style structs.
Definition std_types.h:231
The Boolean constant true.
Definition std_expr.h:3190
Definition threeval.h:20
static tvt unknown()
Definition threeval.h:33
Semantic type conversion.
Definition std_expr.h:2073
The type of an expression, extends irept.
Definition type.h:29
void intersection(const unsigned_union_find &other)
size_type size() const
Definition union_find.h:97
void check_index(size_type a)
Definition union_find.h:111
size_type find(size_type a) const
size_type count(size_type a) const
Definition union_find.h:103
size_type count_roots() const
Definition union_find.h:118
bool is_root(size_type a) const
Definition union_find.h:82
void make_union(size_type a, size_type b)
void isolate(size_type a)
#define Forall_operands(it, expr)
Definition expr.h:27
exprt boolean_negate(const exprt &src)
negate a Boolean expression, possibly removing a not_exprt, and swapping false and true
bool is_null_pointer(const constant_exprt &expr)
Returns true if expr has a pointer type and a value NULL; it also returns true when expr has value ze...
Deprecated expression utility functions.
interval_templatet< T > lower_interval(const T &l)
interval_templatet< T > upper_interval(const T &u)
Value Set.
const irept & get_nil_irep()
Definition irep.cpp:19
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
static int8_t r
Definition irep_hash.h:60
std::string from_expr(const namespacet &ns, const irep_idt &identifier, const exprt &expr)
const std::string integer2string(const mp_integer &n, unsigned base)
Definition mp_arith.cpp:103
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.
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 PRECONDITION(CONDITION)
Definition invariant.h:463
const codet & to_code(const exprt &expr)
const binary_relation_exprt & to_binary_relation_expr(const exprt &expr)
Cast an exprt to a binary_relation_exprt.
Definition std_expr.h:895
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1538
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2107
const notequal_exprt & to_notequal_expr(const exprt &expr)
Cast an exprt to an notequal_exprt.
Definition std_expr.h:1450
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition std_expr.h:2577
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:3063
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3172
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
Definition std_expr.h:2479
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:272
const equal_exprt & to_equal_expr(const exprt &expr)
Cast an exprt to an equal_exprt.
Definition std_expr.h:1407
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
dstringt irep_idt