diff options
Diffstat (limited to 'gcc/analyzer/engine.cc')
-rw-r--r-- | gcc/analyzer/engine.cc | 201 |
1 files changed, 183 insertions, 18 deletions
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 742ac02..b4deee5 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -72,6 +72,7 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "tree-dfa.h" #include "analyzer/known-function-manager.h" +#include "analyzer/call-summary.h" /* For an overview, see gcc/doc/analyzer.texi. */ @@ -1425,6 +1426,26 @@ exploded_node::on_stmt (exploded_graph &eg, &old_state, state, uncertainty, path_ctxt, stmt); + /* Handle call summaries here. */ + if (cgraph_edge *cgedge + = supergraph_call_edge (snode->get_function (), stmt)) + if (eg.get_analysis_plan ().use_summary_p (cgedge)) + { + function *called_fn = get_ultimate_function_for_cgraph_edge (cgedge); + per_function_data *called_fn_data + = eg.get_per_function_data (called_fn); + if (called_fn_data) + return replay_call_summaries (eg, + snode, + as_a <const gcall *> (stmt), + state, + uncertainty, + path_ctxt, + called_fn, + called_fn_data, + &ctxt); + } + bool unknown_side_effects = false; bool terminate_path = false; @@ -1520,6 +1541,142 @@ exploded_node::on_stmt_post (const gimple *stmt, state->m_region_model->on_call_post (call, unknown_side_effects, ctxt); } +/* A concrete call_info subclass representing a replay of a call summary. */ + +class call_summary_edge_info : public call_info +{ +public: + call_summary_edge_info (const call_details &cd, + function *called_fn, + call_summary *summary, + const extrinsic_state &ext_state) + : call_info (cd), + m_called_fn (called_fn), + m_summary (summary), + m_ext_state (ext_state) + {} + + bool update_state (program_state *state, + const exploded_edge *, + region_model_context *ctxt) const final override + { + /* Update STATE based on summary_end_state. */ + call_details cd (get_call_details (state->m_region_model, ctxt)); + call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state); + const program_state &summary_end_state = m_summary->get_state (); + return state->replay_call_summary (r, summary_end_state); + } + + bool update_model (region_model *model, + const exploded_edge *, + region_model_context *ctxt) const final override + { + /* Update STATE based on summary_end_state. */ + call_details cd (get_call_details (model, ctxt)); + call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state); + const program_state &summary_end_state = m_summary->get_state (); + model->replay_call_summary (r, *summary_end_state.m_region_model); + return true; + } + + label_text get_desc (bool /*can_colorize*/) const final override + { + return m_summary->get_desc (); + } + +private: + function *m_called_fn; + call_summary *m_summary; + const extrinsic_state &m_ext_state; +}; + +/* Use PATH_CTXT to bifurcate, which when handled will add custom edges + for a replay of the various feasible summaries in CALLED_FN_DATA. */ + +exploded_node::on_stmt_flags +exploded_node::replay_call_summaries (exploded_graph &eg, + const supernode *snode, + const gcall *call_stmt, + program_state *state, + uncertainty_t *uncertainty, + path_context *path_ctxt, + function *called_fn, + per_function_data *called_fn_data, + region_model_context *ctxt) +{ + logger *logger = eg.get_logger (); + LOG_SCOPE (logger); + + gcc_assert (called_fn); + gcc_assert (called_fn_data); + + /* Each summary will call bifurcate on the PATH_CTXT. */ + for (auto summary : called_fn_data->m_summaries) + replay_call_summary (eg, snode, call_stmt, state, uncertainty, + path_ctxt, called_fn, summary, ctxt); + path_ctxt->terminate_path (); + + return on_stmt_flags (); +} + +/* Use PATH_CTXT to bifurcate, which when handled will add a + custom edge for a replay of SUMMARY, if the summary's + conditions are feasible based on the current state. */ + +void +exploded_node::replay_call_summary (exploded_graph &eg, + const supernode *snode, + const gcall *call_stmt, + program_state *old_state, + uncertainty_t *uncertainty, + path_context *path_ctxt, + function *called_fn, + call_summary *summary, + region_model_context *ctxt) +{ + logger *logger = eg.get_logger (); + LOG_SCOPE (logger); + gcc_assert (snode); + gcc_assert (call_stmt); + gcc_assert (old_state); + gcc_assert (called_fn); + gcc_assert (summary); + + if (logger) + logger->log ("using %s as summary for call to %qE from %qE", + summary->get_desc ().get (), + called_fn->decl, + snode->get_function ()->decl); + const extrinsic_state &ext_state = eg.get_ext_state (); + const program_state &summary_end_state = summary->get_state (); + if (logger) + { + pretty_printer *pp = logger->get_printer (); + + logger->start_log_line (); + pp_string (pp, "callsite state: "); + old_state->dump_to_pp (ext_state, true, false, pp); + logger->end_log_line (); + + logger->start_log_line (); + pp_string (pp, "summary end state: "); + summary_end_state.dump_to_pp (ext_state, true, false, pp); + logger->end_log_line (); + } + + program_state new_state (*old_state); + + call_details cd (call_stmt, new_state.m_region_model, ctxt); + call_summary_replay r (cd, called_fn, summary, ext_state); + + if (path_ctxt) + path_ctxt->bifurcate (new call_summary_edge_info (cd, + called_fn, + summary, + ext_state)); +} + + /* Consider the effect of following superedge SUCC from this node. Return true if it's feasible to follow the edge, or false @@ -2115,6 +2272,20 @@ stats::get_total_enodes () const return result; } +/* struct per_function_data. */ + +per_function_data::~per_function_data () +{ + for (auto iter : m_summaries) + delete iter; +} + +void +per_function_data::add_call_summary (exploded_node *node) +{ + m_summaries.safe_push (new call_summary (this, node)); +} + /* strongly_connected_components's ctor. Tarjan's SCC algorithm. */ strongly_connected_components:: @@ -3980,7 +4151,7 @@ exploded_graph::process_node (exploded_node *node) NULL, // uncertainty_t *uncertainty NULL, // path_context *path_ctxt stmt); - if (edge_info->update_model (bifurcated_new_state.m_region_model, + if (edge_info->update_state (&bifurcated_new_state, NULL, /* no exploded_edge yet. */ &bifurcation_ctxt)) { @@ -5350,24 +5521,17 @@ public: pretty_printer *pp = gv->get_pp (); dump_dot_id (pp); - pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=<", + pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=\"", "lightgrey"); - pp_string (pp, "<TABLE BORDER=\"0\">"); pp_write_text_to_stream (pp); - gv->begin_trtd (); pp_printf (pp, "VCG: %i: %s", m_index, function_name (m_fun)); - gv->end_tdtr (); pp_newline (pp); - gv->begin_trtd (); pp_printf (pp, "supernodes: %i\n", m_num_supernodes); - gv->end_tdtr (); pp_newline (pp); - gv->begin_trtd (); pp_printf (pp, "superedges: %i\n", m_num_superedges); - gv->end_tdtr (); pp_newline (pp); if (args.m_eg) @@ -5380,9 +5544,7 @@ public: if (enode->get_point ().get_function () == m_fun) num_enodes++; } - gv->begin_trtd (); pp_printf (pp, "enodes: %i\n", num_enodes); - gv->end_tdtr (); pp_newline (pp); // TODO: also show the per-callstring breakdown @@ -5404,11 +5566,8 @@ public: } if (num_enodes > 0) { - gv->begin_trtd (); cs->print (pp); pp_printf (pp, ": %i\n", num_enodes); - pp_write_text_as_html_like_dot_to_stream (pp); - gv->end_tdtr (); } } @@ -5417,14 +5576,20 @@ public: if (data) { pp_newline (pp); - gv->begin_trtd (); pp_printf (pp, "summaries: %i\n", data->m_summaries.length ()); - pp_write_text_as_html_like_dot_to_stream (pp); - gv->end_tdtr (); + for (auto summary : data->m_summaries) + { + pp_printf (pp, "\nsummary: %s:\n", summary->get_desc ().get ()); + const extrinsic_state &ext_state = args.m_eg->get_ext_state (); + const program_state &state = summary->get_state (); + state.dump_to_pp (ext_state, false, true, pp); + pp_newline (pp); + } } } - pp_string (pp, "</TABLE>>];\n\n"); + pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true); + pp_string (pp, "\"];\n\n"); pp_flush (pp); } |