Hi, this is first patch that makes function body management more consistent to what happens with variables. We now no longer incorrectly call cgraph_release_function_body for decls that are shared during LTO streaming and I fixed ipa.c to make proper reachability analysis of partial symtabs seen during ltrans.
Bootstrapped/regtested x86_64-linux, also tested on firefox LTO, comitted. Honza * lto-symtab.c (lto_cgraph_replace_node): Release function body. * cgraph.c (cgraph_remove_node): Do not release function body when in cgraph streaming. * ipa.c (process_references, symtab_remove_unreachable_nodes): Objects in other partitions are not considered reachable; fix handling of clones. Index: lto-symtab.c =================================================================== *** lto-symtab.c (revision 201225) --- lto-symtab.c (working copy) *************** lto_cgraph_replace_node (struct cgraph_n *** 80,85 **** --- 80,88 ---- /* Redirect incomming references. */ ipa_clone_referring ((symtab_node)prevailing_node, &node->symbol.ref_list); + if (node->symbol.decl != prevailing_node->symbol.decl) + cgraph_release_function_body (node); + /* Finally remove the replaced node. */ cgraph_remove_node (node); } Index: cgraph.c =================================================================== *** cgraph.c (revision 201225) --- cgraph.c (working copy) *************** cgraph_remove_node (struct cgraph_node * *** 1384,1398 **** itself is kept in the cgraph even after it is compiled. Check whether we are done with this body and reclaim it proactively if this is the case. */ ! n = cgraph_get_node (node->symbol.decl); ! if (!n ! || (!n->clones && !n->clone_of && !n->global.inlined_to ! && (cgraph_global_info_ready ! && (TREE_ASM_WRITTEN (n->symbol.decl) ! || DECL_EXTERNAL (n->symbol.decl) ! || !n->symbol.analyzed ! || n->symbol.in_other_partition)))) ! cgraph_release_function_body (node); node->symbol.decl = NULL; if (node->call_site_hash) --- 1384,1401 ---- itself is kept in the cgraph even after it is compiled. Check whether we are done with this body and reclaim it proactively if this is the case. */ ! if (cgraph_state != CGRAPH_LTO_STREAMING) ! { ! n = cgraph_get_node (node->symbol.decl); ! if (!n ! || (!n->clones && !n->clone_of && !n->global.inlined_to ! && (cgraph_global_info_ready ! && (TREE_ASM_WRITTEN (n->symbol.decl) ! || DECL_EXTERNAL (n->symbol.decl) ! || !n->symbol.analyzed ! || (!flag_wpa && n->symbol.in_other_partition))))) ! cgraph_release_function_body (node); ! } node->symbol.decl = NULL; if (node->call_site_hash) Index: ipa.c =================================================================== *** ipa.c (revision 201225) --- ipa.c (working copy) *************** process_references (struct ipa_ref_list *** 138,144 **** { symtab_node node = ref->referred; ! if (node->symbol.definition && ((!DECL_EXTERNAL (node->symbol.decl) || node->symbol.alias) || (before_inlining_p /* We use variable constructors during late complation for --- 138,144 ---- { symtab_node node = ref->referred; ! if (node->symbol.definition && !node->symbol.in_other_partition && ((!DECL_EXTERNAL (node->symbol.decl) || node->symbol.alias) || (before_inlining_p /* We use variable constructors during late complation for *************** symtab_remove_unreachable_nodes (bool be *** 236,241 **** --- 236,242 ---- 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 *************** symtab_remove_unreachable_nodes (bool be *** 250,256 **** /* Mark variables that are obviously needed. */ FOR_EACH_DEFINED_VARIABLE (vnode) ! if (!varpool_can_remove_if_no_refs (vnode)) { pointer_set_insert (reachable, vnode); enqueue_node ((symtab_node)vnode, &first, reachable); --- 251,258 ---- /* Mark variables that are obviously needed. */ FOR_EACH_DEFINED_VARIABLE (vnode) ! if (!varpool_can_remove_if_no_refs (vnode) ! && !vnode->symbol.in_other_partition) { pointer_set_insert (reachable, vnode); enqueue_node ((symtab_node)vnode, &first, reachable); *************** symtab_remove_unreachable_nodes (bool be *** 296,301 **** --- 298,304 ---- for (e = cnode->callees; e; e = e->next_callee) { if (e->callee->symbol.definition + && !e->callee->symbol.in_other_partition && (!e->inline_failed || !DECL_EXTERNAL (e->callee->symbol.decl) || e->callee->symbol.alias *************** symtab_remove_unreachable_nodes (bool be *** 306,327 **** /* When inline clone exists, mark body to be preserved so when removing offline copy of the function we don't kill it. */ ! if (!cnode->symbol.alias && cnode->global.inlined_to) pointer_set_insert (body_needed_for_clonning, cnode->symbol.decl); - } ! /* For non-inline clones, force their origins to the boundary and ensure ! that body is not removed. */ ! while (cnode->clone_of ! && !gimple_has_body_p (cnode->symbol.decl)) ! { ! bool noninline = cnode->clone_of->symbol.decl != cnode->symbol.decl; ! cnode = cnode->clone_of; ! if (noninline) ! { ! pointer_set_insert (body_needed_for_clonning, cnode->symbol.decl); ! enqueue_node ((symtab_node)cnode, &first, reachable); ! break; } } } --- 309,328 ---- /* When inline clone exists, mark body to be preserved so when removing offline copy of the function we don't kill it. */ ! if (cnode->global.inlined_to) pointer_set_insert (body_needed_for_clonning, cnode->symbol.decl); ! /* For non-inline clones, force their origins to the boundary and ensure ! that body is not removed. */ ! while (cnode->clone_of) ! { ! bool noninline = cnode->clone_of->symbol.decl != cnode->symbol.decl; ! cnode = cnode->clone_of; ! if (noninline) ! { ! pointer_set_insert (body_needed_for_clonning, cnode->symbol.decl); ! enqueue_node ((symtab_node)cnode, &first, reachable); ! } } } } *************** symtab_remove_unreachable_nodes (bool be *** 358,363 **** --- 359,366 ---- { if (!pointer_set_contains (body_needed_for_clonning, node->symbol.decl)) cgraph_release_function_body (node); + else if (!node->clone_of) + gcc_assert (DECL_RESULT (node->symbol.decl)); if (node->symbol.definition) { if (file) *************** symtab_remove_unreachable_nodes (bool be *** 366,371 **** --- 369,377 ---- changed = true; } } + else + gcc_assert (node->clone_of || !cgraph_function_with_gimple_body_p (node) + || DECL_RESULT (node->symbol.decl)); } /* Inline clones might be kept around so their materializing allows further