analyzer: fix ICE in call summarization [PR114159]
PR analyzer/114159 reports an ICE inside playback of call summaries for very low values of --param=analyzer-max-svalue-depth=VAL. Root cause is that call_summary_edge_info's ctor tries to evaluate the function ptr of a gimple call stmt and assumes it gets a function *, but with low values of --param=analyzer-max-svalue-depth=VAL we get back an UNKNOWN svalue, rather than a pointer to a specific function. Fix by adding a new call_info ctor that passes a specific const function & from the call_summary_edge_info, rather than trying to compute the function. In doing so, I noticed that the analyzer was using "function *" despite not modifying functions, and was sloppy about can-be-null versus must-be-non-null function pointers, so I "constified" the function, and converted the many places where the function must be non-null to be "const function &". gcc/analyzer/ChangeLog: PR analyzer/114159 * analyzer.cc: Include "tree-dfa.h". (get_ssa_default_def): New decl. * analyzer.h (get_ssa_default_def): New. * call-info.cc (call_info::call_info): New ctor taking an explicit called_fn. * call-info.h (call_info::call_info): Likewise. * call-summary.cc (call_summary_replay::call_summary_replay): Convert param from function * to const function &. * call-summary.h (call_summary_replay::call_summary_replay): Likewise. * checker-event.h (state_change_event::get_dest_function): Constify return value. * engine.cc (point_and_state::validate): Update for conversion to const function &. (exploded_node::on_stmt): Likewise. (call_summary_edge_info::call_summary_edge_info): Likewise. Pass in called_fn to call_info ctor. (exploded_node::replay_call_summaries): Update for conversion to const function &. Convert per_function_data from * to &. (exploded_node::replay_call_summary): Update for conversion to const function &. (exploded_graph::add_function_entry): Likewise. (toplevel_function_p): Likewise. (add_tainted_args_callback): Likewise. (exploded_graph::build_initial_worklist): Likewise. (exploded_graph::maybe_create_dynamic_call): Likewise. (maybe_update_for_edge): Likewise. (exploded_graph::on_escaped_function): Likewise. * exploded-graph.h (exploded_node::replay_call_summaries): Likewise. (exploded_node::replay_call_summary): Likewise. (exploded_graph::add_function_entry): Likewise. * program-point.cc (function_point::from_function_entry): Likewise. (program_point::from_function_entry): Likewise. * program-point.h (function_point::from_function_entry): Likewise. (program_point::from_function_entry): Likewise. * program-state.cc (program_state::push_frame): Likewise. (program_state::get_current_function): Constify return type. * program-state.h (program_state::push_frame): Update for conversion to const function &. (program_state::get_current_function): Likewise. * region-model-manager.cc (region_model_manager::get_frame_region): Likewise. * region-model-manager.h (region_model_manager::get_frame_region): Likewise. * region-model.cc (region_model::called_from_main_p): Likewise. (region_model::update_for_gcall): Likewise. (region_model::push_frame): Likewise. (region_model::get_current_function): Constify return type. (region_model::pop_frame): Update for conversion to const function &. (selftest::test_stack_frames): Likewise. (selftest::test_get_representative_path_var): Likewise. (selftest::test_state_merging): Likewise. (selftest::test_alloca): Likewise. * region-model.h (region_model::push_frame): Likewise. (region_model::get_current_function): Likewise. * region.cc (frame_region::dump_to_pp): Likewise. (frame_region::get_region_for_local): Likewise. * region.h (class frame_region): Likewise. * sm-signal.cc (signal_unsafe_call::describe_state_change): Likewise. (update_model_for_signal_handler): Likewise. (signal_delivery_edge_info_t::update_model): Likewise. (register_signal_handler::impl_transition): Likewise. * state-purge.cc (class gimple_op_visitor): Likewise. (state_purge_map::state_purge_map): Likewise. (state_purge_map::get_or_create_data_for_decl): Likewise. (state_purge_per_ssa_name::state_purge_per_ssa_name): Likewise. (state_purge_per_ssa_name::add_to_worklist): Likewise. (state_purge_per_ssa_name::process_point): Likewise. (state_purge_per_decl::add_to_worklist): Likewise. (state_purge_annotator::print_needed): Likewise. * state-purge.h (state_purge_map::get_or_create_data_for_decl): Likewise. (class state_purge_per_tree): Likewise. (class state_purge_per_ssa_name): Likewise. (class state_purge_per_decl): Likewise. * supergraph.cc (supergraph::dump_dot_to_pp): Likewise. * supergraph.h (supergraph::get_node_for_function_entry): Likewise. (supergraph::get_node_for_function_exit): Likewise. gcc/ChangeLog: PR analyzer/114159 * function.cc (function_name): Make param const. * function.h (function_name): Likewise. gcc/testsuite/ChangeLog: PR analyzer/114159 * c-c++-common/analyzer/call-summaries-pr114159.c: New test. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
This commit is contained in:
parent
cda3836161
commit
c0d8a64e72
27 changed files with 181 additions and 129 deletions
|
@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "analyzer/analyzer.h"
|
||||
#include "tree-pretty-print.h"
|
||||
#include "diagnostic-event-id.h"
|
||||
#include "tree-dfa.h"
|
||||
|
||||
#if ENABLE_ANALYZER
|
||||
|
||||
|
@ -275,6 +276,14 @@ byte_offset_to_json (const byte_offset_t &offset)
|
|||
return new json::string (pp_formatted_text (&pp));
|
||||
}
|
||||
|
||||
/* Workaround for lack of const-correctness of ssa_default_def. */
|
||||
|
||||
tree
|
||||
get_ssa_default_def (const function &fun, tree var)
|
||||
{
|
||||
return ssa_default_def (const_cast <function *> (&fun), var);
|
||||
}
|
||||
|
||||
} // namespace ana
|
||||
|
||||
/* Helper function for checkers. Is the CALL to the given function name,
|
||||
|
|
|
@ -433,6 +433,9 @@ compare_constants (tree lhs_const, enum tree_code op, tree rhs_const);
|
|||
extern tree
|
||||
get_string_cst_size (const_tree string_cst);
|
||||
|
||||
extern tree
|
||||
get_ssa_default_def (const function &fun, tree var);
|
||||
|
||||
} // namespace ana
|
||||
|
||||
extern bool is_special_named_call_p (const gcall *call, const char *funcname,
|
||||
|
|
|
@ -143,6 +143,14 @@ call_info::call_info (const call_details &cd)
|
|||
gcc_assert (m_fndecl);
|
||||
}
|
||||
|
||||
call_info::call_info (const call_details &cd,
|
||||
const function &called_fn)
|
||||
: m_call_stmt (cd.get_call_stmt ()),
|
||||
m_fndecl (called_fn.decl)
|
||||
{
|
||||
gcc_assert (m_fndecl);
|
||||
}
|
||||
|
||||
/* class succeed_or_fail_call_info : public call_info. */
|
||||
|
||||
label_text
|
||||
|
|
|
@ -44,6 +44,7 @@ public:
|
|||
|
||||
protected:
|
||||
call_info (const call_details &cd);
|
||||
call_info (const call_details &cd, const function &called_fn);
|
||||
|
||||
private:
|
||||
const gcall *m_call_stmt;
|
||||
|
|
|
@ -167,7 +167,7 @@ call_summary::dump (const extrinsic_state &ext_state, bool simple) const
|
|||
arguments at the caller. */
|
||||
|
||||
call_summary_replay::call_summary_replay (const call_details &cd,
|
||||
function *called_fn,
|
||||
const function &called_fn,
|
||||
call_summary *summary,
|
||||
const extrinsic_state &ext_state)
|
||||
: m_cd (cd),
|
||||
|
@ -177,7 +177,7 @@ call_summary_replay::call_summary_replay (const call_details &cd,
|
|||
region_model_manager *mgr = cd.get_manager ();
|
||||
|
||||
// populate params based on args
|
||||
tree fndecl = called_fn->decl;
|
||||
tree fndecl = called_fn.decl;
|
||||
|
||||
/* Get a frame_region for use with respect to the summary.
|
||||
This will be a top-level frame, since that's what's in
|
||||
|
@ -196,7 +196,7 @@ call_summary_replay::call_summary_replay (const call_details &cd,
|
|||
break;
|
||||
const svalue *caller_arg_sval = cd.get_arg_svalue (idx);
|
||||
tree parm_lval = iter_parm;
|
||||
if (tree parm_default_ssa = ssa_default_def (called_fn, iter_parm))
|
||||
if (tree parm_default_ssa = get_ssa_default_def (called_fn, iter_parm))
|
||||
parm_lval = parm_default_ssa;
|
||||
const region *summary_parm_reg
|
||||
= summary_frame->get_region_for_local (mgr, parm_lval, cd.get_ctxt ());
|
||||
|
|
|
@ -68,7 +68,7 @@ class call_summary_replay
|
|||
{
|
||||
public:
|
||||
call_summary_replay (const call_details &cd,
|
||||
function *called_fn,
|
||||
const function &called_fn,
|
||||
call_summary *m_summary,
|
||||
const extrinsic_state &ext_state);
|
||||
|
||||
|
|
|
@ -370,7 +370,7 @@ public:
|
|||
label_text get_desc (bool can_colorize) const final override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
function *get_dest_function () const
|
||||
const function *get_dest_function () const
|
||||
{
|
||||
return m_dst_state.get_current_function ();
|
||||
}
|
||||
|
|
|
@ -1072,7 +1072,7 @@ point_and_state::validate (const extrinsic_state &ext_state) const
|
|||
{
|
||||
int index = iter_frame->get_index ();
|
||||
gcc_assert (m_point.get_function_at_depth (index)
|
||||
== iter_frame->get_function ());
|
||||
== &iter_frame->get_function ());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1496,14 +1496,17 @@ exploded_node::on_stmt (exploded_graph &eg,
|
|||
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,
|
||||
path_ctxt,
|
||||
called_fn,
|
||||
called_fn_data,
|
||||
&ctxt);
|
||||
{
|
||||
gcc_assert (called_fn);
|
||||
return replay_call_summaries (eg,
|
||||
snode,
|
||||
as_a <const gcall *> (stmt),
|
||||
state,
|
||||
path_ctxt,
|
||||
*called_fn,
|
||||
*called_fn_data,
|
||||
&ctxt);
|
||||
}
|
||||
}
|
||||
|
||||
bool unknown_side_effects = false;
|
||||
|
@ -1610,10 +1613,10 @@ class call_summary_edge_info : public call_info
|
|||
{
|
||||
public:
|
||||
call_summary_edge_info (const call_details &cd,
|
||||
function *called_fn,
|
||||
const function &called_fn,
|
||||
call_summary *summary,
|
||||
const extrinsic_state &ext_state)
|
||||
: call_info (cd),
|
||||
: call_info (cd, called_fn),
|
||||
m_called_fn (called_fn),
|
||||
m_summary (summary),
|
||||
m_ext_state (ext_state)
|
||||
|
@ -1648,7 +1651,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
function *m_called_fn;
|
||||
const function &m_called_fn;
|
||||
call_summary *m_summary;
|
||||
const extrinsic_state &m_ext_state;
|
||||
};
|
||||
|
@ -1662,18 +1665,15 @@ exploded_node::replay_call_summaries (exploded_graph &eg,
|
|||
const gcall *call_stmt,
|
||||
program_state *state,
|
||||
path_context *path_ctxt,
|
||||
function *called_fn,
|
||||
per_function_data *called_fn_data,
|
||||
const 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)
|
||||
for (auto summary : called_fn_data.m_summaries)
|
||||
replay_call_summary (eg, snode, call_stmt, state,
|
||||
path_ctxt, called_fn, summary, ctxt);
|
||||
path_ctxt->terminate_path ();
|
||||
|
@ -1691,7 +1691,7 @@ exploded_node::replay_call_summary (exploded_graph &eg,
|
|||
const gcall *call_stmt,
|
||||
program_state *old_state,
|
||||
path_context *path_ctxt,
|
||||
function *called_fn,
|
||||
const function &called_fn,
|
||||
call_summary *summary,
|
||||
region_model_context *ctxt)
|
||||
{
|
||||
|
@ -1700,13 +1700,12 @@ exploded_node::replay_call_summary (exploded_graph &eg,
|
|||
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,
|
||||
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 ();
|
||||
|
@ -2784,16 +2783,17 @@ private:
|
|||
Return the exploded_node for the entrypoint to the function. */
|
||||
|
||||
exploded_node *
|
||||
exploded_graph::add_function_entry (function *fun)
|
||||
exploded_graph::add_function_entry (const function &fun)
|
||||
{
|
||||
gcc_assert (gimple_has_body_p (fun->decl));
|
||||
gcc_assert (gimple_has_body_p (fun.decl));
|
||||
|
||||
/* Be idempotent. */
|
||||
if (m_functions_with_enodes.contains (fun))
|
||||
function *key = const_cast<function *> (&fun);
|
||||
if (m_functions_with_enodes.contains (key))
|
||||
{
|
||||
logger * const logger = get_logger ();
|
||||
if (logger)
|
||||
logger->log ("entrypoint for %qE already exists", fun->decl);
|
||||
logger->log ("entrypoint for %qE already exists", fun.decl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -2805,10 +2805,10 @@ exploded_graph::add_function_entry (function *fun)
|
|||
|
||||
std::unique_ptr<custom_edge_info> edge_info = NULL;
|
||||
|
||||
if (lookup_attribute ("tainted_args", DECL_ATTRIBUTES (fun->decl)))
|
||||
if (lookup_attribute ("tainted_args", DECL_ATTRIBUTES (fun.decl)))
|
||||
{
|
||||
if (mark_params_as_tainted (&state, fun->decl, m_ext_state))
|
||||
edge_info = make_unique<tainted_args_function_info> (fun->decl);
|
||||
if (mark_params_as_tainted (&state, fun.decl, m_ext_state))
|
||||
edge_info = make_unique<tainted_args_function_info> (fun.decl);
|
||||
}
|
||||
|
||||
if (!state.m_valid)
|
||||
|
@ -2820,7 +2820,7 @@ exploded_graph::add_function_entry (function *fun)
|
|||
|
||||
add_edge (m_origin, enode, NULL, false, std::move (edge_info));
|
||||
|
||||
m_functions_with_enodes.add (fun);
|
||||
m_functions_with_enodes.add (key);
|
||||
|
||||
return enode;
|
||||
}
|
||||
|
@ -3108,7 +3108,7 @@ exploded_graph::get_per_function_data (function *fun) const
|
|||
called via other functions. */
|
||||
|
||||
static bool
|
||||
toplevel_function_p (function *fun, logger *logger)
|
||||
toplevel_function_p (const function &fun, logger *logger)
|
||||
{
|
||||
/* Don't directly traverse into functions that have an "__analyzer_"
|
||||
prefix. Doing so is useful for the analyzer test suite, allowing
|
||||
|
@ -3119,17 +3119,17 @@ toplevel_function_p (function *fun, logger *logger)
|
|||
excess messages from the case of the first function being traversed
|
||||
directly. */
|
||||
#define ANALYZER_PREFIX "__analyzer_"
|
||||
if (!strncmp (IDENTIFIER_POINTER (DECL_NAME (fun->decl)), ANALYZER_PREFIX,
|
||||
if (!strncmp (IDENTIFIER_POINTER (DECL_NAME (fun.decl)), ANALYZER_PREFIX,
|
||||
strlen (ANALYZER_PREFIX)))
|
||||
{
|
||||
if (logger)
|
||||
logger->log ("not traversing %qE (starts with %qs)",
|
||||
fun->decl, ANALYZER_PREFIX);
|
||||
fun.decl, ANALYZER_PREFIX);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (logger)
|
||||
logger->log ("traversing %qE (all checks passed)", fun->decl);
|
||||
logger->log ("traversing %qE (all checks passed)", fun.decl);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -3254,9 +3254,9 @@ add_tainted_args_callback (exploded_graph *eg, tree field, tree fndecl,
|
|||
|
||||
program_point point
|
||||
= program_point::from_function_entry (*ext_state.get_model_manager (),
|
||||
eg->get_supergraph (), fun);
|
||||
eg->get_supergraph (), *fun);
|
||||
program_state state (ext_state);
|
||||
state.push_frame (ext_state, fun);
|
||||
state.push_frame (ext_state, *fun);
|
||||
|
||||
if (!mark_params_as_tainted (&state, fndecl, ext_state))
|
||||
return;
|
||||
|
@ -3330,9 +3330,10 @@ exploded_graph::build_initial_worklist ()
|
|||
FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
|
||||
{
|
||||
function *fun = node->get_fun ();
|
||||
if (!toplevel_function_p (fun, logger))
|
||||
gcc_assert (fun);
|
||||
if (!toplevel_function_p (*fun, logger))
|
||||
continue;
|
||||
exploded_node *enode = add_function_entry (fun);
|
||||
exploded_node *enode = add_function_entry (*fun);
|
||||
if (logger)
|
||||
{
|
||||
if (enode)
|
||||
|
@ -3838,8 +3839,8 @@ exploded_graph::maybe_create_dynamic_call (const gcall *call,
|
|||
if (fun)
|
||||
{
|
||||
const supergraph &sg = this->get_supergraph ();
|
||||
supernode *sn_entry = sg.get_node_for_function_entry (fun);
|
||||
supernode *sn_exit = sg.get_node_for_function_exit (fun);
|
||||
supernode *sn_entry = sg.get_node_for_function_entry (*fun);
|
||||
supernode *sn_exit = sg.get_node_for_function_exit (*fun);
|
||||
|
||||
program_point new_point
|
||||
= program_point::before_supernode (sn_entry,
|
||||
|
@ -4962,7 +4963,7 @@ maybe_update_for_edge (logger *logger,
|
|||
== PK_BEFORE_SUPERNODE);
|
||||
function *fun = eedge->m_dest->get_function ();
|
||||
gcc_assert (fun);
|
||||
m_model.push_frame (fun, NULL, ctxt);
|
||||
m_model.push_frame (*fun, NULL, ctxt);
|
||||
if (logger)
|
||||
logger->log (" pushing frame for %qD", fun->decl);
|
||||
}
|
||||
|
@ -5582,7 +5583,7 @@ exploded_graph::on_escaped_function (tree fndecl)
|
|||
if (!gimple_has_body_p (fndecl))
|
||||
return;
|
||||
|
||||
exploded_node *enode = add_function_entry (fun);
|
||||
exploded_node *enode = add_function_entry (*fun);
|
||||
if (logger)
|
||||
{
|
||||
if (enode)
|
||||
|
|
|
@ -285,15 +285,15 @@ class exploded_node : public dnode<eg_traits>
|
|||
const gcall *call_stmt,
|
||||
program_state *state,
|
||||
path_context *path_ctxt,
|
||||
function *called_fn,
|
||||
per_function_data *called_fn_data,
|
||||
const function &called_fn,
|
||||
per_function_data &called_fn_data,
|
||||
region_model_context *ctxt);
|
||||
void replay_call_summary (exploded_graph &eg,
|
||||
const supernode *snode,
|
||||
const gcall *call_stmt,
|
||||
program_state *state,
|
||||
path_context *path_ctxt,
|
||||
function *called_fn,
|
||||
const function &called_fn,
|
||||
call_summary *summary,
|
||||
region_model_context *ctxt);
|
||||
|
||||
|
@ -810,7 +810,7 @@ public:
|
|||
|
||||
exploded_node *get_origin () const { return m_origin; }
|
||||
|
||||
exploded_node *add_function_entry (function *fun);
|
||||
exploded_node *add_function_entry (const function &fun);
|
||||
|
||||
void build_initial_worklist ();
|
||||
void process_worklist ();
|
||||
|
|
|
@ -230,7 +230,7 @@ function_point::final_stmt_p () const
|
|||
/* Create a function_point representing the entrypoint of function FUN. */
|
||||
|
||||
function_point
|
||||
function_point::from_function_entry (const supergraph &sg, function *fun)
|
||||
function_point::from_function_entry (const supergraph &sg, const function &fun)
|
||||
{
|
||||
return before_supernode (sg.get_node_for_function_entry (fun), NULL);
|
||||
}
|
||||
|
@ -698,7 +698,7 @@ program_point::origin (const region_model_manager &mgr)
|
|||
program_point
|
||||
program_point::from_function_entry (const region_model_manager &mgr,
|
||||
const supergraph &sg,
|
||||
function *fun)
|
||||
const function &fun)
|
||||
{
|
||||
return program_point (function_point::from_function_entry (sg, fun),
|
||||
mgr.get_empty_call_string ());
|
||||
|
|
|
@ -112,7 +112,7 @@ public:
|
|||
/* Factory functions for making various kinds of program_point. */
|
||||
|
||||
static function_point from_function_entry (const supergraph &sg,
|
||||
function *fun);
|
||||
const function &fun);
|
||||
|
||||
static function_point before_supernode (const supernode *supernode,
|
||||
const superedge *from_edge);
|
||||
|
@ -252,7 +252,7 @@ public:
|
|||
static program_point origin (const region_model_manager &mgr);
|
||||
static program_point from_function_entry (const region_model_manager &mgr,
|
||||
const supergraph &sg,
|
||||
function *fun);
|
||||
const function &fun);
|
||||
|
||||
static program_point before_supernode (const supernode *supernode,
|
||||
const superedge *from_edge,
|
||||
|
|
|
@ -1143,14 +1143,14 @@ program_state::to_json (const extrinsic_state &ext_state) const
|
|||
|
||||
void
|
||||
program_state::push_frame (const extrinsic_state &ext_state ATTRIBUTE_UNUSED,
|
||||
function *fun)
|
||||
const function &fun)
|
||||
{
|
||||
m_region_model->push_frame (fun, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Get the current function of this state. */
|
||||
|
||||
function *
|
||||
const function *
|
||||
program_state::get_current_function () const
|
||||
{
|
||||
return m_region_model->get_current_function ();
|
||||
|
|
|
@ -226,8 +226,8 @@ public:
|
|||
|
||||
json::object *to_json (const extrinsic_state &ext_state) const;
|
||||
|
||||
void push_frame (const extrinsic_state &ext_state, function *fun);
|
||||
function * get_current_function () const;
|
||||
void push_frame (const extrinsic_state &ext_state, const function &fun);
|
||||
const function * get_current_function () const;
|
||||
|
||||
void push_call (exploded_graph &eg,
|
||||
exploded_node *enode,
|
||||
|
|
|
@ -1676,7 +1676,7 @@ region_model_manager::get_cast_region (const region *original_region,
|
|||
|
||||
const frame_region *
|
||||
region_model_manager::get_frame_region (const frame_region *calling_frame,
|
||||
function *fun)
|
||||
const function &fun)
|
||||
{
|
||||
int index = calling_frame ? calling_frame->get_index () + 1 : 0;
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ public:
|
|||
const region *get_cast_region (const region *original_region,
|
||||
tree type);
|
||||
const frame_region *get_frame_region (const frame_region *calling_frame,
|
||||
function *fun);
|
||||
const function &fun);
|
||||
const region *get_symbolic_region (const svalue *sval);
|
||||
const string_region *get_region_for_string (tree string_cst);
|
||||
const region *get_bit_range (const region *parent, tree type,
|
||||
|
|
|
@ -2619,7 +2619,7 @@ region_model::called_from_main_p () const
|
|||
/* Determine if the oldest stack frame in this model is for "main". */
|
||||
const frame_region *frame0 = get_frame_at_index (0);
|
||||
gcc_assert (frame0);
|
||||
return id_equal (DECL_NAME (frame0->get_function ()->decl), "main");
|
||||
return id_equal (DECL_NAME (frame0->get_function ().decl), "main");
|
||||
}
|
||||
|
||||
/* Subroutine of region_model::get_store_value for when REG is (or is within)
|
||||
|
@ -5552,7 +5552,8 @@ region_model::update_for_gcall (const gcall *call_stmt,
|
|||
callee = DECL_STRUCT_FUNCTION (fn_decl);
|
||||
}
|
||||
|
||||
push_frame (callee, &arg_svals, ctxt);
|
||||
gcc_assert (callee);
|
||||
push_frame (*callee, &arg_svals, ctxt);
|
||||
}
|
||||
|
||||
/* Pop the top-most frame_region from the stack, and copy the return
|
||||
|
@ -5896,14 +5897,15 @@ region_model::on_top_level_param (tree param,
|
|||
Return the frame_region for the new frame. */
|
||||
|
||||
const region *
|
||||
region_model::push_frame (function *fun, const vec<const svalue *> *arg_svals,
|
||||
region_model::push_frame (const function &fun,
|
||||
const vec<const svalue *> *arg_svals,
|
||||
region_model_context *ctxt)
|
||||
{
|
||||
m_current_frame = m_mgr->get_frame_region (m_current_frame, fun);
|
||||
if (arg_svals)
|
||||
{
|
||||
/* Arguments supplied from a caller frame. */
|
||||
tree fndecl = fun->decl;
|
||||
tree fndecl = fun.decl;
|
||||
unsigned idx = 0;
|
||||
for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
|
||||
iter_parm = DECL_CHAIN (iter_parm), ++idx)
|
||||
|
@ -5914,7 +5916,7 @@ region_model::push_frame (function *fun, const vec<const svalue *> *arg_svals,
|
|||
if (idx >= arg_svals->length ())
|
||||
break;
|
||||
tree parm_lval = iter_parm;
|
||||
if (tree parm_default_ssa = ssa_default_def (fun, iter_parm))
|
||||
if (tree parm_default_ssa = get_ssa_default_def (fun, iter_parm))
|
||||
parm_lval = parm_default_ssa;
|
||||
const region *parm_reg = get_lvalue (parm_lval, ctxt);
|
||||
const svalue *arg_sval = (*arg_svals)[idx];
|
||||
|
@ -5937,7 +5939,7 @@ region_model::push_frame (function *fun, const vec<const svalue *> *arg_svals,
|
|||
/* Otherwise we have a top-level call within the analysis. The params
|
||||
have defined but unknown initial values.
|
||||
Anything they point to has escaped. */
|
||||
tree fndecl = fun->decl;
|
||||
tree fndecl = fun.decl;
|
||||
|
||||
/* Handle "__attribute__((nonnull))". */
|
||||
tree fntype = TREE_TYPE (fndecl);
|
||||
|
@ -5951,7 +5953,7 @@ region_model::push_frame (function *fun, const vec<const svalue *> *arg_svals,
|
|||
? (bitmap_empty_p (nonnull_args)
|
||||
|| bitmap_bit_p (nonnull_args, parm_idx))
|
||||
: false);
|
||||
if (tree parm_default_ssa = ssa_default_def (fun, iter_parm))
|
||||
if (tree parm_default_ssa = get_ssa_default_def (fun, iter_parm))
|
||||
on_top_level_param (parm_default_ssa, non_null, ctxt);
|
||||
else
|
||||
on_top_level_param (iter_parm, non_null, ctxt);
|
||||
|
@ -5967,12 +5969,12 @@ region_model::push_frame (function *fun, const vec<const svalue *> *arg_svals,
|
|||
/* Get the function of the top-most frame in this region_model's stack.
|
||||
There must be such a frame. */
|
||||
|
||||
function *
|
||||
const function *
|
||||
region_model::get_current_function () const
|
||||
{
|
||||
const frame_region *frame = get_current_frame ();
|
||||
gcc_assert (frame);
|
||||
return frame->get_function ();
|
||||
return &frame->get_function ();
|
||||
}
|
||||
|
||||
/* Pop the topmost frame_region from this region_model's stack;
|
||||
|
@ -6007,7 +6009,7 @@ region_model::pop_frame (tree result_lvalue,
|
|||
ctxt->on_pop_frame (frame_reg);
|
||||
|
||||
/* Evaluate the result, within the callee frame. */
|
||||
tree fndecl = m_current_frame->get_function ()->decl;
|
||||
tree fndecl = m_current_frame->get_function ().decl;
|
||||
tree result = DECL_RESULT (fndecl);
|
||||
const svalue *retval = NULL;
|
||||
if (result
|
||||
|
@ -7966,7 +7968,7 @@ test_stack_frames ()
|
|||
|
||||
/* Push stack frame for "parent_fn". */
|
||||
const region *parent_frame_reg
|
||||
= model.push_frame (DECL_STRUCT_FUNCTION (parent_fndecl),
|
||||
= model.push_frame (*DECL_STRUCT_FUNCTION (parent_fndecl),
|
||||
NULL, &ctxt);
|
||||
ASSERT_EQ (model.get_current_frame (), parent_frame_reg);
|
||||
ASSERT_TRUE (model.region_exists_p (parent_frame_reg));
|
||||
|
@ -7982,7 +7984,7 @@ test_stack_frames ()
|
|||
|
||||
/* Push stack frame for "child_fn". */
|
||||
const region *child_frame_reg
|
||||
= model.push_frame (DECL_STRUCT_FUNCTION (child_fndecl), NULL, &ctxt);
|
||||
= model.push_frame (*DECL_STRUCT_FUNCTION (child_fndecl), NULL, &ctxt);
|
||||
ASSERT_EQ (model.get_current_frame (), child_frame_reg);
|
||||
ASSERT_TRUE (model.region_exists_p (child_frame_reg));
|
||||
const region *x_in_child_reg = model.get_lvalue (x, &ctxt);
|
||||
|
@ -8075,7 +8077,7 @@ test_get_representative_path_var ()
|
|||
for (int depth = 0; depth < 5; depth++)
|
||||
{
|
||||
const region *frame_n_reg
|
||||
= model.push_frame (DECL_STRUCT_FUNCTION (fndecl), NULL, &ctxt);
|
||||
= model.push_frame (*DECL_STRUCT_FUNCTION (fndecl), NULL, &ctxt);
|
||||
const region *parm_n_reg = model.get_lvalue (path_var (n, depth), &ctxt);
|
||||
parm_regs.safe_push (parm_n_reg);
|
||||
|
||||
|
@ -8319,9 +8321,9 @@ test_state_merging ()
|
|||
region_model model0 (&mgr);
|
||||
region_model model1 (&mgr);
|
||||
ASSERT_EQ (model0.get_stack_depth (), 0);
|
||||
model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
|
||||
model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
|
||||
ASSERT_EQ (model0.get_stack_depth (), 1);
|
||||
model1.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
|
||||
model1.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
|
||||
|
||||
placeholder_svalue test_sval (mgr.alloc_symbol_id (),
|
||||
integer_type_node, "test sval");
|
||||
|
@ -8413,7 +8415,7 @@ test_state_merging ()
|
|||
/* Pointers: non-NULL and non-NULL: ptr to a local. */
|
||||
{
|
||||
region_model model0 (&mgr);
|
||||
model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
|
||||
model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
|
||||
model0.set_value (model0.get_lvalue (p, NULL),
|
||||
model0.get_rvalue (addr_of_a, NULL), NULL);
|
||||
|
||||
|
@ -8552,12 +8554,12 @@ test_state_merging ()
|
|||
frame points to a local in a more recent stack frame. */
|
||||
{
|
||||
region_model model0 (&mgr);
|
||||
model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
|
||||
model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
|
||||
const region *q_in_first_frame = model0.get_lvalue (q, NULL);
|
||||
|
||||
/* Push a second frame. */
|
||||
const region *reg_2nd_frame
|
||||
= model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
|
||||
= model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
|
||||
|
||||
/* Have a pointer in the older frame point to a local in the
|
||||
more recent frame. */
|
||||
|
@ -8584,7 +8586,7 @@ test_state_merging ()
|
|||
/* Verify that we can merge a model in which a local points to a global. */
|
||||
{
|
||||
region_model model0 (&mgr);
|
||||
model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
|
||||
model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
|
||||
model0.set_value (model0.get_lvalue (q, NULL),
|
||||
model0.get_rvalue (addr_of_y, NULL), NULL);
|
||||
|
||||
|
@ -9110,7 +9112,7 @@ test_alloca ()
|
|||
|
||||
/* Push stack frame. */
|
||||
const region *frame_reg
|
||||
= model.push_frame (DECL_STRUCT_FUNCTION (fndecl),
|
||||
= model.push_frame (*DECL_STRUCT_FUNCTION (fndecl),
|
||||
NULL, &ctxt);
|
||||
/* "p = alloca (n * 4);". */
|
||||
const svalue *size_sval = model.get_rvalue (n_times_4, &ctxt);
|
||||
|
|
|
@ -347,10 +347,10 @@ class region_model
|
|||
void update_for_return_gcall (const gcall *call_stmt,
|
||||
region_model_context *ctxt);
|
||||
|
||||
const region *push_frame (function *fun, const vec<const svalue *> *arg_sids,
|
||||
const region *push_frame (const function &fun, const vec<const svalue *> *arg_sids,
|
||||
region_model_context *ctxt);
|
||||
const frame_region *get_current_frame () const { return m_current_frame; }
|
||||
function * get_current_function () const;
|
||||
const function *get_current_function () const;
|
||||
void pop_frame (tree result_lvalue,
|
||||
const svalue **out_result,
|
||||
region_model_context *ctxt,
|
||||
|
|
|
@ -1306,10 +1306,10 @@ void
|
|||
frame_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
||||
{
|
||||
if (simple)
|
||||
pp_printf (pp, "frame: %qs@%i", function_name (m_fun), get_stack_depth ());
|
||||
pp_printf (pp, "frame: %qs@%i", function_name (&m_fun), get_stack_depth ());
|
||||
else
|
||||
pp_printf (pp, "frame_region(%qs, index: %i, depth: %i)",
|
||||
function_name (m_fun), m_index, get_stack_depth ());
|
||||
function_name (&m_fun), m_index, get_stack_depth ());
|
||||
}
|
||||
|
||||
const decl_region *
|
||||
|
@ -1334,14 +1334,14 @@ frame_region::get_region_for_local (region_model_manager *mgr,
|
|||
/* Fall through. */
|
||||
case PARM_DECL:
|
||||
case RESULT_DECL:
|
||||
gcc_assert (DECL_CONTEXT (expr) == m_fun->decl);
|
||||
gcc_assert (DECL_CONTEXT (expr) == m_fun.decl);
|
||||
break;
|
||||
case SSA_NAME:
|
||||
{
|
||||
if (tree var = SSA_NAME_VAR (expr))
|
||||
{
|
||||
if (DECL_P (var))
|
||||
gcc_assert (DECL_CONTEXT (var) == m_fun->decl);
|
||||
gcc_assert (DECL_CONTEXT (var) == m_fun.decl);
|
||||
}
|
||||
else if (ctxt)
|
||||
if (const extrinsic_state *ext_state = ctxt->get_ext_state ())
|
||||
|
@ -1351,7 +1351,7 @@ frame_region::get_region_for_local (region_model_manager *mgr,
|
|||
const gimple *def_stmt = SSA_NAME_DEF_STMT (expr);
|
||||
const supernode *snode
|
||||
= sg->get_supernode_for_stmt (def_stmt);
|
||||
gcc_assert (snode->get_function () == m_fun);
|
||||
gcc_assert (snode->get_function () == &m_fun);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -305,11 +305,10 @@ public:
|
|||
/* A support class for uniquifying instances of frame_region. */
|
||||
struct key_t
|
||||
{
|
||||
key_t (const frame_region *calling_frame, function *fun)
|
||||
: m_calling_frame (calling_frame), m_fun (fun)
|
||||
key_t (const frame_region *calling_frame, const function &fun)
|
||||
: m_calling_frame (calling_frame), m_fun (&fun)
|
||||
{
|
||||
/* calling_frame can be NULL. */
|
||||
gcc_assert (fun);
|
||||
}
|
||||
|
||||
hashval_t hash () const
|
||||
|
@ -322,7 +321,8 @@ public:
|
|||
|
||||
bool operator== (const key_t &other) const
|
||||
{
|
||||
return (m_calling_frame == other.m_calling_frame && m_fun == other.m_fun);
|
||||
return (m_calling_frame == other.m_calling_frame
|
||||
&& m_fun == other.m_fun);
|
||||
}
|
||||
|
||||
void mark_deleted () { m_fun = reinterpret_cast<function *> (1); }
|
||||
|
@ -334,12 +334,12 @@ public:
|
|||
bool is_empty () const { return m_fun == NULL; }
|
||||
|
||||
const frame_region *m_calling_frame;
|
||||
function *m_fun;
|
||||
const function *m_fun;
|
||||
};
|
||||
|
||||
frame_region (symbol::id_t id, const region *parent,
|
||||
const frame_region *calling_frame,
|
||||
function *fun, int index)
|
||||
const function &fun, int index)
|
||||
: space_region (id, parent), m_calling_frame (calling_frame),
|
||||
m_fun (fun), m_index (index)
|
||||
{}
|
||||
|
@ -356,8 +356,8 @@ public:
|
|||
|
||||
/* Accessors. */
|
||||
const frame_region *get_calling_frame () const { return m_calling_frame; }
|
||||
function *get_function () const { return m_fun; }
|
||||
tree get_fndecl () const { return get_function ()->decl; }
|
||||
const function &get_function () const { return m_fun; }
|
||||
tree get_fndecl () const { return get_function ().decl; }
|
||||
int get_index () const { return m_index; }
|
||||
int get_stack_depth () const { return m_index + 1; }
|
||||
|
||||
|
@ -373,7 +373,7 @@ public:
|
|||
|
||||
private:
|
||||
const frame_region *m_calling_frame;
|
||||
function *m_fun;
|
||||
const function &m_fun;
|
||||
int m_index;
|
||||
|
||||
/* The regions for the decls within this frame are managed by this
|
||||
|
|
|
@ -146,7 +146,8 @@ public:
|
|||
if (change.is_global_p ()
|
||||
&& change.m_new_state == m_sm.m_in_signal_handler)
|
||||
{
|
||||
function *handler = change.m_event.get_dest_function ();
|
||||
const function *handler = change.m_event.get_dest_function ();
|
||||
gcc_assert (handler);
|
||||
return change.formatted_print ("registering %qD as signal handler",
|
||||
handler->decl);
|
||||
}
|
||||
|
@ -193,7 +194,7 @@ signal_state_machine::signal_state_machine (logger *logger)
|
|||
|
||||
static void
|
||||
update_model_for_signal_handler (region_model *model,
|
||||
function *handler_fun)
|
||||
const function &handler_fun)
|
||||
{
|
||||
gcc_assert (model);
|
||||
/* Purge all state within MODEL. */
|
||||
|
@ -222,7 +223,9 @@ public:
|
|||
region_model_context *) const final override
|
||||
{
|
||||
gcc_assert (eedge);
|
||||
update_model_for_signal_handler (model, eedge->m_dest->get_function ());
|
||||
gcc_assert (eedge->m_dest->get_function ());
|
||||
update_model_for_signal_handler (model,
|
||||
*eedge->m_dest->get_function ());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -263,11 +266,11 @@ public:
|
|||
program_point entering_handler
|
||||
= program_point::from_function_entry (*ext_state.get_model_manager (),
|
||||
eg->get_supergraph (),
|
||||
handler_fun);
|
||||
*handler_fun);
|
||||
|
||||
program_state state_entering_handler (ext_state);
|
||||
update_model_for_signal_handler (state_entering_handler.m_region_model,
|
||||
handler_fun);
|
||||
*handler_fun);
|
||||
state_entering_handler.m_checker_states[sm_idx]->set_global_state
|
||||
(m_sm.m_in_signal_handler);
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ class gimple_op_visitor : public log_user
|
|||
public:
|
||||
gimple_op_visitor (state_purge_map *map,
|
||||
const function_point &point,
|
||||
function *fun)
|
||||
const function &fun)
|
||||
: log_user (map->get_logger ()),
|
||||
m_map (map),
|
||||
m_point (point),
|
||||
|
@ -172,7 +172,7 @@ private:
|
|||
|
||||
state_purge_map *m_map;
|
||||
const function_point &m_point;
|
||||
function *m_fun;
|
||||
const function &m_fun;
|
||||
};
|
||||
|
||||
static bool
|
||||
|
@ -214,6 +214,7 @@ state_purge_map::state_purge_map (const supergraph &sg,
|
|||
FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
|
||||
{
|
||||
function *fun = node->get_fun ();
|
||||
gcc_assert (fun);
|
||||
if (logger)
|
||||
log ("function: %s", function_name (fun));
|
||||
tree name;
|
||||
|
@ -225,7 +226,7 @@ state_purge_map::state_purge_map (const supergraph &sg,
|
|||
if (TREE_CODE (var) == VAR_DECL)
|
||||
if (VAR_DECL_IS_VIRTUAL_OPERAND (var))
|
||||
continue;
|
||||
m_ssa_map.put (name, new state_purge_per_ssa_name (*this, name, fun));
|
||||
m_ssa_map.put (name, new state_purge_per_ssa_name (*this, name, *fun));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,8 +242,10 @@ state_purge_map::state_purge_map (const supergraph &sg,
|
|||
unsigned i;
|
||||
FOR_EACH_VEC_ELT (snode->m_stmts, i, stmt)
|
||||
{
|
||||
function *fun = snode->get_function ();
|
||||
gcc_assert (fun);
|
||||
function_point point (function_point::before_stmt (snode, i));
|
||||
gimple_op_visitor v (this, point, snode->get_function ());
|
||||
gimple_op_visitor v (this, point, *fun);
|
||||
walk_stmt_load_store_addr_ops (stmt, &v,
|
||||
my_load_cb, my_store_cb, my_addr_cb);
|
||||
}
|
||||
|
@ -272,7 +275,7 @@ state_purge_map::~state_purge_map ()
|
|||
if necessary. */
|
||||
|
||||
state_purge_per_decl &
|
||||
state_purge_map::get_or_create_data_for_decl (function *fun, tree decl)
|
||||
state_purge_map::get_or_create_data_for_decl (const function &fun, tree decl)
|
||||
{
|
||||
if (state_purge_per_decl **slot
|
||||
= const_cast <decl_map_t&> (m_decl_map).get (decl))
|
||||
|
@ -295,14 +298,14 @@ state_purge_map::get_or_create_data_for_decl (function *fun, tree decl)
|
|||
|
||||
state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map,
|
||||
tree name,
|
||||
function *fun)
|
||||
const function &fun)
|
||||
: state_purge_per_tree (fun), m_points_needing_name (), m_name (name)
|
||||
{
|
||||
LOG_FUNC (map.get_logger ());
|
||||
|
||||
if (map.get_logger ())
|
||||
{
|
||||
map.log ("SSA name: %qE within %qD", name, fun->decl);
|
||||
map.log ("SSA name: %qE within %qD", name, fun.decl);
|
||||
|
||||
/* Show def stmt. */
|
||||
const gimple *def_stmt = SSA_NAME_DEF_STMT (name);
|
||||
|
@ -410,7 +413,7 @@ state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map,
|
|||
|
||||
if (map.get_logger ())
|
||||
{
|
||||
map.log ("%qE in %qD is needed to process:", name, fun->decl);
|
||||
map.log ("%qE in %qD is needed to process:", name, fun.decl);
|
||||
/* Log m_points_needing_name, sorting it to avoid churn when comparing
|
||||
dumps. */
|
||||
auto_vec<function_point> points;
|
||||
|
@ -472,7 +475,7 @@ state_purge_per_ssa_name::add_to_worklist (const function_point &point,
|
|||
logger->end_log_line ();
|
||||
}
|
||||
|
||||
gcc_assert (point.get_function () == get_function ());
|
||||
gcc_assert (point.get_function () == &get_function ());
|
||||
if (point.get_from_edge ())
|
||||
gcc_assert (point.get_from_edge ()->get_kind () == SUPEREDGE_CFG_EDGE);
|
||||
|
||||
|
@ -678,7 +681,7 @@ state_purge_per_ssa_name::process_point (const function_point &point,
|
|||
|
||||
state_purge_per_decl::state_purge_per_decl (const state_purge_map &map,
|
||||
tree decl,
|
||||
function *fun)
|
||||
const function &fun)
|
||||
: state_purge_per_tree (fun),
|
||||
m_decl (decl)
|
||||
{
|
||||
|
@ -794,7 +797,7 @@ state_purge_per_decl::add_to_worklist (const function_point &point,
|
|||
logger->end_log_line ();
|
||||
}
|
||||
|
||||
gcc_assert (point.get_function () == get_function ());
|
||||
gcc_assert (point.get_function () == &get_function ());
|
||||
if (point.get_from_edge ())
|
||||
gcc_assert (point.get_from_edge ()->get_kind () == SUPEREDGE_CFG_EDGE);
|
||||
|
||||
|
@ -1192,7 +1195,7 @@ state_purge_annotator::print_needed (graphviz_out *gv,
|
|||
{
|
||||
tree name = (*iter).first;
|
||||
state_purge_per_ssa_name *per_name_data = (*iter).second;
|
||||
if (per_name_data->get_function () == point.get_function ())
|
||||
if (&per_name_data->get_function () == point.get_function ())
|
||||
{
|
||||
if (per_name_data->needed_at_point_p (point))
|
||||
needed.safe_push (name);
|
||||
|
@ -1206,7 +1209,7 @@ state_purge_annotator::print_needed (graphviz_out *gv,
|
|||
{
|
||||
tree decl = (*iter).first;
|
||||
state_purge_per_decl *per_decl_data = (*iter).second;
|
||||
if (per_decl_data->get_function () == point.get_function ())
|
||||
if (&per_decl_data->get_function () == point.get_function ())
|
||||
{
|
||||
if (per_decl_data->needed_at_point_p (point))
|
||||
needed.safe_push (decl);
|
||||
|
|
|
@ -112,7 +112,8 @@ public:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
state_purge_per_decl &get_or_create_data_for_decl (function *fun, tree decl);
|
||||
state_purge_per_decl &
|
||||
get_or_create_data_for_decl (const function &fun, tree decl);
|
||||
|
||||
const supergraph &get_sg () const { return m_sg; }
|
||||
|
||||
|
@ -135,19 +136,19 @@ private:
|
|||
class state_purge_per_tree
|
||||
{
|
||||
public:
|
||||
function *get_function () const { return m_fun; }
|
||||
tree get_fndecl () const { return m_fun->decl; }
|
||||
const function &get_function () const { return m_fun; }
|
||||
tree get_fndecl () const { return m_fun.decl; }
|
||||
|
||||
protected:
|
||||
typedef hash_set<function_point> point_set_t;
|
||||
|
||||
state_purge_per_tree (function *fun)
|
||||
state_purge_per_tree (const function &fun)
|
||||
: m_fun (fun)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
function *m_fun;
|
||||
const function &m_fun;
|
||||
};
|
||||
|
||||
/* The part of a state_purge_map relating to a specific SSA name.
|
||||
|
@ -162,7 +163,7 @@ class state_purge_per_ssa_name : public state_purge_per_tree
|
|||
public:
|
||||
state_purge_per_ssa_name (const state_purge_map &map,
|
||||
tree name,
|
||||
function *fun);
|
||||
const function &fun);
|
||||
|
||||
bool needed_at_point_p (const function_point &point) const;
|
||||
|
||||
|
@ -194,7 +195,7 @@ class state_purge_per_decl : public state_purge_per_tree
|
|||
public:
|
||||
state_purge_per_decl (const state_purge_map &map,
|
||||
tree decl,
|
||||
function *fun);
|
||||
const function &fun);
|
||||
|
||||
bool needed_at_point_p (const function_point &point) const;
|
||||
|
||||
|
|
|
@ -364,6 +364,7 @@ supergraph::dump_dot_to_pp (pretty_printer *pp,
|
|||
FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
|
||||
{
|
||||
function *fun = node->get_fun ();
|
||||
gcc_assert (fun);
|
||||
const char *funcname = function_name (fun);
|
||||
gv.println ("subgraph \"cluster_%s\" {",
|
||||
funcname);
|
||||
|
@ -409,9 +410,9 @@ supergraph::dump_dot_to_pp (pretty_printer *pp,
|
|||
|
||||
/* Add an invisible edge from ENTRY to EXIT, to improve the graph layout. */
|
||||
pp_string (pp, "\t");
|
||||
get_node_for_function_entry (fun)->dump_dot_id (pp);
|
||||
get_node_for_function_entry (*fun)->dump_dot_id (pp);
|
||||
pp_string (pp, ":s -> ");
|
||||
get_node_for_function_exit (fun)->dump_dot_id (pp);
|
||||
get_node_for_function_exit (*fun)->dump_dot_id (pp);
|
||||
pp_string (pp, ":n [style=\"invis\",constraint=true];\n");
|
||||
|
||||
/* Terminate per-function "subgraph" */
|
||||
|
|
|
@ -111,14 +111,14 @@ public:
|
|||
supergraph (logger *logger);
|
||||
~supergraph ();
|
||||
|
||||
supernode *get_node_for_function_entry (function *fun) const
|
||||
supernode *get_node_for_function_entry (const function &fun) const
|
||||
{
|
||||
return get_node_for_block (ENTRY_BLOCK_PTR_FOR_FN (fun));
|
||||
return get_node_for_block (ENTRY_BLOCK_PTR_FOR_FN (&fun));
|
||||
}
|
||||
|
||||
supernode *get_node_for_function_exit (function *fun) const
|
||||
supernode *get_node_for_function_exit (const function &fun) const
|
||||
{
|
||||
return get_node_for_block (EXIT_BLOCK_PTR_FOR_FN (fun));
|
||||
return get_node_for_block (EXIT_BLOCK_PTR_FOR_FN (&fun));
|
||||
}
|
||||
|
||||
supernode *get_node_for_block (basic_block bb) const
|
||||
|
|
|
@ -6391,7 +6391,7 @@ fndecl_name (tree fndecl)
|
|||
|
||||
/* Returns the name of function FN. */
|
||||
const char *
|
||||
function_name (struct function *fn)
|
||||
function_name (const function *fn)
|
||||
{
|
||||
tree fndecl = (fn == NULL) ? NULL : fn->decl;
|
||||
return fndecl_name (fndecl);
|
||||
|
|
|
@ -730,7 +730,7 @@ extern poly_int64 get_stack_dynamic_offset ();
|
|||
|
||||
/* Returns the name of the current function. */
|
||||
extern const char *fndecl_name (tree);
|
||||
extern const char *function_name (struct function *);
|
||||
extern const char *function_name (const function *);
|
||||
extern const char *current_function_name (void);
|
||||
|
||||
extern void used_types_insert (tree);
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/* Verify we don't ICE on this case with these options. */
|
||||
|
||||
/* { dg-additional-options "-fanalyzer-call-summaries --param=analyzer-max-svalue-depth=0 -Wno-analyzer-symbol-too-complex" } */
|
||||
|
||||
int foo_i;
|
||||
void bar() {}
|
||||
void foo() {
|
||||
if (foo_i)
|
||||
bar();
|
||||
else
|
||||
goto f1;
|
||||
bar();
|
||||
f1:
|
||||
bar();
|
||||
}
|
||||
int main() {
|
||||
foo();
|
||||
foo();
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue