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. */
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)
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),
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
{
gcc_assert (!inlined_to);
return (!force_output && !address_taken
+ && !ref_by_asm
&& !ifunc_resolver
&& !used_from_other_partition
&& !DECL_VIRTUAL_P (decl)
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))
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 ())
return (definition
&& !externally_visible
&& !used_from_other_partition
+ && !ref_by_asm
&& !force_output);
}
/* 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))
&& 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 ());
|| DECL_EXTERNAL (node->decl)
|| TREE_PUBLIC (node->decl)
|| node->force_output
+ || node->ref_by_asm
|| lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)));
return false;
}
*nonlocal_p |= (node->used_from_other_partition
|| DECL_EXTERNAL (node->decl)
|| TREE_PUBLIC (node->decl)
+ || node->ref_by_asm
|| node->force_output);
return false;
}
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)
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 ()
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
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 ())
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;
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)
{
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);
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
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);
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);
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);
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)
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++)