Hi, this patch is not so nice fix for quite nasty problem with devirtualization and decl merging. Once we determine the call target, we use possible_polymorphic_call_target_p to check if this is type consistent and if not we redirect to builtin_unreachable and do not account this as a hint to the inlining/cloning.
THe testing is done by collecing all polymorphic target of a given virtual call and checking that the determined target is in the list. What happens in omnetpp is that it has external vtables which do not have symbol nodes associated with them (as they are not use by the code only by the devirt machinery). Consequently they are not seeen by lto-symtab.c and kept unmerged. Now ipa-cp has different copy of same vtable than what is used by the the ipa-devirt and each of them has different function unmerged external decls in them. Since ipa-cp pulls out one decl and possible_polymorphic_call_target_p has other decl and we do not have the the alias link between them, we incorrectly think the function is not in the list. The patch makes the virtuals to be always merged, so ODR rule is represented correctly. I am also working on patch that makes the trensparent alias links for duplicated decls at node creation time that will also fix the wrong code, but this patch also improves the hitrate of devirtualization code because it now can get to the vtable constructors more often (on Firefox from 800 to 3900 devirtualizations), so this patch still makes sense. An alternative solution I will try again (probably only next stage1) is to record all those vtables into symbol table at streaming time. I did that in past but the extra streaming overhead did not seem to pay back for the extra devirtualizaitons achieved. Note that the bug to some degree exists at the release branches too. These still won't merge declarations that have no symbol tables at all. I will try to make a testcase. Bootstrapped/regtested x86_64-linux, will commit it after re-testing at Firefox and libreoffice. Honza PR lto/68878 * lto-symtab.c (lto_symtab_prevailing_virtual_decl): New function. * lto-symtab.h (lto_symtab_prevailing_virtual_decl): Declare. (lto_symtab_prevailing_decl): Use it. Index: lto/lto-symtab.c =================================================================== --- lto/lto-symtab.c (revision 231581) +++ lto/lto-symtab.c (working copy) @@ -968,3 +975,33 @@ lto_symtab_merge_symbols (void) } } } + +/* Virtual tables may matter for code generation even if they are not + directly refernced by the code because they may be used for devirtualizaiton. + For this reason it is important to merge even virtual tables that have no + associated symbol table entries. Without doing so we lose optimization + oppurtunities by losing track of the vtable constructor. + FIXME: we probably ought to introduce explicit symbol table entries for + those before streaming. */ + +tree +lto_symtab_prevailing_virtual_decl (tree decl) +{ + gcc_checking_assert (!type_in_anonymous_namespace_p (DECL_CONTEXT (decl)) + && DECL_ASSEMBLER_NAME_SET_P (decl)); + + symtab_node *n = symtab_node::get_for_asmname + (DECL_ASSEMBLER_NAME (decl)); + while (n && ((!DECL_EXTERNAL (n->decl) && !TREE_PUBLIC (n->decl)) + || !DECL_VIRTUAL_P (n->decl))) + n = n->next_sharing_asm_name; + if (n) + { + lto_symtab_prevail_decl (n->decl, decl); + decl = n->decl; + } + else + symtab_node::get_create (decl); + + return decl; +} Index: lto/lto-symtab.h =================================================================== --- lto/lto-symtab.h (revision 231581) +++ lto/lto-symtab.h (working copy) @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. extern void lto_symtab_merge_decls (void); extern void lto_symtab_merge_symbols (void); extern tree lto_symtab_prevailing_decl (tree decl); +extern tree lto_symtab_prevailing_virtual_decl (tree decl); /* Mark DECL to be previailed by PREVAILING. Use DECL_ABSTRACT_ORIGIN and DECL_CHAIN as special markers; those do not @@ -31,6 +32,7 @@ inline void lto_symtab_prevail_decl (tree prevailing, tree decl) { gcc_checking_assert (DECL_ABSTRACT_ORIGIN (decl) != error_mark_node); + gcc_assert (TREE_PUBLIC (decl) || DECL_EXTERNAL (decl)); DECL_CHAIN (decl) = prevailing; DECL_ABSTRACT_ORIGIN (decl) = error_mark_node; } @@ -43,5 +45,12 @@ lto_symtab_prevailing_decl (tree decl) if (DECL_ABSTRACT_ORIGIN (decl) == error_mark_node) return DECL_CHAIN (decl); else - return decl; + { + if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL) + && DECL_VIRTUAL_P (decl) + && (TREE_PUBLIC (decl) || DECL_EXTERNAL (decl)) + && !symtab_node::get (decl)) + return lto_symtab_prevailing_virtual_decl (decl); + return decl; + } }