> .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;
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
> + }
> +}
> +
> +/* 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
>