summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2013-08-02 14:38:15 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2013-08-02 14:38:15 +0000
commit44e825028f5bb046ffa1d27da959397e2699375e (patch)
tree1cccd5c74a32da024ef7d68be27022345b749039 /gcc
parent691cfda44a7604be69ece556a4b548cc16fdedae (diff)
downloadgcc-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/ChangeLog11
-rw-r--r--gcc/cgraph.c1
-rw-r--r--gcc/cgraph.h6
-rw-r--r--gcc/ipa.c46
-rw-r--r--gcc/symtab.c84
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"