This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Get aliases and weakrefs into better shape with LTO


> On 07/01/2011 01:02, Jan Hubicka wrote:
> >     This seems a symptomatic fix as it goes backwards.  I assume that original
> >     problem was an aliases stalling referencing optimized out object.
> 
>   AFAIK PR46221 (see also its subsequent, PR46674) was the original motivation
> for the patch.
Hi,
I am attaching re-diffed patch.  Now it seems to apply clearly.
Thanks for the pointer, the chained aliases should work with my patch.  I looked
for origns of remove_unreachable_alias_pairs but missed this PR.

Honza

	* 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.
Index: tree.h
===================================================================
*** tree.h	(revision 168566)
--- tree.h	(working copy)
*************** extern void remove_unreachable_alias_pai
*** 5389,5394 ****
--- 5389,5406 ----
  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: testsuite/gcc.dg/lto/pr45721_0.c
===================================================================
*** testsuite/gcc.dg/lto/pr45721_0.c	(revision 0)
--- testsuite/gcc.dg/lto/pr45721_0.c	(revision 0)
***************
*** 0 ****
--- 1,4 ----
+ /* { dg-lto-do assemble }  */
+ void baz(void) {}
+ void *y = (void *)baz;
+ int main () { return 0; }
Index: testsuite/gcc.dg/lto/pr45721_1.c
===================================================================
*** testsuite/gcc.dg/lto/pr45721_1.c	(revision 0)
--- testsuite/gcc.dg/lto/pr45721_1.c	(revision 0)
***************
*** 0 ****
--- 1,2 ----
+ static void bar(void) __attribute__ ((weakref("baz")));
+ void *x = (void *)bar;
Index: lto-streamer-out.c
===================================================================
*** lto-streamer-out.c	(revision 168566)
--- lto-streamer-out.c	(working copy)
*************** output_function (struct cgraph_node *nod
*** 2005,2010 ****
--- 2005,2017 ----
  }
  
  
+ /* 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
*************** output_function (struct cgraph_node *nod
*** 2014,2029 ****
     the file processed by LTRANS.  */
  
  static bool
! output_alias_pair_p (alias_pair *p, cgraph_node_set set, varpool_node_set vset)
  {
!   if (TREE_CODE (p->decl) == VAR_DECL)
!     return varpool_node_in_set_p (varpool_node_for_asm (p->target), vset);
  
!   /* 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);
! }
  
  
  /* Output any unreferenced global symbol defined in SET, alias pairs
     and labels.  */
--- 2021,2071 ----
     the file processed by LTRANS.  */
  
  static bool
! trivally_defined_alias (tree decl ATTRIBUTE_UNUSED,
! 			tree target, void *data)
  {
!   struct sets *set = (struct sets *) data;
!   struct cgraph_node *fnode = NULL;
!   struct varpool_node *vnode = NULL;
! 
!   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.  */
*************** output_unreferenced_globals (cgraph_node
*** 2035,2040 ****
--- 2077,2087 ----
    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;
*************** output_unreferenced_globals (cgraph_node
*** 2068,2082 ****
  
    output_zero (ob);
  
    /* 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);
! 	}
!     }
  
    output_zero (ob);
  
--- 2115,2134 ----
  
    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, 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);
  
*************** produce_symtab (struct output_block *ob,
*** 2474,2479 ****
--- 2526,2536 ----
    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);
*************** produce_symtab (struct output_block *ob,
*** 2551,2559 ****
      }
  
    /* Write all aliases.  */
    FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p)
!     if (output_alias_pair_p (p, set, vset))
        write_symbol (cache, &stream, p->decl, seen, true);
  
    lto_write_stream (&stream);
    pointer_set_destroy (seen);
--- 2608,2618 ----
      }
  
    /* 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, 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: ipa.c
===================================================================
*** ipa.c	(revision 168566)
--- ipa.c	(working copy)
*************** function_and_variable_visibility (bool w
*** 846,851 ****
--- 846,858 ----
  		
        if ((node = cgraph_node_for_asm (p->target)) != NULL)
          {
+ 	  /* Weakrefs alias symbols from other compilation unit.  In the case
+ 	     the destination of weakref became available because of LTO, we must
+ 	     mark it as needed.  */
+ 	  if (in_lto_p
+ 	      && lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl))
+ 	      && !node->needed)
+ 	    cgraph_mark_needed_node (node);
  	  gcc_assert (node->needed);
  	  pointer_set_insert (aliased_nodes, node);
  	  if (dump_file)
*************** function_and_variable_visibility (bool w
*** 854,859 ****
--- 861,873 ----
          }
        else if ((vnode = varpool_node_for_asm (p->target)) != NULL)
          {
+ 	  /* Weakrefs alias symbols from other compilation unit.  In the case
+ 	     the destination of weakref became available because of LTO, we must
+ 	     mark it as needed.  */
+ 	  if (in_lto_p
+ 	      && lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl))
+ 	      && !vnode->needed)
+ 	    varpool_mark_needed_node (vnode);
  	  gcc_assert (vnode->needed);
  	  pointer_set_insert (aliased_vnodes, vnode);
  	  if (dump_file)
Index: lto/lto.c
===================================================================
*** lto/lto.c	(revision 168566)
--- lto/lto.c	(working copy)
*************** partition_cgraph_node_p (struct cgraph_n
*** 837,842 ****
--- 837,844 ----
        || (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;
  }
  
*************** partition_varpool_node_p (struct varpool
*** 854,859 ****
--- 856,863 ----
  	  && !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: varasm.c
===================================================================
*** varasm.c	(revision 168566)
--- varasm.c	(working copy)
*************** do_assemble_alias (tree decl, tree targe
*** 5504,5515 ****
  #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.  */
  
--- 5504,5509 ----
*************** symbol_alias_set_create (void)
*** 5521,5527 ****
  
  /* Destruct and free a symbol alias set.  */
  
! static void
  symbol_alias_set_destroy (symbol_alias_set_t *aset)
  {
    pointer_set_destroy (aset);
--- 5515,5521 ----
  
  /* Destruct and free a symbol alias set.  */
  
! void
  symbol_alias_set_destroy (symbol_alias_set_t *aset)
  {
    pointer_set_destroy (aset);
*************** symbol_alias_set_destroy (symbol_alias_s
*** 5529,5535 ****
  
  /* Test if a symbol alias set contains a given name.  */
  
! static int
  symbol_alias_set_contains (const symbol_alias_set_t *aset, tree t)
  {
    /* We accept either a DECL or an IDENTIFIER directly.  */
--- 5523,5529 ----
  
  /* Test if a symbol alias set contains a given name.  */
  
! int
  symbol_alias_set_contains (const symbol_alias_set_t *aset, tree t)
  {
    /* We accept either a DECL or an IDENTIFIER directly.  */
*************** symbol_alias_set_insert (symbol_alias_se
*** 5551,5590 ****
    return pointer_set_insert (aset, t);
  }
  
! /* Compute the set of indentifier nodes that is generated by aliases
!    whose targets are reachable.  */
  
  static symbol_alias_set_t *
! compute_visible_aliases (void)
  {
!   symbol_alias_set_t *visible;
    unsigned i;
    alias_pair *p;
    bool changed;
  
!   /* We have to compute the set of visible nodes including aliases
!      themselves.  */
!   visible = symbol_alias_set_create ();
    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;
! 	}
      }
    while (changed);
  
!   return visible;
  }
  
  /* Remove the alias pairing for functions that are no longer in the call
--- 5545,5654 ----
    return pointer_set_insert (aset, t);
  }
  
! /* 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 *
! propagate_aliases_forward (bool (*in_set_p)
! 			     (tree decl, tree target, void *data),
! 		           void *data)
  {
!   symbol_alias_set_t *set;
    unsigned i;
    alias_pair *p;
    bool changed;
  
!   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.  */
!   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)
! 	if (symbol_alias_set_contains (set, p->target)
! 	    && !symbol_alias_set_insert (set, p->decl))
! 	  changed = true;
      }
    while (changed);
  
!   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
*************** remove_unreachable_alias_pairs (void)
*** 5602,5624 ****
  
    /* We have to compute the set of visible nodes including aliases
       themselves.  */
!   visible = compute_visible_aliases ();
  
    for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); )
      {
!       if (!DECL_EXTERNAL (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;
! 	    }
  	}
  
        i++;
--- 5666,5680 ----
  
    /* We have to compute the set of visible nodes including aliases
       themselves.  */
!   visible = propagate_aliases_forward (trivially_visible_alias, NULL);
  
    for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); )
      {
!       if (!DECL_EXTERNAL (p->decl)
! 	  && !symbol_alias_set_contains (visible, p->decl))
  	{
! 	  VEC_unordered_remove (alias_pair, alias_pairs, i);
! 	  continue;
  	}
  
        i++;
*************** remove_unreachable_alias_pairs (void)
*** 5634,5649 ****
  void
  finish_aliases_1 (void)
  {
!   symbol_alias_set_t *visible;
    unsigned i;
    alias_pair *p;
  
    if (alias_pairs == NULL)
      return;
  
!   /* We have to compute the set of visible nodes including aliases
       themselves.  */
!   visible = compute_visible_aliases ();
  
    FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p)
      {
--- 5690,5705 ----
  void
  finish_aliases_1 (void)
  {
!   symbol_alias_set_t *defined;
    unsigned i;
    alias_pair *p;
  
    if (alias_pairs == NULL)
      return;
  
!   /* We have to compute the set of defined nodes including aliases
       themselves.  */
!   defined = propagate_aliases_backward (trivially_defined_alias, NULL);
  
    FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p)
      {
*************** finish_aliases_1 (void)
*** 5652,5658 ****
        target_decl = find_decl_and_mark_needed (p->decl, p->target);
        if (target_decl == NULL)
  	{
! 	  if (symbol_alias_set_contains (visible, p->target))
  	    continue;
  
  	  if (! (p->emitted_diags & ALIAS_DIAG_TO_UNDEF)
--- 5708,5714 ----
        target_decl = find_decl_and_mark_needed (p->decl, p->target);
        if (target_decl == NULL)
  	{
! 	  if (symbol_alias_set_contains (defined, p->target))
  	    continue;
  
  	  if (! (p->emitted_diags & ALIAS_DIAG_TO_UNDEF)
*************** finish_aliases_1 (void)
*** 5678,5684 ****
  	}
      }
  
!   symbol_alias_set_destroy (visible);
  }
  
  /* Second pass of completing pending aliases.  Emit the actual assembly.
--- 5734,5740 ----
  	}
      }
  
!   symbol_alias_set_destroy (defined);
  }
  
  /* Second pass of completing pending aliases.  Emit the actual assembly.
Index: passes.c
===================================================================
*** passes.c	(revision 168566)
--- passes.c	(working copy)
*************** rest_of_decl_compilation (tree decl,
*** 144,149 ****
--- 144,150 ----
  {
    /* 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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]