diff options
-rw-r--r-- | gcc/ChangeLog | 26 | ||||
-rw-r--r-- | gcc/lto-streamer-out.c | 87 | ||||
-rw-r--r-- | gcc/lto/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/lto/lto.c | 4 | ||||
-rw-r--r-- | gcc/passes.c | 1 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/lto/pr45721_0.c | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/lto/pr45721_1.c | 4 | ||||
-rw-r--r-- | gcc/tree.h | 12 | ||||
-rw-r--r-- | gcc/varasm.c | 146 |
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; @@ -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. |