summaryrefslogtreecommitdiff
path: root/gcc/cgraphunit.c
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2011-05-06 23:00:49 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2011-05-06 23:00:49 +0000
commit91bf9d9ad6f23ff598b998fb10670fafd837cf77 (patch)
tree00b435c7373736adc2b2930493aa86fc6e9c0b31 /gcc/cgraphunit.c
parent84117c98ad16505884af5074b306ea064f05d61e (diff)
downloadgcc-91bf9d9ad6f23ff598b998fb10670fafd837cf77.tar.gz
* cgraph.c (cgraph_add_thunk): Create real function node instead
of alias node; finalize it and mark needed/reachale; arrange visibility to be right and add it into the corresponding same comdat group list. (dump_cgraph_node): Dump thunks. * cgraph.h (cgraph_first_defined_function, cgraph_next_defined_function, cgraph_function_with_gimple_body_p, cgraph_first_function_with_gimple_body, cgraph_next_function_with_gimple_body): New functions. (FOR_EACH_FUNCTION_WITH_GIMPLE_BODY, FOR_EACH_DEFINED_FUNCTION): New macros. * ipa-cp.c (ipcp_need_redirect_p): Thunks can't be redirected. (ipcp_generate_summary): Use FOR_EACH_FUNCTION_WITH_GIMPLE_BODY. * cgraphunit.c (cgraph_finalize_function): Only look into possible devirtualization when optimizing. (verify_cgraph_node): Verify thunks. (cgraph_analyze_function): Analyze thunks. (cgraph_mark_functions_to_output): Output thunks only in combination with function they are assigned to. (assemble_thunk): Turn thunk into non-thunk; don't try to turn alias into normal node. (assemble_thunks): New functoin. (cgraph_expand_function): Use it. * lto-cgraph.c (lto_output_node): Stream thunks. (input_overwrite_node): Stream in thunks. * ipa-pure-const.c (analyze_function): Thunks do nothing interesting. * lto-streamer-out.c (lto_output): Do not try to output thunk's body. * ipa-inline.c (inline_small_functions): Use FOR_EACH_DEFINED_FUNCTION. * ipa-inline-analysis.c (compute_inline_parameters): "Analyze" thunks. (inline_analyze_function): Do not care about thunk jump functions. (inline_generate_summary):Use FOR_EACH_DEFINED_FUNCTION. * ipa-prop.c (ipa_prop_write_jump_functions): Use cgraph_function_with_gimple_body_p. * passes.c (do_per_function_toporder): Use cgraph_function_with_gimple_body_p. (execute_one_pass);Use FOR_EACH_FUNCTION_WITH_GIMPLE_BODY. (ipa_write_summaries): Use cgraph_function_with_gimple_body_p. (function_called_by_processed_nodes_p): Likewise. * lto.c (lto_materialize_function): Use cgraph_function_with_gimple_body_p. (add_cgraph_node_to_partition): Do not re-add items to partition; handle thunks. (add_varpool_node_to_partition): Do not re-add items to partition. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@173517 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cgraphunit.c')
-rw-r--r--gcc/cgraphunit.c122
1 files changed, 84 insertions, 38 deletions
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 2d609290099..68eb91d35e8 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -370,7 +370,8 @@ cgraph_finalize_function (tree decl, bool nested)
to those so we need to analyze them.
FIXME: We should introduce may edges for this purpose and update
their handling in unreachable function removal and inliner too. */
- || (DECL_VIRTUAL_P (decl) && (DECL_COMDAT (decl) || DECL_EXTERNAL (decl))))
+ || (DECL_VIRTUAL_P (decl)
+ && optimize && (DECL_COMDAT (decl) || DECL_EXTERNAL (decl))))
cgraph_mark_reachable_node (node);
/* If we've not yet emitted decl, tell the debug info about it. */
@@ -624,10 +625,28 @@ verify_cgraph_node (struct cgraph_node *node)
while (n != node);
}
- if (node->analyzed && gimple_has_body_p (node->decl)
- && !TREE_ASM_WRITTEN (node->decl)
- && (!DECL_EXTERNAL (node->decl) || node->global.inlined_to)
- && !flag_wpa)
+ if (node->analyzed && node->thunk.thunk_p)
+ {
+ if (!node->callees)
+ {
+ error ("No edge out of thunk node");
+ error_found = true;
+ }
+ else if (node->callees->next_callee)
+ {
+ error ("More than one edge out of thunk node");
+ error_found = true;
+ }
+ if (gimple_has_body_p (node->decl))
+ {
+ error ("Thunk is not supposed to have body");
+ error_found = true;
+ }
+ }
+ else if (node->analyzed && gimple_has_body_p (node->decl)
+ && !TREE_ASM_WRITTEN (node->decl)
+ && (!DECL_EXTERNAL (node->decl) || node->global.inlined_to)
+ && !flag_wpa)
{
if (this_cfun->cfg)
{
@@ -656,8 +675,6 @@ verify_cgraph_node (struct cgraph_node *node)
}
if (!e->indirect_unknown_callee)
{
- struct cgraph_node *n;
-
if (e->callee->same_body_alias)
{
error ("edge points to same body alias:");
@@ -678,16 +695,6 @@ verify_cgraph_node (struct cgraph_node *node)
debug_tree (decl);
error_found = true;
}
- else if (decl
- && (n = cgraph_get_node_or_alias (decl))
- && (n->same_body_alias
- && n->thunk.thunk_p))
- {
- error ("a call to thunk improperly represented "
- "in the call graph:");
- cgraph_debug_gimple_stmt (this_cfun, stmt);
- error_found = true;
- }
}
else if (decl)
{
@@ -780,23 +787,31 @@ cgraph_analyze_function (struct cgraph_node *node)
tree save = current_function_decl;
tree decl = node->decl;
- current_function_decl = decl;
- push_cfun (DECL_STRUCT_FUNCTION (decl));
+ if (node->thunk.thunk_p)
+ {
+ cgraph_create_edge (node, cgraph_get_node (node->thunk.alias),
+ NULL, 0, CGRAPH_FREQ_BASE);
+ }
+ else
+ {
+ current_function_decl = decl;
+ push_cfun (DECL_STRUCT_FUNCTION (decl));
- assign_assembler_name_if_neeeded (node->decl);
+ assign_assembler_name_if_neeeded (node->decl);
- /* Make sure to gimplify bodies only once. During analyzing a
- function we lower it, which will require gimplified nested
- functions, so we can end up here with an already gimplified
- body. */
- if (!gimple_body (decl))
- gimplify_function_tree (decl);
- dump_function (TDI_generic, decl);
+ /* Make sure to gimplify bodies only once. During analyzing a
+ function we lower it, which will require gimplified nested
+ functions, so we can end up here with an already gimplified
+ body. */
+ if (!gimple_body (decl))
+ gimplify_function_tree (decl);
+ dump_function (TDI_generic, decl);
- cgraph_lower_function (node);
+ cgraph_lower_function (node);
+ pop_cfun ();
+ }
node->analyzed = true;
- pop_cfun ();
current_function_decl = save;
}
@@ -969,7 +984,8 @@ cgraph_analyze_functions (void)
/* ??? It is possible to create extern inline function and later using
weak alias attribute to kill its body. See
gcc.c-torture/compile/20011119-1.c */
- if (!DECL_STRUCT_FUNCTION (decl))
+ if (!DECL_STRUCT_FUNCTION (decl)
+ && !node->thunk.thunk_p)
{
cgraph_reset_node (node);
continue;
@@ -981,6 +997,9 @@ cgraph_analyze_functions (void)
for (edge = node->callees; edge; edge = edge->next_callee)
if (!edge->callee->reachable)
cgraph_mark_reachable_node (edge->callee);
+ for (edge = node->callers; edge; edge = edge->next_caller)
+ if (!edge->caller->reachable && edge->caller->thunk.thunk_p)
+ cgraph_mark_reachable_node (edge->caller);
if (node->same_comdat_group)
{
@@ -1031,10 +1050,12 @@ cgraph_analyze_functions (void)
tree decl = node->decl;
next = node->next;
- if (node->local.finalized && !gimple_has_body_p (decl))
+ if (node->local.finalized && !gimple_has_body_p (decl)
+ && !node->thunk.thunk_p)
cgraph_reset_node (node);
- if (!node->reachable && gimple_has_body_p (decl))
+ if (!node->reachable
+ && (gimple_has_body_p (decl) || node->thunk.thunk_p))
{
if (cgraph_dump_file)
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
@@ -1043,7 +1064,8 @@ cgraph_analyze_functions (void)
}
else
node->next_needed = NULL;
- gcc_assert (!node->local.finalized || gimple_has_body_p (decl));
+ gcc_assert (!node->local.finalized || node->thunk.thunk_p
+ || gimple_has_body_p (decl));
gcc_assert (node->analyzed == node->local.finalized);
}
if (cgraph_dump_file)
@@ -1132,6 +1154,7 @@ cgraph_mark_functions_to_output (void)
always inlined, as well as those that are reachable from
outside the current compilation unit. */
if (node->analyzed
+ && !node->thunk.thunk_p
&& !node->global.inlined_to
&& (!cgraph_only_called_directly_p (node)
|| (e && node->reachable))
@@ -1145,7 +1168,8 @@ cgraph_mark_functions_to_output (void)
for (next = node->same_comdat_group;
next != node;
next = next->same_comdat_group)
- next->process = 1;
+ if (!next->thunk.thunk_p)
+ next->process = 1;
}
}
else if (node->same_comdat_group)
@@ -1406,6 +1430,8 @@ assemble_thunk (struct cgraph_node *node)
free_after_compilation (cfun);
set_cfun (NULL);
TREE_ASM_WRITTEN (thunk_fndecl) = 1;
+ node->thunk.thunk_p = false;
+ node->analyzed = false;
}
else
{
@@ -1530,15 +1556,36 @@ assemble_thunk (struct cgraph_node *node)
delete_unreachable_blocks ();
update_ssa (TODO_update_ssa);
- cgraph_remove_same_body_alias (node);
/* Since we want to emit the thunk, we explicitly mark its name as
referenced. */
+ node->thunk.thunk_p = false;
+ cgraph_node_remove_callees (node);
cgraph_add_new_function (thunk_fndecl, true);
bitmap_obstack_release (NULL);
}
current_function_decl = NULL;
}
+
+/* Assemble thunks asociated to NODE. */
+
+static void
+assemble_thunks (struct cgraph_node *node)
+{
+ struct cgraph_edge *e;
+ for (e = node->callers; e;)
+ if (e->caller->thunk.thunk_p)
+ {
+ struct cgraph_node *thunk = e->caller;
+
+ e = e->next_caller;
+ assemble_thunks (thunk);
+ assemble_thunk (thunk);
+ }
+ else
+ e = e->next_caller;
+}
+
/* Expand function specified by NODE. */
static void
@@ -1566,13 +1613,12 @@ cgraph_expand_function (struct cgraph_node *node)
if (!alias->thunk.thunk_p)
assemble_alias (alias->decl,
DECL_ASSEMBLER_NAME (alias->thunk.alias));
- else
- assemble_thunk (alias);
}
node->alias = saved_alias;
cgraph_process_new_functions ();
}
+ assemble_thunks (node);
gcc_assert (node->lowered);
/* Generate RTL for the body of DECL. */
@@ -1688,7 +1734,7 @@ cgraph_output_in_order (void)
for (pf = cgraph_nodes; pf; pf = pf->next)
{
- if (pf->process)
+ if (pf->process && !pf->thunk.thunk_p)
{
i = pf->order;
gcc_assert (nodes[i].kind == ORDER_UNDEFINED);