Hi, GNU LD has bug about reporting references to hidden symbol sthat has been optimized out. This however made me notice that we do output into LTO symbol tables things that do not belong there. In partiuclar we often output extern inline functions that has been fully inlined by early opts. This patch solves the problem by running cgraph unreachable function rmeoval before IPA (currently it is done only before early opts, not after). There is also hunk in ipa.c that hsould have been removed afte ipa-ref has been introduced and finally we keep around virtual functions for possible type based devirutalization. These are also not real references in the ymbol table sense.
Bootstrapped/regtested x86_64-linux, tested on Mozilla build and comitted. Honza * cgraphunit.c (ipa_passes): Remove unrechable nodes. * lto-streamer-out.c (produce_symtab): Skip unused extern declarations. * ipa.c (cgraph_remove_unreachable_nodes): Do not assume that external functions are reachable when address is taken. * ipa-inline-analysis.c (reset_inline_edge_summary): New * gcc.dg/ipa/ctor-empty-1.c: Update dump file. Index: cgraphunit.c =================================================================== *** cgraphunit.c (revision 179423) --- cgraphunit.c (working copy) *************** ipa_passes (void) *** 2011,2016 **** --- 2011,2022 ---- return; } + /* We never run removal of unreachable nodes after early passes. This is + because TODO is run before the subpasses. It is important to remove + the unreachable functions to save works at IPA level and to get LTO + symbol tables right. */ + cgraph_remove_unreachable_nodes (true, cgraph_dump_file); + /* If pass_all_early_optimizations was not scheduled, the state of the cgraph will not be properly updated. Update it now. */ if (cgraph_state < CGRAPH_STATE_IPA_SSA) Index: testsuite/gcc.dg/ipa/ctor-empty-1.c =================================================================== *** testsuite/gcc.dg/ipa/ctor-empty-1.c (revision 179423) --- testsuite/gcc.dg/ipa/ctor-empty-1.c (working copy) *************** *** 1,8 **** /* { dg-do compile } */ ! /* { dg-options "-O3 -c -fdump-ipa-whole-program" } */ static __attribute__((constructor)) void empty_constructor() { } ! /* { dg-final { scan-ipa-dump "Reclaiming functions: empty_constructor" "whole-program" } } */ ! /* { dg-final { cleanup-ipa-dump "whole-program" } } */ --- 1,8 ---- /* { dg-do compile } */ ! /* { dg-options "-O3 -c -fdump-ipa-cgraph" } */ static __attribute__((constructor)) void empty_constructor() { } ! /* { dg-final { scan-ipa-dump "Reclaiming functions: empty_constructor" "cgraph" } } */ ! /* { dg-final { cleanup-ipa-dump "cgraph" } } */ Index: lto-streamer-out.c =================================================================== *** lto-streamer-out.c (revision 179423) --- lto-streamer-out.c (working copy) *************** produce_symtab (struct output_block *ob, *** 1407,1412 **** --- 1407,1421 ---- node = lto_cgraph_encoder_deref (encoder, i); if (!DECL_EXTERNAL (node->decl)) continue; + /* We keep around unused extern inlines in order to be able to inline + them indirectly or via vtables. Do not output them to symbol + table: they end up being undefined and just consume space. */ + if (!node->address_taken && !node->callers) + { + gcc_assert (node->analyzed); + gcc_assert (DECL_DECLARED_INLINE_P (node->decl)); + continue; + } if (DECL_COMDAT (node->decl) && cgraph_comdat_can_be_unshared_p (node)) continue; Index: ipa.c =================================================================== *** ipa.c (revision 179424) --- ipa.c (working copy) *************** cgraph_remove_unreachable_nodes (bool be *** 196,207 **** /* Keep around virtual functions for possible devirtualization. */ || (before_inlining_p && DECL_VIRTUAL_P (node->decl) ! && (DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))) ! /* Also external functions with address taken are better to stay ! for indirect inlining. */ ! || (before_inlining_p ! && DECL_EXTERNAL (node->decl) ! && node->address_taken))) { gcc_assert (!node->global.inlined_to); enqueue_cgraph_node (node, &first); --- 196,202 ---- /* Keep around virtual functions for possible devirtualization. */ || (before_inlining_p && DECL_VIRTUAL_P (node->decl) ! && (DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))))) { gcc_assert (!node->global.inlined_to); enqueue_cgraph_node (node, &first); Index: tree-sra.c =================================================================== *** tree-sra.c (revision 179423) --- tree-sra.c (working copy) *************** modify_function (struct cgraph_node *nod *** 4622,4627 **** --- 4622,4628 ---- VEC (cgraph_edge_p, heap) * redirect_callers = collect_callers_of_node (node); rebuild_cgraph_edges (); + free_dominance_info (CDI_DOMINATORS); pop_cfun (); current_function_decl = NULL_TREE;