cgraph.c (cgraph_function_body_availability): Do not check cgrpah flags.

* cgraph.c (cgraph_function_body_availability): Do not check cgrpah flags.
	* cgraph.h (symtab_for_node_and_aliases, symtab_nonoverwritable_alias,
	symtab_node_availability): Declare.
	* ipa.c (can_replace_by_local_alias): New.
	(function_and_variable_visibility): Use it.
	* symtab.c (symtab_for_node_and_aliases, symtab_nonoverwritable_alias_1,
	symtab_nonoverwritable_alias): New.

Co-Authored-By: Martin Liska <marxin.liska@gmail.com>

From-SVN: r201439
This commit is contained in:
Jan Hubicka 2013-08-02 16:38:15 +02:00 committed by Jan Hubicka
parent 01e54ef86f
commit af15184ab6
5 changed files with 146 additions and 2 deletions

View file

@ -1,3 +1,14 @@
2013-08-02 Jan Hubicka <jh@suse.cz>
Martin Liska <marxin.liska@gmail.com>
* cgraph.c (cgraph_function_body_availability): Do not check cgrpah flags.
* cgraph.h (symtab_for_node_and_aliases, symtab_nonoverwritable_alias,
symtab_node_availability): Declare.
* ipa.c (can_replace_by_local_alias): New.
(function_and_variable_visibility): Use it.
* symtab.c (symtab_for_node_and_aliases, symtab_nonoverwritable_alias_1,
symtab_nonoverwritable_alias): New.
2013-08-02 Vladimir Makarov <vmakarov@redhat.com>
PR rtl-optimization/57963

View file

@ -1697,7 +1697,6 @@ enum availability
cgraph_function_body_availability (struct cgraph_node *node)
{
enum availability avail;
gcc_assert (cgraph_function_flags_ready);
if (!node->symbol.analyzed)
avail = AVAIL_NOT_AVAILABLE;
else if (node->local.local)

View file

@ -597,6 +597,12 @@ symtab_node symtab_alias_ultimate_target (symtab_node,
enum availability *avail = NULL);
bool symtab_resolve_alias (symtab_node node, symtab_node target);
void fixup_same_cpp_alias_visibility (symtab_node node, symtab_node target);
bool symtab_for_node_and_aliases (symtab_node,
bool (*) (symtab_node, void *),
void *,
bool);
symtab_node symtab_nonoverwritable_alias (symtab_node);
enum availability symtab_node_availability (symtab_node);
/* In cgraph.c */
void dump_cgraph (FILE *);

View file

@ -751,6 +751,21 @@ varpool_externally_visible_p (struct varpool_node *vnode)
return false;
}
/* Return true if reference to NODE can be replaced by a local alias.
Local aliases save dynamic linking overhead and enable more optimizations.
*/
bool
can_replace_by_local_alias (symtab_node node)
{
return (symtab_node_availability (node) > AVAIL_OVERWRITABLE
&& !DECL_EXTERNAL (node->symbol.decl)
&& (!DECL_ONE_ONLY (node->symbol.decl)
|| node->symbol.resolution == LDPR_PREVAILING_DEF
|| node->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY
|| node->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY_EXP));
}
/* Mark visibility of all functions.
A local function is one whose calls can occur only in the current
@ -872,7 +887,36 @@ function_and_variable_visibility (bool whole_program)
}
}
FOR_EACH_DEFINED_FUNCTION (node)
node->local.local = cgraph_local_node_p (node);
{
node->local.local = cgraph_local_node_p (node);
/* If we know that function can not be overwritten by a different semantics
and moreover its section can not be discarded, replace all direct calls
by calls to an nonoverwritable alias. This make dynamic linking
cheaper and enable more optimization.
TODO: We can also update virtual tables. */
if (node->callers && can_replace_by_local_alias ((symtab_node)node))
{
struct cgraph_node *alias = cgraph (symtab_nonoverwritable_alias ((symtab_node) node));
if (alias != node)
{
while (node->callers)
{
struct cgraph_edge *e = node->callers;
cgraph_redirect_edge_callee (e, alias);
if (!flag_wpa)
{
push_cfun (DECL_STRUCT_FUNCTION (e->caller->symbol.decl));
cgraph_redirect_edge_call_stmt_to_callee (e);
pop_cfun ();
}
}
}
}
}
FOR_EACH_VARIABLE (vnode)
{
/* weak flag makes no sense on local variables. */

View file

@ -1014,4 +1014,88 @@ symtab_resolve_alias (symtab_node node, symtab_node target)
symtab_alias_ultimate_target (target, NULL)->symbol.address_taken = true;
return true;
}
/* Call calback on NODE and aliases associated to NODE.
When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
skipped. */
bool
symtab_for_node_and_aliases (symtab_node node,
bool (*callback) (symtab_node, void *),
void *data,
bool include_overwritable)
{
int i;
struct ipa_ref *ref;
if (callback (node, data))
return true;
for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, i, ref); i++)
if (ref->use == IPA_REF_ALIAS)
{
symtab_node alias = ref->referring;
if (include_overwritable
|| symtab_node_availability (alias) > AVAIL_OVERWRITABLE)
if (symtab_for_node_and_aliases (alias, callback, data,
include_overwritable))
return true;
}
return false;
}
/* Worker searching nonoverwritable alias. */
static bool
symtab_nonoverwritable_alias_1 (symtab_node node, void *data)
{
if (decl_binds_to_current_def_p (node->symbol.decl))
{
*(symtab_node *)data = node;
return true;
}
return false;
}
/* If NODE can not be overwriten by static or dynamic linker to point to different
definition, return NODE. Otherwise look for alias with such property and if
none exists, introduce new one. */
symtab_node
symtab_nonoverwritable_alias (symtab_node node)
{
tree new_decl;
symtab_node new_node = NULL;
symtab_for_node_and_aliases (node, symtab_nonoverwritable_alias_1,
(void *)&new_node, true);
if (new_node)
return new_node;
new_decl = copy_node (node->symbol.decl);
DECL_NAME (new_decl) = clone_function_name (node->symbol.decl, "localalias");
if (TREE_CODE (new_decl) == FUNCTION_DECL)
DECL_STRUCT_FUNCTION (new_decl) = NULL;
DECL_INITIAL (new_decl) = NULL;
SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
SET_DECL_RTL (new_decl, NULL);
/* Update the properties. */
DECL_EXTERNAL (new_decl) = 0;
if (DECL_ONE_ONLY (node->symbol.decl))
DECL_SECTION_NAME (new_decl) = NULL;
DECL_COMDAT_GROUP (new_decl) = 0;
TREE_PUBLIC (new_decl) = 0;
DECL_COMDAT (new_decl) = 0;
DECL_WEAK (new_decl) = 0;
DECL_VIRTUAL_P (new_decl) = 0;
if (TREE_CODE (new_decl) == FUNCTION_DECL)
{
DECL_STATIC_CONSTRUCTOR (new_decl) = 0;
DECL_STATIC_DESTRUCTOR (new_decl) = 0;
new_node = (symtab_node) cgraph_create_function_alias (new_decl, node->symbol.decl);
}
else
new_node = (symtab_node) varpool_create_variable_alias (new_decl, node->symbol.decl);
symtab_resolve_alias (new_node, node);
return new_node;
}
#include "gt-symtab.h"