CBMC
Loading...
Searching...
No Matches
horn_encoding.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Horn-clause Encoding
4
5Author: Daniel Kroening
6
7Date: June 2015
8
9\*******************************************************************/
10
13
14#include "horn_encoding.h"
15
16#include <util/c_types.h>
18#include <util/format_expr.h>
20#include <util/pointer_expr.h>
21#include <util/prefix.h>
22#include <util/replace_symbol.h>
23#include <util/std_code.h>
24#include <util/std_expr.h>
25
27
29
30#include <algorithm>
31#include <ostream>
32#include <unordered_set>
33
34class state_typet : public typet
35{
36public:
38 {
39 }
40};
41
46
47static inline symbol_exprt state_expr()
48{
49 return symbol_exprt(u8"\u03c2", state_typet());
50}
51
52class evaluate_exprt : public binary_exprt
53{
54public:
57 std::move(state),
59 std::move(address),
60 std::move(type))
61 {
62 PRECONDITION(this->state().type().id() == ID_state);
63 PRECONDITION(this->address().type().id() == ID_pointer);
64 }
65
66 const exprt &state() const
67 {
68 return op0();
69 }
70
72 {
73 return op0();
74 }
75
76 const exprt &address() const
77 {
78 return op1();
79 }
80};
81
88inline const evaluate_exprt &to_evaluate_expr(const exprt &expr)
89{
90 PRECONDITION(expr.id() == ID_evaluate);
91 const evaluate_exprt &ret = static_cast<const evaluate_exprt &>(expr);
93 return ret;
94}
95
98{
99 PRECONDITION(expr.id() == ID_evaluate);
100 evaluate_exprt &ret = static_cast<evaluate_exprt &>(expr);
102 return ret;
103}
104
106{
107public:
111 std::move(state),
112 std::move(address),
113 std::move(new_value),
114 state_typet())
115 {
116 // PRECONDITION(this->state().id() == ID_state);
117 PRECONDITION(this->address().type().id() == ID_pointer);
118 }
119
120 const exprt &state() const
121 {
122 return op0();
123 }
124
126 {
127 return op0();
128 }
129
130 const exprt &address() const
131 {
132 return op1();
133 }
134
135 const exprt &new_value() const
136 {
137 return op2();
138 }
139};
140
148{
150 const update_state_exprt &ret = static_cast<const update_state_exprt &>(expr);
152 return ret;
153}
154
157{
159 update_state_exprt &ret = static_cast<update_state_exprt &>(expr);
161 return ret;
162}
163
164class allocate_exprt : public ternary_exprt
165{
166public:
170 std::move(state),
171 std::move(address),
172 std::move(size),
173 state_typet())
174 {
175 PRECONDITION(this->state().type().id() == ID_state);
176 PRECONDITION(this->address().type().id() == ID_pointer);
177 }
178
179 const exprt &state() const
180 {
181 return op0();
182 }
183
185 {
186 return op0();
187 }
188
189 const exprt &address() const
190 {
191 return op1();
192 }
193
194 const exprt &size() const
195 {
196 return op2();
197 }
198};
199
206inline const allocate_exprt &to_allocate_expr(const exprt &expr)
207{
208 PRECONDITION(expr.id() == ID_allocate);
209 const allocate_exprt &ret = static_cast<const allocate_exprt &>(expr);
211 return ret;
212}
213
215{
216public:
217 virtual void annotation(const std::string &)
218 {
219 }
220
222
224 {
225 set_to_true(source_location, std::move(expr));
226 }
227
232
233 virtual ~encoding_targett() = default;
234
235protected:
237};
238
240{
241public:
243
244 using constraintst = std::vector<exprt>;
246
248 {
251
252 constraints.emplace_back(std::move(expr));
253 }
254
255protected:
257};
258
259static inline void operator<<(encoding_targett &target, exprt constraint)
260{
261 target.set_to_true(std::move(constraint));
262}
263
264static inline void
266{
267 for(const auto &constraint : src.constraints)
268 target << constraint;
269}
270
272{
273public:
274 smt2_encoding_targett(const namespacet &ns, std::ostream &_out)
275 : out(_out),
276 smt2_conv(ns, "", "cprover", "", smt2_convt::solvert::GENERIC, _out)
277 {
279 smt2_conv.use_as_const = true;
280 }
281
283 {
284 // finish the conversion to SMT-LIB2
285 smt2_conv();
286 }
287
288 void set_to_true(source_locationt, exprt expr) override
289 {
290 smt2_conv.set_to_true(std::move(expr));
291 }
292
293 void annotation(const std::string &text) override
294 {
295 if(text.empty())
296 out << '\n';
297 else
298 out << ';' << ' ' << text << '\n';
299 }
300
301protected:
302 std::ostream &out;
304};
305
307{
308public:
309 explicit ascii_encoding_targett(std::ostream &_out) : out(_out)
310 {
311 }
312
314
315 void annotation(const std::string &text) override
316 {
317 out << text << '\n';
318 }
319
320protected:
321 std::ostream &out;
322 std::size_t counter = 0;
323};
324
326 const exprt &src,
327 std::unordered_set<symbol_exprt, irep_hash> &result)
328{
329 if(src.id() == ID_object_address)
330 result.insert(to_object_address_expr(src).object_expr());
331 else
332 {
333 for(auto &op : src.operands())
334 find_variables_rec(op, result);
335 }
336}
337
338class state_encodingt
339{
340public:
345
347 const goto_functionst::function_mapt::const_iterator,
349
350 void encode(
351 const goto_functiont &,
352 const std::string &state_prefix,
353 const std::string &annotation,
355 const exprt &return_lhs,
357
358protected:
361
363 symbol_exprt state_expr_with_suffix(loct, const std::string &suffix) const;
366 std::vector<symbol_exprt> incoming_symbols(loct) const;
367 exprt evaluate_expr(loct, const exprt &, const exprt &) const;
369 loct,
370 const exprt &,
371 const exprt &,
372 const std::unordered_set<symbol_exprt, irep_hash> &) const;
374 loct,
375 const exprt &,
376 std::vector<symbol_exprt> &nondet_symbols) const;
377 exprt evaluate_expr(loct, const exprt &) const;
378 exprt address_rec(loct, const exprt &, exprt) const;
386
387 std::string state_prefix;
388 std::string annotation;
392 using incomingt =
393 std::map<loct, std::vector<loct>, goto_programt::target_less_than>;
395};
396
398{
399 return state_expr_with_suffix(loc, "");
400}
401
403 loct loc,
404 const std::string &suffix) const
405{
406 irep_idt identifier =
407 state_prefix + std::to_string(loc->location_number) + suffix;
408 return symbol_exprt(identifier, state_predicate_type());
409}
410
412{
413 return state_expr_with_suffix(loc, taken ? "T" : "");
414}
415
416std::vector<symbol_exprt> state_encodingt::incoming_symbols(loct loc) const
417{
418 auto incoming_it = incoming.find(loc);
419
420 DATA_INVARIANT(incoming_it != incoming.end(), "incoming is complete");
421
422 std::vector<symbol_exprt> symbols;
423 symbols.reserve(incoming_it->second.size());
424
425 for(auto &loc_in : incoming_it->second)
426 {
427 std::string suffix;
428
429 // conditional jump from loc_in to loc?
430 if(
431 loc_in->is_goto() && loc_in->condition() != true &&
432 loc != std::next(loc_in))
433 {
434 suffix = "T";
435 }
436
437 symbols.push_back(state_expr_with_suffix(loc_in, suffix));
438 }
439
440 return symbols;
441}
442
444{
445 if(loc == first_loc)
446 return entry_state;
447
448 auto incoming_symbols = this->incoming_symbols(loc);
449
450 if(incoming_symbols.size() == 1)
451 return incoming_symbols.front();
452 else
453 return state_expr_with_suffix(loc, "in");
454}
455
457 loct loc,
458 const exprt &state,
459 const exprt &what) const
460{
461 return evaluate_expr_rec(loc, state, what, {});
462}
463
465 loct loc,
466 const exprt &what,
467 std::vector<symbol_exprt> &nondet_symbols) const
468{
469 if(what.id() == ID_side_effect)
470 {
471 auto &side_effect = to_side_effect_expr(what);
472 auto statement = side_effect.get_statement();
473 if(statement == ID_nondet)
474 {
475 irep_idt identifier =
476 "nondet::" + state_prefix + std::to_string(loc->location_number);
477 auto symbol = symbol_exprt(identifier, side_effect.type());
478 nondet_symbols.push_back(symbol);
479 return std::move(symbol);
480 }
481 else
482 return what; // leave it
483 }
484 else
485 {
486 exprt tmp = what;
487 for(auto &op : tmp.operands())
488 op = replace_nondet_rec(loc, op, nondet_symbols);
489 return tmp;
490 }
491}
492
494 loct loc,
495 const exprt &state,
496 const exprt &what,
497 const std::unordered_set<symbol_exprt, irep_hash> &bound_symbols) const
498{
499 PRECONDITION(state.type().id() == ID_state);
500
501 if(what.id() == ID_symbol)
502 {
503 const auto &symbol_expr = to_symbol_expr(what);
504
505 if(bound_symbols.find(symbol_expr) == bound_symbols.end())
506 {
507 return evaluate_exprt(state, address_rec(loc, state, what), what.type());
508 }
509 else
510 return what; // leave as is
511 }
512 else if(
513 what.id() == ID_dereference || what.id() == ID_member ||
514 what.id() == ID_index)
515 {
516 return evaluate_exprt(state, address_rec(loc, state, what), what.type());
517 }
518 else if(what.id() == ID_forall || what.id() == ID_exists)
519 {
520 auto new_quantifier_expr = to_quantifier_expr(what); // copy
521 auto new_bound_symbols = bound_symbols; // copy
522
523 for(const auto &v : new_quantifier_expr.variables())
524 new_bound_symbols.insert(v);
525
527 loc, state, new_quantifier_expr.where(), new_bound_symbols);
528
529 return std::move(new_quantifier_expr);
530 }
531 else if(what.id() == ID_address_of)
532 {
533 const auto &object = to_address_of_expr(what).object();
534 return address_rec(loc, state, object);
535 }
536 else if(what.id() == ID_r_ok || what.id() == ID_w_ok || what.id() == ID_rw_ok)
537 {
538 // we need to add the state
539 const auto &r_or_w_ok_expr = to_r_or_w_ok_expr(what);
540 auto pointer =
541 evaluate_expr_rec(loc, state, r_or_w_ok_expr.pointer(), bound_symbols);
542 auto size =
544 return ternary_exprt(what.id(), state, pointer, size, what.type());
545 }
546 else
547 {
548 exprt tmp = what;
549 for(auto &op : tmp.operands())
550 op = evaluate_expr_rec(loc, state, op, bound_symbols);
551 return tmp;
552 }
553}
554
555exprt state_encodingt::evaluate_expr(loct loc, const exprt &what) const
556{
557 return evaluate_expr(loc, in_state_expr(loc), what);
558}
559
561{
562 return lambda_exprt({state_expr()}, std::move(what));
563}
564
566{
567 return forall_exprt(
568 {state_expr()},
571 std::move(what)));
572}
573
574exprt state_encodingt::forall_states_expr(loct loc, exprt condition, exprt what)
575 const
576{
577 return forall_exprt(
578 {state_expr()},
580 and_exprt(
582 std::move(condition)),
583 std::move(what)));
584}
585
586exprt state_encodingt::address_rec(loct loc, const exprt &state, exprt expr)
587 const
588{
589 if(expr.id() == ID_symbol)
590 {
591 if(expr.type().id() == ID_array)
592 {
593 const auto &element_type = to_array_type(expr.type()).element_type();
595 to_symbol_expr(expr), pointer_type(element_type));
596 }
597 else
599 }
600 else if(expr.id() == ID_member)
601 {
602 auto compound = to_member_expr(expr).struct_op();
603 auto compound_address = address_rec(loc, state, std::move(compound));
604 auto component_name = to_member_expr(expr).get_component_name();
605
606 if(expr.type().id() == ID_array)
607 {
608 const auto &element_type = to_array_type(expr.type()).element_type();
609 return field_address_exprt(
610 std::move(compound_address),
611 component_name,
612 pointer_type(element_type));
613 }
614 else
615 {
616 return field_address_exprt(
617 std::move(compound_address), component_name, pointer_type(expr.type()));
618 }
619 }
620 else if(expr.id() == ID_index)
621 {
622 auto array = to_index_expr(expr).array();
623 auto index_evaluated =
624 evaluate_expr(loc, state, to_index_expr(expr).index());
625 auto array_address = address_rec(loc, state, std::move(array));
627 std::move(array_address), std::move(index_evaluated));
628 }
629 else if(expr.id() == ID_dereference)
630 return evaluate_expr(loc, state, to_dereference_expr(expr).pointer());
631 else if(expr.id() == ID_string_constant)
632 {
633 // TBD.
635 "can't do string literals", expr.source_location());
636 }
637 else if(expr.id() == ID_array)
638 {
639 // TBD.
641 "can't do array literals", expr.source_location());
642 }
643 else if(expr.id() == ID_union)
644 {
645 // TBD.
647 "can't do union literals", expr.source_location());
648 }
649 else
650 return nil_exprt();
651}
652
654 const
655{
656 auto s = state_expr();
657
658 auto address = address_rec(loc, s, lhs);
659
660 exprt rhs_evaluated = evaluate_expr(loc, s, rhs);
661
662 std::vector<symbol_exprt> nondet_symbols;
664
665 auto new_state = update_state_exprt(s, address, new_value);
666
668 binding.insert(binding.end(), nondet_symbols.begin(), nondet_symbols.end());
669
670 return forall_exprt(
671 std::move(binding),
675}
676
677void state_encodingt::setup_incoming(const goto_functiont &goto_function)
678{
679 forall_goto_program_instructions(it, goto_function.body)
680 incoming[it];
681
682 forall_goto_program_instructions(it, goto_function.body)
683 {
684 if(it->is_goto())
685 incoming[it->get_target()].push_back(it);
686 }
687
688 forall_goto_program_instructions(it, goto_function.body)
689 {
690 auto next = std::next(it);
691 if(it->is_goto() && it->condition() == true)
692 {
693 }
694 else if(next != goto_function.body.instructions.end())
695 {
696 incoming[next].push_back(it);
697 }
698 }
699}
700
702{
703 if(src.id() == ID_not)
704 return to_not_expr(src).op();
705 else
706 return not_exprt(src);
707}
708
711 encoding_targett &dest)
712{
713 const auto &function = to_symbol_expr(loc->call_function());
714 const auto &type = to_code_type(function.type());
715 auto identifier = function.get_identifier();
716
717 auto new_annotation = annotation + u8" \u2192 " + id2string(identifier);
719
720 // malloc is special-cased
721 if(identifier == "malloc")
722 {
723 auto state = state_expr();
724 PRECONDITION(loc->call_arguments().size() == 1);
725 auto size_evaluated = evaluate_expr(loc, state, loc->call_arguments()[0]);
726
727 auto lhs_address = address_rec(loc, state, loc->call_lhs());
730 dest << forall_states_expr(
732 return;
733 }
734
735 // Find the function
736 auto f = goto_functions.function_map.find(identifier);
737 if(f == goto_functions.function_map.end())
738 DATA_INVARIANT(false, "failed find function in function_map");
739
740 // Do we have a function body?
741 if(!f->second.body_available())
742 {
743 // no function body -- do LHS assignment nondeterministically, if any
744 if(loc->call_lhs().is_not_nil())
745 {
746 auto rhs = side_effect_expr_nondett(
747 loc->call_lhs().type(), loc->source_location());
748 dest << assignment_constraint(loc, loc->call_lhs(), std::move(rhs));
749 }
750 else
751 {
752 // This is a SKIP.
753 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
754 }
755 }
756
757 // Evaluate the arguments of the call in the 'in state'
759
760 for(std::size_t i = 0; i < type.parameters().size(); i++)
761 {
762 auto address = object_address_exprt(symbol_exprt(
763 f->second.parameter_identifiers[i], type.parameters()[i].type()));
764 auto argument = loc->call_arguments()[i];
765 auto value = evaluate_expr(loc, state_expr(), argument);
767 }
768
769 // Now assign them
770 auto function_entry_state = state_expr_with_suffix(loc, "Entry");
771 dest << forall_states_expr(
773
774 // now do the body, recursively
776 auto new_state_prefix =
777 state_prefix + std::to_string(loc->location_number) + ".";
778 body_state_encoding.encode(
779 f->second,
783 nil_exprt(),
784 dest);
785
786 // exit state of called function
787 auto exit_loc = std::prev(f->second.body.instructions.end());
789 new_state_prefix + std::to_string(exit_loc->location_number);
791
792 // now link up return state
793 dest << equal_exprt(out_state_expr(loc), std::move(exit_state));
794}
795
798 encoding_targett &dest)
799{
800 // Function pointer?
801 const auto &function = loc->call_function();
802 if(function.id() == ID_dereference)
803 {
804 // TBD.
806 "can't do function pointers", loc->source_location());
807 }
808 else if(function.id() == ID_symbol)
809 {
810 function_call_symbol(loc, dest);
811 }
812 else
813 {
815 false, "got function that's neither a symbol nor a function pointer");
816 }
817}
818
820 goto_functionst::function_mapt::const_iterator f_entry,
821 encoding_targett &dest)
822{
823 const auto &goto_function = f_entry->second;
824
825 if(goto_function.body.instructions.empty())
826 return;
827
828 // initial state
829 auto in_state = symbol_exprt("SInitial", state_predicate_type());
830
831 dest << forall_exprt(
832 {state_expr()},
835
836 auto annotation = id2string(f_entry->first);
837
838 encode(goto_function, "S", annotation, in_state, nil_exprt(), dest);
839}
840
842 const goto_functiont &goto_function,
843 const std::string &state_prefix,
844 const std::string &annotation,
845 const symbol_exprt &entry_state,
846 const exprt &return_lhs,
847 encoding_targett &dest)
848{
849 first_loc = goto_function.body.instructions.begin();
850 this->state_prefix = state_prefix;
851 this->annotation = annotation;
852 this->entry_state = entry_state;
853 this->return_lhs = return_lhs;
854
855 setup_incoming(goto_function);
856
857 // constraints for each instruction
858 forall_goto_program_instructions(loc, goto_function.body)
859 {
860 // pass on the source code location
861 dest.set_source_location(loc->source_location());
862
863 // constraints on the incoming state
864 {
865 auto incoming_symbols = this->incoming_symbols(loc);
866
867 if(incoming_symbols.size() >= 2)
868 {
869 auto s = state_expr();
871 {
872 dest << forall_exprt(
873 {s},
877 }
878 }
879 }
880
881 if(loc->is_assign())
882 {
883 auto &lhs = loc->assign_lhs();
884 auto &rhs = loc->assign_rhs();
885
886 if(lhs.type().id() == ID_array)
887 {
888 // skip
889 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
890 }
891 else if(lhs.type().id() == ID_struct_tag)
892 {
893 // skip
894 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
895 }
896 else if(
897 lhs.id() == ID_symbol &&
899 id2string(to_symbol_expr(lhs).get_identifier()), CPROVER_PREFIX) &&
900 to_symbol_expr(lhs).get_identifier() != CPROVER_PREFIX "rounding_mode")
901 {
902 // skip for now
903 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
904 }
905 else
906 dest << assignment_constraint(loc, lhs, rhs);
907 }
908 else if(loc->is_assume())
909 {
910 // we produce ∅ when the assumption is false
911 auto state = state_expr();
912 auto condition_evaluated = evaluate_expr(loc, state, loc->condition());
913
914 dest << forall_states_expr(
915 loc,
918 }
919 else if(loc->is_goto())
920 {
921 // We produce ∅ when the 'other' branch is taken. Get the condition.
922 const auto &condition = loc->condition();
923
924 if(condition == true)
925 {
926 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
927 }
928 else
929 {
930 auto state = state_expr();
931 auto condition_evaluated = evaluate_expr(loc, state, condition);
932
933 dest << forall_states_expr(
934 loc,
936 function_application_exprt(out_state_expr(loc, true), {state}));
937
938 dest << forall_states_expr(
939 loc,
941 function_application_exprt(out_state_expr(loc, false), {state}));
942 }
943 }
944 else if(loc->is_assert())
945 {
946 // all assertions need to hold
947 dest << forall_states_expr(
948 loc, evaluate_expr(loc, state_expr(), loc->condition()));
949
950 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
951 }
952 else if(
953 loc->is_skip() || loc->is_assert() || loc->is_location() ||
954 loc->is_end_function() || loc->is_other())
955 {
956 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
957 }
958 else if(loc->is_decl() || loc->is_dead())
959 {
960 // may wish to havoc the symbol
961 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
962 }
963 else if(loc->is_function_call())
964 {
965 function_call(loc, dest);
966 }
967 else if(loc->is_set_return_value())
968 {
969 const auto &rhs = loc->return_value();
970
971 if(return_lhs.is_nil())
972 {
973 // treat these as assignments to a special symbol named 'return_value'
974 auto lhs = symbol_exprt("return_value", rhs.type());
975 dest << assignment_constraint(loc, std::move(lhs), std::move(rhs));
976 }
977 else
978 {
979 }
980 }
981 }
982}
983
985 const goto_modelt &goto_model,
987 encoding_targett &dest)
988{
990 {
991 auto f_entry = goto_model.goto_functions.function_map.find(
993
994 if(f_entry == goto_model.goto_functions.function_map.end())
995 throw incorrect_goto_program_exceptiont("The program has no entry point");
996
997 dest.annotation("function " + id2string(f_entry->first));
998
999 state_encodingt{goto_model.goto_functions}(f_entry, dest);
1000 }
1001 else
1002 {
1003 // sort alphabetically
1004 const auto sorted = goto_model.goto_functions.sorted();
1005 const namespacet ns(goto_model.symbol_table);
1006 for(auto &f : sorted)
1007 {
1008 const auto &symbol = ns.lookup(f->first);
1009 if(
1010 f->first == goto_functionst::entry_point() ||
1011 to_code_with_contract_type(symbol.type).has_contract())
1012 {
1013 dest.annotation("");
1014 dest.annotation("function " + id2string(f->first));
1015 state_encodingt{goto_model.goto_functions}(f, dest);
1016 }
1017 }
1018 }
1019}
1020
1021std::unordered_set<symbol_exprt, irep_hash>
1022find_variables(const std::vector<exprt> &src)
1023{
1024 std::unordered_set<symbol_exprt, irep_hash> result;
1025
1026 for(auto &expr : src)
1027 find_variables_rec(expr, result);
1028
1029 return result;
1030}
1031
1032static typet
1034{
1036 for(auto &v : variables)
1037 domain.push_back(v.type());
1038
1039 return mathematical_function_typet(std::move(domain), bool_typet());
1040}
1041
1043{
1044 // operands first
1045 for(auto &op : src.operands())
1046 op = variable_encoding(op, variables);
1047
1048 if(src.id() == ID_forall)
1049 {
1050 auto &forall_expr = to_forall_expr(src);
1051 if(
1052 forall_expr.variables().size() >= 1 &&
1053 forall_expr.variables().front().type().id() == ID_state)
1054 {
1055 // replace 'state' by the program variables
1056 forall_exprt::variablest new_variables = variables;
1057 new_variables.insert(
1058 new_variables.end(),
1059 forall_expr.variables().begin() + 1,
1060 forall_expr.variables().end());
1062 .variables() = std::move(new_variables);
1063 return std::move(forall_expr);
1064 }
1065 }
1066 else if(src.id() == ID_function_application)
1067 {
1068 auto &function_application = to_function_application_expr(src);
1069 if(
1070 function_application.arguments().size() == 1 &&
1071 function_application.arguments().front().type().id() == ID_state)
1072 {
1073 function_application.function().type() =
1074 new_state_predicate_type(variables);
1075
1076 if(function_application.arguments().front().id() == ID_symbol)
1077 {
1079 for(auto &v : variables)
1080 new_arguments.push_back(v);
1081 function_application.arguments() = new_arguments;
1082 }
1083 else if(function_application.arguments().front().id() == ID_tuple)
1084 {
1086 function_application.arguments().front().operands().size() ==
1087 variables.size(),
1088 "tuple size must match");
1089 auto operands = function_application.arguments().front().operands();
1090 function_application.arguments() = operands;
1091 }
1092 else
1093 throw analysis_exceptiont("can't convert " + format_to_string(src));
1094 }
1095 else
1096 throw analysis_exceptiont("can't convert " + format_to_string(src));
1097 }
1098 else if(src.id() == ID_evaluate)
1099 {
1100 auto &evaluate_expr = to_evaluate_expr(src);
1101 if(evaluate_expr.address().id() == ID_object_address)
1102 return symbol_exprt(
1103 to_object_address_expr(evaluate_expr.address()).object_expr());
1104 else
1105 throw analysis_exceptiont("can't convert " + format_to_string(src));
1106 }
1107 else if(src.id() == ID_update_state)
1108 {
1110 if(update_state_expr.address().id() == ID_object_address)
1111 {
1112 auto lhs_symbol =
1113 to_object_address_expr(update_state_expr.address()).object_expr();
1114 exprt::operandst operands;
1115 for(auto &v : variables)
1116 {
1117 if(v == lhs_symbol)
1118 operands.push_back(update_state_expr.new_value());
1119 else
1120 operands.push_back(v);
1121 }
1122 return tuple_exprt(operands, typet(ID_state));
1123 }
1124 else
1125 throw analysis_exceptiont("can't convert " + format_to_string(src));
1126 }
1127
1128 return src;
1129}
1130
1131void variable_encoding(std::vector<exprt> &constraints)
1132{
1133 binding_exprt::variablest variables;
1134
1135 for(auto &v : find_variables(constraints))
1136 variables.push_back(v);
1137
1138 if(variables.empty())
1139 throw analysis_exceptiont("no variables found");
1140
1141 // sort alphabetically
1142 std::sort(
1143 variables.begin(),
1144 variables.end(),
1145 [](const symbol_exprt &a, const symbol_exprt &b) {
1146 return id2string(a.get_identifier()) < id2string(b.get_identifier());
1147 });
1148
1149 for(auto &c : constraints)
1150 c = variable_encoding(c, variables);
1151}
1152
1153void equality_propagation(std::vector<exprt> &constraints)
1154{
1155 replace_symbolt values;
1156
1157 std::vector<exprt> new_constraints;
1158 new_constraints.reserve(constraints.size());
1159
1160 // forward-propagation of equalities
1161 for(auto &expr : constraints)
1162 {
1163 bool retain_constraint = true;
1164
1165 // apply the map
1166 values(expr);
1167
1168 if(expr.id() == ID_equal)
1169 {
1170 const auto &equal_expr = to_equal_expr(expr);
1171 if(equal_expr.lhs().id() == ID_symbol)
1172 {
1173 const auto &symbol_expr = to_symbol_expr(equal_expr.lhs());
1174
1175 // this is a (deliberate) no-op when the symbol is already in the map
1176 if(values.replaces_symbol(symbol_expr.get_identifier()))
1177 {
1178 }
1179 else
1180 {
1181 values.insert(symbol_expr, equal_expr.rhs());
1182 // insertion has happened
1183 retain_constraint = false;
1184 }
1185 }
1186 }
1187
1189 new_constraints.push_back(std::move(expr));
1190 }
1191
1192 constraints = std::move(new_constraints);
1193
1194 // apply the map again, to catch any backwards definitions
1195 for(auto &expr : constraints)
1196 {
1197 if(expr.id() == ID_equal && to_equal_expr(expr).lhs().id() == ID_symbol)
1198 {
1199 // it's a definition
1200 }
1201 else
1202 {
1203 // apply the map
1204 values(expr);
1205 }
1206 }
1207}
1208
1209void horn_encoding(const goto_modelt &goto_model, std::ostream &out)
1210{
1211 const namespacet ns(goto_model.symbol_table);
1212
1214 state_encoding(goto_model, true, container);
1215
1217
1218 variable_encoding(container.constraints);
1219
1220 smt2_encoding_targett dest(ns, out);
1221 dest << container;
1222}
void validate_expr(const shuffle_vector_exprt &value)
Definition c_expr.h:82
pointer_typet pointer_type(const typet &subtype)
Definition c_types.cpp:235
const code_with_contract_typet & to_code_with_contract_type(const typet &type)
Cast a typet to a code_with_contract_typet.
Definition c_types.h:467
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
allocate_exprt(exprt state, exprt address, exprt size)
const exprt & address() const
const exprt & size() const
Definition state.h:240
const exprt & state() const
Definition state.h:230
Thrown when an unexpected error occurs during the analysis (e.g., when the SAT solver returns an erro...
Boolean AND All operands must be boolean, and the result is always boolean.
Definition std_expr.h:2126
void annotation(const std::string &text) override
ascii_encoding_targett(std::ostream &_out)
void set_to_true(source_locationt, exprt) override
A base class for binary expressions.
Definition std_expr.h:638
const exprt & op2() const =delete
exprt & op0()
Definition expr.h:134
exprt & op1()
Definition expr.h:137
std::vector< symbol_exprt > variablest
Definition std_expr.h:3291
The Boolean type.
Definition std_types.h:36
container_encoding_targett()=default
void set_to_true(source_locationt source_location, exprt expr) override
void set_to_true(const exprt &)
For a Boolean expression expr, add the constraint 'expr'.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
Operator to return the address of an array element relative to a base address.
void set_to_true(exprt expr)
virtual void annotation(const std::string &)
virtual ~encoding_targett()=default
void set_source_location(source_locationt __source_location)
virtual void set_to_true(source_locationt, exprt)=0
source_locationt source_location
Equality.
Definition std_expr.h:1366
const exprt & address() const
Definition state.h:110
const exprt & state() const
Definition state.h:100
evaluate_exprt(exprt state, exprt address, typet type)
Base class for all expressions.
Definition expr.h:57
std::vector< exprt > operandst
Definition expr.h:59
typet & type()
Return the type of the expression.
Definition expr.h:85
operandst & operands()
Definition expr.h:95
const source_locationt & source_location() const
Definition expr.h:236
source_locationt & add_source_location()
Definition expr.h:241
Operator to return the address of a field relative to a base address.
A forall expression.
Application of (mathematical) function.
A collection of goto functions.
function_mapt function_map
std::vector< function_mapt::const_iterator > sorted() const
returns a vector of the iterators in alphabetical order
static irep_idt entry_point()
Get the identifier of the entry point to a goto model.
A goto function, consisting of function body (see body) and parameter identifiers (see parameter_iden...
goto_programt body
symbol_tablet symbol_table
Symbol table.
Definition goto_model.h:31
goto_functionst goto_functions
GOTO functions.
Definition goto_model.h:34
instructionst instructions
The list of instructions in the goto program.
instructionst::const_iterator const_targett
Boolean implication.
Definition std_expr.h:2233
Thrown when a goto program that's being processed is in an invalid format, for example passing the wr...
bool is_not_nil() const
Definition irep.h:372
const irep_idt & id() const
Definition irep.h:388
bool is_nil() const
Definition irep.h:368
A (mathematical) lambda expression.
A type for mathematical functions (do not confuse with functions/methods in code)
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
The NIL expression.
Definition std_expr.h:3263
Boolean negation.
Definition std_expr.h:2467
Operator to return the address of an object.
Replace a symbol expression by a given expression.
void insert(const class symbol_exprt &old_expr, const exprt &new_expr)
Sets old_expr to be replaced by new_expr if we don't already have a replacement; otherwise does nothi...
bool replaces_symbol(const irep_idt &id) const
A side_effect_exprt that returns a non-deterministically chosen value.
Definition std_code.h:1520
bool use_as_const
Definition smt2_conv.h:69
bool use_array_of_bool
Definition smt2_conv.h:68
void set_to_true(source_locationt, exprt expr) override
smt2_encoding_targett(const namespacet &ns, std::ostream &_out)
void annotation(const std::string &text) override
state_encoding_smt2_convt smt2_conv
static const source_locationt & nil()
static exprt state_lambda_expr(exprt)
exprt evaluate_expr_rec(loct, const exprt &, const exprt &, const std::unordered_set< symbol_exprt, irep_hash > &) const
void setup_incoming(const goto_functiont &)
exprt forall_states_expr(loct, exprt, exprt) const
symbol_exprt in_state_expr(loct) const
void function_call(goto_programt::const_targett, encoding_targett &)
exprt address_rec(loct, const exprt &, exprt) const
goto_programt::const_targett loct
void encode(const goto_functiont &, const irep_idt function_identifier, const std::string &state_prefix, const std::vector< irep_idt > &call_stack, const std::string &annotation, const symbol_exprt &entry_state, const exprt &return_lhs, encoding_targett &)
std::string annotation
symbol_exprt out_state_expr(loct) const
state_encodingt(const goto_functionst &__goto_functions)
std::map< loct, std::vector< loct >, goto_programt::target_less_than > incomingt
exprt replace_nondet_rec(loct, const exprt &, std::vector< symbol_exprt > &nondet_symbols) const
void function_call_symbol(goto_programt::const_targett, encoding_targett &)
symbol_exprt entry_state
exprt evaluate_expr(loct, const exprt &, const exprt &) const
symbol_exprt out_state_expr(loct, bool taken) const
symbol_exprt state_expr_with_suffix(loct, const std::string &suffix) const
exprt evaluate_expr(loct, const exprt &) const
exprt assignment_constraint(loct, exprt lhs, exprt rhs) const
std::string state_prefix
std::vector< symbol_exprt > incoming_symbols(loct) const
void operator()(const goto_functionst::function_mapt::const_iterator, encoding_targett &)
static exprt state_lambda_expr(exprt)
exprt forall_states_expr(loct, exprt) const
const goto_functionst & goto_functions
Expression to hold a symbol (variable)
Definition std_expr.h:131
An expression with three operands.
Definition std_expr.h:67
exprt & op0()
Definition expr.h:134
exprt & op1()
Definition expr.h:137
exprt & op2()
Definition expr.h:140
The Boolean constant true.
Definition std_expr.h:3245
The type of an expression, extends irept.
Definition type.h:29
const exprt & new_value() const
Definition state.h:180
const exprt & address() const
Definition state.h:175
update_state_exprt(exprt state, exprt address, exprt new_value)
const exprt & state() const
Definition state.h:165
bool has_prefix(const std::string &s, const std::string &prefix)
Definition converter.cpp:13
#define CPROVER_PREFIX
#define forall_expr(it, expr)
Definition expr.h:33
std::string format_to_string(const T &o)
Definition format.h:43
Symbol Table + CFG.
#define forall_goto_program_instructions(it, program)
static typet new_state_predicate_type(const binding_exprt::variablest &variables)
void equality_propagation(std::vector< exprt > &constraints)
static void find_variables_rec(const exprt &src, std::unordered_set< symbol_exprt, irep_hash > &result)
std::unordered_set< symbol_exprt, irep_hash > find_variables(const std::vector< exprt > &src)
Returns the set of program variables (as identified by object_address expressions) in the given expre...
static symbol_exprt state_expr()
void horn_encoding(const goto_modelt &goto_model, std::ostream &out)
exprt variable_encoding(exprt src, const binding_exprt::variablest &variables)
void state_encoding(const goto_modelt &goto_model, bool program_is_inlined, encoding_targett &dest)
static void operator<<(encoding_targett &target, exprt constraint)
const update_state_exprt & to_update_state_expr(const exprt &expr)
Cast an exprt to a update_state_exprt.
const allocate_exprt & to_allocate_expr(const exprt &expr)
Cast an exprt to a allocate_exprt.
const evaluate_exprt & to_evaluate_expr(const exprt &expr)
Cast an exprt to a evaluate_exprt.
static exprt simplifying_not(exprt src)
static mathematical_function_typet state_predicate_type()
Horn-clause Encoding.
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
API to expression classes for 'mathematical' expressions.
const quantifier_exprt & to_quantifier_expr(const exprt &expr)
Cast an exprt to a quantifier_exprt.
const forall_exprt & to_forall_expr(const exprt &expr)
const function_application_exprt & to_function_application_expr(const exprt &expr)
Cast an exprt to a function_application_exprt.
STL namespace.
API to expression classes for Pointers.
const r_or_w_ok_exprt & to_r_or_w_ok_expr(const exprt &expr)
const object_address_exprt & to_object_address_expr(const exprt &expr)
Cast an exprt to an object_address_exprt.
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
#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 PRECONDITION(CONDITION)
Definition invariant.h:463
side_effect_exprt & to_side_effect_expr(exprt &expr)
Definition std_code.h:1506
API to expression classes.
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1538
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:3072
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
Definition std_expr.h:2492
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 code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition std_types.h:788
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition std_types.h:888
A total order over targett and const_targett.
dstringt irep_idt