.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

Reply via email to