summaryrefslogtreecommitdiff
path: root/gcc/cgraphunit.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cgraphunit.c')
-rw-r--r--gcc/cgraphunit.c261
1 files changed, 121 insertions, 140 deletions
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index ca314a68476..016a6e43fa9 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -216,37 +216,45 @@ static GTY(()) struct asm_node *asm_last_node;
/* Used for vtable lookup in thunk adjusting. */
static GTY (()) tree vtable_entry_type;
-/* Determine if function DECL is trivially needed and should stay in the
- compilation unit. This is used at the symbol table construction time
- and differs from later logic removing unnecessary functions that can
- take into account results of analysis, whole program info etc. */
-
-static bool
-cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl)
+/* Determine if symbol DECL is needed. That is, visible to something
+ either outside this translation unit, something magic in the system
+ configury */
+bool
+decide_is_symbol_needed (symtab_node node)
{
- /* If the user told us it is used, then it must be so. */
- if (node->symbol.force_output)
- return true;
+ tree decl = node->symbol.decl;
/* Double check that no one output the function into assembly file
early. */
gcc_checking_assert (!DECL_ASSEMBLER_NAME_SET_P (decl)
- || (node->thunk.thunk_p || node->same_body_alias)
- || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)));
+ || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)));
+
+ if (!node->symbol.definition)
+ return false;
+ /* Devirtualization may access these. */
+ if (DECL_VIRTUAL_P (decl) && optimize)
+ return true;
- /* Keep constructors, destructors and virtual functions. */
- if (DECL_STATIC_CONSTRUCTOR (decl)
- || DECL_STATIC_DESTRUCTOR (decl)
- || (DECL_VIRTUAL_P (decl)
- && optimize && (DECL_COMDAT (decl) || DECL_EXTERNAL (decl))))
- return true;
+ if (DECL_EXTERNAL (decl))
+ return false;
- /* Externally visible functions must be output. The exception is
- COMDAT functions that must be output only when they are needed. */
+ /* If the user told us it is used, then it must be so. */
+ if (node->symbol.force_output)
+ return true;
- if (TREE_PUBLIC (decl)
- && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
+ /* ABI forced symbols are needed when they are external. */
+ if (node->symbol.forced_by_abi && TREE_PUBLIC (decl))
+ return true;
+
+ /* Keep constructors, destructors and virtual functions. */
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && (DECL_STATIC_CONSTRUCTOR (decl) || DECL_STATIC_DESTRUCTOR (decl)))
+ return true;
+
+ /* Externally visible variables must be output. The exception is
+ COMDAT variables that must be output only when they are needed. */
+ if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl))
return true;
return false;
@@ -370,6 +378,9 @@ cgraph_reset_node (struct cgraph_node *node)
memset (&node->rtl, 0, sizeof (node->rtl));
node->symbol.analyzed = false;
node->symbol.definition = false;
+ node->symbol.alias = false;
+ node->symbol.weakref = false;
+ node->symbol.cpp_implicit_alias = false;
cgraph_node_remove_callees (node);
ipa_remove_all_references (&node->symbol.ref_list);
@@ -426,7 +437,7 @@ cgraph_finalize_function (tree decl, bool nested)
in the original implementation and it is unclear whether we want
to change the behavior here. */
if ((!optimize
- && !node->same_body_alias
+ && !node->symbol.cpp_implicit_alias
&& !DECL_DISREGARD_INLINE_LIMITS (decl)
&& !DECL_DECLARED_INLINE_P (decl)
&& !(DECL_CONTEXT (decl)
@@ -446,7 +457,7 @@ cgraph_finalize_function (tree decl, bool nested)
ggc_collect ();
if (cgraph_state == CGRAPH_STATE_CONSTRUCTION
- && (cgraph_decide_is_function_needed (node, decl)
+ && (decide_is_symbol_needed ((symtab_node) node)
|| referred_to_p ((symtab_node)node)))
enqueue_node ((symtab_node)node);
}
@@ -573,22 +584,6 @@ output_asm_statements (void)
asm_nodes = NULL;
}
-/* C++ FE sometimes change linkage flags after producing same body aliases. */
-void
-fixup_same_cpp_alias_visibility (symtab_node node, symtab_node target, tree alias)
-{
- DECL_VIRTUAL_P (node->symbol.decl) = DECL_VIRTUAL_P (alias);
- if (TREE_PUBLIC (node->symbol.decl))
- {
- DECL_EXTERNAL (node->symbol.decl) = DECL_EXTERNAL (alias);
- DECL_COMDAT (node->symbol.decl) = DECL_COMDAT (alias);
- DECL_COMDAT_GROUP (node->symbol.decl) = DECL_COMDAT_GROUP (alias);
- if (DECL_ONE_ONLY (alias)
- && !node->symbol.same_comdat_group)
- symtab_add_to_same_comdat_group ((symtab_node)node, (symtab_node)target);
- }
-}
-
/* Analyze the function scheduled to be output. */
static void
analyze_function (struct cgraph_node *node)
@@ -597,39 +592,14 @@ analyze_function (struct cgraph_node *node)
location_t saved_loc = input_location;
input_location = DECL_SOURCE_LOCATION (decl);
- if (node->symbol.alias && node->thunk.alias)
- {
- struct cgraph_node *tgt = cgraph_get_node (node->thunk.alias);
- struct cgraph_node *n;
-
- for (n = tgt; n && n->symbol.alias;
- n = n->symbol.analyzed ? cgraph_alias_target (n) : NULL)
- if (n == node)
- {
- error ("function %q+D part of alias cycle", node->symbol.decl);
- node->symbol.alias = false;
- input_location = saved_loc;
- return;
- }
- if (!vec_safe_length (node->symbol.ref_list.references))
- ipa_record_reference ((symtab_node)node, (symtab_node)tgt,
- IPA_REF_ALIAS, NULL);
- if (node->same_body_alias)
- {
- DECL_DECLARED_INLINE_P (node->symbol.decl)
- = DECL_DECLARED_INLINE_P (node->thunk.alias);
- DECL_DISREGARD_INLINE_LIMITS (node->symbol.decl)
- = DECL_DISREGARD_INLINE_LIMITS (node->thunk.alias);
- fixup_same_cpp_alias_visibility ((symtab_node) node, (symtab_node) tgt, node->thunk.alias);
- }
-
- if (node->symbol.address_taken)
- cgraph_mark_address_taken_node (cgraph_alias_target (node));
- }
+ if (node->symbol.alias)
+ symtab_resolve_alias
+ ((symtab_node) node, (symtab_node) cgraph_get_node (node->symbol.alias_target));
else if (node->thunk.thunk_p)
{
cgraph_create_edge (node, cgraph_get_node (node->thunk.alias),
NULL, 0, CGRAPH_FREQ_BASE);
+ node->thunk.alias = NULL;
}
else if (node->dispatcher_function)
{
@@ -693,16 +663,15 @@ analyze_function (struct cgraph_node *node)
void
cgraph_process_same_body_aliases (void)
{
- struct cgraph_node *node;
- FOR_EACH_FUNCTION (node)
- if (node->same_body_alias
- && !vec_safe_length (node->symbol.ref_list.references))
- {
- struct cgraph_node *tgt = cgraph_get_node (node->thunk.alias);
- ipa_record_reference ((symtab_node)node, (symtab_node)tgt,
- IPA_REF_ALIAS, NULL);
- }
- same_body_aliases_done = true;
+ symtab_node node;
+ FOR_EACH_SYMBOL (node)
+ if (node->symbol.cpp_implicit_alias && !node->symbol.analyzed)
+ symtab_resolve_alias
+ (node,
+ TREE_CODE (node->symbol.alias_target) == VAR_DECL
+ ? (symtab_node)varpool_node_for_decl (node->symbol.alias_target)
+ : (symtab_node)cgraph_get_create_node (node->symbol.alias_target));
+ cpp_implicit_aliases_done = true;
}
/* Process attributes common for vars and functions. */
@@ -842,7 +811,7 @@ varpool_finalize_decl (tree decl)
node->symbol.force_output = true;
if (cgraph_state == CGRAPH_STATE_CONSTRUCTION
- && (decide_is_variable_needed (node, decl)
+ && (decide_is_symbol_needed ((symtab_node) node)
|| referred_to_p ((symtab_node)node)))
enqueue_node ((symtab_node)node);
if (cgraph_state >= CGRAPH_STATE_IPA_SSA)
@@ -854,21 +823,6 @@ varpool_finalize_decl (tree decl)
}
-/* Determine if a symbol NODE is finalized and needed. */
-
-inline static bool
-symbol_defined_and_needed (symtab_node node)
-{
- if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
- return cnode->symbol.definition
- && cgraph_decide_is_function_needed (cnode, cnode->symbol.decl);
- if (varpool_node *vnode = dyn_cast <varpool_node> (node))
- return vnode->symbol.definition
- && !DECL_EXTERNAL (vnode->symbol.decl)
- && decide_is_variable_needed (vnode, vnode->symbol.decl);
- return false;
-}
-
/* Discover all functions and variables that are trivially needed, analyze
them as well as all functions and variables referred by them */
@@ -890,6 +844,13 @@ analyze_functions (void)
bitmap_obstack_initialize (NULL);
cgraph_state = CGRAPH_STATE_CONSTRUCTION;
+ /* Ugly, but the fixup can not happen at a time same body alias is created;
+ C++ FE is confused about the COMDAT groups being right. */
+ if (cpp_implicit_aliases_done)
+ FOR_EACH_SYMBOL (node)
+ if (node->symbol.cpp_implicit_alias)
+ fixup_same_cpp_alias_visibility (node, symtab_alias_target (node));
+
/* Analysis adds static variables that in turn adds references to new functions.
So we need to iterate the process until it stabilize. */
while (changed)
@@ -903,7 +864,7 @@ analyze_functions (void)
node != (symtab_node)first_analyzed
&& node != (symtab_node)first_analyzed_var; node = node->symbol.next)
{
- if (symbol_defined_and_needed (node))
+ if (decide_is_symbol_needed (node))
{
enqueue_node (node);
if (!changed && cgraph_dump_file)
@@ -940,7 +901,7 @@ analyze_functions (void)
and later using weak alias attribute to kill its body.
See gcc.c-torture/compile/20011119-1.c */
if (!DECL_STRUCT_FUNCTION (decl)
- && (!cnode->symbol.alias || !cnode->thunk.alias)
+ && !cnode->symbol.alias
&& !cnode->thunk.thunk_p
&& !cnode->dispatcher_function)
{
@@ -970,7 +931,7 @@ analyze_functions (void)
else
{
varpool_node *vnode = dyn_cast <varpool_node> (node);
- if (vnode && vnode->symbol.definition)
+ if (vnode && vnode->symbol.definition && !vnode->symbol.analyzed)
varpool_analyze_node (vnode);
}
@@ -1016,7 +977,7 @@ analyze_functions (void)
tree decl = node->symbol.decl;
if (cnode->symbol.definition && !gimple_has_body_p (decl)
- && (!cnode->symbol.alias || !cnode->thunk.alias)
+ && !cnode->symbol.alias
&& !cnode->thunk.thunk_p)
cgraph_reset_node (cnode);
@@ -1057,19 +1018,13 @@ handle_alias_pairs (void)
to later output the weakref pseudo op into asm file. */
if (!target_node && lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)) != NULL)
{
- if (TREE_CODE (p->decl) == FUNCTION_DECL)
- {
- struct cgraph_node *anode = cgraph_get_create_node (p->decl);
- anode->symbol.alias = true;
- anode->thunk.alias = p->target;
- }
- else
+ symtab_node node = symtab_get_node (p->decl);
+ if (node)
{
- struct varpool_node *anode = varpool_get_node (p->decl);
- anode->symbol.alias = true;
- anode->alias_of = p->target;
+ node->symbol.alias_target = p->target;
+ node->symbol.weakref = true;
+ node->symbol.alias = true;
}
- DECL_EXTERNAL (p->decl) = 1;
alias_pairs->unordered_remove (i);
continue;
}
@@ -1080,16 +1035,6 @@ handle_alias_pairs (void)
continue;
}
- /* Normally EXTERNAL flag is used to mark external inlines,
- however for aliases it seems to be allowed to use it w/o
- any meaning. See gcc.dg/attr-alias-3.c
- However for weakref we insist on EXTERNAL flag being set.
- See gcc.dg/attr-alias-5.c */
- if (DECL_EXTERNAL (p->decl))
- DECL_EXTERNAL (p->decl)
- = lookup_attribute ("weakref",
- DECL_ATTRIBUTES (p->decl)) != NULL;
-
if (DECL_EXTERNAL (target_node->symbol.decl)
/* We use local aliases for C++ thunks to force the tailcall
to bind locally. This is a hack - to keep it working do
@@ -1380,7 +1325,7 @@ assemble_thunk (struct cgraph_node *node)
HOST_WIDE_INT fixed_offset = node->thunk.fixed_offset;
HOST_WIDE_INT virtual_value = node->thunk.virtual_value;
tree virtual_offset = NULL;
- tree alias = node->thunk.alias;
+ tree alias = node->callees->callee->symbol.decl;
tree thunk_fndecl = node->symbol.decl;
tree a = DECL_ARGUMENTS (thunk_fndecl);
@@ -1581,15 +1526,15 @@ assemble_thunks_and_aliases (struct cgraph_node *node)
if (ref->use == IPA_REF_ALIAS)
{
struct cgraph_node *alias = ipa_ref_referring_node (ref);
- bool saved_written = TREE_ASM_WRITTEN (alias->thunk.alias);
+ bool saved_written = TREE_ASM_WRITTEN (node->symbol.decl);
/* Force assemble_alias to really output the alias this time instead
of buffering it in same alias pairs. */
- TREE_ASM_WRITTEN (alias->thunk.alias) = 1;
+ TREE_ASM_WRITTEN (node->symbol.decl) = 1;
do_assemble_alias (alias->symbol.decl,
- DECL_ASSEMBLER_NAME (alias->thunk.alias));
+ DECL_ASSEMBLER_NAME (node->symbol.decl));
assemble_thunks_and_aliases (alias);
- TREE_ASM_WRITTEN (alias->thunk.alias) = saved_written;
+ TREE_ASM_WRITTEN (node->symbol.decl) = saved_written;
}
}
@@ -1929,22 +1874,32 @@ get_alias_symbol (tree decl)
static void
output_weakrefs (void)
{
- struct cgraph_node *node;
- struct varpool_node *vnode;
- FOR_EACH_FUNCTION (node)
- if (node->symbol.alias && DECL_EXTERNAL (node->symbol.decl)
+ symtab_node node;
+ FOR_EACH_SYMBOL (node)
+ if (node->symbol.alias
&& !TREE_ASM_WRITTEN (node->symbol.decl)
- && lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
- do_assemble_alias (node->symbol.decl,
- node->thunk.alias && DECL_P (node->thunk.alias) ? DECL_ASSEMBLER_NAME (node->thunk.alias)
- : get_alias_symbol (node->symbol.decl));
- FOR_EACH_VARIABLE (vnode)
- if (vnode->symbol.alias && DECL_EXTERNAL (vnode->symbol.decl)
- && !TREE_ASM_WRITTEN (vnode->symbol.decl)
- && lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->symbol.decl)))
- do_assemble_alias (vnode->symbol.decl,
- vnode->alias_of && DECL_P (vnode->alias_of) ? DECL_ASSEMBLER_NAME (vnode->alias_of)
- : get_alias_symbol (vnode->symbol.decl));
+ && node->symbol.weakref)
+ {
+ tree target;
+
+ /* Weakrefs are special by not requiring target definition in current
+ compilation unit. It is thus bit hard to work out what we want to
+ alias.
+ When alias target is defined, we need to fetch it from symtab reference,
+ otherwise it is pointed to by alias_target. */
+ if (node->symbol.alias_target)
+ target = (DECL_P (node->symbol.alias_target)
+ ? DECL_ASSEMBLER_NAME (node->symbol.alias_target)
+ : node->symbol.alias_target);
+ else if (node->symbol.analyzed)
+ target = DECL_ASSEMBLER_NAME (symtab_alias_target (node)->symbol.decl);
+ else
+ {
+ gcc_unreachable ();
+ target = get_alias_symbol (node->symbol.decl);
+ }
+ do_assemble_alias (node->symbol.decl, target);
+ }
}
/* Initialize callgraph dump file. */
@@ -2029,6 +1984,32 @@ compile (void)
bitmap_obstack_release (NULL);
mark_functions_to_output ();
+ /* When weakref support is missing, we autmatically translate all
+ references to NODE to references to its ultimate alias target.
+ The renaming mechanizm uses flag IDENTIFIER_TRANSPARENT_ALIAS and
+ TREE_CHAIN.
+
+ Set up this mapping before we output any assembler but once we are sure
+ that all symbol renaming is done.
+
+ FIXME: All this uglyness can go away if we just do renaming at gimple
+ level by physically rewritting the IL. At the moment we can only redirect
+ calls, so we need infrastructure for renaming references as well. */
+#ifndef ASM_OUTPUT_WEAKREF
+ symtab_node node;
+
+ FOR_EACH_SYMBOL (node)
+ if (node->symbol.alias
+ && lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
+ {
+ IDENTIFIER_TRANSPARENT_ALIAS
+ (DECL_ASSEMBLER_NAME (node->symbol.decl)) = 1;
+ TREE_CHAIN (DECL_ASSEMBLER_NAME (node->symbol.decl))
+ = (node->symbol.alias_target ? node->symbol.alias_target
+ : DECL_ASSEMBLER_NAME (symtab_alias_target (node)->symbol.decl));
+ }
+#endif
+
cgraph_state = CGRAPH_STATE_EXPANSION;
if (!flag_toplevel_reorder)
output_in_order ();