cgraph.c (cgraph_function_body_availability): Do not check cgrpah flags.
authorJan Hubicka <jh@suse.cz>
Fri, 2 Aug 2013 14:38:15 +0000 (16:38 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Fri, 2 Aug 2013 14:38:15 +0000 (14:38 +0000)
* 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.

Co-Authored-By: Martin Liska <marxin.liska@gmail.com>
From-SVN: r201439

gcc/ChangeLog
gcc/cgraph.c
gcc/cgraph.h
gcc/ipa.c
gcc/symtab.c

index 94a65d2bdb57b2298261c593f3ac100355cfce60..9e0e253745f3b0f327f46ddd025e0b899cf99582 100644 (file)
@@ -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
index 5b3fb5abf908ad684662db8d5669a20048699e2b..6ab7891ec8f9c9f0a1380fb3b4bee3eb1412e520 100644 (file)
@@ -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)
index 9b76b67d2f4d05a4225503ff999e229505b41fc1..4e4dddc0c3eef1c81b8a8b536c87e98c52b3b198 100644 (file)
@@ -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 *);
index 085454d02e106989873202cf8c4abcc761da4255..f42de4dac693942e379a5f7a8391954956358cac 100644 (file)
--- 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.  */
index d15881b609a73ab88bc8f65e5f1f2dd2eeea34da..a86bf6b132791e6b670519f8e251aceadfab2b6c 100644 (file)
@@ -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"