summaryrefslogtreecommitdiff
path: root/gcc/cgraph.c
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2009-11-18 09:53:52 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2009-11-18 09:53:52 +0000
commited772161067b3dbee0dbc2ccf93e20e574db2067 (patch)
treee08b1ed30e6c41061167a50b2e85f7af35d6e70c /gcc/cgraph.c
parente694b73b6383ee08ed2d4c4058049a62ab6677b7 (diff)
downloadgcc-ed772161067b3dbee0dbc2ccf93e20e574db2067.tar.gz
PR c++/3187
* cgraph.h (struct cgraph_node): Add same_body and same_body_alias fields. (cgraph_same_body_alias, cgraph_remove_same_body_alias): New prototypes. * cgraphunit.c (cgraph_expand_function, cgraph_emit_thunks, cgraph_materialize_all_clones): Handle same_body aliases. * cgraph.c (cgraph_allocate_node): New function. (cgraph_create_node): Use it. (cgraph_node_for_decl, cgraph_node, cgraph_get_node, cgraph_node_for_asm, cgraph_remove_node): Handle same_body aliases. (cgraph_same_body_alias, cgraph_remove_same_body_alias): New functions. * lto-cgraph.c (lto_output_node): Stream out same_body aliases. (input_node): Stream in same_body aliases. * lto-symtab.c (lto_cgraph_replace_node): Clear node pointers for same_body aliases. (lto_symtab_merge_cgraph_nodes_1): Handle same_body aliases. * cp-tree.h (expand_or_defer_fn_1): New prototype. * decl2.c (cp_write_global_declarations): Mark as !DECL_EXTERNAL also all same_body aliases. * semantics.c (expand_or_defer_fn): Move most of the function except registering with cgraph to ... (expand_or_defer_fn_1): ... here. New function. * optimize.c: Include cgraph.h. (maybe_clone_body): If in charge parm is not used and both base and complete clones are created and are not comdat, tell cgraph they have the same body. * Make-lang.in (cp/optimize.o): Depend on $(CGRAPH_H). * g++.dg/abi/mangle26.C: Also match *C2* definition. * g++.dg/abi/mangle27.C: Likewise. * g++.dg/abi/mangle28.C: Likewise. * g++.dg/abi/mangle29.C: Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@154284 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cgraph.c')
-rw-r--r--gcc/cgraph.c144
1 files changed, 135 insertions, 9 deletions
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 391882ed2c8..02beae92469 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -425,7 +425,11 @@ cgraph_node_for_decl (tree decl)
key.decl = decl;
slot = htab_find_slot (cgraph_hash, &key, NO_INSERT);
if (slot && *slot)
- node = (struct cgraph_node *) *slot;
+ {
+ node = (struct cgraph_node *) *slot;
+ if (node->same_body_alias)
+ node = node->same_body;
+ }
}
return node;
@@ -442,10 +446,10 @@ eq_node (const void *p1, const void *p2)
return DECL_UID (n1->decl) == DECL_UID (n2->decl);
}
-/* Allocate new callgraph node and insert it into basic data structures. */
+/* Allocate new callgraph node. */
-static struct cgraph_node *
-cgraph_create_node (void)
+static inline struct cgraph_node *
+cgraph_allocate_node (void)
{
struct cgraph_node *node;
@@ -460,6 +464,16 @@ cgraph_create_node (void)
node->uid = cgraph_max_uid++;
}
+ return node;
+}
+
+/* Allocate new callgraph node and insert it into basic data structures. */
+
+static struct cgraph_node *
+cgraph_create_node (void)
+{
+ struct cgraph_node *node = cgraph_allocate_node ();
+
node->next = cgraph_nodes;
node->pid = -1;
node->order = cgraph_order++;
@@ -491,6 +505,8 @@ cgraph_node (tree decl)
if (*slot)
{
node = *slot;
+ if (node->same_body_alias)
+ node = node->same_body;
return node;
}
@@ -521,6 +537,52 @@ cgraph_node (tree decl)
return node;
}
+/* Attempt to mark ALIAS as an alias to DECL. Return TRUE if successful.
+ Same body aliases are output whenever the body of DECL is output,
+ and cgraph_node (ALIAS) transparently returns cgraph_node (DECL). */
+
+bool
+cgraph_same_body_alias (tree alias, tree decl)
+{
+ struct cgraph_node key, *alias_node, *decl_node, **slot;
+
+ gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+ gcc_assert (TREE_CODE (alias) == FUNCTION_DECL);
+ gcc_assert (!assembler_name_hash);
+
+#ifndef ASM_OUTPUT_DEF
+ /* If aliases aren't supported by the assembler, fail. */
+ return false;
+#endif
+
+ /* Comdat same body aliases are only supported when comdat groups
+ are supported and the symbols are weak. */
+ if (DECL_ONE_ONLY (decl) && (!HAVE_COMDAT_GROUP || !DECL_WEAK (decl)))
+ return false;
+
+ decl_node = cgraph_node (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 false;
+
+ 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;
+ decl_node->same_body = alias_node;
+ *slot = alias_node;
+ return true;
+}
+
/* Returns the cgraph node assigned to DECL or NULL if no cgraph node
is assigned. */
@@ -540,7 +602,11 @@ cgraph_get_node (tree decl)
NO_INSERT);
if (slot && *slot)
- node = *slot;
+ {
+ node = *slot;
+ if (node->same_body_alias)
+ node = node->same_body;
+ }
return node;
}
@@ -601,9 +667,23 @@ cgraph_node_for_asm (tree asmname)
it is __builtin_strlen and strlen, for instance. Do we need to
record them all? Original implementation marked just first one
so lets hope for the best. */
- if (*slot)
- continue;
- *slot = node;
+ 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;
+ }
+ }
}
}
@@ -612,7 +692,12 @@ cgraph_node_for_asm (tree asmname)
NO_INSERT);
if (slot)
- return (struct cgraph_node *) *slot;
+ {
+ node = (struct cgraph_node *) *slot;
+ if (node->same_body_alias)
+ node = node->same_body;
+ return node;
+ }
return NULL;
}
@@ -1146,6 +1231,44 @@ 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
@@ -1283,6 +1406,9 @@ cgraph_remove_node (struct cgraph_node *node)
node->clone_of->clones = node->clones;
}
+ while (node->same_body)
+ cgraph_remove_same_body_alias (node->same_body);
+
/* While all the clones are removed after being proceeded, the function
itself is kept in the cgraph even after it is compiled. Check whether
we are done with this body and reclaim it proactively if this is the case.