===================================================================
@@ -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)
===================================================================
@@ -597,6 +597,12 @@ symtab_node symtab_alias_ultimate_target
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 *);
===================================================================
@@ -750,6 +750,21 @@ varpool_externally_visible_p (struct var
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
@@ -871,7 +886,36 @@ function_and_variable_visibility (bool w
}
}
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. */
===================================================================
@@ -1014,4 +1014,84 @@ symtab_resolve_alias (symtab_node node,
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;
+}
+
+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"