re PR lto/68881 (UNRESOLVED/FAIL: gcc.dg/lto/attr-weakref-1 -O2 -flto)
authorJan Hubicka <hubicka@ucw.cz>
Mon, 4 Apr 2016 09:26:29 +0000 (11:26 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Mon, 4 Apr 2016 09:26:29 +0000 (09:26 +0000)
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.

From-SVN: r234708

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

index 68574f438c8dc8c443c9b06fd9625e4663613aa9..61515258626485a098f08320dee14926fcf744bd 100644 (file)
@@ -1,3 +1,11 @@
+2016-03-30  Jan Hubicka  <hubicka@ucw.cz>
+
+       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.
+
 2016-04-04  Martin Liska  <mliska@suse.cz>
 
        PR hsa/70402
index e92928523992b1913d80f028a346fcc8f633f479..1d39d918b21deaba9f173cde9a379f7d5b70bbdd 100644 (file)
@@ -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 8198a3da17563e90970466a6f58f12558c8b8bcd..e4c3f7c51109895a1a46df411c44c2d941dda5f1 100644 (file)
@@ -452,6 +452,84 @@ update_visibility_by_resolution_info (symtab_node * node)
     }
 }
 
+/* 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 whole_program)
        }
 
       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 whole_program)
              || ! (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 2d7705e657cb1e798ac739b2fc964caefc2194b2..3d3cc4f738c3676e752780dae8325899986ce946 100644 (file)
@@ -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.  */