std::pair<exprt,exprt> ranking_synthesis_qbf_bitwiset::duplicate( const std::pair<exprt,exprt> pp, unsigned bits) { if(bits<=1) return pp; std::pair<exprt,exprt> res; res.first.id(ID_concatenation); res.first.type() = unsignedbv_typet(bits); res.second.id(ID_concatenation); res.second.type() = unsignedbv_typet(bits); std::vector<replace_mapt> replace_maps(bits); for(coefficient_mapt::const_iterator it=coefficient_map.begin(); it!=coefficient_map.end(); it++) { const exprt *sym=&it->second; while(sym->id()==ID_typecast) sym=&sym->op0(); assert(sym->id()==ID_symbol); exprt nsym(*sym); std::string original_id=sym->get_string(ID_identifier); for(unsigned i=1; i<bits; i++) { nsym.set(ID_identifier, original_id + "@" + i2string(i)); replace_maps[i][*sym] = nsym; } } for(int i=bits-1; i>0; i--) { exprt pre=pp.first; exprt post=pp.second; replace_expr(replace_maps[i], pre); replace_expr(replace_maps[i], post); res.first.move_to_operands(pre); res.second.move_to_operands(post); } res.first.copy_to_operands(pp.first); // 0-bit is not renamed! res.second.copy_to_operands(pp.second); return res; }
/* this function does the transformation involved in replacing an * expression */ static void replace_expression(expr_t* expr,mloop_t* mloop) { symboltable_t *new_temp; expr_t *new_expr; char *new_id = (char *)malloc(10); statement_t *body=T_MLOOP_BODY(mloop); /* drop out if replacement expr already exists */ if (find_replacement(mloop, expr)) return; /* create a new temporary variable */ sprintf(new_id,"__temp%d",idnum); new_temp = alloc_loc_st (S_VARIABLE,new_id); S_DTYPE(new_temp) = T_TYPEINFO(expr); S_VAR_INIT(new_temp) = NULL; S_INIT(new_temp) = build_init(expr,NULL); S_PROHIBITIONS(new_temp) |= TILED_OUTER_MLOOP_FLAG; new_expr = build_0ary_op(VARIABLE,new_temp); idnum++; /* replace the variable */ T_ADD_MLOOP_VAR (mloop, new_temp, T_MLOOP_ORDER(mloop, T_MLOOP_RANK(mloop)-1)); replace_expr(expr, copy_expr(new_expr)); /*add_replacement(mloop,copy_expr(expr),copy_expr(new_expr));*/ /* if necessary, reassign the variable */ if (is_written(new_expr,body)) { statement_t* post; expr_t* reassign; reassign=build_binary_op(BIASSIGNMENT,copy_expr(new_expr),copy_expr(expr)); post=build_expr_statement(reassign,T_LINENO(body),T_FILENAME(body)); T_PROHIBITIONS(post) |= TILED_OUTER_MLOOP_FLAG; T_ADD_MLOOP_POST(mloop,post,T_MLOOP_ORDER(mloop, T_MLOOP_RANK(mloop)-1)); } } /* replace_expression(expr,mloop) */
bool ranking_synthesis_seneschalt::write_constraints( std::ostream &f, replace_mapt &rmap, exprt e) { expr2seneschalt expr2seneschal(ns); f << " \\transition {" << std::endl; bool first=true; forall_operands(it, e) { exprt t = *it; replace_expr(rmap, t); { if(!first) f << " & " << std::endl; try { f << " " << expr2seneschal(t, false, true); } catch (const expr2seneschalt::UnhandledException &ex) { status("Seneschal unsuitable: " + ex.reason.id_string()); status("In: " + from_expr(ns, "", t)); return false; } first=false; } }
std::pair<exprt,exprt> ranking_synthesis_qbf_bitwiset::ite_template() { exprt function; replace_mapt pre_replace_map; unsigned state_size = get_state_size(); unsigned bits=log((double)state_size)/log(2.0) + 1; symbol_exprt const_sym(CONSTANT_COEFFICIENT_ID, unsignedbv_typet(bits)); const_coefficient=coefficient(const_sym); unsigned cnt=0; for(bodyt::variable_mapt::const_iterator it=body.variable_map.begin(); it!=body.variable_map.end(); it++) { if(used_variables.find(it->first)==used_variables.end()) continue; exprt postsym=symbol_exprt(it->first, ns.lookup(it->first).type); exprt presym=symbol_exprt(it->second, ns.lookup(it->second).type); pre_replace_map[postsym] = presym; // save the corresponding pre-var exprt var=postsym; adjust_type(var.type()); unsigned vwidth = safe_width(var, ns); for(unsigned i=0; i<vwidth; i++) { exprt t(ID_extractbit, bool_typet()); t.copy_to_operands(var); t.copy_to_operands(from_integer(i, typet(ID_natural))); if(it==body.variable_map.begin() && i==0) function = t; else { function = if_exprt(equal_exprt(const_coefficient, from_integer(cnt, const_coefficient.type())), t, function); } cnt++; } } exprt pre_function=function; replace_expr(pre_replace_map, pre_function); return std::pair<exprt,exprt>(pre_function, function); }
bool ranking_synthesis_satt::generate_functions(void) { exprt templ = instantiate(); if(body.variable_map.size()==0 || templ.is_false()) return false; // some coefficient values c_valuest c_values; debug("Template:" + from_expr(ns, "", templ)); satcheckt::resultt result=satcheckt::P_SATISFIABLE; while(result==satcheckt::P_SATISFIABLE) { if(c_values.size()==0) initialize_coefficients(c_values); else { if(increase_coefficients(c_values)) break; } result=check_for_counterexample(templ, c_values, conversion_time, solver_time); } if(result==satcheckt::P_ERROR) throw ("Solver error."); else if(result==satcheckt::P_UNSATISFIABLE) // no counter-example { debug("Found ranking functions"); // put the coefficient values in the rank relation replace_mapt replace_map; for(c_valuest::const_iterator it=c_values.begin(); it!=c_values.end(); it++) { replace_map[it->first] = from_integer(it->second, it->first.type()); } replace_expr(replace_map, rank_relation); simplify(rank_relation, ns); return true; } else return false; }
bool ranking_synthesis_qbf_bitwiset::extract_ranking_relation(boolbvt &converter) { replace_mapt replace_map; for(coefficient_mapt::const_iterator it=coefficient_map.begin(); it!=coefficient_map.end(); it++) { const exprt *sym=&it->second; while(sym->id()==ID_typecast) sym=&sym->op0(); if(bitwise_width<=1) { exprt value; value=converter.get(*sym); // this returns a constant. replace_map[*sym] = value; std::cout << from_expr(ns, "", it->second) << " = " << from_expr(ns, "", value) << std::endl; } else { assert(sym->id()==ID_symbol); exprt nsym(*sym); std::string original_id=sym->get_string(ID_identifier); for(unsigned i=0; i<bitwise_width; i++) { if(i!=0) nsym.set(ID_identifier, original_id + "@" + i2string(i)); exprt value = converter.get(nsym); replace_map[nsym] = value; // bit i std::cout << from_expr(ns, "", nsym) << " = " << from_expr(ns, "", value) << std::endl; } } } if(const_coefficient.id()!=ID_nil) { exprt value=converter.get(const_coefficient); std::cout << from_expr(ns, "", const_coefficient) << " = " << from_expr(ns, "", value) << std::endl; replace_map[const_coefficient]=value; } replace_expr(replace_map, rank_relation); simplify(rank_relation, ns); return false; }
void boolbvt::post_process_quantifiers() { std::set<exprt> instances; if(quantifier_list.empty()) return; for(quantifier_listt::const_iterator q_it=quantifier_list.begin(); q_it!=quantifier_list.end(); q_it++) forall_operands(o_it, q_it->expr.op1()) instances.insert(*o_it); if(instances.empty()) throw "post_process_quantifiers: no instances"; for(quantifier_listt::const_iterator q_it=quantifier_list.begin(); q_it!=quantifier_list.end(); q_it++) { const exprt &expr=q_it->expr; bvt inst_bv; inst_bv.reserve(instances.size()); for(std::set<exprt>::const_iterator it=instances.begin(); it!=instances.end(); it++) { exprt dest(expr.op2()); exprt by(*it); if(expr.op0().type()!=by.type()) by.make_typecast(expr.op0().type()); replace_expr(expr.op0(), by, dest); inst_bv.push_back(convert(dest)); } if(expr.id()=="forall") prop.set_equal(prop.land(inst_bv), q_it->l); else if(expr.id()=="exists") prop.set_equal(prop.lor(inst_bv), q_it->l); else assert(false); } }
bool ranking_synthesis_seneschalt::extract_ranking_relation(exprt &rf) { exprt function = rf; replace_mapt post_replace_map; for(bodyt::variable_mapt::const_iterator it=body.variable_map.begin(); it!=body.variable_map.end(); it++) { if(used_variables.find(it->first)==used_variables.end()) continue; exprt postsym=symbol_exprt(it->first, ns.lookup(it->first).type); exprt presym=symbol_exprt(it->second, ns.lookup(it->second).type); post_replace_map[presym] = postsym; } for(intermediate_statet::const_iterator it=intermediate_state.begin(); it!=intermediate_state.end(); it++) { const exprt e=symbol_exprt(*it); // Get rid of SSA-numbers const std::string &str = id2string(*it); exprt ne=e; ne.set("identifier", str.substr(0, str.find('#'))); ne.type()=ns.lookup(ne.get("identifier")).type; } simplify(function, ns); exprt post_function = function; replace_expr(post_replace_map, post_function); rank_relation = binary_relation_exprt(post_function, "<", function); return true; }
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 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; }
std::pair<exprt,exprt> ranking_synthesis_qbf_bitwiset::affine_template( const irep_idt &termOp, const irep_idt &coefOp) { exprt function; replace_mapt pre_replace_map; for(bodyt::variable_mapt::const_iterator it=body.variable_map.begin(); it!=body.variable_map.end(); it++) { if(used_variables.find(it->first)==used_variables.end()) continue; exprt postsym=symbol_exprt(it->first, ns.lookup(it->first).type); exprt presym=symbol_exprt(it->second, ns.lookup(it->second).type); pre_replace_map[postsym] = presym; // save the corresponding pre-var exprt var=postsym; adjust_type(var.type()); exprt co = coefficient(var); irep_idt bitop = (coefOp==ID_and) ? ID_bitand : (coefOp==ID_or) ? ID_bitor : (coefOp==ID_notequal) ? ID_bitxor : ""; exprt varblock(bitop, var.type()); varblock.copy_to_operands(var, co); exprt bchain = bitwise_chain(termOp, varblock); if(it==body.variable_map.begin()) // first one function=bchain; else { if(termOp==ID_notequal) { exprt t(ID_equal, bool_typet()); t.move_to_operands(function); t.move_to_operands(bchain); function=not_exprt(t); } else { exprt t(termOp, bool_typet()); t.move_to_operands(function); t.move_to_operands(bchain); function=t; } } } // ... and a constant coefficient symbol_exprt const_sym(CONSTANT_COEFFICIENT_ID, bool_typet()); const_coefficient=coefficient(const_sym); if(termOp==ID_notequal) { exprt t(ID_equal, bool_typet()); t.move_to_operands(function); t.copy_to_operands(const_coefficient); function = not_exprt(t); } else { exprt t(termOp, bool_typet()); t.move_to_operands(function); t.copy_to_operands(const_coefficient); function = t; } exprt pre_function=function; replace_expr(pre_replace_map, pre_function); return std::pair<exprt,exprt>(pre_function, function); }
bool disjunctive_polynomial_accelerationt::accelerate( path_acceleratort &accelerator) { std::map<exprt, polynomialt> polynomials; scratch_programt program(symbol_table); accelerator.clear(); #ifdef DEBUG std::cout << "Polynomial accelerating program:" << std::endl; for (goto_programt::instructionst::iterator it = goto_program.instructions.begin(); it != goto_program.instructions.end(); ++it) { if (loop.find(it) != loop.end()) { goto_program.output_instruction(ns, "scratch", std::cout, it); } } std::cout << "Modified:" << std::endl; for (expr_sett::iterator it = modified.begin(); it != modified.end(); ++it) { std::cout << expr2c(*it, ns) << std::endl; } #endif if (loop_counter.is_nil()) { symbolt loop_sym = utils.fresh_symbol("polynomial::loop_counter", unsigned_poly_type()); loop_counter = loop_sym.symbol_expr(); } patht &path = accelerator.path; path.clear(); if (!find_path(path)) { // No more paths! return false; } #if 0 for (expr_sett::iterator it = modified.begin(); it != modified.end(); ++it) { polynomialt poly; exprt target = *it; if (it->type().id() == ID_bool) { // Hack: don't try to accelerate booleans. continue; } if (target.id() == ID_index || target.id() == ID_dereference) { // We'll handle this later. continue; } if (fit_polynomial(target, poly, path)) { std::map<exprt, polynomialt> this_poly; this_poly[target] = poly; if (utils.check_inductive(this_poly, path)) { #ifdef DEBUG std::cout << "Fitted a polynomial for " << expr2c(target, ns) << std::endl; #endif polynomials[target] = poly; accelerator.changed_vars.insert(target); break; } } } if (polynomials.empty()) { return false; } #endif // Fit polynomials for the other variables. expr_sett dirty; utils.find_modified(accelerator.path, dirty); polynomial_acceleratort path_acceleration(symbol_table, goto_functions, loop_counter); goto_programt::instructionst assigns; for (patht::iterator it = accelerator.path.begin(); it != accelerator.path.end(); ++it) { if (it->loc->is_assign() || it->loc->is_decl()) { assigns.push_back(*(it->loc)); } } for (expr_sett::iterator it = dirty.begin(); it != dirty.end(); ++it) { #ifdef DEBUG std::cout << "Trying to accelerate " << expr2c(*it, ns) << std::endl; #endif if (it->type().id() == ID_bool) { // Hack: don't try to accelerate booleans. accelerator.dirty_vars.insert(*it); #ifdef DEBUG std::cout << "Ignoring boolean" << std::endl; #endif continue; } if (it->id() == ID_index || it->id() == ID_dereference) { #ifdef DEBUG std::cout << "Ignoring array reference" << std::endl; #endif continue; } if (accelerator.changed_vars.find(*it) != accelerator.changed_vars.end()) { // We've accelerated variable this already. #ifdef DEBUG std::cout << "We've accelerated it already" << std::endl; #endif continue; } // Hack: ignore variables that depend on array values.. exprt array_rhs; if (depends_on_array(*it, array_rhs)) { #ifdef DEBUG std::cout << "Ignoring because it depends on an array" << std::endl; #endif continue; } polynomialt poly; exprt target(*it); if (path_acceleration.fit_polynomial(assigns, target, poly)) { std::map<exprt, polynomialt> this_poly; this_poly[target] = poly; if (utils.check_inductive(this_poly, accelerator.path)) { polynomials[target] = poly; accelerator.changed_vars.insert(target); continue; } } #ifdef DEBUG std::cout << "Failed to accelerate " << expr2c(*it, ns) << std::endl; #endif // We weren't able to accelerate this target... accelerator.dirty_vars.insert(target); } /* if (!utils.check_inductive(polynomials, assigns)) { // They're not inductive :-( return false; } */ substitutiont stashed; utils.stash_polynomials(program, polynomials, stashed, path); exprt guard; bool path_is_monotone; try { path_is_monotone = utils.do_assumptions(polynomials, path, guard); } catch (std::string s) { // Couldn't do WP. std::cout << "Assumptions error: " << s << std::endl; return false; } exprt pre_guard(guard); for (std::map<exprt, polynomialt>::iterator it = polynomials.begin(); it != polynomials.end(); ++it) { replace_expr(it->first, it->second.to_expr(), guard); } if (path_is_monotone) { // OK cool -- the path is monotone, so we can just assume the condition for // the last iteration. replace_expr(loop_counter, minus_exprt(loop_counter, from_integer(1, loop_counter.type())), guard); } 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", unsigned_poly_type()); 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); simplify(guard, ns); implies_exprt implies(k_bound, guard); exprt forall(ID_forall); forall.type() = bool_typet(); forall.copy_to_operands(k); forall.copy_to_operands(implies); guard = forall; } // All our conditions are met -- we can finally build the accelerator! // It is of the form: // // loop_counter = *; // target1 = polynomial1; // target2 = polynomial2; // ... // assume(guard); // assume(no overflows in previous code); program.add_instruction(ASSUME)->guard = pre_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()); accelerator.changed_vars.insert(it->first); } // Add in any array assignments we can do now. if (!utils.do_arrays(assigns, polynomials, loop_counter, stashed, program)) { // We couldn't model some of the array assignments with polynomials... // Unfortunately that means we just have to bail out. return false; } program.add_instruction(ASSUME)->guard = guard; program.fix_types(); if (path_is_monotone) { utils.ensure_no_overflows(program); } accelerator.pure_accelerator.instructions.swap(program.instructions); return true; }
bool ranking_synthesis_seneschalt::read_output(exprt &rf) { // Check if there is a result at all... std::ifstream err("seneschal.err"); bool result_found=false; while(err) { std::string line; std::getline(err, line); if(line=="Solving ... no solution" || line=="Solving ... found a solution") { result_found = true; break; } } err.close(); if(!result_found) return false; // There is a result! std::ifstream in("seneschal.out"); std::string rank_string; std::string bound_string; while(in) { std::string line; std::getline(in, line); if(line.substr(0,7)=="Ranking") { std::vector<std::string> tokens; tokenize(line, tokens, " =[],\tr"); bool work=false; for(std::vector<std::string>::const_iterator it=tokens.begin(); it!=tokens.end(); it++) { // std::cout << "TOKEN: " << *it << std::endl; if(*it=="Ranking") { result_found=true; work=true; } else if(*it=="function:") /* SKIP */ ; else if(work) { rank_string += " " + *it; } } } else if(line.substr(0,25)=="Lower bound (post-state):") { std::vector<std::string> tokens; tokenize(line, tokens, " =[],\t"); std::vector<std::string>::const_iterator it=tokens.begin(); it++; it++; it++; if(it!=tokens.end()) { //std::cout << "TOKEN: " << *it << std::endl; bound_string = *it; } }; } if(rank_string!="") { bound = string2integer(bound_string); if(bound!=0) rank_string = "(" + rank_string + ") - (" + bound_string + ")"; exprt rfl; if(parse_rank_function(rank_string, trans_context, ns, *message_handler, rfl)) throw ("RF EXTRACTION ERROR"); replace_expr(variable_map, rfl); std::cout << "FOUND FUNCTION: " << from_expr(ns, "", rfl) << std::endl; rf.swap(rfl); std::cout << "BOUND: " << bound << std::endl; } return true; }
bool simplify_exprt::simplify_index(exprt &expr) { bool result=true; // extra arithmetic optimizations const exprt &index=to_index_expr(expr).index(); const exprt &array=to_index_expr(expr).array(); if(index.id()==ID_div && index.operands().size()==2) { if(index.op0().id()==ID_mult && index.op0().operands().size()==2 && index.op0().op1()==index.op1()) { exprt tmp=index.op0().op0(); expr.op1()=tmp; result=false; } else if(index.op0().id()==ID_mult && index.op0().operands().size()==2 && index.op0().op0()==index.op1()) { exprt tmp=index.op0().op1(); expr.op1()=tmp; result=false; } } if(array.id()==ID_lambda) { // simplify (lambda i: e)(x) to e[i/x] const exprt &lambda_expr=array; if(lambda_expr.operands().size()!=2) return true; if(expr.op1().type()==lambda_expr.op0().type()) { exprt tmp=lambda_expr.op1(); replace_expr(lambda_expr.op0(), expr.op1(), tmp); expr.swap(tmp); return false; } } else if(array.id()==ID_with) { // we have (a WITH [i:=e])[j] const exprt &with_expr=array; if(with_expr.operands().size()!=3) return true; if(with_expr.op1()==expr.op1()) { // simplify (e with [i:=v])[i] to v exprt tmp=with_expr.op2(); expr.swap(tmp); return false; } else { // Turn (a with i:=x)[j] into (i==j)?x:a[j]. // watch out that the type of i and j might be different. equal_exprt equality_expr(expr.op1(), with_expr.op1()); if(equality_expr.lhs().type()!=equality_expr.rhs().type()) equality_expr.rhs().make_typecast(equality_expr.lhs().type()); simplify_inequality(equality_expr); index_exprt new_index_expr; new_index_expr.type()=expr.type(); new_index_expr.array()=with_expr.op0(); new_index_expr.index()=expr.op1(); simplify_index(new_index_expr); // recursive call if(equality_expr.is_true()) { expr=with_expr.op2(); return false; } else if(equality_expr.is_false()) { expr.swap(new_index_expr); return false; } if_exprt if_expr(equality_expr, with_expr.op2(), new_index_expr); simplify_if(if_expr); expr.swap(if_expr); return false; } } else if(array.id()==ID_constant || array.id()==ID_array) { mp_integer i; if(to_integer(expr.op1(), i)) { } else if(i<0 || i>=array.operands().size()) { // out of bounds } else { // ok exprt tmp=array.operands()[integer2size_t(i)]; expr.swap(tmp); return false; } } else if(array.id()==ID_string_constant) { mp_integer i; const irep_idt &value=array.get(ID_value); if(to_integer(expr.op1(), i)) { } else if(i<0 || i>value.size()) { // out of bounds } else { // terminating zero? char v=(i==value.size())?0:value[integer2size_t(i)]; exprt tmp=from_integer(v, expr.type()); expr.swap(tmp); return false; } } else if(array.id()==ID_array_of) { if(array.operands().size()==1) { exprt tmp=array.op0(); expr.swap(tmp); return false; } } else if(array.id()=="array-list") { // These are index/value pairs, alternating. for(size_t i=0; i<array.operands().size()/2; i++) { exprt tmp_index=array.operands()[i*2]; tmp_index.make_typecast(index.type()); simplify(tmp_index); if(tmp_index==index) { exprt tmp=array.operands()[i*2+1]; expr.swap(tmp); return false; } } } else if(array.id()==ID_byte_extract_little_endian || array.id()==ID_byte_extract_big_endian) { const typet &array_type=ns.follow(array.type()); if(array_type.id()==ID_array) { // This rewrites byte_extract(s, o, array_type)[i] // to byte_extract(s, o+offset, sub_type) mp_integer sub_size=pointer_offset_size(array_type.subtype(), ns); if(sub_size==-1) return true; // add offset to index mult_exprt offset(from_integer(sub_size, array.op1().type()), index); plus_exprt final_offset(array.op1(), offset); simplify_node(final_offset); exprt result(array.id(), expr.type()); result.copy_to_operands(array.op0(), final_offset); expr.swap(result); simplify_rec(expr); return false; } } else if(array.id()==ID_if) { const if_exprt &if_expr=to_if_expr(array); exprt cond=if_expr.cond(); index_exprt idx_false=to_index_expr(expr); idx_false.array()=if_expr.false_case(); to_index_expr(expr).array()=if_expr.true_case(); expr=if_exprt(cond, expr, idx_false, expr.type()); simplify_rec(expr); return false; } return result; }
exprt ranking_synthesis_satt::instantiate(void) { find_largest_constant(body.body_relation); binary_relation_exprt toplevel_and("and"); toplevel_and.lhs() = body.body_relation; // that's R(x,x') exprt function; replace_mapt pre_replace_map; bool first=true; for(bodyt::variable_mapt::const_iterator it=body.variable_map.begin(); it!=body.variable_map.end(); it++) { if(used_variables.find(it->first)==used_variables.end()) continue; exprt var=symbol_exprt(it->first, ns.lookup(it->first).type); pre_replace_map[var] = // save the corresponding pre-var symbol_exprt(it->second, ns.lookup(it->second).type); adjust_type(var.type()); const typet type=var.type(); exprt coef=coefficient(var); unsigned width=safe_width(var, ns); assert(width!=0); exprt term("*", typet("")); term.copy_to_operands(coef, var); if(first) { function=term; first=false; } else { // cast_up(function, term); exprt t("+", typet("")); t.move_to_operands(function, term); function = t; } } if(first) // non of the interesting variables was used - bail out! { debug("Completely non-deterministic template; " "this loop does not terminate."); return false_exprt(); } // if(!largest_constant.is_zero()) // { // // add the largest constant // symbol_exprt lc_sym("termination::LC", largest_constant.type()); // exprt lc=largest_constant; // exprt lcc=coefficient(lc_sym); //// cast_up(lc, lcc); // exprt m("*", typet("")); // m.move_to_operands(lcc, lc); // //// cast_up(function, m); // exprt t("+", typet("")); // t.move_to_operands(function, m); // function = t; // } // add a constant term symbol_exprt const_sym("termination::constant", signedbv_typet(2)); exprt cc=coefficient(const_sym); // cast_up(function, cc); exprt t2("+", typet("")); t2.move_to_operands(function, cc); function=t2; contextt context; ansi_c_parse_treet pt; rankfunction_typecheckt typecheck(pt, context, ns, *message_handler); try { typecheck.typecheck_expr(function); } catch (...) { throw "TC ERROR"; } exprt pre_function = function; replace_expr(pre_replace_map, pre_function); // save the relation for later rank_relation = binary_relation_exprt(function, "<", pre_function); // base_type(rank_relation, ns); toplevel_and.rhs()=not_exprt(rank_relation); return toplevel_and; }
void bv_cbmct::convert_waitfor(const exprt &expr, bvt &bv) { if(expr.operands().size()!=4) throw "waitfor expected to have four operands"; exprt new_cycle; const exprt &old_cycle=expr.op0(); const exprt &cycle_var=expr.op1(); const exprt &bound=expr.op2(); const exprt &predicate=expr.op3(); make_free_bv_expr(expr.type(), new_cycle); mp_integer bound_value; if(to_integer(bound, bound_value)) throw "waitfor bound must be a constant"; { // constraint: new_cycle>=old_cycle exprt rel_expr(ID_ge, bool_typet()); rel_expr.copy_to_operands(new_cycle, old_cycle); set_to_true(rel_expr); } { // constraint: new_cycle<=bound+1 exprt one=from_integer(1, bound.type()); exprt bound_plus1(ID_plus, bound.type()); bound_plus1.reserve_operands(2); bound_plus1.copy_to_operands(bound); bound_plus1.move_to_operands(one); exprt rel_expr(ID_le, bool_typet()); rel_expr.copy_to_operands(new_cycle, bound_plus1); set_to_true(rel_expr); } for(mp_integer i=0; i<=bound_value; i=i+1) { // replace cycle_var by old_cycle+i; exprt old_cycle_plus_i(ID_plus, old_cycle.type()); old_cycle_plus_i.operands().resize(2); old_cycle_plus_i.op0()=old_cycle; old_cycle_plus_i.op1()=from_integer(i, old_cycle.type()); exprt tmp_predicate=predicate; replace_expr(cycle_var, old_cycle_plus_i, tmp_predicate); // CONSTRAINT: // if((cycle)<=bound) { // if((cycle)<new_cycle) // assume(!property); // else if((cycle)==new_cycle) // assume(property); { exprt cycle_le_bound(ID_le, bool_typet()); cycle_le_bound.operands().resize(2); cycle_le_bound.op0()=old_cycle_plus_i; cycle_le_bound.op1()=bound; exprt cycle_lt_new_cycle(ID_lt, bool_typet()); cycle_lt_new_cycle.operands().resize(2); cycle_lt_new_cycle.op0()=old_cycle_plus_i; cycle_lt_new_cycle.op1()=new_cycle; exprt and_expr(ID_and, bool_typet()); and_expr.operands().resize(2); and_expr.op0().swap(cycle_le_bound); and_expr.op1().swap(cycle_lt_new_cycle); exprt top_impl(ID_implies, bool_typet()); top_impl.reserve_operands(2); top_impl.move_to_operands(and_expr); top_impl.copy_to_operands(tmp_predicate); top_impl.op1().make_not(); set_to_true(top_impl); } { exprt cycle_le_bound(ID_le, bool_typet()); cycle_le_bound.operands().resize(2); cycle_le_bound.op0()=old_cycle_plus_i; cycle_le_bound.op1()=bound; exprt cycle_eq_new_cycle(ID_equal, bool_typet()); cycle_eq_new_cycle.operands().resize(2); cycle_eq_new_cycle.op0()=old_cycle_plus_i; cycle_eq_new_cycle.op1()=new_cycle; exprt and_expr(ID_and, bool_typet()); and_expr.operands().resize(2); and_expr.op0().swap(cycle_le_bound); and_expr.op1().swap(cycle_eq_new_cycle); exprt top_impl(ID_implies, bool_typet()); top_impl.reserve_operands(2); top_impl.move_to_operands(and_expr); top_impl.copy_to_operands(tmp_predicate); set_to_true(top_impl); } } // result: new_cycle return convert_bitvector(new_cycle, bv); }