Hi, this patch makes cgraph code to also handle wekrefs as long as their destination declaration is known. The cases where it is not still needs updating at lto-symtab I plan to do incrementally.
The basic idea is to handle weakrefs as external declaration (so they are subject of unrechable code removal) and make cgraph code to output those that are still needed. I had this in my tree for a while, so hope it will not cause much surprises. Bootstrapped/regtested x86_64-linux & tested on Mozilla/libreoffice LTO Honza * cgraphunit.c (handle_alias_pairs): Also handle wekref with destination declared. (output_weakrefs): New function. * varpool.c (varpool_create_variable_alias): Handle external aliases. Index: cgraphunit.c =================================================================== *** cgraphunit.c (revision 180053) --- cgraphunit.c (working copy) *************** handle_alias_pairs (void) *** 1219,1225 **** for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p);) { if (TREE_CODE (p->decl) == FUNCTION_DECL - && !lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)) && (target_node = cgraph_node_for_asm (p->target)) != NULL) { src_node = cgraph_get_node (p->decl); --- 1219,1224 ---- *************** handle_alias_pairs (void) *** 1231,1242 **** 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) = 0; cgraph_create_function_alias (p->decl, target_node->decl); VEC_unordered_remove (alias_pair, alias_pairs, i); } else if (TREE_CODE (p->decl) == VAR_DECL - && !lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)) && (target_vnode = varpool_node_for_asm (p->target)) != NULL) { /* Normally EXTERNAL flag is used to mark external inlines, --- 1230,1241 ---- 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; cgraph_create_function_alias (p->decl, target_node->decl); VEC_unordered_remove (alias_pair, alias_pairs, i); } else if (TREE_CODE (p->decl) == VAR_DECL && (target_vnode = varpool_node_for_asm (p->target)) != NULL) { /* Normally EXTERNAL flag is used to mark external inlines, *************** handle_alias_pairs (void) *** 1245,1251 **** 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) = 0; varpool_create_variable_alias (p->decl, target_vnode->decl); VEC_unordered_remove (alias_pair, alias_pairs, i); } --- 1244,1251 ---- 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; varpool_create_variable_alias (p->decl, target_vnode->decl); VEC_unordered_remove (alias_pair, alias_pairs, i); } *************** ipa_passes (void) *** 2064,2069 **** --- 2064,2089 ---- bitmap_obstack_release (NULL); } + /* Weakrefs may be associated to external decls and thus not output + at expansion time. Emit all neccesary aliases. */ + + void + output_weakrefs (void) + { + struct cgraph_node *node; + struct varpool_node *vnode; + for (node = cgraph_nodes; node; node = node->next) + if (node->alias && node->thunk.alias && DECL_EXTERNAL (node->decl) + && !TREE_ASM_WRITTEN (node->decl)) + assemble_alias (node->decl, + DECL_ASSEMBLER_NAME (node->thunk.alias)); + for (vnode = varpool_nodes; vnode; vnode = vnode->next) + if (vnode->alias && vnode->alias_of && DECL_EXTERNAL (vnode->decl) + && !TREE_ASM_WRITTEN (vnode->decl)) + assemble_alias (vnode->decl, + DECL_ASSEMBLER_NAME (vnode->alias_of)); + } + /* Perform simple optimizations based on callgraph. */ *************** cgraph_optimize (void) *** 2150,2155 **** --- 2170,2177 ---- varpool_assemble_pending_decls (); } + + output_weakrefs (); cgraph_process_new_functions (); cgraph_state = CGRAPH_STATE_FINISHED; Index: varpool.c =================================================================== *** varpool.c (revision 180052) --- varpool.c (working copy) *************** varpool_create_variable_alias (tree alia *** 703,711 **** gcc_assert (TREE_CODE (alias) == VAR_DECL); alias_node = varpool_node (alias); alias_node->alias = 1; ! alias_node->finalized = 1; alias_node->alias_of = decl; ! if (decide_is_variable_needed (alias_node, alias) || alias_node->needed) varpool_mark_needed_node (alias_node); return alias_node; --- 703,713 ---- gcc_assert (TREE_CODE (alias) == VAR_DECL); alias_node = varpool_node (alias); alias_node->alias = 1; ! if (!DECL_EXTERNAL (alias)) ! alias_node->finalized = 1; alias_node->alias_of = decl; ! if ((!DECL_EXTERNAL (alias) ! && decide_is_variable_needed (alias_node, alias)) || alias_node->needed) varpool_mark_needed_node (alias_node); return alias_node;