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>
* 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. */
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;
}

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 *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;
}

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
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,
"%<weakref%> 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)

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>
PR c++/41769

View File

@ -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);

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
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;
}

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
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);

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 *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;
}

View File

@ -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;
}

View File

@ -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 *);

View File

@ -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)

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. */
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. */

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);
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;
}

View File

@ -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. */

View File

@ -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. */

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>
* 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++)
{
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,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
add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node)
static bool
add_cgraph_node_to_partition_1 (struct cgraph_node *node, void *data)
{
struct cgraph_edge *e;
cgraph_node_set_iterator csi;
ltrans_partition part = (ltrans_partition) data;
/* 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;
part->insns += inline_summary (node)->self_size;
/* 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)
{
@ -1353,26 +1354,45 @@ add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node)
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
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);
/* 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);

View File

@ -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;