diff options
author | Jan Hubicka <hubicka@ucw.cz> | 2016-04-04 11:26:29 +0200 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2016-04-04 09:26:29 +0000 |
commit | ed2a53e7ca7aafa5fea5316c7fdebdc77fb8f327 (patch) | |
tree | 046b846b874b04d1165f5b13e3c53c3879ea4558 /gcc | |
parent | e8661ad6cfb1d6773a8613270250ab69c7faa95c (diff) | |
download | gcc-ed2a53e7ca7aafa5fea5316c7fdebdc77fb8f327.zip gcc-ed2a53e7ca7aafa5fea5316c7fdebdc77fb8f327.tar.gz gcc-ed2a53e7ca7aafa5fea5316c7fdebdc77fb8f327.tar.bz2 |
re PR lto/68881 (UNRESOLVED/FAIL: gcc.dg/lto/attr-weakref-1 -O2 -flto)
PR ipa/68881
* cgraph.h (symtab_node::copy_visibility_from): New function.
* symtab.c (symtab_node::copy_visibility_from): New function.
* ipa-visibility.c (optimize_weakref): New function.
(function_and_variable_visibility): Use it.
From-SVN: r234708
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/cgraph.h | 3 | ||||
-rw-r--r-- | gcc/ipa-visibility.c | 82 | ||||
-rw-r--r-- | gcc/symtab.c | 55 |
4 files changed, 148 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 68574f4..6151525 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2016-03-30 Jan Hubicka <hubicka@ucw.cz> + + PR ipa/68881 + * cgraph.h (symtab_node::copy_visibility_from): New function. + * symtab.c (symtab_node::copy_visibility_from): New function. + * ipa-visibility.c (optimize_weakref): New function. + (function_and_variable_visibility): Use it. + 2016-04-04 Martin Liska <mliska@suse.cz> PR hsa/70402 diff --git a/gcc/cgraph.h b/gcc/cgraph.h index e929285..1d39d91 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -293,6 +293,9 @@ public: /* Make DECL local. */ void make_decl_local (void); + /* Copy visibility from N. */ + void copy_visibility_from (symtab_node *n); + /* Return desired alignment of the definition. This is NOT alignment useful to access THIS, because THIS may be interposable and DECL_ALIGN should be used instead. It however must be guaranteed when output definition diff --git a/gcc/ipa-visibility.c b/gcc/ipa-visibility.c index 8198a3d..e4c3f7c 100644 --- a/gcc/ipa-visibility.c +++ b/gcc/ipa-visibility.c @@ -452,6 +452,84 @@ update_visibility_by_resolution_info (symtab_node * node) } } +/* Try to get rid of weakref. */ + +static void +optimize_weakref (symtab_node *node) +{ +#ifdef ASM_OUTPUT_DEF + bool aliases_supported = true; +#else + bool aliases_supported = false; +#endif + bool strip_weakref = false; + bool static_alias = false; + + gcc_assert (node->weakref); + + /* Weakrefs with no target defined can not be optimized. */ + if (!node->analyzed) + return; + symtab_node *target = node->get_alias_target (); + + /* Weakrefs to weakrefs can be optimized only if target can be. */ + if (target->weakref) + optimize_weakref (target); + if (target->weakref) + return; + + /* If we have definition of weakref's target and we know it binds locally, + we can turn weakref to static alias. */ + if (target->definition && decl_binds_to_current_def_p (target->decl) + && aliases_supported) + strip_weakref = static_alias = true; + /* Otherwise we can turn weakref into transparent alias. This transformation + may break asm statements which directly refers to symbol name and expect + GNU as to translate it via .weakref directive. So do not optimize when + DECL_PRESERVED is set and .weakref is supported. */ + else if ((!DECL_PRESERVE_P (target->decl) + || IDENTIFIER_TRANSPARENT_ALIAS (DECL_ASSEMBLER_NAME (node->decl))) + && !DECL_WEAK (target->decl) + && !DECL_EXTERNAL (target->decl) + && ((target->definition && !target->can_be_discarded_p ()) + || target->resolution != LDPR_UNDEF)) + strip_weakref = true; + if (!strip_weakref) + return; + node->weakref = false; + IDENTIFIER_TRANSPARENT_ALIAS (DECL_ASSEMBLER_NAME (node->decl)) = 0; + TREE_CHAIN (DECL_ASSEMBLER_NAME (node->decl)) = NULL_TREE; + DECL_ATTRIBUTES (node->decl) = remove_attribute ("weakref", + DECL_ATTRIBUTES + (node->decl)); + + if (dump_file) + fprintf (dump_file, "Optimizing weakref %s %s\n", + node->name(), + static_alias ? "as static alias" : "as transparent alias"); + + if (static_alias) + { + /* make_decl_local will shortcircuit if it doesn't see TREE_PUBLIC. + be sure it really clears the WEAK flag. */ + TREE_PUBLIC (node->decl) = true; + node->make_decl_local (); + node->forced_by_abi = false; + node->resolution = LDPR_PREVAILING_DEF_IRONLY; + node->externally_visible = false; + gcc_assert (!DECL_WEAK (node->decl)); + node->transparent_alias = false; + } + else + { + symtab->change_decl_assembler_name + (node->decl, DECL_ASSEMBLER_NAME (node->get_alias_target ()->decl)); + node->transparent_alias = true; + node->copy_visibility_from (target); + } + gcc_assert (node->alias); +} + /* Decide on visibility of all symbols. */ static unsigned int @@ -594,6 +672,8 @@ function_and_variable_visibility (bool whole_program) } update_visibility_by_resolution_info (node); + if (node->weakref) + optimize_weakref (node); } FOR_EACH_DEFINED_FUNCTION (node) { @@ -660,6 +740,8 @@ function_and_variable_visibility (bool whole_program) || ! (ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl)))))) DECL_COMMON (vnode->decl) = 0; + if (vnode->weakref) + optimize_weakref (vnode); } FOR_EACH_DEFINED_VARIABLE (vnode) { diff --git a/gcc/symtab.c b/gcc/symtab.c index 2d7705e..3d3cc4f 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -1287,6 +1287,61 @@ symtab_node::make_decl_local (void) SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl); } +/* Copy visibility from N. + This is useful when THIS becomes a transparent alias of N. */ + +void +symtab_node::copy_visibility_from (symtab_node *n) +{ + gcc_checking_assert (n->weakref == weakref); + + ipa_ref *ref; + for (unsigned i = 0; iterate_direct_aliases (i, ref); i++) + { + struct symtab_node *alias = ref->referring; + if (alias->transparent_alias) + alias->copy_visibility_from (n); + } + + if (TREE_CODE (decl) == VAR_DECL) + { + DECL_COMMON (decl) = DECL_COMMON (n->decl); + /* ADDRESSABLE flag is not defined for public symbols. */ + if (TREE_PUBLIC (decl) && !TREE_PUBLIC (n->decl)) + TREE_ADDRESSABLE (decl) = 1; + TREE_STATIC (decl) = TREE_STATIC (n->decl); + } + else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); + + DECL_COMDAT (decl) = DECL_COMDAT (n->decl); + DECL_WEAK (decl) = DECL_WEAK (n->decl); + DECL_EXTERNAL (decl) = DECL_EXTERNAL (n->decl); + DECL_VISIBILITY_SPECIFIED (decl) = DECL_VISIBILITY_SPECIFIED (n->decl); + DECL_VISIBILITY (decl) = DECL_VISIBILITY (n->decl); + TREE_PUBLIC (decl) = TREE_PUBLIC (n->decl); + DECL_DLLIMPORT_P (decl) = DECL_DLLIMPORT_P (n->decl); + resolution = n->resolution; + set_comdat_group (n->get_comdat_group ()); + call_for_symbol_and_aliases (symtab_node::set_section, + const_cast<char *>(n->get_section ()), true); + externally_visible = n->externally_visible; + if (!DECL_RTL_SET_P (decl)) + return; + + /* Update rtl flags. */ + make_decl_rtl (decl); + + rtx rtl = DECL_RTL (decl); + if (!MEM_P (rtl)) + return; + + rtx symbol = XEXP (rtl, 0); + if (GET_CODE (symbol) != SYMBOL_REF) + return; + + SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl); +} + /* Walk the alias chain to return the symbol NODE is alias of. If NODE is not an alias, return NODE. Assumes NODE is known to be alias. */ |