diff mbox

Fix weakrefs and LTO

Message ID 20130515153309.GA27333@kam.mff.cuni.cz
State New
Headers show

Commit Message

Jan Hubicka May 15, 2013, 3:33 p.m. UTC
Hi,
my testcase unfortunately passes with plugin disabled only. With plugin enabled
it hits a bug where we won't associate alais with its taerget across units and
we optimize out the target as unused.

Funilly enough this hits yet another bug in GNU LD that makes the testcase
to run infinitely, while with Gold it ICEs.

This patch fixes the GCC part of th ebug.  It is ugly by overusing ->alias
field to store identifier node when decl is not around and by duplicating cycle
detection for aliases.  I have patch in queue to cleanup the whole area, but I
would like to fix this first, since release branches are also affected and this
makes the patch easier to backport.

Bootstrap/regtest of x86_64-linux in progress.  Will commit the patch if it passes.

Honza

	* cgraphunit.c (handle_alias_pairs): Save target of weakref alias.
	(output_weakrefs): Do not ice on unresolved weakrefs.
	* lto-symtab.c (lto_symtab_merge_cgraph_nodes): Resolve weakrefs.
	* cgraph.c (dump_cgraph_node): Do not ICE on unresolved weakrefs.
diff mbox

Patch

Index: cgraphunit.c
===================================================================
--- cgraphunit.c	(revision 198926)
+++ cgraphunit.c	(working copy)
@@ -1069,9 +1069,17 @@  handle_alias_pairs (void)
       if (!target_node && lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)) != NULL)
 	{
 	  if (TREE_CODE (p->decl) == FUNCTION_DECL)
-	    cgraph_get_create_node (p->decl)->alias = true;
+	    {
+	      struct cgraph_node *anode = cgraph_get_create_node (p->decl);
+	      anode->alias = true;
+	      anode->thunk.alias = p->target;
+	    }
 	  else
-	    varpool_get_node (p->decl)->alias = true;
+	    {
+	      struct varpool_node *anode = varpool_get_node (p->decl);
+	      anode->alias = true;
+	      anode->alias_of = p->target;
+	    }
 	  DECL_EXTERNAL (p->decl) = 1;
 	  alias_pairs->unordered_remove (i);
 	  continue;
@@ -1939,14 +1947,14 @@  output_weakrefs (void)
         && !TREE_ASM_WRITTEN (node->symbol.decl)
 	&& lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
       do_assemble_alias (node->symbol.decl,
-		         node->thunk.alias ? DECL_ASSEMBLER_NAME (node->thunk.alias)
+		         node->thunk.alias && DECL_P (node->thunk.alias) ? DECL_ASSEMBLER_NAME (node->thunk.alias)
 		         : get_alias_symbol (node->symbol.decl));
   FOR_EACH_VARIABLE (vnode)
     if (vnode->alias && DECL_EXTERNAL (vnode->symbol.decl)
         && !TREE_ASM_WRITTEN (vnode->symbol.decl)
 	&& lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->symbol.decl)))
       do_assemble_alias (vnode->symbol.decl,
-		         vnode->alias_of ? DECL_ASSEMBLER_NAME (vnode->alias_of)
+		         vnode->alias_of && DECL_P (vnode->alias_of) ? DECL_ASSEMBLER_NAME (vnode->alias_of)
 		         : get_alias_symbol (vnode->symbol.decl));
 }
 
Index: lto-symtab.c
===================================================================
--- lto-symtab.c	(revision 198926)
+++ lto-symtab.c	(working copy)
@@ -593,13 +593,67 @@  lto_symtab_merge_cgraph_nodes (void)
 
   FOR_EACH_FUNCTION (cnode)
     {
+      /* Resolve weakrefs to symbol defined in other unit.  */
+      if (!cnode->analyzed && cnode->thunk.alias && !DECL_P (cnode->thunk.alias))
+	{
+	  symtab_node node = symtab_node_for_asm (cnode->thunk.alias);
+	  if (node && is_a <cgraph_node> (node))
+	    {
+	      struct cgraph_node *n;
+
+	      for (n = cgraph (node); n && n->alias;
+		   n = n->analyzed ? cgraph_alias_aliased_node (n) : NULL)
+		if (n == cnode)
+		  {
+		    error ("function %q+D part of alias cycle", cnode->symbol.decl);
+		    cnode->alias = false;
+		    break;
+		  }
+	      if (cnode->alias)
+		{
+		  cgraph_create_function_alias (cnode->symbol.decl, node->symbol.decl);
+		  ipa_record_reference ((symtab_node)cnode, (symtab_node)node,
+					IPA_REF_ALIAS, NULL);
+		  cnode->analyzed = true;
+		}
+	    }
+	  else if (node)
+	    error ("%q+D alias in between function and variable is not supported", cnode->symbol.decl);
+	}
       if ((cnode->thunk.thunk_p || cnode->alias)
-	  && cnode->thunk.alias)
+	  && cnode->thunk.alias && DECL_P (cnode->thunk.alias))
         cnode->thunk.alias = lto_symtab_prevailing_decl (cnode->thunk.alias);
       cnode->symbol.aux = NULL;
     }
   FOR_EACH_VARIABLE (vnode)
     {
+      /* Resolve weakrefs to symbol defined in other unit.  */
+      if (!vnode->analyzed && vnode->alias_of && !DECL_P (vnode->alias_of))
+	{
+	  symtab_node node = symtab_node_for_asm (vnode->alias_of);
+	  if (node && is_a <cgraph_node> (node))
+	    {
+	      struct varpool_node *n;
+
+	      for (n = varpool (node); n && n->alias;
+		   n = n->analyzed ? varpool_alias_aliased_node (n) : NULL)
+		if (n == vnode)
+		  {
+		    error ("function %q+D part of alias cycle", vnode->symbol.decl);
+		    vnode->alias = false;
+		    break;
+		  }
+	      if (vnode->alias)
+		{
+		  varpool_create_variable_alias (vnode->symbol.decl, node->symbol.decl);
+		  ipa_record_reference ((symtab_node)vnode, (symtab_node)node,
+					IPA_REF_ALIAS, NULL);
+		  vnode->analyzed = true;
+		}
+	    }
+	  else if (node)
+	    error ("%q+D alias in between function and variable is not supported", vnode->symbol.decl);
+	}
       if (vnode->alias_of)
         vnode->alias_of = lto_symtab_prevailing_decl (vnode->alias_of);
       vnode->symbol.aux = NULL;
Index: cgraph.c
===================================================================
--- cgraph.c	(revision 198926)
+++ cgraph.c	(working copy)
@@ -1558,7 +1558,7 @@  dump_cgraph_node (FILE *f, struct cgraph
 	       (int)node->thunk.virtual_value,
 	       (int)node->thunk.virtual_offset_p);
     }
-  if (node->alias && node->thunk.alias)
+  if (node->alias && node->thunk.alias && DECL_P (node->thunk.alias))
     {
       fprintf (f, "  Alias of %s",
 	       lang_hooks.decl_printable_name (node->thunk.alias, 2));