+2013-06-01 Jan Hubicka <jh@suse.cz>
+
+ * lto-symtab.c (lto_symtab_merge_cgraph_nodes_1): Rename to ...
+ (lto_symtab_merge_symbols_1): ... this one.
+ (lto_symtab_merge_cgraph_nodes): Rename to ...
+ (lto_symtab_merge_symbols): ... this one; simplify.
+ * cgraph.c (same_body_aliases_done): Rename to ...
+ (cpp_implicit_aliases_done): ... this one.
+ (cgraph_create_function_alias): Update.
+ (cgraph_same_body_alias): Update.
+ (dump_cgraph_node): Remove alias dumping; simplify
+ thunk dumping.
+ (verify_edge_corresponds_to_fndecl): Simplify.
+ * cgraph.h (symtab_node_base): Add cpp_implicit_alias,
+ alias_target.
+ (cgraph_node): Remove same_body_alias.
+ (varpool_node): Remove alias_of and extra_name_alias.
+ (same_body_aliases_done): Rename to ..
+ (cpp_implicit_aliases_done): ... this one.
+ (symtab_alias_ultimate_target): Add default parameter.
+ (symtab_resolve_alias): New function.
+ (fixup_same_cpp_alias_visibility): Declare.
+ (cgraph_function_node): Add default parameter.
+ (cgraph_node_asm_name): Likewise.
+ (cgraph_function_or_thunk_node): Add default parameter; do
+ not ICE when it is NULL.
+ (varpool_variable_node): Likewise.
+ * tree-emutls.c (create_emultls_var): Update.
+ (ipa_lower_emutls): Update.
+ * cgraphunit.c (cgraph_decide_is_function_needed): Update.
+ (cgraph_reset_node): Reset alias info.
+ (cgraph_finalize_function): Update.
+ (fixup_same_cpp_alias_visibility): Move to symtab.c.
+ (analyze_function): Simplify.
+ (cgraph_process_same_body_aliases): Simplify.
+ (analyze_functions): Fixup same body aliases.
+ (handle_alias_pairs): Simplify.
+ (assemble_thunk): Update.
+ (assemble_thunks_and_aliases): Update.
+ (output_weakrefs): Rewrite.
+ * lto-cgraph.c (lto_output_node): Rewrite alias handling.
+ (lto_output_varpool_node): Likewise.
+ (compute_ltrans_boundary): Remve assert.
+ (get_alias_symbol): New functoin.
+ (input_node): Rewrite alias handling.
+ (input_varpool_node): Likewise.
+ * ipa-pure-const.c (propagate_pure_const): Fix formating.
+ * ipa.c (process_references): Handle weakrefs correctly.
+ (symtab_remove_unreachable_nodes): Likewise.
+ * trans-mem.c (get_cg_data): Update.
+ (ipa_tm_create_version_alias): Update.
+ (ipa_tm_execute): Update.
+ * symtab.c (dump_symtab_base): Dump aliases.
+ (verify_symtab_base): Verify aliases.
+ (symtab_node_availability): New function.
+ (symtab_alias_ultimate_target): Simplify.
+ (fixup_same_cpp_alias_visibility): Move here from cgraphunit.c;
+ handle all the fixup cases.
+ (symtab_resolve_alias): New function.
+ * passes.c (ipa_write_summaries): Handle weakrefs.
+ * varpool.c (varpool_analyze_node): Simplify.
+ (assemble_aliases): Update.
+ (varpool_create_variable_alias): Simplify.
+ (varpool_extra_name_alias): Simplify.
+ * lto-streamer.h (lto_symtab_merge_cgraph_nodes): Rename to...
+ (lto_symtab_merge_symbols): ... this one.
+
2013-06-01 Dinar Temirbulatov <dinar@kugelworks.com>
Revert
static GTY(()) struct cgraph_edge *free_edges;
/* Did procss_same_body_aliases run? */
-bool same_body_aliases_done;
+bool cpp_implicit_aliases_done;
/* Map a cgraph_node to cgraph_function_version_info using this htab.
The cgraph_function_version_info has a THIS_NODE field that is the
the function body is associated with (not necessarily cgraph_node (DECL). */
struct cgraph_node *
-cgraph_create_function_alias (tree alias, tree decl)
+cgraph_create_function_alias (tree alias, tree target)
{
struct cgraph_node *alias_node;
- gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+ gcc_assert (TREE_CODE (target) == FUNCTION_DECL
+ || TREE_CODE (target) == IDENTIFIER_NODE);
gcc_assert (TREE_CODE (alias) == FUNCTION_DECL);
alias_node = cgraph_get_create_node (alias);
gcc_assert (!alias_node->symbol.definition);
- alias_node->thunk.alias = decl;
+ alias_node->symbol.alias_target = target;
alias_node->symbol.definition = true;
alias_node->symbol.alias = true;
return alias_node;
return NULL;
n = cgraph_create_function_alias (alias, decl);
- n->same_body_alias = true;
- if (same_body_aliases_done)
- ipa_record_reference ((symtab_node)n, (symtab_node)cgraph_get_node (decl),
- IPA_REF_ALIAS, NULL);
+ n->symbol.cpp_implicit_alias = true;
+ if (cpp_implicit_aliases_done)
+ symtab_resolve_alias ((symtab_node)n,
+ (symtab_node)cgraph_get_node (decl));
return n;
}
if (node->thunk.thunk_p)
{
- fprintf (f, " Thunk of %s (asm: %s) fixed offset %i virtual value %i has "
+ fprintf (f, " Thunk");
+ if (node->thunk.alias)
+ fprintf (f, " of %s (asm: %s)",
+ lang_hooks.decl_printable_name (node->thunk.alias, 2),
+ IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->thunk.alias)));
+ fprintf (f, " fixed offset %i virtual value %i has "
"virtual offset %i)\n",
- lang_hooks.decl_printable_name (node->thunk.alias, 2),
- IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->thunk.alias)),
(int)node->thunk.fixed_offset,
(int)node->thunk.virtual_value,
(int)node->thunk.virtual_offset_p);
return false;
node = cgraph_function_or_thunk_node (node, NULL);
- if ((e->callee->former_clone_of != node->symbol.decl
- && (!node->same_body_alias
- || e->callee->former_clone_of != node->thunk.alias))
+ if (e->callee->former_clone_of != node->symbol.decl
/* IPA-CP sometimes redirect edge to clone and then back to the former
function. This ping-pong has to go, eventually. */
&& (node != cgraph_function_or_thunk_node (e->callee, NULL))
- && !clone_of_p (node, e->callee)
- /* If decl is a same body alias of some other decl, allow e->callee to be
- a clone of a clone of that other decl too. */
- && (!node->same_body_alias
- || !clone_of_p (cgraph_get_node (node->thunk.alias), e->callee)))
+ && !clone_of_p (cgraph_function_or_thunk_node (node, NULL), e->callee))
return true;
else
return false;
/* True when symbol is an alias.
Set by assemble_alias. */
unsigned alias : 1;
+ /* C++ frontend produce same body aliases and extra name aliases for
+ virutal functions and vtables that are obviously equivalent.
+ Those aliases are bit special, especially because C++ frontend
+ visibility code is so ugly it can not get them right at first time
+ and their visibility needs to be copied from their "masters" at
+ the end of parsing. */
+ unsigned cpp_implicit_alias : 1;
/* Set once the definition was analyzed. The list of references and
other properties are built during analysis. */
unsigned analyzed : 1;
/* Vectors of referring and referenced entities. */
struct ipa_ref_list ref_list;
+ /* Alias target. May be either DECL pointer or ASSEMBLER_NAME pointer
+ depending to what was known to frontend on the creation time.
+ Once alias is resolved, this pointer become NULL. */
+ tree alias_target;
+
/* File stream where this node is being written to. */
struct lto_file_decl_data * lto_file_data;
/* Set once the function has been instantiated and its callee
lists created. */
unsigned process : 1;
- /* Set for aliases created as C++ same body aliases. */
- unsigned same_body_alias : 1;
/* How commonly executed the node is. Initialized during branch
probabilities pass. */
ENUM_BITFIELD (node_frequency) frequency : 2;
struct GTY(()) varpool_node {
struct symtab_node_base symbol;
- /* For aliases points to declaration DECL is alias of. */
- tree alias_of;
/* Set when variable is scheduled to be assembled. */
unsigned output : 1;
- unsigned extra_name_alias : 1;
};
/* Every top level asm statement is put into a asm_node. */
extern GTY(()) struct asm_node *asm_nodes;
extern GTY(()) int symtab_order;
-extern bool same_body_aliases_done;
+extern bool cpp_implicit_aliases_done;
/* In symtab.c */
void symtab_register_node (symtab_node);
bool verify_symtab_base (symtab_node);
bool symtab_used_from_object_file_p (symtab_node);
void symtab_make_decl_local (tree);
-symtab_node symtab_alias_ultimate_target (symtab_node, enum availability *);
+symtab_node symtab_alias_ultimate_target (symtab_node,
+ enum availability *avail = NULL);
+bool symtab_resolve_alias (symtab_node node, symtab_node target);
+void fixup_same_cpp_alias_visibility (symtab_node node, symtab_node target);
/* In cgraph.c */
void dump_cgraph (FILE *);
void cgraph_remove_node_duplication_hook (struct cgraph_2node_hook_list *);
gimple cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *);
bool cgraph_propagate_frequency (struct cgraph_node *node);
-struct cgraph_node * cgraph_function_node (struct cgraph_node *, enum availability *);
+struct cgraph_node * cgraph_function_node (struct cgraph_node *,
+ enum availability *avail = NULL);
/* In cgraphunit.c */
struct asm_node *add_asm_node (tree);
/* Return asm name of cgraph node. */
static inline const char *
-cgraph_node_asm_name(struct cgraph_node *node)
+cgraph_node_asm_name (struct cgraph_node *node)
{
return symtab_node_asm_name ((symtab_node)node);
}
When AVAILABILITY is non-NULL, get minimal availability in the chain. */
static inline struct cgraph_node *
-cgraph_function_or_thunk_node (struct cgraph_node *node, enum availability *availability)
+cgraph_function_or_thunk_node (struct cgraph_node *node,
+ enum availability *availability = NULL)
{
struct cgraph_node *n;
- n = dyn_cast <cgraph_node> (symtab_alias_ultimate_target ((symtab_node)node, availability));
- if (!n)
+ n = dyn_cast <cgraph_node> (symtab_alias_ultimate_target ((symtab_node)node,
+ availability));
+ if (!n && availability)
*availability = AVAIL_NOT_AVAILABLE;
return n;
}
When AVAILABILITY is non-NULL, get minimal availability in the chain. */
static inline struct varpool_node *
-varpool_variable_node (struct varpool_node *node, enum availability *availability)
+varpool_variable_node (struct varpool_node *node,
+ enum availability *availability = NULL)
{
struct varpool_node *n;
- n = dyn_cast <varpool_node> (symtab_alias_ultimate_target ((symtab_node)node, availability));
- if (!n)
+ n = dyn_cast <varpool_node> (symtab_alias_ultimate_target ((symtab_node)node,
+ availability));
+ if (!n && availability)
*availability = AVAIL_NOT_AVAILABLE;
return n;
}
/* 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)));
/* Keep constructors, destructors and virtual functions. */
memset (&node->rtl, 0, sizeof (node->rtl));
node->symbol.analyzed = false;
node->symbol.definition = false;
+ node->symbol.alias = false;
+ node->symbol.cpp_implicit_alias = false;
cgraph_node_remove_callees (node);
ipa_remove_all_references (&node->symbol.ref_list);
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)
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)
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)
{
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,
+ symtab_get_node (node->symbol.alias_target));
+ cpp_implicit_aliases_done = true;
}
/* Process attributes common for vars and functions. */
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)
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)
{
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);
}
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);
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.alias = true;
}
DECL_EXTERNAL (p->decl) = 1;
alias_pairs->unordered_remove (i);
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);
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;
}
}
static void
output_weakrefs (void)
{
- struct cgraph_node *node;
- struct varpool_node *vnode;
- FOR_EACH_FUNCTION (node)
+ symtab_node node;
+ FOR_EACH_SYMBOL (node)
if (node->symbol.alias && DECL_EXTERNAL (node->symbol.decl)
&& !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));
+ {
+ 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. */
+2013-06-01 Jan Hubicka <jh@suse.cz>
+
+ * decl2.c (cp_write_global_declarations): Replace same_body_alias
+ by symbol.cpp_implicit_alias.
+
2013-05-30 Jason Merrill <jason@redhat.com>
PR c++/57404
struct cgraph_node *node, *next;
node = cgraph_get_node (decl);
- if (node->same_body_alias)
+ if (node->symbol.cpp_implicit_alias)
node = cgraph_alias_target (node);
cgraph_for_node_and_aliases (node, clear_decl_external,
if (dump_file)
{
dump_cgraph (dump_file);
- ipa_print_order(dump_file, "reduced", order, order_pos);
+ ipa_print_order (dump_file, "reduced", order, order_pos);
}
/* Propagate the local information through the call graph to produce
symtab_node node = ref->referred;
if (node->symbol.definition
- && (!DECL_EXTERNAL (node->symbol.decl)
- || node->symbol.alias
+ && ((!DECL_EXTERNAL (node->symbol.decl) || node->symbol.alias)
|| (before_inlining_p
/* We use variable constructors during late complation for
constant folding. Keep references alive so partitioning
if (e->callee->symbol.definition
&& (!e->inline_failed
|| !DECL_EXTERNAL (e->callee->symbol.decl)
- || cnode->symbol.alias
+ || e->callee->symbol.alias
|| before_inlining_p))
pointer_set_insert (reachable, e->callee);
enqueue_node ((symtab_node) e->callee, &first, reachable);
struct cgraph_node *clone_of;
struct ipa_opt_pass_d *pass;
int i;
+ bool alias_p;
boundary_p = !lto_symtab_encoder_in_partition_p (encoder, (symtab_node)node);
defined in other unit, we may use the info on aliases to resolve
symbol1 != symbol2 type tests that we can do only for locally defined objects
otherwise. */
- bp_pack_value (&bp, node->symbol.alias && (!boundary_p || DECL_EXTERNAL (node->symbol.decl)), 1);
+ alias_p = node->symbol.alias && (!boundary_p || DECL_EXTERNAL (node->symbol.decl));
+ bp_pack_value (&bp, alias_p, 1);
bp_pack_value (&bp, node->frequency, 2);
bp_pack_value (&bp, node->only_called_at_startup, 1);
bp_pack_value (&bp, node->only_called_at_exit, 1);
streamer_write_uhwi_stream (ob->main_stream, node->thunk.fixed_offset);
streamer_write_uhwi_stream (ob->main_stream, node->thunk.virtual_value);
}
- if ((node->symbol.alias || node->thunk.thunk_p)
- && (!boundary_p || (node->symbol.alias && DECL_EXTERNAL (node->symbol.decl))))
- {
- streamer_write_hwi_in_range (ob->main_stream, 0, 1,
- node->thunk.alias != NULL);
- if (node->thunk.alias != NULL)
- lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
- node->thunk.alias);
- }
}
/* Output the varpool NODE to OB.
lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node *node,
lto_symtab_encoder_t encoder)
{
- bool boundary_p = (node->symbol.definition
- && !lto_symtab_encoder_in_partition_p (encoder, (symtab_node)node));
+ bool boundary_p = !lto_symtab_encoder_in_partition_p (encoder, (symtab_node)node);
struct bitpack_d bp;
int ref;
+ bool alias_p;
streamer_write_enum (ob->main_stream, LTO_symtab_tags, LTO_symtab_last_tag,
LTO_symtab_variable);
bp_pack_value (&bp, node->symbol.force_output, 1);
bp_pack_value (&bp, node->symbol.unique_name, 1);
bp_pack_value (&bp, node->symbol.definition, 1);
- bp_pack_value (&bp, node->symbol.alias, 1);
- bp_pack_value (&bp, node->alias_of != NULL, 1);
+ alias_p = node->symbol.alias && (!boundary_p || DECL_EXTERNAL (node->symbol.decl));
+ bp_pack_value (&bp, alias_p, 1);
+ bp_pack_value (&bp, node->symbol.analyzed && !boundary_p, 1);
gcc_assert (node->symbol.definition || !node->symbol.analyzed);
/* Constant pool initializers can be de-unified into individual ltrans units.
FIXME: Alternatively at -Os we may want to avoid generating for them the local
bp_pack_value (&bp, node->symbol.definition
&& referenced_from_other_partition_p (&node->symbol.ref_list,
encoder), 1);
- bp_pack_value (&bp, boundary_p && !DECL_EXTERNAL (node->symbol.decl), 1);
+ bp_pack_value (&bp, node->symbol.analyzed
+ && boundary_p && !DECL_EXTERNAL (node->symbol.decl), 1);
/* in_other_partition. */
}
streamer_write_bitpack (&bp);
- if (node->alias_of)
- lto_output_var_decl_index (ob->decl_state, ob->main_stream, node->alias_of);
if (node->symbol.same_comdat_group && !boundary_p)
{
ref = lto_symtab_encoder_lookup (encoder,
!lsei_end_p (lsei); lsei_next_variable_in_partition (&lsei))
{
struct varpool_node *vnode = lsei_varpool_node (lsei);
- gcc_assert (!vnode->symbol.alias || vnode->alias_of);
+
lto_set_symtab_encoder_in_partition (encoder, (symtab_node)vnode);
lto_set_symtab_encoder_encode_initializer (encoder, vnode);
add_references (encoder, &vnode->symbol.ref_list);
LDPR_NUM_KNOWN);
}
+/* Return string alias is alias of. */
+
+static tree
+get_alias_symbol (tree decl)
+{
+ tree alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl));
+ gcc_assert (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)));
+ return get_identifier (TREE_STRING_POINTER
+ (TREE_VALUE (TREE_VALUE (alias))));
+}
+
/* Read a node from input_block IB. TAG is the node's tag just read.
Return the node read or overwriten. */
node->thunk.virtual_value = virtual_value;
node->thunk.virtual_offset_p = (type & 4);
}
- if (node->thunk.thunk_p || node->symbol.alias)
- {
- if (streamer_read_hwi_in_range (ib, "alias nonzero flag", 0, 1))
- {
- decl_index = streamer_read_uhwi (ib);
- node->thunk.alias = lto_file_decl_data_get_fn_decl (file_data,
- decl_index);
- }
- }
+ if (node->symbol.alias && !node->symbol.analyzed)
+ node->symbol.alias_target = get_alias_symbol (node->symbol.decl);
return node;
}
struct varpool_node *node;
struct bitpack_d bp;
int ref = LCC_NOT_FOUND;
- bool non_null_aliasof;
int order;
order = streamer_read_hwi (ib) + order_base;
node->symbol.unique_name = bp_unpack_value (&bp, 1);
node->symbol.definition = bp_unpack_value (&bp, 1);
node->symbol.alias = bp_unpack_value (&bp, 1);
- non_null_aliasof = bp_unpack_value (&bp, 1);
+ node->symbol.analyzed = bp_unpack_value (&bp, 1);
node->symbol.used_from_other_partition = bp_unpack_value (&bp, 1);
node->symbol.in_other_partition = bp_unpack_value (&bp, 1);
- node->symbol.analyzed = (node->symbol.definition && (!node->symbol.alias || !node->symbol.in_other_partition));
if (node->symbol.in_other_partition)
{
DECL_EXTERNAL (node->symbol.decl) = 1;
TREE_STATIC (node->symbol.decl) = 0;
}
- if (non_null_aliasof)
- {
- decl_index = streamer_read_uhwi (ib);
- node->alias_of = lto_file_decl_data_get_var_decl (file_data, decl_index);
- }
+ if (node->symbol.alias && !node->symbol.analyzed)
+ node->symbol.alias_target = get_alias_symbol (node->symbol.decl);
ref = streamer_read_hwi (ib);
/* Store a reference for now, and fix up later to be a pointer. */
node->symbol.same_comdat_group = (symtab_node) (intptr_t) ref;
/* In lto-symtab.c. */
extern void lto_symtab_merge_decls (void);
-extern void lto_symtab_merge_cgraph_nodes (void);
+extern void lto_symtab_merge_symbols (void);
extern tree lto_symtab_prevailing_decl (tree decl);
extern GTY(()) vec<tree, va_gc> *lto_global_var_decls;
/* Helper to process the decl chain for the symbol table entry *SLOT. */
static void
-lto_symtab_merge_cgraph_nodes_1 (symtab_node prevailing)
+lto_symtab_merge_symbols_1 (symtab_node prevailing)
{
symtab_node e, next;
lto_symtab_merge_decls. */
void
-lto_symtab_merge_cgraph_nodes (void)
+lto_symtab_merge_symbols (void)
{
- struct cgraph_node *cnode;
- struct varpool_node *vnode;
symtab_node node;
- /* Populate assembler name hash. */
- symtab_initialize_asm_name_hash ();
-
if (!flag_ltrans)
- FOR_EACH_SYMBOL (node)
- if (lto_symtab_symbol_p (node)
- && node->symbol.next_sharing_asm_name
- && !node->symbol.previous_sharing_asm_name)
- lto_symtab_merge_cgraph_nodes_1 (node);
-
- FOR_EACH_FUNCTION (cnode)
- {
- /* Resolve weakrefs to symbol defined in other unit. */
- if (!cnode->symbol.analyzed && cnode->thunk.alias && !DECL_P (cnode->thunk.alias))
- {
- symtab_node node = symtab_node_for_asm (cnode->thunk.alias);
- if (node && is_a <cgraph_node> (node))
- {
- struct cgraph_node *n;
-
- for (n = cgraph (node); n && n->symbol.alias;
- n = n->symbol.analyzed ? cgraph_alias_target (n) : NULL)
- if (n == cnode)
- {
- error ("function %q+D part of alias cycle", cnode->symbol.decl);
- cnode->symbol.alias = false;
- break;
- }
- if (cnode->symbol.alias)
- {
- cgraph_create_function_alias (cnode->symbol.decl, node->symbol.decl);
- ipa_record_reference ((symtab_node)cnode, (symtab_node)node,
- IPA_REF_ALIAS, NULL);
- cnode->symbol.analyzed = true;
- }
- }
- else if (node)
- error ("%q+D alias in between function and variable is not supported", cnode->symbol.decl);
- }
- if ((cnode->thunk.thunk_p || cnode->symbol.alias)
- && cnode->thunk.alias && DECL_P (cnode->thunk.alias))
- cnode->thunk.alias = lto_symtab_prevailing_decl (cnode->thunk.alias);
- cnode->symbol.aux = NULL;
- }
- FOR_EACH_VARIABLE (vnode)
{
- /* Resolve weakrefs to symbol defined in other unit. */
- if (!vnode->symbol.analyzed && vnode->alias_of && !DECL_P (vnode->alias_of))
+ symtab_initialize_asm_name_hash ();
+
+ /* Do the actual merging. */
+ FOR_EACH_SYMBOL (node)
+ if (lto_symtab_symbol_p (node)
+ && node->symbol.next_sharing_asm_name
+ && !node->symbol.previous_sharing_asm_name)
+ lto_symtab_merge_symbols_1 (node);
+
+ /* Resolve weakref aliases whose target are now in the compilation unit. */
+ FOR_EACH_SYMBOL (node)
{
- symtab_node node = symtab_node_for_asm (vnode->alias_of);
- if (node && is_a <cgraph_node> (node))
+ if (!node->symbol.analyzed && node->symbol.alias_target)
{
- struct varpool_node *n;
-
- for (n = varpool (node); n && n->symbol.alias;
- n = n->symbol.analyzed ? varpool_alias_target (n) : NULL)
- if (n == vnode)
- {
- error ("function %q+D part of alias cycle", vnode->symbol.decl);
- vnode->symbol.alias = false;
- break;
- }
- if (vnode->symbol.alias)
- {
- varpool_create_variable_alias (vnode->symbol.decl, node->symbol.decl);
- ipa_record_reference ((symtab_node)vnode, (symtab_node)node,
- IPA_REF_ALIAS, NULL);
- vnode->symbol.analyzed = true;
- }
+ symtab_node tgt = symtab_node_for_asm (node->symbol.alias_target);
+ if (tgt)
+ symtab_resolve_alias (node, tgt);
}
- else if (node)
- error ("%q+D alias in between function and variable is not supported", vnode->symbol.decl);
+ node->symbol.aux = NULL;
}
- if (vnode->symbol.alias && DECL_P (vnode->alias_of))
- vnode->alias_of = lto_symtab_prevailing_decl (vnode->alias_of);
- vnode->symbol.aux = NULL;
}
}
+2013-06-01 Jan Hubicka <jh@suse.cz>
+
+ * lto.c (read_cgraph_and_symbols): Simplify dumping; Replace
+ lto_symtab_merge_cgraph_nodes by lto_symtab_merge_symbols.
+ (do_whole_program_analysis): Update dumping.
+
2013-05-29 Jan Hubicka <jh@suse.cz>
* lto.c (has_analyzed_clone_p, lto_materialize_function): Update for new symtab
if (cgraph_dump_file)
{
fprintf (cgraph_dump_file, "Before merging:\n");
- dump_cgraph (cgraph_dump_file);
- dump_varpool (cgraph_dump_file);
+ dump_symtab (cgraph_dump_file);
}
- lto_symtab_merge_cgraph_nodes ();
+ lto_symtab_merge_symbols ();
ggc_collect ();
/* FIXME: ipa_transforms_to_apply holds list of passes that have optimization
cgraph_function_flags_ready = true;
if (cgraph_dump_file)
- {
- dump_cgraph (cgraph_dump_file);
- dump_varpool (cgraph_dump_file);
- }
+ dump_symtab (cgraph_dump_file);
bitmap_obstack_initialize (NULL);
cgraph_state = CGRAPH_STATE_IPA_SSA;
if (cgraph_dump_file)
{
fprintf (cgraph_dump_file, "Optimized ");
- dump_cgraph (cgraph_dump_file);
- dump_varpool (cgraph_dump_file);
+ dump_symtab (cgraph_dump_file);
}
#ifdef ENABLE_CHECKING
verify_cgraph ();
lto_symtab_encoder_t encoder;
int i, order_pos;
struct varpool_node *vnode;
+ struct cgraph_node *node;
struct cgraph_node **order;
if (!flag_generate_lto || seen_error ())
lto_set_symtab_encoder_in_partition (encoder, (symtab_node)node);
}
+ FOR_EACH_DEFINED_FUNCTION (node)
+ if (node->symbol.alias)
+ lto_set_symtab_encoder_in_partition (encoder, (symtab_node)node);
FOR_EACH_DEFINED_VARIABLE (vnode)
- if ((!vnode->symbol.alias || vnode->alias_of))
- lto_set_symtab_encoder_in_partition (encoder, (symtab_node)vnode);
+ lto_set_symtab_encoder_in_partition (encoder, (symtab_node)vnode);
ipa_write_summaries_1 (compute_ltrans_boundary (encoder));
fprintf (f, " analyzed");
if (node->symbol.alias)
fprintf (f, " alias");
+ if (node->symbol.cpp_implicit_alias)
+ fprintf (f, " cpp_implicit_alias");
+ if (node->symbol.alias_target)
+ fprintf (f, " target:%s",
+ DECL_P (node->symbol.alias_target)
+ ? IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME
+ (node->symbol.alias_target))
+ : IDENTIFIER_POINTER (node->symbol.alias_target));
fprintf (f, "\n Visibility:");
if (node->symbol.in_other_partition)
fprintf (f, " in_other_partition");
error ("node is analyzed byt it is not a definition");
error_found = true;
}
+ if (node->symbol.cpp_implicit_alias && !node->symbol.alias)
+ {
+ error ("node is alias but not implicit alias");
+ error_found = true;
+ }
+ if (node->symbol.alias && !node->symbol.definition
+ && !lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
+ {
+ error ("node is alias but not definition");
+ error_found = true;
+ }
if (node->symbol.same_comdat_group)
{
symtab_node n = node->symbol.same_comdat_group;
/* Make DECL local. FIXME: We shouldn't need to mess with rtl this early,
but other code such as notice_global_symbol generates rtl. */
+
void
symtab_make_decl_local (tree decl)
{
SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl);
}
+/* Return availability of NODE. */
+
+enum availability
+symtab_node_availability (symtab_node node)
+{
+ if (is_a <cgraph_node> (node))
+ return cgraph_function_body_availability (cgraph (node));
+ else
+ return cgraph_variable_initializer_availability (varpool (node));
+}
+
/* Given NODE, walk the alias chain to return the symbol NODE is alias of.
If NODE is not an alias, return NODE.
When AVAILABILITY is non-NULL, get minimal availability in the chain. */
symtab_alias_ultimate_target (symtab_node node, enum availability *availability)
{
if (availability)
- {
- if (is_a <cgraph_node> (node))
- *availability = cgraph_function_body_availability (cgraph (node));
- else
- *availability = cgraph_variable_initializer_availability (varpool (node));
- }
+ *availability = symtab_node_availability (node);
while (node)
{
if (node->symbol.alias && node->symbol.analyzed)
return node;
if (node && availability)
{
- enum availability a;
- if (is_a <cgraph_node> (node))
- a = cgraph_function_body_availability (cgraph (node));
- else
- a = cgraph_variable_initializer_availability (varpool (node));
+ enum availability a = symtab_node_availability (node);
if (a < *availability)
*availability = a;
}
*availability = AVAIL_NOT_AVAILABLE;
return NULL;
}
+
+/* C++ FE sometimes change linkage flags after producing same body aliases.
+
+ FIXME: C++ produce implicit aliases for virtual functions and vtables that
+ are obviously equivalent. The way it is doing so is however somewhat
+ kludgy and interferes with the visibility code. As a result we need to
+ copy the visibility from the target to get things right. */
+
+void
+fixup_same_cpp_alias_visibility (symtab_node node, symtab_node target)
+{
+ if (is_a <cgraph_node> (node))
+ {
+ DECL_DECLARED_INLINE_P (node->symbol.decl)
+ = DECL_DECLARED_INLINE_P (target->symbol.decl);
+ DECL_DISREGARD_INLINE_LIMITS (node->symbol.decl)
+ = DECL_DISREGARD_INLINE_LIMITS (target->symbol.decl);
+ }
+ /* FIXME: It is not really clear why those flags should not be copied for
+ functions, too. */
+ else
+ {
+ DECL_WEAK (node->symbol.decl) = DECL_WEAK (target->symbol.decl);
+ DECL_EXTERNAL (node->symbol.decl) = DECL_EXTERNAL (target->symbol.decl);
+ DECL_VISIBILITY (node->symbol.decl) = DECL_VISIBILITY (target->symbol.decl);
+ }
+ DECL_VIRTUAL_P (node->symbol.decl) = DECL_VIRTUAL_P (target->symbol.decl);
+ if (TREE_PUBLIC (node->symbol.decl))
+ {
+ DECL_EXTERNAL (node->symbol.decl) = DECL_EXTERNAL (target->symbol.decl);
+ DECL_COMDAT (node->symbol.decl) = DECL_COMDAT (target->symbol.decl);
+ DECL_COMDAT_GROUP (node->symbol.decl)
+ = DECL_COMDAT_GROUP (target->symbol.decl);
+ if (DECL_ONE_ONLY (target->symbol.decl)
+ && !node->symbol.same_comdat_group)
+ symtab_add_to_same_comdat_group ((symtab_node)node, (symtab_node)target);
+ }
+ node->symbol.externally_visible = target->symbol.externally_visible;
+}
+
+/* Add reference recording that NODE is alias of TARGET.
+ The function can fail in the case of aliasing cycles; in this case
+ it returns false. */
+
+bool
+symtab_resolve_alias (symtab_node node, symtab_node target)
+{
+ symtab_node n;
+
+ gcc_assert (!node->symbol.analyzed
+ && !vec_safe_length (node->symbol.ref_list.references));
+
+ /* Never let cycles to creep into the symbol table alias references;
+ those will make alias walkers to be infinite. */
+ for (n = target; n && n->symbol.alias;
+ n = n->symbol.analyzed ? symtab_alias_target (n) : NULL)
+ if (n == node)
+ {
+ if (is_a <cgraph_node> (node))
+ error ("function %q+D part of alias cycle", node->symbol.decl);
+ else if (is_a <varpool_node> (node))
+ error ("variable %q+D part of alias cycle", node->symbol.decl);
+ else
+ gcc_unreachable ();
+ node->symbol.alias = false;
+ return false;
+ }
+
+ /* "analyze" the node - i.e. mark the reference. */
+ node->symbol.definition = true;
+ node->symbol.alias = true;
+ node->symbol.analyzed = true;
+ ipa_record_reference (node, target, IPA_REF_ALIAS, NULL);
+
+ /* Alias targets become reudndant after alias is resolved into an reference.
+ We do not want to keep it around or we would have to mind updating them
+ when renaming symbols. */
+ node->symbol.alias_target = NULL;
+ DECL_ATTRIBUTES (node->symbol.decl)
+ = remove_attribute ("alias", DECL_ATTRIBUTES (node->symbol.decl));
+
+ if (node->symbol.cpp_implicit_alias && cgraph_state >= CGRAPH_STATE_CONSTRUCTION)
+ fixup_same_cpp_alias_visibility (node, target);
+
+ /* If alias has address taken, so does the target. */
+ if (node->symbol.address_taken)
+ symtab_alias_ultimate_target (target, NULL)->symbol.address_taken = true;
+ return true;
+}
#include "gt-symtab.h"
struct tm_ipa_cg_data *d;
if (traverse_aliases && (*node)->symbol.alias)
- *node = cgraph_get_node ((*node)->thunk.alias);
+ *node = cgraph_alias_target (*node);
d = (struct tm_ipa_cg_data *) (*node)->symbol.aux;
tree old_decl, new_decl, tm_name;
struct cgraph_node *new_node;
- if (!node->same_body_alias)
+ if (!node->symbol.cpp_implicit_alias)
return false;
old_decl = node->symbol.decl;
bool doit = false;
node = tm_callees[i];
- if (node->same_body_alias)
+ if (node->symbol.cpp_implicit_alias)
continue;
a = cgraph_function_body_availability (node);
tree cdecl;
struct varpool_node *cvar;
- cdecl = new_emutls_decl (var->symbol.decl, var->alias_of);
+ cdecl = new_emutls_decl (var->symbol.decl,
+ var->symbol.alias && var->symbol.analyzed
+ ? varpool_alias_target (var)->symbol.decl : NULL);
cvar = varpool_get_node (cdecl);
control_vars.quick_push (cvar);
need to do this once for the main variable. */
emutls_common_1 (var->symbol.decl, cdecl, (tree *)data);
}
- if (var->symbol.alias && !var->alias_of)
+ if (var->symbol.alias && !var->symbol.analyzed)
cvar->symbol.alias = true;
/* Indicate that the value of the TLS variable may be found elsewhere,
{
var = tls_vars->nodes[i];
- if (var->symbol.alias && !var->alias_of)
+ if (var->symbol.alias && !var->symbol.analyzed)
any_aliases = true;
else if (!var->symbol.alias)
varpool_for_node_and_aliases (var, create_emultls_var, &ctor_body, true);
already informed about increased alignment. */
align_variable (decl, 0);
}
- if (node->symbol.alias && node->alias_of)
- {
- struct varpool_node *tgt = varpool_node_for_decl (node->alias_of);
- struct varpool_node *n;
-
- for (n = tgt; n && n->symbol.alias;
- n = n->symbol.analyzed ? varpool_alias_target (n) : NULL)
- if (n == node)
- {
- error ("variable %q+D part of alias cycle", node->symbol.decl);
- node->symbol.alias = false;
- continue;
- }
- if (!vec_safe_length (node->symbol.ref_list.references))
- ipa_record_reference ((symtab_node)node, (symtab_node)tgt, IPA_REF_ALIAS, NULL);
- if (node->extra_name_alias)
- {
- DECL_WEAK (node->symbol.decl) = DECL_WEAK (node->alias_of);
- DECL_EXTERNAL (node->symbol.decl) = DECL_EXTERNAL (node->alias_of);
- DECL_VISIBILITY (node->symbol.decl) = DECL_VISIBILITY (node->alias_of);
- fixup_same_cpp_alias_visibility ((symtab_node) node,
- (symtab_node) tgt, node->alias_of);
- }
- }
+ if (node->symbol.alias)
+ symtab_resolve_alias
+ ((symtab_node) node, (symtab_node) varpool_get_node (node->symbol.alias_target));
else if (DECL_INITIAL (decl))
record_references_in_initializer (decl, node->symbol.analyzed);
node->symbol.analyzed = true;
{
struct varpool_node *alias = ipa_ref_referring_varpool_node (ref);
do_assemble_alias (alias->symbol.decl,
- DECL_ASSEMBLER_NAME (alias->alias_of));
+ DECL_ASSEMBLER_NAME (node->symbol.decl));
assemble_aliases (alias);
}
}
alias_node = varpool_node_for_decl (alias);
alias_node->symbol.alias = true;
alias_node->symbol.definition = true;
- alias_node->alias_of = decl;
-
- /* Extra name alias mechanizm creates aliases really late
- via DECL_ASSEMBLER_NAME mechanizm.
- This is unfortunate because they are not going through the
- standard channels. Ensure they get output. */
- if (cgraph_state >= CGRAPH_STATE_IPA)
- {
- varpool_analyze_node (alias_node);
- if (TREE_PUBLIC (alias))
- alias_node->symbol.externally_visible = true;
- }
+ alias_node->symbol.alias_target = decl;
return alias_node;
}
return NULL;
#endif
alias_node = varpool_create_variable_alias (alias, decl);
- alias_node->extra_name_alias = true;
+ alias_node->symbol.cpp_implicit_alias = true;
+
+ /* Extra name alias mechanizm creates aliases really late
+ via DECL_ASSEMBLER_NAME mechanizm.
+ This is unfortunate because they are not going through the
+ standard channels. Ensure they get output. */
+ if (cpp_implicit_aliases_done)
+ symtab_resolve_alias ((symtab_node)alias_node,
+ (symtab_node)varpool_node_for_decl (decl));
return alias_node;
}