Hi, this patch removes code handling alias pairs after they was taken over by symbol table. It also streamlines how things are output - do_assemble_alias is called when alias should be output now, while assemble_alias is the function registering new alias into symbol table.
I think I will rename these incrementaly. Bootstrapped/regtested x86_64-linux * tree.h (alias_diag_flags): Remove. (alias_pair): Remove emitted_diags. (finish_aliases_1, finish_aliases_2, remove_unreachable_alias_pairs, symbol_alias_set_t, symbol_alias_set_destroy, symbol_alias_set_contains, propagate_aliases_backward): Remove. * toplev.c (compile_file): Do not call finish_aliases_2 * cgraphunit.c (cgraph_process_new_functions): Do not call finish_aliases_1. (handle_alias_pairs): Output diagnostics about aliases to externals. (assemble_thunks_and_aliases): Use do_assemble_alias. (output_weakrefs): Likewise. (finalize_compilation_unit): Do not call finish_aliases_1. * ipa.c (symtab_remove_unreachable_nodes): De not call remove_unreachable_alias_pairs. * varasm.c (do_assemble_alias): Export. (symbol_alias_set_create, symbol_alias_set_destroy, symbol_alias_set_contains, symbol_alias_set_insert, propagate_aliases_forward, propagate_aliases_backward, propagate_aliases_backward, trivially_visible_alias, trivially_defined_alias, remove_unreachable_alias_pairs, finish_aliases_1, finish_aliases_2, assemble_alias): Remove. * output.h (do_assemble_alias): Declare. * varpool.c (varpool_remove_unreferenced_decls): Do not call finish_aliases_1. Index: tree.h =================================================================== *** tree.h (revision 187695) --- tree.h (working copy) *************** extern const unsigned char tree_code_len *** 239,263 **** extern const char *const tree_code_name[]; ! /* We have to be able to tell cgraph about the needed-ness of the target ! of an alias. This requires that the decl have been defined. Aliases ! that precede their definition have to be queued for later processing. */ ! ! /* The deferred processing proceeds in several passes. We memorize the ! diagnostics emitted for a pair to prevent repeating messages when the ! queue gets re-scanned after possible updates. */ ! ! typedef enum { ! ALIAS_DIAG_NONE = 0x0, ! ALIAS_DIAG_TO_UNDEF = 0x1, ! ALIAS_DIAG_TO_EXTERN = 0x2 ! } alias_diag_flags; ! typedef struct GTY(()) alias_pair { tree decl; tree target; - int emitted_diags; /* alias_diags already emitted for this pair. */ } alias_pair; /* Define gc'd vector type. */ --- 239,252 ---- extern const char *const tree_code_name[]; ! /* When procesing aliases on symtab level, we need the declaration of target. ! For this reason we need to queue aliases and process them after all declarations ! has been produced. */ ! typedef struct GTY(()) alias_pair { tree decl; tree target; } alias_pair; /* Define gc'd vector type. */ *************** extern void mark_decl_referenced (tree); *** 5686,5709 **** extern void notice_global_symbol (tree); extern void set_user_assembler_name (tree, const char *); extern void process_pending_assemble_externals (void); - extern void finish_aliases_1 (void); - extern void finish_aliases_2 (void); - extern void remove_unreachable_alias_pairs (void); extern bool decl_replaceable_p (tree); extern bool decl_binds_to_current_def_p (tree); - - /* Derived type for use by compute_visible_aliases and callers. A symbol - alias set is a pointer set into which we enter IDENTIFIER_NODES bearing - the canonicalised assembler-level symbol names corresponding to decls - and their aliases. */ - typedef struct pointer_set_t symbol_alias_set_t; - - extern void symbol_alias_set_destroy (symbol_alias_set_t *); - extern int symbol_alias_set_contains (const symbol_alias_set_t *, tree); - extern symbol_alias_set_t * propagate_aliases_backward (bool (*) - (tree, tree, void *), - void *); - /* In stmt.c */ extern void expand_computed_goto (tree); extern bool parse_output_constraint (const char **, int, int, int, --- 5675,5682 ---- Index: toplev.c =================================================================== *** toplev.c (revision 187695) --- toplev.c (working copy) *************** compile_file (void) *** 577,584 **** basically finished. */ if (in_lto_p || !flag_lto || flag_fat_lto_objects) { - finish_aliases_2 (); - /* Likewise for mudflap static object registrations. */ if (flag_mudflap) mudflap_finish_file (); --- 577,582 ---- Index: cgraphunit.c =================================================================== *** cgraphunit.c (revision 187695) --- cgraphunit.c (working copy) *************** cgraph_process_new_functions (void) *** 285,291 **** if (!cgraph_new_nodes) return false; - finish_aliases_1 (); handle_alias_pairs (); /* Note that this queue may grow as its being processed, as the new functions may generate new ones. */ --- 285,290 ---- *************** handle_alias_pairs (void) *** 1068,1073 **** --- 1070,1087 ---- = 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 + the following (which is not strictly correct). */ + && (! TREE_CODE (target_node->symbol.decl) == FUNCTION_DECL + || ! DECL_VIRTUAL_P (target_node->symbol.decl)) + && ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl))) + { + error ("%q+D aliased to external symbol %qE", + p->decl, p->target); + } + if (TREE_CODE (p->decl) == FUNCTION_DECL && target_node && symtab_function_p (target_node)) { *************** assemble_thunks_and_aliases (struct cgra *** 1552,1559 **** /* 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; ! assemble_alias (alias->symbol.decl, ! DECL_ASSEMBLER_NAME (alias->thunk.alias)); assemble_thunks_and_aliases (alias); TREE_ASM_WRITTEN (alias->thunk.alias) = saved_written; } --- 1566,1573 ---- /* 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; ! do_assemble_alias (alias->symbol.decl, ! DECL_ASSEMBLER_NAME (alias->thunk.alias)); assemble_thunks_and_aliases (alias); TREE_ASM_WRITTEN (alias->thunk.alias) = saved_written; } *************** output_weakrefs (void) *** 1902,1917 **** if (node->alias && DECL_EXTERNAL (node->symbol.decl) && !TREE_ASM_WRITTEN (node->symbol.decl) && lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl))) ! assemble_alias (node->symbol.decl, ! node->thunk.alias ? DECL_ASSEMBLER_NAME (node->thunk.alias) ! : get_alias_symbol (node->symbol.decl)); FOR_EACH_VARIABLE (vnode) if (vnode->alias && DECL_EXTERNAL (vnode->symbol.decl) && !TREE_ASM_WRITTEN (vnode->symbol.decl) && lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->symbol.decl))) ! assemble_alias (vnode->symbol.decl, ! vnode->alias_of ? DECL_ASSEMBLER_NAME (vnode->alias_of) ! : get_alias_symbol (vnode->symbol.decl)); } /* Initialize callgraph dump file. */ --- 1916,1931 ---- if (node->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_ASSEMBLER_NAME (node->thunk.alias) ! : get_alias_symbol (node->symbol.decl)); FOR_EACH_VARIABLE (vnode) if (vnode->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_ASSEMBLER_NAME (vnode->alias_of) ! : get_alias_symbol (vnode->symbol.decl)); } /* Initialize callgraph dump file. */ *************** finalize_compilation_unit (void) *** 2058,2064 **** finalize_size_functions (); /* Mark alias targets necessary and emit diagnostics. */ - finish_aliases_1 (); handle_alias_pairs (); if (!quiet_flag) --- 2072,2077 ---- *************** finalize_compilation_unit (void) *** 2075,2081 **** cgraph_analyze_functions (); /* Mark alias targets necessary and emit diagnostics. */ - finish_aliases_1 (); handle_alias_pairs (); /* Gimplify and lower thunks. */ --- 2088,2093 ---- Index: ipa.c =================================================================== *** ipa.c (revision 187695) --- ipa.c (working copy) *************** symtab_remove_unreachable_nodes (bool be *** 454,463 **** FOR_EACH_DEFINED_FUNCTION (node) cgraph_propagate_frequency (node); - /* Reclaim alias pairs for functions that have disappeared from the - call graph. */ - remove_unreachable_alias_pairs (); - return changed; } --- 454,459 ---- Index: varasm.c =================================================================== *** varasm.c (revision 187695) --- varasm.c (working copy) *************** VEC(alias_pair,gc) *alias_pairs; *** 5435,5441 **** or ASM_OUTPUT_DEF_FROM_DECLS. The function defines the symbol whose tree node is DECL to have the value of the tree node TARGET. */ ! static void do_assemble_alias (tree decl, tree target) { /* Emulated TLS had better not get this var. */ --- 5435,5441 ---- or ASM_OUTPUT_DEF_FROM_DECLS. The function defines the symbol whose tree node is DECL to have the value of the tree node TARGET. */ ! void do_assemble_alias (tree decl, tree target) { /* Emulated TLS had better not get this var. */ *************** do_assemble_alias (tree decl, tree targe *** 5535,5789 **** #endif } - - /* Allocate and construct a symbol alias set. */ - - static symbol_alias_set_t * - symbol_alias_set_create (void) - { - return pointer_set_create (); - } - - /* Destruct and free a symbol alias set. */ - - void - symbol_alias_set_destroy (symbol_alias_set_t *aset) - { - pointer_set_destroy (aset); - } - - /* Test if a symbol alias set contains a given name. */ - - int - symbol_alias_set_contains (const symbol_alias_set_t *aset, tree t) - { - /* We accept either a DECL or an IDENTIFIER directly. */ - if (TREE_CODE (t) != IDENTIFIER_NODE) - t = DECL_ASSEMBLER_NAME (t); - t = targetm.asm_out.mangle_assembler_name (IDENTIFIER_POINTER (t)); - return pointer_set_contains (aset, t); - } - - /* Enter a new name into a symbol alias set. */ - - static int - symbol_alias_set_insert (symbol_alias_set_t *aset, tree t) - { - /* We accept either a DECL or an IDENTIFIER directly. */ - if (TREE_CODE (t) != IDENTIFIER_NODE) - t = DECL_ASSEMBLER_NAME (t); - t = targetm.asm_out.mangle_assembler_name (IDENTIFIER_POINTER (t)); - return pointer_set_insert (aset, t); - } - - /* IN_SET_P is a predicate function assuming to be taken - alias_pair->decl, alias_pair->target and DATA arguments. - - Compute set of aliases by including everything where TRIVIALLY_VISIBLE - predeicate is true and propagate across aliases such that when - alias DECL is included, its TARGET is included too. */ - - static symbol_alias_set_t * - propagate_aliases_forward (bool (*in_set_p) - (tree decl, tree target, void *data), - void *data) - { - symbol_alias_set_t *set; - unsigned i; - alias_pair *p; - bool changed; - - set = symbol_alias_set_create (); - for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i) - if (in_set_p (p->decl, p->target, data)) - symbol_alias_set_insert (set, p->decl); - do - { - changed = false; - for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i) - if (symbol_alias_set_contains (set, p->decl) - && !symbol_alias_set_insert (set, p->target)) - changed = true; - } - while (changed); - - return set; - } - - /* Like propagate_aliases_forward but do backward propagation. */ - - symbol_alias_set_t * - propagate_aliases_backward (bool (*in_set_p) - (tree decl, tree target, void *data), - void *data) - { - symbol_alias_set_t *set; - unsigned i; - alias_pair *p; - bool changed; - - /* We have to compute the set of set nodes including aliases - themselves. */ - set = symbol_alias_set_create (); - for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i) - if (in_set_p (p->decl, p->target, data)) - symbol_alias_set_insert (set, p->target); - do - { - changed = false; - for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i) - if (symbol_alias_set_contains (set, p->target) - && !symbol_alias_set_insert (set, p->decl)) - changed = true; - } - while (changed); - - return set; - } - /* See if the alias is trivially visible. This means - 1) alias is expoerted from the unit or - 2) alias is used in the code. - We assume that unused cgraph/varpool nodes has been - removed. - Used as callback for propagate_aliases. */ - - static bool - trivially_visible_alias (tree decl, tree target ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) - { - struct cgraph_node *fnode = NULL; - struct varpool_node *vnode = NULL; - - if (!TREE_PUBLIC (decl)) - { - if (TREE_CODE (decl) == FUNCTION_DECL) - fnode = cgraph_get_node (decl); - else - vnode = varpool_get_node (decl); - return vnode || fnode; - } - else - return true; - } - - /* See if the target of alias is defined in this unit. - Used as callback for propagate_aliases. */ - - static bool - trivially_defined_alias (tree decl ATTRIBUTE_UNUSED, - tree target, - void *data ATTRIBUTE_UNUSED) - { - struct cgraph_node *fnode = NULL; - struct varpool_node *vnode = NULL; - - fnode = cgraph_node_for_asm (target); - vnode = (fnode == NULL) ? varpool_node_for_asm (target) : NULL; - return (fnode && fnode->analyzed) || (vnode && vnode->finalized); - } - - /* Remove the alias pairing for functions that are no longer in the call - graph. */ - - void - remove_unreachable_alias_pairs (void) - { - symbol_alias_set_t *visible; - unsigned i; - alias_pair *p; - - if (alias_pairs == NULL) - return; - - /* We have to compute the set of visible nodes including aliases - themselves. */ - visible = propagate_aliases_forward (trivially_visible_alias, NULL); - - for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ) - { - if (!DECL_EXTERNAL (p->decl) - && !symbol_alias_set_contains (visible, p->decl)) - { - VEC_unordered_remove (alias_pair, alias_pairs, i); - continue; - } - - i++; - } - - symbol_alias_set_destroy (visible); - } - - - /* First pass of completing pending aliases. Make sure that cgraph knows - which symbols will be required. */ - - void - finish_aliases_1 (void) - { - symbol_alias_set_t *defined; - unsigned i; - alias_pair *p; - - if (alias_pairs == NULL) - return; - - /* We have to compute the set of defined nodes including aliases - themselves. */ - defined = propagate_aliases_backward (trivially_defined_alias, NULL); - - FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p) - { - tree target_decl; - - target_decl = find_decl (p->target); - if (target_decl == NULL) - { - if (symbol_alias_set_contains (defined, p->target)) - continue; - - if (! (p->emitted_diags & ALIAS_DIAG_TO_UNDEF) - && ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl))) - { - error ("%q+D aliased to undefined symbol %qE", - p->decl, p->target); - p->emitted_diags |= ALIAS_DIAG_TO_UNDEF; - } - } - else if (! (p->emitted_diags & ALIAS_DIAG_TO_EXTERN) - && DECL_EXTERNAL (target_decl) - /* We use local aliases for C++ thunks to force the tailcall - to bind locally. This is a hack - to keep it working do - the following (which is not strictly correct). */ - && (! TREE_CODE (target_decl) == FUNCTION_DECL - || ! DECL_VIRTUAL_P (target_decl)) - && ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl))) - { - error ("%q+D aliased to external symbol %qE", - p->decl, p->target); - p->emitted_diags |= ALIAS_DIAG_TO_EXTERN; - } - } - - symbol_alias_set_destroy (defined); - } - - /* Second pass of completing pending aliases. Emit the actual assembly. - This happens at the end of compilation and thus it is assured that the - target symbol has been emitted. */ - - void - finish_aliases_2 (void) - { - unsigned i; - alias_pair *p; - - FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p) - do_assemble_alias (p->decl, p->target); - - VEC_truncate (alias_pair, alias_pairs, 0); - } - /* Emit an assembler directive to make the symbol for DECL an alias to the symbol for TARGET. */ --- 5535,5540 ---- *************** assemble_alias (tree decl, tree target) *** 5845,5858 **** target_decl = find_decl (target); else target_decl= NULL; ! if (target_decl && TREE_ASM_WRITTEN (target_decl)) do_assemble_alias (decl, target); else { alias_pair *p = VEC_safe_push (alias_pair, gc, alias_pairs, NULL); p->decl = decl; p->target = target; - p->emitted_diags = ALIAS_DIAG_NONE; } } --- 5596,5609 ---- target_decl = find_decl (target); else target_decl= NULL; ! if ((target_decl && TREE_ASM_WRITTEN (target_decl)) ! || cgraph_state >= CGRAPH_STATE_EXPANSION) do_assemble_alias (decl, target); else { alias_pair *p = VEC_safe_push (alias_pair, gc, alias_pairs, NULL); p->decl = decl; p->target = target; } } Index: output.h =================================================================== *** output.h (revision 187695) --- output.h (working copy) *************** extern int decode_reg_name (const char * *** 187,192 **** --- 187,193 ---- extern int decode_reg_name_and_count (const char *, int *); extern void assemble_alias (tree, tree); + extern void do_assemble_alias (tree, tree); extern void default_assemble_visibility (tree, int); Index: varpool.c =================================================================== *** varpool.c (revision 187695) --- varpool.c (working copy) *************** varpool_remove_unreferenced_decls (void) *** 349,355 **** if (cgraph_dump_file) fprintf (cgraph_dump_file, "Trivially needed variables:"); - finish_aliases_1 (); FOR_EACH_DEFINED_VARIABLE (node) { if (node->analyzed --- 349,354 ----