Only differences in v2 are in symbol_table::remove_unreachable_nodes,
see comment below.

---

ref_by_asm will be used by toplevel assembly to mark symbols that cannot
be removed.
It largely overlaps with force_output. Main difference is that ref_by_asm
is meaningful on declarations by not removing them. force_output with
declaration is ignored, which cannot be easily changed, since several
places depend on this behavior.

Global ref_by_asm should not be localized, because they cannot benefit
from it. It would only result in complications, for example by renaming
the symbol.

Notes on different solutions in unreachability analysis:
First unreachability analysis is done in analyze_functions. Marking
ref_by_asm declarations as needed from the start would require
reprocessing, because some declarations may gain definition during the
analysis. Since at this point declarations do not need adding any other
symbol, we can check for ref_by_asm at the end, next to referred_to_p
check.

Second unreachability analysis is in remove_unreachable_nodes. Here
declarations (or symbols in_other_partition) may require an alias.
So there we need to add the declarations from the start.

gcc/ChangeLog:

        * cgraph.cc (cgraph_node_cannot_be_local_p_1): Check ref_by_asm.
        (cgraph_node::verify_node): Likewise.
        * cgraph.h (cgraph_node::only_called_directly_or_aliased_p):
        Likewise.
        (cgraph_node::can_remove_if_no_direct_calls_and_refs_p):
        Likewise.
        (varpool_node::can_remove_if_no_refs_p): Likewise.
        (varpool_node::all_refs_explicit_p): Likewise.
        * cgraphunit.cc (symtab_node::needed_p): Likewise.
        (analyze_functions): Likewise.
        * gimple-ssa-pta-constraints.cc (refered_from_nonlocal_fn):
        Likewise.
        (refered_from_nonlocal_var): Likewise.
        (ipa_create_global_variable_infos): Likewise.
        * ipa-comdats.cc (ipa_comdats): Likewise.
        * ipa-visibility.cc (cgraph_externally_visible_p): Likewise.
        (varpool_node::externally_visible_p): Likewise.
        * ipa.cc (symbol_table::remove_unreachable_nodes): Likewise.
        * lto-cgraph.cc (lto_output_node): Output ref_by_asm.
        (lto_output_varpool_node): Likewise.
        (input_overwrite_node): Input ref_by_asm.
        (input_varpool_node): Likewise.
        * symtab.cc (address_matters_1): Check ref_by_asm.

gcc/lto/ChangeLog:

        * lto-symtab.cc (lto_cgraph_replace_node): Propagate ref_by_asm.
        (lto_varpool_replace_node): Propagate ref_by_asm.
---
 gcc/cgraph.cc                     |  6 ++++++
 gcc/cgraph.h                      | 10 +++++++++-
 gcc/cgraphunit.cc                 |  4 +++-
 gcc/gimple-ssa-pta-constraints.cc |  5 ++++-
 gcc/ipa-comdats.cc                |  1 +
 gcc/ipa-visibility.cc             |  4 ++++
 gcc/ipa.cc                        |  7 +++++++
 gcc/lto-cgraph.cc                 |  4 ++++
 gcc/lto/lto-symtab.cc             |  3 +++
 gcc/symtab.cc                     |  2 +-
 10 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc
index 3c21e174943..1dfb4027a89 100644
--- a/gcc/cgraph.cc
+++ b/gcc/cgraph.cc
@@ -2794,6 +2794,7 @@ static bool
 cgraph_node_cannot_be_local_p_1 (cgraph_node *node, void *)
 {
   return !(!node->force_output
+          && !node->ref_by_asm
           && !node->ifunc_resolver
           /* Limitation of gas requires us to output targets of symver aliases
              as global symbols.  This is binutils PR 25295.  */
@@ -3954,6 +3955,11 @@ cgraph_node::verify_node (void)
       error ("inline clone is forced to output");
       error_found = true;
     }
+  if (inlined_to && ref_by_asm)
+    {
+      error ("inline clone is referenced by assembly");
+      error_found = true;
+    }
   if (symtab->state != LTO_STREAMING)
     {
       if (calls_comdat_local && !same_comdat_group)
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 313610fbe2c..e1df02ebbc6 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -140,6 +140,7 @@ public:
       symver (false), analyzed (false), writeonly (false),
       refuse_visibility_changes (false), externally_visible (false),
       no_reorder (false), force_output (false), forced_by_abi (false),
+      ref_by_asm (false),
       unique_name (false), implicit_section (false), body_removed (false),
       semantic_interposition (flag_semantic_interposition),
       used_from_other_partition (false), in_other_partition (false),
@@ -588,6 +589,10 @@ public:
      exported.  Unlike FORCE_OUTPUT this flag gets cleared to symbols promoted
      to static and it does not inhibit optimization.  */
   unsigned forced_by_abi : 1;
+  /* Referenced from toplevel assembly.  Must not be removed.
+     Static symbol may be renamed.  Global symbol should not be renamed.
+     Unlike force_output, can be on declarations.  */
+  unsigned ref_by_asm : 1;
   /* True when the name is known to be unique and thus it does not need 
mangling.  */
   unsigned unique_name : 1;
   /* Specify whether the section was set by user or by
@@ -3276,6 +3281,7 @@ cgraph_node::only_called_directly_or_aliased_p (void)
 {
   gcc_assert (!inlined_to);
   return (!force_output && !address_taken
+         && !ref_by_asm
          && !ifunc_resolver
          && !used_from_other_partition
          && !DECL_VIRTUAL_P (decl)
@@ -3296,7 +3302,7 @@ cgraph_node::can_remove_if_no_direct_calls_and_refs_p 
(void)
   if (DECL_EXTERNAL (decl))
     return true;
   /* When function is needed, we cannot remove it.  */
-  if (force_output || used_from_other_partition)
+  if (force_output || used_from_other_partition || ref_by_asm)
     return false;
   if (DECL_STATIC_CONSTRUCTOR (decl)
       || DECL_STATIC_DESTRUCTOR (decl))
@@ -3328,6 +3334,7 @@ varpool_node::can_remove_if_no_refs_p (void)
   if (DECL_EXTERNAL (decl))
     return true;
   return (!force_output && !used_from_other_partition
+         && !ref_by_asm
          && ((DECL_COMDAT (decl)
               && !forced_by_abi
               && !used_from_object_file_p ())
@@ -3346,6 +3353,7 @@ varpool_node::all_refs_explicit_p ()
   return (definition
          && !externally_visible
          && !used_from_other_partition
+         && !ref_by_asm
          && !force_output);
 }
 
diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc
index a81f685654f..d50ffd270b6 100644
--- a/gcc/cgraphunit.cc
+++ b/gcc/cgraphunit.cc
@@ -255,6 +255,8 @@ symtab_node::needed_p (void)
   /* If the user told us it is used, then it must be so.  */
   if (force_output)
     return true;
+  if (ref_by_asm)
+    return true;
 
   /* ABI forced symbols are needed when they are external.  */
   if (forced_by_abi && TREE_PUBLIC (decl))
@@ -1383,7 +1385,7 @@ analyze_functions (bool first_time)
          && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (node->decl))
          && DECL_EXTERNAL (node->decl))
        TREE_READONLY (node->decl) = 0;
-      if (!node->aux && !node->referred_to_p ())
+      if (!node->aux && !node->referred_to_p () && !node->ref_by_asm)
        {
          if (symtab->dump_file)
            fprintf (symtab->dump_file, " %s", node->dump_name ());
diff --git a/gcc/gimple-ssa-pta-constraints.cc 
b/gcc/gimple-ssa-pta-constraints.cc
index 7212707858e..d68c59ae777 100644
--- a/gcc/gimple-ssa-pta-constraints.cc
+++ b/gcc/gimple-ssa-pta-constraints.cc
@@ -3866,6 +3866,7 @@ refered_from_nonlocal_fn (struct cgraph_node *node, void 
*data)
                  || DECL_EXTERNAL (node->decl)
                  || TREE_PUBLIC (node->decl)
                  || node->force_output
+                 || node->ref_by_asm
                  || lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)));
   return false;
 }
@@ -3878,6 +3879,7 @@ refered_from_nonlocal_var (struct varpool_node *node, 
void *data)
   *nonlocal_p |= (node->used_from_other_partition
                  || DECL_EXTERNAL (node->decl)
                  || TREE_PUBLIC (node->decl)
+                 || node->ref_by_asm
                  || node->force_output);
   return false;
 }
@@ -3962,7 +3964,8 @@ ipa_create_global_variable_infos (void)
       bool nonlocal_p = (DECL_EXTERNAL (var->decl)
                         || TREE_PUBLIC (var->decl)
                         || var->used_from_other_partition
-                        || var->force_output);
+                        || var->force_output
+                        || var->ref_by_asm);
       var->call_for_symbol_and_aliases (refered_from_nonlocal_var,
                                        &nonlocal_p, true);
       if (nonlocal_p)
diff --git a/gcc/ipa-comdats.cc b/gcc/ipa-comdats.cc
index 0c6f8a70831..2ac51abc79e 100644
--- a/gcc/ipa-comdats.cc
+++ b/gcc/ipa-comdats.cc
@@ -262,6 +262,7 @@ ipa_comdats (void)
        user section names.  */
     else if (symbol->externally_visible
             || symbol->force_output
+            || symbol->ref_by_asm
             || symbol->used_from_other_partition
             || TREE_THIS_VOLATILE (symbol->decl)
             || symbol->get_section ()
diff --git a/gcc/ipa-visibility.cc b/gcc/ipa-visibility.cc
index 8097a03e240..19161ccb1eb 100644
--- a/gcc/ipa-visibility.cc
+++ b/gcc/ipa-visibility.cc
@@ -198,6 +198,8 @@ cgraph_externally_visible_p (struct cgraph_node *node,
   if (!TREE_PUBLIC (node->decl)
       || DECL_EXTERNAL (node->decl))
     return false;
+  if (node->ref_by_asm)
+    return true;
 
   /* Do not try to localize built-in functions yet.  One of problems is that we
      end up mangling their asm for WHOPR that makes it impossible to call them
@@ -269,6 +271,8 @@ varpool_node::externally_visible_p (void)
 
   if (!TREE_PUBLIC (decl))
     return false;
+  if (ref_by_asm)
+    return true;
 
   /* If linker counts on us, we must preserve the function.  */
   if (used_from_object_file_p ())
diff --git a/gcc/ipa.cc b/gcc/ipa.cc
index dea22ea0b49..c306729cfec 100644
--- a/gcc/ipa.cc
+++ b/gcc/ipa.cc
@@ -310,6 +310,7 @@ bool
 symbol_table::remove_unreachable_nodes (FILE *file)
 {
   symtab_node *first = (symtab_node *) (void *) 1;
+  symtab_node *snode;
   struct cgraph_node *node, *next;
   varpool_node *vnode, *vnext;
   bool changed = false;
@@ -358,6 +359,12 @@ symbol_table::remove_unreachable_nodes (FILE *file)
        enqueue_node (vnode, &first, &reachable);
       }
 
+  /* Declarations or symbols in other partitions are also needed if referenced
+     from asm.  */
+  FOR_EACH_SYMBOL (snode)
+    if (snode->ref_by_asm)
+      enqueue_node (snode, &first, &reachable);
+
   /* Perform reachability analysis.  */
   while (first != (symtab_node *) (void *) 1)
     {
diff --git a/gcc/lto-cgraph.cc b/gcc/lto-cgraph.cc
index 4c60bf0dd74..9be75dd90d7 100644
--- a/gcc/lto-cgraph.cc
+++ b/gcc/lto-cgraph.cc
@@ -531,6 +531,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct 
cgraph_node *node,
   bp_pack_value (&bp, node->redefined_extern_inline, 1);
   bp_pack_value (&bp, node->force_output, 1);
   bp_pack_value (&bp, node->forced_by_abi, 1);
+  bp_pack_value (&bp, node->ref_by_asm, 1);
   bp_pack_value (&bp, node->unique_name, 1);
   bp_pack_value (&bp, node->body_removed, 1);
   bp_pack_value (&bp, node->semantic_interposition, 1);
@@ -618,6 +619,7 @@ lto_output_varpool_node (struct lto_simple_output_block 
*ob, varpool_node *node,
   bp_pack_value (&bp, node->no_reorder, 1);
   bp_pack_value (&bp, node->force_output, 1);
   bp_pack_value (&bp, node->forced_by_abi, 1);
+  bp_pack_value (&bp, node->ref_by_asm, 1);
   bp_pack_value (&bp, node->unique_name, 1);
   bp_pack_value (&bp,
                 node->body_removed
@@ -1232,6 +1234,7 @@ input_overwrite_node (struct lto_file_decl_data 
*file_data,
   node->redefined_extern_inline = bp_unpack_value (bp, 1);
   node->force_output = bp_unpack_value (bp, 1);
   node->forced_by_abi = bp_unpack_value (bp, 1);
+  node->ref_by_asm = bp_unpack_value (bp, 1);
   node->unique_name = bp_unpack_value (bp, 1);
   node->body_removed = bp_unpack_value (bp, 1);
   node->semantic_interposition = bp_unpack_value (bp, 1);
@@ -1438,6 +1441,7 @@ input_varpool_node (struct lto_file_decl_data *file_data,
   node->no_reorder = bp_unpack_value (&bp, 1);
   node->force_output = bp_unpack_value (&bp, 1);
   node->forced_by_abi = bp_unpack_value (&bp, 1);
+  node->ref_by_asm = bp_unpack_value (&bp, 1);
   node->unique_name = bp_unpack_value (&bp, 1);
   node->body_removed = bp_unpack_value (&bp, 1);
   node->semantic_interposition = bp_unpack_value (&bp, 1);
diff --git a/gcc/lto/lto-symtab.cc b/gcc/lto/lto-symtab.cc
index 8d7fc6805e9..2a84fce24ff 100644
--- a/gcc/lto/lto-symtab.cc
+++ b/gcc/lto/lto-symtab.cc
@@ -61,6 +61,8 @@ lto_cgraph_replace_node (struct cgraph_node *node,
     prevailing_node->mark_force_output ();
   if (node->forced_by_abi)
     prevailing_node->forced_by_abi = true;
+  prevailing_node->ref_by_asm |= node->ref_by_asm;
+
   if (node->address_taken)
     {
       gcc_assert (!prevailing_node->inlined_to);
@@ -121,6 +123,7 @@ lto_varpool_replace_node (varpool_node *vnode,
     prevailing_node->force_output = true;
   if (vnode->forced_by_abi)
     prevailing_node->forced_by_abi = true;
+  prevailing_node->ref_by_asm |= vnode->ref_by_asm;
 
   /* Be sure we can garbage collect the initializer.  */
   if (DECL_INITIAL (vnode->decl)
diff --git a/gcc/symtab.cc b/gcc/symtab.cc
index 3dbfad33ea2..4ca27387862 100644
--- a/gcc/symtab.cc
+++ b/gcc/symtab.cc
@@ -2450,7 +2450,7 @@ address_matters_1 (symtab_node *n, void *)
 
   if (!n->address_can_be_compared_p ())
     return false;
-  if (n->externally_visible || n->force_output)
+  if (n->externally_visible || n->force_output || n->ref_by_asm)
     return true;
 
   for (unsigned int i = 0; n->iterate_referring (i, ref); i++)
-- 
2.51.1

Reply via email to