Hi, this segfault in c-c++-common/torture/builtin-arith-overflow-12.c is caused by fact that we split ltrans units separating call to alias of local function and its target. Because LTO partitioning turns aliases in boundaries into normal symbols, we end up checking alias for can_change_signature_p that is false.
This is just a manifestation of deeper problem that we do not represent aliases between external symbols. Doing so is also needed to get address equality and alias analysis right among other details. While I was aware of this issue, I managed to delay proper fix until wrong code issues came. This patch teaches middle-end about external aliases it 1) makes symbol_table::remove_unreachable_nodes to not remove aliases from boundaries 2) teach lto-cgraph to do right thing about streaming: insert alias targets to the boundary and stream the references Same thing is also done for thunks as for good part of IPA optimizers these are similar to aliases. I also removed cgrpah_node::global_info that is unused and secured cgraph_node::local_info and cgraph_node::rtl_info for aliases. Bootstrapped/regtested x86_64-linux, will commit it after lto-bootstrapping. Honza PR ipa/65005 * ipa-visibility.c (cgraph_node::non_local_p): Turn into static function. * symtab.c (symtab_node::verify_base): Remove check that non-definitions have no comdat group. * lto-cgraph.c (lto_output_node): Always output thunk and alias info. (lto_output_varpool_node): Always output alias info. (output_refs): Output refs of boundary aliases, too. (compute_ltrans_boundary): Add alias and thunk target into boundaries. (output_symtab): Output call eges in thunks in boundary. (get_alias_symbol): Remove. (input_node, input_varpool_node): Do not special case weakrefs. * ipa.c (symbol_table::remove_unreachable_nodes): Do not remove alias and thunks targets in the boundary; do not take removed symbols from their comdat groups. * cgraph.c (cgraph_node::local_info): Look through aliases and thunks. (cgraph_node::global_info): Remove. (cgraph_node::rtl_info): Look through aliases and thunks. * cgrpah.h (global_info): Remove. (non_local_p): Remove. Index: ipa-visibility.c =================================================================== --- ipa-visibility.c (revision 220606) +++ ipa-visibility.c (working copy) @@ -101,8 +101,8 @@ along with GCC; see the file COPYING3. /* Return true when NODE can not be local. Worker for cgraph_local_node_p. */ -bool -cgraph_node::non_local_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) +static bool +non_local_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) { return !(node->only_called_directly_or_aliased_p () /* i386 would need update to output thunk with locak calling @@ -124,7 +124,7 @@ cgraph_node::local_p (void) if (n->thunk.thunk_p) return n->callees->callee->local_p (); - return !n->call_for_symbol_thunks_and_aliases (cgraph_node::non_local_p, + return !n->call_for_symbol_thunks_and_aliases (non_local_p, NULL, true); } Index: lto-cgraph.c =================================================================== --- lto-cgraph.c (revision 220606) +++ lto-cgraph.c (working copy) @@ -432,14 +432,13 @@ lto_output_node (struct lto_simple_outpu struct cgraph_node *clone_of, *ultimate_clone_of; ipa_opt_pass_d *pass; int i; - bool alias_p; const char *comdat; const char *section; tree group; boundary_p = !lto_symtab_encoder_in_partition_p (encoder, node); - if (node->analyzed && !boundary_p) + if (node->analyzed && (!boundary_p || node->alias || node->thunk.thunk_p)) tag = LTO_symtab_analyzed_node; else tag = LTO_symtab_unavail_node; @@ -565,14 +564,7 @@ lto_output_node (struct lto_simple_outpu || referenced_from_other_partition_p (node, encoder)), 1); bp_pack_value (&bp, node->lowered, 1); bp_pack_value (&bp, in_other_partition, 1); - /* Real aliases in a boundary become non-aliases. However we still stream - alias info on weakrefs. - TODO: We lose a bit of information here - when we know that variable is - defined in other unit, we may use the info on aliases to resolve - symbol1 != symbol2 type tests that we can do only for locally defined objects - otherwise. */ - alias_p = node->alias && (!boundary_p || node->weakref); - bp_pack_value (&bp, alias_p, 1); + bp_pack_value (&bp, node->alias, 1); bp_pack_value (&bp, node->weakref, 1); bp_pack_value (&bp, node->frequency, 2); bp_pack_value (&bp, node->only_called_at_startup, 1); @@ -581,14 +573,14 @@ lto_output_node (struct lto_simple_outpu bp_pack_value (&bp, node->calls_comdat_local, 1); bp_pack_value (&bp, node->icf_merged, 1); bp_pack_value (&bp, node->nonfreeing_fn, 1); - bp_pack_value (&bp, node->thunk.thunk_p && !boundary_p, 1); + bp_pack_value (&bp, node->thunk.thunk_p, 1); bp_pack_enum (&bp, ld_plugin_symbol_resolution, LDPR_NUM_KNOWN, node->resolution); bp_pack_value (&bp, node->instrumentation_clone, 1); streamer_write_bitpack (&bp); streamer_write_data_stream (ob->main_stream, section, strlen (section) + 1); - if (node->thunk.thunk_p && !boundary_p) + if (node->thunk.thunk_p) { streamer_write_uhwi_stream (ob->main_stream, @@ -618,7 +610,6 @@ lto_output_varpool_node (struct lto_simp bool boundary_p = !lto_symtab_encoder_in_partition_p (encoder, node); struct bitpack_d bp; int ref; - bool alias_p; const char *comdat; const char *section; tree group; @@ -638,8 +629,7 @@ lto_output_varpool_node (struct lto_simp bp_pack_value (&bp, node->implicit_section, 1); bp_pack_value (&bp, node->writeonly, 1); bp_pack_value (&bp, node->definition, 1); - alias_p = node->alias && (!boundary_p || node->weakref); - bp_pack_value (&bp, alias_p, 1); + bp_pack_value (&bp, node->alias, 1); bp_pack_value (&bp, node->weakref, 1); bp_pack_value (&bp, node->analyzed && !boundary_p, 1); gcc_assert (node->definition || !node->analyzed); @@ -794,18 +784,18 @@ output_outgoing_cgraph_edges (struct cgr static void output_refs (lto_symtab_encoder_t encoder) { - lto_symtab_encoder_iterator lsei; struct lto_simple_output_block *ob; int count; struct ipa_ref *ref; - int i; ob = lto_create_simple_output_block (LTO_section_refs); - for (lsei = lsei_start_in_partition (encoder); !lsei_end_p (lsei); - lsei_next_in_partition (&lsei)) + for (int i = 0; i < lto_symtab_encoder_size (encoder); i++) { - symtab_node *node = lsei_node (lsei); + symtab_node *node = lto_symtab_encoder_deref (encoder, i); + + if (!node->alias && !lto_symtab_encoder_in_partition_p (encoder, node)) + continue; count = node->ref_list.nreferences (); if (count) @@ -813,7 +803,7 @@ output_refs (lto_symtab_encoder_t encode streamer_write_gcov_count_stream (ob->main_stream, count); streamer_write_uhwi_stream (ob->main_stream, lto_symtab_encoder_lookup (encoder, node)); - for (i = 0; node->iterate_reference (i, ref); i++) + for (int i = 0; node->iterate_reference (i, ref); i++) lto_output_ref (ob, ref, encoder); } } @@ -987,6 +977,19 @@ compute_ltrans_boundary (lto_symtab_enco } } } + /* Be sure to also insert alias targert and thunk callees. These needs + to stay to aid local calling conventions. */ + for (i = 0; i < lto_symtab_encoder_size (encoder); i++) + { + symtab_node *node = lto_symtab_encoder_deref (encoder, i); + cgraph_node *cnode = dyn_cast <cgraph_node *> (node); + + if (node->alias && node->analyzed) + create_references (encoder, node); + if (cnode + && cnode->thunk.thunk_p) + add_node_to (encoder, cnode->callees->callee, false); + } lto_symtab_encoder_delete (in_encoder); return encoder; } @@ -998,7 +1001,6 @@ output_symtab (void) { struct cgraph_node *node; struct lto_simple_output_block *ob; - lto_symtab_encoder_iterator lsei; int i, n_nodes; lto_symtab_encoder_t encoder; @@ -1028,12 +1030,16 @@ output_symtab (void) } /* Go over the nodes in SET again to write edges. */ - for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei); - lsei_next_function_in_partition (&lsei)) + for (int i = 0; i < lto_symtab_encoder_size (encoder); i++) { - node = lsei_cgraph_node (lsei); - output_outgoing_cgraph_edges (node->callees, ob, encoder); - output_outgoing_cgraph_edges (node->indirect_calls, ob, encoder); + node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder, i)); + if (node + && (node->thunk.thunk_p + || lto_symtab_encoder_in_partition_p (encoder, node))) + { + output_outgoing_cgraph_edges (node->callees, ob, encoder); + output_outgoing_cgraph_edges (node->indirect_calls, ob, encoder); + } } streamer_write_uhwi_stream (ob->main_stream, 0); Index: symtab.c =================================================================== --- symtab.c (revision 220606) +++ symtab.c (working copy) @@ -1070,11 +1070,6 @@ symtab_node::verify_base (void) error ("same_comdat_group list across different groups"); error_found = true; } - if (!n->definition) - { - error ("Node has same_comdat_group but it is not a definition"); - error_found = true; - } if (n->type != type) { error ("mixing different types of symbol in same comdat groups is not supported"); Index: cgraph.c =================================================================== --- cgraph.c (revision 220606) +++ cgraph.c (working copy) @@ -1846,20 +1846,7 @@ cgraph_node::local_info (tree decl) cgraph_node *node = get (decl); if (!node) return NULL; - return &node->local; -} - -/* Return global info for the compiled function. */ - -cgraph_global_info * -cgraph_node::global_info (tree decl) -{ - gcc_assert (TREE_CODE (decl) == FUNCTION_DECL - && symtab->global_info_ready); - cgraph_node *node = get (decl); - if (!node) - return NULL; - return &node->global; + return &node->ultimate_alias_target ()->local; } /* Return local info for the compiled function. */ @@ -1869,11 +1856,13 @@ cgraph_node::rtl_info (tree decl) { gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); cgraph_node *node = get (decl); - if (!node - || (decl != current_function_decl - && !TREE_ASM_WRITTEN (node->decl))) + if (!node) + return NULL; + node = node->ultimate_alias_target (); + if (node->decl != current_function_decl + && !TREE_ASM_WRITTEN (node->decl)) return NULL; - return &node->rtl; + return &node->ultimate_alias_target ()->rtl; } /* Return a string describing the failure REASON. */ Index: cgraph.h =================================================================== --- cgraph.h (revision 220606) +++ cgraph.h (working copy) @@ -1164,9 +1164,6 @@ public: /* Return local info for the compiled function. */ static cgraph_local_info *local_info (tree decl); - /* Return global info for the compiled function. */ - static cgraph_global_info *global_info (tree); - /* Return local info for the compiled function. */ static cgraph_rtl_info *rtl_info (tree); @@ -1187,10 +1184,6 @@ public: return node->used_from_object_file_p (); } - /* Return true when cgraph_node can not be local. - Worker for cgraph_local_node_p. */ - static bool non_local_p (cgraph_node *node, void *); - /* Verify whole cgraph structure. */ static void DEBUG_FUNCTION verify_cgraph_nodes (void); Index: ipa.c =================================================================== --- ipa.c (revision 220606) +++ ipa.c (working copy) @@ -383,7 +383,11 @@ symbol_table::remove_unreachable_nodes ( /* If we are processing symbol in boundary, mark its AUX pointer for possible later re-processing in enqueue_node. */ if (in_boundary_p) - node->aux = (void *)2; + { + node->aux = (void *)2; + if (node->alias && node->analyzed) + enqueue_node (node->get_alias_target (), &first, &reachable); + } else { if (TREE_CODE (node->decl) == FUNCTION_DECL @@ -486,6 +490,9 @@ symbol_table::remove_unreachable_nodes ( } } + else if (cnode->thunk.thunk_p) + enqueue_node (cnode->callees->callee, &first, &reachable); + /* If any reachable function has simd clones, mark them as reachable as well. */ if (cnode->simd_clones) @@ -534,7 +541,7 @@ symbol_table::remove_unreachable_nodes ( node->release_body (); else if (!node->clone_of) gcc_assert (in_lto_p || DECL_RESULT (node->decl)); - if (node->definition) + if (node->definition && !node->alias && !node->thunk.thunk_p) { if (file) fprintf (file, " %s/%i", node->name (), node->order); @@ -554,7 +561,6 @@ symbol_table::remove_unreachable_nodes ( if (!node->in_other_partition) node->local.local = false; node->remove_callees (); - node->remove_from_same_comdat_group (); node->remove_all_references (); changed = true; if (node->thunk.thunk_p @@ -614,7 +620,7 @@ symbol_table::remove_unreachable_nodes ( vnode->remove (); changed = true; } - else if (!reachable.contains (vnode)) + else if (!reachable.contains (vnode) && !vnode->alias) { tree init; if (vnode->definition)