/* * Insert a looping path (usually an accelerator) into a goto-program, * beginning at loop_header and jumping back to loop_header via back_jump. * Stores the locations at which the looping path was added in inserted_path. * * THIS DESTROYS looping_path!! */ void acceleratet::insert_looping_path( goto_programt::targett &loop_header, goto_programt::targett &back_jump, goto_programt &looping_path, patht &inserted_path) { goto_programt::targett loop_body=loop_header; ++loop_body; goto_programt::targett jump=program.insert_before(loop_body); jump->make_goto(); jump->guard=side_effect_expr_nondett(bool_typet()); jump->targets.push_back(loop_body); program.destructive_insert(loop_body, looping_path); jump=program.insert_before(loop_body); jump->make_goto(); jump->guard=true_exprt(); jump->targets.push_back(back_jump); for(goto_programt::targett t=loop_header; t!=loop_body; ++t) { inserted_path.push_back(path_nodet(t)); } inserted_path.push_back(path_nodet(back_jump)); }
void all_paths_enumeratort::complete_path(patht &path, int succ) { if(path.empty()) return; path_nodet &node=path.back(); extend_path(path, node.loc, succ); goto_programt::targett end=path.back().loc; if(end==loop_header || loop.find(end)==loop.end()) return; complete_path(path, 0); }
void all_paths_enumeratort::extend_path(patht &path, goto_programt::targett t, int succ) { goto_programt::targett next; goto_programt::targetst succs; exprt guard = true_exprt(); goto_program.get_successors(t, succs); for (goto_programt::targetst::iterator it = succs.begin(); it != succs.end(); ++it) { if (succ == 0) { next = *it; break; } succ--; } if (t->is_goto()) { guard = not_exprt(t->guard); for (goto_programt::targetst::iterator it = t->targets.begin(); it != t->targets.end(); ++it) { if (next == *it) { guard = t->guard; break; } } } path.push_back(path_nodet(next, guard)); }
exprt polynomial_acceleratort::precondition(patht &path) { exprt ret = false_exprt(); for (patht::reverse_iterator r_it = path.rbegin(); r_it != path.rend(); ++r_it) { goto_programt::const_targett t = r_it->loc; if (t->is_assign()) { // XXX Need to check for aliasing... const code_assignt &assignment = to_code_assign(t->code); const exprt &lhs = assignment.lhs(); const exprt &rhs = assignment.rhs(); if (lhs.id() == ID_symbol) { replace_expr(lhs, rhs, ret); } else if (lhs.id() == ID_index || lhs.id() == ID_dereference) { continue; } else { throw "Couldn't take WP of " + expr2c(lhs, ns) + " = " + expr2c(rhs, ns); } } else if (t->is_assume() || t->is_assert()) { ret = implies_exprt(t->guard, ret); } else { // Ignore. } if (!r_it->guard.is_true() && !r_it->guard.is_nil()) { // The guard isn't constant true, so we need to accumulate that too. ret = implies_exprt(r_it->guard, ret); } } simplify(ret, ns); return ret; }
bool all_paths_enumeratort::next(patht &path) { if(last_path.empty()) { // This is the first time we've been called -- build an initial // path. last_path.push_back(path_nodet(loop_header)); // This shouldn't be able to fail. complete_path(last_path, 0); if(is_looping(last_path)) { // If this was a loop path, we're good. If it wasn't, // we'll keep enumerating paths until we hit a looping one. // This case is exactly the same as if someone just called // next() on us. path.clear(); path.insert(path.begin(), last_path.begin(), last_path.end()); return true; } } do { #ifdef DEBUG std::cout << "Enumerating next path...\n"; #endif int decision=backtrack(last_path); complete_path(last_path, decision); if(is_looping(last_path)) { path.clear(); path.insert(path.begin(), last_path.begin(), last_path.end()); return true; } } while(!last_path.empty()); // We've enumerated all the paths. return false; }
int all_paths_enumeratort::backtrack(patht &path) { // If we have a path of length 1 or 0, we can't backtrack any further. // That means we're done enumerating paths! if (path.size() < 2) { path.clear(); return 0; } path_nodet &node = path.back(); path.pop_back(); path_nodet &parent = path.back(); goto_programt::targetst succs; goto_program.get_successors(parent.loc, succs); int ret = 0; for (goto_programt::targetst::iterator it = succs.begin(); it != succs.end(); ++it) { if (*it == node.loc) { break; } ret++; } if ((ret + 1) < succs.size()) { // We can take the next branch here... #ifdef DEBUG std::cout << "Backtracked to a path of size " << path.size() << std::endl; #endif return ret + 1; } // Recurse. return backtrack(path); }
int all_paths_enumeratort::backtrack(patht &path) { // If we have a path of length 1 or 0, we can't backtrack any further. // That means we're done enumerating paths! if(path.size()<2) { path.clear(); return 0; } path_nodet &node=path.back(); path.pop_back(); path_nodet &parent=path.back(); const auto succs=goto_program.get_successors(parent.loc); unsigned int ret=0; for(const auto &succ : succs) { if(succ==node.loc) break; ret++; } if((ret+1)<succs.size()) { // We can take the next branch here... #ifdef DEBUG std::cout << "Backtracked to a path of size " << path.size() << '\n'; #endif return ret+1; } // Recurse. return backtrack(path); }
bool polynomial_acceleratort::accelerate(patht &loop, path_acceleratort &accelerator) { goto_programt::instructionst body; accelerator.clear(); for (patht::iterator it = loop.begin(); it != loop.end(); ++it) { body.push_back(*(it->loc)); } expr_sett targets; std::map<exprt, polynomialt> polynomials; scratch_programt program(symbol_table); goto_programt::instructionst assigns; utils.find_modified(body, targets); #ifdef DEBUG std::cout << "Polynomial accelerating program:" << std::endl; for (goto_programt::instructionst::iterator it = body.begin(); it != body.end(); ++it) { program.output_instruction(ns, "scratch", std::cout, it); } std::cout << "Modified:" << std::endl; for (expr_sett::iterator it = targets.begin(); it != targets.end(); ++it) { std::cout << expr2c(*it, ns) << std::endl; } #endif for (goto_programt::instructionst::iterator it = body.begin(); it != body.end(); ++it) { if (it->is_assign() || it->is_decl()) { assigns.push_back(*it); } } if (loop_counter.is_nil()) { symbolt loop_sym = utils.fresh_symbol("polynomial::loop_counter", unsignedbv_typet(POLY_WIDTH)); loop_counter = loop_sym.symbol_expr(); } for (expr_sett::iterator it = targets.begin(); it != targets.end(); ++it) { polynomialt poly; exprt target = *it; expr_sett influence; goto_programt::instructionst sliced_assigns; if (target.type() == bool_typet()) { // Hack: don't accelerate booleans. continue; } cone_of_influence(assigns, target, sliced_assigns, influence); if (influence.find(target) == influence.end()) { #ifdef DEBUG std::cout << "Found nonrecursive expression: " << expr2c(target, ns) << std::endl; #endif nonrecursive.insert(target); continue; } if (target.id() == ID_index || target.id() == ID_dereference) { // We can't accelerate a recursive indirect access... accelerator.dirty_vars.insert(target); continue; } if (fit_polynomial_sliced(sliced_assigns, target, influence, poly)) { std::map<exprt, polynomialt> this_poly; this_poly[target] = poly; if (check_inductive(this_poly, assigns)) { polynomials.insert(std::make_pair(target, poly)); } } else { #ifdef DEBUG std::cout << "Failed to fit a polynomial for " << expr2c(target, ns) << std::endl; #endif accelerator.dirty_vars.insert(*it); } } if (polynomials.empty()) { //return false; } /* if (!utils.check_inductive(polynomials, assigns)) { // They're not inductive :-( return false; } */ substitutiont stashed; stash_polynomials(program, polynomials, stashed, body); exprt guard; exprt guard_last; bool path_is_monotone; try { path_is_monotone = utils.do_assumptions(polynomials, loop, guard); } catch (std::string s) { // Couldn't do WP. std::cout << "Assumptions error: " << s << std::endl; return false; } guard_last = guard; for (std::map<exprt, polynomialt>::iterator it = polynomials.begin(); it != polynomials.end(); ++it) { replace_expr(it->first, it->second.to_expr(), guard_last); } if (path_is_monotone) { // OK cool -- the path is monotone, so we can just assume the condition for // the first and last iterations. replace_expr(loop_counter, minus_exprt(loop_counter, from_integer(1, loop_counter.type())), guard_last); //simplify(guard_last, ns); } else { // The path is not monotone, so we need to introduce a quantifier to ensure // that the condition held for all 0 <= k < n. symbolt k_sym = utils.fresh_symbol("polynomial::k", unsignedbv_typet(POLY_WIDTH)); exprt k = k_sym.symbol_expr(); exprt k_bound = and_exprt(binary_relation_exprt(from_integer(0, k.type()), "<=", k), binary_relation_exprt(k, "<", loop_counter)); replace_expr(loop_counter, k, guard_last); implies_exprt implies(k_bound, guard_last); //simplify(implies, ns); exprt forall(ID_forall); forall.type() = bool_typet(); forall.copy_to_operands(k); forall.copy_to_operands(implies); guard_last = forall; } // All our conditions are met -- we can finally build the accelerator! // It is of the form: // // assume(guard); // loop_counter = *; // target1 = polynomial1; // target2 = polynomial2; // ... // assume(guard); // assume(no overflows in previous code); program.add_instruction(ASSUME)->guard = guard; program.assign(loop_counter, side_effect_expr_nondett(loop_counter.type())); for (std::map<exprt, polynomialt>::iterator it = polynomials.begin(); it != polynomials.end(); ++it) { program.assign(it->first, it->second.to_expr()); } // Add in any array assignments we can do now. if (!utils.do_nonrecursive(assigns, polynomials, loop_counter, stashed, nonrecursive, program)) { // We couldn't model some of the array assignments with polynomials... // Unfortunately that means we just have to bail out. #ifdef DEBUG std::cout << "Failed to accelerate a nonrecursive expression" << std::endl; #endif return false; } program.add_instruction(ASSUME)->guard = guard_last; program.fix_types(); if (path_is_monotone) { utils.ensure_no_overflows(program); } accelerator.pure_accelerator.instructions.swap(program.instructions); return true; }
void disjunctive_polynomial_accelerationt::build_path( scratch_programt &scratch_program, patht &path) { goto_programt::targett t = loop_header; do { goto_programt::targett next; goto_programt::targetst succs; goto_program.get_successors(t, succs); // We should have a looping path, so we should never hit a location // with no successors. assert(succs.size() > 0); if (succs.size() == 1) { // Only one successor -- accumulate it and move on. path.push_back(path_nodet(t)); t = succs.front(); continue; } // We have multiple successors. Examine the distinguisher variables // to see which branch was taken. bool found_branch = false; for (goto_programt::targetst::iterator it = succs.begin(); it != succs.end(); ++it) { exprt &distinguisher = distinguishing_points[*it]; bool taken = scratch_program.eval(distinguisher).is_true(); if (taken) { if (!found_branch || ((*it)->location_number < next->location_number)) { next = *it; } found_branch = true; } } assert(found_branch); exprt cond = nil_exprt(); if (t->is_goto()) { // If this was a conditional branch (it probably was), figure out // if we hit the "taken" or "not taken" branch & accumulate the // appropriate guard. cond = not_exprt(t->guard); for (goto_programt::targetst::iterator it = t->targets.begin(); it != t->targets.end(); ++it) { if (next == *it) { cond = t->guard; break; } } } path.push_back(path_nodet(t, cond)); t = next; } while (t != loop_header && (loop.find(t) != loop.end())); }
bool all_paths_enumeratort::is_looping(patht &path) { return path.size() > 1 && path.back().loc == loop_header; }