summaryrefslogtreecommitdiff
path: root/gcc/ipa.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ipa.c')
-rw-r--r--gcc/ipa.c46
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. */