aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/cgraph.h3
-rw-r--r--gcc/ipa-visibility.c82
-rw-r--r--gcc/symtab.c55
4 files changed, 148 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 68574f438c8..61515258626 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 e9292852399..1d39d918b21 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 8198a3da175..e4c3f7c5110 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 2d7705e657c..3d3cc4f738c 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. */