On Wed, Jan 16, 2013 at 01:44:20PM +0100, Jan Hubicka wrote: > > Perhaps could you first change cgraph_non_local_node_p_1 and try to check > > some code > > if codegen differs significantly? It should not at all. > > ipa-cp is the sole user of this flag in IPA passes, so you should know what > > it does. > > Thinking deeper of ipa-cp and local virtuals, I think this is all slipperly. > Local means that all calls to the functions are explicit and known. Obviously > if function is virutal and new calls may appear by devirtualization, the local > flag is bogus. I guess the external functions are the only that may be local > and virtual because somewhere there must be a vtable reference, but to play > safe, I would suggest marking all virtuals non-local. >
Right, as discussed on IRC, the patch below therfore modifies cgraph_only_called_directly_or_aliased_p to return false for virtual functions (which translates into cleared local flag) and the cloning machinery to clear that flag. Bootstrapped and tested on x86_64-linux without any problems. OK for trunk? Thanks, Martin 2013-01-16 Martin Jambor <mjam...@suse.cz> PR tree-optimizations/55264 * ipa-inline-transform.c (can_remove_node_now_p_1): Never return true for virtual methods. * ipa.c (symtab_remove_unreachable_nodes): Never return true for virtual methods before inlining is over. * cgraph.h (cgraph_only_called_directly_or_aliased_p): Return false for virtual functions. * cgraphclones.c (cgraph_create_virtual_clone): Mark clones as non-virtual. testsuite/ * g++.dg/ipa/pr55264.C: New test. Index: src/gcc/ipa-inline-transform.c =================================================================== --- src.orig/gcc/ipa-inline-transform.c +++ src/gcc/ipa-inline-transform.c @@ -92,9 +92,7 @@ can_remove_node_now_p_1 (struct cgraph_n those only after all devirtualizable virtual calls are processed. Lacking may edges in callgraph we just preserve them post inlining. */ - && (!DECL_VIRTUAL_P (node->symbol.decl) - || (!DECL_COMDAT (node->symbol.decl) - && !DECL_EXTERNAL (node->symbol.decl))) + && !DECL_VIRTUAL_P (node->symbol.decl) /* During early inlining some unanalyzed cgraph nodes might be in the callgraph and they might reffer the function in question. */ && !cgraph_new_nodes); Index: src/gcc/ipa.c =================================================================== --- src.orig/gcc/ipa.c +++ src/gcc/ipa.c @@ -241,8 +241,7 @@ symtab_remove_unreachable_nodes (bool be && (!cgraph_can_remove_if_no_direct_calls_and_refs_p (node) /* Keep around virtual functions for possible devirtualization. */ || (before_inlining_p - && DECL_VIRTUAL_P (node->symbol.decl) - && (DECL_COMDAT (node->symbol.decl) || DECL_EXTERNAL (node->symbol.decl))))) + && DECL_VIRTUAL_P (node->symbol.decl)))) { gcc_assert (!node->global.inlined_to); pointer_set_insert (reachable, node); Index: src/gcc/testsuite/g++.dg/ipa/pr55264.C =================================================================== --- /dev/null +++ src/gcc/testsuite/g++.dg/ipa/pr55264.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-early-inlining -fno-weak" } */ + +struct S +{ + S(); + virtual inline void foo () + { + foo(); + } +}; + +void +B () +{ + S().foo (); +} Index: src/gcc/cgraph.h =================================================================== --- src.orig/gcc/cgraph.h +++ src/gcc/cgraph.h @@ -1164,6 +1164,7 @@ cgraph_only_called_directly_or_aliased_p gcc_assert (!node->global.inlined_to); return (!node->symbol.force_output && !node->symbol.address_taken && !node->symbol.used_from_other_partition + && !DECL_VIRTUAL_P (node->symbol.decl) && !DECL_STATIC_CONSTRUCTOR (node->symbol.decl) && !DECL_STATIC_DESTRUCTOR (node->symbol.decl) && !node->symbol.externally_visible); Index: src/gcc/cgraphclones.c =================================================================== --- src.orig/gcc/cgraphclones.c +++ src/gcc/cgraphclones.c @@ -319,6 +319,7 @@ cgraph_create_virtual_clone (struct cgra TREE_PUBLIC (new_node->symbol.decl) = 0; DECL_COMDAT (new_node->symbol.decl) = 0; DECL_WEAK (new_node->symbol.decl) = 0; + DECL_VIRTUAL_P (new_node->symbol.decl) = 0; DECL_STATIC_CONSTRUCTOR (new_node->symbol.decl) = 0; DECL_STATIC_DESTRUCTOR (new_node->symbol.decl) = 0; new_node->clone.tree_map = tree_map;