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

Reply via email to