https://gcc.gnu.org/g:cf4eb269051e7ddcc1ca805a83ec0e4a547c3d1a
commit r16-6692-gcf4eb269051e7ddcc1ca805a83ec0e4a547c3d1a Author: Michal Jires <[email protected]> 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))
