PR lto/45721
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 11 Jan 2011 17:29:52 +0000 (17:29 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 11 Jan 2011 17:29:52 +0000 (17:29 +0000)
PR lto/45375
* tree.h (symbol_alias_set_t): Move typedef here from varasm.c
(symbol_alias_set_destroy, symbol_alias_set_contains,
propagate_aliases_backward): Declare.
* lto-streamer-out.c (struct sets): New sturcture.
(trivally_defined_alias): New function.
(output_alias_pair_p): Rewrite.
(output_unreferenced_globals): Fix output of alias pairs.
(produce_symtab): Likewise.
* ipa.c (function_and_variable_visibility): Set weak alias destination
as needed in lto.
* varasm.c (symbol_alias_set_t): Remove.
(symbol_alias_set_destroy): Export.
(propagate_aliases_forward, propagate_aliases_backward): New functions
based on ...
(compute_visible_aliases): ... this one; remove.
(trivially_visible_alias): New
(trivially_defined_alias): New.
(remove_unreachable_alias_pairs): Rewrite.
(finish_aliases_1): Reorganize code checking if alias is defined.
* passes.c (rest_of_decl_compilation): Do not call assemble_alias when
in LTO mode.

* lto.c (partition_cgraph_node_p, partition_varpool_node_p): Weakrefs are
not partitioned.

* testsuite/gcc.dg/lto/pr45721_1.c: New file.
* testsuite/gcc.dg/lto/pr45721_0.c: New file.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@168666 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/lto-streamer-out.c
gcc/lto/ChangeLog
gcc/lto/lto.c
gcc/passes.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/lto/pr45721_0.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/lto/pr45721_1.c [new file with mode: 0644]
gcc/tree.h
gcc/varasm.c

index 9724eee..7c42fab 100644 (file)
@@ -1,3 +1,29 @@
+2011-01-11  Jan Hubicka  <jh@suse.cz>
+
+       PR lto/45721
+       PR lto/45375
+       * tree.h (symbol_alias_set_t): Move typedef here from varasm.c
+       (symbol_alias_set_destroy, symbol_alias_set_contains,
+       propagate_aliases_backward): Declare.
+       * lto-streamer-out.c (struct sets): New sturcture.
+       (trivally_defined_alias): New function.
+       (output_alias_pair_p): Rewrite.
+       (output_unreferenced_globals): Fix output of alias pairs.
+       (produce_symtab): Likewise.
+       * ipa.c (function_and_variable_visibility): Set weak alias destination
+       as needed in lto.
+       * varasm.c (symbol_alias_set_t): Remove.
+       (symbol_alias_set_destroy): Export.
+       (propagate_aliases_forward, propagate_aliases_backward): New functions
+       based on ...
+       (compute_visible_aliases): ... this one; remove.
+       (trivially_visible_alias): New
+       (trivially_defined_alias): New.
+       (remove_unreachable_alias_pairs): Rewrite.
+       (finish_aliases_1): Reorganize code checking if alias is defined.
+       * passes.c (rest_of_decl_compilation): Do not call assemble_alias when
+       in LTO mode.
+
 2011-01-11  Richard Guenther  <rguenther@suse.de>
 
        PR tree-optimization/46076
index 82c2f6f..7c00293 100644 (file)
@@ -2007,6 +2007,13 @@ output_function (struct cgraph_node *node)
 }
 
 
+/* Used to pass data to trivally_defined_alias callback.  */
+struct sets {
+  cgraph_node_set set;
+  varpool_node_set vset;
+};
+
+
 /* Return true if alias pair P belongs to the set of cgraph nodes in
    SET.  If P is a an alias for a VAR_DECL, it can always be emitted.
    However, for FUNCTION_DECL aliases, we should only output the pair
@@ -2016,16 +2023,51 @@ output_function (struct cgraph_node *node)
    the file processed by LTRANS.  */
 
 static bool
-output_alias_pair_p (alias_pair *p, cgraph_node_set set, varpool_node_set vset)
+trivally_defined_alias (tree decl ATTRIBUTE_UNUSED,
+                       tree target, void *data)
 {
-  if (TREE_CODE (p->decl) == VAR_DECL)
-    return varpool_node_in_set_p (varpool_node_for_asm (p->target), vset);
+  struct sets *set = (struct sets *) data;
+  struct cgraph_node *fnode = NULL;
+  struct varpool_node *vnode = NULL;
 
-  /* Check if the assembler name for P->TARGET has its cgraph node in SET.  */
-  gcc_assert (TREE_CODE (p->decl) == FUNCTION_DECL);
-  return cgraph_node_in_set_p (cgraph_node_for_asm (p->target), set);
+  fnode = cgraph_node_for_asm (target);
+  if (fnode)
+    return cgraph_node_in_set_p (fnode, set->set);
+  vnode = varpool_node_for_asm (target);
+  return vnode && varpool_node_in_set_p (vnode, set->vset);
 }
 
+/* Return true if alias pair P should be output in the current
+   partition contains cgrpah nodes SET and varpool nodes VSET.
+   DEFINED is set of all aliases whose targets are defined in
+   the partition.
+
+   Normal aliases are output when they are defined, while WEAKREF
+   aliases are output when they are used.  */
+
+static bool
+output_alias_pair_p (alias_pair *p, symbol_alias_set_t *defined,
+                    cgraph_node_set set, varpool_node_set vset)
+{
+  struct cgraph_node *node;
+  struct varpool_node *vnode;
+
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
+    {
+      if (TREE_CODE (p->decl) == VAR_DECL)
+       {
+         vnode = varpool_get_node (p->decl);
+         return (vnode
+                 && referenced_from_this_partition_p (&vnode->ref_list, set, vset));
+       }
+      node = cgraph_get_node (p->decl);
+      return (node
+             && (referenced_from_this_partition_p (&node->ref_list, set, vset)
+                 || reachable_from_this_partition_p (node, set)));
+    }
+  else
+    return symbol_alias_set_contains (defined, p->decl);
+}
 
 /* Output any unreferenced global symbol defined in SET, alias pairs
    and labels.  */
@@ -2037,6 +2079,11 @@ output_unreferenced_globals (cgraph_node_set set, varpool_node_set vset)
   alias_pair *p;
   unsigned i;
   struct varpool_node *vnode;
+  symbol_alias_set_t *defined;
+  struct sets setdata;
+
+  setdata.set = set;
+  setdata.vset = vset;
 
   ob = create_output_block (LTO_section_static_initializer);
   ob->cgraph_node = NULL;
@@ -2070,15 +2117,20 @@ output_unreferenced_globals (cgraph_node_set set, varpool_node_set vset)
 
   output_zero (ob);
 
+  /* We really need to propagate in both directoins:
+     for normal aliases we propagate from first defined alias to
+     all aliases defined based on it.  For weakrefs we propagate in
+     the oposite direction.  */
+  defined = propagate_aliases_backward (trivally_defined_alias, &setdata);
+
   /* Emit the alias pairs for the nodes in SET.  */
   FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p)
-    {
-      if (output_alias_pair_p (p, set, vset))
-       {
-         lto_output_tree_ref (ob, p->decl);
-         lto_output_tree_ref (ob, p->target);
-       }
-    }
+    if (output_alias_pair_p (p, defined, set, vset))
+      {
+       lto_output_tree_ref (ob, p->decl);
+       lto_output_tree_ref (ob, p->target);
+      }
+  symbol_alias_set_destroy (defined);
 
   output_zero (ob);
 
@@ -2476,6 +2528,11 @@ produce_symtab (struct output_block *ob,
   lto_cgraph_encoder_t encoder = ob->decl_state->cgraph_node_encoder;
   int i;
   alias_pair *p;
+  struct sets setdata;
+  symbol_alias_set_t *defined;
+
+  setdata.set = set;
+  setdata.vset = vset;
 
   lto_begin_section (section_name, false);
   free (section_name);
@@ -2553,9 +2610,11 @@ produce_symtab (struct output_block *ob,
     }
 
   /* Write all aliases.  */
+  defined = propagate_aliases_backward (trivally_defined_alias, &setdata);
   FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p)
-    if (output_alias_pair_p (p, set, vset))
+    if (output_alias_pair_p (p, defined, set, vset))
       write_symbol (cache, &stream, p->decl, seen, true);
+  symbol_alias_set_destroy (defined);
 
   lto_write_stream (&stream);
   pointer_set_destroy (seen);
index 319a47a..4cb66fe 100644 (file)
@@ -1,3 +1,10 @@
+2011-01-11  Jan Hubicka  <jh@suse.cz>
+
+       PR lto/45721
+       PR lto/45375
+       * lto.c (partition_cgraph_node_p, partition_varpool_node_p): Weakrefs are
+       not partitioned.
+
 2010-12-22  Nathan Froyd  <froydnj@codesourcery.com>
 
        * lto-lang.c (handle_nonnull_attribute, handle_sentinel_attribute):
index 9cfb5e2..cbc192a 100644 (file)
@@ -837,6 +837,8 @@ partition_cgraph_node_p (struct cgraph_node *node)
       || (DECL_COMDAT (node->decl)
          && !cgraph_used_from_object_file_p (node)))
     return false;
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (node->decl)))
+    return false;
   return true;
 }
 
@@ -854,6 +856,8 @@ partition_varpool_node_p (struct varpool_node *vnode)
          && !vnode->force_output
          && !varpool_used_from_object_file_p (vnode)))
     return false;
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->decl)))
+    return false;
   return true;
 }
 
index 804ac9f..090110e 100644 (file)
@@ -144,6 +144,7 @@ rest_of_decl_compilation (tree decl,
 {
   /* We deferred calling assemble_alias so that we could collect
      other attributes such as visibility.  Emit the alias now.  */
+  if (!in_lto_p)
   {
     tree alias;
     alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl));
index adb6740..18a4873 100644 (file)
@@ -1,3 +1,10 @@
+2011-01-11  Jan Hubicka  <jh@suse.cz>
+
+       PR lto/45721
+       PR lto/45375
+       * testsuite/gcc.dg/lto/pr45721_1.c: New file.
+       * testsuite/gcc.dg/lto/pr45721_0.c: New file.
+
 2011-01-11  Richard Guenther  <rguenther@suse.de>
 
        PR tree-optimization/46076
diff --git a/gcc/testsuite/gcc.dg/lto/pr45721_0.c b/gcc/testsuite/gcc.dg/lto/pr45721_0.c
new file mode 100644 (file)
index 0000000..0af1620
--- /dev/null
@@ -0,0 +1,8 @@
+/* { dg-lto-do assemble }  */
+void baz(void) {}
+void *y = (void *)baz;
+int main () { return 0; }
+/* { dg-lto-do assemble }  */
+void baz(void) {}
+void *y = (void *)baz;
+int main () { return 0; }
diff --git a/gcc/testsuite/gcc.dg/lto/pr45721_1.c b/gcc/testsuite/gcc.dg/lto/pr45721_1.c
new file mode 100644 (file)
index 0000000..63cbfef
--- /dev/null
@@ -0,0 +1,4 @@
+static void bar(void) __attribute__ ((weakref("baz")));
+void *x = (void *)bar;
+static void bar(void) __attribute__ ((weakref("baz")));
+void *x = (void *)bar;
index 216f3d2..a49e335 100644 (file)
@@ -5389,6 +5389,18 @@ extern void remove_unreachable_alias_pairs (void);
 extern bool decl_replaceable_p (tree);
 extern bool decl_binds_to_current_def_p (tree);
 
+/* Derived type for use by compute_visible_aliases and callers.  A symbol
+   alias set is a pointer set into which we enter IDENTIFIER_NODES bearing
+   the canonicalised assembler-level symbol names corresponding to decls
+   and their aliases.  */
+typedef struct pointer_set_t symbol_alias_set_t;
+
+extern void symbol_alias_set_destroy (symbol_alias_set_t *);
+extern int symbol_alias_set_contains (const symbol_alias_set_t *, tree);
+extern symbol_alias_set_t * propagate_aliases_backward (bool (*)
+                                                        (tree, tree, void *),
+                                                       void *);
+
 /* In stmt.c */
 extern void expand_computed_goto (tree);
 extern bool parse_output_constraint (const char **, int, int, int,
index cc05c18..bbebd87 100644 (file)
@@ -5504,12 +5504,6 @@ do_assemble_alias (tree decl, tree target)
 #endif
 }
 
-/* Derived type for use by compute_visible_aliases and callers.  A symbol
-   alias set is a pointer set into which we enter IDENTIFIER_NODES bearing
-   the canonicalised assembler-level symbol names corresponding to decls
-   and their aliases.  */
-
-typedef struct pointer_set_t symbol_alias_set_t;
 
 /* Allocate and construct a symbol alias set.  */
 
@@ -5521,7 +5515,7 @@ symbol_alias_set_create (void)
 
 /* Destruct and free a symbol alias set.  */
 
-static void
+void
 symbol_alias_set_destroy (symbol_alias_set_t *aset)
 {
   pointer_set_destroy (aset);
@@ -5529,7 +5523,7 @@ symbol_alias_set_destroy (symbol_alias_set_t *aset)
 
 /* Test if a symbol alias set contains a given name.  */
 
-static int
+int
 symbol_alias_set_contains (const symbol_alias_set_t *aset, tree t)
 {
   /* We accept either a DECL or an IDENTIFIER directly.  */
@@ -5551,40 +5545,110 @@ symbol_alias_set_insert (symbol_alias_set_t *aset, tree t)
   return pointer_set_insert (aset, t);
 }
 
-/* Compute the set of indentifier nodes that is generated by aliases
-   whose targets are reachable.  */
+/* IN_SET_P is a predicate function assuming to be taken
+   alias_pair->decl, alias_pair->target and DATA arguments.
+
+   Compute set of aliases by including everything where TRIVIALLY_VISIBLE
+   predeicate is true and propagate across aliases such that when
+   alias DECL is included, its TARGET is included too.  */
 
 static symbol_alias_set_t *
-compute_visible_aliases (void)
+propagate_aliases_forward (bool (*in_set_p)
+                            (tree decl, tree target, void *data),
+                          void *data)
 {
-  symbol_alias_set_t *visible;
+  symbol_alias_set_t *set;
   unsigned i;
   alias_pair *p;
   bool changed;
 
-  /* We have to compute the set of visible nodes including aliases
+  set = symbol_alias_set_create ();
+  for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i)
+    if (in_set_p (p->decl, p->target, data))
+      symbol_alias_set_insert (set, p->decl);
+  do
+    {
+      changed = false;
+      for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i)
+       if (symbol_alias_set_contains (set, p->decl)
+           && !symbol_alias_set_insert (set, p->target))
+         changed = true;
+    }
+  while (changed);
+
+  return set;
+}
+
+/* Like propagate_aliases_forward but do backward propagation.  */
+
+symbol_alias_set_t *
+propagate_aliases_backward (bool (*in_set_p)
+                            (tree decl, tree target, void *data),
+                          void *data)
+{
+  symbol_alias_set_t *set;
+  unsigned i;
+  alias_pair *p;
+  bool changed;
+
+  /* We have to compute the set of set nodes including aliases
      themselves.  */
-  visible = symbol_alias_set_create ();
+  set = symbol_alias_set_create ();
+  for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i)
+    if (in_set_p (p->decl, p->target, data))
+      symbol_alias_set_insert (set, p->target);
   do
     {
       changed = false;
       for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i)
-       {
-         struct cgraph_node *fnode = NULL;
-         struct varpool_node *vnode = NULL;
-
-         fnode = cgraph_node_for_asm (p->target);
-         vnode = (fnode == NULL) ? varpool_node_for_asm (p->target) : NULL;
-         if ((fnode
-              || vnode
-              || symbol_alias_set_contains (visible, p->target))
-             && !symbol_alias_set_insert (visible, p->decl))
-           changed = true;
-       }
+       if (symbol_alias_set_contains (set, p->target)
+           && !symbol_alias_set_insert (set, p->decl))
+         changed = true;
     }
   while (changed);
 
-  return visible;
+  return set;
+}
+/* See if the alias is trivially visible.  This means
+     1) alias is expoerted from the unit or
+     2) alias is used in the code.
+   We assume that unused cgraph/varpool nodes has been
+   removed.
+   Used as callback for propagate_aliases.  */
+
+static bool
+trivially_visible_alias (tree decl, tree target ATTRIBUTE_UNUSED,
+                        void *data ATTRIBUTE_UNUSED)
+{
+  struct cgraph_node *fnode = NULL;
+  struct varpool_node *vnode = NULL;
+
+  if (!TREE_PUBLIC (decl))
+    {
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+       fnode = cgraph_get_node (decl);
+      else
+       vnode = varpool_get_node (decl);
+      return vnode || fnode;
+    }
+  else
+    return true;
+}
+
+/* See if the target of alias is defined in this unit.
+   Used as callback for propagate_aliases.  */
+
+static bool
+trivially_defined_alias (tree decl ATTRIBUTE_UNUSED,
+                        tree target,
+                        void *data ATTRIBUTE_UNUSED)
+{
+  struct cgraph_node *fnode = NULL;
+  struct varpool_node *vnode = NULL;
+
+  fnode = cgraph_node_for_asm (target);
+  vnode = (fnode == NULL) ? varpool_node_for_asm (target) : NULL;
+  return (fnode && fnode->analyzed) || (vnode && vnode->finalized);
 }
 
 /* Remove the alias pairing for functions that are no longer in the call
@@ -5602,23 +5666,15 @@ remove_unreachable_alias_pairs (void)
 
   /* We have to compute the set of visible nodes including aliases
      themselves.  */
-  visible = compute_visible_aliases ();
+  visible = propagate_aliases_forward (trivially_visible_alias, NULL);
 
   for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); )
     {
-      if (!DECL_EXTERNAL (p->decl))
+      if (!DECL_EXTERNAL (p->decl)
+         && !symbol_alias_set_contains (visible, p->decl))
        {
-         struct cgraph_node *fnode = NULL;
-         struct varpool_node *vnode = NULL;
-         fnode = cgraph_node_for_asm (p->target);
-         vnode = (fnode == NULL) ? varpool_node_for_asm (p->target) : NULL;
-         if (!fnode
-             && !vnode
-             && !symbol_alias_set_contains (visible, p->target))
-           {
-             VEC_unordered_remove (alias_pair, alias_pairs, i);
-             continue;
-           }
+         VEC_unordered_remove (alias_pair, alias_pairs, i);
+         continue;
        }
 
       i++;
@@ -5634,16 +5690,16 @@ remove_unreachable_alias_pairs (void)
 void
 finish_aliases_1 (void)
 {
-  symbol_alias_set_t *visible;
+  symbol_alias_set_t *defined;
   unsigned i;
   alias_pair *p;
 
   if (alias_pairs == NULL)
     return;
 
-  /* We have to compute the set of visible nodes including aliases
+  /* We have to compute the set of defined nodes including aliases
      themselves.  */
-  visible = compute_visible_aliases ();
+  defined = propagate_aliases_backward (trivially_defined_alias, NULL);
 
   FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p)
     {
@@ -5652,7 +5708,7 @@ finish_aliases_1 (void)
       target_decl = find_decl_and_mark_needed (p->decl, p->target);
       if (target_decl == NULL)
        {
-         if (symbol_alias_set_contains (visible, p->target))
+         if (symbol_alias_set_contains (defined, p->target))
            continue;
 
          if (! (p->emitted_diags & ALIAS_DIAG_TO_UNDEF)
@@ -5678,7 +5734,7 @@ finish_aliases_1 (void)
        }
     }
 
-  symbol_alias_set_destroy (visible);
+  symbol_alias_set_destroy (defined);
 }
 
 /* Second pass of completing pending aliases.  Emit the actual assembly.