void summarizer_bwt::do_summary(const function_namet &function_name, local_SSAt &SSA, const summaryt &old_summary, summaryt &summary, bool context_sensitive) { bool sufficient = options.get_bool_option("sufficient"); status() << "Computing preconditions" << eom; // solver incremental_solvert &solver = ssa_db.get_solver(function_name); solver.set_message_handler(get_message_handler()); template_generator_summaryt template_generator( options,ssa_db,ssa_unwinder.get(function_name)); template_generator.set_message_handler(get_message_handler()); template_generator(solver.next_domain_number(),SSA,false); exprt::operandst c; c.push_back(old_summary.fw_precondition); c.push_back(old_summary.fw_invariant); c.push_back(ssa_inliner.get_summaries(SSA)); //forward summaries exprt::operandst postcond; ssa_inliner.get_summaries(SSA,false,postcond,c); //backward summaries collect_postconditions(function_name, SSA, summary, postcond,sufficient); if(!sufficient) { c.push_back(conjunction(postcond)); } else //sufficient { c.push_back(not_exprt(conjunction(postcond))); } if(!template_generator.out_vars().empty()) { ssa_analyzert analyzer; analyzer.set_message_handler(get_message_handler()); analyzer(solver,SSA,conjunction(c),template_generator); analyzer.get_result(summary.bw_transformer,template_generator.inout_vars()); analyzer.get_result(summary.bw_invariant,template_generator.loop_vars()); analyzer.get_result(summary.bw_precondition,template_generator.out_vars()); //statistics solver_instances += analyzer.get_number_of_solver_instances(); solver_calls += analyzer.get_number_of_solver_calls(); } else // TODO: yet another workaround for ssa_analyzer not being able to handle empty templates properly { solver << SSA; solver.new_context(); solver << SSA.get_enabling_exprs(); solver << conjunction(c); exprt result = true_exprt(); if(solver()==decision_proceduret::D_UNSATISFIABLE) result = false_exprt(); solver.pop_context(); summary.bw_transformer = result; summary.bw_invariant = result; summary.bw_precondition = result; } if(sufficient) { summary.bw_transformer = not_exprt(summary.bw_transformer); summary.bw_invariant = not_exprt(summary.bw_invariant); summary.bw_precondition = not_exprt(summary.bw_precondition); } if(context_sensitive && !summary.bw_postcondition.is_true()) { summary.bw_transformer = implies_exprt(summary.bw_postcondition,summary.bw_transformer); summary.bw_invariant = implies_exprt(summary.bw_postcondition,summary.bw_invariant); summary.bw_precondition = implies_exprt(summary.bw_postcondition,summary.bw_precondition); } }
exprt summarizer_bwt::compute_calling_context2( const function_namet &function_name, local_SSAt &SSA, summaryt old_summary, local_SSAt::nodest::const_iterator n_it, local_SSAt::nodet::function_callst::const_iterator f_it, const exprt &postcondition, bool sufficient) { assert(f_it->function().id()==ID_symbol); //no function pointers irep_idt fname = to_symbol_expr(f_it->function()).get_identifier(); status() << "Computing calling context for function " << fname << eom; // solver incremental_solvert &solver = ssa_db.get_solver(function_name); solver.set_message_handler(get_message_handler()); //analyze ssa_analyzert analyzer; analyzer.set_message_handler(get_message_handler()); template_generator_callingcontextt template_generator( options,ssa_db,ssa_unwinder.get(function_name)); template_generator.set_message_handler(get_message_handler()); template_generator(solver.next_domain_number(),SSA,n_it,f_it,false); // collect globals at call site std::map<local_SSAt::nodet::function_callst::const_iterator, local_SSAt::var_sett> cs_globals_out; SSA.get_globals(n_it->location,cs_globals_out[f_it],false); exprt::operandst c; c.push_back(old_summary.fw_precondition); c.push_back(old_summary.fw_invariant); c.push_back(ssa_inliner.get_summaries(SSA)); //forward summaries exprt::operandst postcond; ssa_inliner.get_summaries(SSA,false,postcond,c); //backward summaries old_summary.bw_postcondition = postcondition; //that's a bit awkward collect_postconditions(function_name, SSA, old_summary, postcond,sufficient); if(!sufficient) { c.push_back(conjunction(postcond)); } else //sufficient { c.push_back(not_exprt(conjunction(postcond))); } analyzer(solver,SSA,conjunction(c),template_generator); // set preconditions local_SSAt &fSSA = ssa_db.get(fname); exprt postcondition_call; analyzer.get_result(postcondition_call, template_generator.callingcontext_vars()); ssa_inliner.rename_to_callee(f_it, fSSA.params, cs_globals_out[f_it],fSSA.globals_out, postcondition_call); if(sufficient && !postcondition_call.is_true()) //TODO: this should actually be handled by ssa_analyzer using a "guard-reachabiliity-only" analysis if template is empty { postcondition_call = not_exprt(postcondition_call); } debug() << "Backward calling context for " << from_expr(SSA.ns, "", *f_it) << ": " << from_expr(SSA.ns, "", postcondition_call) << eom; //statistics solver_instances += analyzer.get_number_of_solver_instances(); solver_calls += analyzer.get_number_of_solver_calls(); return postcondition_call; }
void summarizer_bw_termt::do_summary_term( const function_namet &function_name, local_SSAt &SSA, const summaryt &old_summary, summaryt &summary, bool context_sensitive) { status() << "Computing preconditions for termination" << eom; // solver incremental_solvert &solver=ssa_db.get_solver(function_name); solver.set_message_handler(get_message_handler()); // templates for ranking functions template_generator_rankingt template_generator1( options, ssa_db, ssa_unwinder.get(function_name)); template_generator1.set_message_handler(get_message_handler()); template_generator1(solver.next_domain_number(), SSA, true); // templates for backward summary template_generator_summaryt template_generator2( options, ssa_db, ssa_unwinder.get(function_name)); template_generator2.set_message_handler(get_message_handler()); template_generator2(solver.next_domain_number(), SSA, false); exprt::operandst bindings; exprt::operandst postcond; // backward summaries ssa_inliner.get_summaries(SSA, false, postcond, bindings); collect_postconditions(function_name, SSA, summary, postcond, true); // prepare solver solver << SSA; solver.new_context(); solver << SSA.get_enabling_exprs(); solver << old_summary.fw_precondition; solver << old_summary.fw_invariant; solver << ssa_inliner.get_summaries(SSA); // forward summaries solver << conjunction(bindings); // bindings for backward summaries #if 0 // compute preconditions individually // TODO: this should be done more transparently for(unsigned i=0; i<postcond.size(); i++) { exprt::operandst postcond2; postcond2.push_back(postcond[i]); compute_precondition( SSA, summary, postcond2, solver, template_generator2, context_sensitive); } postcond.clear(); #endif if(template_generator1.all_vars().empty()) { compute_precondition( SSA, summary, postcond, solver, template_generator2, context_sensitive); solver.pop_context(); return; } summary.bw_precondition=false_exprt(); // initialize unsigned number_disjuncts=0; while(number_disjuncts++<MAX_PRECONDITION_DISJUNCTS) { // bootstrap preconditions exprt termination_argument; if(!bootstrap_preconditions( SSA, summary, solver, template_generator1, template_generator2, termination_argument)) { break; } // compute precondition // compute for individual termination arguments separately // TODO: this should be done more transparently if(termination_argument.id()==ID_and) { for(unsigned i=0; i<termination_argument.operands().size(); i++) { postcond.push_back(termination_argument.operands()[i]); exprt precondition= compute_precondition( SSA, summary, postcond, solver, template_generator2, context_sensitive); // join results if(summary.termination_argument.is_nil()) { summary.termination_argument= implies_exprt(precondition, termination_argument); } else { summary.termination_argument= and_exprt( summary.termination_argument, implies_exprt(precondition, termination_argument)); } // TODO: this is a bit asymmetric: // the first precondition is joined with all other sources // of non-termination (calls, bw calling context) postcond.clear(); } } else // do not split termination arguments { postcond.push_back(termination_argument); exprt precondition= compute_precondition( SSA, summary, postcond, solver, template_generator2, context_sensitive); // join results if(summary.termination_argument.is_nil()) { summary.termination_argument= implies_exprt(precondition, termination_argument); } else { summary.termination_argument= and_exprt( summary.termination_argument, implies_exprt(precondition, termination_argument)); } // TODO: this is a bit asymmetric: // the first precondition is joined with all other sources // of non-termination (calls, bw calling context) postcond.clear(); } } solver.pop_context(); }