CBMC
acceleration_utils.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Loop Acceleration
4 
5 Author: Matt Lewis
6 
7 \*******************************************************************/
8 
11 
12 #include "acceleration_utils.h"
13 
14 #include <iostream>
15 #include <map>
16 #include <set>
17 #include <string>
18 #include <algorithm>
19 
21 
22 #include <ansi-c/expr2c.h>
23 
24 #include <util/symbol_table.h>
25 #include <util/options.h>
26 #include <util/std_code.h>
27 #include <util/find_symbols.h>
28 #include <util/simplify_expr.h>
29 #include <util/replace_expr.h>
30 #include <util/arith_tools.h>
31 
32 #include "cone_of_influence.h"
33 #include "overflow_instrumenter.h"
34 #include "scratch_program.h"
35 #include "util.h"
36 
38  const exprt &expr,
39  expr_sett &rvalues)
40 {
41  if(expr.id()==ID_symbol ||
42  expr.id()==ID_index ||
43  expr.id()==ID_member ||
44  expr.id()==ID_dereference)
45  {
46  rvalues.insert(expr);
47  }
48  else
49  {
50  forall_operands(it, expr)
51  {
52  gather_rvalues(*it, rvalues);
53  }
54  }
55 }
56 
58  const goto_programt &body,
59  expr_sett &modified)
60 {
62  find_modified(it, modified);
63 }
64 
66  const goto_programt::instructionst &instructions,
67  expr_sett &modified)
68 {
69  for(goto_programt::instructionst::const_iterator
70  it=instructions.begin();
71  it!=instructions.end();
72  ++it)
73  find_modified(it, modified);
74 }
75 
77  const patht &path,
78  expr_sett &modified)
79 {
80  for(const auto &step : path)
81  find_modified(step.loc, modified);
82 }
83 
86  expr_sett &modified)
87 {
88  for(const auto &step : loop)
89  find_modified(step, modified);
90 }
91 
94  expr_sett &modified)
95 {
96  if(t->is_assign())
97  modified.insert(t->assign_lhs());
98 }
99 
101  std::map<exprt, polynomialt> polynomials,
102  patht &path,
103  guard_managert &guard_manager)
104 {
105  // Checking that our polynomial is inductive with respect to the loop body is
106  // equivalent to checking safety of the following program:
107  //
108  // assume (target1==polynomial1);
109  // assume (target2==polynomial2)
110  // ...
111  // loop_body;
112  // loop_counter++;
113  // assert (target1==polynomial1);
114  // assert (target2==polynomial2);
115  // ...
116  scratch_programt program(symbol_table, message_handler, guard_manager);
117  std::vector<exprt> polynomials_hold;
118  substitutiont substitution;
119 
120  stash_polynomials(program, polynomials, substitution, path);
121 
122  for(std::map<exprt, polynomialt>::iterator it=polynomials.begin();
123  it!=polynomials.end();
124  ++it)
125  {
126  const equal_exprt holds(it->first, it->second.to_expr());
127  program.add(goto_programt::make_assumption(holds));
128 
129  polynomials_hold.push_back(holds);
130  }
131 
132  program.append_path(path);
133 
134  auto inc_loop_counter = code_assignt(
135  loop_counter,
137 
138  program.add(goto_programt::make_assignment(inc_loop_counter));
139 
140  ensure_no_overflows(program);
141 
142  for(const auto &p : polynomials_hold)
144 
145 #ifdef DEBUG
146  std::cout << "Checking following program for inductiveness:\n";
147  program.output(ns, irep_idt(), std::cout);
148 #endif
149 
150  try
151  {
152  if(program.check_sat(guard_manager))
153  {
154  // We found a counterexample to inductiveness... :-(
155  #ifdef DEBUG
156  std::cout << "Not inductive!\n";
157  #endif
158  return false;
159  }
160  else
161  {
162  return true;
163  }
164  }
165  catch(const std::string &s)
166  {
167  std::cout << "Error in inductiveness SAT check: " << s << '\n';
168  return false;
169  }
170  catch (const char *s)
171  {
172  std::cout << "Error in inductiveness SAT check: " << s << '\n';
173  return false;
174  }
175 }
176 
178  scratch_programt &program,
179  std::map<exprt, polynomialt> &polynomials,
180  substitutiont &substitution,
181  patht &path)
182 {
183  expr_sett modified;
184 
185  find_modified(path, modified);
186  stash_variables(program, modified, substitution);
187 
188  for(std::map<exprt, polynomialt>::iterator it=polynomials.begin();
189  it!=polynomials.end();
190  ++it)
191  {
192  it->second.substitute(substitution);
193  }
194 }
195 
197  scratch_programt &program,
198  expr_sett modified,
199  substitutiont &substitution)
200 {
201  const symbol_exprt &loop_counter_sym = to_symbol_expr(loop_counter);
202 
203  std::set<symbol_exprt> vars;
204  for(const exprt &expr : modified)
205  find_symbols(expr, vars);
206 
207  vars.erase(loop_counter_sym);
208 
209  for(const symbol_exprt &orig : vars)
210  {
211  symbolt stashed_sym = fresh_symbol("polynomial::stash", orig.type());
212  substitution[orig] = stashed_sym.symbol_expr();
213  program.assign(stashed_sym.symbol_expr(), orig);
214  }
215 }
216 
217 /*
218  * Finds a precondition which guarantees that all the assumptions and assertions
219  * along this path hold.
220  *
221  * This is not the weakest precondition, since we make underapproximations due
222  * to aliasing.
223  */
224 
226 {
227  exprt ret=false_exprt();
228 
229  for(patht::reverse_iterator r_it=path.rbegin();
230  r_it!=path.rend();
231  ++r_it)
232  {
233  goto_programt::const_targett t=r_it->loc;
234 
235  if(t->is_assign())
236  {
237  // XXX Need to check for aliasing...
238  const exprt &lhs = t->assign_lhs();
239  const exprt &rhs = t->assign_rhs();
240 
241  if(lhs.id()==ID_symbol ||
242  lhs.id()==ID_index ||
243  lhs.id()==ID_dereference)
244  {
245  replace_expr(lhs, rhs, ret);
246  }
247  else
248  {
249  throw "couldn't take WP of " + expr2c(lhs, ns) + "=" + expr2c(rhs, ns);
250  }
251  }
252  else if(t->is_assume() || t->is_assert())
253  {
254  ret = implies_exprt(t->condition(), ret);
255  }
256  else
257  {
258  // Ignore.
259  }
260 
261  if(!r_it->guard.is_true() && !r_it->guard.is_nil())
262  {
263  // The guard isn't constant true, so we need to accumulate that too.
264  ret=implies_exprt(r_it->guard, ret);
265  }
266  }
267 
268  // Hack: replace array accesses with nondet.
269  expr_mapt array_abstractions;
270  // abstract_arrays(ret, array_abstractions);
271 
272  simplify(ret, ns);
273 
274  return ret;
275 }
276 
278  exprt &expr,
279  expr_mapt &abstractions)
280 {
281  if(expr.id()==ID_index ||
282  expr.id()==ID_dereference)
283  {
284  expr_mapt::iterator it=abstractions.find(expr);
285 
286  if(it==abstractions.end())
287  {
288  symbolt sym=fresh_symbol("accelerate::array_abstraction", expr.type());
289  abstractions[expr]=sym.symbol_expr();
290  expr=sym.symbol_expr();
291  }
292  else
293  {
294  expr=it->second;
295  }
296  }
297  else
298  {
299  Forall_operands(it, expr)
300  {
301  abstract_arrays(*it, abstractions);
302  }
303  }
304 }
305 
307 {
308  Forall_operands(it, expr)
309  {
310  push_nondet(*it);
311  }
312 
313  if(expr.id() == ID_not && to_not_expr(expr).op().id() == ID_nondet)
314  {
315  expr = side_effect_expr_nondett(expr.type(), expr.source_location());
316  }
317  else if(expr.id()==ID_equal ||
318  expr.id()==ID_lt ||
319  expr.id()==ID_gt ||
320  expr.id()==ID_le ||
321  expr.id()==ID_ge)
322  {
323  const auto &rel_expr = to_binary_relation_expr(expr);
324  if(rel_expr.lhs().id() == ID_nondet || rel_expr.rhs().id() == ID_nondet)
325  {
326  expr = side_effect_expr_nondett(expr.type(), expr.source_location());
327  }
328  }
329 }
330 
332  std::map<exprt, polynomialt> polynomials,
333  patht &path,
334  exprt &guard,
335  guard_managert &guard_manager)
336 {
337  // We want to check that if an assumption fails, the next iteration can't be
338  // feasible again. To do this we check the following program for safety:
339  //
340  // loop_counter=1;
341  // assume(target1==polynomial1);
342  // assume(target2==polynomial2);
343  // ...
344  // assume(precondition);
345  //
346  // loop_counter=*;
347  // target1=polynomial1);
348  // target2=polynomial2);
349  // ...
350  // assume(!precondition);
351  //
352  // loop_counter++;
353  //
354  // target1=polynomial1;
355  // target2=polynomial2;
356  // ...
357  //
358  // assume(no overflows in above program)
359  // assert(!precondition);
360 
361  exprt condition=precondition(path);
362  scratch_programt program(symbol_table, message_handler, guard_manager);
363 
364  substitutiont substitution;
365  stash_polynomials(program, polynomials, substitution, path);
366 
367  std::vector<exprt> polynomials_hold;
368 
369  for(std::map<exprt, polynomialt>::iterator it=polynomials.begin();
370  it!=polynomials.end();
371  ++it)
372  {
373  exprt lhs=it->first;
374  exprt rhs=it->second.to_expr();
375 
376  polynomials_hold.push_back(equal_exprt(lhs, rhs));
377  }
378 
380 
381  for(std::vector<exprt>::iterator it=polynomials_hold.begin();
382  it!=polynomials_hold.end();
383  ++it)
384  {
385  program.assume(*it);
386  }
387 
388  program.assume(not_exprt(condition));
389 
390  program.assign(
391  loop_counter,
393 
394  for(std::map<exprt, polynomialt>::iterator p_it=polynomials.begin();
395  p_it!=polynomials.end();
396  ++p_it)
397  {
398  program.assign(p_it->first, p_it->second.to_expr());
399  }
400 
401  program.assume(condition);
402  program.assign(
403  loop_counter,
405 
406  for(std::map<exprt, polynomialt>::iterator p_it=polynomials.begin();
407  p_it!=polynomials.end();
408  ++p_it)
409  {
410  program.assign(p_it->first, p_it->second.to_expr());
411  }
412 
413  ensure_no_overflows(program);
414 
415  program.add(goto_programt::make_assertion(condition));
416 
417  guard=not_exprt(condition);
418  simplify(guard, ns);
419 
420 #ifdef DEBUG
421  std::cout << "Checking following program for monotonicity:\n";
422  program.output(ns, irep_idt(), std::cout);
423 #endif
424 
425  try
426  {
427  if(program.check_sat(guard_manager))
428  {
429  #ifdef DEBUG
430  std::cout << "Path is not monotone\n";
431  #endif
432 
433  return false;
434  }
435  }
436  catch(const std::string &s)
437  {
438  std::cout << "Error in monotonicity SAT check: " << s << '\n';
439  return false;
440  }
441  catch(const char *s)
442  {
443  std::cout << "Error in monotonicity SAT check: " << s << '\n';
444  return false;
445  }
446 
447 #ifdef DEBUG
448  std::cout << "Path is monotone\n";
449 #endif
450 
451  return true;
452 }
453 
455 {
456  symbolt overflow_sym=fresh_symbol("polynomial::overflow", bool_typet());
457  const exprt &overflow_var=overflow_sym.symbol_expr();
458  overflow_instrumentert instrumenter(program, overflow_var, symbol_table);
459 
460  optionst checker_options;
461 
462  checker_options.set_option("signed-overflow-check", true);
463  checker_options.set_option("unsigned-overflow-check", true);
464  checker_options.set_option("assert-to-assume", true);
465  checker_options.set_option("assumptions", true);
466  checker_options.set_option("simplify", true);
467 
468 
469 #ifdef DEBUG
470  time_t now=time(0);
471  std::cout << "Adding overflow checks at " << now << "...\n";
472 #endif
473 
474  instrumenter.add_overflow_checks();
475  program.add(goto_programt::make_assumption(not_exprt(overflow_var)));
476 
477  // goto_functionst::goto_functiont fn;
478  // fn.body.instructions.swap(program.instructions);
479  // goto_check_c(ns, checker_options, fn);
480  // fn.body.instructions.swap(program.instructions);
481 
482 #ifdef DEBUG
483  now=time(0);
484  std::cout << "Done at " << now << ".\n";
485 #endif
486 }
487 
489  goto_programt::instructionst &loop_body,
490  expr_sett &arrays_written)
491 {
492  expr_pairst assignments;
493 
494  for(goto_programt::instructionst::reverse_iterator r_it=loop_body.rbegin();
495  r_it!=loop_body.rend();
496  ++r_it)
497  {
498  if(r_it->is_assign())
499  {
500  // Is this an array assignment?
501  exprt assignment_lhs = r_it->assign_lhs();
502  exprt assignment_rhs = r_it->assign_rhs();
503 
504  if(assignment_lhs.id() == ID_index)
505  {
506  // This is an array assignment -- accumulate it in our list.
507  assignments.push_back(std::make_pair(assignment_lhs, assignment_rhs));
508 
509  // Also add this array to the set of arrays written to.
510  index_exprt index_expr = to_index_expr(assignment_lhs);
511  arrays_written.insert(index_expr.array());
512  }
513  else
514  {
515  // This is a regular assignment. Do weakest precondition on all our
516  // array expressions with respect to this assignment.
517  for(expr_pairst::iterator a_it=assignments.begin();
518  a_it!=assignments.end();
519  ++a_it)
520  {
521  replace_expr(assignment_lhs, assignment_rhs, a_it->first);
522  replace_expr(assignment_lhs, assignment_rhs, a_it->second);
523  }
524  }
525  }
526  }
527 
528  return assignments;
529 }
530 
532  goto_programt::instructionst &loop_body,
533  std::map<exprt, polynomialt> &polynomials,
534  substitutiont &substitution,
535  scratch_programt &program)
536 {
537 #ifdef DEBUG
538  std::cout << "Doing arrays...\n";
539 #endif
540 
541  expr_sett arrays_written;
542  expr_pairst array_assignments;
543 
544  array_assignments=gather_array_assignments(loop_body, arrays_written);
545 
546 #ifdef DEBUG
547  std::cout << "Found " << array_assignments.size()
548  << " array assignments\n";
549 #endif
550 
551  if(array_assignments.empty())
552  {
553  // The loop doesn't write to any arrays. We're done!
554  return true;
555  }
556 
557  polynomial_array_assignmentst poly_assignments;
558  polynomialst nondet_indices;
559 
561  array_assignments, polynomials, poly_assignments, nondet_indices))
562  {
563  // We weren't able to model some array assignment. That means we need to
564  // bail out altogether :-(
565 #ifdef DEBUG
566  std::cout << "Couldn't model an array assignment :-(\n";
567 #endif
568  return false;
569  }
570 
571  // First make all written-to arrays nondeterministic.
572  for(expr_sett::iterator it=arrays_written.begin();
573  it!=arrays_written.end();
574  ++it)
575  {
576  program.assign(
577  *it, side_effect_expr_nondett(it->type(), source_locationt()));
578  }
579 
580  // Now add in all the effects of this loop on the arrays.
581  exprt::operandst array_operands;
582 
583  for(polynomial_array_assignmentst::iterator it=poly_assignments.begin();
584  it!=poly_assignments.end();
585  ++it)
586  {
587  polynomialt stashed_index=it->index;
588  polynomialt stashed_value=it->value;
589 
590  stashed_index.substitute(substitution);
591  stashed_value.substitute(substitution);
592 
593  array_operands.push_back(equal_exprt(
594  index_exprt(it->array, stashed_index.to_expr()),
595  stashed_value.to_expr()));
596  }
597 
598  exprt arrays_expr=conjunction(array_operands);
599 
600  symbolt k_sym=fresh_symbol("polynomial::k", unsigned_poly_type());
601  const symbol_exprt k = k_sym.symbol_expr();
602 
603  const and_exprt k_bound(
604  binary_relation_exprt(from_integer(0, k.type()), ID_le, k),
606  replace_expr(loop_counter, k, arrays_expr);
607 
608  implies_exprt implies(k_bound, arrays_expr);
609 
610  const forall_exprt forall(k, implies);
611  program.assume(forall);
612 
613  // Now have to encode that the array doesn't change at indices we didn't
614  // touch.
615  for(expr_sett::iterator a_it=arrays_written.begin();
616  a_it!=arrays_written.end();
617  ++a_it)
618  {
619  exprt array=*a_it;
620  exprt old_array=substitution[array];
621  std::vector<polynomialt> indices;
622  bool nonlinear_index=false;
623 
624  for(polynomial_array_assignmentst::iterator it=poly_assignments.begin();
625  it!=poly_assignments.end();
626  ++it)
627  {
628  if(it->array==array)
629  {
630  polynomialt index=it->index;
631  index.substitute(substitution);
632  indices.push_back(index);
633 
634  if(index.max_degree(loop_counter) > 1 ||
635  (index.coeff(loop_counter)!=1 && index.coeff(loop_counter)!=-1))
636  {
637 #ifdef DEBUG
638  std::cout << expr2c(index.to_expr(), ns) << " is nonlinear\n";
639 #endif
640  nonlinear_index=true;
641  }
642  }
643  }
644 
645  exprt idx_never_touched=nil_exprt();
646  symbolt idx_sym=fresh_symbol("polynomial::idx", signed_poly_type());
647  const symbol_exprt idx = idx_sym.symbol_expr();
648 
649  // Optimization: if all the assignments to a particular array A are of the
650  // form:
651  // A[loop_counter + e]=f
652  // where e does not contain loop_counter, we don't need quantifier
653  // alternation to encode the non-changedness. We can get away
654  // with the expression:
655  // forall k; k < e || k > loop_counter+e => A[k]=old_A[k]
656 
657  if(!nonlinear_index)
658  {
659  polynomialt pos_eliminator, neg_eliminator;
660 
661  neg_eliminator.from_expr(loop_counter);
662  pos_eliminator=neg_eliminator;
663  pos_eliminator.mult(-1);
664 
665  exprt::operandst unchanged_operands;
666 
667  for(std::vector<polynomialt>::iterator it=indices.begin();
668  it!=indices.end();
669  ++it)
670  {
671  polynomialt index=*it;
672  exprt max_idx, min_idx;
673 
674  if(index.coeff(loop_counter)==1)
675  {
676  max_idx=
677  minus_exprt(
678  index.to_expr(),
679  from_integer(1, index.to_expr().type()));
680  index.add(pos_eliminator);
681  min_idx=index.to_expr();
682  }
683  else if(index.coeff(loop_counter)==-1)
684  {
685  min_idx=
686  plus_exprt(
687  index.to_expr(),
688  from_integer(1, index.to_expr().type()));
689  index.add(neg_eliminator);
690  max_idx=index.to_expr();
691  }
692  else
693  {
694  assert(!"ITSALLGONEWRONG");
695  }
696 
697  or_exprt unchanged_by_this_one(
698  binary_relation_exprt(idx, ID_lt, min_idx),
699  binary_relation_exprt(idx, ID_gt, max_idx));
700  unchanged_operands.push_back(unchanged_by_this_one);
701  }
702 
703  idx_never_touched=conjunction(unchanged_operands);
704  }
705  else
706  {
707  // The vector `indices' now contains all of the indices written
708  // to for the current array, each with the free variable
709  // loop_counter. Now let's build an expression saying that the
710  // fresh variable idx is none of these indices.
711  exprt::operandst idx_touched_operands;
712 
713  for(std::vector<polynomialt>::iterator it=indices.begin();
714  it!=indices.end();
715  ++it)
716  {
717  idx_touched_operands.push_back(
718  not_exprt(equal_exprt(idx, it->to_expr())));
719  }
720 
721  exprt idx_not_touched=conjunction(idx_touched_operands);
722 
723  // OK, we have an expression saying idx is not touched by the
724  // loop_counter'th iteration. Let's quantify that to say that
725  // idx is not touched at all.
726  symbolt l_sym=fresh_symbol("polynomial::l", signed_poly_type());
727  exprt l=l_sym.symbol_expr();
728 
729  replace_expr(loop_counter, l, idx_not_touched);
730 
731  // 0 < l <= loop_counter => idx_not_touched
732  and_exprt l_bound(
733  binary_relation_exprt(from_integer(0, l.type()), ID_lt, l),
735  implies_exprt idx_not_touched_bound(l_bound, idx_not_touched);
736 
737  idx_never_touched=exprt(ID_forall);
738  idx_never_touched.type()=bool_typet();
739  idx_never_touched.copy_to_operands(l);
740  idx_never_touched.copy_to_operands(idx_not_touched_bound);
741  }
742 
743  // We now have an expression saying idx is never touched. It is the
744  // following:
745  // forall l . 0 < l <= loop_counter => idx!=index_1 && ... && idx!=index_N
746  //
747  // Now let's build an expression saying that such an idx doesn't get
748  // updated by this loop, i.e.
749  // idx_never_touched => A[idx]==A_old[idx]
750  equal_exprt value_unchanged(
751  index_exprt(array, idx), index_exprt(old_array, idx));
752  implies_exprt idx_unchanged(idx_never_touched, value_unchanged);
753 
754  // Cool. Finally, we want to quantify over idx to say that every idx that
755  // is never touched has its value unchanged. So our expression is:
756  // forall idx . idx_never_touched => A[idx]==A_old[idx]
757  const forall_exprt array_unchanged(idx, idx_unchanged);
758 
759  // And we're done!
760  program.assume(array_unchanged);
761  }
762 
763  return true;
764 }
765 
767  expr_pairst &array_assignments,
768  std::map<exprt, polynomialt> &polynomials,
769  polynomial_array_assignmentst &array_polynomials,
770  polynomialst &nondet_indices)
771 {
772  for(expr_pairst::iterator it=array_assignments.begin();
773  it!=array_assignments.end();
774  ++it)
775  {
776  polynomial_array_assignmentt poly_assignment;
777  index_exprt index_expr=to_index_expr(it->first);
778 
779  poly_assignment.array=index_expr.array();
780 
781  if(!expr2poly(index_expr.index(), polynomials, poly_assignment.index))
782  {
783  // Couldn't convert the index -- bail out.
784 #ifdef DEBUG
785  std::cout << "Couldn't convert index: "
786  << expr2c(index_expr.index(), ns) << '\n';
787 #endif
788  return false;
789  }
790 
791 #ifdef DEBUG
792  std::cout << "Converted index to: "
793  << expr2c(poly_assignment.index.to_expr(), ns)
794  << '\n';
795 #endif
796 
797  if(it->second.id()==ID_nondet)
798  {
799  nondet_indices.push_back(poly_assignment.index);
800  }
801  else if(!expr2poly(it->second, polynomials, poly_assignment.value))
802  {
803  // Couldn't conver the RHS -- bail out.
804 #ifdef DEBUG
805  std::cout << "Couldn't convert RHS: " << expr2c(it->second, ns)
806  << '\n';
807 #endif
808  return false;
809  }
810  else
811  {
812 #ifdef DEBUG
813  std::cout << "Converted RHS to: "
814  << expr2c(poly_assignment.value.to_expr(), ns)
815  << '\n';
816 #endif
817 
818  array_polynomials.push_back(poly_assignment);
819  }
820  }
821 
822  return true;
823 }
824 
826  exprt &expr,
827  std::map<exprt, polynomialt> &polynomials,
828  polynomialt &poly)
829 {
830  exprt subbed_expr=expr;
831 
832  for(std::map<exprt, polynomialt>::iterator it=polynomials.begin();
833  it!=polynomials.end();
834  ++it)
835  {
836  replace_expr(it->first, it->second.to_expr(), subbed_expr);
837  }
838 
839 #ifdef DEBUG
840  std::cout << "expr2poly(" << expr2c(subbed_expr, ns) << ")\n";
841 #endif
842 
843  try
844  {
845  poly.from_expr(subbed_expr);
846  }
847  catch(...)
848  {
849  return false;
850  }
851 
852  return true;
853 }
854 
857  std::map<exprt, polynomialt> &polynomials,
858  substitutiont &substitution,
859  expr_sett &nonrecursive,
860  scratch_programt &program)
861 {
862  // We have some variables that are defined non-recursively -- that
863  // is to say, their value at the end of a loop iteration does not
864  // depend on their value at the previous iteration. We can solve
865  // for these variables by just forward simulating the path and
866  // taking the expressions we get at the end.
867  replace_mapt state;
868  std::unordered_set<index_exprt, irep_hash> array_writes;
869  expr_sett arrays_written;
870  expr_sett arrays_read;
871 
872  for(std::map<exprt, polynomialt>::iterator it=polynomials.begin();
873  it!=polynomials.end();
874  ++it)
875  {
876  const exprt &var=it->first;
877  polynomialt poly=it->second;
878  poly.substitute(substitution);
879  exprt e=poly.to_expr();
880 
881 #if 0
882  replace_expr(
883  loop_counter,
885  e);
886 #endif
887 
888  state[var]=e;
889  }
890 
891  for(expr_sett::iterator it=nonrecursive.begin();
892  it!=nonrecursive.end();
893  ++it)
894  {
895  exprt e=*it;
896  state[e]=e;
897  }
898 
899  for(goto_programt::instructionst::iterator it=body.begin();
900  it!=body.end();
901  ++it)
902  {
903  if(it->is_assign())
904  {
905  exprt lhs = it->assign_lhs();
906  exprt rhs = it->assign_rhs();
907 
908  if(lhs.id()==ID_dereference)
909  {
910  // Not handling pointer dereferences yet...
911 #ifdef DEBUG
912  std::cout << "Bailing out on write-through-pointer\n";
913 #endif
914  return false;
915  }
916 
917  if(lhs.id()==ID_index)
918  {
919  auto &lhs_index_expr = to_index_expr(lhs);
920  replace_expr(state, lhs_index_expr.index());
921  array_writes.insert(lhs_index_expr);
922 
923  if(arrays_written.find(lhs_index_expr.array()) != arrays_written.end())
924  {
925  // We've written to this array before -- be conservative and bail
926  // out now.
927 #ifdef DEBUG
928  std::cout << "Bailing out on array written to twice in loop: "
929  << expr2c(lhs_index_expr.array(), ns) << '\n';
930 #endif
931  return false;
932  }
933 
934  arrays_written.insert(lhs_index_expr.array());
935  }
936 
937  replace_expr(state, rhs);
938  state[lhs]=rhs;
939 
940  gather_array_accesses(rhs, arrays_read);
941  }
942  }
943 
944  // Be conservative: if we read and write from the same array, bail out.
945  for(expr_sett::iterator it=arrays_written.begin();
946  it!=arrays_written.end();
947  ++it)
948  {
949  if(arrays_read.find(*it)!=arrays_read.end())
950  {
951 #ifdef DEBUG
952  std::cout << "Bailing out on array read and written on same path\n";
953 #endif
954  return false;
955  }
956  }
957 
958  for(expr_sett::iterator it=nonrecursive.begin();
959  it!=nonrecursive.end();
960  ++it)
961  {
962  if(it->id()==ID_symbol)
963  {
964  exprt &val=state[*it];
965  program.assign(*it, val);
966 
967 #ifdef DEBUG
968  std::cout << "Fitted nonrecursive: " << expr2c(*it, ns) << "=" <<
969  expr2c(val, ns) << '\n';
970 #endif
971  }
972  }
973 
974  for(const auto &write : array_writes)
975  {
976  const auto &lhs = write;
977  const auto &rhs = state[write];
978 
979  if(!assign_array(lhs, rhs, program))
980  {
981 #ifdef DEBUG
982  std::cout << "Failed to assign a nonrecursive array: " <<
983  expr2c(lhs, ns) << "=" << expr2c(rhs, ns) << '\n';
984 #endif
985  return false;
986  }
987  }
988 
989  return true;
990 }
991 
993  const index_exprt &lhs,
994  const exprt &rhs,
995  scratch_programt &program)
996 {
997 #ifdef DEBUG
998  std::cout << "Modelling array assignment " << expr2c(lhs, ns) << "=" <<
999  expr2c(rhs, ns) << '\n';
1000 #endif
1001 
1002  if(lhs.id()==ID_dereference)
1003  {
1004  // Don't handle writes through pointers for now...
1005 #ifdef DEBUG
1006  std::cout << "Bailing out on write-through-pointer\n";
1007 #endif
1008  return false;
1009  }
1010 
1011  // We handle N iterations of the array write:
1012  //
1013  // A[i]=e
1014  //
1015  // by the following sequence:
1016  //
1017  // A'=nondet()
1018  // assume(forall 0 <= k < N . A'[i(k/loop_counter)]=e(k/loop_counter));
1019  // assume(forall j . notwritten(j) ==> A'[j]=A[j]);
1020  // A=A'
1021 
1022  const exprt &arr=lhs.op0();
1023  exprt idx=lhs.op1();
1024  const exprt &fresh_array =
1025  fresh_symbol("polynomial::array", arr.type()).symbol_expr();
1026 
1027  // First make the fresh nondet array.
1028  program.assign(
1029  fresh_array, side_effect_expr_nondett(arr.type(), lhs.source_location()));
1030 
1031  // Then assume that the fresh array has the appropriate values at the indices
1032  // the loop updated.
1033  equal_exprt changed(lhs, rhs);
1034  replace_expr(arr, fresh_array, changed);
1035 
1036  symbolt k_sym=fresh_symbol("polynomial::k", unsigned_poly_type());
1037  const symbol_exprt k = k_sym.symbol_expr();
1038 
1039  const and_exprt k_bound(
1040  binary_relation_exprt(from_integer(0, k.type()), ID_le, k),
1041  binary_relation_exprt(k, ID_lt, loop_counter));
1042  replace_expr(loop_counter, k, changed);
1043 
1044  implies_exprt implies(k_bound, changed);
1045 
1046  forall_exprt forall(k, implies);
1047  program.assume(forall);
1048 
1049  // Now let's ensure that the array did not change at the indices we
1050  // didn't touch.
1051 #ifdef DEBUG
1052  std::cout << "Trying to polynomialize " << expr2c(idx, ns) << '\n';
1053 #endif
1054 
1055  polynomialt poly;
1056 
1057  try
1058  {
1059  if(idx.id()==ID_pointer_offset)
1060  {
1061  poly.from_expr(to_pointer_offset_expr(idx).pointer());
1062  }
1063  else
1064  {
1065  poly.from_expr(idx);
1066  }
1067  }
1068  catch(...)
1069  {
1070  // idx is probably nonlinear... bail out.
1071 #ifdef DEBUG
1072  std::cout << "Failed to polynomialize\n";
1073 #endif
1074  return false;
1075  }
1076 
1077  if(poly.max_degree(loop_counter) > 1)
1078  {
1079  // The index expression is nonlinear, e.g. it's something like:
1080  //
1081  // A[x*loop_counter]=0;
1082  //
1083  // where x changes inside the loop. Modelling this requires quantifier
1084  // alternation, and that's too expensive. Bail out.
1085 #ifdef DEBUG
1086  std::cout << "Bailing out on nonlinear index: "
1087  << expr2c(idx, ns) << '\n';
1088 #endif
1089  return false;
1090  }
1091 
1092  int stride=poly.coeff(loop_counter);
1093  exprt not_touched;
1094  exprt lower_bound=idx;
1095  exprt upper_bound=idx;
1096 
1097  if(stride > 0)
1098  {
1099  replace_expr(
1100  loop_counter, from_integer(0, loop_counter.type()), lower_bound);
1101  lower_bound = simplify_expr(std::move(lower_bound), ns);
1102  }
1103  else
1104  {
1105  replace_expr(
1106  loop_counter, from_integer(0, loop_counter.type()), upper_bound);
1107  upper_bound = simplify_expr(std::move(upper_bound), ns);
1108  }
1109 
1110  if(stride==0)
1111  {
1112  // The index we write to doesn't depend on the loop counter....
1113  // We could optimise for this, but I suspect it's not going to
1114  // happen to much so just bail out.
1115 #ifdef DEBUG
1116  std::cout << "Bailing out on write to constant array index: " <<
1117  expr2c(idx, ns) << '\n';
1118 #endif
1119  return false;
1120  }
1121  else if(stride == 1 || stride == -1)
1122  {
1123  // This is the simplest case -- we have an assignment like:
1124  //
1125  // A[c + loop_counter]=e;
1126  //
1127  // where c doesn't change in the loop. The expression to say it doesn't
1128  // change at unexpected places is:
1129  //
1130  // forall k . (k < c || k >= loop_counter + c) ==> A'[k]==A[k]
1131 
1132  not_touched = or_exprt(
1133  binary_relation_exprt(k, ID_lt, lower_bound),
1134  binary_relation_exprt(k, ID_ge, upper_bound));
1135  }
1136  else
1137  {
1138  // A more complex case -- our assignment is:
1139  //
1140  // A[c + s*loop_counter]=e;
1141  //
1142  // where c and s are constants. Now our condition for an index i
1143  // to be unchanged is:
1144  //
1145  // i < c || i >= (c + s*loop_counter) || (i - c) % s!=0
1146 
1147  const minus_exprt step(k, lower_bound);
1148 
1149  not_touched = or_exprt(
1150  or_exprt(
1151  binary_relation_exprt(k, ID_lt, lower_bound),
1152  binary_relation_exprt(k, ID_ge, lower_bound)),
1154  mod_exprt(step, from_integer(stride, step.type())),
1155  from_integer(0, step.type())));
1156  }
1157 
1158  // OK now do the assumption.
1159  exprt fresh_lhs=lhs;
1160  exprt old_lhs=lhs;
1161 
1162  replace_expr(arr, fresh_array, fresh_lhs);
1163  replace_expr(loop_counter, k, fresh_lhs);
1164 
1165  replace_expr(loop_counter, k, old_lhs);
1166 
1167  equal_exprt idx_unchanged(fresh_lhs, old_lhs);
1168 
1169  implies=implies_exprt(not_touched, idx_unchanged);
1170  forall.where() = implies;
1171 
1172  program.assume(forall);
1173 
1174  // Finally, assign the array to the fresh one we've just build.
1175  program.assign(arr, fresh_array);
1176 
1177  return true;
1178 }
1179 
1181  const exprt &e,
1182  expr_sett &arrays)
1183 {
1184  if(e.id() == ID_index)
1185  {
1186  arrays.insert(to_index_expr(e).array());
1187  }
1188  else if(e.id() == ID_dereference)
1189  {
1190  arrays.insert(to_dereference_expr(e).pointer());
1191  }
1192 
1193  forall_operands(it, e)
1194  {
1195  gather_array_accesses(*it, arrays);
1196  }
1197 }
1198 
1200  scratch_programt &program,
1201  std::set<std::pair<expr_listt, exprt> > &coefficients,
1202  polynomialt &polynomial)
1203 {
1204  for(std::set<std::pair<expr_listt, exprt> >::iterator it=coefficients.begin();
1205  it!=coefficients.end();
1206  ++it)
1207  {
1208  monomialt monomial;
1209  expr_listt terms=it->first;
1210  exprt coefficient=it->second;
1211  constant_exprt concrete_term=to_constant_expr(program.eval(coefficient));
1212  std::map<exprt, int> degrees;
1213 
1214  mp_integer mp=binary2integer(concrete_term.get_value().c_str(), true);
1215  monomial.coeff = numeric_cast_v<int>(mp);
1216 
1217  if(monomial.coeff==0)
1218  {
1219  continue;
1220  }
1221 
1222  for(const auto &term : terms)
1223  {
1224  if(degrees.find(term)!=degrees.end())
1225  {
1226  degrees[term]++;
1227  }
1228  else
1229  {
1230  degrees[term]=1;
1231  }
1232  }
1233 
1234  for(std::map<exprt, int>::iterator it=degrees.begin();
1235  it!=degrees.end();
1236  ++it)
1237  {
1238  monomialt::termt term;
1239  term.var=it->first;
1240  term.exp=it->second;
1241  monomial.terms.push_back(term);
1242  }
1243 
1244  polynomial.monomials.push_back(monomial);
1245  }
1246 }
1247 
1249 {
1250  static int num_symbols=0;
1251 
1252  std::string name=base + "_" + std::to_string(num_symbols++);
1253  symbolt ret;
1254  ret.module="scratch";
1255  ret.name=name;
1256  ret.base_name=name;
1257  ret.pretty_name=name;
1258  ret.type=type;
1259 
1260  symbol_table.add(ret);
1261 
1262  return ret;
1263 }
acceleration_utilst::symbol_table
symbol_tablet & symbol_table
Definition: acceleration_utils.h:157
exprt::copy_to_operands
void copy_to_operands(const exprt &expr)
Copy the given argument to the end of exprt's operands.
Definition: expr.h:155
polynomialt::from_expr
void from_expr(const exprt &expr)
Definition: polynomial.cpp:100
overflow_instrumenter.h
dstringt::c_str
const char * c_str() const
Definition: dstring.h:115
polynomialt::add
void add(polynomialt &other)
Definition: polynomial.cpp:178
find_symbols
static bool find_symbols(symbol_kindt, const typet &, std::function< bool(const symbol_exprt &)>, std::unordered_set< irep_idt > &bindings)
Definition: find_symbols.cpp:122
polynomialt
Definition: polynomial.h:41
mp_integer
BigInt mp_integer
Definition: smt_terms.h:17
conjunction
exprt conjunction(const exprt::operandst &op)
1) generates a conjunction for two or more operands 2) for one operand, returns the operand 3) return...
Definition: std_expr.cpp:62
Forall_operands
#define Forall_operands(it, expr)
Definition: expr.h:27
arith_tools.h
acceleration_utilst::do_assumptions
bool do_assumptions(std::map< exprt, polynomialt > polynomials, patht &body, exprt &guard, guard_managert &guard_manager)
Definition: acceleration_utils.cpp:331
acceleration_utilst::expr_pairst
std::vector< expr_pairt > expr_pairst
Definition: acceleration_utils.h:95
forall_exprt
A forall expression.
Definition: mathematical_expr.h:337
to_dereference_expr
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
Definition: pointer_expr.h:716
optionst
Definition: options.h:22
typet
The type of an expression, extends irept.
Definition: type.h:28
acceleration_utilst::fresh_symbol
symbolt fresh_symbol(std::string base, typet type)
Definition: acceleration_utils.cpp:1248
acceleration_utilst::push_nondet
void push_nondet(exprt &expr)
Definition: acceleration_utils.cpp:306
to_index_expr
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1478
expr_listt
std::list< exprt > expr_listt
Definition: acceleration_utils.h:34
symbolt::type
typet type
Type of symbol.
Definition: symbol.h:31
goto_programt::instructionst
std::list< instructiont > instructionst
Definition: goto_program.h:584
acceleration_utils.h
monomialt::termt::exp
unsigned int exp
Definition: polynomial.h:26
acceleration_utilst::assign_array
bool assign_array(const index_exprt &lhs, const exprt &rhs, scratch_programt &program)
Definition: acceleration_utils.cpp:992
acceleration_utilst::message_handler
message_handlert & message_handler
Definition: acceleration_utils.h:39
and_exprt
Boolean AND.
Definition: std_expr.h:2070
goto_programt::add
targett add(instructiont &&instruction)
Adds a given instruction at the end.
Definition: goto_program.h:709
plus_exprt
The plus expression Associativity is not specified.
Definition: std_expr.h:946
acceleration_utilst::do_arrays
bool do_arrays(goto_programt::instructionst &loop_body, std::map< exprt, polynomialt > &polynomials, substitutiont &substitution, scratch_programt &program)
Definition: acceleration_utils.cpp:531
exprt
Base class for all expressions.
Definition: expr.h:55
symbolt::base_name
irep_idt base_name
Base (non-scoped) name.
Definition: symbol.h:46
scratch_program.h
options.h
optionst::set_option
void set_option(const std::string &option, const bool value)
Definition: options.cpp:28
irep_idt
dstringt irep_idt
Definition: irep.h:37
bool_typet
The Boolean type.
Definition: std_types.h:35
to_string
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
Definition: string_constraint.cpp:58
acceleration_utilst::check_inductive
bool check_inductive(std::map< exprt, polynomialt > polynomials, patht &path, guard_managert &guard_manager)
Definition: acceleration_utils.cpp:100
symbol_exprt
Expression to hold a symbol (variable)
Definition: std_expr.h:112
polynomialt::monomials
std::vector< monomialt > monomials
Definition: polynomial.h:46
equal_exprt
Equality.
Definition: std_expr.h:1305
goto_programt::make_assignment
static instructiont make_assignment(const code_assignt &_code, const source_locationt &l=source_locationt::nil())
Create an assignment instruction.
Definition: goto_program.h:1056
unsigned_poly_type
unsignedbv_typet unsigned_poly_type()
Definition: util.cpp:25
notequal_exprt
Disequality.
Definition: std_expr.h:1364
acceleration_utilst::find_modified
void find_modified(const patht &path, expr_sett &modified)
Definition: acceleration_utils.cpp:76
symbolt::pretty_name
irep_idt pretty_name
Language-specific display name.
Definition: symbol.h:52
guard_expr_managert
This is unused by this implementation of guards, but can be used by other implementations of the same...
Definition: guard_expr.h:19
acceleration_utilst::stash_polynomials
void stash_polynomials(scratch_programt &program, std::map< exprt, polynomialt > &polynomials, std::map< exprt, exprt > &stashed, patht &path)
Definition: acceleration_utils.cpp:177
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:84
polynomialt::coeff
int coeff(const exprt &expr)
Definition: polynomial.cpp:426
polynomialt::max_degree
int max_degree(const exprt &var)
Definition: polynomial.cpp:408
goto_programt::make_assertion
static instructiont make_assertion(const exprt &g, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:924
find_symbols.h
or_exprt
Boolean OR.
Definition: std_expr.h:2178
acceleration_utilst::expr2poly
bool expr2poly(exprt &expr, std::map< exprt, polynomialt > &polynomials, polynomialt &poly)
Definition: acceleration_utils.cpp:825
scratch_programt
Definition: scratch_program.h:61
monomialt::coeff
int coeff
Definition: polynomial.h:31
monomialt
Definition: polynomial.h:20
forall_operands
#define forall_operands(it, expr)
Definition: expr.h:20
signed_poly_type
signedbv_typet signed_poly_type()
Definition: util.cpp:20
expr2c.h
expr2c
std::string expr2c(const exprt &expr, const namespacet &ns, const expr2c_configurationt &configuration)
Definition: expr2c.cpp:4046
polynomialt::mult
void mult(int scalar)
Definition: polynomial.cpp:252
scratch_programt::eval
exprt eval(const exprt &e)
Definition: scratch_program.cpp:89
nil_exprt
The NIL expression.
Definition: std_expr.h:3025
symbolt::symbol_expr
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition: symbol.cpp:121
acceleration_utilst::precondition
exprt precondition(patht &path)
Definition: acceleration_utils.cpp:225
monomialt::termt::var
exprt var
Definition: polynomial.h:25
goto_programt::output
std::ostream & output(const namespacet &ns, const irep_idt &identifier, std::ostream &out) const
Output goto program to given stream.
Definition: goto_program.h:731
simplify
bool simplify(exprt &expr, const namespacet &ns)
Definition: simplify_expr.cpp:2926
simplify_expr
exprt simplify_expr(exprt src, const namespacet &ns)
Definition: simplify_expr.cpp:2931
index_exprt::index
exprt & index()
Definition: std_expr.h:1450
expr_sett
std::unordered_set< exprt, irep_hash > expr_sett
Definition: cone_of_influence.h:21
acceleration_utilst::ensure_no_overflows
void ensure_no_overflows(scratch_programt &program)
Definition: acceleration_utils.cpp:454
acceleration_utilst::extract_polynomial
void extract_polynomial(scratch_programt &program, std::set< std::pair< expr_listt, exprt >> &coefficients, polynomialt &polynomial)
Definition: acceleration_utils.cpp:1199
index_exprt::array
exprt & array()
Definition: std_expr.h:1440
to_symbol_expr
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:222
scratch_programt::assume
targett assume(const exprt &guard)
Definition: scratch_program.cpp:109
irept::id
const irep_idt & id() const
Definition: irep.h:396
acceleration_utilst::polynomial_array_assignmentst
std::vector< polynomial_array_assignmentt > polynomial_array_assignmentst
Definition: acceleration_utils.h:105
exprt::operandst
std::vector< exprt > operandst
Definition: expr.h:58
false_exprt
The Boolean constant false.
Definition: std_expr.h:3016
overflow_instrumentert
Definition: overflow_instrumenter.h:24
std_code.h
acceleration_utilst::abstract_arrays
void abstract_arrays(exprt &expr, expr_mapt &abstractions)
Definition: acceleration_utils.cpp:277
minus_exprt
Binary minus.
Definition: std_expr.h:1005
scratch_programt::append_path
void append_path(patht &path)
Definition: scratch_program.cpp:163
acceleration_utilst::array_assignments2polys
bool array_assignments2polys(expr_pairst &array_assignments, std::map< exprt, polynomialt > &polynomials, polynomial_array_assignmentst &array_polynomials, polynomialst &nondet_indices)
Definition: acceleration_utils.cpp:766
goto_program.h
natural_loops_templatet< goto_programt, goto_programt::targett >::natural_loopt
parentt::loopt natural_loopt
Definition: natural_loops.h:52
source_locationt
Definition: source_location.h:18
simplify_expr.h
side_effect_expr_nondett
A side_effect_exprt that returns a non-deterministically chosen value.
Definition: std_code.h:1519
substitutiont
std::map< exprt, exprt > substitutiont
Definition: polynomial.h:39
acceleration_utilst::polynomial_array_assignmentt::index
polynomialt index
Definition: acceleration_utils.h:100
monomialt::termt
Definition: polynomial.h:23
symbol_table_baset::add
bool add(const symbolt &symbol)
Add a new symbol to the symbol table.
Definition: symbol_table_base.cpp:18
acceleration_utilst::gather_array_assignments
expr_pairst gather_array_assignments(goto_programt::instructionst &loop_body, expr_sett &arrays_written)
Definition: acceleration_utils.cpp:488
binding_exprt::where
exprt & where()
Definition: std_expr.h:3083
polynomialt::to_expr
exprt to_expr()
Definition: polynomial.cpp:22
patht
std::list< path_nodet > patht
Definition: path.h:44
to_not_expr
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
Definition: std_expr.h:2303
polynomialt::substitute
void substitute(substitutiont &substitution)
Definition: polynomial.cpp:160
symbolt
Symbol table entry.
Definition: symbol.h:27
replace_expr
bool replace_expr(const exprt &what, const exprt &by, exprt &dest)
Definition: replace_expr.cpp:12
from_integer
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:100
acceleration_utilst::polynomial_array_assignmentt::array
exprt array
Definition: acceleration_utils.h:99
replace_mapt
std::unordered_map< exprt, exprt, irep_hash > replace_mapt
Definition: replace_expr.h:22
binary2integer
const mp_integer binary2integer(const std::string &n, bool is_signed)
convert binary string representation to mp_integer
Definition: mp_arith.cpp:117
cone_of_influence.h
acceleration_utilst::gather_array_accesses
void gather_array_accesses(const exprt &expr, expr_sett &arrays)
Definition: acceleration_utils.cpp:1180
binary_relation_exprt
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition: std_expr.h:706
polynomialst
std::vector< polynomialt > polynomialst
Definition: polynomial.h:63
acceleration_utilst::polynomial_array_assignmentt
Definition: acceleration_utils.h:97
goto_programt
A generic container class for the GOTO intermediate representation of one function.
Definition: goto_program.h:72
acceleration_utilst::loop_counter
exprt & loop_counter
Definition: acceleration_utils.h:160
to_pointer_offset_expr
const pointer_offset_exprt & to_pointer_offset_expr(const exprt &expr)
Cast an exprt to a pointer_offset_exprt.
Definition: pointer_expr.h:928
goto_programt::const_targett
instructionst::const_iterator const_targett
Definition: goto_program.h:587
acceleration_utilst::polynomial_array_assignmentt::value
polynomialt value
Definition: acceleration_utils.h:101
implies_exprt
Boolean implication.
Definition: std_expr.h:2133
acceleration_utilst::stash_variables
void stash_variables(scratch_programt &program, expr_sett modified, substitutiont &substitution)
Definition: acceleration_utils.cpp:196
goto_programt::make_assumption
static instructiont make_assumption(const exprt &g, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:936
replace_expr.h
index_exprt
Array index operator.
Definition: std_expr.h:1409
scratch_programt::check_sat
bool check_sat(bool do_slice, guard_managert &guard_manager)
Definition: scratch_program.cpp:24
symbol_table.h
Author: Diffblue Ltd.
code_assignt
A goto_instruction_codet representing an assignment in the program.
Definition: goto_instruction_code.h:22
constant_exprt
A constant literal expression.
Definition: std_expr.h:2941
symbolt::module
irep_idt module
Name of module the symbol belongs to.
Definition: symbol.h:43
binary_exprt::op1
exprt & op1()
Definition: expr.h:128
expr_mapt
std::unordered_map< exprt, exprt, irep_hash > expr_mapt
Definition: acceleration_utils.h:31
scratch_programt::assign
targett assign(const exprt &lhs, const exprt &rhs)
Definition: scratch_program.cpp:102
acceleration_utilst::gather_rvalues
void gather_rvalues(const exprt &expr, expr_sett &rvalues)
Definition: acceleration_utils.cpp:37
util.h
to_binary_relation_expr
const binary_relation_exprt & to_binary_relation_expr(const exprt &expr)
Cast an exprt to a binary_relation_exprt.
Definition: std_expr.h:840
constant_exprt::get_value
const irep_idt & get_value() const
Definition: std_expr.h:2950
exprt::source_location
const source_locationt & source_location() const
Definition: expr.h:211
symbolt::name
irep_idt name
The unique identifier.
Definition: symbol.h:40
overflow_instrumentert::add_overflow_checks
void add_overflow_checks()
Definition: overflow_instrumenter.cpp:29
acceleration_utilst::ns
namespacet ns
Definition: acceleration_utils.h:158
forall_goto_program_instructions
#define forall_goto_program_instructions(it, program)
Definition: goto_program.h:1229
binary_exprt::op0
exprt & op0()
Definition: expr.h:125
monomialt::terms
std::vector< termt > terms
Definition: polynomial.h:30
mod_exprt
Modulo defined as lhs-(rhs * truncate(lhs/rhs)).
Definition: std_expr.h:1167
not_exprt
Boolean negation.
Definition: std_expr.h:2277
acceleration_utilst::do_nonrecursive
bool do_nonrecursive(goto_programt::instructionst &loop_body, std::map< exprt, polynomialt > &polynomials, substitutiont &substitution, expr_sett &nonrecursive, scratch_programt &program)
Definition: acceleration_utils.cpp:855
to_constant_expr
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:2992