Makefile.in (cgraphbuild.o): Add dependency on ipa-utils.h

* Makefile.in (cgraphbuild.o): Add dependency on ipa-utils.h
	* cgraphbuild.c: Include ipa-utils.h
	(record_reference_ctx): New struct.
	(record_reference): Simplify to work on initializers; not statements.
	(mark_address, mark_load, mark_store): New.
	(build_cgraph_edges): Simplify using walk_stmt_load_store_addr_ops;
	walk PHI nodes too.
	(record_references_in_initializer): Update use of record_reference.
	(rebuild_cgraph_edges): Simplify using walk_stmt_load_store_addr_ops;
	walk PHI nodes too.

From-SVN: r159032
This commit is contained in:
Jan Hubicka 2010-05-04 17:42:15 +02:00 committed by Jan Hubicka
parent 688a10c2b9
commit 85912441e4
2 changed files with 155 additions and 62 deletions

View File

@ -1,3 +1,16 @@
2010-05-04 Jan Hubicka <jh@suse.cz>
* Makefile.in (cgraphbuild.o): Add dependency on ipa-utils.h
* cgraphbuild.c: Include ipa-utils.h
(record_reference_ctx): New struct.
(record_reference): Simplify to work on initializers; not statements.
(mark_address, mark_load, mark_store): New.
(build_cgraph_edges): Simplify using walk_stmt_load_store_addr_ops;
walk PHI nodes too.
(record_references_in_initializer): Update use of record_reference.
(rebuild_cgraph_edges): Simplify using walk_stmt_load_store_addr_ops;
walk PHI nodes too.
2010-05-04 Jan Hubicka <jh@suse.cz>
* lto-symtab.c (lto_cgraph_replace_node): Do not remove edges;

View File

@ -31,6 +31,13 @@ along with GCC; see the file COPYING3. If not see
#include "intl.h"
#include "gimple.h"
#include "tree-pass.h"
#include "ipa-utils.h"
/* Context of record_reference. */
struct record_reference_ctx
{
bool only_vars;
};
/* Walk tree and record all calls and references to functions/variables.
Called via walk_tree: TP is pointer to tree to be examined.
@ -42,26 +49,31 @@ record_reference (tree *tp, int *walk_subtrees, void *data)
{
tree t = *tp;
tree decl;
bool do_callgraph = data != NULL;
struct record_reference_ctx *ctx = (struct record_reference_ctx *)data;
switch (TREE_CODE (t))
{
case VAR_DECL:
if (TREE_STATIC (t) || DECL_EXTERNAL (t))
{
varpool_mark_needed_node (varpool_node (t));
if (lang_hooks.callgraph.analyze_expr)
return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees);
}
case FUNCTION_DECL:
gcc_unreachable ();
break;
case FDESC_EXPR:
case ADDR_EXPR:
/* Record dereferences to the functions. This makes the
functions reachable unconditionally. */
decl = TREE_OPERAND (*tp, 0);
if (TREE_CODE (decl) == FUNCTION_DECL && do_callgraph)
decl = get_base_var (*tp);
if (TREE_CODE (decl) == FUNCTION_DECL && !ctx->only_vars)
cgraph_mark_address_taken_node (cgraph_node (decl));
if (TREE_CODE (decl) == VAR_DECL)
{
gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl));
if (lang_hooks.callgraph.analyze_expr)
lang_hooks.callgraph.analyze_expr (&decl, walk_subtrees);
varpool_mark_needed_node (varpool_node (decl));
}
*walk_subtrees = 0;
break;
default:
@ -126,6 +138,75 @@ compute_call_stmt_bb_frequency (tree decl, basic_block bb)
return freq;
}
/* Mark address taken in STMT. */
static bool
mark_address (gimple stmt ATTRIBUTE_UNUSED, tree addr,
void *data ATTRIBUTE_UNUSED)
{
if (TREE_CODE (addr) == FUNCTION_DECL)
{
struct cgraph_node *node = cgraph_node (addr);
cgraph_mark_address_taken_node (node);
}
else
{
addr = get_base_address (addr);
if (addr && TREE_CODE (addr) == VAR_DECL
&& (TREE_STATIC (addr) || DECL_EXTERNAL (addr)))
{
struct varpool_node *vnode = varpool_node (addr);
int walk_subtrees;
if (lang_hooks.callgraph.analyze_expr)
lang_hooks.callgraph.analyze_expr (&addr, &walk_subtrees);
varpool_mark_needed_node (vnode);
}
}
return false;
}
/* Mark load of T. */
static bool
mark_load (gimple stmt ATTRIBUTE_UNUSED, tree t,
void *data ATTRIBUTE_UNUSED)
{
t = get_base_address (t);
if (TREE_CODE (t) == VAR_DECL
&& (TREE_STATIC (t) || DECL_EXTERNAL (t)))
{
struct varpool_node *vnode = varpool_node (t);
int walk_subtrees;
if (lang_hooks.callgraph.analyze_expr)
lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees);
varpool_mark_needed_node (vnode);
}
return false;
}
/* Mark store of T. */
static bool
mark_store (gimple stmt ATTRIBUTE_UNUSED, tree t,
void *data ATTRIBUTE_UNUSED)
{
t = get_base_address (t);
if (TREE_CODE (t) == VAR_DECL
&& (TREE_STATIC (t) || DECL_EXTERNAL (t)))
{
struct varpool_node *vnode = varpool_node (t);
int walk_subtrees;
if (lang_hooks.callgraph.analyze_expr)
lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees);
varpool_mark_needed_node (vnode);
}
return false;
}
/* Create cgraph edges for function calls.
Also look for functions and variables having addresses taken. */
@ -141,49 +222,40 @@ build_cgraph_edges (void)
/* Create the callgraph edges and record the nodes referenced by the function.
body. */
FOR_EACH_BB (bb)
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple stmt = gsi_stmt (gsi);
tree decl;
{
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple stmt = gsi_stmt (gsi);
tree decl;
if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
{
size_t i;
size_t n = gimple_call_num_args (stmt);
if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
cgraph_create_edge (node, cgraph_node (decl), stmt,
bb->count, compute_call_stmt_bb_frequency (current_function_decl, bb),
bb->count,
compute_call_stmt_bb_frequency
(current_function_decl, bb),
bb->loop_depth);
for (i = 0; i < n; i++)
walk_tree (gimple_call_arg_ptr (stmt, i), record_reference,
node, visited_nodes);
if (gimple_call_lhs (stmt))
walk_tree (gimple_call_lhs_ptr (stmt), record_reference, node,
visited_nodes);
}
else
{
struct walk_stmt_info wi;
memset (&wi, 0, sizeof (wi));
wi.info = node;
wi.pset = visited_nodes;
walk_gimple_op (stmt, record_reference, &wi);
if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
&& gimple_omp_parallel_child_fn (stmt))
{
tree fn = gimple_omp_parallel_child_fn (stmt);
walk_stmt_load_store_addr_ops (stmt, node, mark_load,
mark_store, mark_address);
if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
&& gimple_omp_parallel_child_fn (stmt))
{
tree fn = gimple_omp_parallel_child_fn (stmt);
cgraph_mark_needed_node (cgraph_node (fn));
}
if (gimple_code (stmt) == GIMPLE_OMP_TASK)
{
tree fn = gimple_omp_task_child_fn (stmt);
if (fn)
cgraph_mark_needed_node (cgraph_node (fn));
}
if (gimple_code (stmt) == GIMPLE_OMP_TASK)
{
tree fn = gimple_omp_task_child_fn (stmt);
if (fn)
cgraph_mark_needed_node (cgraph_node (fn));
fn = gimple_omp_task_copy_fn (stmt);
if (fn)
cgraph_mark_needed_node (cgraph_node (fn));
}
}
}
fn = gimple_omp_task_copy_fn (stmt);
if (fn)
cgraph_mark_needed_node (cgraph_node (fn));
}
}
for (gsi = gsi_start (phi_nodes (bb)); !gsi_end_p (gsi); gsi_next (&gsi))
walk_stmt_load_store_addr_ops (gsi_stmt (gsi), node,
mark_load, mark_store, mark_address);
}
/* Look for initializers of constant variables and private statics. */
for (step = cfun->local_decls;
@ -194,8 +266,6 @@ build_cgraph_edges (void)
if (TREE_CODE (decl) == VAR_DECL
&& (TREE_STATIC (decl) && !DECL_EXTERNAL (decl)))
varpool_finalize_decl (decl);
else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes);
}
pointer_set_destroy (visited_nodes);
@ -229,8 +299,11 @@ void
record_references_in_initializer (tree decl, bool only_vars)
{
struct pointer_set_t *visited_nodes = pointer_set_create ();
struct record_reference_ctx ctx = {false};
ctx.only_vars = only_vars;
walk_tree (&DECL_INITIAL (decl), record_reference,
only_vars ? NULL : decl, visited_nodes);
&ctx, visited_nodes);
pointer_set_destroy (visited_nodes);
}
@ -249,19 +322,26 @@ rebuild_cgraph_edges (void)
node->count = ENTRY_BLOCK_PTR->count;
FOR_EACH_BB (bb)
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple stmt = gsi_stmt (gsi);
tree decl;
{
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple stmt = gsi_stmt (gsi);
tree decl;
if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
cgraph_create_edge (node, cgraph_node (decl), stmt,
bb->count,
compute_call_stmt_bb_frequency
(current_function_decl, bb),
bb->loop_depth);
if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
cgraph_create_edge (node, cgraph_node (decl), stmt,
bb->count,
compute_call_stmt_bb_frequency
(current_function_decl, bb),
bb->loop_depth);
walk_stmt_load_store_addr_ops (stmt, node, mark_load,
mark_store, mark_address);
}
}
for (gsi = gsi_start (phi_nodes (bb)); !gsi_end_p (gsi); gsi_next (&gsi))
walk_stmt_load_store_addr_ops (gsi_stmt (gsi), node,
mark_load, mark_store, mark_address);
}
gcc_assert (!node->global.inlined_to);
return 0;