void havoc_loopst::havoc_loop( const goto_programt::targett loop_head, const loopt &loop) { assert(!loop.empty()); // first find out what can get changed in the loop modifiest modifies; get_modifies(loop, modifies); // build the havocking code goto_programt havoc_code; build_havoc_code(loop_head, modifies, havoc_code); // Now havoc at the loop head. Use insert_swap to // preserve jumps to loop head. goto_function.body.insert_before_swap(loop_head, havoc_code); // compute the loop exit goto_programt::targett loop_exit= get_loop_exit(loop); // divert all gotos to the loop head to the loop exit for(loopt::const_iterator l_it=loop.begin(); l_it!=loop.end(); l_it++) { goto_programt::instructiont &instruction=**l_it; if(instruction.is_goto()) { for(goto_programt::targetst::iterator t_it=instruction.targets.begin(); t_it!=instruction.targets.end(); t_it++) { if(*t_it==loop_head) *t_it=loop_exit; // divert } } } // remove skips remove_skip(goto_function.body); }
bool scratch_programt::check_sat(bool do_slice) { fix_types(); add_instruction(END_FUNCTION); remove_skip(*this); update(); #ifdef DEBUG std::cout << "Checking following program for satness:\n"; output(ns, "scratch", std::cout); #endif symex.constant_propagation=constant_propagation; goto_symex_statet::propagationt::valuest constants; symex(symex_state, functions, *this); if(do_slice) { slice(equation); } if(equation.count_assertions()==0) { // Symex sliced away all our assertions. #ifdef DEBUG std::cout << "Trivially unsat\n"; #endif return false; } equation.convert(*checker); #ifdef DEBUG std::cout << "Finished symex, invoking decision procedure.\n"; #endif return (checker->dec_solve()==decision_proceduret::D_SATISFIABLE); }
/* * Take the body of the loop we are accelerating and produce a fixed-path * version of that body, suitable for use in the fixed-path acceleration we * will be doing later. */ void disjunctive_polynomial_accelerationt::build_fixed() { scratch_programt scratch(symbol_table); std::map<exprt, exprt> shadow_distinguishers; fixed.copy_from(goto_program); Forall_goto_program_instructions(it, fixed) { if (it->is_assert()) { it->type = ASSUME; } } // We're only interested in paths that loop back to the loop header. // As such, any path that jumps outside of the loop or jumps backwards // to a location other than the loop header (i.e. a nested loop) is not // one we're interested in, and we'll redirect it to this assume(false). goto_programt::targett kill = fixed.add_instruction(ASSUME); kill->guard = false_exprt(); // Make a sentinel instruction to mark the end of the loop body. // We'll use this as the new target for any back-jumps to the loop // header. goto_programt::targett end = fixed.add_instruction(SKIP); // A pointer to the start of the fixed-path body. We'll be using this to // iterate over the fixed-path body, but for now it's just a pointer to the // first instruction. goto_programt::targett fixedt = fixed.instructions.begin(); // Create shadow distinguisher variables. These guys identify the path that // is taken through the fixed-path body. for (std::list<exprt>::iterator it = distinguishers.begin(); it != distinguishers.end(); ++it) { exprt &distinguisher = *it; symbolt shadow_sym = utils.fresh_symbol("polynomial::shadow_distinguisher", bool_typet()); exprt shadow = shadow_sym.symbol_expr(); shadow_distinguishers[distinguisher] = shadow; goto_programt::targett assign = fixed.insert_before(fixedt); assign->make_assignment(); assign->code = code_assignt(shadow, false_exprt()); } // We're going to iterate over the 2 programs in lockstep, which allows // us to figure out which distinguishing point we've hit & instrument // the relevant distinguisher variables. for (goto_programt::targett t = goto_program.instructions.begin(); t != goto_program.instructions.end(); ++t, ++fixedt) { distinguish_mapt::iterator d = distinguishing_points.find(t); if (loop.find(t) == loop.end()) { // This instruction isn't part of the loop... Just remove it. fixedt->make_skip(); continue; } if (d != distinguishing_points.end()) { // We've hit a distinguishing point. Set the relevant shadow // distinguisher to true. exprt &distinguisher = d->second; exprt &shadow = shadow_distinguishers[distinguisher]; goto_programt::targett assign = fixed.insert_after(fixedt); assign->make_assignment(); assign->code = code_assignt(shadow, true_exprt()); assign->swap(*fixedt); fixedt = assign; } if (t->is_goto()) { assert(fixedt->is_goto()); // If this is a forwards jump, it's either jumping inside the loop // (in which case we leave it alone), or it jumps outside the loop. // If it jumps out of the loop, it's on a path we don't care about // so we kill it. // // Otherwise, it's a backwards jump. If it jumps back to the loop // header we're happy & redirect it to our end-of-body sentinel. // If it jumps somewhere else, it's part of a nested loop and we // kill it. for (goto_programt::targetst::iterator target = t->targets.begin(); target != t->targets.end(); ++target) { if ((*target)->location_number > t->location_number) { // A forward jump... if (loop.find(*target) != loop.end()) { // Case 1: a forward jump within the loop. Do nothing. continue; } else { // Case 2: a forward jump out of the loop. Kill. fixedt->targets.clear(); fixedt->targets.push_back(kill); } } else { // A backwards jump... if (*target == loop_header) { // Case 3: a backwards jump to the loop header. Redirect to sentinel. fixedt->targets.clear(); fixedt->targets.push_back(end); } else { // Case 4: a nested loop. Kill. fixedt->targets.clear(); fixedt->targets.push_back(kill); } } } } } // OK, now let's assume that the path we took through the fixed-path // body is the same as the master path. We do this by assuming that // each of the shadow-distinguisher variables is equal to its corresponding // master-distinguisher. for (std::list<exprt>::iterator it = distinguishers.begin(); it != distinguishers.end(); ++it) { exprt &shadow = shadow_distinguishers[*it]; fixed.insert_after(end)->make_assumption(equal_exprt(*it, shadow)); } // Finally, let's remove all the skips we introduced and fix the // jump targets. fixed.update(); remove_skip(fixed); }
void remove_skip(goto_functionst &goto_functions) { Forall_goto_functions(f_it, goto_functions) remove_skip(f_it->second.body); }
void k_inductiont::process_loop( const goto_programt::targett loop_head, const loopt &loop) { assert(!loop.empty()); // compute the loop exit goto_programt::targett loop_exit= get_loop_exit(loop); if(base_case) { // now unwind k times unwind(goto_function.body, loop_head, loop_exit, k); // assume the loop condition has become false goto_programt::instructiont assume(ASSUME); assume.guard=loop_head->guard; goto_function.body.insert_before_swap(loop_exit, assume); } if(step_case) { // step case // find out what can get changed in the loop modifiest modifies; get_modifies(loop, modifies); // build the havoc-ing code goto_programt havoc_code; build_havoc_code(loop_head, modifies, havoc_code); // unwind to get k+1 copies std::vector<goto_programt::targett> iteration_points; unwind(goto_function.body, loop_head, loop_exit, k+1, iteration_points); // now turn any assertions in iterations 0..k-1 into assumptions assert(iteration_points.size()==k+1); assert(k>=1); goto_programt::targett end=iteration_points[k-1]; std::size_t it_p_count=0; bool after_it_p=true; for(goto_programt::targett t=loop_head; t!=end; t++) { assert(t!=goto_function.body.instructions.end()); if(t->is_assert()) t->type=ASSUME; if(t==iteration_points[it_p_count]) { after_it_p=true; ++it_p_count; } else if(t->is_goto() && after_it_p) { assert(t==loop_head || not_exprt(t->guard)==loop_head->guard); t->type=ASSUME; t->targets.clear(); t->guard=not_exprt(t->guard); after_it_p=false; } } // assume the loop condition has become false goto_programt::instructiont assume(ASSUME); assume.guard=to_not_expr(loop_head->guard).op(); goto_function.body.insert_before_swap(loop_exit, assume); // Now havoc at the loop head. Use insert_swap to // preserve jumps to loop head. goto_function.body.insert_before_swap(loop_head, havoc_code); } // remove skips remove_skip(goto_function.body); }
void k_inductiont::process_loop( const goto_programt::targett loop_head, const loopt &loop) { assert(!loop.empty()); // save the loop guard const exprt loop_guard=loop_head->guard; // compute the loop exit goto_programt::targett loop_exit= get_loop_exit(loop); if(base_case) { // now unwind k times unwind(goto_function.body, loop_head, loop_exit, k); // assume the loop condition has become false goto_programt::instructiont assume(ASSUME); assume.guard=loop_guard; goto_function.body.insert_before_swap(loop_exit, assume); } if(step_case) { // step case // find out what can get changed in the loop modifiest modifies; get_modifies(loop, modifies); // build the havoc-ing code goto_programt havoc_code; build_havoc_code(loop_head, modifies, havoc_code); // unwind to get k+1 copies std::vector<goto_programt::targett> iteration_points; unwind(goto_function.body, loop_head, loop_exit, k+1, iteration_points); // we can remove everything up to the first assertion for(goto_programt::targett t=loop_head; t!=loop_exit; t++) { if(t->is_assert()) break; t->make_skip(); } // now turn any assertions in iterations 0..k-1 into assumptions assert(iteration_points.size()==k+1); assert(k>=1); goto_programt::targett end=iteration_points[k-1]; for(goto_programt::targett t=loop_head; t!=end; t++) { assert(t!=goto_function.body.instructions.end()); if(t->is_assert()) t->type=ASSUME; } // assume the loop condition has become false goto_programt::instructiont assume(ASSUME); assume.guard=loop_guard; goto_function.body.insert_before_swap(loop_exit, assume); // Now havoc at the loop head. Use insert_swap to // preserve jumps to loop head. goto_function.body.insert_before_swap(loop_head, havoc_code); } // remove skips remove_skip(goto_function.body); }