Hi, inliner uses crossmodule hint that during LTO preffers in-module inlining over cross-module. This hint is wrong for comdats that gets merged and thus the module information is more or less random.
The patch fixes it by adding merged flag to cgraph_node indicating merged comdats and always disabling the hint for those. Bootstrapped/regtested x86_64-linux. Honza * ipa-inline-analysis.c (simple_edge_hints): Fix check for cross-module inlining. * cgraph.h (cgraph_node): Add flag merged. * ipa-icf.c (sem_function::merge): Maintain it. * lto-symtab.c (lto_cgraph_replace_node): Maintain merged flag. Index: ipa-inline-analysis.c =================================================================== --- ipa-inline-analysis.c (revision 220329) +++ ipa-inline-analysis.c (working copy) @@ -3702,13 +3702,15 @@ simple_edge_hints (struct cgraph_edge *e int hints = 0; struct cgraph_node *to = (edge->caller->global.inlined_to ? edge->caller->global.inlined_to : edge->caller); + struct cgraph_node *callee = edge->callee->ultimate_alias_target (); if (inline_summaries->get (to)->scc_no && inline_summaries->get (to)->scc_no == inline_summaries->get (edge->callee)->scc_no && !edge->recursive_p ()) hints |= INLINE_HINT_same_scc; - if (to->lto_file_data && edge->callee->lto_file_data - && to->lto_file_data != edge->callee->lto_file_data) + if (callee->lto_file_data && edge->caller->lto_file_data + && edge->caller->lto_file_data != callee->lto_file_data + && !callee->merged) hints |= INLINE_HINT_cross_module; return hints; Index: ipa-icf.c =================================================================== --- ipa-icf.c (revision 220329) +++ ipa-icf.c (working copy) @@ -711,6 +711,10 @@ sem_function::merge (sem_item *alias_ite } alias->icf_merged = true; + if (local_original->lto_file_data + && alias->lto_file_data + && local_original->lto_file_data != alias->lto_file_data) + local_original->merged = true; /* The alias function is removed if symbol address does not matter. */ @@ -725,6 +729,10 @@ sem_function::merge (sem_item *alias_ite else if (create_alias) { alias->icf_merged = true; + if (local_original->lto_file_data + && alias->lto_file_data + && local_original->lto_file_data != alias->lto_file_data) + local_original->merged = true; /* Remove the function's body. */ ipa_merge_profiles (original, alias); @@ -762,6 +770,10 @@ sem_function::merge (sem_item *alias_ite } alias->icf_merged = true; + if (local_original->lto_file_data + && alias->lto_file_data + && local_original->lto_file_data != alias->lto_file_data) + local_original->merged = true; ipa_merge_profiles (local_original, alias, true); alias->create_wrapper (local_original); Index: lto/lto-symtab.c =================================================================== --- lto/lto-symtab.c (revision 220329) +++ lto/lto-symtab.c (working copy) @@ -88,6 +88,8 @@ lto_cgraph_replace_node (struct cgraph_n gcc_assert (!prevailing_node->global.inlined_to); prevailing_node->mark_address_taken (); } + if (node->definition && prevailing_node->definition) + prevailing_node->merged = true; /* Redirect all incoming edges. */ compatible_p Index: cgraph.h =================================================================== --- cgraph.h (revision 220329) +++ cgraph.h (working copy) @@ -1296,6 +1296,8 @@ public: other operation that could make previously non-trapping memory accesses trapping. */ unsigned nonfreeing_fn : 1; + /* True if there was multiple COMDAT bodies merged by lto-symtab. */ + unsigned merged : 1; }; /* A cgraph node set is a collection of cgraph nodes. A cgraph node