These optimizations may cross translation unit boundaries, so disable them when must_remain_in_tu is set.
gcc/ChangeLog: * cif-code.def (MUST_REMAIN_IN_TU): New. * ipa-icf.cc (sem_function::equals_wpa): False with must_remain_in_tu. (sem_variable::equals_wpa): Likewise. * ipa-inline-transform.cc (inline_call): Propagate must_remain_in_tu. * ipa-inline.cc (can_inline_edge_p): Disable with must_remain_in_tu. * varpool.cc (varpool_node::ctor_useable_for_folding_p): Likewise. --- gcc/cif-code.def | 5 +++++ gcc/ipa-icf.cc | 6 ++++++ gcc/ipa-inline-transform.cc | 6 ++++++ gcc/ipa-inline.cc | 6 ++++++ gcc/varpool.cc | 4 ++++ 5 files changed, 27 insertions(+) diff --git a/gcc/cif-code.def b/gcc/cif-code.def index 8735eafebc5..ea91a68b5d1 100644 --- a/gcc/cif-code.def +++ b/gcc/cif-code.def @@ -139,6 +139,11 @@ DEFCIFCODE(EXTERN_LIVE_ONLY_STATIC, CIF_FINAL_ERROR, N_("function has external linkage when the user requests only" " inlining static for live patching")) +/* We can't inline because callee must remain in translation unit + and caller is in another. */ +DEFCIFCODE(MUST_REMAIN_IN_TU, CIF_FINAL_ERROR, + N_("callee must remain in translation unit")) + /* We proved that the call is unreachable. */ DEFCIFCODE(UNREACHABLE, CIF_FINAL_ERROR, N_("unreachable")) diff --git a/gcc/ipa-icf.cc b/gcc/ipa-icf.cc index c7596f9ff1c..d420b173af4 100644 --- a/gcc/ipa-icf.cc +++ b/gcc/ipa-icf.cc @@ -534,6 +534,9 @@ sem_function::equals_wpa (sem_item *item, m_compared_func = static_cast<sem_function *> (item); + if (cnode->must_remain_in_tu || cnode2->must_remain_in_tu) + return return_false_with_msg ("must_remain_in_tu"); + if (cnode->thunk != cnode2->thunk) return return_false_with_msg ("thunk mismatch"); if (cnode->former_thunk_p () != cnode2->former_thunk_p ()) @@ -1651,6 +1654,9 @@ sem_variable::equals_wpa (sem_item *item, { gcc_assert (item->type == VAR); + if (node->must_remain_in_tu || item->node->must_remain_in_tu) + return return_false_with_msg ("must_remain_in_tu"); + if (node->num_references () != item->node->num_references ()) return return_false_with_msg ("different number of references"); diff --git a/gcc/ipa-inline-transform.cc b/gcc/ipa-inline-transform.cc index 9d759d218b5..2ed9258e74a 100644 --- a/gcc/ipa-inline-transform.cc +++ b/gcc/ipa-inline-transform.cc @@ -495,6 +495,12 @@ inline_call (struct cgraph_edge *e, bool update_original, } } + if (e->callee->must_remain_in_tu) + { + gcc_assert (e->callee->lto_file_data == e->caller->lto_file_data); + e->caller->must_remain_in_tu = true; + } + clone_inlined_nodes (e, true, update_original, overall_size); gcc_assert (curr->callee->inlined_to == to); diff --git a/gcc/ipa-inline.cc b/gcc/ipa-inline.cc index 0cf97a80687..04ceb2206f5 100644 --- a/gcc/ipa-inline.cc +++ b/gcc/ipa-inline.cc @@ -452,6 +452,12 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, e->inline_failed = CIF_UNSPECIFIED; inlinable = false; } + if (inlinable && callee->must_remain_in_tu + && caller->lto_file_data != callee->lto_file_data) + { + e->inline_failed = CIF_MUST_REMAIN_IN_TU; + inlinable = false; + } if (!inlinable && report) report_inline_failed_reason (e); return inlinable; diff --git a/gcc/varpool.cc b/gcc/varpool.cc index 8dc5f986294..4bc6e6840d1 100644 --- a/gcc/varpool.cc +++ b/gcc/varpool.cc @@ -339,6 +339,10 @@ varpool_node::ctor_useable_for_folding_p (void) && !real_node->lto_file_data) return false; + /* Folding may cross TU boundaries. */ + if (must_remain_in_tu) + return false; + /* Vtables are defined by their types and must match no matter of interposition rules. */ if (DECL_VIRTUAL_P (decl)) -- 2.50.0