mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-02-20 02:39:45 +08:00
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:
parent
671769c38a
commit
430c6cebe1
@ -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);
|
||||
|
90
gcc/ipa.c
90
gcc/ipa.c
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user