This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Get aliases and weakrefs into better shape with LTO
- From: Jan Hubicka <hubicka at ucw dot cz>
- To: Dave Korn <dave dot korn dot cygwin at gmail dot com>
- Cc: Jan Hubicka <hubicka at ucw dot cz>, gcc-patches at gcc dot gnu dot org, rguenther at suse dot de, jakub at redhat dot com, dnovillo at google dot com
- Date: Fri, 7 Jan 2011 17:57:24 +0100
- Subject: Re: Get aliases and weakrefs into better shape with LTO
- References: <20110107010242.GC32433@kam.mff.cuni.cz> <4D267BF4.5080101@gmail.com>
> 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));