diff options
Diffstat (limited to 'gcc/ipa.c')
-rw-r--r-- | gcc/ipa.c | 46 |
1 files changed, 45 insertions, 1 deletions
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. */ |