.local symbols cannot become global, so we have to use must_remain_in_tu.
There is no way to mark declaration as both external and static/.local
in C. So we have to disable the implicit definition of static variables.
Also .local asm function still produces "used but never defined" warning.
gcc/ChangeLog:
* asm-toplevel.cc (mark_fragile_ref_by_asm): New.
(struct constraint_data): New.
(walk_through_constraints): Handle .local definitions.
(analyze_toplevel_extended_asm): Propagate constraint_data.
gcc/testsuite/ChangeLog:
* gcc.dg/lto/toplevel-extended-asm-2_0.c: New test.
* gcc.dg/lto/toplevel-extended-asm-2_1.c: New test.
---
gcc/asm-toplevel.cc | 55 +++++++++++++++++--
.../gcc.dg/lto/toplevel-extended-asm-2_0.c | 10 ++++
.../gcc.dg/lto/toplevel-extended-asm-2_1.c | 12 ++++
3 files changed, 73 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/lto/toplevel-extended-asm-2_0.c
create mode 100644 gcc/testsuite/gcc.dg/lto/toplevel-extended-asm-2_1.c
diff --git a/gcc/asm-toplevel.cc b/gcc/asm-toplevel.cc
index 9d7ba934e29..3f1f0f0aad5 100644
--- a/gcc/asm-toplevel.cc
+++ b/gcc/asm-toplevel.cc
@@ -26,11 +26,40 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pass.h"
#include "cgraph.h"
+/* This symbol must be available and cannot be renamed.
+ Marks the symbol and symbols that reference it. */
+static void
+mark_fragile_ref_by_asm (symtab_node* node)
+{
+ node->ref_by_asm = true;
+ /* Local symbols must remain in the same partition with their callers. */
+ if (!TREE_PUBLIC (node->decl))
+ {
+ unsigned j;
+ ipa_ref *ref;
+ node->must_remain_in_tu = true;
+ for (j = 0; node->iterate_referring (j, ref); j++)
+ ref->referring->must_remain_in_tu = true;
+
+ if (cgraph_node* cnode = dyn_cast <cgraph_node *> (node))
+ for (cgraph_edge *e = cnode->callers; e ; e = e->next_caller)
+ e->caller->must_remain_in_tu = true;
+ }
+}
+
+/* Helper struct for walk_through_constraints. */
+struct constraint_data {
+ asm_node *node;
+ unsigned asm_definition : 1;
+};
+
/* Mark symbols in constraints. */
static tree
-walk_through_constraints (tree* t, int*, void* data)
+walk_through_constraints (tree* t, int*, void* dat)
{
- asm_node* anode = (asm_node*) data;
+ constraint_data* data = (constraint_data*) dat;
+ asm_node* anode = data->node;
+
if (VAR_OR_FUNCTION_DECL_P (*t))
{
symtab_node* node;
@@ -38,11 +67,22 @@ walk_through_constraints (tree* t, int*, void* data)
{
node = symtab_node::get_create (*t);
node->ref_by_asm = true;
+
+ /* Disable implicit definition on static variables defined in asm. */
+ if (data->asm_definition && is_a<varpool_node*> (node)
+ && !TREE_PUBLIC (node->decl))
+ DECL_EXTERNAL (node->decl) = true;
}
else
{
node = symtab_node::get (*t);
gcc_assert (node);
+
+ /* Local symbols defined in asm cannot be renamed.
+ LGEN pass is too early to use node->callers.
+ So we do it in WPA. */
+ if (data->asm_definition && flag_wpa)
+ mark_fragile_ref_by_asm (node);
}
anode->symbols_referenced.safe_push (node);
}
@@ -58,10 +98,17 @@ analyze_toplevel_extended_asm ()
{
if (TREE_CODE (anode->asm_str) != ASM_EXPR)
continue;
+ struct constraint_data data {anode, false};
for (tree l = ASM_INPUTS (anode->asm_str); l; l = TREE_CHAIN (l))
- walk_tree (&l, walk_through_constraints, (void*) anode, NULL);
+ {
+ tree constraint = TREE_VALUE (TREE_PURPOSE (l));
+ const char* c = TREE_STRING_POINTER (constraint);
+ data.asm_definition = c[0] == ':' && c[1] == 0;
+ walk_tree (&l, walk_through_constraints, (void*) &data, NULL);
+ }
+ data.asm_definition = false;
for (tree l = ASM_OUTPUTS (anode->asm_str); l; l = TREE_CHAIN (l))
- walk_tree (&l, walk_through_constraints, (void*) anode, NULL);
+ walk_tree (&l, walk_through_constraints, (void*) &data, NULL);
}
}
diff --git a/gcc/testsuite/gcc.dg/lto/toplevel-extended-asm-2_0.c
b/gcc/testsuite/gcc.dg/lto/toplevel-extended-asm-2_0.c
new file mode 100644
index 00000000000..19ac7c21b2d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/toplevel-extended-asm-2_0.c
@@ -0,0 +1,10 @@
+/* { dg-lto-do link } */
+/* { dg-lto-options {{-O2 -flto -flto-partition=1to1} } } */
+
+extern int use_statics ();
+
+extern int asm_var;
+
+int main() {
+ return use_statics ();
+}
diff --git a/gcc/testsuite/gcc.dg/lto/toplevel-extended-asm-2_1.c
b/gcc/testsuite/gcc.dg/lto/toplevel-extended-asm-2_1.c
new file mode 100644
index 00000000000..a115f139eaa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/toplevel-extended-asm-2_1.c
@@ -0,0 +1,12 @@
+static void static_asm_fn ();
+static int static_asm_var;
+asm("%cc0:" :: ":" (&static_asm_fn));
+asm("%cc0:" :: ":" (&static_asm_var));
+
+extern int asm_var;
+asm("%cc0:" :: ":" (&asm_var));
+
+int use_statics () {
+ static_asm_fn ();
+ return static_asm_var;
+}
--
2.51.1