Hi, this patch fixes problem with partitioning WRT named labels. This problem reproduces with linux kernel LTO and also on firefox with -fno-toplevel-reorder at least.
Bootstrapped/regtested x86_64-linux and tested it fixes the problem on Firefx, intend to commit it tomorrow after some more testing on chromium The patch may need a bit more tweaking WRT nested functions contains nonlocal adresses taken, but that is even more exotic than the problem I am trying to solve so I think it can wait for next stage1. This patch should be backportable to earlier releases after reversing the C++ APi changes. Honza PR lto/50676 * symtab.c (symtab_node::get_partitioning_class): Local static taking named label inherits partitioning property of the function it belong to. * lto-cgraph.c (lto_output_varpool_node, input_varpool_node): Stream contains_named_label. * tree.c (decl_address_ip_invariant_p): LABEL_DECL is not IP invariant. * cgraph.h (varpool_node): Add contains_named_label. * cgraphbuild.c (record_reference): Record contains_named_label. * lto-partition.c (add_references_to_partition, add_symbol_to_partition_1): Local static var should stay in same partition as its containing function when it reffer to named label. (add_sorted_nodes): Skip static var referring named label. (lto_balanced_map): Likewise. * varpool.c (varpool_node::dump): Dump contains_named_label. * ipa.c (symbol_table::remove_unreachable_nodes): Variable referring named label keeps its function alive. * gcc.dg/lto/named-label.c: New testcase. Index: symtab.c =================================================================== --- symtab.c (revision 221757) +++ symtab.c (working copy) @@ -1682,6 +1682,11 @@ symtab_node::get_partitioning_class (voi if (varpool_node *vnode = dyn_cast <varpool_node *> (this)) { + /* Static variables referring named label are always handled the same way + as the function they belong to. */ + if (vnode->contains_named_label) + return cgraph_node::get (decl_function_context (decl)) + ->get_partitioning_class (); if (alias && definition && !ultimate_alias_target ()->definition) return SYMBOL_EXTERNAL; /* Constant pool references use local symbol names that can not Index: lto-cgraph.c =================================================================== --- lto-cgraph.c (revision 221757) +++ lto-cgraph.c (working copy) @@ -662,6 +663,7 @@ lto_output_varpool_node (struct lto_simp bp_pack_value (&bp, node->tls_model, 3); bp_pack_value (&bp, node->used_by_single_function, 1); bp_pack_value (&bp, node->need_bounds_init, 1); + bp_pack_value (&bp, node->contains_named_label, 1); streamer_write_bitpack (&bp); group = node->get_comdat_group (); @@ -1413,6 +1416,7 @@ input_varpool_node (struct lto_file_decl node->tls_model = (enum tls_model)bp_unpack_value (&bp, 3); node->used_by_single_function = (enum tls_model)bp_unpack_value (&bp, 1); node->need_bounds_init = bp_unpack_value (&bp, 1); + node->contains_named_label = bp_unpack_value (&bp, 1); group = read_identifier (ib); if (group) { Index: tree.c =================================================================== --- tree.c (revision 221757) +++ tree.c (working copy) @@ -3149,7 +3149,12 @@ decl_address_ip_invariant_p (const_tree switch (TREE_CODE (op)) { + /* Theoretically label decls can be considered IP invariants, but until + we are able to handle them as regular symbols (i.e. output with + non-local visibility), we really want them to be contained in a function + they belong to. */ case LABEL_DECL: + return false; case FUNCTION_DECL: case STRING_CST: return true; Index: cgraph.h =================================================================== --- cgraph.h (revision 221757) +++ cgraph.h (working copy) @@ -1778,6 +1780,9 @@ public: if we did not do any inter-procedural code movement. */ unsigned used_by_single_function : 1; + /* Set if te variable is contains a named label. */ + unsigned contains_named_label : 1; + private: /* Assemble thunks and aliases associated to varpool node. */ void assemble_aliases (void); Index: cgraphbuild.c =================================================================== --- cgraphbuild.c (revision 221757) +++ cgraphbuild.c (working copy) @@ -112,6 +112,8 @@ record_reference (tree *tp, int *walk_su varpool_node *vnode = varpool_node::get_create (decl); ctx->varpool_node->create_reference (vnode, IPA_REF_ADDR); } + if (TREE_CODE (decl) == LABEL_DECL) + ctx->varpool_node->contains_named_label = true; *walk_subtrees = 0; break; Index: lto/lto-partition.c =================================================================== --- lto/lto-partition.c (revision 221757) +++ lto/lto-partition.c (working copy) @@ -113,6 +113,14 @@ add_references_to_partition (ltrans_part for (i = 0; node->iterate_reference (i, ref); i++) if (ref->referred->get_partitioning_class () == SYMBOL_DUPLICATE) add_symbol_to_partition (part, ref->referred); + /* A static variable referring to named labels must go to the same + partition as a function it belongs to. */ + else if (is_a <varpool_node *> (ref->referred) + && (dyn_cast <varpool_node *> (ref->referred) + ->contains_named_label) + && node->decl == decl_function_context (ref->referred->decl) + && !lto_symtab_encoder_in_partition_p (part->encoder, ref->referred)) + add_symbol_to_partition (part, ref->referred); /* References to a readonly variable may be constant foled into its value. Recursively look into the initializers of the constant variable and add references, too. */ @@ -193,6 +201,14 @@ add_symbol_to_partition_1 (ltrans_partit add_symbol_to_partition_1 (part, cnode->instrumented_version); } + /* Variables referring named labels must always go to the same section + as the function they belong to. */ + if (is_a <varpool_node *> (node) + && dyn_cast <varpool_node *> (node)->contains_named_label) + add_symbol_to_partition_1 (part, + cgraph_node::get + (decl_function_context (node->decl))); + add_references_to_partition (part, node); /* Add all aliases associated with the symbol. */ @@ -409,7 +425,12 @@ add_sorted_nodes (vec<symtab_node *> &ne next_nodes.qsort (varpool_node_cmp); FOR_EACH_VEC_ELT (next_nodes, i, node) - if (!symbol_partitioned_p (node)) + if (!symbol_partitioned_p (node) + /* Local statics containing named labels always go after their + functions. Do not partition on them and wait for them to be + dragged in, so we do not force reordering of the functions. */ + && (!is_a <varpool_node *> (node) + || !dyn_cast <varpool_node *> (node)->contains_named_label)) add_symbol_to_partition (partition, node); } @@ -636,6 +657,7 @@ lto_balanced_map (int n_lto_partitions) continue; if (!symbol_partitioned_p (vnode) && flag_toplevel_reorder && !vnode->no_reorder + && !vnode->contains_named_label && vnode->get_partitioning_class () == SYMBOL_PARTITION) add_symbol_to_partition (partition, vnode); index = lto_symtab_encoder_lookup (partition->encoder, @@ -674,6 +696,7 @@ lto_balanced_map (int n_lto_partitions) if (!symbol_partitioned_p (vnode) && flag_toplevel_reorder && !vnode->no_reorder && !vnode->can_remove_if_no_refs_p () + && !vnode->contains_named_label && vnode->get_partitioning_class () == SYMBOL_PARTITION) add_symbol_to_partition (partition, vnode); index = lto_symtab_encoder_lookup (partition->encoder, Index: varpool.c =================================================================== --- varpool.c (revision 221757) +++ varpool.c (working copy) @@ -256,6 +256,8 @@ varpool_node::dump (FILE *f) fprintf (f, " const-value-known"); if (writeonly) fprintf (f, " write-only"); + if (contains_named_label) + fprintf (f, " contains-named-label"); if (tls_model) fprintf (f, " tls-%s", tls_model_names [tls_model]); fprintf (f, "\n"); Index: ipa.c =================================================================== --- ipa.c (revision 221757) +++ ipa.c (working copy) @@ -406,6 +406,18 @@ symbol_table::remove_unreachable_nodes ( n->used_as_abstract_origin = true; } } + + /* Static variables referring local label needs the containing + function to be output. */ + if (is_a <varpool_node *> (node) + && dyn_cast <varpool_node *> (node)->contains_named_label) + { + cgraph_node *cn + = cgraph_node::get (decl_function_context (node->decl)); + if (!reachable.add (cn)) + enqueue_node (cn, &first, &reachable); + } + /* If any symbol in a comdat group is reachable, force all externally visible symbols in the same comdat group to be reachable as well. Comdat-local symbols Index: testsuite/gcc.dg/lto/named-label.c =================================================================== --- testsuite/gcc.dg/lto/named-label.c (revision 0) +++ testsuite/gcc.dg/lto/named-label.c (revision 0) @@ -0,0 +1,29 @@ +/* { dg-lto-do link } */ +/* { dg-lto-options { { -fPIC -flto -flto-partition=max } } } */ +void *p0,*p1; +void test (void **p) +{ + if (p[0]==p[1]) + __builtin_abort (); + p0=p[0]; + p1=p[1]; +} +void test2 (void **p) +{ + if (p[0]!=p0|| p[1] !=p1) + __builtin_abort (); +} +void ** t() +{ + static void * labelptr[2]={&&label, &&label2}; +label: + test (labelptr); +label2: + return labelptr; +} +int +main() +{ + void **labelptr = t(); + test2 (labelptr); +}