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
This commit is contained in:
Jan Hubicka 2011-06-11 15:01:53 +02:00 committed by Jan Hubicka
parent c44ddf9615
commit 39e2db00da
19 changed files with 475 additions and 345 deletions

View File

@ -1,3 +1,71 @@
2011-06-11 Jan Hubicka <jh@suse.cz>
* 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 <ubizjak@gmail.com> 2011-06-11 Uros Bizjak <ubizjak@gmail.com>
* config/i386/sse.md (vec_dupv4sf): Correct mode of forced register. * config/i386/sse.md (vec_dupv4sf): Correct mode of forced register.

View File

@ -208,6 +208,9 @@ static GTY(()) struct cgraph_node *free_nodes;
Do not GTY((delete)) this list so UIDs gets reliably recycled. */ Do not GTY((delete)) this list so UIDs gets reliably recycled. */
static GTY(()) struct cgraph_edge *free_edges; 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 /* Macros to access the next item in the list of free cgraph nodes and
edges. */ edges. */
#define NEXT_FREE_NODE(NODE) (NODE)->next #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 /* Mark ALIAS as an alias to DECL. DECL_NODE is cgraph node representing
the function body is associated with (not neccesarily cgraph_node (DECL). */ the function body is associated with (not neccesarily cgraph_node (DECL). */
static struct cgraph_node * struct cgraph_node *
cgraph_same_body_alias_1 (struct cgraph_node *decl_node, tree alias, tree decl) 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 (decl) == FUNCTION_DECL);
gcc_assert (TREE_CODE (alias) == FUNCTION_DECL); gcc_assert (TREE_CODE (alias) == FUNCTION_DECL);
alias_node = cgraph_get_create_node (alias);
key.decl = alias; gcc_assert (!alias_node->local.finalized);
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->thunk.alias = decl; alias_node->thunk.alias = decl;
decl_node->same_body = alias_node; alias_node->local.finalized = true;
*slot = alias_node; 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; 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). */ and cgraph_get_node (ALIAS) transparently returns cgraph_get_node (DECL). */
struct cgraph_node * 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 #ifndef ASM_OUTPUT_DEF
/* If aliases aren't supported by the assembler, fail. */ /* If aliases aren't supported by the assembler, fail. */
return NULL; return NULL;
#endif #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);*/ n = cgraph_create_function_alias (alias, decl);
n->same_body_alias = true;
return cgraph_same_body_alias_1 (decl_node, alias, decl); 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 /* 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_VIRTUAL_P (decl)
&& (DECL_COMDAT (decl) || DECL_EXTERNAL (decl)))) && (DECL_COMDAT (decl) || DECL_EXTERNAL (decl))))
cgraph_mark_reachable_node (node); cgraph_mark_reachable_node (node);
return node; return node;
} }
@ -678,11 +680,7 @@ cgraph_get_node (const_tree decl)
NO_INSERT); NO_INSERT);
if (slot && *slot) if (slot && *slot)
{ node = *slot;
node = *slot;
if (node->same_body_alias)
node = node->same_body;
}
return node; return node;
} }
@ -745,21 +743,6 @@ cgraph_node_for_asm (tree asmname)
so lets hope for the best. */ so lets hope for the best. */
if (!*slot) if (!*slot)
*slot = node; *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) if (slot)
{ {
node = (struct cgraph_node *) *slot; node = (struct cgraph_node *) *slot;
if (node->same_body_alias)
node = node->same_body;
return node; return node;
} }
return NULL; return NULL;
@ -1432,44 +1413,6 @@ cgraph_release_function_body (struct cgraph_node *node)
DECL_INITIAL (node->decl) = error_mark_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. */ /* Remove the node from cgraph. */
void 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) if (node->same_comdat_group)
{ {
struct cgraph_node *prev; struct cgraph_node *prev;
@ -1747,6 +1687,14 @@ cgraph_mark_address_taken_node (struct cgraph_node *node)
{ {
gcc_assert (!node->global.inlined_to); gcc_assert (!node->global.inlined_to);
cgraph_mark_reachable_node (node); 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; 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_value,
(int)node->thunk.virtual_offset_p); (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: "); fprintf (f, " called by: ");
@ -1952,19 +1909,6 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
if (indirect_calls_count) if (indirect_calls_count)
fprintf (f, " has %i outgoing edges for indirect calls.\n", fprintf (f, " has %i outgoing edges for indirect calls.\n",
indirect_calls_count); 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) bool include_overwritable)
{ {
struct cgraph_edge *e; struct cgraph_edge *e;
struct cgraph_node *alias; int i;
struct ipa_ref *ref;
if (callback (node, data)) if (callback (node, data))
return true; 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) for (e = node->callers; e; e = e->next_caller)
if (e->caller->thunk.thunk_p if (e->caller->thunk.thunk_p
&& (include_overwritable && (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); 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; return false;
} }
@ -2637,15 +2587,21 @@ bool
cgraph_for_node_and_aliases (struct cgraph_node *node, cgraph_for_node_and_aliases (struct cgraph_node *node,
bool (*callback) (struct cgraph_node *, void *), bool (*callback) (struct cgraph_node *, void *),
void *data, void *data,
bool include_overwritable ATTRIBUTE_UNUSED) bool include_overwritable)
{ {
struct cgraph_node *alias; int i;
struct ipa_ref *ref;
if (callback (node, data)) if (callback (node, data))
return true; return true;
for (alias = node->same_body; alias; alias = alias->next) for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++)
if (callback (alias, data)) if (ref->use == IPA_REF_ALIAS)
return true; {
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; return false;
} }

View File

@ -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 *prev_sibling_clone;
struct cgraph_node *clones; struct cgraph_node *clones;
struct cgraph_node *clone_of; 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. */ /* Circular list of nodes in the same comdat group if non-NULL. */
struct cgraph_node *same_comdat_group; struct cgraph_node *same_comdat_group;
/* For functions with many calls sites it holds map from call expression /* 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; unsigned process : 1;
/* Set for aliases once they got through assemble_alias. */ /* Set for aliases once they got through assemble_alias. */
unsigned alias : 1; unsigned alias : 1;
/* Set for alias and thunk nodes, same_body points to the node they are alias /* Set for aliases created as C++ same body aliases. */
of and they are linked through the next/previous pointers. */
unsigned same_body_alias : 1; unsigned same_body_alias : 1;
/* How commonly executed the node is. Initialized during branch /* How commonly executed the node is. Initialized during branch
probabilities pass. */ 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(()) struct cgraph_asm_node *cgraph_asm_nodes;
extern GTY(()) int cgraph_order; extern GTY(()) int cgraph_order;
extern bool same_body_aliases_done;
/* In cgraph.c */ /* In cgraph.c */
void dump_cgraph (FILE *); 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_same_body_alias (struct cgraph_node *, tree, tree);
struct cgraph_node * cgraph_add_thunk (struct cgraph_node *, tree, tree, bool, HOST_WIDE_INT, struct cgraph_node * cgraph_add_thunk (struct cgraph_node *, tree, tree, bool, HOST_WIDE_INT,
HOST_WIDE_INT, tree, tree); HOST_WIDE_INT, tree, tree);
void cgraph_remove_same_body_alias (struct cgraph_node *);
struct cgraph_node *cgraph_node_for_asm (tree); struct cgraph_node *cgraph_node_for_asm (tree);
struct cgraph_edge *cgraph_edge (struct cgraph_node *, gimple); struct cgraph_edge *cgraph_edge (struct cgraph_node *, gimple);
void cgraph_set_call_stmt (struct cgraph_edge *, 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, struct cgraph_node * cgraph_clone_node (struct cgraph_node *, tree, gcov_type,
int, bool, VEC(cgraph_edge_p,heap) *, int, bool, VEC(cgraph_edge_p,heap) *,
bool); bool);
struct cgraph_node *cgraph_create_function_alias (tree, tree);
void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *); void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *);
void cgraph_make_edge_direct (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); bitmap, basic_block);
void record_references_in_initializer (tree, bool); void record_references_in_initializer (tree, bool);
bool cgraph_process_new_functions (void); bool cgraph_process_new_functions (void);
void cgraph_process_same_body_aliases (void);
bool cgraph_decide_is_function_needed (struct cgraph_node *, tree); 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 static inline bool
cgraph_function_with_gimple_body_p (struct cgraph_node *node) 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. */ /* 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)) if (DECL_EXTERNAL (node->decl))
return true; return true;
return (!node->address_taken 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 /* 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. */ /* FIXME: inappropriate dependency of cgraph on IPA. */
#include "ipa-ref-inline.h" #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. /* Given NODE, walk the alias chain to return the function NODE is alias of.
Walk through thunk, too. Walk through thunk, too.
When AVAILABILITY is non-NULL, get minimal availablity in the chain. */ 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); *availability = cgraph_function_body_availability (node);
while (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; node = node->callees->callee;
else else
return node; return node;
if (availability) if (node && availability)
{ {
enum availability a; enum availability a;
a = cgraph_function_body_availability (node); a = cgraph_function_body_availability (node);
@ -991,6 +1006,8 @@ cgraph_function_node (struct cgraph_node *node, enum availability *availability)
*availability = a; *availability = a;
} }
} }
if (*availability)
*availability = AVAIL_NOT_AVAILABLE;
return NULL; return NULL;
} }
@ -1003,7 +1020,22 @@ cgraph_function_or_thunk_node (struct cgraph_node *node, enum availability *avai
{ {
if (availability) if (availability)
*availability = cgraph_function_body_availability (node); *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; return NULL;
} }

View File

@ -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 the name later after finalizing the function and the fact is noticed
in assemble_name then. This is arguably a bug. */ in assemble_name then. This is arguably a bug. */
if (DECL_ASSEMBLER_NAME_SET_P (decl) if (DECL_ASSEMBLER_NAME_SET_P (decl)
&& (!node->thunk.thunk_p && !node->same_body_alias)
&& TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
return true; return true;
@ -391,6 +392,8 @@ cgraph_mark_if_needed (tree decl)
static bool static bool
clone_of_p (struct cgraph_node *node, struct cgraph_node *node2) 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) while (node != node2 && node2)
node2 = node2->clone_of; node2 = node2->clone_of;
return node2 != NULL; return node2 != NULL;
@ -619,6 +622,36 @@ verify_cgraph_node (struct cgraph_node *node)
while (n != 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->analyzed && node->thunk.thunk_p)
{ {
if (!node->callees) if (!node->callees)
@ -669,19 +702,17 @@ verify_cgraph_node (struct cgraph_node *node)
} }
if (!e->indirect_unknown_callee) if (!e->indirect_unknown_callee)
{ {
if (e->callee->same_body_alias) if (!e->callee->global.inlined_to
{ && decl
error ("edge points to same body alias:"); && cgraph_get_node (decl)
debug_tree (e->callee->decl); && (e->callee->former_clone_of
error_found = true; != cgraph_get_node (decl)->decl)
} /* IPA-CP sometimes redirect edge to clone and then back to the former
else if (!e->callee->global.inlined_to function. This ping-pong has to go, eventaully. */
&& decl && (cgraph_function_or_thunk_node (cgraph_get_node (decl), NULL)
&& cgraph_get_node (decl) != cgraph_function_or_thunk_node (e->callee, NULL))
&& (e->callee->former_clone_of && !clone_of_p (cgraph_get_node (decl),
!= cgraph_get_node (decl)->decl) e->callee))
&& !clone_of_p (cgraph_get_node (decl),
e->callee))
{ {
error ("edge points to wrong declaration:"); error ("edge points to wrong declaration:");
debug_tree (e->callee->decl); debug_tree (e->callee->decl);
@ -781,7 +812,53 @@ cgraph_analyze_function (struct cgraph_node *node)
tree save = current_function_decl; tree save = current_function_decl;
tree decl = node->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), cgraph_create_edge (node, cgraph_get_node (node->thunk.alias),
NULL, 0, CGRAPH_FREQ_BASE); NULL, 0, CGRAPH_FREQ_BASE);
@ -809,6 +886,26 @@ cgraph_analyze_function (struct cgraph_node *node)
current_function_decl = save; 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. */ /* Process attributes common for vars and functions. */
static void static void
@ -880,7 +977,7 @@ process_function_and_variable_attributes (struct cgraph_node *first,
cgraph_mark_needed_node (node); cgraph_mark_needed_node (node);
} }
if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)) if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))
&& node->local.finalized) && (node->local.finalized && !node->alias))
{ {
warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wattributes, warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wattributes,
"%<weakref%> attribute ignored" "%<weakref%> attribute ignored"
@ -979,6 +1076,7 @@ cgraph_analyze_functions (void)
weak alias attribute to kill its body. See weak alias attribute to kill its body. See
gcc.c-torture/compile/20011119-1.c */ gcc.c-torture/compile/20011119-1.c */
if (!DECL_STRUCT_FUNCTION (decl) if (!DECL_STRUCT_FUNCTION (decl)
&& (!node->alias || !node->thunk.alias)
&& !node->thunk.thunk_p) && !node->thunk.thunk_p)
{ {
cgraph_reset_node (node); cgraph_reset_node (node);
@ -1046,11 +1144,13 @@ cgraph_analyze_functions (void)
next = node->next; next = node->next;
if (node->local.finalized && !gimple_has_body_p (decl) if (node->local.finalized && !gimple_has_body_p (decl)
&& (!node->alias || !node->thunk.alias)
&& !node->thunk.thunk_p) && !node->thunk.thunk_p)
cgraph_reset_node (node); cgraph_reset_node (node);
if (!node->reachable 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) if (cgraph_dump_file)
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node)); fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
@ -1060,6 +1160,7 @@ cgraph_analyze_functions (void)
else else
node->next_needed = NULL; node->next_needed = NULL;
gcc_assert (!node->local.finalized || node->thunk.thunk_p gcc_assert (!node->local.finalized || node->thunk.thunk_p
|| node->alias
|| gimple_has_body_p (decl)); || gimple_has_body_p (decl));
gcc_assert (node->analyzed == node->local.finalized); gcc_assert (node->analyzed == node->local.finalized);
} }
@ -1157,9 +1258,11 @@ cgraph_mark_functions_to_output (void)
outside the current compilation unit. */ outside the current compilation unit. */
if (node->analyzed if (node->analyzed
&& !node->thunk.thunk_p && !node->thunk.thunk_p
&& !node->alias
&& !node->global.inlined_to && !node->global.inlined_to
&& (!cgraph_only_called_directly_p (node) && (!cgraph_only_called_directly_p (node)
|| (e && node->reachable)) || ((e || ipa_ref_has_aliases_p (&node->ref_list))
&& node->reachable))
&& !TREE_ASM_WRITTEN (decl) && !TREE_ASM_WRITTEN (decl)
&& !DECL_EXTERNAL (decl)) && !DECL_EXTERNAL (decl))
{ {
@ -1170,7 +1273,7 @@ cgraph_mark_functions_to_output (void)
for (next = node->same_comdat_group; for (next = node->same_comdat_group;
next != node; next != node;
next = next->same_comdat_group) next = next->same_comdat_group)
if (!next->thunk.thunk_p) if (!next->thunk.thunk_p && !next->alias)
next->process = 1; 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 are inside partition, we can end up not removing the body since we no longer
have analyzed node pointing to it. */ have analyzed node pointing to it. */
&& !node->in_other_partition && !node->in_other_partition
&& !node->alias
&& !DECL_EXTERNAL (decl)) && !DECL_EXTERNAL (decl))
{ {
dump_cgraph_node (stderr, node); dump_cgraph_node (stderr, node);
@ -1219,7 +1323,7 @@ cgraph_mark_functions_to_output (void)
&& !DECL_EXTERNAL (decl)) && !DECL_EXTERNAL (decl))
{ {
dump_cgraph_node (stderr, node); dump_cgraph_node (stderr, node);
internal_error ("failed to reclaim unneeded function"); internal_error ("failed to reclaim unneeded functionin same comdat group");
} }
} }
#endif #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 static void
assemble_thunks (struct cgraph_node *node) assemble_thunks_and_aliases (struct cgraph_node *node)
{ {
struct cgraph_edge *e; struct cgraph_edge *e;
int i;
struct ipa_ref *ref;
for (e = node->callers; e;) for (e = node->callers; e;)
if (e->caller->thunk.thunk_p) if (e->caller->thunk.thunk_p)
{ {
struct cgraph_node *thunk = e->caller; struct cgraph_node *thunk = e->caller;
e = e->next_caller; e = e->next_caller;
assemble_thunks (thunk); assemble_thunks_and_aliases (thunk);
assemble_thunk (thunk); assemble_thunk (thunk);
} }
else else
e = e->next_caller; 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. */ /* Expand function specified by NODE. */
@ -1600,27 +1716,7 @@ cgraph_expand_function (struct cgraph_node *node)
announce_function (decl); announce_function (decl);
node->process = 0; node->process = 0;
if (node->same_body) assemble_thunks_and_aliases (node);
{
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);
gcc_assert (node->lowered); gcc_assert (node->lowered);
/* Generate RTL for the body of DECL. */ /* Generate RTL for the body of DECL. */
@ -1736,7 +1832,7 @@ cgraph_output_in_order (void)
for (pf = cgraph_nodes; pf; pf = pf->next) 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; i = pf->order;
gcc_assert (nodes[i].kind == ORDER_UNDEFINED); gcc_assert (nodes[i].kind == ORDER_UNDEFINED);
@ -1810,7 +1906,7 @@ bool
cgraph_preserve_function_body_p (struct cgraph_node *node) cgraph_preserve_function_body_p (struct cgraph_node *node)
{ {
gcc_assert (cgraph_global_info_ready); 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. */ /* Look if there is any clone around. */
if (node->clones) if (node->clones)

View File

@ -1,3 +1,8 @@
2011-06-11 Jan Hubicka <jh@suse.cz>
* decl2.c (cp_write_global_declarations): Process aliases; look trhough
same body aliases.
2011-06-10 Paolo Carlini <paolo.carlini@oracle.com> 2011-06-10 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/41769 PR c++/41769

View File

@ -3672,6 +3672,8 @@ cp_write_global_declarations (void)
if (pch_file) if (pch_file)
c_common_write_pch (); c_common_write_pch ();
cgraph_process_same_body_aliases ();
/* Handle -fdump-ada-spec[-slim] */ /* Handle -fdump-ada-spec[-slim] */
if (dump_enabled_p (TDI_ada)) if (dump_enabled_p (TDI_ada))
{ {
@ -3869,6 +3871,8 @@ cp_write_global_declarations (void)
struct cgraph_node *node, *next; struct cgraph_node *node, *next;
node = cgraph_get_node (decl); 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, cgraph_for_node_and_aliases (node, clear_decl_external,
NULL, true); NULL, true);

View File

@ -3363,9 +3363,8 @@ cp_fix_function_decl_p (tree decl)
/* Don't fix same_body aliases. Although they don't have their own /* Don't fix same_body aliases. Although they don't have their own
CFG, they share it with what they alias to. */ CFG, they share it with what they alias to. */
if (!node if (!node || !node->alias
|| node->decl == decl || !VEC_length (ipa_ref_t, node->ref_list.references))
|| !node->same_body)
return true; return true;
} }

View File

@ -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 can remove its offline copy, but we would need to keep unanalyzed node in
the callgraph so references can point to it. */ the callgraph so references can point to it. */
return (!node->address_taken return (!node->address_taken
&& !ipa_ref_has_aliases_p (&node->ref_list)
&& cgraph_can_remove_if_no_direct_calls_p (node) && cgraph_can_remove_if_no_direct_calls_p (node)
/* Inlining might enable more devirtualizing, so we want to remove /* Inlining might enable more devirtualizing, so we want to remove
those only after all devirtualizable virtual calls are processed. 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 /* If aliases are involved, redirect edge to the actual destination and
possibly remove the aliases. */ possibly remove the aliases. */
if (e->callee != callee) 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); clone_inlined_nodes (e, true, update_original, overall_size);

View File

@ -965,6 +965,8 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
struct cgraph_edge *check_inlinablity_for) struct cgraph_edge *check_inlinablity_for)
{ {
struct cgraph_edge *edge; struct cgraph_edge *edge;
int i;
struct ipa_ref *ref;
if (!inline_summary (node)->inlinable if (!inline_summary (node)->inlinable
|| cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE || 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)) if (!bitmap_set_bit (updated_nodes, node->uid))
return; 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) for (edge = node->callers; edge; edge = edge->next_caller)
if (edge->inline_failed) if (edge->inline_failed)
{ {
@ -1451,7 +1460,7 @@ inline_small_functions (void)
where = edge->caller; where = edge->caller;
while (where->global.inlined_to) while (where->global.inlined_to)
{ {
if (where->decl == edge->callee->decl) if (where->decl == callee->decl)
outer_node = where, depth++; outer_node = where, depth++;
where = where->callers->caller; where = where->callers->caller;
} }

View File

@ -27,7 +27,7 @@ along with GCC; see the file COPYING3. If not see
#include "target.h" #include "target.h"
#include "cgraph.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 /* Return ipa reference from REFERING_NODE or REFERING_VARPOOL_NODE
to REFERED_NODE or REFERED_VARPOOL_NODE. USE_TYPE specify type 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 ((!refering_node) ^ (!refering_varpool_node));
gcc_assert ((!refered_node) ^ (!refered_varpool_node)); gcc_assert ((!refered_node) ^ (!refered_varpool_node));
gcc_assert (!stmt || refering_node); gcc_assert (!stmt || refering_node);
gcc_assert (use_type != IPA_REF_ALIAS || !stmt);
list = (refering_node ? &refering_node->ref_list list = (refering_node ? &refering_node->ref_list
: &refering_varpool_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.cgraph_node = refered_node;
ref->refered_type = IPA_REF_CGRAPH; 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 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 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;
}

View File

@ -27,7 +27,8 @@ enum GTY(()) ipa_ref_use
{ {
IPA_REF_LOAD, IPA_REF_LOAD,
IPA_REF_STORE, IPA_REF_STORE,
IPA_REF_ADDR IPA_REF_ADDR,
IPA_REF_ALIAS
}; };
/* Type of refering or refered type. */ /* 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_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 *); 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_cannot_lead_to_return (struct ipa_ref *);
bool ipa_ref_has_aliases_p (struct ipa_ref_list *);

View File

@ -234,7 +234,8 @@ ipa_free_postorder_info (void)
} }
/* Fill array order with all nodes with output flag set in the reverse /* 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 int
ipa_reverse_postorder (struct cgraph_node **order) ipa_reverse_postorder (struct cgraph_node **order)
@ -260,7 +261,7 @@ ipa_reverse_postorder (struct cgraph_node **order)
&& (pass && (pass
|| (!node->address_taken || (!node->address_taken
&& !node->global.inlined_to && !node->global.inlined_to
&& !cgraph_only_called_directly_p (node)))) && !cgraph_only_called_directly_or_aliased_p (node))))
{ {
node2 = node; node2 = node;
if (!node->callers) if (!node->callers)

View File

@ -581,9 +581,9 @@ cgraph_comdat_can_be_unshared_p (struct cgraph_node *node)
/* Return true when function NODE should be considered externally visible. */ /* Return true when function NODE should be considered externally visible. */
static bool 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) if (!node->local.finalized)
return false; return false;
if (!DECL_COMDAT (node->decl) 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)) && cgraph_comdat_can_be_unshared_p (node))
return false; 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. */ /* When doing link time optimizations, hidden symbols become local. */
if (in_lto_p if (in_lto_p
&& (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN && (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN
@ -881,12 +869,9 @@ function_and_variable_visibility (bool whole_program)
if (!node->local.externally_visible && node->analyzed if (!node->local.externally_visible && node->analyzed
&& !DECL_EXTERNAL (node->decl)) && !DECL_EXTERNAL (node->decl))
{ {
struct cgraph_node *alias;
gcc_assert (whole_program || in_lto_p || !TREE_PUBLIC (node->decl)); gcc_assert (whole_program || in_lto_p || !TREE_PUBLIC (node->decl));
cgraph_make_decl_local (node->decl); cgraph_make_decl_local (node->decl);
node->resolution = LDPR_PREVAILING_DEF_IRONLY; 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) if (node->same_comdat_group)
/* cgraph_externally_visible_p has already checked all other nodes /* cgraph_externally_visible_p has already checked all other nodes
in the group and they will all be made local. We need to 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; struct cgraph_node *decl_node = node;
while (decl_node->thunk.thunk_p) decl_node = cgraph_function_node (decl_node->callees->callee, NULL);
decl_node = decl_node->callees->callee;
/* Thunks have the same visibility as function they are attached to. /* Thunks have the same visibility as function they are attached to.
For some reason C++ frontend don't seem to care. I.e. in 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)) if (DECL_EXTERNAL (decl_node->decl))
DECL_EXTERNAL (node->decl) = 1; 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) for (vnode = varpool_nodes; vnode; vnode = vnode->next)
{ {
/* weak flag makes no sense on local variables. */ /* weak flag makes no sense on local variables. */

View File

@ -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); || referenced_from_other_partition_p (&node->ref_list, set, vset)), 1);
bp_pack_value (&bp, node->lowered, 1); bp_pack_value (&bp, node->lowered, 1);
bp_pack_value (&bp, in_other_partition, 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->frequency, 2);
bp_pack_value (&bp, node->only_called_at_startup, 1); bp_pack_value (&bp, node->only_called_at_startup, 1);
bp_pack_value (&bp, node->only_called_at_exit, 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); node->thunk.fixed_offset);
lto_output_uleb128_stream (ob->main_stream, lto_output_uleb128_stream (ob->main_stream,
node->thunk.virtual_value); node->thunk.virtual_value);
lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
node->thunk.alias);
} }
if ((node->alias || node->thunk.thunk_p) && !boundary_p)
if (node->same_body)
{ {
struct cgraph_node *alias; lto_output_int_in_range (ob->main_stream, 0, 1,
unsigned long alias_count = 1; node->thunk.alias != NULL);
for (alias = node->same_body; alias->next; alias = alias->next) if (node->thunk.alias != NULL)
alias_count++; lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
lto_output_uleb128_stream (ob->main_stream, alias_count); node->thunk.alias);
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);
} }
else
lto_output_uleb128_stream (ob->main_stream, 0);
} }
/* Output the varpool NODE to OB. /* Output the varpool NODE to OB.
@ -997,7 +980,6 @@ input_node (struct lto_file_decl_data *file_data,
struct bitpack_d bp; struct bitpack_d bp;
unsigned decl_index; unsigned decl_index;
int ref = LCC_NOT_FOUND, ref2 = LCC_NOT_FOUND; int ref = LCC_NOT_FOUND, ref2 = LCC_NOT_FOUND;
unsigned long same_body_count = 0;
int clone_ref; int clone_ref;
clone_ref = lto_input_sleb128 (ib); 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); int type = lto_input_uleb128 (ib);
HOST_WIDE_INT fixed_offset = lto_input_uleb128 (ib); HOST_WIDE_INT fixed_offset = lto_input_uleb128 (ib);
HOST_WIDE_INT virtual_value = 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.fixed_offset = fixed_offset;
node->thunk.this_adjusting = (type & 2); node->thunk.this_adjusting = (type & 2);
node->thunk.virtual_value = virtual_value; node->thunk.virtual_value = virtual_value;
node->thunk.virtual_offset_p = (type & 4); node->thunk.virtual_offset_p = (type & 4);
node->thunk.alias = real_alias;
} }
if (node->thunk.thunk_p || node->alias)
same_body_count = lto_input_uleb128 (ib);
while (same_body_count-- > 0)
{ {
tree alias_decl, real_alias; if (lto_input_int_in_range (ib, "alias nonzero flag", 0, 1))
struct cgraph_node *alias; {
decl_index = lto_input_uleb128 (ib);
decl_index = lto_input_uleb128 (ib); node->thunk.alias = lto_file_decl_data_get_fn_decl (file_data,
alias_decl = lto_file_decl_data_get_fn_decl (file_data, decl_index); 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);
} }
return node; return node;
} }

View File

@ -2253,6 +2253,7 @@ lto_output (cgraph_node_set set, varpool_node_set vset)
{ {
node = lto_cgraph_encoder_deref (encoder, i); node = lto_cgraph_encoder_deref (encoder, i);
if (lto_cgraph_encoder_encode_body_p (encoder, node) if (lto_cgraph_encoder_encode_body_p (encoder, node)
&& !node->alias
&& !node->thunk.thunk_p) && !node->thunk.thunk_p)
{ {
#ifdef ENABLE_CHECKING #ifdef ENABLE_CHECKING
@ -2551,7 +2552,7 @@ produce_symtab (struct output_block *ob,
struct lto_streamer_cache_d *cache = ob->writer_cache; struct lto_streamer_cache_d *cache = ob->writer_cache;
char *section_name = lto_get_section_name (LTO_section_symtab, NULL, NULL); char *section_name = lto_get_section_name (LTO_section_symtab, NULL, NULL);
struct pointer_set_t *seen; struct pointer_set_t *seen;
struct cgraph_node *node, *alias; struct cgraph_node *node;
struct varpool_node *vnode, *valias; struct varpool_node *vnode, *valias;
struct lto_output_stream stream; struct lto_output_stream stream;
lto_varpool_encoder_t varpool_encoder = ob->decl_state->varpool_node_encoder; 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) if (node->alias || node->global.inlined_to)
continue; continue;
write_symbol (cache, &stream, node->decl, seen, false); 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++) 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) if (node->alias || node->global.inlined_to)
continue; continue;
write_symbol (cache, &stream, node->decl, seen, false); 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. */ /* Write all variables. */

View File

@ -209,7 +209,6 @@ lto_cgraph_replace_node (struct cgraph_node *node,
struct cgraph_node *prevailing_node) struct cgraph_node *prevailing_node)
{ {
struct cgraph_edge *e, *next; struct cgraph_edge *e, *next;
bool no_aliases_please = false;
bool compatible_p; bool compatible_p;
if (cgraph_dump_file) if (cgraph_dump_file)
@ -223,13 +222,6 @@ lto_cgraph_replace_node (struct cgraph_node *node,
(IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl))))); (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. */ /* Merge node flags. */
if (node->needed) if (node->needed)
cgraph_mark_needed_node (prevailing_node); cgraph_mark_needed_node (prevailing_node);
@ -259,36 +251,8 @@ lto_cgraph_replace_node (struct cgraph_node *node,
/* Redirect incomming references. */ /* Redirect incomming references. */
ipa_clone_refering (prevailing_node, NULL, &node->ref_list); 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. */ /* Finally remove the replaced node. */
if (node->same_body_alias) cgraph_remove_node (node);
cgraph_remove_same_body_alias (node);
else
cgraph_remove_node (node);
} }
/* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging /* 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. */ /* For functions we need a non-discarded body. */
if (TREE_CODE (e->decl) == FUNCTION_DECL) if (TREE_CODE (e->decl) == FUNCTION_DECL)
return (e->node return (e->node && e->node->analyzed);
&& (e->node->analyzed
|| (e->node->same_body_alias && e->node->same_body->analyzed)));
/* A variable should have a size. */ /* A variable should have a size. */
else if (TREE_CODE (e->decl) == VAR_DECL) 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 void
lto_symtab_merge_cgraph_nodes (void) lto_symtab_merge_cgraph_nodes (void)
{ {
struct cgraph_node *node, *alias, *next; struct cgraph_node *node;
lto_symtab_maybe_init_hash_table (); lto_symtab_maybe_init_hash_table ();
htab_traverse (lto_symtab_identifiers, lto_symtab_merge_cgraph_nodes_1, NULL); htab_traverse (lto_symtab_identifiers, lto_symtab_merge_cgraph_nodes_1, NULL);
for (node = cgraph_nodes; node; node = node->next) for (node = cgraph_nodes; node; node = node->next)
{ if ((node->thunk.thunk_p || node->alias)
if (node->thunk.thunk_p) && node->thunk.alias)
node->thunk.alias = lto_symtab_prevailing_decl (node->thunk.alias); 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);
}
}
} }
/* Given the decl DECL, return the prevailing decl with the same name. */ /* Given the decl DECL, return the prevailing decl with the same name. */

View File

@ -1,3 +1,12 @@
2011-06-11 Jan Hubicka <jh@suse.cz>
* 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 <dnovillo@google.com> 2011-06-07 Diego Novillo <dnovillo@google.com>
* lto.c (uniquify_nodes): Move code to register decls to * lto.c (uniquify_nodes): Move code to register decls to

View File

@ -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++) for (i = 0; ipa_ref_list_reference_iterate (refs, i, ref); i++)
{ {
if (ref->refered_type == IPA_REF_CGRAPH 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)) && !cgraph_node_in_set_p (ipa_ref_node (ref), part->cgraph_set))
add_cgraph_node_to_partition (part, ipa_ref_node (ref)); add_cgraph_node_to_partition (part, ipa_ref_node (ref));
else else
@ -1330,20 +1330,21 @@ add_references_to_partition (ltrans_partition part, struct ipa_ref_list *refs)
} }
} }
/* Add NODE to partition as well as the inline callees and referred comdats into partition PART. */ /* Worker for add_cgraph_node_to_partition. */
static void static bool
add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node) add_cgraph_node_to_partition_1 (struct cgraph_node *node, void *data)
{ {
struct cgraph_edge *e; ltrans_partition part = (ltrans_partition) data;
cgraph_node_set_iterator csi;
/* If NODE is already there, we have nothing to do. */ /* non-COMDAT aliases of COMDAT functions needs to be output just once. */
csi = cgraph_node_set_find (part->cgraph_set, node); if (!DECL_COMDAT (node->decl)
if (!csi_end_p (csi)) && !node->global.inlined_to
return; && node->aux)
{
part->insns += inline_summary (node)->self_size; gcc_assert (node->thunk.thunk_p || node->alias);
return false;
}
if (node->aux) if (node->aux)
{ {
@ -1353,26 +1354,45 @@ add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node)
cgraph_node_name (node), node->uid); cgraph_node_name (node), node->uid);
} }
node->aux = (void *)((size_t)node->aux + 1); 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
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;
cgraph_node_set_add (part->cgraph_set, node); 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) 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)) && !cgraph_node_in_set_p (e->callee, part->cgraph_set))
add_cgraph_node_to_partition (part, e->callee); add_cgraph_node_to_partition (part, e->callee);
add_references_to_partition (part, &node->ref_list); add_references_to_partition (part, &node->ref_list);
if (node->same_comdat_group if (node->same_comdat_group)
&& !cgraph_node_in_set_p (node->same_comdat_group, part->cgraph_set)) for (n = node->same_comdat_group; n != node; n = n->same_comdat_group)
add_cgraph_node_to_partition (part, node->same_comdat_group); add_cgraph_node_to_partition (part, n);
} }
/* Add VNODE to partition as well as comdat references partition PART. */ /* Add VNODE to partition as well as comdat references partition PART. */
@ -1500,7 +1520,6 @@ lto_1_to_1_map (void)
continue; continue;
file_data = node->local.lto_file_data; file_data = node->local.lto_file_data;
gcc_assert (!node->same_body_alias);
if (file_data) if (file_data)
{ {
@ -1900,17 +1919,6 @@ promote_fn (struct cgraph_node *node)
TREE_PUBLIC (node->decl) = 1; TREE_PUBLIC (node->decl) = 1;
DECL_VISIBILITY (node->decl) = VISIBILITY_HIDDEN; DECL_VISIBILITY (node->decl) = VISIBILITY_HIDDEN;
DECL_VISIBILITY_SPECIFIED (node->decl) = true; 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) if (cgraph_dump_file)
fprintf (cgraph_dump_file, fprintf (cgraph_dump_file,
"Promoting function as hidden: %s/%i\n", "Promoting function as hidden: %s/%i\n",
@ -1944,8 +1952,8 @@ lto_promote_cross_file_statics (void)
set = part->cgraph_set; set = part->cgraph_set;
vset = part->varpool_set; vset = part->varpool_set;
/* If node has either address taken (and we have no clue from where) /* If node called or referred to from other partition, it needs to be
or it is called from other partition, it needs to be globalized. */ globalized. */
for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
{ {
struct cgraph_node *node = csi_node (csi); struct cgraph_node *node = csi_node (csi);

View File

@ -6675,6 +6675,16 @@ gate_ipa_pta (void)
struct pt_solution ipa_escaped_pt struct pt_solution ipa_escaped_pt
= { true, false, false, false, false, false, false, NULL }; = { 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. */ /* Execute the driver for IPA PTA. */
static unsigned int static unsigned int
ipa_pta_execute (void) ipa_pta_execute (void)
@ -6690,22 +6700,17 @@ ipa_pta_execute (void)
/* Build the constraints. */ /* Build the constraints. */
for (node = cgraph_nodes; node; node = node->next) for (node = cgraph_nodes; node; node = node->next)
{ {
struct cgraph_node *alias;
varinfo_t vi; varinfo_t vi;
/* Nodes without a body are not interesting. Especially do not /* Nodes without a body are not interesting. Especially do not
visit clones at this point for now - we get duplicate decls visit clones at this point for now - we get duplicate decls
there for inline clones at least. */ there for inline clones at least. */
if (!gimple_has_body_p (node->decl) if (!cgraph_function_with_gimple_body_p (node)
|| node->clone_of) || node->clone_of)
continue; continue;
vi = create_function_info_for (node->decl, vi = create_function_info_for (node->decl,
alias_get_name (node->decl)); alias_get_name (node->decl));
cgraph_for_node_and_aliases (node, associate_varinfo_to_alias, vi, true);
/* Associate the varinfo node with all aliases. */
for (alias = node->same_body; alias; alias = alias->next)
insert_vi_for_tree (alias->decl, vi);
} }
/* Create constraints for global variables and their initializers. */ /* Create constraints for global variables and their initializers. */
@ -6737,7 +6742,7 @@ ipa_pta_execute (void)
tree old_func_decl; tree old_func_decl;
/* Nodes without a body are not interesting. */ /* 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) || node->clone_of)
continue; continue;
@ -6846,7 +6851,7 @@ ipa_pta_execute (void)
struct cgraph_edge *e; struct cgraph_edge *e;
/* Nodes without a body are not interesting. */ /* 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) || node->clone_of)
continue; continue;