diff options
author | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-08-02 14:38:15 +0000 |
---|---|---|
committer | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-08-02 14:38:15 +0000 |
commit | 44e825028f5bb046ffa1d27da959397e2699375e (patch) | |
tree | 1cccd5c74a32da024ef7d68be27022345b749039 /gcc | |
parent | 691cfda44a7604be69ece556a4b548cc16fdedae (diff) | |
download | gcc-44e825028f5bb046ffa1d27da959397e2699375e.tar.gz |
* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@201439 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/cgraph.c | 1 | ||||
-rw-r--r-- | gcc/cgraph.h | 6 | ||||
-rw-r--r-- | gcc/ipa.c | 46 | ||||
-rw-r--r-- | gcc/symtab.c | 84 |
5 files changed, 146 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 94a65d2bdb5..9e0e253745f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 5b3fb5abf90..6ab7891ec8f 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -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) diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 9b76b67d2f4..4e4dddc0c3e 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -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 *); diff --git a/gcc/ipa.c b/gcc/ipa.c index 085454d02e1..f42de4dac69 100644 --- a/gcc/ipa.c +++ b/gcc/ipa.c @@ -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. */ diff --git a/gcc/symtab.c b/gcc/symtab.c index d15881b609a..a86bf6b1327 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -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" |