Hi, current functions that appear as abstract origin of other function gets abstract_and_needed flag set. This flag is then not maintained in any way, but it is used by cgraph_remove_node to avoid removing block tree dneeded later by dwarf2out.
This patch makes the tracking more explicit. Unreachable function removal now maintains the info about what is used as abstract origin. I also renamed the flag to used_as_abstract_origin, since abstract_and_needed suggest that function is DECL_ABSTRACT that is not the rule. This ensures that all abstract origin functions do have nodes attached and this info can be used in free_lang_data and LTO streaming/partitioning (currently we do not bother to ship the trees into LTO partitions that needs them) Bootstrapped/regtested ppc64-linux and in earlier version x86_64-linux, comitted. Honza * cgraph.c (cgraph_release_function_body): Use used_as_abstract_origin. (cgraph_release_function_body): Likewise. (cgraph_can_remove_if_no_direct_calls_p): Likewise. * cgraph.h (cgrpah_node): Rename abstract_and_needed to used_as_abstract_origin. * tree-inline-transfrom.c (can_remove_node_now_p_1): Do not remove symbols used as abstract origins. * cgraphunit.c (analyze_functions): Update. * ipa.c (symtab_remove_unreachable_nodes): Recompute used_as_abstract_origin. * tree-inline.c (tree_function_versioning): Update used_as_abstract_origin; be ready for DECL_RESULT and DECL_ARGUMENTS to be NULL. Index: cgraph.c =================================================================== *** cgraph.c (revision 201291) --- cgraph.c (working copy) *************** void *** 1316,1322 **** cgraph_release_function_body (struct cgraph_node *node) { node->ipa_transforms_to_apply.release (); ! if (!node->abstract_and_needed && cgraph_state != CGRAPH_STATE_PARSING) { DECL_RESULT (node->symbol.decl) = NULL; DECL_ARGUMENTS (node->symbol.decl) = NULL; --- 1317,1323 ---- cgraph_release_function_body (struct cgraph_node *node) { node->ipa_transforms_to_apply.release (); ! if (!node->used_as_abstract_origin && cgraph_state != CGRAPH_STATE_PARSING) { DECL_RESULT (node->symbol.decl) = NULL; DECL_ARGUMENTS (node->symbol.decl) = NULL; *************** cgraph_release_function_body (struct cgr *** 1324,1330 **** /* If the node is abstract and needed, then do not clear DECL_INITIAL of its associated function function declaration because it's needed to emit debug info later. */ ! if (!node->abstract_and_needed && DECL_INITIAL (node->symbol.decl)) DECL_INITIAL (node->symbol.decl) = error_mark_node; release_function_body (node->symbol.decl); } --- 1325,1331 ---- /* If the node is abstract and needed, then do not clear DECL_INITIAL of its associated function function declaration because it's needed to emit debug info later. */ ! if (!node->used_as_abstract_origin && DECL_INITIAL (node->symbol.decl)) DECL_INITIAL (node->symbol.decl) = error_mark_node; release_function_body (node->symbol.decl); } Index: cgraph.h =================================================================== *** cgraph.h (revision 201291) --- cgraph.h (working copy) *************** struct GTY(()) cgraph_node { *** 303,309 **** /* Set when decl is an abstract function pointed to by the ABSTRACT_DECL_ORIGIN of a reachable function. */ ! unsigned abstract_and_needed : 1; /* Set once the function is lowered (i.e. its CFG is built). */ unsigned lowered : 1; /* Set once the function has been instantiated and its callee --- 303,309 ---- /* Set when decl is an abstract function pointed to by the ABSTRACT_DECL_ORIGIN of a reachable function. */ ! unsigned used_as_abstract_origin : 1; /* Set once the function is lowered (i.e. its CFG is built). */ unsigned lowered : 1; /* Set once the function has been instantiated and its callee Index: ipa-inline-transform.c =================================================================== *** ipa-inline-transform.c (revision 201291) --- ipa-inline-transform.c (working copy) *************** can_remove_node_now_p_1 (struct cgraph_n *** 87,92 **** --- 87,93 ---- the callgraph so references can point to it. */ return (!node->symbol.address_taken && !ipa_ref_has_aliases_p (&node->symbol.ref_list) + && !node->used_as_abstract_origin && cgraph_can_remove_if_no_direct_calls_p (node) /* Inlining might enable more devirtualizing, so we want to remove those only after all devirtualizable virtual calls are processed. Index: cgraphunit.c =================================================================== *** cgraphunit.c (revision 201291) --- cgraphunit.c (working copy) *************** analyze_functions (void) *** 925,931 **** { struct cgraph_node *origin_node = cgraph_get_node (DECL_ABSTRACT_ORIGIN (decl)); ! origin_node->abstract_and_needed = true; } } else --- 925,931 ---- { struct cgraph_node *origin_node = cgraph_get_node (DECL_ABSTRACT_ORIGIN (decl)); ! origin_node->used_as_abstract_origin = true; } } else Index: ipa.c =================================================================== *** ipa.c (revision 201291) --- ipa.c (working copy) *************** symtab_remove_unreachable_nodes (bool be *** 234,253 **** This is mostly when they can be referenced externally. Inline clones are special since their declarations are shared with master clone and thus cgraph_can_remove_if_no_direct_calls_and_refs_p should not be called on them. */ ! FOR_EACH_DEFINED_FUNCTION (node) ! if (!node->global.inlined_to ! && !node->symbol.in_other_partition ! && (!cgraph_can_remove_if_no_direct_calls_and_refs_p (node) ! /* Keep around virtual functions for possible devirtualization. */ ! || (before_inlining_p ! && DECL_VIRTUAL_P (node->symbol.decl)))) ! { ! gcc_assert (!node->global.inlined_to); ! pointer_set_insert (reachable, node); ! enqueue_node ((symtab_node)node, &first, reachable); ! } ! else ! gcc_assert (!node->symbol.aux); /* Mark variables that are obviously needed. */ FOR_EACH_DEFINED_VARIABLE (vnode) --- 234,256 ---- This is mostly when they can be referenced externally. Inline clones are special since their declarations are shared with master clone and thus cgraph_can_remove_if_no_direct_calls_and_refs_p should not be called on them. */ ! FOR_EACH_FUNCTION (node) ! { ! node->used_as_abstract_origin = false; ! if (node->symbol.definition ! && !node->global.inlined_to ! && (!cgraph_can_remove_if_no_direct_calls_and_refs_p (node) ! /* Keep around virtual functions for possible devirtualization. */ ! || (before_inlining_p ! && DECL_VIRTUAL_P (node->symbol.decl)))) ! { ! gcc_assert (!node->global.inlined_to); ! pointer_set_insert (reachable, node); ! enqueue_node ((symtab_node)node, &first, reachable); ! } ! else ! gcc_assert (!node->symbol.aux); ! } /* Mark variables that are obviously needed. */ FOR_EACH_DEFINED_VARIABLE (vnode) *************** symtab_remove_unreachable_nodes (bool be *** 272,277 **** --- 275,287 ---- node->symbol.aux = (void *)2; else { + if (DECL_ABSTRACT_ORIGIN (node->symbol.decl)) + { + struct cgraph_node *origin_node + = cgraph_get_create_real_symbol_node (DECL_ABSTRACT_ORIGIN (node->symbol.decl)); + origin_node->used_as_abstract_origin = true; + enqueue_node ((symtab_node) origin_node, &first, reachable); + } /* If any symbol in a comdat group is reachable, force all other in the same comdat group to be also reachable. */ if (node->symbol.same_comdat_group) Index: tree-inline.c =================================================================== *** tree-inline.c (revision 201291) --- tree-inline.c (working copy) *************** tree_function_versioning (tree old_decl, *** 5085,5090 **** --- 5085,5092 ---- DECL_ARTIFICIAL (new_decl) = 1; DECL_ABSTRACT_ORIGIN (new_decl) = DECL_ORIGIN (old_decl); + if (DECL_ORIGIN (old_decl) == old_decl) + old_version_node->used_as_abstract_origin = true; DECL_FUNCTION_PERSONALITY (new_decl) = DECL_FUNCTION_PERSONALITY (old_decl); /* Prepare the data structures for the tree copy. */ *************** tree_function_versioning (tree old_decl, *** 5122,5127 **** --- 5124,5131 ---- old_entry_block = ENTRY_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (old_decl)); + DECL_RESULT (new_decl) = DECL_RESULT (old_decl); + DECL_ARGUMENTS (new_decl) = DECL_ARGUMENTS (old_decl); initialize_cfun (new_decl, old_decl, old_entry_block->count); DECL_STRUCT_FUNCTION (new_decl)->gimple_df->ipa_pta