From 71e546870c4afb3c3ff993bd354a98637bcccdc7 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Mon, 7 Dec 2015 18:36:54 +0100 Subject: re PR lto/61886 (LTO breaks fread with _FORTIFY_SOURCE=2) PR ipa/61886 * symtab.c (ultimate_transparent_alias_target): New inline function. (symbol_table::assembler_names_equal_p): New method; break out from ... (symbol_table::decl_assembler_name_equal): ... here. (symbol_table::change_decl_assembler_name): Also update names and translation links of transparent aliases. (symtab_node::dump_base): Dump transparent_alias. (symtab_node::verify_base): Implement basic transparent alias verification. (symtab_node::make_decl_local): Support localization of weakrefs; recurse to transparent aliases; set TREE_STATIC. (symtab_node::ultimate_alias_target_1): Handle visibility of transparent aliases. (symtab_node::resolve_alias): New parmaeter transparent; handle transparent aliases; recurse to aliases of aliases to fix comdat groups. (symtab_node::get_partitioning_class): Handle transparent aliases. * ipa-visibility.c (cgraph_externally_visible_p, varpool_node::externally_visible_p): Visibility of transparent alias depends on its target. (function_and_variable_visibility): Do not tweak visibility of transparent laiases. (function_and_variable_visibility): Likewise. * ipa.c (symbol_table::remove_unreachable_nodes): Clear transparent_alias flag. * alias.c (cgraph_node::create_alias, cgraph_node::get_availability): Support transparent aliases. * cgraph.h (symtab_node): Update prototype of resolve_alias; add transparent_alias flag. (symbol_table: Add assembler_names_equal_p. (symtab_node::real_symbol_p): Skip transparent aliases. * cgraphunit.c (cgraph_node::reset): Reset transparent_alias flag. (handle_alias_pairs): Set transparent_alias for weakref. (cgraph_node::assemble_thunks_and_aliases): Do not asemble transparent aliases. * lto-cgraph.c (lto_output_node): When outputting same_comdat_group skip symbols not put into boundary; stream transparent_alias. (lto_output_varpool_node): Likewise. (input_overwrite_node, input_varpool_node): Stream transparent alias. * varpool.c (ctor_for_folding, varpool_node::get_availability, varpool_node::assemble_aliases, symbol_table::remove_unreferenced_decls): Handle transparent aliase. (varpool_node::create_alias): Set transparent_alias. * lto-partition.c (add_symbol_to_partition_1, contained_in_symbol, rename_statics, rename_statics): Handle transparent aliases. From-SVN: r231373 --- gcc/ChangeLog | 46 +++++++++ gcc/cgraph.c | 4 +- gcc/cgraph.h | 31 +++++- gcc/cgraphunit.c | 25 +++-- gcc/ipa-visibility.c | 32 ++++-- gcc/ipa.c | 1 + gcc/lto-cgraph.c | 24 +++-- gcc/lto/ChangeLog | 6 ++ gcc/lto/lto-partition.c | 10 +- gcc/symtab.c | 266 ++++++++++++++++++++++++++++++++++-------------- gcc/tree.c | 57 +++++++---- gcc/varpool.c | 22 ++-- 12 files changed, 388 insertions(+), 136 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index abd648e..d60a6da 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,49 @@ +2015-12-07 Jan Hubicka + + PR ipa/61886 + * symtab.c (ultimate_transparent_alias_target): New inline function. + (symbol_table::assembler_names_equal_p): New method; break out from ... + (symbol_table::decl_assembler_name_equal): ... here. + (symbol_table::change_decl_assembler_name): Also update names and + translation links of transparent aliases. + (symtab_node::dump_base): Dump transparent_alias. + (symtab_node::verify_base): Implement basic transparent alias + verification. + (symtab_node::make_decl_local): Support localization of weakrefs; + recurse to transparent aliases; set TREE_STATIC. + (symtab_node::ultimate_alias_target_1): Handle visibility of + transparent aliases. + (symtab_node::resolve_alias): New parmaeter transparent; handle + transparent aliases; recurse to aliases of aliases to fix comdat + groups. + (symtab_node::get_partitioning_class): Handle transparent aliases. + * ipa-visibility.c (cgraph_externally_visible_p, + varpool_node::externally_visible_p): Visibility of transparent alias + depends on its target. + (function_and_variable_visibility): Do not tweak visibility of + transparent laiases. + (function_and_variable_visibility): Likewise. + * ipa.c (symbol_table::remove_unreachable_nodes): Clear + transparent_alias flag. + * alias.c (cgraph_node::create_alias, cgraph_node::get_availability): + Support transparent aliases. + * cgraph.h (symtab_node): Update prototype of resolve_alias; + add transparent_alias flag. + (symbol_table: Add assembler_names_equal_p. + (symtab_node::real_symbol_p): Skip transparent aliases. + * cgraphunit.c (cgraph_node::reset): Reset transparent_alias flag. + (handle_alias_pairs): Set transparent_alias for weakref. + (cgraph_node::assemble_thunks_and_aliases): Do not asemble transparent + aliases. + * lto-cgraph.c (lto_output_node): When outputting same_comdat_group + skip symbols not put into boundary; stream transparent_alias. + (lto_output_varpool_node): Likewise. + (input_overwrite_node, input_varpool_node): Stream transparent alias. + * varpool.c (ctor_for_folding, varpool_node::get_availability, + varpool_node::assemble_aliases, + symbol_table::remove_unreferenced_decls): Handle transparent aliase. + (varpool_node::create_alias): Set transparent_alias. + 2015-12-07 Eric Botcazou PR middle-end/68291 diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 2a55978..35cd98c 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -560,7 +560,7 @@ cgraph_node::create_alias (tree alias, tree target) alias_node->definition = true; alias_node->alias = true; if (lookup_attribute ("weakref", DECL_ATTRIBUTES (alias)) != NULL) - alias_node->weakref = true; + alias_node->transparent_alias = alias_node->weakref = true; return alias_node; } @@ -2147,7 +2147,7 @@ cgraph_node::get_availability (void) avail = AVAIL_NOT_AVAILABLE; else if (local.local) avail = AVAIL_LOCAL; - else if (alias && weakref) + else if (transparent_alias) ultimate_alias_target (&avail); else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl))) avail = AVAIL_INTERPOSABLE; diff --git a/gcc/cgraph.h b/gcc/cgraph.h index e689fcd..7c643502 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -249,9 +249,10 @@ public: inline symtab_node *next_defined_symbol (void); /* Add reference recording that symtab node is alias of TARGET. + If TRANSPARENT is true make the alias to be transparent alias. The function can fail in the case of aliasing cycles; in this case it returns false. */ - bool resolve_alias (symtab_node *target); + bool resolve_alias (symtab_node *target, bool transparent = false); /* C++ FE sometimes change linkage flags after producing same body aliases. */ @@ -421,6 +422,28 @@ public: /* True when symbol is an alias. Set by ssemble_alias. */ unsigned alias : 1; + /* When true the alias is translated into its target symbol either by GCC + or assembler (it also may just be a duplicate declaration of the same + linker name). + + Currently transparent aliases come in three different flavors + - aliases having the same assembler name as their target (aka duplicated + declarations). In this case the assembler names compare via + assembler_names_equal_p and weakref is false + - aliases that are renamed at a time being output to final file + by varasm.c. For those DECL_ASSEMBLER_NAME have + IDENTIFIER_TRANSPARENT_ALIAS set and thus also their assembler + name must be unique. + Weakrefs belong to this cateogry when we target assembler without + .weakref directive. + - weakrefs that are renamed by assembler via .weakref directive. + In this case the alias may or may not be definition (depending if + target declaration was seen by the compiler), weakref is set. + Unless we are before renaming statics, assembler names are different. + + Given that we now support duplicate declarations, the second option is + redundant and will be removed. */ + unsigned transparent_alias : 1; /* True when alias is a weakref. */ unsigned weakref : 1; /* C++ frontend produce same body aliases and extra name aliases for @@ -2098,6 +2121,10 @@ public: /* Set the DECL_ASSEMBLER_NAME and update symtab hashtables. */ void change_decl_assembler_name (tree decl, tree name); + /* Return true if assembler names NAME1 and NAME2 leads to the same symbol + name. */ + static bool assembler_names_equal_p (const char *name1, const char *name2); + int cgraph_count; int cgraph_max_uid; int cgraph_max_summary_uid; @@ -2251,6 +2278,8 @@ symtab_node::real_symbol_p (void) if (DECL_ABSTRACT_P (decl)) return false; + if (transparent_alias && definition) + return false; if (!is_a (this)) return true; cnode = dyn_cast (this); diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 4ab6414..3d86c36 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -369,6 +369,7 @@ cgraph_node::reset (void) analyzed = false; definition = false; alias = false; + transparent_alias = false; weakref = false; cpp_implicit_alias = false; @@ -594,7 +595,7 @@ cgraph_node::analyze (void) thunk.alias = NULL; } if (alias) - resolve_alias (cgraph_node::get (alias_target)); + resolve_alias (cgraph_node::get (alias_target), transparent_alias); else if (dispatcher_function) { /* Generate the dispatcher body of multi-versioned functions. */ @@ -1254,6 +1255,7 @@ handle_alias_pairs (void) node->alias_target = p->target; node->weakref = true; node->alias = true; + node->transparent_alias = true; } alias_pairs->unordered_remove (i); continue; @@ -1908,15 +1910,18 @@ cgraph_node::assemble_thunks_and_aliases (void) FOR_EACH_ALIAS (this, ref) { cgraph_node *alias = dyn_cast (ref->referring); - bool saved_written = TREE_ASM_WRITTEN (decl); - - /* Force assemble_alias to really output the alias this time instead - of buffering it in same alias pairs. */ - TREE_ASM_WRITTEN (decl) = 1; - do_assemble_alias (alias->decl, - DECL_ASSEMBLER_NAME (decl)); - alias->assemble_thunks_and_aliases (); - TREE_ASM_WRITTEN (decl) = saved_written; + if (!alias->transparent_alias) + { + bool saved_written = TREE_ASM_WRITTEN (decl); + + /* Force assemble_alias to really output the alias this time instead + of buffering it in same alias pairs. */ + TREE_ASM_WRITTEN (decl) = 1; + do_assemble_alias (alias->decl, + DECL_ASSEMBLER_NAME (decl)); + alias->assemble_thunks_and_aliases (); + TREE_ASM_WRITTEN (decl) = saved_written; + } } } diff --git a/gcc/ipa-visibility.c b/gcc/ipa-visibility.c index 2eab214..0423f24 100644 --- a/gcc/ipa-visibility.c +++ b/gcc/ipa-visibility.c @@ -185,6 +185,8 @@ static bool cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program) { + while (node->transparent_alias && node->definition) + node = node->get_alias_target (); if (!node->definition) return false; if (!TREE_PUBLIC (node->decl) @@ -248,6 +250,8 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool varpool_node::externally_visible_p (void) { + while (transparent_alias && definition) + return get_alias_target ()->externally_visible_p (); if (DECL_EXTERNAL (decl)) return true; @@ -531,7 +535,8 @@ function_and_variable_visibility (bool whole_program) next->set_comdat_group (NULL); if (!next->alias) next->set_section (NULL); - next->make_decl_local (); + if (!next->transparent_alias) + next->make_decl_local (); next->unique_name |= ((next->resolution == LDPR_PREVAILING_DEF_IRONLY || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) && TREE_PUBLIC (next->decl) @@ -547,7 +552,8 @@ function_and_variable_visibility (bool whole_program) node->set_comdat_group (NULL); if (DECL_COMDAT (node->decl) && !node->alias) node->set_section (NULL); - node->make_decl_local (); + if (!node->transparent_alias) + node->make_decl_local (); } if (node->thunk.thunk_p @@ -654,7 +660,7 @@ function_and_variable_visibility (bool whole_program) DECL_ATTRIBUTES (vnode->decl))) vnode->no_reorder = 1; if (!vnode->externally_visible - && !vnode->weakref) + && !vnode->transparent_alias) { gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->decl)); vnode->unique_name |= ((vnode->resolution == LDPR_PREVAILING_DEF_IRONLY @@ -675,11 +681,14 @@ function_and_variable_visibility (bool whole_program) next->set_comdat_group (NULL); if (!next->alias) next->set_section (NULL); - next->make_decl_local (); - next->unique_name |= ((next->resolution == LDPR_PREVAILING_DEF_IRONLY - || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) - && TREE_PUBLIC (next->decl) - && !flag_incremental_link); + if (!next->transparent_alias) + { + next->make_decl_local (); + next->unique_name |= ((next->resolution == LDPR_PREVAILING_DEF_IRONLY + || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) + && TREE_PUBLIC (next->decl) + && !flag_incremental_link); + } } vnode->dissolve_same_comdat_group_list (); } @@ -687,8 +696,11 @@ function_and_variable_visibility (bool whole_program) vnode->set_comdat_group (NULL); if (DECL_COMDAT (vnode->decl) && !vnode->alias) vnode->set_section (NULL); - vnode->make_decl_local (); - vnode->resolution = LDPR_PREVAILING_DEF_IRONLY; + if (!vnode->transparent_alias) + { + vnode->make_decl_local (); + vnode->resolution = LDPR_PREVAILING_DEF_IRONLY; + } } update_visibility_by_resolution_info (vnode); diff --git a/gcc/ipa.c b/gcc/ipa.c index 77f2dd1..ce891e1 100644 --- a/gcc/ipa.c +++ b/gcc/ipa.c @@ -543,6 +543,7 @@ symbol_table::remove_unreachable_nodes (FILE *file) node->definition = false; node->cpp_implicit_alias = false; node->alias = false; + node->transparent_alias = false; node->thunk.thunk_p = false; node->weakref = false; /* After early inlining we drop always_inline attributes on diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index 67a9024..e1c2595 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -485,11 +485,12 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, if (group) { - if (node->same_comdat_group && !boundary_p) + if (node->same_comdat_group) { - ref = lto_symtab_encoder_lookup (encoder, - node->same_comdat_group); - gcc_assert (ref != LCC_NOT_FOUND); + ref = LCC_NOT_FOUND; + for (struct symtab_node *n = node->same_comdat_group; + ref == LCC_NOT_FOUND && n != node; n = n->same_comdat_group) + ref = lto_symtab_encoder_lookup (encoder, n); } else ref = LCC_NOT_FOUND; @@ -523,6 +524,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, bp_pack_value (&bp, node->lowered, 1); bp_pack_value (&bp, in_other_partition, 1); bp_pack_value (&bp, node->alias, 1); + bp_pack_value (&bp, node->transparent_alias, 1); bp_pack_value (&bp, node->weakref, 1); bp_pack_value (&bp, node->frequency, 2); bp_pack_value (&bp, node->only_called_at_startup, 1); @@ -599,8 +601,9 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, varpool_node *node, bp_pack_value (&bp, node->definition && (encode_initializer_p || node->alias), 1); bp_pack_value (&bp, node->alias, 1); + bp_pack_value (&bp, node->transparent_alias, 1); bp_pack_value (&bp, node->weakref, 1); - bp_pack_value (&bp, node->analyzed && !boundary_p, 1); + bp_pack_value (&bp, node->analyzed && (!boundary_p || node->alias), 1); gcc_assert (node->definition || !node->analyzed); /* Constant pool initializers can be de-unified into individual ltrans units. FIXME: Alternatively at -Os we may want to avoid generating for them the local @@ -632,11 +635,12 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, varpool_node *node, if (group) { - if (node->same_comdat_group && !boundary_p) + if (node->same_comdat_group) { - ref = lto_symtab_encoder_lookup (encoder, - node->same_comdat_group); - gcc_assert (ref != LCC_NOT_FOUND); + ref = LCC_NOT_FOUND; + for (struct symtab_node *n = node->same_comdat_group; + ref == LCC_NOT_FOUND && n != node; n = n->same_comdat_group) + ref = lto_symtab_encoder_lookup (encoder, n); } else ref = LCC_NOT_FOUND; @@ -1170,6 +1174,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data, TREE_STATIC (node->decl) = 0; } node->alias = bp_unpack_value (bp, 1); + node->transparent_alias = bp_unpack_value (bp, 1); node->weakref = bp_unpack_value (bp, 1); node->frequency = (enum node_frequency)bp_unpack_value (bp, 2); node->only_called_at_startup = bp_unpack_value (bp, 1); @@ -1369,6 +1374,7 @@ input_varpool_node (struct lto_file_decl_data *file_data, node->writeonly = bp_unpack_value (&bp, 1); node->definition = bp_unpack_value (&bp, 1); node->alias = bp_unpack_value (&bp, 1); + node->transparent_alias = bp_unpack_value (&bp, 1); node->weakref = bp_unpack_value (&bp, 1); node->analyzed = bp_unpack_value (&bp, 1); node->used_from_other_partition = bp_unpack_value (&bp, 1); diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index df2eaa9..bdbc866 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,9 @@ +2015-12-07 Jan Hubicka + + PR ipa/61886 + * lto-partition.c (add_symbol_to_partition_1, contained_in_symbol, + rename_statics, rename_statics): Handle transparent aliases. + 2015-12-04 Jan Hubicka * lto-symtab.c (lto_cgraph_replace_node): Update code computing diff --git a/gcc/lto/lto-partition.c b/gcc/lto/lto-partition.c index 4fd445f..ac1b618 100644 --- a/gcc/lto/lto-partition.c +++ b/gcc/lto/lto-partition.c @@ -1035,7 +1035,15 @@ rename_statics (lto_symtab_encoder_t encoder, symtab_node *node) /* Assign every symbol in the set that shares the same ASM name an unique mangled name. */ for (s = symtab_node::get_for_asmname (name); s;) - if (!s->externally_visible + if ((!s->externally_visible || s->weakref) + /* Transparent aliases having same name as target are renamed at a + time their target gets new name. Transparent aliases that use + separate assembler name require the name to be unique. */ + && (!s->transparent_alias || !s->definition || s->weakref + || !symbol_table::assembler_names_equal_p + (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (s->decl)), + IDENTIFIER_POINTER + (DECL_ASSEMBLER_NAME (s->get_alias_target()->decl)))) && ((s->real_symbol_p () && !DECL_EXTERNAL (node->decl) && !TREE_PUBLIC (node->decl)) diff --git a/gcc/symtab.c b/gcc/symtab.c index c188710..06d618b 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -52,6 +52,26 @@ const char * const ld_plugin_symbol_resolution_names[]= "prevailing_def_ironly_exp" }; +/* Follow the IDENTIFIER_TRANSPARENT_ALIAS chain starting at ALIAS + until we find an identifier that is not itself a transparent alias. */ + +static inline tree +ultimate_transparent_alias_target (tree alias) +{ + tree target = alias; + + while (IDENTIFIER_TRANSPARENT_ALIAS (target)) + { + gcc_checking_assert (TREE_CHAIN (target)); + target = TREE_CHAIN (target); + } + gcc_checking_assert (! IDENTIFIER_TRANSPARENT_ALIAS (target) + && ! TREE_CHAIN (target)); + + return target; +} + + /* Hash asmnames ignoring the user specified marks. */ hashval_t @@ -73,6 +93,44 @@ symbol_table::decl_assembler_name_hash (const_tree asmname) return htab_hash_string (IDENTIFIER_POINTER (asmname)); } +/* Return true if assembler names NAME1 and NAME2 leads to the same symbol + name. */ + +bool +symbol_table::assembler_names_equal_p (const char *name1, const char *name2) +{ + if (name1 != name2) + { + if (name1[0] == '*') + { + size_t ulp_len = strlen (user_label_prefix); + + name1 ++; + + if (ulp_len == 0) + ; + else if (strncmp (name1, user_label_prefix, ulp_len) == 0) + name1 += ulp_len; + else + return false; + } + if (name2[0] == '*') + { + size_t ulp_len = strlen (user_label_prefix); + + name2 ++; + + if (ulp_len == 0) + ; + else if (strncmp (name2, user_label_prefix, ulp_len) == 0) + name2 += ulp_len; + else + return false; + } + return !strcmp (name1, name2); + } + return true; +} /* Compare ASMNAME with the DECL_ASSEMBLER_NAME of DECL. */ @@ -82,51 +140,13 @@ symbol_table::decl_assembler_name_equal (tree decl, const_tree asmname) tree decl_asmname = DECL_ASSEMBLER_NAME (decl); const char *decl_str; const char *asmname_str; - bool test = false; if (decl_asmname == asmname) return true; decl_str = IDENTIFIER_POINTER (decl_asmname); asmname_str = IDENTIFIER_POINTER (asmname); - - - /* If the target assembler name was set by the user, things are trickier. - We have a leading '*' to begin with. After that, it's arguable what - is the correct thing to do with -fleading-underscore. Arguably, we've - historically been doing the wrong thing in assemble_alias by always - printing the leading underscore. Since we're not changing that, make - sure user_label_prefix follows the '*' before matching. */ - if (decl_str[0] == '*') - { - size_t ulp_len = strlen (user_label_prefix); - - decl_str ++; - - if (ulp_len == 0) - test = true; - else if (strncmp (decl_str, user_label_prefix, ulp_len) == 0) - decl_str += ulp_len, test=true; - else - decl_str --; - } - if (asmname_str[0] == '*') - { - size_t ulp_len = strlen (user_label_prefix); - - asmname_str ++; - - if (ulp_len == 0) - test = true; - else if (strncmp (asmname_str, user_label_prefix, ulp_len) == 0) - asmname_str += ulp_len, test=true; - else - asmname_str --; - } - - if (!test) - return false; - return strcmp (decl_str, asmname_str) == 0; + return assembler_names_equal_p (decl_str, asmname_str); } @@ -273,6 +293,8 @@ symbol_table::change_decl_assembler_name (tree decl, tree name) : NULL); if (node) unlink_from_assembler_name_hash (node, true); + + const char *old_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) && DECL_RTL_SET_P (decl)) warning (0, "%D renamed after being referenced in assembly", decl); @@ -283,8 +305,48 @@ symbol_table::change_decl_assembler_name (tree decl, tree name) IDENTIFIER_TRANSPARENT_ALIAS (name) = 1; TREE_CHAIN (name) = alias; } + /* If we change assembler name, also all transparent aliases must + be updated. There are three kinds - those having same assembler name, + those being renamed in varasm.c and weakref being renamed by the + assembler. */ if (node) - insert_to_assembler_name_hash (node, true); + { + insert_to_assembler_name_hash (node, true); + ipa_ref *ref; + for (unsigned i = 0; node->iterate_direct_aliases (i, ref); i++) + { + struct symtab_node *alias = ref->referring; + if (alias->transparent_alias && !alias->weakref + && symbol_table::assembler_names_equal_p + (old_name, IDENTIFIER_POINTER ( + DECL_ASSEMBLER_NAME (alias->decl)))) + change_decl_assembler_name (alias->decl, name); + else if (alias->transparent_alias + && IDENTIFIER_TRANSPARENT_ALIAS (alias->decl)) + { + gcc_assert (TREE_CHAIN (DECL_ASSEMBLER_NAME (alias->decl)) + && IDENTIFIER_TRANSPARENT_ALIAS + (DECL_ASSEMBLER_NAME (alias->decl))); + + TREE_CHAIN (DECL_ASSEMBLER_NAME (alias->decl)) = + ultimate_transparent_alias_target + (DECL_ASSEMBLER_NAME (node->decl)); + } +#ifdef ASM_OUTPUT_WEAKREF + else gcc_assert (!alias->transparent_alias || alias->weakref); +#else + else gcc_assert (!alias->transparent_alias); +#endif + } + gcc_assert (!node->transparent_alias || !node->definition + || node->weakref + || TREE_CHAIN (DECL_ASSEMBLER_NAME (decl)) + || symbol_table::assembler_names_equal_p + (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), + IDENTIFIER_POINTER + (DECL_ASSEMBLER_NAME + (node->get_alias_target ()->decl)))); + } } } @@ -727,6 +789,8 @@ symtab_node::dump_base (FILE *f) fprintf (f, " analyzed"); if (alias) fprintf (f, " alias"); + if (transparent_alias) + fprintf (f, " transparent_alias"); if (weakref) fprintf (f, " weakref"); if (cpp_implicit_alias) @@ -973,9 +1037,14 @@ symtab_node::verify_base (void) error ("node is alias but not definition"); error_found = true; } - if (weakref && !alias) + if (weakref && !transparent_alias) { - error ("node is weakref but not an alias"); + error ("node is weakref but not an transparent_alias"); + error_found = true; + } + if (transparent_alias && !alias) + { + error ("node is transparent_alias but not an alias"); error_found = true; } if (same_comdat_group) @@ -1061,6 +1130,29 @@ symtab_node::verify_base (void) get_alias_target ()->dump (stderr); error_found = true; } + if (transparent_alias && definition && !weakref) + { + symtab_node *to = get_alias_target (); + const char *name1 + = IDENTIFIER_POINTER ( + ultimate_transparent_alias_target (DECL_ASSEMBLER_NAME (decl))); + const char *name2 + = IDENTIFIER_POINTER ( + ultimate_transparent_alias_target (DECL_ASSEMBLER_NAME (to->decl))); + if (!symbol_table::assembler_names_equal_p (name1, name2)) + { + error ("Transparent alias and target's assembler names differs"); + get_alias_target ()->dump (stderr); + error_found = true; + } + } + if (transparent_alias && definition + && get_alias_target()->transparent_alias && get_alias_target()->analyzed) + { + error ("Chained transparent aliases"); + get_alias_target ()->dump (stderr); + error_found = true; + } return error_found; } @@ -1132,15 +1224,35 @@ symtab_node::make_decl_local (void) { rtx rtl, symbol; + if (weakref) + { + weakref = false; + IDENTIFIER_TRANSPARENT_ALIAS (DECL_ASSEMBLER_NAME (decl)) = 0; + TREE_CHAIN (DECL_ASSEMBLER_NAME (decl)) = NULL_TREE; + symtab->change_decl_assembler_name + (decl, DECL_ASSEMBLER_NAME (get_alias_target ()->decl)); + DECL_ATTRIBUTES (decl) = remove_attribute ("weakref", + DECL_ATTRIBUTES (decl)); + } /* Avoid clearing comdat_groups on comdat-local decls. */ - if (TREE_PUBLIC (decl) == 0) + else if (TREE_PUBLIC (decl) == 0) return; + /* Localizing a symbol also make all its transparent aliases local. */ + ipa_ref *ref; + for (unsigned i = 0; iterate_direct_aliases (i, ref); i++) + { + struct symtab_node *alias = ref->referring; + if (alias->transparent_alias) + alias->make_decl_local (); + } + if (TREE_CODE (decl) == VAR_DECL) { DECL_COMMON (decl) = 0; /* ADDRESSABLE flag is not defined for public symbols. */ TREE_ADDRESSABLE (decl) = 1; + TREE_STATIC (decl) = 1; } else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); @@ -1175,29 +1287,28 @@ symtab_node::make_decl_local (void) symtab_node * symtab_node::ultimate_alias_target_1 (enum availability *availability) { - bool weakref_p = false; + bool transparent_p = false; /* To determine visibility of the target, we follow ELF semantic of aliases. Here alias is an alternative assembler name of a given definition. Its availability prevails the availability of its target (i.e. static alias of weak definition is available. - Weakref is a different animal (and not part of ELF per se). It is just - alternative name of a given symbol used within one complation unit - and is translated prior hitting the object file. It inherits the - visibility of its target (i.e. weakref of non-overwritable definition - is non-overwritable, while weakref of weak definition is weak). + Transaparent alias is just alternative anme of a given symbol used within + one compilation unit and is translated prior hitting the object file. It + inherits the visibility of its target. + Weakref is a different animal (and noweak definition is weak). If we ever get into supporting targets with different semantics, a target hook will be needed here. */ if (availability) { - weakref_p = weakref; - if (!weakref_p) + transparent_p = transparent_alias; + if (!transparent_p) *availability = get_availability (); else - *availability = AVAIL_LOCAL; + *availability = AVAIL_NOT_AVAILABLE; } symtab_node *node = this; @@ -1207,27 +1318,19 @@ symtab_node::ultimate_alias_target_1 (enum availability *availability) node = node->get_alias_target (); else { - if (!availability) + if (!availability || (!transparent_p && node->analyzed)) ; - else if (node->analyzed) - { - if (weakref_p) - { - enum availability a = node->get_availability (); - if (a < *availability) - *availability = a; - } - } + else if (node->analyzed && !node->transparent_alias) + *availability = node->get_availability (); else *availability = AVAIL_NOT_AVAILABLE; return node; } - if (node && availability && weakref_p) + if (node && availability && transparent_p + && node->transparent_alias) { - enum availability a = node->get_availability (); - if (a < *availability) - *availability = a; - weakref_p = node->weakref; + *availability = node->get_availability (); + transparent_p = false; } } if (availability) @@ -1442,7 +1545,7 @@ symtab_node::set_implicit_section (symtab_node *n, it returns false. */ bool -symtab_node::resolve_alias (symtab_node *target) +symtab_node::resolve_alias (symtab_node *target, bool transparent) { symtab_node *n; @@ -1468,6 +1571,11 @@ symtab_node::resolve_alias (symtab_node *target) definition = true; alias = true; analyzed = true; + transparent |= transparent_alias; + transparent_alias = transparent; + if (transparent) + while (target->transparent_alias && target->analyzed) + target = target->get_alias_target (); create_reference (target, IPA_REF_ALIAS, NULL); /* Add alias into the comdat group of its target unless it is already there. */ @@ -1492,19 +1600,29 @@ symtab_node::resolve_alias (symtab_node *target) when renaming symbols. */ alias_target = NULL; - if (cpp_implicit_alias && symtab->state >= CONSTRUCTION) + if (!transparent && cpp_implicit_alias && symtab->state >= CONSTRUCTION) fixup_same_cpp_alias_visibility (target); /* If alias has address taken, so does the target. */ if (address_taken) target->ultimate_alias_target ()->address_taken = true; - /* All non-weakref aliases of THIS are now in fact aliases of TARGET. */ + /* All non-transparent aliases of THIS are now in fact aliases of TARGET. + If alias is transparent, also all transparent aliases of THIS are now + aliases of TARGET. + Also merge same comdat group lists. */ ipa_ref *ref; for (unsigned i = 0; iterate_direct_aliases (i, ref);) { struct symtab_node *alias_alias = ref->referring; - if (!alias_alias->weakref) + if (alias_alias->get_comdat_group ()) + { + alias_alias->remove_from_same_comdat_group (); + alias_alias->set_comdat_group (NULL); + if (target->get_comdat_group ()) + alias_alias->add_to_same_comdat_group (target); + } + if (!alias_alias->transparent_alias || transparent) { alias_alias->remove_all_references (); alias_alias->create_reference (target, IPA_REF_ALIAS, NULL); @@ -1648,9 +1766,9 @@ symtab_node::get_partitioning_class (void) if (cnode && cnode->global.inlined_to) return SYMBOL_DUPLICATE; - /* Weakref aliases are always duplicated. */ - if (weakref) - return SYMBOL_DUPLICATE; + /* Transparent aliases are always duplicated. */ + if (transparent_alias) + return definition ? SYMBOL_DUPLICATE : SYMBOL_EXTERNAL; /* External declarations are external. */ if (DECL_EXTERNAL (decl)) diff --git a/gcc/tree.c b/gcc/tree.c index c8b3ab8..de67c4f 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -13423,6 +13423,12 @@ gimple_canonical_types_compatible_p (const_tree t1, const_tree t2, { tree f1, f2; + /* Don't try to compare variants of an incomplete type, before + TYPE_FIELDS has been copied around. */ + if (!COMPLETE_TYPE_P (t1) && !COMPLETE_TYPE_P (t2)) + return true; + + if (TYPE_REVERSE_STORAGE_ORDER (t1) != TYPE_REVERSE_STORAGE_ORDER (t2)) return false; @@ -13709,28 +13715,35 @@ verify_type (const_tree t) } } else if (RECORD_OR_UNION_TYPE_P (t)) - for (tree fld = TYPE_FIELDS (t); fld; fld = TREE_CHAIN (fld)) - { - /* TODO: verify properties of decls. */ - if (TREE_CODE (fld) == FIELD_DECL) - ; - else if (TREE_CODE (fld) == TYPE_DECL) - ; - else if (TREE_CODE (fld) == CONST_DECL) - ; - else if (TREE_CODE (fld) == VAR_DECL) - ; - else if (TREE_CODE (fld) == TEMPLATE_DECL) - ; - else if (TREE_CODE (fld) == USING_DECL) - ; - else - { - error ("Wrong tree in TYPE_FIELDS list"); - debug_tree (fld); - error_found = true; - } - } + { + if (TYPE_FIELDS (t) && !COMPLETE_TYPE_P (t) && in_lto_p) + { + error ("TYPE_FIELDS defined in incomplete type"); + error_found = true; + } + for (tree fld = TYPE_FIELDS (t); fld; fld = TREE_CHAIN (fld)) + { + /* TODO: verify properties of decls. */ + if (TREE_CODE (fld) == FIELD_DECL) + ; + else if (TREE_CODE (fld) == TYPE_DECL) + ; + else if (TREE_CODE (fld) == CONST_DECL) + ; + else if (TREE_CODE (fld) == VAR_DECL) + ; + else if (TREE_CODE (fld) == TEMPLATE_DECL) + ; + else if (TREE_CODE (fld) == USING_DECL) + ; + else + { + error ("Wrong tree in TYPE_FIELDS list"); + debug_tree (fld); + error_found = true; + } + } + } else if (TREE_CODE (t) == INTEGER_TYPE || TREE_CODE (t) == BOOLEAN_TYPE || TREE_CODE (t) == OFFSET_TYPE diff --git a/gcc/varpool.c b/gcc/varpool.c index 36f19a6..ffbec6d 100644 --- a/gcc/varpool.c +++ b/gcc/varpool.c @@ -440,7 +440,7 @@ ctor_for_folding (tree decl) gcc_assert (!DECL_INITIAL (decl) || (node->alias && node->get_alias_target () == real_node) || DECL_INITIAL (decl) == error_mark_node); - if (node->weakref) + while (node->transparent_alias && node->analyzed) { node = node->get_alias_target (); decl = node->decl; @@ -490,11 +490,11 @@ varpool_node::get_availability (void) if (DECL_IN_CONSTANT_POOL (decl) || DECL_VIRTUAL_P (decl)) return AVAIL_AVAILABLE; - if (alias && weakref) + if (transparent_alias) { enum availability avail; - ultimate_alias_target (&avail)->get_availability (); + ultimate_alias_target (&avail); return avail; } /* If the variable can be overwritten, return OVERWRITABLE. Takes @@ -536,8 +536,9 @@ varpool_node::assemble_aliases (void) FOR_EACH_ALIAS (this, ref) { varpool_node *alias = dyn_cast (ref->referring); - do_assemble_alias (alias->decl, - DECL_ASSEMBLER_NAME (decl)); + if (!alias->transparent_alias) + do_assemble_alias (alias->decl, + DECL_ASSEMBLER_NAME (decl)); alias->assemble_aliases (); } } @@ -665,7 +666,14 @@ symbol_table::remove_unreferenced_decls (void) && vnode->analyzed) enqueue_node (vnode, &first); else - referenced.add (node); + { + referenced.add (node); + while (node->alias && node->definition) + { + node = node->get_alias_target (); + referenced.add (node); + } + } } } if (dump_file) @@ -760,7 +768,7 @@ varpool_node::create_alias (tree alias, tree decl) alias_node->definition = true; alias_node->alias_target = decl; if (lookup_attribute ("weakref", DECL_ATTRIBUTES (alias)) != NULL) - alias_node->weakref = true; + alias_node->weakref = alias_node->transparent_alias = true; return alias_node; } -- cgit v1.1