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
This commit is contained in:
parent
a64333b7ea
commit
b25833451b
|
@ -1,3 +1,24 @@
|
|||
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>
|
||||
|
||||
PR other/39888
|
||||
|
|
144
gcc/cgraph.c
144
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.
|
||||
|
|
|
@ -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 *clones;
|
||||
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
|
||||
to the edge to speed up cgraph_edge function. */
|
||||
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 {
|
|||
unsigned alias : 1;
|
||||
/* Set for nodes that was constructed and finalized by frontend. */
|
||||
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;
|
||||
|
@ -416,6 +422,8 @@ struct cgraph_edge *cgraph_create_edge (struct cgraph_node *,
|
|||
|
||||
struct cgraph_node * cgraph_get_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_decl (tree);
|
||||
struct cgraph_edge *cgraph_edge (struct cgraph_node *, gimple);
|
||||
|
|
|
@ -1040,7 +1040,7 @@ cgraph_analyze_functions (void)
|
|||
static void
|
||||
cgraph_emit_thunks (void)
|
||||
{
|
||||
struct cgraph_node *n;
|
||||
struct cgraph_node *n, *alias;
|
||||
|
||||
for (n = cgraph_nodes; n; n = n->next)
|
||||
{
|
||||
|
@ -1053,7 +1053,12 @@ cgraph_emit_thunks (void)
|
|||
cgraph_mark_functions_to_output in cgraph_optimize). */
|
||||
if (n->reachable
|
||||
&& !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)
|
|||
/* Make sure that BE didn't give up on compiling. */
|
||||
gcc_assert (TREE_ASM_WRITTEN (decl));
|
||||
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));
|
||||
cgraph_release_function_body (node);
|
||||
/* Eliminate all call edges. This is important so the GIMPLE_CALL no longer
|
||||
|
@ -1924,7 +1937,22 @@ cgraph_materialize_all_clones (void)
|
|||
{
|
||||
gimple new_stmt;
|
||||
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)
|
||||
{
|
||||
fprintf (cgraph_dump_file, "updating call of %s in %s:",
|
||||
|
|
|
@ -1,3 +1,18 @@
|
|||
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>
|
||||
|
||||
PR c++/42058
|
||||
|
|
|
@ -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/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) \
|
||||
$(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) \
|
||||
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 \
|
||||
|
|
|
@ -5037,6 +5037,7 @@ extern void finish_eh_cleanup (tree);
|
|||
extern void emit_associated_thunks (tree);
|
||||
extern void finish_mem_initializers (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 check_accessibility_of_qualified_id (tree, tree, tree);
|
||||
extern tree finish_qualified_id_expr (tree, tree, bool, bool,
|
||||
|
|
|
@ -3658,7 +3658,19 @@ cp_write_global_declarations (void)
|
|||
if (DECL_NOT_REALLY_EXTERN (decl)
|
||||
&& DECL_INITIAL (decl)
|
||||
&& decl_needed_p (decl))
|
||||
DECL_EXTERNAL (decl) = 0;
|
||||
{
|
||||
struct cgraph_node *node = cgraph_get_node (decl), *alias;
|
||||
|
||||
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
|
||||
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
|
|||
#include "tree-dump.h"
|
||||
#include "gimple.h"
|
||||
#include "tree-iterator.h"
|
||||
#include "cgraph.h"
|
||||
|
||||
/* Prototypes. */
|
||||
|
||||
|
@ -149,8 +150,10 @@ bool
|
|||
maybe_clone_body (tree fn)
|
||||
{
|
||||
tree clone;
|
||||
tree complete_dtor = NULL_TREE;
|
||||
tree fns[3];
|
||||
bool first = true;
|
||||
bool in_charge_parm_used;
|
||||
int idx;
|
||||
|
||||
/* We only clone constructors and destructors. */
|
||||
if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
|
||||
|
@ -160,25 +163,40 @@ maybe_clone_body (tree fn)
|
|||
/* Emit the DWARF1 abstract instance. */
|
||||
(*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
|
||||
delete destructor. */
|
||||
FOR_EACH_CLONE (clone, fn)
|
||||
if (DECL_NAME (clone) == complete_dtor_identifier)
|
||||
{
|
||||
complete_dtor = clone;
|
||||
break;
|
||||
}
|
||||
if (DECL_NAME (clone) == complete_dtor_identifier
|
||||
|| DECL_NAME (clone) == complete_ctor_identifier)
|
||||
fns[1] = clone;
|
||||
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
|
||||
list. */
|
||||
push_to_top_level ();
|
||||
FOR_EACH_CLONE (clone, fn)
|
||||
for (idx = 0; idx < 3; idx++)
|
||||
{
|
||||
tree parm;
|
||||
tree clone_parm;
|
||||
int parmno;
|
||||
bool alias = false;
|
||||
struct pointer_map_t *decl_map;
|
||||
|
||||
clone = fns[idx];
|
||||
if (!clone)
|
||||
continue;
|
||||
|
||||
/* Update CLONE's source position information to match FN's. */
|
||||
DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn);
|
||||
DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn);
|
||||
|
@ -223,12 +241,25 @@ maybe_clone_body (tree fn)
|
|||
/* Start processing the function. */
|
||||
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
|
||||
and delete function. */
|
||||
if (DECL_NAME (clone) == deleting_dtor_identifier)
|
||||
build_delete_destructor_body (clone, complete_dtor);
|
||||
if (idx == 2)
|
||||
build_delete_destructor_body (clone, fns[1]);
|
||||
else if (alias)
|
||||
/* No need to populate body. */ ;
|
||||
else
|
||||
{
|
||||
{
|
||||
/* Remap the parameters. */
|
||||
decl_map = pointer_map_create ();
|
||||
for (parmno = 0,
|
||||
|
@ -291,7 +322,10 @@ maybe_clone_body (tree fn)
|
|||
/* Now, expand this function into RTL, if appropriate. */
|
||||
finish_function (0);
|
||||
BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
|
||||
expand_or_defer_fn (clone);
|
||||
if (alias)
|
||||
expand_or_defer_fn_1 (clone);
|
||||
else
|
||||
expand_or_defer_fn (clone);
|
||||
first = false;
|
||||
}
|
||||
pop_from_top_level ();
|
||||
|
|
|
@ -3315,8 +3315,8 @@ emit_associated_thunks (tree fn)
|
|||
|
||||
/* Generate RTL for FN. */
|
||||
|
||||
void
|
||||
expand_or_defer_fn (tree fn)
|
||||
bool
|
||||
expand_or_defer_fn_1 (tree fn)
|
||||
{
|
||||
/* When the parser calls us after finishing the body of a template
|
||||
function, we don't really want to expand the body. */
|
||||
|
@ -3330,7 +3330,7 @@ expand_or_defer_fn (tree fn)
|
|||
is not a GC root. */
|
||||
if (!function_depth)
|
||||
ggc_collect ();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
gcc_assert (DECL_SAVED_TREE (fn));
|
||||
|
@ -3343,7 +3343,7 @@ expand_or_defer_fn (tree fn)
|
|||
it out, even though we haven't. */
|
||||
TREE_ASM_WRITTEN (fn) = 1;
|
||||
DECL_SAVED_TREE (fn) = NULL_TREE;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We make a decision about linkage for these functions at the end
|
||||
|
@ -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
|
||||
semantic analysis; this code just generates RTL. */
|
||||
if (flag_syntax_only)
|
||||
return;
|
||||
return false;
|
||||
|
||||
function_depth++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Expand or defer, at the whim of the compilation unit manager. */
|
||||
cgraph_finalize_function (fn, function_depth > 1);
|
||||
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. */
|
||||
cgraph_finalize_function (fn, function_depth > 1);
|
||||
|
||||
function_depth--;
|
||||
}
|
||||
}
|
||||
|
||||
struct nrv_data
|
||||
|
|
|
@ -306,6 +306,23 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
|
|||
lto_output_sleb128_stream (ob->main_stream,
|
||||
node->global.estimated_growth);
|
||||
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. */
|
||||
|
@ -495,6 +512,7 @@ input_node (struct lto_file_decl_data *file_data,
|
|||
int self_size = 0;
|
||||
int time_inlining_benefit = 0;
|
||||
int size_inlining_benefit = 0;
|
||||
unsigned long same_body_count = 0;
|
||||
bool inlined = false;
|
||||
|
||||
clone_p = (lto_input_uleb128 (ib) != 0);
|
||||
|
@ -528,6 +546,7 @@ input_node (struct lto_file_decl_data *file_data,
|
|||
size = lto_input_sleb128 (ib);
|
||||
estimated_growth = lto_input_sleb128 (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
|
||||
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,
|
|||
node->global.estimated_growth = estimated_growth;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -221,6 +221,25 @@ lto_cgraph_replace_node (struct cgraph_node *node,
|
|||
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. */
|
||||
cgraph_remove_node (node);
|
||||
}
|
||||
|
@ -634,7 +653,22 @@ lto_symtab_merge_cgraph_nodes_1 (void **slot, void *data ATTRIBUTE_UNUSED)
|
|||
for (e = prevailing->next; e; e = e->next)
|
||||
{
|
||||
if (e->node != NULL)
|
||||
lto_cgraph_replace_node (e->node, prevailing->node);
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* Drop all but the prevailing decl from the symtab. */
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
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>
|
||||
|
||||
PR debug/41926
|
||||
|
|
|
@ -11,4 +11,4 @@ namespace std {
|
|||
|
||||
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 {
|
|||
|
||||
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 {
|
|||
|
||||
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 {
|
|||
|
||||
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\]" } }
|
||||
|
|
Loading…
Reference in New Issue