Hi,
this patch fixes failure in lto/attr-weakref-1 with plugin disabled setup. The 
issue is that currently
gas rejects .weakref referring to symbol defined in the same translation unit.
/tmp/cc0Zk0UZ.s: Assembler messages:
/tmp/cc0Zk0UZ.s:121: Error: symbol definition loop encountered at 
`callmealias.lto_priv.0'

The message is wrong (there is no loop) and should be also fixed at gas side
https://sourceware.org/bugzilla/show_bug.cgi?id=19498

This patch makes weakref to turn into static alias when aliases are supported 
and the
target binds to current def.

When alias target is defined in current unit and thus we know it will be 
defined (possibly
to other definition) and there is no used attribute, we turn the weakref into 
transparent
alias.

Both should result in slightly better code, but the only code that benefits is 
code that
defines weakrefs target which in practice IMO means that you need to LTO glibc 
itself in.
This is currently not supported (one can't LTO runtime libraries)

Bootstrapepd/regtested x86_64-linux, will commit it shortly.

Honza

        PR ipa/68881
        * cgraph.h (symtab_node::copy_visibility_from): New function.
        * symtab.c (symtab_node::copy_visibility_from): New function.
        * ipa-visibility.c (optimize_weakref): New function.
        (function_and_variable_visibility): Use it.
Index: cgraph.h
===================================================================
--- cgraph.h    (revision 234669)
+++ cgraph.h    (working copy)
@@ -293,6 +293,9 @@ public:
   /* Make DECL local.  */
   void make_decl_local (void);
 
+  /* Copy visibility from N.  */
+  void copy_visibility_from (symtab_node *n);
+
   /* Return desired alignment of the definition.  This is NOT alignment useful
      to access THIS, because THIS may be interposable and DECL_ALIGN should
      be used instead.  It however must be guaranteed when output definition
Index: ipa-visibility.c
===================================================================
--- ipa-visibility.c    (revision 234669)
+++ ipa-visibility.c    (working copy)
@@ -452,6 +452,84 @@ update_visibility_by_resolution_info (sy
     }
 }
 
+/* Try to get rid of weakref.  */
+
+static void
+optimize_weakref (symtab_node *node)
+{
+#ifdef ASM_OUTPUT_DEF
+  bool aliases_supported = true;
+#else
+  bool aliases_supported = false;
+#endif
+  bool strip_weakref = false;
+  bool static_alias = false;
+
+  gcc_assert (node->weakref);
+
+  /* Weakrefs with no target defined can not be optimized.  */
+  if (!node->analyzed)
+    return;
+  symtab_node *target = node->get_alias_target ();
+
+  /* Weakrefs to weakrefs can be optimized only if target can be.  */
+  if (target->weakref)
+    optimize_weakref (target);
+  if (target->weakref)
+    return;
+
+  /* If we have definition of weakref's target and we know it binds locally,
+     we can turn weakref to static alias.  */
+  if (target->definition && decl_binds_to_current_def_p (target->decl)
+      && aliases_supported)
+    strip_weakref = static_alias = true;
+  /* Otherwise we can turn weakref into transparent alias.  This transformation
+     may break asm statements which directly refers to symbol name and expect
+     GNU as to translate it via .weakref directive. So do not optimize when
+     DECL_PRESERVED is set and .weakref is supported.  */
+  else if ((!DECL_PRESERVE_P (target->decl)
+           || IDENTIFIER_TRANSPARENT_ALIAS (DECL_ASSEMBLER_NAME (node->decl)))
+          && !DECL_WEAK (target->decl)
+          && !DECL_EXTERNAL (target->decl)
+          && ((target->definition && !target->can_be_discarded_p ())
+              || target->resolution != LDPR_UNDEF))
+    strip_weakref = true;
+  if (!strip_weakref)
+    return;
+  node->weakref = false;
+  IDENTIFIER_TRANSPARENT_ALIAS (DECL_ASSEMBLER_NAME (node->decl)) = 0;
+  TREE_CHAIN (DECL_ASSEMBLER_NAME (node->decl)) = NULL_TREE;
+  DECL_ATTRIBUTES (node->decl) = remove_attribute ("weakref",
+                                                  DECL_ATTRIBUTES
+                                                        (node->decl));
+
+  if (dump_file)
+    fprintf (dump_file, "Optimizing weakref %s %s\n",
+            node->name(),
+            static_alias ? "as static alias" : "as transparent alias");
+
+  if (static_alias)
+    {
+      /* make_decl_local will shortcircuit if it doesn't see TREE_PUBLIC.
+        be sure it really clears the WEAK flag.  */
+      TREE_PUBLIC (node->decl) = true;
+      node->make_decl_local ();
+      node->forced_by_abi = false;
+      node->resolution = LDPR_PREVAILING_DEF_IRONLY;
+      node->externally_visible = false;
+      gcc_assert (!DECL_WEAK (node->decl));
+      node->transparent_alias = false;
+    }
+  else
+    {
+      symtab->change_decl_assembler_name
+        (node->decl, DECL_ASSEMBLER_NAME (node->get_alias_target ()->decl));
+      node->transparent_alias = true;
+      node->copy_visibility_from (target);
+    }
+  gcc_assert (node->alias);
+}
+
 /* Decide on visibility of all symbols.  */
 
 static unsigned int
@@ -594,6 +672,8 @@ function_and_variable_visibility (bool w
        }
 
       update_visibility_by_resolution_info (node);
+      if (node->weakref)
+       optimize_weakref (node);
     }
   FOR_EACH_DEFINED_FUNCTION (node)
     {
@@ -660,6 +740,8 @@ function_and_variable_visibility (bool w
              || ! (ADDR_SPACE_GENERIC_P
                    (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl))))))
        DECL_COMMON (vnode->decl) = 0;
+      if (vnode->weakref)
+       optimize_weakref (vnode);
     }
   FOR_EACH_DEFINED_VARIABLE (vnode)
     {
Index: symtab.c
===================================================================
--- symtab.c    (revision 234669)
+++ symtab.c    (working copy)
@@ -1287,6 +1287,61 @@ symtab_node::make_decl_local (void)
   SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl);
 }
 
+/* Copy visibility from N.
+   This is useful when THIS becomes a transparent alias of N.  */
+
+void
+symtab_node::copy_visibility_from (symtab_node *n)
+{
+  gcc_checking_assert (n->weakref == weakref);
+
+  ipa_ref *ref;
+  for (unsigned i = 0; iterate_direct_aliases (i, ref); i++)
+    {
+      struct symtab_node *alias = ref->referring;
+      if (alias->transparent_alias)
+       alias->copy_visibility_from (n);
+    }
+
+  if (TREE_CODE (decl) == VAR_DECL)
+    {
+      DECL_COMMON (decl) = DECL_COMMON (n->decl);
+      /* ADDRESSABLE flag is not defined for public symbols.  */
+      if (TREE_PUBLIC (decl) && !TREE_PUBLIC (n->decl))
+        TREE_ADDRESSABLE (decl) = 1;
+      TREE_STATIC (decl) = TREE_STATIC (n->decl);
+    }
+  else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+
+  DECL_COMDAT (decl) = DECL_COMDAT (n->decl);
+  DECL_WEAK (decl) = DECL_WEAK (n->decl);
+  DECL_EXTERNAL (decl) = DECL_EXTERNAL (n->decl);
+  DECL_VISIBILITY_SPECIFIED (decl) = DECL_VISIBILITY_SPECIFIED (n->decl);
+  DECL_VISIBILITY (decl) = DECL_VISIBILITY (n->decl);
+  TREE_PUBLIC (decl) = TREE_PUBLIC (n->decl);
+  DECL_DLLIMPORT_P (decl) = DECL_DLLIMPORT_P (n->decl);
+  resolution = n->resolution;
+  set_comdat_group (n->get_comdat_group ());
+  call_for_symbol_and_aliases (symtab_node::set_section,
+                            const_cast<char *>(n->get_section ()), true);
+  externally_visible = n->externally_visible;
+  if (!DECL_RTL_SET_P (decl))
+    return;
+
+  /* Update rtl flags.  */
+  make_decl_rtl (decl);
+
+  rtx rtl = DECL_RTL (decl);
+  if (!MEM_P (rtl))
+    return;
+
+  rtx symbol = XEXP (rtl, 0);
+  if (GET_CODE (symbol) != SYMBOL_REF)
+    return;
+
+  SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl);
+}
+
 /* Walk the alias chain to return the symbol NODE is alias of.
    If NODE is not an alias, return NODE.
    Assumes NODE is known to be alias.  */

Reply via email to