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