void polynomial_acceleratort::cone_of_influence( goto_programt::instructionst &orig_body, exprt &target, goto_programt::instructionst &body, expr_sett &cone) { utils.gather_rvalues(target, cone); for (goto_programt::instructionst::reverse_iterator r_it = orig_body.rbegin(); r_it != orig_body.rend(); ++r_it) { if (r_it->is_assign()) { // XXX -- this doesn't work if the assignment is not to a symbol, e.g. // A[i] = 0; // or // *p = x; code_assignt assignment = to_code_assign(r_it->code); expr_sett lhs_syms; utils.gather_rvalues(assignment.lhs(), lhs_syms); for (expr_sett::iterator s_it = lhs_syms.begin(); s_it != lhs_syms.end(); ++s_it) { if (cone.find(*s_it) != cone.end()) { // We're assigning to something in the cone of influence -- expand the // cone. body.push_front(*r_it); cone.erase(assignment.lhs()); utils.gather_rvalues(assignment.rhs(), cone); break; } } } } }
void cone_of_influencet::get_succs( goto_programt::instructionst::const_reverse_iterator rit, expr_sett &targets) { if (rit == program.instructions.rbegin()) { return; } goto_programt::instructionst::const_reverse_iterator next = rit; --next; if (rit->is_goto()) { if (!rit->guard.is_false()) { // Branch can be taken. for (goto_programt::targetst::const_iterator t = rit->targets.begin(); t != rit->targets.end(); ++t) { unsigned int loc = (*t)->location_number; expr_sett &s = cone_map[loc]; targets.insert(s.begin(), s.end()); } } if (rit->guard.is_true()) { return; } } else if (rit->is_assume() || rit->is_assert()) { if (rit->guard.is_false()) { return; } } unsigned int loc = next->location_number; expr_sett &s = cone_map[loc]; targets.insert(s.begin(), s.end()); }
void cone_of_influencet::gather_rvalues(const exprt &expr, expr_sett &rvals) { if (expr.id() == ID_symbol || expr.id() == ID_index || expr.id() == ID_member || expr.id() == ID_dereference) { rvals.insert(expr); } else { forall_operands(it, expr) { gather_rvalues(*it, rvals); } }
void acceleration_utilst::gather_rvalues(const exprt &expr, expr_sett &rvalues) { if (expr.id() == ID_symbol || expr.id() == ID_index || expr.id() == ID_member || expr.id() == ID_dereference) { rvalues.insert(expr); } else { forall_operands(it, expr) { gather_rvalues(*it, rvalues); } }
void cone_of_influencet::cone_of_influence( const goto_programt::instructiont &i, const expr_sett &curr, expr_sett &next) { next.insert(curr.begin(), curr.end()); if(i.is_assign()) { const code_assignt &assignment=to_code_assign(i.code); expr_sett lhs_syms; bool care=false; gather_rvalues(assignment.lhs(), lhs_syms); for(const auto &expr : lhs_syms) if(curr.find(expr)!=curr.end()) { care=true; break; } next.erase(assignment.lhs()); if(care) { gather_rvalues(assignment.rhs(), next); } } }
void polynomial_acceleratort::stash_variables(scratch_programt &program, expr_sett modified, substitutiont &substitution) { find_symbols_sett vars; for (expr_sett::iterator it = modified.begin(); it != modified.end(); ++it) { find_symbols(*it, vars); } irep_idt loop_counter_name = to_symbol_expr(loop_counter).get_identifier(); vars.erase(loop_counter_name); for (find_symbols_sett::iterator it = vars.begin(); it != vars.end(); ++it) { symbolt orig = symbol_table.lookup(*it); symbolt stashed_sym = utils.fresh_symbol("polynomial::stash", orig.type); substitution[orig.symbol_expr()] = stashed_sym.symbol_expr(); program.assign(stashed_sym.symbol_expr(), orig.symbol_expr()); } }
bool polynomial_acceleratort::fit_polynomial_sliced(goto_programt::instructionst &body, exprt &var, expr_sett &influence, polynomialt &polynomial) { // These are the variables that var depends on with respect to the body. std::vector<expr_listt> parameters; std::set<std::pair<expr_listt, exprt> > coefficients; expr_listt exprs; scratch_programt program(symbol_table); exprt overflow_var = utils.fresh_symbol("polynomial::overflow", bool_typet()).symbol_expr(); overflow_instrumentert overflow(program, overflow_var, symbol_table); #ifdef DEBUG std::cout << "Fitting a polynomial for " << expr2c(var, ns) << ", which depends on:" << std::endl; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { std::cout << expr2c(*it, ns) << std::endl; } #endif for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { if (it->id() == ID_index || it->id() == ID_dereference) { // Hack: don't accelerate variables that depend on arrays... return false; } exprs.clear(); exprs.push_back(*it); parameters.push_back(exprs); exprs.push_back(loop_counter); parameters.push_back(exprs); } // N exprs.clear(); exprs.push_back(loop_counter); parameters.push_back(exprs); // N^2 exprs.push_back(loop_counter); //parameters.push_back(exprs); // Constant exprs.clear(); parameters.push_back(exprs); if (!is_bitvector(var.type())) { // We don't really know how to accelerate non-bitvectors anyway... return false; } unsigned width=to_bitvector_type(var.type()).get_width(); if(var.type().id()==ID_pointer) width=config.ansi_c.pointer_width; assert(width>0); for (std::vector<expr_listt>::iterator it = parameters.begin(); it != parameters.end(); ++it) { symbolt coeff = utils.fresh_symbol("polynomial::coeff", signedbv_typet(width)); coefficients.insert(std::make_pair(*it, coeff.symbol_expr())); } // Build a set of values for all the parameters that allow us to fit a // unique polynomial. // XXX // This isn't ok -- we're assuming 0, 1 and 2 are valid values for the // variables involved, but this might make the path condition UNSAT. Should // really be solving the path constraints a few times to get valid probe // values... std::map<exprt, int> values; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = 0; } #ifdef DEBUG std::cout << "Fitting polynomial over " << values.size() << " variables" << std::endl; #endif for (int n = 0; n <= 2; n++) { for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = 1; assert_for_values(program, values, coefficients, n, body, var, overflow); values[*it] = 0; } } // Now just need to assert the case where all values are 0 and all are 2. assert_for_values(program, values, coefficients, 0, body, var, overflow); assert_for_values(program, values, coefficients, 2, body, var, overflow); for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = 2; } assert_for_values(program, values, coefficients, 2, body, var, overflow); #ifdef DEBUG std::cout << "Fitting polynomial with program:" << std::endl; program.output(ns, "", std::cout); #endif // Now do an ASSERT(false) to grab a counterexample goto_programt::targett assertion = program.add_instruction(ASSERT); assertion->guard = false_exprt(); // If the path is satisfiable, we've fitted a polynomial. Extract the // relevant coefficients and return the expression. try { if (program.check_sat()) { utils.extract_polynomial(program, coefficients, polynomial); return true; } } catch (std::string s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } catch (const char *s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } return false; }