Index: gcc/gcc/cgraphbuild.c |
diff --git a/gcc/gcc/cgraphbuild.c b/gcc/gcc/cgraphbuild.c |
index 75db87544cea3706c6e65c3cbc541f3da8b95d9f..bcc66c0eecd47de44e409839fe006288915901da 100644 |
--- a/gcc/gcc/cgraphbuild.c |
+++ b/gcc/gcc/cgraphbuild.c |
@@ -1,5 +1,5 @@ |
/* Callgraph construction. |
- Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 |
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 |
Free Software Foundation, Inc. |
Contributed by Jan Hubicka |
@@ -33,13 +33,16 @@ along with GCC; see the file COPYING3. If not see |
#include "tree-pass.h" |
/* Walk tree and record all calls and references to functions/variables. |
- Called via walk_tree: TP is pointer to tree to be examined. */ |
+ Called via walk_tree: TP is pointer to tree to be examined. |
+ When DATA is non-null, record references to callgraph. |
+ */ |
static tree |
-record_reference (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) |
+record_reference (tree *tp, int *walk_subtrees, void *data) |
{ |
tree t = *tp; |
tree decl; |
+ bool do_callgraph = data != NULL; |
switch (TREE_CODE (t)) |
{ |
@@ -57,8 +60,8 @@ record_reference (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) |
/* Record dereferences to the functions. This makes the |
functions reachable unconditionally. */ |
decl = TREE_OPERAND (*tp, 0); |
- if (TREE_CODE (decl) == FUNCTION_DECL) |
- cgraph_mark_needed_node (cgraph_node (decl)); |
+ if (TREE_CODE (decl) == FUNCTION_DECL && do_callgraph) |
+ cgraph_mark_address_taken_node (cgraph_node (decl)); |
break; |
default: |
@@ -78,39 +81,41 @@ record_reference (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) |
return NULL_TREE; |
} |
-/* Give initial reasons why inlining would fail on all calls from |
- NODE. Those get either nullified or usually overwritten by more precise |
- reason later. */ |
+/* Reset inlining information of all incoming call edges of NODE. */ |
-static void |
-initialize_inline_failed (struct cgraph_node *node) |
+void |
+reset_inline_failed (struct cgraph_node *node) |
{ |
struct cgraph_edge *e; |
for (e = node->callers; e; e = e->next_caller) |
{ |
- gcc_assert (!e->callee->global.inlined_to); |
- gcc_assert (e->inline_failed); |
- if (node->local.redefined_extern_inline) |
- e->inline_failed = N_("redefined extern inline functions are not " |
- "considered for inlining"); |
+ e->callee->global.inlined_to = NULL; |
+ if (!node->analyzed) |
+ e->inline_failed = CIF_BODY_NOT_AVAILABLE; |
+ else if (node->local.redefined_extern_inline) |
+ e->inline_failed = CIF_REDEFINED_EXTERN_INLINE; |
else if (!node->local.inlinable) |
- e->inline_failed = N_("function not inlinable"); |
- else if (gimple_call_cannot_inline_p (e->call_stmt)) |
- e->inline_failed = N_("mismatched arguments"); |
+ e->inline_failed = CIF_FUNCTION_NOT_INLINABLE; |
+ else if (e->call_stmt_cannot_inline_p) |
+ e->inline_failed = CIF_MISMATCHED_ARGUMENTS; |
else |
- e->inline_failed = N_("function not considered for inlining"); |
+ e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED; |
} |
} |
/* Computes the frequency of the call statement so that it can be stored in |
cgraph_edge. BB is the basic block of the call statement. */ |
int |
-compute_call_stmt_bb_frequency (basic_block bb) |
+compute_call_stmt_bb_frequency (tree decl, basic_block bb) |
{ |
- int entry_freq = ENTRY_BLOCK_PTR->frequency; |
+ int entry_freq = ENTRY_BLOCK_PTR_FOR_FUNCTION |
+ (DECL_STRUCT_FUNCTION (decl))->frequency; |
int freq = bb->frequency; |
+ if (profile_status_for_function (DECL_STRUCT_FUNCTION (decl)) == PROFILE_ABSENT) |
+ return CGRAPH_FREQ_BASE; |
+ |
if (!entry_freq) |
entry_freq = 1, freq++; |
@@ -146,7 +151,7 @@ build_cgraph_edges (void) |
size_t i; |
size_t n = gimple_call_num_args (stmt); |
cgraph_create_edge (node, cgraph_node (decl), stmt, |
- bb->count, compute_call_stmt_bb_frequency (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, |
@@ -194,7 +199,6 @@ build_cgraph_edges (void) |
} |
pointer_set_destroy (visited_nodes); |
- initialize_inline_failed (node); |
return 0; |
} |
@@ -202,13 +206,13 @@ struct gimple_opt_pass pass_build_cgraph_edges = |
{ |
{ |
GIMPLE_PASS, |
- NULL, /* name */ |
+ "*build_cgraph_edges", /* name */ |
NULL, /* gate */ |
build_cgraph_edges, /* execute */ |
NULL, /* sub */ |
NULL, /* next */ |
0, /* static_pass_number */ |
- 0, /* tv_id */ |
+ TV_NONE, /* tv_id */ |
PROP_cfg, /* properties_required */ |
0, /* properties_provided */ |
0, /* properties_destroyed */ |
@@ -218,13 +222,15 @@ struct gimple_opt_pass pass_build_cgraph_edges = |
}; |
/* Record references to functions and other variables present in the |
- initial value of DECL, a variable. */ |
+ initial value of DECL, a variable. |
+ When ONLY_VARS is true, we mark needed only variables, not functions. */ |
void |
-record_references_in_initializer (tree decl) |
+record_references_in_initializer (tree decl, bool only_vars) |
{ |
struct pointer_set_t *visited_nodes = pointer_set_create (); |
- walk_tree (&DECL_INITIAL (decl), record_reference, NULL, visited_nodes); |
+ walk_tree (&DECL_INITIAL (decl), record_reference, |
+ only_vars ? NULL : decl, visited_nodes); |
pointer_set_destroy (visited_nodes); |
} |
@@ -250,12 +256,14 @@ rebuild_cgraph_edges (void) |
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 (bb), |
+ bb->count, |
+ compute_call_stmt_bb_frequency |
+ (current_function_decl, bb), |
bb->loop_depth); |
} |
- initialize_inline_failed (node); |
gcc_assert (!node->global.inlined_to); |
+ |
return 0; |
} |
@@ -263,13 +271,13 @@ struct gimple_opt_pass pass_rebuild_cgraph_edges = |
{ |
{ |
GIMPLE_PASS, |
- NULL, /* name */ |
+ "*rebuild_cgraph_edges", /* name */ |
NULL, /* gate */ |
rebuild_cgraph_edges, /* execute */ |
NULL, /* sub */ |
NULL, /* next */ |
0, /* static_pass_number */ |
- 0, /* tv_id */ |
+ TV_NONE, /* tv_id */ |
PROP_cfg, /* properties_required */ |
0, /* properties_provided */ |
0, /* properties_destroyed */ |
@@ -277,3 +285,30 @@ struct gimple_opt_pass pass_rebuild_cgraph_edges = |
0, /* todo_flags_finish */ |
} |
}; |
+ |
+ |
+static unsigned int |
+remove_cgraph_callee_edges (void) |
+{ |
+ cgraph_node_remove_callees (cgraph_node (current_function_decl)); |
+ return 0; |
+} |
+ |
+struct gimple_opt_pass pass_remove_cgraph_callee_edges = |
+{ |
+ { |
+ GIMPLE_PASS, |
+ "*remove_cgraph_callee_edges", /* name */ |
+ NULL, /* gate */ |
+ remove_cgraph_callee_edges, /* execute */ |
+ NULL, /* sub */ |
+ NULL, /* next */ |
+ 0, /* static_pass_number */ |
+ TV_NONE, /* tv_id */ |
+ 0, /* properties_required */ |
+ 0, /* properties_provided */ |
+ 0, /* properties_destroyed */ |
+ 0, /* todo_flags_start */ |
+ 0, /* todo_flags_finish */ |
+ } |
+}; |