X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcgraphunit.c;h=b91e218f3a4d636affca436cc1ee7da1ce139a1c;hb=09e23cc32975318caaa78c1c9eebb6d7d68dc329;hp=ec7f9d8fc339b11e2b15923f718b330961c63f36;hpb=55d6cb23109abfa35df107c0ce062004aa27da3b;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index ec7f9d8fc33..b91e218f3a4 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -382,6 +382,7 @@ cgraph_process_new_functions (void) tree fndecl; struct cgraph_node *node; + varpool_analyze_pending_decls (); /* Note that this queue may grow as its being processed, as the new functions may generate new ones. */ while (cgraph_new_nodes) @@ -437,6 +438,7 @@ cgraph_process_new_functions (void) break; } cgraph_call_function_insertion_hooks (node); + varpool_analyze_pending_decls (); } return output; } @@ -607,6 +609,24 @@ verify_cgraph_node (struct cgraph_node *node) error ("Inline clone is needed"); error_found = true; } + for (e = node->indirect_calls; e; e = e->next_callee) + { + if (e->aux) + { + error ("aux field set for indirect edge from %s", + identifier_to_locale (cgraph_node_name (e->caller))); + error_found = true; + } + if (!e->indirect_unknown_callee + || !e->indirect_info) + { + error ("An indirect edge from %s is not marked as indirect or has " + "associated indirect_info, the corresponding statement is: ", + identifier_to_locale (cgraph_node_name (e->caller))); + debug_gimple_stmt (e->call_stmt); + error_found = true; + } + } for (e = node->callers; e; e = e->next_caller) { if (e->count < 0) @@ -714,6 +734,32 @@ verify_cgraph_node (struct cgraph_node *node) error ("double linked list of clones corrupted"); error_found = true; } + if (node->same_comdat_group) + { + struct cgraph_node *n = node->same_comdat_group; + + if (!DECL_ONE_ONLY (node->decl)) + { + error ("non-DECL_ONE_ONLY node in a same_comdat_group list"); + error_found = true; + } + if (n == node) + { + error ("node is alone in a comdat group"); + error_found = true; + } + do + { + if (!n->same_comdat_group) + { + error ("same_comdat_group is not a circular list"); + error_found = true; + break; + } + n = n->same_comdat_group; + } + while (n != node); + } if (node->analyzed && gimple_has_body_p (node->decl) && !TREE_ASM_WRITTEN (node->decl) @@ -733,10 +779,10 @@ verify_cgraph_node (struct cgraph_node *node) gsi_next (&gsi)) { gimple stmt = gsi_stmt (gsi); - tree decl; - if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt))) + if (is_gimple_call (stmt)) { struct cgraph_edge *e = cgraph_edge (node, stmt); + tree decl = gimple_call_fndecl (stmt); if (e) { if (e->aux) @@ -745,24 +791,40 @@ verify_cgraph_node (struct cgraph_node *node) debug_gimple_stmt (stmt); error_found = true; } - if (e->callee->same_body_alias) + if (!e->indirect_unknown_callee) { - error ("edge points to same body alias:"); - debug_tree (e->callee->decl); - error_found = true; + if (e->callee->same_body_alias) + { + error ("edge points to same body alias:"); + debug_tree (e->callee->decl); + error_found = true; + } + else if (!node->global.inlined_to + && !e->callee->global.inlined_to + && decl + && !clone_of_p (cgraph_node (decl), + e->callee)) + { + error ("edge points to wrong declaration:"); + debug_tree (e->callee->decl); + fprintf (stderr," Instead of:"); + debug_tree (decl); + error_found = true; + } } - else if (!clone_of_p (cgraph_node (decl), e->callee) - && !e->callee->global.inlined_to) + else if (!node->global.inlined_to + && !e->callee->global.inlined_to + && !clone_of_p (cgraph_node (decl), e->callee)) { - error ("edge points to wrong declaration:"); - debug_tree (e->callee->decl); - fprintf (stderr," Instead of:"); - debug_tree (decl); + error ("an indirect edge with unknown callee " + "corresponding to a call_stmt with " + "a known declaration:"); error_found = true; + debug_gimple_stmt (e->call_stmt); } e->aux = (void *)1; } - else + else if (decl) { error ("missing callgraph edge for call stmt:"); debug_gimple_stmt (stmt); @@ -778,7 +840,7 @@ verify_cgraph_node (struct cgraph_node *node) for (e = node->callees; e; e = e->next_callee) { - if (!e->aux && !e->indirect_call) + if (!e->aux) { error ("edge %s->%s has no corresponding call_stmt", identifier_to_locale (cgraph_node_name (e->caller)), @@ -788,6 +850,17 @@ verify_cgraph_node (struct cgraph_node *node) } e->aux = 0; } + for (e = node->indirect_calls; e; e = e->next_callee) + { + if (!e->aux) + { + error ("an indirect edge from %s has no corresponding call_stmt", + identifier_to_locale (cgraph_node_name (e->caller))); + debug_gimple_stmt (e->call_stmt); + error_found = true; + } + e->aux = 0; + } } if (error_found) { @@ -836,6 +909,8 @@ cgraph_analyze_function (struct cgraph_node *node) current_function_decl = decl; push_cfun (DECL_STRUCT_FUNCTION (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 @@ -885,12 +960,8 @@ process_function_and_variable_attributes (struct cgraph_node *first, for (node = cgraph_nodes; node != first; node = node->next) { tree decl = node->decl; - if (lookup_attribute ("used", DECL_ATTRIBUTES (decl))) - { - mark_decl_referenced (decl); - if (node->local.finalized) - cgraph_mark_needed_node (node); - } + if (DECL_PRESERVE_P (decl)) + cgraph_mark_needed_node (node); if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (decl))) { if (! TREE_PUBLIC (node->decl)) @@ -904,9 +975,8 @@ process_function_and_variable_attributes (struct cgraph_node *first, for (vnode = varpool_nodes; vnode != first_var; vnode = vnode->next) { tree decl = vnode->decl; - if (lookup_attribute ("used", DECL_ATTRIBUTES (decl))) + if (DECL_PRESERVE_P (decl)) { - mark_decl_referenced (decl); vnode->force_output = true; if (vnode->finalized) varpool_mark_needed_node (vnode); @@ -1127,7 +1197,8 @@ cgraph_mark_functions_to_output (void) outside the current compilation unit. */ if (node->analyzed && !node->global.inlined_to - && (node->needed + && (node->needed || node->reachable_from_other_partition + || node->address_taken || (e && node->reachable)) && !TREE_ASM_WRITTEN (decl) && !DECL_EXTERNAL (decl)) @@ -1154,6 +1225,10 @@ cgraph_mark_functions_to_output (void) #ifdef ENABLE_CHECKING if (!node->global.inlined_to && gimple_has_body_p (decl) + /* FIXME: in ltrans unit when offline copy is outside partition but inline copies + are inside partition, we can end up not removing the body since we no longer + have analyzed node pointing to it. */ + && !node->in_other_partition && !DECL_EXTERNAL (decl)) { dump_cgraph_node (stderr, node); @@ -1162,6 +1237,7 @@ cgraph_mark_functions_to_output (void) #endif gcc_assert (node->global.inlined_to || !gimple_has_body_p (decl) + || node->in_other_partition || DECL_EXTERNAL (decl)); } @@ -1175,6 +1251,10 @@ cgraph_mark_functions_to_output (void) tree decl = node->decl; if (!node->global.inlined_to && gimple_has_body_p (decl) + /* FIXME: in ltrans unit when offline copy is outside partition but inline copies + are inside partition, we can end up not removing the body since we no longer + have analyzed node pointing to it. */ + && !node->in_other_partition && !DECL_EXTERNAL (decl)) { dump_cgraph_node (stderr, node); @@ -1519,7 +1599,6 @@ assemble_thunk (struct cgraph_node *node) cgraph_remove_same_body_alias (node); /* Since we want to emit the thunk, we explicitly mark its name as referenced. */ - mark_decl_referenced (thunk_fndecl); cgraph_add_new_function (thunk_fndecl, true); bitmap_obstack_release (NULL); } @@ -1661,7 +1740,6 @@ static void cgraph_output_in_order (void) { int max; - size_t size; struct cgraph_order_sort *nodes; int i; struct cgraph_node *pf; @@ -1669,9 +1747,7 @@ cgraph_output_in_order (void) struct cgraph_asm_node *pa; max = cgraph_order; - size = max * sizeof (struct cgraph_order_sort); - nodes = (struct cgraph_order_sort *) alloca (size); - memset (nodes, 0, size); + nodes = XCNEWVEC (struct cgraph_order_sort, max); varpool_analyze_pending_decls (); @@ -1738,6 +1814,7 @@ cgraph_output_in_order (void) } cgraph_asm_nodes = NULL; + free (nodes); } /* Return true when function body of DECL still needs to be kept around @@ -1786,11 +1863,19 @@ ipa_passes (void) execute_ipa_summary_passes ((struct ipa_opt_pass_d *) all_regular_ipa_passes); } + + /* Some targets need to handle LTO assembler output specially. */ + if (flag_generate_lto) + targetm.asm_out.lto_start (); + execute_ipa_summary_passes ((struct ipa_opt_pass_d *) all_lto_gen_passes); if (!in_lto_p) ipa_write_summaries (); + if (flag_generate_lto) + targetm.asm_out.lto_end (); + if (!flag_ltrans) execute_ipa_pass_list (all_regular_ipa_passes); invoke_plugin_callbacks (PLUGIN_ALL_IPA_PASSES_END, NULL); @@ -1943,7 +2028,11 @@ cgraph_build_static_cdtor (char which, tree body, int priority) DECL_ARTIFICIAL (decl) = 1; DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1; DECL_SAVED_TREE (decl) = body; - TREE_PUBLIC (decl) = ! targetm.have_ctors_dtors; + if (!targetm.have_ctors_dtors) + { + TREE_PUBLIC (decl) = 1; + DECL_PRESERVE_P (decl) = 1; + } DECL_UNINLINABLE (decl) = 1; DECL_INITIAL (decl) = make_node (BLOCK); @@ -2013,7 +2102,7 @@ cgraph_copy_node_for_versioning (struct cgraph_node *old_version, VEC(cgraph_edge_p,heap) *redirect_callers) { struct cgraph_node *new_version; - struct cgraph_edge *e, *new_e; + struct cgraph_edge *e; struct cgraph_edge *next_callee; unsigned i; @@ -2032,10 +2121,10 @@ cgraph_copy_node_for_versioning (struct cgraph_node *old_version, also cloned. */ for (e = old_version->callees;e; e=e->next_callee) { - new_e = cgraph_clone_edge (e, new_version, e->call_stmt, - e->lto_stmt_uid, 0, e->frequency, - e->loop_nest, true); - new_e->count = e->count; + cgraph_clone_edge (e, new_version, e->call_stmt, + e->lto_stmt_uid, REG_BR_PROB_BASE, + CGRAPH_FREQ_BASE, + e->loop_nest, true); } /* Fix recursive calls. If OLD_VERSION has a recursive call after the @@ -2110,11 +2199,7 @@ cgraph_function_versioning (struct cgraph_node *old_version_node, that is not weak also. ??? We cannot use COMDAT linkage because there is no ABI support for this. */ - DECL_EXTERNAL (new_version_node->decl) = 0; - DECL_COMDAT_GROUP (new_version_node->decl) = NULL_TREE; - TREE_PUBLIC (new_version_node->decl) = 0; - DECL_COMDAT (new_version_node->decl) = 0; - DECL_WEAK (new_version_node->decl) = 0; + cgraph_make_decl_local (new_version_node->decl); DECL_VIRTUAL_P (new_version_node->decl) = 0; new_version_node->local.externally_visible = 0; new_version_node->local.local = 1; @@ -2224,11 +2309,60 @@ cgraph_materialize_clone (struct cgraph_node *node) bitmap_obstack_release (NULL); } +/* If necessary, change the function declaration in the call statement + associated with E so that it corresponds to the edge callee. */ + +gimple +cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e) +{ + tree decl = gimple_call_fndecl (e->call_stmt); + gimple new_stmt; + gimple_stmt_iterator gsi; + + if (!decl || decl == e->callee->decl + /* Don't update call from same body alias to the real function. */ + || cgraph_get_node (decl) == cgraph_get_node (e->callee->decl)) + return e->call_stmt; + + if (cgraph_dump_file) + { + fprintf (cgraph_dump_file, "updating call of %s/%i -> %s/%i: ", + cgraph_node_name (e->caller), e->caller->uid, + cgraph_node_name (e->callee), e->callee->uid); + print_gimple_stmt (cgraph_dump_file, e->call_stmt, 0, dump_flags); + } + + if (e->callee->clone.combined_args_to_skip) + new_stmt = gimple_call_copy_skip_args (e->call_stmt, + e->callee->clone.combined_args_to_skip); + else + new_stmt = e->call_stmt; + if (gimple_vdef (new_stmt) + && TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME) + SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt; + gimple_call_set_fndecl (new_stmt, e->callee->decl); + + gsi = gsi_for_stmt (e->call_stmt); + gsi_replace (&gsi, new_stmt, true); + + /* Update EH information too, just in case. */ + maybe_clean_or_replace_eh_stmt (e->call_stmt, new_stmt); + + cgraph_set_call_stmt_including_clones (e->caller, e->call_stmt, new_stmt); + + if (cgraph_dump_file) + { + fprintf (cgraph_dump_file, " updated to:"); + print_gimple_stmt (cgraph_dump_file, e->call_stmt, 0, dump_flags); + } + return new_stmt; +} + /* Once all functions from compilation unit are in memory, produce all clones - and update all calls. - We might also do this on demand if we don't want to bring all functions to - memory prior compilation, but current WHOPR implementation does that and it is - is bit easier to keep everything right in this order. */ + and update all calls. We might also do this on demand if we don't want to + bring all functions to memory prior compilation, but current WHOPR + implementation does that and it is is bit easier to keep everything right in + this order. */ void cgraph_materialize_all_clones (void) { @@ -2292,9 +2426,8 @@ cgraph_materialize_all_clones (void) } } cgraph_materialize_clone (node); + stabilized = false; } - else - stabilized = false; } } } @@ -2304,69 +2437,28 @@ cgraph_materialize_all_clones (void) if (cgraph_dump_file) fprintf (cgraph_dump_file, "Updating call sites\n"); for (node = cgraph_nodes; node; node = node->next) - if (node->analyzed && gimple_has_body_p (node->decl) - && (!node->clone_of || node->clone_of->decl != node->decl)) + if (node->analyzed && !node->clone_of + && gimple_has_body_p (node->decl)) { struct cgraph_edge *e; current_function_decl = node->decl; push_cfun (DECL_STRUCT_FUNCTION (node->decl)); for (e = node->callees; e; e = e->next_callee) - { - tree decl = gimple_call_fndecl (e->call_stmt); - /* When function gets inlined, indirect inlining might've invented - new edge for orginally indirect stmt. Since we are not - preserving clones in the original form, we must not update here - since other inline clones don't need to contain call to the same - call. Inliner will do the substitution for us later. */ - if (decl && decl != e->callee->decl) - { - gimple new_stmt; - gimple_stmt_iterator gsi; - - if (cgraph_get_node (decl) == cgraph_get_node (e->callee->decl)) - /* Don't update call from same body alias to the real function. */ - continue; - - if (cgraph_dump_file) - { - fprintf (cgraph_dump_file, "updating call of %s in %s:", - cgraph_node_name (node), - cgraph_node_name (e->callee)); - print_gimple_stmt (cgraph_dump_file, e->call_stmt, 0, dump_flags); - } - - if (e->callee->clone.combined_args_to_skip) - new_stmt = gimple_call_copy_skip_args (e->call_stmt, - e->callee->clone.combined_args_to_skip); - else - new_stmt = e->call_stmt; - if (gimple_vdef (new_stmt) - && TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME) - SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt; - gimple_call_set_fndecl (new_stmt, e->callee->decl); - - gsi = gsi_for_stmt (e->call_stmt); - gsi_replace (&gsi, new_stmt, true); - - /* Update EH information too, just in case. */ - maybe_clean_or_replace_eh_stmt (e->call_stmt, new_stmt); - - cgraph_set_call_stmt_including_clones (node, e->call_stmt, new_stmt); - - if (cgraph_dump_file) - { - fprintf (cgraph_dump_file, " updated to:"); - print_gimple_stmt (cgraph_dump_file, e->call_stmt, 0, dump_flags); - } - } - } + cgraph_redirect_edge_call_stmt_to_callee (e); pop_cfun (); current_function_decl = NULL; #ifdef ENABLE_CHECKING verify_cgraph_node (node); #endif } + if (cgraph_dump_file) + fprintf (cgraph_dump_file, "Materialization Call site updates done.\n"); + /* All changes to parameters have been performed. In order not to + incorrectly repeat them, we simply dispose of the bitmaps that drive the + changes. */ + for (node = cgraph_nodes; node; node = node->next) + node->clone.combined_args_to_skip = NULL; #ifdef ENABLE_CHECKING verify_cgraph (); #endif