Hi, this patch fixes undefined symbol seen while compiling LLVM with LTO. The bug here is that lto-cgraph and lto-partition both contain knowledge about what symbols gets partitioned and what gets duplicated to each partition that uses them. This has got out of sync causing lto-cgraph to not set in_other_partition for symbols it believed to be duplicated while they was really partitioned.
This patch unifies the logic. Bootstrapped/regtsted x86_64-linux, comitted. PR ipa/59469 * lto-cgraph.c (lto_output_node): Use symtab_get_symbol_partitioning_class. (lto_output_varpool_node): likewise. (symtab_get_symbol_partitioning_class): Move here from lto/lto-partition.c * cgraph.h (symbol_partitioning_class): Likewise. (symtab_get_symbol_partitioning_class): Declare. * lto-partition.c (symbol_class): Move to cgraph.h (get_symbol_class): Move to symtab.c (add_references_to_partition, add_symbol_to_partition_1, lto_max_map, lto_1_to_1_map, lto_balanced_map, lto_promote_cross_file_statics): Update. Index: lto-cgraph.c =================================================================== --- lto-cgraph.c (revision 207588) +++ lto-cgraph.c (working copy) @@ -417,7 +417,8 @@ lto_output_node (struct lto_simple_outpu Cherry-picked nodes: These are nodes we pulled from other translation units into SET during IPA-inlining. We make them as local static nodes to prevent clashes with other local statics. */ - if (boundary_p && node->analyzed && !DECL_EXTERNAL (node->decl)) + if (boundary_p && node->analyzed + && symtab_get_symbol_partitioning_class (node) == SYMBOL_PARTITION) { /* Inline clones can not be part of boundary. gcc_assert (!node->global.inlined_to); @@ -501,8 +502,7 @@ lto_output_node (struct lto_simple_outpu bp_pack_value (&bp, node->unique_name, 1); bp_pack_value (&bp, node->address_taken, 1); bp_pack_value (&bp, tag == LTO_symtab_analyzed_node - && !DECL_EXTERNAL (node->decl) - && !DECL_COMDAT (node->decl) + && symtab_get_symbol_partitioning_class (node) == SYMBOL_PARTITION && (reachable_from_other_partition_p (node, encoder) || referenced_from_other_partition_p (&node->ref_list, encoder)), 1); @@ -569,9 +569,7 @@ lto_output_varpool_node (struct lto_simp /* Constant pool initializers can be de-unified into individual ltrans units. FIXME: Alternatively at -Os we may want to avoid generating for them the local labels and share them across LTRANS partitions. */ - if (DECL_IN_CONSTANT_POOL (node->decl) - && !DECL_EXTERNAL (node->decl) - && !DECL_COMDAT (node->decl)) + if (symtab_get_symbol_partitioning_class (node) != SYMBOL_PARTITION) { bp_pack_value (&bp, 0, 1); /* used_from_other_parition. */ bp_pack_value (&bp, 0, 1); /* in_other_partition. */ Index: symtab.c =================================================================== --- symtab.c (revision 207588) +++ symtab.c (working copy) @@ -1267,4 +1267,55 @@ symtab_semantically_equivalent_p (symtab bb = b; return bb == ba; } + +/* Classify symbol NODE for partitioning. */ + +enum symbol_partitioning_class +symtab_get_symbol_partitioning_class (symtab_node *node) +{ + /* Inline clones are always duplicated. + This include external delcarations. */ + cgraph_node *cnode = dyn_cast <cgraph_node> (node); + + if (DECL_ABSTRACT (node->decl)) + return SYMBOL_EXTERNAL; + + if (cnode && cnode->global.inlined_to) + return SYMBOL_DUPLICATE; + + /* Weakref aliases are always duplicated. */ + if (node->weakref) + return SYMBOL_DUPLICATE; + + /* External declarations are external. */ + if (DECL_EXTERNAL (node->decl)) + return SYMBOL_EXTERNAL; + + if (varpool_node *vnode = dyn_cast <varpool_node> (node)) + { + /* Constant pool references use local symbol names that can not + be promoted global. We should never put into a constant pool + objects that can not be duplicated across partitions. */ + if (DECL_IN_CONSTANT_POOL (node->decl)) + return SYMBOL_DUPLICATE; + gcc_checking_assert (vnode->definition); + } + /* Functions that are cloned may stay in callgraph even if they are unused. + Handle them as external; compute_ltrans_boundary take care to make + proper things to happen (i.e. to make them appear in the boundary but + with body streamed, so clone can me materialized). */ + else if (!cgraph (node)->definition) + return SYMBOL_EXTERNAL; + + /* Linker discardable symbols are duplicated to every use unless they are + keyed. + Keyed symbols or those. */ + if (DECL_ONE_ONLY (node->decl) + && !node->force_output + && !node->forced_by_abi + && !symtab_used_from_object_file_p (node)) + return SYMBOL_DUPLICATE; + + return SYMBOL_PARTITION; +} #include "gt-symtab.h" Index: cgraph.h =================================================================== --- cgraph.h (revision 207588) +++ cgraph.h (working copy) @@ -704,6 +704,20 @@ extern GTY(()) struct asm_node *asm_node extern GTY(()) int symtab_order; extern bool cpp_implicit_aliases_done; +/* Classifcation of symbols WRT partitioning. */ +enum symbol_partitioning_class +{ + /* External declarations are ignored by partitioning algorithms and they are + added into the boundary later via compute_ltrans_boundary. */ + SYMBOL_EXTERNAL, + /* Partitioned symbols are pur into one of partitions. */ + SYMBOL_PARTITION, + /* Duplicated symbols (such as comdat or constant pool references) are + copied into every node needing them via add_symbol_to_partition. */ + SYMBOL_DUPLICATE +}; + + /* In symtab.c */ void symtab_register_node (symtab_node *); void symtab_unregister_node (symtab_node *); @@ -734,6 +748,7 @@ bool symtab_for_node_and_aliases (symtab symtab_node *symtab_nonoverwritable_alias (symtab_node *); enum availability symtab_node_availability (symtab_node *); bool symtab_semantically_equivalent_p (symtab_node *, symtab_node *); +enum symbol_partitioning_class symtab_get_symbol_partitioning_class (symtab_node *); /* In cgraph.c */ void dump_cgraph (FILE *); Index: lto/lto-partition.c =================================================================== --- lto/lto-partition.c (revision 207588) +++ lto/lto-partition.c (working copy) @@ -38,73 +38,10 @@ along with GCC; see the file COPYING3. #include "ipa-utils.h" #include "lto-partition.h" -/* Classifcation of symbols into classes WRT partitioning. */ -enum symbol_class -{ - /* External declarations are ignored by partitioning algorithms and they are - added into the boundary later via compute_ltrans_boundary. */ - SYMBOL_EXTERNAL, - /* Partitioned symbols are pur into one of partitions. */ - SYMBOL_PARTITION, - /* Duplicated symbols (such as comdat or constant pool references) are - copied into every node needing them via add_symbol_to_partition. */ - SYMBOL_DUPLICATE -}; - vec<ltrans_partition> ltrans_partitions; static void add_symbol_to_partition (ltrans_partition part, symtab_node *node); -/* Classify symbol NODE. */ - -enum symbol_class -get_symbol_class (symtab_node *node) -{ - /* Inline clones are always duplicated. - This include external delcarations. */ - cgraph_node *cnode = dyn_cast <cgraph_node> (node); - - if (DECL_ABSTRACT (node->decl)) - return SYMBOL_EXTERNAL; - - if (cnode && cnode->global.inlined_to) - return SYMBOL_DUPLICATE; - - /* Weakref aliases are always duplicated. */ - if (node->weakref) - return SYMBOL_DUPLICATE; - - /* External declarations are external. */ - if (DECL_EXTERNAL (node->decl)) - return SYMBOL_EXTERNAL; - - if (varpool_node *vnode = dyn_cast <varpool_node> (node)) - { - /* Constant pool references use local symbol names that can not - be promoted global. We should never put into a constant pool - objects that can not be duplicated across partitions. */ - if (DECL_IN_CONSTANT_POOL (node->decl)) - return SYMBOL_DUPLICATE; - gcc_checking_assert (vnode->definition); - } - /* Functions that are cloned may stay in callgraph even if they are unused. - Handle them as external; compute_ltrans_boundary take care to make - proper things to happen (i.e. to make them appear in the boundary but - with body streamed, so clone can me materialized). */ - else if (!cgraph (node)->definition) - return SYMBOL_EXTERNAL; - - /* Linker discardable symbols are duplicated to every use unless they are - keyed. - Keyed symbols or those. */ - if (DECL_ONE_ONLY (node->decl) - && !node->force_output - && !node->forced_by_abi - && !symtab_used_from_object_file_p (node)) - return SYMBOL_DUPLICATE; - - return SYMBOL_PARTITION; -} /* Create new partition with name NAME. */ @@ -153,7 +90,7 @@ add_references_to_partition (ltrans_part /* Add all duplicated references to the partition. */ for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++) - if (get_symbol_class (ref->referred) == SYMBOL_DUPLICATE) + if (symtab_get_symbol_partitioning_class (ref->referred) == SYMBOL_DUPLICATE) 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 @@ -175,7 +112,7 @@ add_references_to_partition (ltrans_part static bool add_symbol_to_partition_1 (ltrans_partition part, symtab_node *node) { - enum symbol_class c = get_symbol_class (node); + enum symbol_partitioning_class c = symtab_get_symbol_partitioning_class (node); int i; struct ipa_ref *ref; symtab_node *node1; @@ -218,7 +155,7 @@ add_symbol_to_partition_1 (ltrans_partit for (e = cnode->callees; e; e = e->next_callee) if (!e->inline_failed) add_symbol_to_partition_1 (part, e->callee); - else if (get_symbol_class (e->callee) == SYMBOL_DUPLICATE) + else if (symtab_get_symbol_partitioning_class (e->callee) == SYMBOL_DUPLICATE) add_symbol_to_partition (part, e->callee); /* Add all thunks associated with the function. */ @@ -238,10 +175,11 @@ add_symbol_to_partition_1 (ltrans_partit if (node->same_comdat_group) for (node1 = node->same_comdat_group; node1 != node; node1 = node1->same_comdat_group) - { - bool added = add_symbol_to_partition_1 (part, node1); - gcc_assert (added); - } + if (!node->alias) + { + bool added = add_symbol_to_partition_1 (part, node1); + gcc_assert (added); + } return true; } @@ -276,7 +214,7 @@ add_symbol_to_partition (ltrans_partitio symtab_node *node1; /* Verify that we do not try to duplicate something that can not be. */ - gcc_checking_assert (get_symbol_class (node) == SYMBOL_DUPLICATE + gcc_checking_assert (symtab_get_symbol_partitioning_class (node) == SYMBOL_DUPLICATE || !symbol_partitioned_p (node)); while ((node1 = contained_in_symbol (node)) != node) @@ -289,7 +227,7 @@ add_symbol_to_partition (ltrans_partitio Be lax about comdats; they may or may not be duplicated and we may end up in need to duplicate keyed comdat because it has unkeyed alias. */ - gcc_assert (get_symbol_class (node) == SYMBOL_DUPLICATE + gcc_assert (symtab_get_symbol_partitioning_class (node) == SYMBOL_DUPLICATE || DECL_COMDAT (node->decl) || !symbol_partitioned_p (node)); @@ -336,7 +274,7 @@ lto_1_to_1_map (void) FOR_EACH_SYMBOL (node) { - if (get_symbol_class (node) != SYMBOL_PARTITION + if (symtab_get_symbol_partitioning_class (node) != SYMBOL_PARTITION || symbol_partitioned_p (node)) continue; @@ -388,7 +326,7 @@ lto_max_map (void) FOR_EACH_SYMBOL (node) { - if (get_symbol_class (node) != SYMBOL_PARTITION + if (symtab_get_symbol_partitioning_class (node) != SYMBOL_PARTITION || symbol_partitioned_p (node)) continue; partition = new_partition (node->asm_name ()); @@ -498,7 +436,7 @@ lto_balanced_map (void) gcc_assert (!vnode->aux); FOR_EACH_DEFINED_FUNCTION (node) - if (get_symbol_class (node) == SYMBOL_PARTITION) + if (symtab_get_symbol_partitioning_class (node) == SYMBOL_PARTITION) { order[n_nodes++] = node; total_size += inline_summary (node)->size; @@ -518,13 +456,13 @@ lto_balanced_map (void) if (!flag_toplevel_reorder) { FOR_EACH_VARIABLE (vnode) - if (get_symbol_class (vnode) == SYMBOL_PARTITION) + if (symtab_get_symbol_partitioning_class (vnode) == SYMBOL_PARTITION) n_varpool_nodes++; varpool_order = XNEWVEC (varpool_node *, n_varpool_nodes); n_varpool_nodes = 0; FOR_EACH_VARIABLE (vnode) - if (get_symbol_class (vnode) == SYMBOL_PARTITION) + if (symtab_get_symbol_partitioning_class (vnode) == SYMBOL_PARTITION) varpool_order[n_varpool_nodes++] = vnode; qsort (varpool_order, n_varpool_nodes, sizeof (varpool_node *), varpool_node_cmp); @@ -643,7 +581,7 @@ lto_balanced_map (void) if (!vnode->definition) continue; if (!symbol_partitioned_p (vnode) && flag_toplevel_reorder - && get_symbol_class (vnode) == SYMBOL_PARTITION) + && symtab_get_symbol_partitioning_class (vnode) == SYMBOL_PARTITION) add_symbol_to_partition (partition, vnode); index = lto_symtab_encoder_lookup (partition->encoder, vnode); @@ -676,7 +614,7 @@ lto_balanced_map (void) vnode = ipa_ref_referring_varpool_node (ref); gcc_assert (vnode->definition); if (!symbol_partitioned_p (vnode) && flag_toplevel_reorder - && get_symbol_class (vnode) == SYMBOL_PARTITION) + && symtab_get_symbol_partitioning_class (vnode) == SYMBOL_PARTITION) add_symbol_to_partition (partition, vnode); index = lto_symtab_encoder_lookup (partition->encoder, vnode); @@ -769,7 +707,7 @@ lto_balanced_map (void) if (flag_toplevel_reorder) { FOR_EACH_VARIABLE (vnode) - if (get_symbol_class (vnode) == SYMBOL_PARTITION + if (symtab_get_symbol_partitioning_class (vnode) == SYMBOL_PARTITION && !symbol_partitioned_p (vnode)) add_symbol_to_partition (partition, vnode); } @@ -979,7 +917,7 @@ lto_promote_cross_file_statics (void) || lto_symtab_encoder_in_partition_p (encoder, node) /* ... or if we do not partition it. This mean that it will appear in every partition refernecing it. */ - || get_symbol_class (node) != SYMBOL_PARTITION) + || symtab_get_symbol_partitioning_class (node) != SYMBOL_PARTITION) continue; promote_symbol (node); Index: symtab.c =================================================================== --- symtab.c (revision 207588) +++ symtab.c (working copy) @@ -1267,4 +1267,55 @@ symtab_semantically_equivalent_p (symtab bb = b; return bb == ba; } + +/* Classify symbol NODE for partitioning. */ + +enum symbol_partitioning_class +symtab_get_symbol_partitioning_class (symtab_node *node) +{ + /* Inline clones are always duplicated. + This include external delcarations. */ + cgraph_node *cnode = dyn_cast <cgraph_node> (node); + + if (DECL_ABSTRACT (node->decl)) + return SYMBOL_EXTERNAL; + + if (cnode && cnode->global.inlined_to) + return SYMBOL_DUPLICATE; + + /* Weakref aliases are always duplicated. */ + if (node->weakref) + return SYMBOL_DUPLICATE; + + /* External declarations are external. */ + if (DECL_EXTERNAL (node->decl)) + return SYMBOL_EXTERNAL; + + if (varpool_node *vnode = dyn_cast <varpool_node> (node)) + { + /* Constant pool references use local symbol names that can not + be promoted global. We should never put into a constant pool + objects that can not be duplicated across partitions. */ + if (DECL_IN_CONSTANT_POOL (node->decl)) + return SYMBOL_DUPLICATE; + gcc_checking_assert (vnode->definition); + } + /* Functions that are cloned may stay in callgraph even if they are unused. + Handle them as external; compute_ltrans_boundary take care to make + proper things to happen (i.e. to make them appear in the boundary but + with body streamed, so clone can me materialized). */ + else if (!cgraph (node)->definition) + return SYMBOL_EXTERNAL; + + /* Linker discardable symbols are duplicated to every use unless they are + keyed. + Keyed symbols or those. */ + if (DECL_ONE_ONLY (node->decl) + && !node->force_output + && !node->forced_by_abi + && !symtab_used_from_object_file_p (node)) + return SYMBOL_DUPLICATE; + + return SYMBOL_PARTITION; +} #include "gt-symtab.h"