diff options
author | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-05-06 23:00:49 +0000 |
---|---|---|
committer | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-05-06 23:00:49 +0000 |
commit | 91bf9d9ad6f23ff598b998fb10670fafd837cf77 (patch) | |
tree | 00b435c7373736adc2b2930493aa86fc6e9c0b31 /gcc/cgraphunit.c | |
parent | 84117c98ad16505884af5074b306ea064f05d61e (diff) | |
download | gcc-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.c | 122 |
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); |