From: Jan Hubicka Date: Sat, 11 Jun 2011 13:01:53 +0000 (+0200) Subject: lto-symtab.c (lto_cgraph_replace_node): Kill same body alias code. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=39e2db00dad38d188a235308d53a2963925bdd85;p=gcc.git lto-symtab.c (lto_cgraph_replace_node): Kill same body alias code. * lto-symtab.c (lto_cgraph_replace_node): Kill same body alias code. (lto_symtab_resolve_can_prevail_p): Likewise. (lto_symtab_merge_cgraph_nodes): Update merging of aliases. * cgraph.c (same_body_aliases_done): New global var. (cgraph_same_body_alias_1): Rename to ... (cgraph_create_function_alias): ... this one; reorg to new representation. (cgraph_same_body_alias): Use cgraph_create_function_alias; record references when asked to. (cgraph_add_thunk): Fix formating. (cgraph_get_node): Kill same body alias code. (cgraph_node_for_asm): Likewise. (cgraph_remove_same_body_alias): Remove. (cgraph_remove_node): Kill same body alias code. (cgraph_mark_address_taken_node): Mark also the aliased function as having address taken. (dump_cgraph_node): Dump same body aliases. (cgraph_for_node_thunks_and_aliases): Update for new alias representation. (cgraph_for_node_and_aliases): Likewise. * cgraph.h (same_body): Kll pointer. (same_body_alias): Update comment. (same_body_aliases_done): Declare. (cgraph_remove_same_body_alias): Remove declaration. (cgraph_create_function_alias): Declare. (cgraph_process_same_body_aliases): Declare. (cgraph_function_with_gimple_body_p): Check for alias. (cgraph_can_remove_if_no_direct_calls_p): Look for aliases. (cgraph_alias_aliased_node): New function. (cgraph_function_node): Update for new aliases. (cgraph_function_or_thunk_node): Likewise. * ipa-inline-transform.c (can_remove_node_now_p): Look for aliases. (inline_call): Remove dead aliases. * cgraphunit.c (cgraph_decide_is_function_needed): Disable assembler name hack for same body aliases. (clone_of_p): Look through aliases. (verify_cgraph_node): Verify aliases. (cgraph_analyze_function): Analyze aliases; fixup C++ bugs. (cgraph_process_same_body_aliases): New function. (process_function_and_variable_attributes): Disable weakref warning on alias. (cgraph_analyze_functions): Handle aliases. (cgraph_mark_functions_to_output): Handle aliases same way as thunks. (assemble_thunks): Rename to ... (assemble_thunks_and_aliases): ... this one; handle aliases, too. (cgraph_expand_function): Remove alias output code. (cgraph_output_in_order): Skip aliases. (cgraph_preserve_function_body_p): Aliases don't need preserving. * ipa-ref.c (ipa_ref_use_name): Add alias reference. (ipa_record_reference): Do not assert on alias references. (ipa_ref_has_aliases_p): New function. * ipa-ref.h (enum ipa_ref_use): Add IPA_REF_ALIAS. (ipa_ref_has_aliases_p): Declare. * lto-cgraph.c (lto_output_node): Handle aliases. (input_node): Likewise. * lto-streamer-out.c (lto_output): Skip aliases. (produce_symtab): Kill same_body_alias code. * ipa-utils.c (ipa_reverse_postorder): Add FIXME. (ipa_reverse_postorder): Use cgraph_only_called_directly_or_aliased_p. * ipa-inline.c (update_caller_keys): Walk aliases. (inline_small_functions): Fix thinko in previous patch. * ipa.c (cgraph_externally_visible_p): Do not walk aliases. (function_and_variable_visibility): Do not walk same body aliases. * tree-ssa-structalias.c (associate_varinfo_to_alias): New function. (ipa_pta_execute): Use it. * lto.c (add_cgraph_node_to_partition_1): Break out from ... (add_cgraph_node_to_partition) ... here; walk aliases. (lto_1_to_1_map): Remove same body alias code. (promote_fn): Likewise. (lto_promote_cross_file_statics): Update comment. * decl2.c (cp_write_global_declarations): Process aliases; look trhough same body aliases. From-SVN: r174952 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1a141e3c160..73c5fb46a87 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,71 @@ +2011-06-11 Jan Hubicka + + * lto-symtab.c (lto_cgraph_replace_node): Kill same body alias code. + (lto_symtab_resolve_can_prevail_p): Likewise. + (lto_symtab_merge_cgraph_nodes): Update merging of aliases. + * cgraph.c (same_body_aliases_done): New global var. + (cgraph_same_body_alias_1): Rename to ... + (cgraph_create_function_alias): ... this one; reorg to new + representation. + (cgraph_same_body_alias): Use cgraph_create_function_alias; + record references when asked to. + (cgraph_add_thunk): Fix formating. + (cgraph_get_node): Kill same body alias code. + (cgraph_node_for_asm): Likewise. + (cgraph_remove_same_body_alias): Remove. + (cgraph_remove_node): Kill same body alias code. + (cgraph_mark_address_taken_node): Mark also the aliased function + as having address taken. + (dump_cgraph_node): Dump same body aliases. + (cgraph_for_node_thunks_and_aliases): Update for new alias + representation. + (cgraph_for_node_and_aliases): Likewise. + * cgraph.h (same_body): Kll pointer. + (same_body_alias): Update comment. + (same_body_aliases_done): Declare. + (cgraph_remove_same_body_alias): Remove declaration. + (cgraph_create_function_alias): Declare. + (cgraph_process_same_body_aliases): Declare. + (cgraph_function_with_gimple_body_p): Check for alias. + (cgraph_can_remove_if_no_direct_calls_p): Look for aliases. + (cgraph_alias_aliased_node): New function. + (cgraph_function_node): Update for new aliases. + (cgraph_function_or_thunk_node): Likewise. + * ipa-inline-transform.c (can_remove_node_now_p): Look for aliases. + (inline_call): Remove dead aliases. + * cgraphunit.c (cgraph_decide_is_function_needed): Disable assembler name + hack for same body aliases. + (clone_of_p): Look through aliases. + (verify_cgraph_node): Verify aliases. + (cgraph_analyze_function): Analyze aliases; fixup C++ bugs. + (cgraph_process_same_body_aliases): New function. + (process_function_and_variable_attributes): Disable weakref warning on + alias. + (cgraph_analyze_functions): Handle aliases. + (cgraph_mark_functions_to_output): Handle aliases same way as thunks. + (assemble_thunks): Rename to ... + (assemble_thunks_and_aliases): ... this one; handle aliases, too. + (cgraph_expand_function): Remove alias output code. + (cgraph_output_in_order): Skip aliases. + (cgraph_preserve_function_body_p): Aliases don't need preserving. + * ipa-ref.c (ipa_ref_use_name): Add alias reference. + (ipa_record_reference): Do not assert on alias references. + (ipa_ref_has_aliases_p): New function. + * ipa-ref.h (enum ipa_ref_use): Add IPA_REF_ALIAS. + (ipa_ref_has_aliases_p): Declare. + * lto-cgraph.c (lto_output_node): Handle aliases. + (input_node): Likewise. + * lto-streamer-out.c (lto_output): Skip aliases. + (produce_symtab): Kill same_body_alias code. + * ipa-utils.c (ipa_reverse_postorder): Add FIXME. + (ipa_reverse_postorder): Use cgraph_only_called_directly_or_aliased_p. + * ipa-inline.c (update_caller_keys): Walk aliases. + (inline_small_functions): Fix thinko in previous patch. + * ipa.c (cgraph_externally_visible_p): Do not walk aliases. + (function_and_variable_visibility): Do not walk same body aliases. + * tree-ssa-structalias.c (associate_varinfo_to_alias): New function. + (ipa_pta_execute): Use it. + 2011-06-11 Uros Bizjak * config/i386/sse.md (vec_dupv4sf): Correct mode of forced register. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index f5fd150baac..2805d46dfad 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -208,6 +208,9 @@ static GTY(()) struct cgraph_node *free_nodes; Do not GTY((delete)) this list so UIDs gets reliably recycled. */ static GTY(()) struct cgraph_edge *free_edges; +/* Did procss_same_body_aliases run? */ +bool same_body_aliases_done; + /* Macros to access the next item in the list of free cgraph nodes and edges. */ #define NEXT_FREE_NODE(NODE) (NODE)->next @@ -542,33 +545,23 @@ cgraph_get_create_node (tree decl) /* Mark ALIAS as an alias to DECL. DECL_NODE is cgraph node representing the function body is associated with (not neccesarily cgraph_node (DECL). */ -static struct cgraph_node * -cgraph_same_body_alias_1 (struct cgraph_node *decl_node, tree alias, tree decl) +struct cgraph_node * +cgraph_create_function_alias (tree alias, tree decl) { - struct cgraph_node key, *alias_node, **slot; + struct cgraph_node *alias_node; gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); gcc_assert (TREE_CODE (alias) == FUNCTION_DECL); - - key.decl = alias; - - slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT); - - /* If the cgraph_node has been already created, fail. */ - if (*slot) - return NULL; - - alias_node = cgraph_allocate_node (); - alias_node->decl = alias; - alias_node->same_body_alias = 1; - alias_node->same_body = decl_node; - alias_node->previous = NULL; - if (decl_node->same_body) - decl_node->same_body->previous = alias_node; - alias_node->next = decl_node->same_body; + alias_node = cgraph_get_create_node (alias); + gcc_assert (!alias_node->local.finalized); alias_node->thunk.alias = decl; - decl_node->same_body = alias_node; - *slot = alias_node; + alias_node->local.finalized = true; + alias_node->alias = 1; + + if ((TREE_PUBLIC (alias) && !DECL_COMDAT (alias) && !DECL_EXTERNAL (alias)) + || (DECL_VIRTUAL_P (alias) + && (DECL_COMDAT (alias) || DECL_EXTERNAL (alias)))) + cgraph_mark_reachable_node (alias_node); return alias_node; } @@ -578,16 +571,24 @@ cgraph_same_body_alias_1 (struct cgraph_node *decl_node, tree alias, tree decl) and cgraph_get_node (ALIAS) transparently returns cgraph_get_node (DECL). */ struct cgraph_node * -cgraph_same_body_alias (struct cgraph_node *decl_node, tree alias, tree decl) +cgraph_same_body_alias (struct cgraph_node *decl_node ATTRIBUTE_UNUSED, tree alias, tree decl) { + struct cgraph_node *n; #ifndef ASM_OUTPUT_DEF /* If aliases aren't supported by the assembler, fail. */ return NULL; #endif + /* Langhooks can create same body aliases of symbols not defined. + Those are useless. Drop them on the floor. */ + if (cgraph_global_info_ready) + return NULL; - /*gcc_assert (!assembler_name_hash);*/ - - return cgraph_same_body_alias_1 (decl_node, alias, decl); + n = cgraph_create_function_alias (alias, decl); + n->same_body_alias = true; + if (same_body_aliases_done) + ipa_record_reference (n, NULL, cgraph_get_node (decl), NULL, IPA_REF_ALIAS, + NULL); + return n; } /* Add thunk alias into callgraph. The alias declaration is ALIAS and it @@ -633,6 +634,7 @@ cgraph_add_thunk (struct cgraph_node *decl_node ATTRIBUTE_UNUSED, || (DECL_VIRTUAL_P (decl) && (DECL_COMDAT (decl) || DECL_EXTERNAL (decl)))) cgraph_mark_reachable_node (node); + return node; } @@ -678,11 +680,7 @@ cgraph_get_node (const_tree decl) NO_INSERT); if (slot && *slot) - { - node = *slot; - if (node->same_body_alias) - node = node->same_body; - } + node = *slot; return node; } @@ -745,21 +743,6 @@ cgraph_node_for_asm (tree asmname) so lets hope for the best. */ if (!*slot) *slot = node; - if (node->same_body) - { - struct cgraph_node *alias; - - for (alias = node->same_body; alias; alias = alias->next) - { - hashval_t hash; - name = DECL_ASSEMBLER_NAME (alias->decl); - hash = decl_assembler_name_hash (name); - slot = htab_find_slot_with_hash (assembler_name_hash, name, - hash, INSERT); - if (!*slot) - *slot = alias; - } - } } } @@ -770,8 +753,6 @@ cgraph_node_for_asm (tree asmname) if (slot) { node = (struct cgraph_node *) *slot; - if (node->same_body_alias) - node = node->same_body; return node; } return NULL; @@ -1432,44 +1413,6 @@ cgraph_release_function_body (struct cgraph_node *node) DECL_INITIAL (node->decl) = error_mark_node; } -/* Remove same body alias node. */ - -void -cgraph_remove_same_body_alias (struct cgraph_node *node) -{ - void **slot; - int uid = node->uid; - - gcc_assert (node->same_body_alias); - if (node->previous) - node->previous->next = node->next; - else - node->same_body->same_body = node->next; - if (node->next) - node->next->previous = node->previous; - node->next = NULL; - node->previous = NULL; - slot = htab_find_slot (cgraph_hash, node, NO_INSERT); - if (*slot == node) - htab_clear_slot (cgraph_hash, slot); - if (assembler_name_hash) - { - tree name = DECL_ASSEMBLER_NAME (node->decl); - slot = htab_find_slot_with_hash (assembler_name_hash, name, - decl_assembler_name_hash (name), - NO_INSERT); - if (slot && *slot == node) - htab_clear_slot (assembler_name_hash, slot); - } - - /* Clear out the node to NULL all pointers and add the node to the free - list. */ - memset (node, 0, sizeof(*node)); - node->uid = uid; - NEXT_FREE_NODE (node) = free_nodes; - free_nodes = node; -} - /* Remove the node from cgraph. */ void @@ -1631,9 +1574,6 @@ cgraph_remove_node (struct cgraph_node *node) } } - while (node->same_body) - cgraph_remove_same_body_alias (node->same_body); - if (node->same_comdat_group) { struct cgraph_node *prev; @@ -1747,6 +1687,14 @@ cgraph_mark_address_taken_node (struct cgraph_node *node) { gcc_assert (!node->global.inlined_to); cgraph_mark_reachable_node (node); + /* FIXME: address_taken flag is used both as a shortcut for testing whether + IPA_REF_ADDR reference exists (and thus it should be set on node + representing alias we take address of) and as a test whether address + of the object was taken (and thus it should be set on node alias is + referring to). We should remove the first use and the remove the + following set. */ + node->address_taken = 1; + node = cgraph_function_or_thunk_node (node, NULL); node->address_taken = 1; } @@ -1902,6 +1850,15 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) (int)node->thunk.virtual_value, (int)node->thunk.virtual_offset_p); } + if (node->alias && node->thunk.alias) + { + fprintf (f, " alias of %s", + lang_hooks.decl_printable_name (node->thunk.alias, 2)); + if (DECL_ASSEMBLER_NAME_SET_P (node->thunk.alias)) + fprintf (f, " (asm: %s)", + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->thunk.alias))); + fprintf (f, "\n"); + } fprintf (f, " called by: "); @@ -1952,19 +1909,6 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) if (indirect_calls_count) fprintf (f, " has %i outgoing edges for indirect calls.\n", indirect_calls_count); - - if (node->same_body) - { - struct cgraph_node *n; - fprintf (f, " aliases:"); - for (n = node->same_body; n; n = n->next) - { - fprintf (f, " %s/%i", cgraph_node_name (n), n->uid); - if (DECL_ASSEMBLER_NAME_SET_P (n->decl)) - fprintf (f, " (asm: %s)", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (n->decl))); - } - fprintf (f, "\n"); - } } @@ -2614,18 +2558,24 @@ cgraph_for_node_thunks_and_aliases (struct cgraph_node *node, bool include_overwritable) { struct cgraph_edge *e; - struct cgraph_node *alias; + int i; + struct ipa_ref *ref; if (callback (node, data)) return true; - for (alias = node->same_body; alias; alias = alias->next) - if (callback (alias, data)) - return true; for (e = node->callers; e; e = e->next_caller) if (e->caller->thunk.thunk_p && (include_overwritable - || cgraph_function_body_availability (e->caller) > AVAIL_OVERWRITABLE)) + || cgraph_function_body_availability (e->caller))) cgraph_for_node_thunks_and_aliases (e->caller, callback, data, include_overwritable); + for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) + if (ref->use == IPA_REF_ALIAS) + { + struct cgraph_node *alias = ipa_ref_refering_node (ref); + if (include_overwritable + || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE) + cgraph_for_node_thunks_and_aliases (alias, callback, data, include_overwritable); + } return false; } @@ -2637,15 +2587,21 @@ bool cgraph_for_node_and_aliases (struct cgraph_node *node, bool (*callback) (struct cgraph_node *, void *), void *data, - bool include_overwritable ATTRIBUTE_UNUSED) + bool include_overwritable) { - struct cgraph_node *alias; + int i; + struct ipa_ref *ref; if (callback (node, data)) return true; - for (alias = node->same_body; alias; alias = alias->next) - if (callback (alias, data)) - return true; + for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) + if (ref->use == IPA_REF_ALIAS) + { + struct cgraph_node *alias = ipa_ref_refering_node (ref); + if (include_overwritable + || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE) + cgraph_for_node_and_aliases (alias, callback, data, include_overwritable); + } return false; } diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 055ab4884ef..09d99b1c1f7 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -165,9 +165,6 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node { struct cgraph_node *prev_sibling_clone; struct cgraph_node *clones; struct cgraph_node *clone_of; - /* For normal nodes pointer to the list of alias and thunk nodes, - in alias/thunk nodes pointer to the normal node. */ - struct cgraph_node *same_body; /* Circular list of nodes in the same comdat group if non-NULL. */ struct cgraph_node *same_comdat_group; /* For functions with many calls sites it holds map from call expression @@ -236,8 +233,7 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node { unsigned process : 1; /* Set for aliases once they got through assemble_alias. */ unsigned alias : 1; - /* Set for alias and thunk nodes, same_body points to the node they are alias - of and they are linked through the next/previous pointers. */ + /* Set for aliases created as C++ same body aliases. */ unsigned same_body_alias : 1; /* How commonly executed the node is. Initialized during branch probabilities pass. */ @@ -463,6 +459,7 @@ extern GTY(()) struct cgraph_node *cgraph_new_nodes; extern GTY(()) struct cgraph_asm_node *cgraph_asm_nodes; extern GTY(()) int cgraph_order; +extern bool same_body_aliases_done; /* In cgraph.c */ void dump_cgraph (FILE *); @@ -488,7 +485,6 @@ struct cgraph_node * cgraph_get_create_node (tree); struct cgraph_node * cgraph_same_body_alias (struct cgraph_node *, tree, tree); struct cgraph_node * cgraph_add_thunk (struct cgraph_node *, tree, tree, bool, HOST_WIDE_INT, HOST_WIDE_INT, tree, tree); -void cgraph_remove_same_body_alias (struct cgraph_node *); struct cgraph_node *cgraph_node_for_asm (tree); struct cgraph_edge *cgraph_edge (struct cgraph_node *, gimple); void cgraph_set_call_stmt (struct cgraph_edge *, gimple); @@ -508,6 +504,7 @@ struct cgraph_edge * cgraph_clone_edge (struct cgraph_edge *, struct cgraph_node * cgraph_clone_node (struct cgraph_node *, tree, gcov_type, int, bool, VEC(cgraph_edge_p,heap) *, bool); +struct cgraph_node *cgraph_create_function_alias (tree, tree); void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *); void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *, @@ -577,6 +574,7 @@ void tree_function_versioning (tree, tree, VEC (ipa_replace_map_p,gc)*, bool, bi bitmap, basic_block); void record_references_in_initializer (tree, bool); bool cgraph_process_new_functions (void); +void cgraph_process_same_body_aliases (void); bool cgraph_decide_is_function_needed (struct cgraph_node *, tree); @@ -746,7 +744,7 @@ cgraph_next_defined_function (struct cgraph_node *node) static inline bool cgraph_function_with_gimple_body_p (struct cgraph_node *node) { - return node->analyzed && !node->thunk.thunk_p; + return node->analyzed && !node->thunk.thunk_p && !node->alias; } /* Return first function with body defined. */ @@ -934,7 +932,8 @@ cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node) if (DECL_EXTERNAL (node->decl)) return true; return (!node->address_taken - && cgraph_can_remove_if_no_direct_calls_and_refs_p (node)); + && cgraph_can_remove_if_no_direct_calls_and_refs_p (node) + && !ipa_ref_has_aliases_p (&node->ref_list)); } /* Return true when function NODE can be removed from callgraph @@ -968,6 +967,20 @@ htab_t constant_pool_htab (void); /* FIXME: inappropriate dependency of cgraph on IPA. */ #include "ipa-ref-inline.h" +/* Return node that alias N is aliasing. */ + +static inline struct cgraph_node * +cgraph_alias_aliased_node (struct cgraph_node *n) +{ + struct ipa_ref *ref; + + ipa_ref_list_reference_iterate (&n->ref_list, 0, ref); + gcc_checking_assert (ref->use == IPA_REF_ALIAS); + if (ref->refered_type == IPA_REF_CGRAPH) + return ipa_ref_node (ref); + return NULL; +} + /* Given NODE, walk the alias chain to return the function NODE is alias of. Walk through thunk, too. When AVAILABILITY is non-NULL, get minimal availablity in the chain. */ @@ -979,11 +992,13 @@ cgraph_function_node (struct cgraph_node *node, enum availability *availability) *availability = cgraph_function_body_availability (node); while (node) { - if (node->thunk.thunk_p) + if (node->alias && node->analyzed) + node = cgraph_alias_aliased_node (node); + else if (node->thunk.thunk_p) node = node->callees->callee; else return node; - if (availability) + if (node && availability) { enum availability a; a = cgraph_function_body_availability (node); @@ -991,6 +1006,8 @@ cgraph_function_node (struct cgraph_node *node, enum availability *availability) *availability = a; } } + if (*availability) + *availability = AVAIL_NOT_AVAILABLE; return NULL; } @@ -1003,7 +1020,22 @@ cgraph_function_or_thunk_node (struct cgraph_node *node, enum availability *avai { if (availability) *availability = cgraph_function_body_availability (node); - return node; + while (node) + { + if (node->alias && node->analyzed) + node = cgraph_alias_aliased_node (node); + else + return node; + if (node && availability) + { + enum availability a; + a = cgraph_function_body_availability (node); + if (a < *availability) + *availability = a; + } + } + if (*availability) + *availability = AVAIL_NOT_AVAILABLE; return NULL; } diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index dd247eb231d..b01f22b2b23 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -167,6 +167,7 @@ cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl) the name later after finalizing the function and the fact is noticed in assemble_name then. This is arguably a bug. */ if (DECL_ASSEMBLER_NAME_SET_P (decl) + && (!node->thunk.thunk_p && !node->same_body_alias) && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) return true; @@ -391,6 +392,8 @@ cgraph_mark_if_needed (tree decl) static bool clone_of_p (struct cgraph_node *node, struct cgraph_node *node2) { + node = cgraph_function_or_thunk_node (node, NULL); + node2 = cgraph_function_or_thunk_node (node2, NULL); while (node != node2 && node2) node2 = node2->clone_of; return node2 != NULL; @@ -619,6 +622,36 @@ verify_cgraph_node (struct cgraph_node *node) while (n != node); } + if (node->analyzed && node->alias) + { + bool ref_found = false; + int i; + struct ipa_ref *ref; + + if (node->callees) + { + error ("Alias has call edges"); + error_found = true; + } + for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++) + if (ref->use != IPA_REF_ALIAS) + { + error ("Alias has non-alias refernece"); + error_found = true; + } + else if (ref_found) + { + error ("Alias has more than one alias reference"); + error_found = true; + } + else + ref_found = true; + if (!ref_found) + { + error ("Analyzed alias has no reference"); + error_found = true; + } + } if (node->analyzed && node->thunk.thunk_p) { if (!node->callees) @@ -669,19 +702,17 @@ verify_cgraph_node (struct cgraph_node *node) } if (!e->indirect_unknown_callee) { - if (e->callee->same_body_alias) - { - error ("edge points to same body alias:"); - debug_tree (e->callee->decl); - error_found = true; - } - else if (!e->callee->global.inlined_to - && decl - && cgraph_get_node (decl) - && (e->callee->former_clone_of - != cgraph_get_node (decl)->decl) - && !clone_of_p (cgraph_get_node (decl), - e->callee)) + if (!e->callee->global.inlined_to + && decl + && cgraph_get_node (decl) + && (e->callee->former_clone_of + != cgraph_get_node (decl)->decl) + /* IPA-CP sometimes redirect edge to clone and then back to the former + function. This ping-pong has to go, eventaully. */ + && (cgraph_function_or_thunk_node (cgraph_get_node (decl), NULL) + != cgraph_function_or_thunk_node (e->callee, NULL)) + && !clone_of_p (cgraph_get_node (decl), + e->callee)) { error ("edge points to wrong declaration:"); debug_tree (e->callee->decl); @@ -781,7 +812,53 @@ cgraph_analyze_function (struct cgraph_node *node) tree save = current_function_decl; tree decl = node->decl; - if (node->thunk.thunk_p) + if (node->alias && node->thunk.alias) + { + struct cgraph_node *tgt = cgraph_get_node (node->thunk.alias); + if (!VEC_length (ipa_ref_t, node->ref_list.references)) + ipa_record_reference (node, NULL, tgt, NULL, IPA_REF_ALIAS, NULL); + if (node->same_body_alias) + { + DECL_VIRTUAL_P (node->decl) = DECL_VIRTUAL_P (node->thunk.alias); + DECL_DECLARED_INLINE_P (node->decl) + = DECL_DECLARED_INLINE_P (node->thunk.alias); + DECL_DISREGARD_INLINE_LIMITS (node->decl) + = DECL_DISREGARD_INLINE_LIMITS (node->thunk.alias); + } + + /* Fixup visibility nonsences C++ frontend produce on same body aliases. */ + if (TREE_PUBLIC (node->decl) && node->same_body_alias) + { + DECL_EXTERNAL (node->decl) = DECL_EXTERNAL (node->thunk.alias); + if (DECL_COMDAT (node->thunk.alias)) + { + DECL_COMDAT (node->decl) = 1; + DECL_COMDAT_GROUP (node->decl) = DECL_COMDAT_GROUP (node->thunk.alias); + if (DECL_ONE_ONLY (node->thunk.alias) && !node->same_comdat_group) + { + struct cgraph_node *tgt = cgraph_get_node (node->thunk.alias); + node->same_comdat_group = tgt; + if (!tgt->same_comdat_group) + tgt->same_comdat_group = node; + else + { + struct cgraph_node *n; + for (n = tgt->same_comdat_group; + n->same_comdat_group != tgt; + n = n->same_comdat_group) + ; + n->same_comdat_group = node; + } + } + } + } + cgraph_mark_reachable_node (cgraph_alias_aliased_node (node)); + if (node->address_taken) + cgraph_mark_address_taken_node (cgraph_alias_aliased_node (node)); + if (cgraph_decide_is_function_needed (node, node->decl)) + cgraph_mark_needed_node (node); + } + else if (node->thunk.thunk_p) { cgraph_create_edge (node, cgraph_get_node (node->thunk.alias), NULL, 0, CGRAPH_FREQ_BASE); @@ -809,6 +886,26 @@ cgraph_analyze_function (struct cgraph_node *node) current_function_decl = save; } +/* C++ frontend produce same body aliases all over the place, even before PCH + gets streamed out. It relies on us linking the aliases with their function + in order to do the fixups, but ipa-ref is not PCH safe. Consequentely we + first produce aliases without links, but once C++ FE is sure he won't sream + PCH we build the links via this function. */ + +void +cgraph_process_same_body_aliases (void) +{ + struct cgraph_node *node; + for (node = cgraph_nodes; node; node = node->next) + if (node->same_body_alias + && !VEC_length (ipa_ref_t, node->ref_list.references)) + { + struct cgraph_node *tgt = cgraph_get_node (node->thunk.alias); + ipa_record_reference (node, NULL, tgt, NULL, IPA_REF_ALIAS, NULL); + } + same_body_aliases_done = true; +} + /* Process attributes common for vars and functions. */ static void @@ -880,7 +977,7 @@ process_function_and_variable_attributes (struct cgraph_node *first, cgraph_mark_needed_node (node); } if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)) - && node->local.finalized) + && (node->local.finalized && !node->alias)) { warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wattributes, "% attribute ignored" @@ -979,6 +1076,7 @@ cgraph_analyze_functions (void) weak alias attribute to kill its body. See gcc.c-torture/compile/20011119-1.c */ if (!DECL_STRUCT_FUNCTION (decl) + && (!node->alias || !node->thunk.alias) && !node->thunk.thunk_p) { cgraph_reset_node (node); @@ -1046,11 +1144,13 @@ cgraph_analyze_functions (void) next = node->next; if (node->local.finalized && !gimple_has_body_p (decl) + && (!node->alias || !node->thunk.alias) && !node->thunk.thunk_p) cgraph_reset_node (node); if (!node->reachable - && (gimple_has_body_p (decl) || node->thunk.thunk_p)) + && (gimple_has_body_p (decl) || node->thunk.thunk_p + || (node->alias && node->thunk.alias))) { if (cgraph_dump_file) fprintf (cgraph_dump_file, " %s", cgraph_node_name (node)); @@ -1060,6 +1160,7 @@ cgraph_analyze_functions (void) else node->next_needed = NULL; gcc_assert (!node->local.finalized || node->thunk.thunk_p + || node->alias || gimple_has_body_p (decl)); gcc_assert (node->analyzed == node->local.finalized); } @@ -1157,9 +1258,11 @@ cgraph_mark_functions_to_output (void) outside the current compilation unit. */ if (node->analyzed && !node->thunk.thunk_p + && !node->alias && !node->global.inlined_to && (!cgraph_only_called_directly_p (node) - || (e && node->reachable)) + || ((e || ipa_ref_has_aliases_p (&node->ref_list)) + && node->reachable)) && !TREE_ASM_WRITTEN (decl) && !DECL_EXTERNAL (decl)) { @@ -1170,7 +1273,7 @@ cgraph_mark_functions_to_output (void) for (next = node->same_comdat_group; next != node; next = next->same_comdat_group) - if (!next->thunk.thunk_p) + if (!next->thunk.thunk_p && !next->alias) next->process = 1; } } @@ -1190,6 +1293,7 @@ cgraph_mark_functions_to_output (void) 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 + && !node->alias && !DECL_EXTERNAL (decl)) { dump_cgraph_node (stderr, node); @@ -1219,7 +1323,7 @@ cgraph_mark_functions_to_output (void) && !DECL_EXTERNAL (decl)) { dump_cgraph_node (stderr, node); - internal_error ("failed to reclaim unneeded function"); + internal_error ("failed to reclaim unneeded functionin same comdat group"); } } #endif @@ -1569,23 +1673,35 @@ assemble_thunk (struct cgraph_node *node) } -/* Assemble thunks asociated to NODE. */ + +/* Assemble thunks and aliases asociated to NODE. */ static void -assemble_thunks (struct cgraph_node *node) +assemble_thunks_and_aliases (struct cgraph_node *node) { struct cgraph_edge *e; + int i; + struct ipa_ref *ref; + 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_thunks_and_aliases (thunk); assemble_thunk (thunk); } else e = e->next_caller; + for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) + if (ref->use == IPA_REF_ALIAS) + { + struct cgraph_node *alias = ipa_ref_refering_node (ref); + assemble_alias (alias->decl, + DECL_ASSEMBLER_NAME (alias->thunk.alias)); + assemble_thunks_and_aliases (alias); + } } /* Expand function specified by NODE. */ @@ -1600,27 +1716,7 @@ cgraph_expand_function (struct cgraph_node *node) announce_function (decl); node->process = 0; - if (node->same_body) - { - struct cgraph_node *alias, *next; - bool saved_alias = node->alias; - for (alias = node->same_body; - alias && alias->next; alias = alias->next) - ; - /* Walk aliases in the order they were created; it is possible that - thunks refers to the aliases made earlier. */ - for (; alias; alias = next) - { - next = alias->previous; - if (!alias->thunk.thunk_p) - assemble_alias (alias->decl, - DECL_ASSEMBLER_NAME (alias->thunk.alias)); - } - node->alias = saved_alias; - cgraph_process_new_functions (); - } - - assemble_thunks (node); + assemble_thunks_and_aliases (node); gcc_assert (node->lowered); /* Generate RTL for the body of DECL. */ @@ -1736,7 +1832,7 @@ cgraph_output_in_order (void) for (pf = cgraph_nodes; pf; pf = pf->next) { - if (pf->process && !pf->thunk.thunk_p) + if (pf->process && !pf->thunk.thunk_p && !pf->alias) { i = pf->order; gcc_assert (nodes[i].kind == ORDER_UNDEFINED); @@ -1810,7 +1906,7 @@ bool cgraph_preserve_function_body_p (struct cgraph_node *node) { gcc_assert (cgraph_global_info_ready); - gcc_assert (!node->same_body_alias); + gcc_assert (!node->alias && !node->thunk.thunk_p); /* Look if there is any clone around. */ if (node->clones) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9f429b51c58..d214ea2f6de 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2011-06-11 Jan Hubicka + + * decl2.c (cp_write_global_declarations): Process aliases; look trhough + same body aliases. + 2011-06-10 Paolo Carlini PR c++/41769 diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 82d0b11e040..d2f075dab0a 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -3672,6 +3672,8 @@ cp_write_global_declarations (void) if (pch_file) c_common_write_pch (); + cgraph_process_same_body_aliases (); + /* Handle -fdump-ada-spec[-slim] */ if (dump_enabled_p (TDI_ada)) { @@ -3869,6 +3871,8 @@ cp_write_global_declarations (void) struct cgraph_node *node, *next; node = cgraph_get_node (decl); + if (node->same_body_alias) + node = cgraph_alias_aliased_node (node); cgraph_for_node_and_aliases (node, clear_decl_external, NULL, true); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 5b988e9e0a1..c1824b4626b 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3363,9 +3363,8 @@ cp_fix_function_decl_p (tree decl) /* Don't fix same_body aliases. Although they don't have their own CFG, they share it with what they alias to. */ - if (!node - || node->decl == decl - || !node->same_body) + if (!node || !node->alias + || !VEC_length (ipa_ref_t, node->ref_list.references)) return true; } diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c index c5f32a34b76..b62e50b93f0 100644 --- a/gcc/ipa-inline-transform.c +++ b/gcc/ipa-inline-transform.c @@ -88,6 +88,7 @@ can_remove_node_now_p (struct cgraph_node *node) can remove its offline copy, but we would need to keep unanalyzed node in the callgraph so references can point to it. */ return (!node->address_taken + && !ipa_ref_has_aliases_p (&node->ref_list) && cgraph_can_remove_if_no_direct_calls_p (node) /* Inlining might enable more devirtualizing, so we want to remove those only after all devirtualizable virtual calls are processed. @@ -192,7 +193,22 @@ inline_call (struct cgraph_edge *e, bool update_original, /* If aliases are involved, redirect edge to the actual destination and possibly remove the aliases. */ if (e->callee != callee) - cgraph_redirect_edge_callee (e, callee); + { + struct cgraph_node *alias = e->callee, *next_alias; + cgraph_redirect_edge_callee (e, callee); + while (alias && alias != callee) + { + if (!alias->callers + && can_remove_node_now_p (alias)) + { + next_alias = cgraph_alias_aliased_node (alias); + cgraph_remove_node (alias); + alias = next_alias; + } + else + break; + } + } clone_inlined_nodes (e, true, update_original, overall_size); diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index 6733e9ae356..4283770a1c3 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -965,6 +965,8 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node, struct cgraph_edge *check_inlinablity_for) { struct cgraph_edge *edge; + int i; + struct ipa_ref *ref; if (!inline_summary (node)->inlinable || cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE @@ -973,6 +975,13 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node, if (!bitmap_set_bit (updated_nodes, node->uid)) return; + for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) + if (ref->use == IPA_REF_ALIAS) + { + struct cgraph_node *alias = ipa_ref_refering_node (ref); + update_caller_keys (heap, alias, updated_nodes, check_inlinablity_for); + } + for (edge = node->callers; edge; edge = edge->next_caller) if (edge->inline_failed) { @@ -1451,7 +1460,7 @@ inline_small_functions (void) where = edge->caller; while (where->global.inlined_to) { - if (where->decl == edge->callee->decl) + if (where->decl == callee->decl) outer_node = where, depth++; where = where->callers->caller; } diff --git a/gcc/ipa-ref.c b/gcc/ipa-ref.c index db70e6e96af..f5fd03f67fb 100644 --- a/gcc/ipa-ref.c +++ b/gcc/ipa-ref.c @@ -27,7 +27,7 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "cgraph.h" -static const char *ipa_ref_use_name[] = {"read","write","addr"}; +static const char *ipa_ref_use_name[] = {"read","write","addr","alias"}; /* Return ipa reference from REFERING_NODE or REFERING_VARPOOL_NODE to REFERED_NODE or REFERED_VARPOOL_NODE. USE_TYPE specify type @@ -46,6 +46,7 @@ ipa_record_reference (struct cgraph_node *refering_node, gcc_assert ((!refering_node) ^ (!refering_varpool_node)); gcc_assert ((!refered_node) ^ (!refered_varpool_node)); gcc_assert (!stmt || refering_node); + gcc_assert (use_type != IPA_REF_ALIAS || !stmt); list = (refering_node ? &refering_node->ref_list : &refering_varpool_node->ref_list); @@ -73,7 +74,7 @@ ipa_record_reference (struct cgraph_node *refering_node, { ref->refered.cgraph_node = refered_node; ref->refered_type = IPA_REF_CGRAPH; - gcc_assert (use_type == IPA_REF_ADDR); + gcc_assert (use_type == IPA_REF_ADDR || use_type == IPA_REF_ALIAS); } else { @@ -241,3 +242,15 @@ ipa_ref_cannot_lead_to_return (struct ipa_ref *ref) { return cgraph_node_cannot_return (ipa_ref_refering_node (ref)); } + +/* Return true if list contains an alias. */ +bool +ipa_ref_has_aliases_p (struct ipa_ref_list *ref_list) +{ + struct ipa_ref *ref; + int i; + for (i = 0; ipa_ref_list_refering_iterate (ref_list, i, ref); i++) + if (ref->use == IPA_REF_ALIAS) + return true; + return false; +} diff --git a/gcc/ipa-ref.h b/gcc/ipa-ref.h index 2be73536f8e..2fdb6ba4158 100644 --- a/gcc/ipa-ref.h +++ b/gcc/ipa-ref.h @@ -27,7 +27,8 @@ enum GTY(()) ipa_ref_use { IPA_REF_LOAD, IPA_REF_STORE, - IPA_REF_ADDR + IPA_REF_ADDR, + IPA_REF_ALIAS }; /* Type of refering or refered type. */ @@ -89,4 +90,4 @@ void ipa_dump_refering (FILE *, struct ipa_ref_list *); void ipa_clone_references (struct cgraph_node *, struct varpool_node *, struct ipa_ref_list *); void ipa_clone_refering (struct cgraph_node *, struct varpool_node *, struct ipa_ref_list *); bool ipa_ref_cannot_lead_to_return (struct ipa_ref *); - +bool ipa_ref_has_aliases_p (struct ipa_ref_list *); diff --git a/gcc/ipa-utils.c b/gcc/ipa-utils.c index ae207369d18..9abc82dbbd9 100644 --- a/gcc/ipa-utils.c +++ b/gcc/ipa-utils.c @@ -234,7 +234,8 @@ ipa_free_postorder_info (void) } /* Fill array order with all nodes with output flag set in the reverse - topological order. Return the number of elements in the array. */ + topological order. Return the number of elements in the array. + FIXME: While walking, consider aliases, too. */ int ipa_reverse_postorder (struct cgraph_node **order) @@ -260,7 +261,7 @@ ipa_reverse_postorder (struct cgraph_node **order) && (pass || (!node->address_taken && !node->global.inlined_to - && !cgraph_only_called_directly_p (node)))) + && !cgraph_only_called_directly_or_aliased_p (node)))) { node2 = node; if (!node->callers) diff --git a/gcc/ipa.c b/gcc/ipa.c index 7822cfde371..a80f9ba2ba4 100644 --- a/gcc/ipa.c +++ b/gcc/ipa.c @@ -581,9 +581,9 @@ cgraph_comdat_can_be_unshared_p (struct cgraph_node *node) /* Return true when function NODE should be considered externally visible. */ static bool -cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool aliased) +cgraph_externally_visible_p (struct cgraph_node *node, + bool whole_program, bool aliased) { - struct cgraph_node *alias; if (!node->local.finalized) return false; if (!DECL_COMDAT (node->decl) @@ -630,18 +630,6 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool && cgraph_comdat_can_be_unshared_p (node)) return false; - /* See if we have linker information about symbol not being used or - if we need to make guess based on the declaration. - - Even if the linker clams the symbol is unused, never bring internal - symbols that are declared by user as used or externally visible. - This is needed for i.e. references from asm statements. */ - for (alias = node->same_body; alias; alias = alias->next) - if (alias->resolution != LDPR_PREVAILING_DEF_IRONLY) - break; - if (!alias && node->resolution == LDPR_PREVAILING_DEF_IRONLY) - return false; - /* When doing link time optimizations, hidden symbols become local. */ if (in_lto_p && (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN @@ -881,12 +869,9 @@ function_and_variable_visibility (bool whole_program) if (!node->local.externally_visible && node->analyzed && !DECL_EXTERNAL (node->decl)) { - struct cgraph_node *alias; gcc_assert (whole_program || in_lto_p || !TREE_PUBLIC (node->decl)); cgraph_make_decl_local (node->decl); node->resolution = LDPR_PREVAILING_DEF_IRONLY; - for (alias = node->same_body; alias; alias = alias->next) - cgraph_make_decl_local (alias->decl); if (node->same_comdat_group) /* cgraph_externally_visible_p has already checked all other nodes in the group and they will all be made local. We need to @@ -900,8 +885,7 @@ function_and_variable_visibility (bool whole_program) { struct cgraph_node *decl_node = node; - while (decl_node->thunk.thunk_p) - decl_node = decl_node->callees->callee; + decl_node = cgraph_function_node (decl_node->callees->callee, NULL); /* Thunks have the same visibility as function they are attached to. For some reason C++ frontend don't seem to care. I.e. in @@ -933,9 +917,9 @@ function_and_variable_visibility (bool whole_program) if (DECL_EXTERNAL (decl_node->decl)) DECL_EXTERNAL (node->decl) = 1; } - node->local.local = cgraph_local_node_p (node); - } + for (node = cgraph_nodes; node; node = node->next) + node->local.local = cgraph_local_node_p (node); for (vnode = varpool_nodes; vnode; vnode = vnode->next) { /* weak flag makes no sense on local variables. */ diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index 3b1115b53f6..169de382dbe 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -504,7 +504,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, || referenced_from_other_partition_p (&node->ref_list, set, vset)), 1); bp_pack_value (&bp, node->lowered, 1); bp_pack_value (&bp, in_other_partition, 1); - bp_pack_value (&bp, node->alias, 1); + bp_pack_value (&bp, node->alias && !boundary_p, 1); bp_pack_value (&bp, node->frequency, 2); bp_pack_value (&bp, node->only_called_at_startup, 1); bp_pack_value (&bp, node->only_called_at_exit, 1); @@ -523,32 +523,15 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, node->thunk.fixed_offset); lto_output_uleb128_stream (ob->main_stream, node->thunk.virtual_value); - lto_output_fn_decl_index (ob->decl_state, ob->main_stream, - node->thunk.alias); } - - if (node->same_body) + if ((node->alias || node->thunk.thunk_p) && !boundary_p) { - struct cgraph_node *alias; - unsigned long alias_count = 1; - for (alias = node->same_body; alias->next; alias = alias->next) - alias_count++; - lto_output_uleb128_stream (ob->main_stream, alias_count); - do - { - lto_output_fn_decl_index (ob->decl_state, ob->main_stream, - alias->decl); - lto_output_fn_decl_index (ob->decl_state, ob->main_stream, - alias->thunk.alias); - gcc_assert (cgraph_get_node (alias->thunk.alias) == node); - lto_output_enum (ob->main_stream, ld_plugin_symbol_resolution, - LDPR_NUM_KNOWN, alias->resolution); - alias = alias->previous; - } - while (alias); + lto_output_int_in_range (ob->main_stream, 0, 1, + node->thunk.alias != NULL); + if (node->thunk.alias != NULL) + lto_output_fn_decl_index (ob->decl_state, ob->main_stream, + node->thunk.alias); } - else - lto_output_uleb128_stream (ob->main_stream, 0); } /* Output the varpool NODE to OB. @@ -997,7 +980,6 @@ input_node (struct lto_file_decl_data *file_data, struct bitpack_d bp; unsigned decl_index; int ref = LCC_NOT_FOUND, ref2 = LCC_NOT_FOUND; - unsigned long same_body_count = 0; int clone_ref; clone_ref = lto_input_sleb128 (ib); @@ -1043,31 +1025,20 @@ input_node (struct lto_file_decl_data *file_data, int type = lto_input_uleb128 (ib); HOST_WIDE_INT fixed_offset = lto_input_uleb128 (ib); HOST_WIDE_INT virtual_value = lto_input_uleb128 (ib); - tree real_alias; - decl_index = lto_input_uleb128 (ib); - real_alias = lto_file_decl_data_get_fn_decl (file_data, decl_index); node->thunk.fixed_offset = fixed_offset; node->thunk.this_adjusting = (type & 2); node->thunk.virtual_value = virtual_value; node->thunk.virtual_offset_p = (type & 4); - node->thunk.alias = real_alias; } - - same_body_count = lto_input_uleb128 (ib); - while (same_body_count-- > 0) + if (node->thunk.thunk_p || node->alias) { - tree alias_decl, real_alias; - struct cgraph_node *alias; - - decl_index = lto_input_uleb128 (ib); - alias_decl = lto_file_decl_data_get_fn_decl (file_data, decl_index); - decl_index = lto_input_uleb128 (ib); - real_alias = lto_file_decl_data_get_fn_decl (file_data, decl_index); - alias = cgraph_same_body_alias (node, alias_decl, real_alias); - gcc_assert (alias); - alias->resolution = lto_input_enum (ib, ld_plugin_symbol_resolution, - LDPR_NUM_KNOWN); + if (lto_input_int_in_range (ib, "alias nonzero flag", 0, 1)) + { + decl_index = lto_input_uleb128 (ib); + node->thunk.alias = lto_file_decl_data_get_fn_decl (file_data, + decl_index); + } } return node; } diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c index 02ac9583ace..7a2f3f02361 100644 --- a/gcc/lto-streamer-out.c +++ b/gcc/lto-streamer-out.c @@ -2253,6 +2253,7 @@ lto_output (cgraph_node_set set, varpool_node_set vset) { node = lto_cgraph_encoder_deref (encoder, i); if (lto_cgraph_encoder_encode_body_p (encoder, node) + && !node->alias && !node->thunk.thunk_p) { #ifdef ENABLE_CHECKING @@ -2551,7 +2552,7 @@ produce_symtab (struct output_block *ob, struct lto_streamer_cache_d *cache = ob->writer_cache; char *section_name = lto_get_section_name (LTO_section_symtab, NULL, NULL); struct pointer_set_t *seen; - struct cgraph_node *node, *alias; + struct cgraph_node *node; struct varpool_node *vnode, *valias; struct lto_output_stream stream; lto_varpool_encoder_t varpool_encoder = ob->decl_state->varpool_node_encoder; @@ -2584,8 +2585,6 @@ produce_symtab (struct output_block *ob, if (node->alias || node->global.inlined_to) continue; write_symbol (cache, &stream, node->decl, seen, false); - for (alias = node->same_body; alias; alias = alias->next) - write_symbol (cache, &stream, alias->decl, seen, true); } for (i = 0; i < lto_cgraph_encoder_size (encoder); i++) { @@ -2598,8 +2597,6 @@ produce_symtab (struct output_block *ob, if (node->alias || node->global.inlined_to) continue; write_symbol (cache, &stream, node->decl, seen, false); - for (alias = node->same_body; alias; alias = alias->next) - write_symbol (cache, &stream, alias->decl, seen, true); } /* Write all variables. */ diff --git a/gcc/lto-symtab.c b/gcc/lto-symtab.c index af8106de94f..d58da8df2db 100644 --- a/gcc/lto-symtab.c +++ b/gcc/lto-symtab.c @@ -209,7 +209,6 @@ lto_cgraph_replace_node (struct cgraph_node *node, struct cgraph_node *prevailing_node) { struct cgraph_edge *e, *next; - bool no_aliases_please = false; bool compatible_p; if (cgraph_dump_file) @@ -223,13 +222,6 @@ lto_cgraph_replace_node (struct cgraph_node *node, (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl))))); } - if (prevailing_node->same_body_alias) - { - if (prevailing_node->thunk.thunk_p) - no_aliases_please = true; - prevailing_node = prevailing_node->same_body; - } - /* Merge node flags. */ if (node->needed) cgraph_mark_needed_node (prevailing_node); @@ -259,36 +251,8 @@ lto_cgraph_replace_node (struct cgraph_node *node, /* Redirect incomming references. */ ipa_clone_refering (prevailing_node, NULL, &node->ref_list); - /* If we have aliases, redirect them to the prevailing node. */ - if (!node->same_body_alias && node->same_body) - { - struct cgraph_node *alias, *last; - /* We prevail aliases/tunks by a thunk. This is doable but - would need thunk combination. Hopefully no ABI changes will - every be crazy enough. */ - gcc_assert (!no_aliases_please); - - for (alias = node->same_body; alias; alias = alias->next) - { - last = alias; - gcc_assert (alias->same_body_alias); - alias->same_body = prevailing_node; - } - last->next = prevailing_node->same_body; - /* Node with aliases is prevailed by alias. - We could handle this, but combining thunks together will be tricky. - Hopefully this does not happen. */ - if (prevailing_node->same_body) - prevailing_node->same_body->previous = last; - prevailing_node->same_body = node->same_body; - node->same_body = NULL; - } - /* Finally remove the replaced node. */ - if (node->same_body_alias) - cgraph_remove_same_body_alias (node); - else - cgraph_remove_node (node); + cgraph_remove_node (node); } /* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging @@ -472,9 +436,7 @@ lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e) /* For functions we need a non-discarded body. */ if (TREE_CODE (e->decl) == FUNCTION_DECL) - return (e->node - && (e->node->analyzed - || (e->node->same_body_alias && e->node->same_body->analyzed))); + return (e->node && e->node->analyzed); /* A variable should have a size. */ else if (TREE_CODE (e->decl) == VAR_DECL) @@ -816,20 +778,14 @@ lto_symtab_merge_cgraph_nodes_1 (void **slot, void *data ATTRIBUTE_UNUSED) void lto_symtab_merge_cgraph_nodes (void) { - struct cgraph_node *node, *alias, *next; + struct cgraph_node *node; lto_symtab_maybe_init_hash_table (); htab_traverse (lto_symtab_identifiers, lto_symtab_merge_cgraph_nodes_1, NULL); for (node = cgraph_nodes; node; node = node->next) - { - if (node->thunk.thunk_p) - node->thunk.alias = lto_symtab_prevailing_decl (node->thunk.alias); - for (alias = node->same_body; alias; alias = next) - { - next = alias->next; - alias->thunk.alias = lto_symtab_prevailing_decl (alias->thunk.alias); - } - } + if ((node->thunk.thunk_p || node->alias) + && node->thunk.alias) + node->thunk.alias = lto_symtab_prevailing_decl (node->thunk.alias); } /* Given the decl DECL, return the prevailing decl with the same name. */ diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index 44265df529f..9956d791ce3 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,12 @@ +2011-06-11 Jan Hubicka + + * lto.c (add_cgraph_node_to_partition_1): Break out from ... + (add_cgraph_node_to_partition) ... here; walk aliases. + (lto_1_to_1_map): Remove same body alias code. + (promote_fn): Likewise. + (lto_promote_cross_file_statics): Update comment. + + 2011-06-07 Diego Novillo * lto.c (uniquify_nodes): Move code to register decls to diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c index 6e49ee77b59..f13ee0e03f2 100644 --- a/gcc/lto/lto.c +++ b/gcc/lto/lto.c @@ -1319,7 +1319,7 @@ add_references_to_partition (ltrans_partition part, struct ipa_ref_list *refs) for (i = 0; ipa_ref_list_reference_iterate (refs, i, ref); i++) { if (ref->refered_type == IPA_REF_CGRAPH - && DECL_COMDAT (ipa_ref_node (ref)->decl) + && DECL_COMDAT (cgraph_function_node (ipa_ref_node (ref), NULL)->decl) && !cgraph_node_in_set_p (ipa_ref_node (ref), part->cgraph_set)) add_cgraph_node_to_partition (part, ipa_ref_node (ref)); else @@ -1330,6 +1330,34 @@ add_references_to_partition (ltrans_partition part, struct ipa_ref_list *refs) } } +/* Worker for add_cgraph_node_to_partition. */ + +static bool +add_cgraph_node_to_partition_1 (struct cgraph_node *node, void *data) +{ + ltrans_partition part = (ltrans_partition) data; + + /* non-COMDAT aliases of COMDAT functions needs to be output just once. */ + if (!DECL_COMDAT (node->decl) + && !node->global.inlined_to + && node->aux) + { + gcc_assert (node->thunk.thunk_p || node->alias); + return false; + } + + if (node->aux) + { + node->in_other_partition = 1; + if (cgraph_dump_file) + fprintf (cgraph_dump_file, "Node %s/%i now used in multiple partitions\n", + cgraph_node_name (node), node->uid); + } + node->aux = (void *)((size_t)node->aux + 1); + cgraph_node_set_add (part->cgraph_set, node); + return false; +} + /* Add NODE to partition as well as the inline callees and referred comdats into partition PART. */ static void @@ -1337,42 +1365,34 @@ add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node) { struct cgraph_edge *e; cgraph_node_set_iterator csi; + struct cgraph_node *n; + + /* We always decide on functions, not associated thunks and aliases. */ + node = cgraph_function_node (node, NULL); /* If NODE is already there, we have nothing to do. */ csi = cgraph_node_set_find (part->cgraph_set, node); if (!csi_end_p (csi)) return; + cgraph_for_node_thunks_and_aliases (node, add_cgraph_node_to_partition_1, part, true); + part->insns += inline_summary (node)->self_size; - if (node->aux) - { - node->in_other_partition = 1; - if (cgraph_dump_file) - fprintf (cgraph_dump_file, "Node %s/%i now used in multiple partitions\n", - cgraph_node_name (node), node->uid); - } - node->aux = (void *)((size_t)node->aux + 1); cgraph_node_set_add (part->cgraph_set, node); - /* Thunks always must go along with function they reffer to. */ - if (node->thunk.thunk_p) - add_cgraph_node_to_partition (part, node->callees->callee); - for (e = node->callers; e; e = e->next_caller) - if (e->caller->thunk.thunk_p) - add_cgraph_node_to_partition (part, e->caller); - for (e = node->callees; e; e = e->next_callee) - if ((!e->inline_failed || DECL_COMDAT (e->callee->decl)) + if ((!e->inline_failed + || DECL_COMDAT (cgraph_function_node (e->callee, NULL)->decl)) && !cgraph_node_in_set_p (e->callee, part->cgraph_set)) add_cgraph_node_to_partition (part, e->callee); add_references_to_partition (part, &node->ref_list); - if (node->same_comdat_group - && !cgraph_node_in_set_p (node->same_comdat_group, part->cgraph_set)) - add_cgraph_node_to_partition (part, node->same_comdat_group); + if (node->same_comdat_group) + for (n = node->same_comdat_group; n != node; n = n->same_comdat_group) + add_cgraph_node_to_partition (part, n); } /* Add VNODE to partition as well as comdat references partition PART. */ @@ -1500,7 +1520,6 @@ lto_1_to_1_map (void) continue; file_data = node->local.lto_file_data; - gcc_assert (!node->same_body_alias); if (file_data) { @@ -1900,17 +1919,6 @@ promote_fn (struct cgraph_node *node) TREE_PUBLIC (node->decl) = 1; DECL_VISIBILITY (node->decl) = VISIBILITY_HIDDEN; DECL_VISIBILITY_SPECIFIED (node->decl) = true; - if (node->same_body) - { - struct cgraph_node *alias; - for (alias = node->same_body; - alias; alias = alias->next) - { - TREE_PUBLIC (alias->decl) = 1; - DECL_VISIBILITY (alias->decl) = VISIBILITY_HIDDEN; - DECL_VISIBILITY_SPECIFIED (alias->decl) = true; - } - } if (cgraph_dump_file) fprintf (cgraph_dump_file, "Promoting function as hidden: %s/%i\n", @@ -1944,8 +1952,8 @@ lto_promote_cross_file_statics (void) set = part->cgraph_set; vset = part->varpool_set; - /* If node has either address taken (and we have no clue from where) - or it is called from other partition, it needs to be globalized. */ + /* If node called or referred to from other partition, it needs to be + globalized. */ for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) { struct cgraph_node *node = csi_node (csi); diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index ce0d8d0653d..3544cafa20c 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -6675,6 +6675,16 @@ gate_ipa_pta (void) struct pt_solution ipa_escaped_pt = { true, false, false, false, false, false, false, NULL }; +/* Associate node with varinfo DATA. Worker for + cgraph_for_node_and_aliases. */ +static bool +associate_varinfo_to_alias (struct cgraph_node *node, void *data) +{ + if (node->alias || node->thunk.thunk_p) + insert_vi_for_tree (node->decl, (varinfo_t)data); + return false; +} + /* Execute the driver for IPA PTA. */ static unsigned int ipa_pta_execute (void) @@ -6690,22 +6700,17 @@ ipa_pta_execute (void) /* Build the constraints. */ for (node = cgraph_nodes; node; node = node->next) { - struct cgraph_node *alias; varinfo_t vi; - /* Nodes without a body are not interesting. Especially do not visit clones at this point for now - we get duplicate decls there for inline clones at least. */ - if (!gimple_has_body_p (node->decl) + if (!cgraph_function_with_gimple_body_p (node) || node->clone_of) continue; vi = create_function_info_for (node->decl, - alias_get_name (node->decl)); - - /* Associate the varinfo node with all aliases. */ - for (alias = node->same_body; alias; alias = alias->next) - insert_vi_for_tree (alias->decl, vi); + alias_get_name (node->decl)); + cgraph_for_node_and_aliases (node, associate_varinfo_to_alias, vi, true); } /* Create constraints for global variables and their initializers. */ @@ -6737,7 +6742,7 @@ ipa_pta_execute (void) tree old_func_decl; /* Nodes without a body are not interesting. */ - if (!gimple_has_body_p (node->decl) + if (!cgraph_function_with_gimple_body_p (node) || node->clone_of) continue; @@ -6846,7 +6851,7 @@ ipa_pta_execute (void) struct cgraph_edge *e; /* Nodes without a body are not interesting. */ - if (!gimple_has_body_p (node->decl) + if (!cgraph_function_with_gimple_body_p (node) || node->clone_of) continue;