Patchwork Introduce local aliases for call targets when possible

login
register
mail settings
Submitter Jan Hubicka
Date Aug. 2, 2013, 2:36 p.m.
Message ID <20130802143621.GB15776@kam.mff.cuni.cz>
Download mbox | patch
Permalink /patch/264299/
State New
Headers show

Comments

Jan Hubicka - Aug. 2, 2013, 2:36 p.m.
Hi,
this patch (developed with Martin Liska) adds symbol table function
symtab_nonoverwritable_alias that for a given definition returns symtab node
that is not overwritable by linking and points to it.
This patch makes simple use of it: when inline function is called and the symbol
itself can be interposed by dynamic linking (and can not be interposed by static
linking), we replace all direct calls to it by calls to the alias.
This saves jumps to PLT entries.

For Firefox this makes just few replacements, but I guess every relocation counts.
Similar replacements are possibly in virtual tables that I am going to change next -
more care is needed there since we do not yet have any infrastructure to redirect
relocations.

Bootstrapped/regtested ppc64-linux, will commit it shortly.

PS: I just noticed symtab_nonoverwritable_alias lacks documentation, will add it
momentarily.

Honza

	* 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.

Patch

Index: cgraph.c
===================================================================
--- cgraph.c	(revision 201412)
+++ cgraph.c	(working copy)
@@ -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: cgraph.h
===================================================================
--- cgraph.h	(revision 201413)
+++ cgraph.h	(working copy)
@@ -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 *);
Index: ipa.c
===================================================================
--- ipa.c	(revision 201412)
+++ ipa.c	(working copy)
@@ -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.  */
Index: symtab.c
===================================================================
--- symtab.c	(revision 201412)
+++ symtab.c	(working copy)
@@ -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"