* 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
+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.
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
/* 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;
}
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
|| (DECL_VIRTUAL_P (decl)
&& (DECL_COMDAT (decl) || DECL_EXTERNAL (decl))))
cgraph_mark_reachable_node (node);
+
return node;
}
NO_INSERT);
if (slot && *slot)
- {
- node = *slot;
- if (node->same_body_alias)
- node = node->same_body;
- }
+ node = *slot;
return node;
}
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;
- }
- }
}
}
if (slot)
{
node = (struct cgraph_node *) *slot;
- if (node->same_body_alias)
- node = node->same_body;
return node;
}
return NULL;
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
}
}
- while (node->same_body)
- cgraph_remove_same_body_alias (node->same_body);
-
if (node->same_comdat_group)
{
struct cgraph_node *prev;
{
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;
}
(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: ");
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");
- }
}
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;
}
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;
}
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
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. */
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 *);
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);
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 *,
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);
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. */
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
/* 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. */
*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);
*availability = a;
}
}
+ if (*availability)
+ *availability = AVAIL_NOT_AVAILABLE;
return NULL;
}
{
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;
}
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;
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;
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)
}
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);
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);
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
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"
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);
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));
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);
}
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))
{
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;
}
}
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);
&& !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
}
-/* 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. */
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. */
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);
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)
+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
if (pch_file)
c_common_write_pch ();
+ cgraph_process_same_body_aliases ();
+
/* Handle -fdump-ada-spec[-slim] */
if (dump_enabled_p (TDI_ada))
{
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);
/* 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;
}
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.
/* 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);
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
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)
{
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;
}
#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
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);
{
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
{
{
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;
+}
{
IPA_REF_LOAD,
IPA_REF_STORE,
- IPA_REF_ADDR
+ IPA_REF_ADDR,
+ IPA_REF_ALIAS
};
/* Type of refering or refered type. */
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 *);
}
/* 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)
&& (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)
/* 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)
&& 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
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
{
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
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. */
|| 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);
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.
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);
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;
}
{
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
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;
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++)
{
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. */
struct cgraph_node *prevailing_node)
{
struct cgraph_edge *e, *next;
- bool no_aliases_please = false;
bool compatible_p;
if (cgraph_dump_file)
(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);
/* 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
/* 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)
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. */
+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
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
}
}
+/* Worker for add_cgraph_node_to_partition. */
+
+static bool
+add_cgraph_node_to_partition_1 (struct cgraph_node *node, void *data)
+{
+ ltrans_partition part = (ltrans_partition) data;
+
+ /* non-COMDAT aliases of COMDAT functions needs to be output just once. */
+ if (!DECL_COMDAT (node->decl)
+ && !node->global.inlined_to
+ && node->aux)
+ {
+ gcc_assert (node->thunk.thunk_p || node->alias);
+ return false;
+ }
+
+ if (node->aux)
+ {
+ node->in_other_partition = 1;
+ if (cgraph_dump_file)
+ fprintf (cgraph_dump_file, "Node %s/%i now used in multiple partitions\n",
+ cgraph_node_name (node), node->uid);
+ }
+ node->aux = (void *)((size_t)node->aux + 1);
+ cgraph_node_set_add (part->cgraph_set, node);
+ return false;
+}
+
/* Add NODE to partition as well as the inline callees and referred comdats into partition PART. */
static void
{
struct cgraph_edge *e;
cgraph_node_set_iterator csi;
+ struct cgraph_node *n;
+
+ /* We always decide on functions, not associated thunks and aliases. */
+ node = cgraph_function_node (node, NULL);
/* If NODE is already there, we have nothing to do. */
csi = cgraph_node_set_find (part->cgraph_set, node);
if (!csi_end_p (csi))
return;
+ cgraph_for_node_thunks_and_aliases (node, add_cgraph_node_to_partition_1, part, true);
+
part->insns += inline_summary (node)->self_size;
- if (node->aux)
- {
- node->in_other_partition = 1;
- if (cgraph_dump_file)
- fprintf (cgraph_dump_file, "Node %s/%i now used in multiple partitions\n",
- cgraph_node_name (node), node->uid);
- }
- node->aux = (void *)((size_t)node->aux + 1);
cgraph_node_set_add (part->cgraph_set, node);
- /* Thunks always must go along with function they reffer to. */
- if (node->thunk.thunk_p)
- add_cgraph_node_to_partition (part, node->callees->callee);
- for (e = node->callers; e; e = e->next_caller)
- if (e->caller->thunk.thunk_p)
- add_cgraph_node_to_partition (part, e->caller);
-
for (e = node->callees; e; e = e->next_callee)
- if ((!e->inline_failed || DECL_COMDAT (e->callee->decl))
+ if ((!e->inline_failed
+ || DECL_COMDAT (cgraph_function_node (e->callee, NULL)->decl))
&& !cgraph_node_in_set_p (e->callee, part->cgraph_set))
add_cgraph_node_to_partition (part, e->callee);
add_references_to_partition (part, &node->ref_list);
- if (node->same_comdat_group
- && !cgraph_node_in_set_p (node->same_comdat_group, part->cgraph_set))
- add_cgraph_node_to_partition (part, node->same_comdat_group);
+ if (node->same_comdat_group)
+ for (n = node->same_comdat_group; n != node; n = n->same_comdat_group)
+ add_cgraph_node_to_partition (part, n);
}
/* Add VNODE to partition as well as comdat references partition PART. */
continue;
file_data = node->local.lto_file_data;
- gcc_assert (!node->same_body_alias);
if (file_data)
{
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",
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);
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)
/* 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. */
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;
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;