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.

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                        |  4 ++--
 gcc/lto-cgraph.cc                 |  4 ++++
 gcc/lto/lto-symtab.cc             |  3 +++
 gcc/symtab.cc                     |  2 +-
 10 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc
index ab09376a1a0..02a7d569b68 100644
--- a/gcc/cgraph.cc
+++ b/gcc/cgraph.cc
@@ -2793,6 +2793,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.  */
@@ -3953,6 +3954,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 aa2207b1dd2..4aed690bac9 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
@@ -3274,6 +3279,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)
@@ -3294,7 +3300,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))
@@ -3326,6 +3332,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 ())
@@ -3344,6 +3351,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..a0389aa2c51 100644
--- a/gcc/ipa.cc
+++ b/gcc/ipa.cc
@@ -521,7 +521,7 @@ symbol_table::remove_unreachable_nodes (FILE *file)
       next = next_function (node);
 
       /* If node is not needed at all, remove it.  */
-      if (!node->aux)
+      if (!node->aux && !node->ref_by_asm)
        {
          if (file)
            fprintf (file, " %s", node->dump_name ());
@@ -597,7 +597,7 @@ symbol_table::remove_unreachable_nodes (FILE *file)
   for (vnode = first_variable (); vnode; vnode = vnext)
     {
       vnext = next_variable (vnode);
-      if (!vnode->aux
+      if (!vnode->aux && !vnode->ref_by_asm
          /* For can_refer_decl_in_current_unit_p we want to track for
             all external variables if they are defined in other partition
             or not.  */
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