aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2011-01-11 18:29:52 +0100
committerJan Hubicka <hubicka@gcc.gnu.org>2011-01-11 17:29:52 +0000
commit6e701822708dbcd9ec935a536830a522d24f8151 (patch)
tree8a0441a53aaf0333716ca7449a404e95b3435f3e /gcc
parent1b248907583f1cf4e02ce4168ad35cf3fe7637ba (diff)
downloadgcc-6e701822708dbcd9ec935a536830a522d24f8151.zip
gcc-6e701822708dbcd9ec935a536830a522d24f8151.tar.gz
gcc-6e701822708dbcd9ec935a536830a522d24f8151.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog26
-rw-r--r--gcc/lto-streamer-out.c87
-rw-r--r--gcc/lto/ChangeLog7
-rw-r--r--gcc/lto/lto.c4
-rw-r--r--gcc/passes.c1
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/gcc.dg/lto/pr45721_0.c8
-rw-r--r--gcc/testsuite/gcc.dg/lto/pr45721_1.c4
-rw-r--r--gcc/tree.h12
-rw-r--r--gcc/varasm.c146
10 files changed, 243 insertions, 59 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9724eee..7c42fab 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index 82c2f6f..7c00293 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -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);
diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog
index 319a47a..4cb66fe 100644
--- a/gcc/lto/ChangeLog
+++ b/gcc/lto/ChangeLog
@@ -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):
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index 9cfb5e2..cbc192a 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -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;
}
diff --git a/gcc/passes.c b/gcc/passes.c
index 804ac9f..090110e 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -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));
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index adb6740..18a4873 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..0af1620
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/pr45721_0.c
@@ -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
index 0000000..63cbfef
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/pr45721_1.c
@@ -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;
diff --git a/gcc/tree.h b/gcc/tree.h
index 216f3d2..a49e335 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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,
diff --git a/gcc/varasm.c b/gcc/varasm.c
index cc05c18..bbebd87 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -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.