re PR lto/45721 (ICE: in function_and_variable_visibility, at ipa.c:673 with -flto)

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.

	* 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.

From-SVN: r168666
This commit is contained in:
Jan Hubicka 2011-01-11 18:29:52 +01:00 committed by Jan Hubicka
parent 1b24890758
commit 6e70182270
10 changed files with 244 additions and 60 deletions

View 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

View 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);

View 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):

View 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;
}

View 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));

View 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

View File

@ -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; }

View File

@ -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;

View 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,

View 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
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->decl);
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->decl)
&& !symbol_alias_set_insert (set, p->target))
changed = true;
}
while (changed);
return visible;
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
@ -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.