Hi, this patch deals with C++ keyed methods and explicit instantiations. Currently C++ calls mark_used that ultimately sets force_output on the functions. This is equivalent to attribute ((used)) on the function/variable and it is bit too strong.
For example at LTO time we can ignore the C++ ABI as long as we see all uses of the symbols (i.e. we have resolution info and the symbol is hidden). This patch thus implements specific flag forced_by_abi. used for this purpose and cleanups the code dealing with it. This affects abour 3800 symbols on Firefox turning them to regular non-forced symbols. This allows bit more unreachable code removal and optimization across these. Bootstrapped/regtested x86_64-linux on ppc64-linux (in bit earlier version) as well as tested on LTO Firefox, comitted. Honza * class.c (emit_register_classes_in_jcr_section): Use DECL_PRESERVE_P instead of mark_decl_referenced. * decl2.c (maybe_make_one_only): Use forced_by_abi instad of mark_decl_referenced. (mark_needed): Likewise. * cgraph.c (cgraph_remove_node): Clear forced_by_abi. (cgraph_node_cannot_be_local_p_1): Honnor symbol.forced_by_abi and symtab_used_from_object_file_p. (cgraph_make_node_local_1): Clear forced_by_abi. (cgraph_can_remove_if_no_direct_calls_and): Use forced_by_abi * cgraph.h (symtab_node_base): Add forced_by_abi. (decide_is_variable_needed): Remove. (varpool_can_remove_if_no_refs): Honnor symbol.forced_by_abi. * cgraphunit.c (cgraph_decide_is_function_needed): Rename to .. (decide_is_symbol_needed): ... this one; handle symbols in general; always analyze virtuals; honnor forced_by_abi. (cgraph_finalize_function): Update. (varpool_finalize_decl): Update. (symbol_defined_and_needed): Remove. (analyze_functions): Update. * lto-cgraph.c (lto_output_node, lto_output_varpool_node, output_refs, input_overwrite_node): Handle forced_by_abi. * ipa.c (cgraph_address_taken_from_non_vtable_p): Rename to ... (address_taken_from_non_vtable_p): ... this one. (comdat_can_be_unshared_p_1): New function. (cgraph_comdat_can_be_unshared_p): Rename to ... (comdat_can_be_unshared_p): ... this one; handle symbols in general. (varpool_externally_visible_p): Use comdat_can_be_unshared_p. (function_and_variable_visibility): Clear forced_by_abi as needed. * trans-mem.c (ipa_tm_mark_forced_by_abi_node): New functoin. (ipa_tm_create_version_alias, ipa_tm_create_version): Update. * varasm.c (mark_decl_referenced): Remove. * symtab.c (dump_symtab_base): Dump forced_by_abi. * varpool.c (decide_is_variable_needed): Remove. Index: java/class.c =================================================================== *** java/class.c (revision 199608) --- java/class.c (working copy) *************** emit_register_classes_in_jcr_section (vo *** 2814,2823 **** TREE_CONSTANT (cdecl) = 1; DECL_ARTIFICIAL (cdecl) = 1; DECL_IGNORED_P (cdecl) = 1; pushdecl_top_level (cdecl); relayout_decl (cdecl); rest_of_decl_compilation (cdecl, 1, 0); - mark_decl_referenced (cdecl); #else /* A target has defined TARGET_USE_JCR_SECTION, but doesn't have a JCR_SECTION_NAME. */ --- 2814,2823 ---- TREE_CONSTANT (cdecl) = 1; DECL_ARTIFICIAL (cdecl) = 1; DECL_IGNORED_P (cdecl) = 1; + DECL_PRESERVE_P (cdecl) = 1; pushdecl_top_level (cdecl); relayout_decl (cdecl); rest_of_decl_compilation (cdecl, 1, 0); #else /* A target has defined TARGET_USE_JCR_SECTION, but doesn't have a JCR_SECTION_NAME. */ Index: cgraph.c =================================================================== *** cgraph.c (revision 199608) --- cgraph.c (working copy) *************** cgraph_remove_node (struct cgraph_node * *** 1326,1331 **** --- 1326,1332 ---- /* Incremental inlining access removed nodes stored in the postorder list. */ node->symbol.force_output = false; + node->symbol.forced_by_abi = false; for (n = node->nested; n; n = n->next_nested) n->origin = NULL; node->nested = NULL; *************** cgraph_node_cannot_be_local_p_1 (struct *** 1712,1717 **** --- 1713,1720 ---- { return !(!node->symbol.force_output && ((DECL_COMDAT (node->symbol.decl) + && !node->symbol.forced_by_abi + && !symtab_used_from_object_file_p ((symtab_node) node) && !node->symbol.same_comdat_group) || !node->symbol.externally_visible)); } *************** cgraph_make_node_local_1 (struct cgraph_ *** 1804,1809 **** --- 1807,1813 ---- symtab_make_decl_local (node->symbol.decl); node->symbol.externally_visible = false; + node->symbol.forced_by_abi = false; node->local.local = true; node->symbol.unique_name = (node->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY || node->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY_EXP); *************** cgraph_can_remove_if_no_direct_calls_and *** 2085,2090 **** --- 2089,2095 ---- /* Only COMDAT functions can be removed if externally visible. */ if (node->symbol.externally_visible && (!DECL_COMDAT (node->symbol.decl) + || node->symbol.forced_by_abi || symtab_used_from_object_file_p ((symtab_node) node))) return false; return true; Index: cgraph.h =================================================================== *** cgraph.h (revision 199608) --- cgraph.h (working copy) *************** struct GTY(()) symtab_node_base *** 72,80 **** /* Set when function is visible by other units. */ unsigned externally_visible : 1; ! /* Needed variables might become dead by optimization. This flag ! forces the variable to be output even if it appears dead otherwise. */ unsigned force_output : 1; /* True when the name is known to be unique and thus it does not need mangling. */ unsigned unique_name : 1; --- 72,84 ---- /* Set when function is visible by other units. */ unsigned externally_visible : 1; ! /* The symbol will be assumed to be used in an invisiable way (like ! by an toplevel asm statement). */ unsigned force_output : 1; + /* Like FORCE_OUTPUT, but in the case it is ABI requiring the symbol to be + exported. Unlike FORCE_OUTPUT this flag gets cleared to symbols promoted + to static and it does not inhibit optimization. */ + unsigned forced_by_abi : 1; /* True when the name is known to be unique and thus it does not need mangling. */ unsigned unique_name : 1; *************** void dump_varpool (FILE *); *** 775,781 **** void dump_varpool_node (FILE *, struct varpool_node *); void varpool_finalize_decl (tree); - bool decide_is_variable_needed (struct varpool_node *, tree); enum availability cgraph_variable_initializer_availability (struct varpool_node *); void cgraph_make_node_local (struct cgraph_node *); bool cgraph_node_can_be_local_p (struct cgraph_node *); --- 779,784 ---- *************** varpool_can_remove_if_no_refs (struct va *** 1216,1221 **** --- 1219,1225 ---- return true; return (!node->symbol.force_output && !node->symbol.used_from_other_partition && ((DECL_COMDAT (node->symbol.decl) + && !node->symbol.forced_by_abi && !symtab_used_from_object_file_p ((symtab_node) node)) || !node->symbol.externally_visible || DECL_HAS_VALUE_EXPR_P (node->symbol.decl))); Index: cgraphunit.c =================================================================== *** cgraphunit.c (revision 199608) --- cgraphunit.c (working copy) *************** static GTY(()) struct asm_node *asm_last *** 216,251 **** /* 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) { ! /* If the user told us it is used, then it must be so. */ ! if (node->symbol.force_output) ! return true; /* Double check that no one output the function into assembly file early. */ gcc_checking_assert (!DECL_ASSEMBLER_NAME_SET_P (decl) || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))); ! /* 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; ! /* Externally visible functions must be output. The exception is ! COMDAT functions that must be output only when they are needed. */ ! if (TREE_PUBLIC (decl) ! && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) return true; return false; --- 216,260 ---- /* Used for vtable lookup in thunk adjusting. */ static GTY (()) tree vtable_entry_type; ! /* 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) { ! 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) || !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; ! if (DECL_EXTERNAL (decl)) ! return false; ! /* If the user told us it is used, then it must be so. */ ! if (node->symbol.force_output) ! return true; ! ! /* 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; *************** cgraph_finalize_function (tree decl, boo *** 447,453 **** ggc_collect (); if (cgraph_state == CGRAPH_STATE_CONSTRUCTION ! && (cgraph_decide_is_function_needed (node, decl) || referred_to_p ((symtab_node)node))) enqueue_node ((symtab_node)node); } --- 456,462 ---- ggc_collect (); if (cgraph_state == CGRAPH_STATE_CONSTRUCTION ! && (decide_is_symbol_needed ((symtab_node) node) || referred_to_p ((symtab_node)node))) enqueue_node ((symtab_node)node); } *************** varpool_finalize_decl (tree decl) *** 798,804 **** node->symbol.force_output = true; if (cgraph_state == CGRAPH_STATE_CONSTRUCTION ! && (decide_is_variable_needed (node, decl) || referred_to_p ((symtab_node)node))) enqueue_node ((symtab_node)node); if (cgraph_state >= CGRAPH_STATE_IPA_SSA) --- 807,813 ---- node->symbol.force_output = true; if (cgraph_state == CGRAPH_STATE_CONSTRUCTION ! && (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) *************** varpool_finalize_decl (tree decl) *** 810,830 **** } - /* 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 */ --- 819,824 ---- *************** analyze_functions (void) *** 866,872 **** node != (symtab_node)first_analyzed && node != (symtab_node)first_analyzed_var; node = node->symbol.next) { ! if (symbol_defined_and_needed (node)) { enqueue_node (node); if (!changed && cgraph_dump_file) --- 860,866 ---- node != (symtab_node)first_analyzed && node != (symtab_node)first_analyzed_var; node = node->symbol.next) { ! if (decide_is_symbol_needed (node)) { enqueue_node (node); if (!changed && cgraph_dump_file) Index: cp/decl2.c =================================================================== *** cp/decl2.c (revision 199608) --- cp/decl2.c (working copy) *************** maybe_make_one_only (tree decl) *** 1703,1711 **** if (VAR_P (decl)) { DECL_COMDAT (decl) = 1; /* Mark it needed so we don't forget to emit it. */ ! mark_decl_referenced (decl); TREE_USED (decl) = 1; } } --- 1703,1712 ---- if (VAR_P (decl)) { + struct varpool_node *node = varpool_node_for_decl (decl); DECL_COMDAT (decl) = 1; /* Mark it needed so we don't forget to emit it. */ ! node->symbol.forced_by_abi = true; TREE_USED (decl) = 1; } } *************** void *** 1813,1819 **** mark_needed (tree decl) { TREE_USED (decl) = 1; ! mark_decl_referenced (decl); } /* DECL is either a FUNCTION_DECL or a VAR_DECL. This function --- 1814,1835 ---- mark_needed (tree decl) { TREE_USED (decl) = 1; ! if (TREE_CODE (decl) == FUNCTION_DECL) ! { ! /* Extern inline functions don't become needed when referenced. ! If we know a method will be emitted in other TU and no new ! functions can be marked reachable, just use the external ! definition. */ ! struct cgraph_node *node = cgraph_get_create_node (decl); ! node->symbol.forced_by_abi = true; ! } ! else if (TREE_CODE (decl) == VAR_DECL) ! { ! struct varpool_node *node = varpool_node_for_decl (decl); ! /* C++ frontend use mark_decl_references to force COMDAT variables ! to be output that might appear dead otherwise. */ ! node->symbol.forced_by_abi = true; ! } } /* DECL is either a FUNCTION_DECL or a VAR_DECL. This function Index: lto-cgraph.c =================================================================== *** lto-cgraph.c (revision 199608) --- lto-cgraph.c (working copy) *************** lto_output_node (struct lto_simple_outpu *** 469,474 **** --- 469,475 ---- bp_pack_value (&bp, node->local.can_change_signature, 1); bp_pack_value (&bp, node->local.redefined_extern_inline, 1); bp_pack_value (&bp, node->symbol.force_output, 1); + bp_pack_value (&bp, node->symbol.forced_by_abi, 1); bp_pack_value (&bp, node->symbol.unique_name, 1); bp_pack_value (&bp, node->symbol.address_taken, 1); bp_pack_value (&bp, node->abstract_and_needed, 1); *************** lto_output_varpool_node (struct lto_simp *** 527,532 **** --- 528,534 ---- bp = bitpack_create (ob->main_stream); bp_pack_value (&bp, node->symbol.externally_visible, 1); bp_pack_value (&bp, node->symbol.force_output, 1); + bp_pack_value (&bp, node->symbol.forced_by_abi, 1); bp_pack_value (&bp, node->symbol.unique_name, 1); bp_pack_value (&bp, node->symbol.definition, 1); alias_p = node->symbol.alias && (!boundary_p || DECL_EXTERNAL (node->symbol.decl)); *************** output_refs (lto_symtab_encoder_t encode *** 672,678 **** count = ipa_ref_list_nreferences (&node->symbol.ref_list); if (count) { ! streamer_write_uhwi_stream (ob->main_stream, count); streamer_write_uhwi_stream (ob->main_stream, lto_symtab_encoder_lookup (encoder, node)); for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list, --- 674,680 ---- count = ipa_ref_list_nreferences (&node->symbol.ref_list); if (count) { ! streamer_write_gcov_count_stream (ob->main_stream, count); streamer_write_uhwi_stream (ob->main_stream, lto_symtab_encoder_lookup (encoder, node)); for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list, *************** input_overwrite_node (struct lto_file_de *** 881,886 **** --- 883,889 ---- node->local.can_change_signature = bp_unpack_value (bp, 1); node->local.redefined_extern_inline = bp_unpack_value (bp, 1); node->symbol.force_output = bp_unpack_value (bp, 1); + node->symbol.forced_by_abi = bp_unpack_value (bp, 1); node->symbol.unique_name = bp_unpack_value (bp, 1); node->symbol.address_taken = bp_unpack_value (bp, 1); node->abstract_and_needed = bp_unpack_value (bp, 1); *************** input_varpool_node (struct lto_file_decl *** 1039,1044 **** --- 1042,1048 ---- bp = streamer_read_bitpack (ib); node->symbol.externally_visible = bp_unpack_value (&bp, 1); node->symbol.force_output = bp_unpack_value (&bp, 1); + node->symbol.forced_by_abi = bp_unpack_value (&bp, 1); 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); Index: ipa.c =================================================================== *** ipa.c (revision 199608) --- ipa.c (working copy) *************** ipa_discover_readonly_nonaddressable_var *** 515,521 **** /* Return true when there is a reference to node and it is not vtable. */ static bool ! cgraph_address_taken_from_non_vtable_p (struct cgraph_node *node) { int i; struct ipa_ref *ref; --- 519,525 ---- /* Return true when there is a reference to node and it is not vtable. */ static bool ! address_taken_from_non_vtable_p (symtab_node node) { int i; struct ipa_ref *ref; *************** cgraph_address_taken_from_non_vtable_p ( *** 533,538 **** --- 537,574 ---- return false; } + /* A helper for comdat_can_be_unshared_p. */ + + static bool + comdat_can_be_unshared_p_1 (symtab_node node) + { + /* When address is taken, we don't know if equality comparison won't + break eventaully. Exception are virutal functions and vtables, where + this is not possible by language standard. */ + if (!DECL_VIRTUAL_P (node->symbol.decl) + && address_taken_from_non_vtable_p (node)) + return false; + + /* If the symbol is used in some weird way, better to not touch it. */ + if (node->symbol.force_output) + return false; + + /* Explicit instantiations needs to be output when possibly + used externally. */ + if (node->symbol.forced_by_abi + && TREE_PUBLIC (node->symbol.decl) + && (node->symbol.resolution != LDPR_PREVAILING_DEF_IRONLY + && !flag_whole_program)) + return false; + + /* Non-readonly and volatile variables can not be duplicated. */ + if (is_a <varpool_node> (node) + && (!TREE_READONLY (node->symbol.decl) + || TREE_THIS_VOLATILE (node->symbol.decl))) + return false; + return true; + } + /* COMDAT functions must be shared only if they have address taken, otherwise we can produce our own private implementation with -fwhole-program. *************** cgraph_address_taken_from_non_vtable_p ( *** 543,566 **** but in C++ there is no way to compare their addresses for equality. */ static bool ! cgraph_comdat_can_be_unshared_p (struct cgraph_node *node) { ! if ((cgraph_address_taken_from_non_vtable_p (node) ! && !DECL_VIRTUAL_P (node->symbol.decl)) ! || !node->symbol.definition) return false; if (node->symbol.same_comdat_group) { ! struct cgraph_node *next; /* If more than one function is in the same COMDAT group, it must be shared even if just one function in the comdat group has address taken. */ ! for (next = cgraph (node->symbol.same_comdat_group); ! next != node; next = cgraph (next->symbol.same_comdat_group)) ! if (cgraph_address_taken_from_non_vtable_p (next) ! && !DECL_VIRTUAL_P (next->symbol.decl)) ! return false; } return true; } --- 578,598 ---- but in C++ there is no way to compare their addresses for equality. */ static bool ! comdat_can_be_unshared_p (symtab_node node) { ! if (!comdat_can_be_unshared_p_1 (node)) return false; if (node->symbol.same_comdat_group) { ! symtab_node next; /* If more than one function is in the same COMDAT group, it must be shared even if just one function in the comdat group has address taken. */ ! for (next = node->symbol.same_comdat_group; ! next != node; next = next->symbol.same_comdat_group) ! if (!comdat_can_be_unshared_p_1 (next)) ! return false; } return true; } *************** cgraph_externally_visible_p (struct cgra *** 606,612 **** implementing same COMDAT) */ if ((in_lto_p || whole_program) && DECL_COMDAT (node->symbol.decl) ! && cgraph_comdat_can_be_unshared_p (node)) return false; /* When doing link time optimizations, hidden symbols become local. */ --- 638,644 ---- implementing same COMDAT) */ if ((in_lto_p || whole_program) && DECL_COMDAT (node->symbol.decl) ! && comdat_can_be_unshared_p ((symtab_node) node)) return false; /* When doing link time optimizations, hidden symbols become local. */ *************** varpool_externally_visible_p (struct var *** 676,683 **** is faster for dynamic linking. Also this match logic hidding vtables from LTO symbol tables. */ if ((in_lto_p || flag_whole_program) ! && !vnode->symbol.force_output ! && DECL_COMDAT (vnode->symbol.decl) && DECL_VIRTUAL_P (vnode->symbol.decl)) return false; /* When doing link time optimizations, hidden symbols become local. */ --- 708,715 ---- is faster for dynamic linking. Also this match logic hidding vtables from LTO symbol tables. */ if ((in_lto_p || flag_whole_program) ! && DECL_COMDAT (vnode->symbol.decl) ! && comdat_can_be_unshared_p ((symtab_node) vnode)) return false; /* When doing link time optimizations, hidden symbols become local. */ *************** function_and_variable_visibility (bool w *** 739,747 **** /* Frontends and alias code marks nodes as needed before parsing is finished. We may end up marking as node external nodes where this flag is meaningless strip it. */ ! if (node->symbol.force_output ! && (DECL_EXTERNAL (node->symbol.decl) || !node->symbol.definition)) ! node->symbol.force_output = 0; /* C++ FE on lack of COMDAT support create local COMDAT functions (that ought to be shared but can not due to object format --- 771,781 ---- /* Frontends and alias code marks nodes as needed before parsing is finished. We may end up marking as node external nodes where this flag is meaningless strip it. */ ! if (DECL_EXTERNAL (node->symbol.decl) || !node->symbol.definition) ! { ! node->symbol.force_output = 0; ! node->symbol.forced_by_abi = 0; ! } /* C++ FE on lack of COMDAT support create local COMDAT functions (that ought to be shared but can not due to object format *************** function_and_variable_visibility (bool w *** 776,782 **** node->symbol.externally_visible = true; } else ! node->symbol.externally_visible = false; if (!node->symbol.externally_visible && node->symbol.definition && !DECL_EXTERNAL (node->symbol.decl)) { --- 810,819 ---- node->symbol.externally_visible = true; } else ! { ! node->symbol.externally_visible = false; ! node->symbol.forced_by_abi = false; ! } if (!node->symbol.externally_visible && node->symbol.definition && !DECL_EXTERNAL (node->symbol.decl)) { *************** function_and_variable_visibility (bool w *** 855,861 **** if (varpool_externally_visible_p (vnode)) vnode->symbol.externally_visible = true; else ! vnode->symbol.externally_visible = false; if (!vnode->symbol.externally_visible) { gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->symbol.decl)); --- 892,901 ---- if (varpool_externally_visible_p (vnode)) vnode->symbol.externally_visible = true; else ! { ! vnode->symbol.externally_visible = false; ! vnode->symbol.forced_by_abi = false; ! } if (!vnode->symbol.externally_visible) { gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->symbol.decl)); Index: trans-mem.c =================================================================== *** trans-mem.c (revision 199608) --- trans-mem.c (working copy) *************** ipa_tm_mark_force_output_node (struct cg *** 4681,4686 **** --- 4681,4693 ---- node->symbol.analyzed = true; } + static inline void + ipa_tm_mark_forced_by_abi_node (struct cgraph_node *node) + { + node->symbol.forced_by_abi = true; + node->symbol.analyzed = true; + } + /* Callback data for ipa_tm_create_version_alias. */ struct create_version_alias_info { *************** ipa_tm_create_version_alias (struct cgra *** 4737,4742 **** --- 4744,4751 ---- if (info->old_node->symbol.force_output || ipa_ref_list_first_referring (&info->old_node->symbol.ref_list)) ipa_tm_mark_force_output_node (new_node); + if (info->old_node->symbol.forced_by_abi) + ipa_tm_mark_forced_by_abi_node (new_node); return false; } *************** ipa_tm_create_version (struct cgraph_nod *** 4792,4797 **** --- 4801,4808 ---- if (old_node->symbol.force_output || ipa_ref_list_first_referring (&old_node->symbol.ref_list)) ipa_tm_mark_force_output_node (new_node); + if (old_node->symbol.forced_by_abi) + ipa_tm_mark_forced_by_abi_node (new_node); /* Do the same thing, but for any aliases of the original node. */ { Index: varasm.c =================================================================== *** varasm.c (revision 199608) --- varasm.c (working copy) *************** mark_referenced (tree id) *** 2244,2276 **** TREE_SYMBOL_REFERENCED (id) = 1; } - /* Set the symbol_referenced flag for DECL and notify callgraph. */ - void - mark_decl_referenced (tree decl) - { - if (TREE_CODE (decl) == FUNCTION_DECL) - { - /* Extern inline functions don't become needed when referenced. - If we know a method will be emitted in other TU and no new - functions can be marked reachable, just use the external - definition. */ - struct cgraph_node *node = cgraph_get_create_node (decl); - if (!DECL_EXTERNAL (decl) - && !node->symbol.definition) - cgraph_mark_force_output_node (node); - } - else if (TREE_CODE (decl) == VAR_DECL) - { - struct varpool_node *node = varpool_node_for_decl (decl); - /* C++ frontend use mark_decl_references to force COMDAT variables - to be output that might appear dead otherwise. */ - node->symbol.force_output = true; - } - /* else do nothing - we can get various sorts of CST nodes here, - which do not need to be marked. */ - } - - /* Follow the IDENTIFIER_TRANSPARENT_ALIAS chain starting at *ALIAS until we find an identifier that is not itself a transparent alias. Modify the alias passed to it by reference (and all aliases on the --- 2244,2249 ---- Index: symtab.c =================================================================== *** symtab.c (revision 199608) --- symtab.c (working copy) *************** dump_symtab_base (FILE *f, symtab_node n *** 496,501 **** --- 496,503 ---- fprintf (f, " used_from_other_partition"); if (node->symbol.force_output) fprintf (f, " force_output"); + if (node->symbol.forced_by_abi) + fprintf (f, " forced_by_abi"); if (node->symbol.resolution != LDPR_UNKNOWN) fprintf (f, " %s", ld_plugin_symbol_resolution_names[(int)node->symbol.resolution]); Index: varpool.c =================================================================== *** varpool.c (revision 199608) --- varpool.c (working copy) *************** varpool_node_for_asm (tree asmname) *** 130,157 **** return NULL; } - /* Determine if variable DECL is needed. That is, visible to something - either outside this translation unit, something magic in the system - configury */ - bool - decide_is_variable_needed (struct varpool_node *node, tree decl) - { - if (DECL_EXTERNAL (decl)) - return false; - - /* If the user told us it is used, then it must be so. */ - if (node->symbol.force_output) - 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; - } - /* Return if DECL is constant and its initial value is known (so we can do constant folding using DECL_INITIAL (decl)). */ --- 130,135 ----