lto/124289 - Correctly handle toplevel asm with -flto-partition=cache

This patch adds create_asm_partitions to cache partitioning
to prevent issues with non-renameable symbols (while partition
joining) and static asm symbols (while partition splitting).

All other relevant partitionings use create_asm_partitions.
This was not used in cache partitioning, because toplevel asm
could be in principle special handled in cache partitioning
with marginally better results, but I never implemented it.

	lto/124289

gcc/lto/ChangeLog:

	* lto-partition.cc (enum map1to1_content): New.
	(map_1_to_1): Use map1to1_content.
	(lto_1_to_1_map): Likewise.
	(create_asm_partitions): Likewise.
	(lto_max_map): Likewise.
	(lto_cache_map): Use create_asm_partitions.

gcc/testsuite/ChangeLog:

	* gcc.dg/lto/toplevel-extended-asm-2_0.c: Add padding to asm label.
	* gcc.dg/lto/toplevel-extended-asm-2_1.c: Add padding to asm label.
This commit is contained in:
Michal Jires
2026-03-05 10:03:21 +01:00
parent da7f40611e
commit 5eed9f5ddd
3 changed files with 43 additions and 12 deletions

View File

@@ -366,10 +366,25 @@ node_into_file_partition (toplevel_node* node,
add_symbol_to_partition (partition, node);
}
/* map_1_to_1 is able to partition a subset of symbols/asm.
map1to1_forced covers symbols/asm that we are forced to partition
with 1_to_1 partitioning, otherwise they may become broken.
Other symbols may be partitioned arbitrarily. */
enum map1to1_content {
/* Forced symbols are always attempted. */
map1to1_forced_symbols = 0,
map1to1_asm = 1,
map1to1_other_symbols = 2,
map1to1_symbols = map1to1_forced_symbols | map1to1_other_symbols,
map1to1_forced = map1to1_asm | map1to1_forced_symbols,
map1to1_all = map1to1_symbols | map1to1_asm,
};
/* Group cgraph nodes by input files. Used for symbols that must remain
together. */
static void
map_1_to_1 (bool forced_symbols_only)
map_1_to_1 (map1to1_content content)
{
symtab_node *node;
hash_map<lto_file_decl_data *, ltrans_partition> pmap;
@@ -380,7 +395,7 @@ map_1_to_1 (bool forced_symbols_only)
|| symbol_partitioned_p (node))
continue;
if (forced_symbols_only && !node->must_remain_in_tu_name
if (!(content & map1to1_other_symbols) && !node->must_remain_in_tu_name
&& !node->must_remain_in_tu_body && !node->no_reorder)
continue;
@@ -388,8 +403,10 @@ map_1_to_1 (bool forced_symbols_only)
}
struct asm_node *anode;
for (anode = symtab->first_asm_symbol (); anode; anode = safe_as_a<asm_node*>(anode->next))
node_into_file_partition (anode, pmap);
if (content & map1to1_asm)
for (anode = symtab->first_asm_symbol (); anode;
anode = safe_as_a<asm_node*>(anode->next))
node_into_file_partition (anode, pmap);
/* Order partitions by order of symbols because they are linked into binary
that way. */
@@ -402,7 +419,7 @@ map_1_to_1 (bool forced_symbols_only)
void
lto_1_to_1_map (void)
{
map_1_to_1 (false);
map_1_to_1 (map1to1_all);
create_partition_if_empty ();
}
@@ -420,7 +437,7 @@ create_asm_partitions (int64_t target_size)
{
if (!symtab->first_asm_symbol ())
return;
map_1_to_1 (true);
map_1_to_1 (map1to1_forced);
size_t join_into = 0;
size_t join_from = 0;
@@ -486,7 +503,7 @@ lto_max_map (void)
ltrans_partition partition;
/* Needed for toplevel assembly. */
map_1_to_1 (true);
map_1_to_1 (map1to1_forced);
FOR_EACH_SYMBOL (node)
{
@@ -1111,15 +1128,29 @@ private:
void
lto_cache_map (int n_lto_partitions, int max_partition_size)
{
lto_1_to_1_map ();
cgraph_node *node;
int64_t total_size = 0;
FOR_EACH_DEFINED_FUNCTION (node)
if (node->get_partitioning_class () == SYMBOL_PARTITION && !node->alias)
total_size += ipa_size_summaries->get (node)->size;
/* Separates toplevel asm into its own partitions and handles name conflicts.
We could do this directly in cache partitioning without separating asm
into its own partitions in most cases. */
create_asm_partitions (total_size / n_lto_partitions);
unsigned asm_n = ltrans_partitions.length ();
map_1_to_1 (map1to1_symbols);
create_partition_if_empty ();
std::vector<ltrans_partition> partitions;
for (unsigned i = 0; i < ltrans_partitions.length (); ++i)
for (unsigned i = asm_n; i < ltrans_partitions.length (); ++i)
{
ltrans_partition part = ltrans_partitions[i];
partitions.push_back (part);
}
ltrans_partitions.truncate (0);
ltrans_partitions.truncate (asm_n);
partitioner_default partitioner = partitioner_default
(param_min_partition_size, max_partition_size);

View File

@@ -6,7 +6,7 @@ extern int use_statics ();
extern int asm_var;
static int a;
asm (".local %cc0\n %cc0:" :: ":"(&a));
asm (".local %cc0\n %cc0: .long 0" :: ":"(&a));
int main() {
return a + use_statics ();

View File

@@ -7,7 +7,7 @@ extern int asm_var;
asm("%cc0:" :: ":" (&asm_var));
static int a;
asm (".local %cc0\n %cc0:" :: ":"(&a));
asm (".local %cc0\n %cc0: .long 0" :: ":"(&a));
int use_statics () {
static_asm_fn ();