Commit b2583345 by Jakub Jelinek Committed by Jakub Jelinek

re PR c++/3187 (gcc lays down two copies of constructors)

	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.

From-SVN: r154284
parent a64333b7
2009-11-18 Jakub Jelinek <jakub@redhat.com>
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.
2009-11-18 Iain Sandoe <iain.sandoe@sandoe-acoustics.co.uk> 2009-11-18 Iain Sandoe <iain.sandoe@sandoe-acoustics.co.uk>
PR other/39888 PR other/39888
...@@ -425,7 +425,11 @@ cgraph_node_for_decl (tree decl) ...@@ -425,7 +425,11 @@ cgraph_node_for_decl (tree decl)
key.decl = decl; key.decl = decl;
slot = htab_find_slot (cgraph_hash, &key, NO_INSERT); slot = htab_find_slot (cgraph_hash, &key, NO_INSERT);
if (slot && *slot) if (slot && *slot)
{
node = (struct cgraph_node *) *slot; node = (struct cgraph_node *) *slot;
if (node->same_body_alias)
node = node->same_body;
}
} }
return node; return node;
...@@ -442,10 +446,10 @@ eq_node (const void *p1, const void *p2) ...@@ -442,10 +446,10 @@ eq_node (const void *p1, const void *p2)
return DECL_UID (n1->decl) == DECL_UID (n2->decl); 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 * static inline struct cgraph_node *
cgraph_create_node (void) cgraph_allocate_node (void)
{ {
struct cgraph_node *node; struct cgraph_node *node;
...@@ -460,6 +464,16 @@ cgraph_create_node (void) ...@@ -460,6 +464,16 @@ cgraph_create_node (void)
node->uid = cgraph_max_uid++; 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->next = cgraph_nodes;
node->pid = -1; node->pid = -1;
node->order = cgraph_order++; node->order = cgraph_order++;
...@@ -491,6 +505,8 @@ cgraph_node (tree decl) ...@@ -491,6 +505,8 @@ cgraph_node (tree decl)
if (*slot) if (*slot)
{ {
node = *slot; node = *slot;
if (node->same_body_alias)
node = node->same_body;
return node; return node;
} }
...@@ -521,6 +537,52 @@ cgraph_node (tree decl) ...@@ -521,6 +537,52 @@ cgraph_node (tree decl)
return node; 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 /* Returns the cgraph node assigned to DECL or NULL if no cgraph node
is assigned. */ is assigned. */
...@@ -540,7 +602,11 @@ cgraph_get_node (tree decl) ...@@ -540,7 +602,11 @@ cgraph_get_node (tree decl)
NO_INSERT); NO_INSERT);
if (slot && *slot) if (slot && *slot)
{
node = *slot; node = *slot;
if (node->same_body_alias)
node = node->same_body;
}
return node; return node;
} }
...@@ -601,9 +667,23 @@ cgraph_node_for_asm (tree asmname) ...@@ -601,9 +667,23 @@ cgraph_node_for_asm (tree asmname)
it is __builtin_strlen and strlen, for instance. Do we need to it is __builtin_strlen and strlen, for instance. Do we need to
record them all? Original implementation marked just first one record them all? Original implementation marked just first one
so lets hope for the best. */ so lets hope for the best. */
if (*slot) if (!*slot)
continue;
*slot = node; *slot = node;
if (node->same_body)
{
struct cgraph_node *alias;
for (alias = node->same_body; alias; alias = alias->next)
{
hashval_t hash;
name = DECL_ASSEMBLER_NAME (alias->decl);
hash = decl_assembler_name_hash (name);
slot = htab_find_slot_with_hash (assembler_name_hash, name,
hash, INSERT);
if (!*slot)
*slot = alias;
}
}
} }
} }
...@@ -612,7 +692,12 @@ cgraph_node_for_asm (tree asmname) ...@@ -612,7 +692,12 @@ cgraph_node_for_asm (tree asmname)
NO_INSERT); NO_INSERT);
if (slot) 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; return NULL;
} }
...@@ -1146,6 +1231,44 @@ cgraph_release_function_body (struct cgraph_node *node) ...@@ -1146,6 +1231,44 @@ cgraph_release_function_body (struct cgraph_node *node)
DECL_INITIAL (node->decl) = error_mark_node; DECL_INITIAL (node->decl) = error_mark_node;
} }
/* Remove same body alias node. */
void
cgraph_remove_same_body_alias (struct cgraph_node *node)
{
void **slot;
int uid = node->uid;
gcc_assert (node->same_body_alias);
if (node->previous)
node->previous->next = node->next;
else
node->same_body->same_body = node->next;
if (node->next)
node->next->previous = node->previous;
node->next = NULL;
node->previous = NULL;
slot = htab_find_slot (cgraph_hash, node, NO_INSERT);
if (*slot == node)
htab_clear_slot (cgraph_hash, slot);
if (assembler_name_hash)
{
tree name = DECL_ASSEMBLER_NAME (node->decl);
slot = htab_find_slot_with_hash (assembler_name_hash, name,
decl_assembler_name_hash (name),
NO_INSERT);
if (slot && *slot == node)
htab_clear_slot (assembler_name_hash, slot);
}
/* Clear out the node to NULL all pointers and add the node to the free
list. */
memset (node, 0, sizeof(*node));
node->uid = uid;
NEXT_FREE_NODE (node) = free_nodes;
free_nodes = node;
}
/* Remove the node from cgraph. */ /* Remove the node from cgraph. */
void void
...@@ -1283,6 +1406,9 @@ cgraph_remove_node (struct cgraph_node *node) ...@@ -1283,6 +1406,9 @@ cgraph_remove_node (struct cgraph_node *node)
node->clone_of->clones = node->clones; 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 /* While all the clones are removed after being proceeded, the function
itself is kept in the cgraph even after it is compiled. Check whether 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. we are done with this body and reclaim it proactively if this is the case.
......
...@@ -184,6 +184,9 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node { ...@@ -184,6 +184,9 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
struct cgraph_node *prev_sibling_clone; struct cgraph_node *prev_sibling_clone;
struct cgraph_node *clones; struct cgraph_node *clones;
struct cgraph_node *clone_of; struct cgraph_node *clone_of;
/* For normal nodes pointer to the list of alias nodes, in alias
nodes pointer to the normal node. */
struct cgraph_node *same_body;
/* For functions with many calls sites it holds map from call expression /* For functions with many calls sites it holds map from call expression
to the edge to speed up cgraph_edge function. */ to the edge to speed up cgraph_edge function. */
htab_t GTY((param_is (struct cgraph_edge))) call_site_hash; htab_t GTY((param_is (struct cgraph_edge))) call_site_hash;
...@@ -241,6 +244,9 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node { ...@@ -241,6 +244,9 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
unsigned alias : 1; unsigned alias : 1;
/* Set for nodes that was constructed and finalized by frontend. */ /* Set for nodes that was constructed and finalized by frontend. */
unsigned finalized_by_frontend : 1; unsigned finalized_by_frontend : 1;
/* Set for alias nodes, same_body points to the node they are alias of
and they are linked through the next/previous pointers. */
unsigned same_body_alias : 1;
}; };
typedef struct cgraph_node *cgraph_node_ptr; typedef struct cgraph_node *cgraph_node_ptr;
...@@ -416,6 +422,8 @@ struct cgraph_edge *cgraph_create_edge (struct cgraph_node *, ...@@ -416,6 +422,8 @@ struct cgraph_edge *cgraph_create_edge (struct cgraph_node *,
struct cgraph_node * cgraph_get_node (tree); struct cgraph_node * cgraph_get_node (tree);
struct cgraph_node *cgraph_node (tree); struct cgraph_node *cgraph_node (tree);
bool cgraph_same_body_alias (tree, tree);
void cgraph_remove_same_body_alias (struct cgraph_node *);
struct cgraph_node *cgraph_node_for_asm (tree); struct cgraph_node *cgraph_node_for_asm (tree);
struct cgraph_node *cgraph_node_for_decl (tree); struct cgraph_node *cgraph_node_for_decl (tree);
struct cgraph_edge *cgraph_edge (struct cgraph_node *, gimple); struct cgraph_edge *cgraph_edge (struct cgraph_node *, gimple);
......
...@@ -1040,7 +1040,7 @@ cgraph_analyze_functions (void) ...@@ -1040,7 +1040,7 @@ cgraph_analyze_functions (void)
static void static void
cgraph_emit_thunks (void) cgraph_emit_thunks (void)
{ {
struct cgraph_node *n; struct cgraph_node *n, *alias;
for (n = cgraph_nodes; n; n = n->next) for (n = cgraph_nodes; n; n = n->next)
{ {
...@@ -1053,7 +1053,12 @@ cgraph_emit_thunks (void) ...@@ -1053,7 +1053,12 @@ cgraph_emit_thunks (void)
cgraph_mark_functions_to_output in cgraph_optimize). */ cgraph_mark_functions_to_output in cgraph_optimize). */
if (n->reachable if (n->reachable
&& !DECL_EXTERNAL (n->decl)) && !DECL_EXTERNAL (n->decl))
{
lang_hooks.callgraph.emit_associated_thunks (n->decl); lang_hooks.callgraph.emit_associated_thunks (n->decl);
for (alias = n->same_body; alias; alias = alias->next)
if (!DECL_EXTERNAL (alias->decl))
lang_hooks.callgraph.emit_associated_thunks (alias->decl);
}
} }
} }
...@@ -1175,6 +1180,14 @@ cgraph_expand_function (struct cgraph_node *node) ...@@ -1175,6 +1180,14 @@ cgraph_expand_function (struct cgraph_node *node)
/* Make sure that BE didn't give up on compiling. */ /* Make sure that BE didn't give up on compiling. */
gcc_assert (TREE_ASM_WRITTEN (decl)); gcc_assert (TREE_ASM_WRITTEN (decl));
current_function_decl = NULL; current_function_decl = NULL;
if (node->same_body)
{
struct cgraph_node *alias;
bool saved_alias = node->alias;
for (alias = node->same_body; alias; alias = alias->next)
assemble_alias (alias->decl, DECL_ASSEMBLER_NAME (decl));
node->alias = saved_alias;
}
gcc_assert (!cgraph_preserve_function_body_p (decl)); gcc_assert (!cgraph_preserve_function_body_p (decl));
cgraph_release_function_body (node); cgraph_release_function_body (node);
/* Eliminate all call edges. This is important so the GIMPLE_CALL no longer /* Eliminate all call edges. This is important so the GIMPLE_CALL no longer
...@@ -1925,6 +1938,21 @@ cgraph_materialize_all_clones (void) ...@@ -1925,6 +1938,21 @@ cgraph_materialize_all_clones (void)
gimple new_stmt; gimple new_stmt;
gimple_stmt_iterator gsi; gimple_stmt_iterator gsi;
if (e->callee->same_body)
{
struct cgraph_node *alias;
for (alias = e->callee->same_body;
alias;
alias = alias->next)
if (decl == alias->decl)
break;
/* Don't update call from same body alias to the real
function. */
if (alias)
continue;
}
if (cgraph_dump_file) if (cgraph_dump_file)
{ {
fprintf (cgraph_dump_file, "updating call of %s in %s:", fprintf (cgraph_dump_file, "updating call of %s in %s:",
......
2009-11-18 Jakub Jelinek <jakub@redhat.com>
PR c++/3187
* 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).
2009-11-17 Paolo Carlini <paolo.carlini@oracle.com> 2009-11-17 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/42058 PR c++/42058
......
...@@ -303,7 +303,7 @@ cp/semantics.o: cp/semantics.c $(CXX_TREE_H) $(TM_H) except.h toplev.h \ ...@@ -303,7 +303,7 @@ cp/semantics.o: cp/semantics.c $(CXX_TREE_H) $(TM_H) except.h toplev.h \
cp/dump.o: cp/dump.c $(CXX_TREE_H) $(TM_H) $(TREE_DUMP_H) cp/dump.o: cp/dump.c $(CXX_TREE_H) $(TM_H) $(TREE_DUMP_H)
cp/optimize.o: cp/optimize.c $(CXX_TREE_H) $(TM_H) rtl.h $(INTEGRATE_H) \ cp/optimize.o: cp/optimize.c $(CXX_TREE_H) $(TM_H) rtl.h $(INTEGRATE_H) \
insn-config.h input.h $(PARAMS_H) debug.h $(TREE_INLINE_H) $(GIMPLE_H) \ insn-config.h input.h $(PARAMS_H) debug.h $(TREE_INLINE_H) $(GIMPLE_H) \
$(TARGET_H) tree-iterator.h $(TARGET_H) tree-iterator.h $(CGRAPH_H)
cp/mangle.o: cp/mangle.c $(CXX_TREE_H) $(TM_H) toplev.h $(REAL_H) \ cp/mangle.o: cp/mangle.c $(CXX_TREE_H) $(TM_H) toplev.h $(REAL_H) \
gt-cp-mangle.h $(TARGET_H) $(TM_P_H) gt-cp-mangle.h $(TARGET_H) $(TM_P_H)
cp/parser.o: cp/parser.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_H) gt-cp-parser.h \ cp/parser.o: cp/parser.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_H) gt-cp-parser.h \
......
...@@ -5037,6 +5037,7 @@ extern void finish_eh_cleanup (tree); ...@@ -5037,6 +5037,7 @@ extern void finish_eh_cleanup (tree);
extern void emit_associated_thunks (tree); extern void emit_associated_thunks (tree);
extern void finish_mem_initializers (tree); extern void finish_mem_initializers (tree);
extern tree check_template_template_default_arg (tree); extern tree check_template_template_default_arg (tree);
extern bool expand_or_defer_fn_1 (tree);
extern void expand_or_defer_fn (tree); extern void expand_or_defer_fn (tree);
extern void check_accessibility_of_qualified_id (tree, tree, tree); extern void check_accessibility_of_qualified_id (tree, tree, tree);
extern tree finish_qualified_id_expr (tree, tree, bool, bool, extern tree finish_qualified_id_expr (tree, tree, bool, bool,
......
...@@ -3658,7 +3658,19 @@ cp_write_global_declarations (void) ...@@ -3658,7 +3658,19 @@ cp_write_global_declarations (void)
if (DECL_NOT_REALLY_EXTERN (decl) if (DECL_NOT_REALLY_EXTERN (decl)
&& DECL_INITIAL (decl) && DECL_INITIAL (decl)
&& decl_needed_p (decl)) && decl_needed_p (decl))
{
struct cgraph_node *node = cgraph_get_node (decl), *alias;
DECL_EXTERNAL (decl) = 0; DECL_EXTERNAL (decl) = 0;
/* If we mark !DECL_EXTERNAL one of the same body aliases,
we need to mark all of them that way. */
if (node && node->same_body)
{
DECL_EXTERNAL (node->decl) = 0;
for (alias = node->same_body; alias; alias = alias->next)
DECL_EXTERNAL (alias->decl) = 0;
}
}
/* If we're going to need to write this function out, and /* If we're going to need to write this function out, and
there's already a body for it, create RTL for it now. there's already a body for it, create RTL for it now.
......
...@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-dump.h" #include "tree-dump.h"
#include "gimple.h" #include "gimple.h"
#include "tree-iterator.h" #include "tree-iterator.h"
#include "cgraph.h"
/* Prototypes. */ /* Prototypes. */
...@@ -149,8 +150,10 @@ bool ...@@ -149,8 +150,10 @@ bool
maybe_clone_body (tree fn) maybe_clone_body (tree fn)
{ {
tree clone; tree clone;
tree complete_dtor = NULL_TREE; tree fns[3];
bool first = true; bool first = true;
bool in_charge_parm_used;
int idx;
/* We only clone constructors and destructors. */ /* We only clone constructors and destructors. */
if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn) if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
...@@ -160,25 +163,40 @@ maybe_clone_body (tree fn) ...@@ -160,25 +163,40 @@ maybe_clone_body (tree fn)
/* Emit the DWARF1 abstract instance. */ /* Emit the DWARF1 abstract instance. */
(*debug_hooks->deferred_inline_function) (fn); (*debug_hooks->deferred_inline_function) (fn);
in_charge_parm_used = CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fn)) != NULL;
fns[0] = NULL_TREE;
fns[1] = NULL_TREE;
fns[2] = NULL_TREE;
/* Look for the complete destructor which may be used to build the /* Look for the complete destructor which may be used to build the
delete destructor. */ delete destructor. */
FOR_EACH_CLONE (clone, fn) FOR_EACH_CLONE (clone, fn)
if (DECL_NAME (clone) == complete_dtor_identifier) if (DECL_NAME (clone) == complete_dtor_identifier
{ || DECL_NAME (clone) == complete_ctor_identifier)
complete_dtor = clone; fns[1] = clone;
break; else if (DECL_NAME (clone) == base_dtor_identifier
} || DECL_NAME (clone) == base_ctor_identifier)
fns[0] = clone;
else if (DECL_NAME (clone) == deleting_dtor_identifier)
fns[2] = clone;
else
gcc_unreachable ();
/* We know that any clones immediately follow FN in the TYPE_METHODS /* We know that any clones immediately follow FN in the TYPE_METHODS
list. */ list. */
push_to_top_level (); push_to_top_level ();
FOR_EACH_CLONE (clone, fn) for (idx = 0; idx < 3; idx++)
{ {
tree parm; tree parm;
tree clone_parm; tree clone_parm;
int parmno; int parmno;
bool alias = false;
struct pointer_map_t *decl_map; struct pointer_map_t *decl_map;
clone = fns[idx];
if (!clone)
continue;
/* Update CLONE's source position information to match FN's. */ /* Update CLONE's source position information to match FN's. */
DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn); DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn);
DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn); DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn);
...@@ -223,10 +241,23 @@ maybe_clone_body (tree fn) ...@@ -223,10 +241,23 @@ maybe_clone_body (tree fn)
/* Start processing the function. */ /* Start processing the function. */
start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED); start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED);
/* Tell cgraph if both ctors or both dtors are known to have
the same body. */
if (!in_charge_parm_used
&& fns[0]
&& idx == 1
&& !flag_use_repository
&& DECL_INTERFACE_KNOWN (fns[0])
&& !DECL_ONE_ONLY (fns[0])
&& cgraph_same_body_alias (clone, fns[0]))
alias = true;
/* Build the delete destructor by calling complete destructor /* Build the delete destructor by calling complete destructor
and delete function. */ and delete function. */
if (DECL_NAME (clone) == deleting_dtor_identifier) if (idx == 2)
build_delete_destructor_body (clone, complete_dtor); build_delete_destructor_body (clone, fns[1]);
else if (alias)
/* No need to populate body. */ ;
else else
{ {
/* Remap the parameters. */ /* Remap the parameters. */
...@@ -291,6 +322,9 @@ maybe_clone_body (tree fn) ...@@ -291,6 +322,9 @@ maybe_clone_body (tree fn)
/* Now, expand this function into RTL, if appropriate. */ /* Now, expand this function into RTL, if appropriate. */
finish_function (0); finish_function (0);
BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn); BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
if (alias)
expand_or_defer_fn_1 (clone);
else
expand_or_defer_fn (clone); expand_or_defer_fn (clone);
first = false; first = false;
} }
......
...@@ -3315,8 +3315,8 @@ emit_associated_thunks (tree fn) ...@@ -3315,8 +3315,8 @@ emit_associated_thunks (tree fn)
/* Generate RTL for FN. */ /* Generate RTL for FN. */
void bool
expand_or_defer_fn (tree fn) expand_or_defer_fn_1 (tree fn)
{ {
/* When the parser calls us after finishing the body of a template /* When the parser calls us after finishing the body of a template
function, we don't really want to expand the body. */ function, we don't really want to expand the body. */
...@@ -3330,7 +3330,7 @@ expand_or_defer_fn (tree fn) ...@@ -3330,7 +3330,7 @@ expand_or_defer_fn (tree fn)
is not a GC root. */ is not a GC root. */
if (!function_depth) if (!function_depth)
ggc_collect (); ggc_collect ();
return; return false;
} }
gcc_assert (DECL_SAVED_TREE (fn)); gcc_assert (DECL_SAVED_TREE (fn));
...@@ -3343,7 +3343,7 @@ expand_or_defer_fn (tree fn) ...@@ -3343,7 +3343,7 @@ expand_or_defer_fn (tree fn)
it out, even though we haven't. */ it out, even though we haven't. */
TREE_ASM_WRITTEN (fn) = 1; TREE_ASM_WRITTEN (fn) = 1;
DECL_SAVED_TREE (fn) = NULL_TREE; DECL_SAVED_TREE (fn) = NULL_TREE;
return; return false;
} }
/* We make a decision about linkage for these functions at the end /* We make a decision about linkage for these functions at the end
...@@ -3390,14 +3390,23 @@ expand_or_defer_fn (tree fn) ...@@ -3390,14 +3390,23 @@ expand_or_defer_fn (tree fn)
/* There's no reason to do any of the work here if we're only doing /* There's no reason to do any of the work here if we're only doing
semantic analysis; this code just generates RTL. */ semantic analysis; this code just generates RTL. */
if (flag_syntax_only) if (flag_syntax_only)
return; return false;
return true;
}
void
expand_or_defer_fn (tree fn)
{
if (expand_or_defer_fn_1 (fn))
{
function_depth++; function_depth++;
/* Expand or defer, at the whim of the compilation unit manager. */ /* Expand or defer, at the whim of the compilation unit manager. */
cgraph_finalize_function (fn, function_depth > 1); cgraph_finalize_function (fn, function_depth > 1);
function_depth--; function_depth--;
}
} }
struct nrv_data struct nrv_data
......
...@@ -306,6 +306,23 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, ...@@ -306,6 +306,23 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
lto_output_sleb128_stream (ob->main_stream, lto_output_sleb128_stream (ob->main_stream,
node->global.estimated_growth); node->global.estimated_growth);
lto_output_uleb128_stream (ob->main_stream, node->global.inlined); lto_output_uleb128_stream (ob->main_stream, node->global.inlined);
if (node->same_body)
{
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);
alias = alias->previous;
}
while (alias);
}
else
lto_output_uleb128_stream (ob->main_stream, 0);
} }
/* Stream out profile_summary to OB. */ /* Stream out profile_summary to OB. */
...@@ -495,6 +512,7 @@ input_node (struct lto_file_decl_data *file_data, ...@@ -495,6 +512,7 @@ input_node (struct lto_file_decl_data *file_data,
int self_size = 0; int self_size = 0;
int time_inlining_benefit = 0; int time_inlining_benefit = 0;
int size_inlining_benefit = 0; int size_inlining_benefit = 0;
unsigned long same_body_count = 0;
bool inlined = false; bool inlined = false;
clone_p = (lto_input_uleb128 (ib) != 0); clone_p = (lto_input_uleb128 (ib) != 0);
...@@ -528,6 +546,7 @@ input_node (struct lto_file_decl_data *file_data, ...@@ -528,6 +546,7 @@ input_node (struct lto_file_decl_data *file_data,
size = lto_input_sleb128 (ib); size = lto_input_sleb128 (ib);
estimated_growth = lto_input_sleb128 (ib); estimated_growth = lto_input_sleb128 (ib);
inlined = lto_input_uleb128 (ib); inlined = lto_input_uleb128 (ib);
same_body_count = lto_input_uleb128 (ib);
/* Make sure that we have not read this node before. Nodes that /* Make sure that we have not read this node before. Nodes that
have already been read will have their tag stored in the 'aux' have already been read will have their tag stored in the 'aux'
...@@ -553,6 +572,13 @@ input_node (struct lto_file_decl_data *file_data, ...@@ -553,6 +572,13 @@ input_node (struct lto_file_decl_data *file_data,
node->global.estimated_growth = estimated_growth; node->global.estimated_growth = estimated_growth;
node->global.inlined = inlined; node->global.inlined = inlined;
while (same_body_count-- > 0)
{
tree alias_decl;
decl_index = lto_input_uleb128 (ib);
alias_decl = lto_file_decl_data_get_fn_decl (file_data, decl_index);
cgraph_same_body_alias (alias_decl, fn_decl);
}
return node; return node;
} }
......
...@@ -221,6 +221,25 @@ lto_cgraph_replace_node (struct cgraph_node *node, ...@@ -221,6 +221,25 @@ lto_cgraph_replace_node (struct cgraph_node *node,
cgraph_remove_edge (e); cgraph_remove_edge (e);
} }
if (node->same_body)
{
struct cgraph_node *alias;
for (alias = node->same_body; alias; alias = alias->next)
if (DECL_ASSEMBLER_NAME_SET_P (alias->decl))
{
lto_symtab_entry_t se
= lto_symtab_get (DECL_ASSEMBLER_NAME (alias->decl));
for (; se; se = se->next)
if (se->node == node)
{
se->node = NULL;
break;
}
}
}
/* Finally remove the replaced node. */ /* Finally remove the replaced node. */
cgraph_remove_node (node); cgraph_remove_node (node);
} }
...@@ -634,8 +653,23 @@ lto_symtab_merge_cgraph_nodes_1 (void **slot, void *data ATTRIBUTE_UNUSED) ...@@ -634,8 +653,23 @@ lto_symtab_merge_cgraph_nodes_1 (void **slot, void *data ATTRIBUTE_UNUSED)
for (e = prevailing->next; e; e = e->next) for (e = prevailing->next; e; e = e->next)
{ {
if (e->node != NULL) if (e->node != NULL)
{
if (e->node->decl != e->decl && e->node->same_body)
{
struct cgraph_node *alias;
for (alias = e->node->same_body; alias; alias = alias->next)
if (alias->decl == e->decl)
break;
if (alias)
{
cgraph_remove_same_body_alias (alias);
continue;
}
}
lto_cgraph_replace_node (e->node, prevailing->node); lto_cgraph_replace_node (e->node, prevailing->node);
} }
}
/* Drop all but the prevailing decl from the symtab. */ /* Drop all but the prevailing decl from the symtab. */
prevailing->next = NULL; prevailing->next = NULL;
......
2009-11-18 Jakub Jelinek <jakub@redhat.com>
PR c++/3187
* 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.
2009-11-18 Alexandre Oliva <aoliva@redhat.com> 2009-11-18 Alexandre Oliva <aoliva@redhat.com>
PR debug/41926 PR debug/41926
......
...@@ -11,4 +11,4 @@ namespace std { ...@@ -11,4 +11,4 @@ namespace std {
std::A a; std::A a;
// { dg-final { scan-assembler "\n_?_ZNSt1AC1Ev\[: \t\n\]" } } // { dg-final { scan-assembler "\n_?_ZNSt1AC\[12\]Ev\[: \t\n\]" } }
...@@ -11,4 +11,4 @@ namespace std { ...@@ -11,4 +11,4 @@ namespace std {
std::basic_iostream<char,std::char_traits<char> > s1; std::basic_iostream<char,std::char_traits<char> > s1;
// { dg-final { scan-assembler "\n_?_ZNSdC1Ev\[: \t\n\]" } } // { dg-final { scan-assembler "\n_?_ZNSdC\[12\]Ev\[: \t\n\]" } }
...@@ -11,4 +11,4 @@ namespace std { ...@@ -11,4 +11,4 @@ namespace std {
std::basic_istream<char,std::char_traits<char> > s1; std::basic_istream<char,std::char_traits<char> > s1;
// { dg-final { scan-assembler "\n_?_ZNSiC1Ev\[: \t\n\]" } } // { dg-final { scan-assembler "\n_?_ZNSiC\[12\]Ev\[: \t\n\]" } }
...@@ -11,4 +11,4 @@ namespace std { ...@@ -11,4 +11,4 @@ namespace std {
std::basic_ostream<char,std::char_traits<char> > s1; std::basic_ostream<char,std::char_traits<char> > s1;
// { dg-final { scan-assembler "\n_?_ZNSoC1Ev\[: \t\n\]" } } // { dg-final { scan-assembler "\n_?_ZNSoC\[12\]Ev\[: \t\n\]" } }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment