cgraph.c (ld_plugin_symbol_resolution_names): New.

* cgraph.c (ld_plugin_symbol_resolution_names): New.
	(dump_cgraph_node): Dump resolution.
	* cgraph.h (ld_plugin_symbol_resolution_names): Declare.
	(cgraph_comdat_can_be_unshared_p): Dclare.
	* lto-streamer-out.c (produce_symtab): Use
	cgraph_comdat_can_be_unshared_p.
	* ipa.c (cgraph_address_taken_from_non_vtable_p): New function.
	(cgraph_comdat_can_be_unshared_p): New function based on logic
	in cgraph_externally_visible_p.
	(cgraph_externally_visible_p): Use it.
	(varpool_externally_visible_p): Virtual tables can be unshared.
	* varpool.c (dump_varpool_node): Dump resolution.

From-SVN: r166985
This commit is contained in:
Jan Hubicka 2010-11-20 21:10:46 +00:00
parent 671769c38a
commit 430c6cebe1
4 changed files with 89 additions and 23 deletions

View File

@ -56,6 +56,7 @@ enum availability
struct lto_file_decl_data;
extern const char * const cgraph_availability_names[];
extern const char * const ld_plugin_symbol_resolution_names[];
/* Function inlining information. */
@ -695,6 +696,7 @@ void varpool_node_set_remove (varpool_node_set, struct varpool_node *);
void dump_varpool_node_set (FILE *, varpool_node_set);
void debug_varpool_node_set (varpool_node_set);
void ipa_discover_readonly_nonaddressable_vars (void);
bool cgraph_comdat_can_be_unshared_p (struct cgraph_node *);
/* In predict.c */
bool cgraph_maybe_hot_edge_p (struct cgraph_edge *e);

View File

@ -588,6 +588,56 @@ ipa_discover_readonly_nonaddressable_vars (void)
fprintf (dump_file, "\n");
}
/* Return true when there is a reference to node and it is not vtable. */
static bool
cgraph_address_taken_from_non_vtable_p (struct cgraph_node *node)
{
int i;
struct ipa_ref *ref;
for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++)
{
struct varpool_node *node;
if (ref->refered_type == IPA_REF_CGRAPH)
return true;
node = ipa_ref_varpool_node (ref);
if (!DECL_VIRTUAL_P (node->decl))
return true;
}
return false;
}
/* COMDAT functions must be shared only if they have address taken,
otherwise we can produce our own private implementation with
-fwhole-program.
Return true when turning COMDAT functoin static can not lead to wrong
code when the resulting object links with a library defining same COMDAT.
Virtual functions do have their addresses taken from the vtables,
but in C++ there is no way to compare their addresses for equality. */
bool
cgraph_comdat_can_be_unshared_p (struct cgraph_node *node)
{
if ((cgraph_address_taken_from_non_vtable_p (node)
&& !DECL_VIRTUAL_P (node->decl))
|| !node->analyzed)
return false;
if (node->same_comdat_group)
{
struct cgraph_node *next;
/* If more than one function is in the same COMDAT group, it must
be shared even if just one function in the comdat group has
address taken. */
for (next = node->same_comdat_group;
next != node; next = next->same_comdat_group)
if (cgraph_address_taken_from_non_vtable_p (node)
&& !DECL_VIRTUAL_P (next->decl))
return false;
}
return true;
}
/* Return true when function NODE should be considered externally visible. */
static bool
@ -613,6 +663,15 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool
if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
return true;
/* When doing LTO or whole program, we can bring COMDAT functoins static.
This improves code quality and we know we will duplicate them at most twice
(in the case that we are not using plugin and link with object file
implementing same COMDAT) */
if ((in_lto_p || whole_program)
&& 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.
@ -635,27 +694,6 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool
;
else if (!whole_program)
return true;
/* COMDAT functions must be shared only if they have address taken,
otherwise we can produce our own private implementation with
-fwhole-program. */
else if (DECL_COMDAT (node->decl))
{
if (node->address_taken || !node->analyzed)
return true;
if (node->same_comdat_group)
{
struct cgraph_node *next;
/* If more than one function is in the same COMDAT group, it must
be shared even if just one function in the comdat group has
address taken. */
for (next = node->same_comdat_group;
next != node;
next = next->same_comdat_group)
if (next->address_taken || !next->analyzed)
return true;
}
}
if (MAIN_NAME_P (DECL_NAME (node->decl)))
return true;
@ -701,6 +739,16 @@ varpool_externally_visible_p (struct varpool_node *vnode, bool aliased)
if (!alias && vnode->resolution == LDPR_PREVAILING_DEF_IRONLY)
return false;
/* As a special case, the COMDAT virutal tables can be unshared.
In LTO mode turn vtables into static variables. The variable is readonly,
so this does not enable more optimization, but referring static var
is faster for dynamic linking. Also this match logic hidding vtables
from LTO symbol tables. */
if ((in_lto_p || flag_whole_program)
&& !vnode->force_output
&& DECL_COMDAT (vnode->decl) && DECL_VIRTUAL_P (vnode->decl))
return false;
/* When doing link time optimizations, hidden symbols become local. */
if (in_lto_p
&& (DECL_VISIBILITY (vnode->decl) == VISIBILITY_HIDDEN

View File

@ -2492,7 +2492,7 @@ produce_symtab (struct output_block *ob,
if (DECL_EXTERNAL (node->decl))
continue;
if (DECL_COMDAT (node->decl)
&& cgraph_can_remove_if_no_direct_calls_p (node))
&& cgraph_comdat_can_be_unshared_p (node))
continue;
if (node->alias || node->global.inlined_to)
continue;
@ -2506,7 +2506,7 @@ produce_symtab (struct output_block *ob,
if (!DECL_EXTERNAL (node->decl))
continue;
if (DECL_COMDAT (node->decl)
&& cgraph_can_remove_if_no_direct_calls_p (node))
&& cgraph_comdat_can_be_unshared_p (node))
continue;
if (node->alias || node->global.inlined_to)
continue;
@ -2521,6 +2521,14 @@ produce_symtab (struct output_block *ob,
vnode = lto_varpool_encoder_deref (varpool_encoder, i);
if (DECL_EXTERNAL (vnode->decl))
continue;
/* COMDAT virtual tables can be unshared. Do not declare them
in the LTO symbol table to prevent linker from forcing them
into the output. */
if (DECL_COMDAT (vnode->decl)
&& !vnode->force_output
&& vnode->finalized
&& DECL_VIRTUAL_P (vnode->decl))
continue;
if (vnode->alias)
continue;
write_symbol (cache, &stream, vnode->decl, seen, false);
@ -2532,6 +2540,11 @@ produce_symtab (struct output_block *ob,
vnode = lto_varpool_encoder_deref (varpool_encoder, i);
if (!DECL_EXTERNAL (vnode->decl))
continue;
if (DECL_COMDAT (vnode->decl)
&& !vnode->force_output
&& vnode->finalized
&& DECL_VIRTUAL_P (vnode->decl))
continue;
if (vnode->alias)
continue;
write_symbol (cache, &stream, vnode->decl, seen, false);

View File

@ -241,6 +241,9 @@ dump_varpool_node (FILE *f, struct varpool_node *node)
fprintf (f, " output");
if (node->externally_visible)
fprintf (f, " externally_visible");
if (node->resolution != LDPR_UNKNOWN)
fprintf (f, " %s",
ld_plugin_symbol_resolution_names[(int)node->resolution]);
if (node->in_other_partition)
fprintf (f, " in_other_partition");
else if (node->used_from_other_partition)