> I see that must_remain_in_tu is about functions/variables using the
> problematic symbol.
> 
> I wonder if we can get around by simply producing a static alias of this
> symbol and redirect everything there?  This should solve the renaming
> problem, since we will only globalize the alias.
> We will need to be careful to not replace the alias by ultimate alias
> target, but there is already some infrastructure for that in local
> aliases.
> 
> While we have targets that does not support aliases, those do not
> support LTO...
> 
> Honza

I presumed that alias to assembly symbol would not be possible, but
looking into it, we already emit the alias in a way that would be
compatible with assembly symbols.

So if we would want to allow full inlining of these symbols, we could
use aliases. Though we would still need these flags, at least for ICF.
And we would have to handle aliases to symtab_nodes without definition,
which might break some assumptions.

---

Changes in v3:
Renaming and changes related to const propagation in PATCH 5/9 v3.

---

.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.dg/lto/toplevel-extended-asm-3_0.c: New test.
        * gcc.dg/lto/toplevel-extended-asm-3_1.c: New test.
---
 gcc/asm-toplevel.cc                           | 58 +++++++++++++++++--
 .../gcc.dg/lto/toplevel-extended-asm-2_0.c    | 10 ++++
 .../gcc.dg/lto/toplevel-extended-asm-2_1.c    | 12 ++++
 .../gcc.dg/lto/toplevel-extended-asm-3_0.c    | 18 ++++++
 .../gcc.dg/lto/toplevel-extended-asm-3_1.c    | 14 +++++
 5 files changed, 108 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
 create mode 100644 gcc/testsuite/gcc.dg/lto/toplevel-extended-asm-3_0.c
 create mode 100644 gcc/testsuite/gcc.dg/lto/toplevel-extended-asm-3_1.c

diff --git a/gcc/asm-toplevel.cc b/gcc/asm-toplevel.cc
index 336564bb95e..576e4b3ba73 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_name = true;
+      for (j = 0; node->iterate_referring (j, ref); j++)
+       ref->referring->must_remain_in_tu_body = 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_body = 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,25 @@ 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;
+
+         if (data->asm_definition && !TREE_PUBLIC (node->decl) && flag_lto)
+           node->must_remain_in_tu_name = 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);
     }
@@ -59,10 +102,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;
+}
diff --git a/gcc/testsuite/gcc.dg/lto/toplevel-extended-asm-3_0.c 
b/gcc/testsuite/gcc.dg/lto/toplevel-extended-asm-3_0.c
new file mode 100644
index 00000000000..c20f12b9dfd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/toplevel-extended-asm-3_0.c
@@ -0,0 +1,18 @@
+/* { dg-lto-do link } */
+/* { dg-lto-options {{-O2 -flto -flto-partition=1to1} } } */
+
+static void asm_fn();
+asm("%cc0:" :: ":"(&asm_fn));
+
+static int asm_var;
+asm("%cc0:" :: ":"(&asm_var));
+
+int use_asm_var1 (int* var);
+int use_asm_var2 (int** var);
+void use_asm_fn (void (*fn) ());
+
+int main () {
+  use_asm_fn (asm_fn);
+  int *asm_var_ptr = &asm_var;
+  return use_asm_var2(&asm_var_ptr) + use_asm_var1(&asm_var);
+}
diff --git a/gcc/testsuite/gcc.dg/lto/toplevel-extended-asm-3_1.c 
b/gcc/testsuite/gcc.dg/lto/toplevel-extended-asm-3_1.c
new file mode 100644
index 00000000000..4bd287bce45
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/toplevel-extended-asm-3_1.c
@@ -0,0 +1,14 @@
+__attribute__((noinline))
+int use_asm_var1 (int* var) {
+  return *var;
+}
+
+__attribute__((noinline))
+int use_asm_var2 (int** var) {
+  return **var;
+}
+
+__attribute__((noinline))
+void use_asm_fn (void (*fn) ()) {
+  fn ();
+}
-- 
2.52.0

Reply via email to