[gcc r16-6692] lto: Add must_remain_in_tu flags to symtab_node
Michal Jires
mjires@gcc.gnu.org
Sun Jan 11 22:09:58 GMT 2026
https://gcc.gnu.org/g:cf4eb269051e7ddcc1ca805a83ec0e4a547c3d1a
commit r16-6692-gcf4eb269051e7ddcc1ca805a83ec0e4a547c3d1a
Author: Michal Jires <mjires@suse.cz>
Date: Thu Dec 18 14:58:15 2025 +0100
lto: Add must_remain_in_tu flags to symtab_node
With toplevel assembly we are sometimes not allowed to globalize static
symbols. So such symbols cannot be in more than one partition.
must_remain_in_tu_* guarantee that such symbols or references to them do
not escape the original translation unit. Thus 1to1 partitioning is always
valid.
gcc/ChangeLog:
* cgraph.h: Add must_remain_in_tu_*.
* cgraphclones.cc (cgraph_node::create_clone): Propagate
must_remain_in_tu_body.
* cif-code.def (MUST_REMAIN_IN_TU): New.
* ipa-icf.cc (sem_function::equals_wpa): Check
must_remain_in_tu_*
(sem_variable::equals_wpa): Likewise.
* ipa-inline-transform.cc (inline_call): Propagate
must_remain_in_tu_body.
* ipa-inline.cc (can_inline_edge_p): Check
must_remain_in_tu_body.
* lto-cgraph.cc (lto_output_node): Output must_remain_in_tu_*
(lto_output_varpool_node): Likewise.
(input_overwrite_node): Input must_remain_in_tu_*.
(input_varpool_node): Likewise.
* tree.cc (decl_address_ip_invariant_p): Check
must_remain_in_tu_name.
* varpool.cc (varpool_node::ctor_useable_for_folding_p): Check
must_remain_in_tu_body.
gcc/lto/ChangeLog:
* lto-symtab.cc (lto_cgraph_replace_node): Propagate
must_remain_in_tu_*.
(lto_varpool_replace_node): Likewise.
Diff:
---
gcc/cgraph.h | 7 +++++++
gcc/cgraphclones.cc | 1 +
gcc/cif-code.def | 5 +++++
gcc/ipa-icf.cc | 8 ++++++++
gcc/ipa-inline-transform.cc | 6 ++++++
gcc/ipa-inline.cc | 6 ++++++
gcc/lto-cgraph.cc | 8 ++++++++
gcc/lto/lto-symtab.cc | 4 ++++
gcc/tree.cc | 14 +++++++++++++-
gcc/varpool.cc | 4 ++++
10 files changed, 62 insertions(+), 1 deletion(-)
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index c36020d06168..39209b539577 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -146,6 +146,7 @@ public:
refuse_visibility_changes (false), externally_visible (false),
no_reorder (false), force_output (false), forced_by_abi (false),
ref_by_asm (false),
+ must_remain_in_tu_name (false), must_remain_in_tu_body (false),
unique_name (false), implicit_section (false), body_removed (false),
semantic_interposition (flag_semantic_interposition),
used_from_other_partition (false), in_other_partition (false),
@@ -598,6 +599,12 @@ public:
Static symbol may be renamed. Global symbol should not be renamed.
Unlike force_output, can be on declarations. */
unsigned ref_by_asm : 1;
+ /* Set when asm_name must remain in TU partition.
+ Used to guarantee not renaming of static ref_by_asm symbols. */
+ unsigned must_remain_in_tu_name : 1;
+ /* Set when body (or any references) must remain in TU partition.
+ Used on symbols referring/calling must_remain_in_tu_name. */
+ unsigned must_remain_in_tu_body : 1;
/* True when the name is known to be unique and thus it does not need mangling. */
unsigned unique_name : 1;
/* Specify whether the section was set by user or by
diff --git a/gcc/cgraphclones.cc b/gcc/cgraphclones.cc
index 3ea23fd7668e..180ef4e52c87 100644
--- a/gcc/cgraphclones.cc
+++ b/gcc/cgraphclones.cc
@@ -457,6 +457,7 @@ cgraph_node::create_clone (tree new_decl, profile_count prof_count,
new_node->unit_id = unit_id;
new_node->merged_comdat = merged_comdat;
new_node->merged_extern_inline = merged_extern_inline;
+ new_node->must_remain_in_tu_body = must_remain_in_tu_body;
clone_info *info = clone_info::get (this);
if (param_adjustments)
diff --git a/gcc/cif-code.def b/gcc/cif-code.def
index a8347bb8bfb0..071fd936622c 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 099ab75457dc..40e9614c7364 100644
--- a/gcc/ipa-icf.cc
+++ b/gcc/ipa-icf.cc
@@ -534,6 +534,10 @@ sem_function::equals_wpa (sem_item *item,
m_compared_func = static_cast<sem_function *> (item);
+ if (cnode->must_remain_in_tu_name || cnode2->must_remain_in_tu_name
+ || cnode->must_remain_in_tu_body || cnode2->must_remain_in_tu_body)
+ 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 +1655,10 @@ sem_variable::equals_wpa (sem_item *item,
{
gcc_assert (item->type == VAR);
+ if (node->must_remain_in_tu_name || item->node->must_remain_in_tu_name
+ || node->must_remain_in_tu_body || item->node->must_remain_in_tu_body)
+ 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 895b6e785ac3..c4df9d91425b 100644
--- a/gcc/ipa-inline-transform.cc
+++ b/gcc/ipa-inline-transform.cc
@@ -558,6 +558,12 @@ inline_call (struct cgraph_edge *e, bool update_original,
}
}
+ if (callee->must_remain_in_tu_body)
+ {
+ gcc_assert (callee->lto_file_data == to->lto_file_data);
+ to->must_remain_in_tu_body = true;
+ }
+
clone_inlined_nodes (e, true, keep_offline_copy,
update_original, overall_size);
diff --git a/gcc/ipa-inline.cc b/gcc/ipa-inline.cc
index 8b0e9b194fa5..24d8974d5ca4 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_body
+ && 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/lto-cgraph.cc b/gcc/lto-cgraph.cc
index 71fbf80c54b2..635ed1af76b3 100644
--- a/gcc/lto-cgraph.cc
+++ b/gcc/lto-cgraph.cc
@@ -534,6 +534,8 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
bp_pack_value (&bp, node->force_output, 1);
bp_pack_value (&bp, node->forced_by_abi, 1);
bp_pack_value (&bp, node->ref_by_asm, 1);
+ bp_pack_value (&bp, node->must_remain_in_tu_name, 1);
+ bp_pack_value (&bp, node->must_remain_in_tu_body, 1);
bp_pack_value (&bp, node->unique_name, 1);
bp_pack_value (&bp, node->body_removed, 1);
bp_pack_value (&bp, node->semantic_interposition, 1);
@@ -622,6 +624,8 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, varpool_node *node,
bp_pack_value (&bp, node->force_output, 1);
bp_pack_value (&bp, node->forced_by_abi, 1);
bp_pack_value (&bp, node->ref_by_asm, 1);
+ bp_pack_value (&bp, node->must_remain_in_tu_name, 1);
+ bp_pack_value (&bp, node->must_remain_in_tu_body, 1);
bp_pack_value (&bp, node->unique_name, 1);
bp_pack_value (&bp,
node->body_removed
@@ -1255,6 +1259,8 @@ input_overwrite_node (struct lto_file_decl_data *file_data,
node->force_output = bp_unpack_value (bp, 1);
node->forced_by_abi = bp_unpack_value (bp, 1);
node->ref_by_asm = bp_unpack_value (bp, 1);
+ node->must_remain_in_tu_name = bp_unpack_value (bp, 1);
+ node->must_remain_in_tu_body = bp_unpack_value (bp, 1);
node->unique_name = bp_unpack_value (bp, 1);
node->body_removed = bp_unpack_value (bp, 1);
node->semantic_interposition = bp_unpack_value (bp, 1);
@@ -1462,6 +1468,8 @@ input_varpool_node (struct lto_file_decl_data *file_data,
node->force_output = bp_unpack_value (&bp, 1);
node->forced_by_abi = bp_unpack_value (&bp, 1);
node->ref_by_asm = bp_unpack_value (&bp, 1);
+ node->must_remain_in_tu_name = bp_unpack_value (&bp, 1);
+ node->must_remain_in_tu_body = bp_unpack_value (&bp, 1);
node->unique_name = bp_unpack_value (&bp, 1);
node->body_removed = bp_unpack_value (&bp, 1);
node->semantic_interposition = bp_unpack_value (&bp, 1);
diff --git a/gcc/lto/lto-symtab.cc b/gcc/lto/lto-symtab.cc
index 6bbc30c2ebca..b8759a7fef55 100644
--- a/gcc/lto/lto-symtab.cc
+++ b/gcc/lto/lto-symtab.cc
@@ -62,6 +62,8 @@ lto_cgraph_replace_node (struct cgraph_node *node,
if (node->forced_by_abi)
prevailing_node->forced_by_abi = true;
prevailing_node->ref_by_asm |= node->ref_by_asm;
+ prevailing_node->must_remain_in_tu_name |= node->must_remain_in_tu_name;
+ prevailing_node->must_remain_in_tu_body |= node->must_remain_in_tu_body;
if (node->address_taken)
{
@@ -124,6 +126,8 @@ lto_varpool_replace_node (varpool_node *vnode,
if (vnode->forced_by_abi)
prevailing_node->forced_by_abi = true;
prevailing_node->ref_by_asm |= vnode->ref_by_asm;
+ prevailing_node->must_remain_in_tu_name |= vnode->must_remain_in_tu_name;
+ prevailing_node->must_remain_in_tu_body |= vnode->must_remain_in_tu_body;
/* Be sure we can garbage collect the initializer. */
if (DECL_INITIAL (vnode->decl)
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 610a3fc82ab8..faa0aa9f1af8 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -4000,14 +4000,26 @@ decl_address_ip_invariant_p (const_tree op)
/* The conditions below are slightly less strict than the one in
staticp. */
+ symtab_node* node;
switch (TREE_CODE (op))
{
case LABEL_DECL:
- case FUNCTION_DECL:
case STRING_CST:
return true;
+ case FUNCTION_DECL:
+ /* Disable const propagation of symbols defined in assembly. */
+ node = symtab_node::get (op);
+ return !node || !node->must_remain_in_tu_name;
+
case VAR_DECL:
+ if (TREE_STATIC (op) || DECL_EXTERNAL (op))
+ {
+ /* Disable const propagation of symbols defined in assembly. */
+ node = symtab_node::get (op);
+ if (node && node->must_remain_in_tu_name)
+ return false;
+ }
if (((TREE_STATIC (op) || DECL_EXTERNAL (op))
&& !DECL_DLLIMPORT_P (op))
|| DECL_THREAD_LOCAL_P (op))
diff --git a/gcc/varpool.cc b/gcc/varpool.cc
index b1ec157733ab..1025535ec5aa 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_body)
+ return false;
+
/* Vtables are defined by their types and must match no matter of interposition
rules. */
if (DECL_VIRTUAL_P (decl))
More information about the Gcc-cvs
mailing list