Hi, this patch drops vtable_method filed. I never understood what it is about but reading PR20991 I am convinced that we hit the same problem with work on new devirutalization code. I implemented what Mark describe as "ideal solution" there - i.e. teaching cgraph that virtual functions might become reachable until after inlining. Since we still can devirutalize in late compilation (that is pretty much poinless but anyway), we no ahve can_refer_decl_in_current_unit_p that tests if the function has been already thrown away. Perhaps we might apply there the observation about vtable being output somewhere, but I do not think it is safe: if vtable is COMDAT, we can pretty much also optimize all references to it out in all compilation unit and up not outputting it. When vtable is not COMDAT, the methods won't be either and this trick will not apply.
Consequently I am dropping the flag. This is very trivial based on observation that cp_fold_obj_type_ref, the only setter of the flag, is now dead. Plus the varasm code is no-longer executed at the time of IPA optimizations that the original patch was fixing. Martin, can you please look into why cp_fold_obj_type_ref is no longer used and if possible get rid of it? Richi, compiling the original testcase: // PR middle-end/20991 // { dg-options "-O2" } // { dg-do compile } struct S { virtual inline int foo () const; virtual inline bool bar () const; virtual int baz (int) const; }; inline int S::foo () const { return 1; } inline bool S::bar () const { return foo () == 0; } void A () { S s; if (s.bar ()) s.foo (); } void B () { S s; if (s.bar ()) s.foo (); } we end up with bit amusing code: void B() () { int D.2147; struct S s; <bb 2>: s._vptr.S = &_ZTV1S[2]; D.2147_8 = OBJ_TYPE_REF(foo;&s->0) (&s); return; } notice that OBJ_TYPE_REF is useless since foo got devitualized and it holds alive the useless s._vptr.S = &_ZTV1S[2]. We want to drop OBJ_TYPE_REF at time we fold first argument to constant. a.C.027t.fre1 dump reads: void B() () { int (*__vtbl_ptr_type) () * D.2149; int (*__vtbl_ptr_type) () D.2148; int D.2147; bool D.2146; struct S s; <bb 2>: s._vptr.S = &_ZTV1S[2]; D.2149_6 = &_ZTV1S[2]; D.2148_7 = foo; D.2147_8 = OBJ_TYPE_REF(D.2148_7;&s->0) (&s); D.2146_9 = D.2147_8 == 0; D.2146_12 = D.2146_9; D.2146_1 = D.2146_12; D.2146_2 = D.2146_1; return; } already I would expect FRE to replace D.2148_7 by foo. Later this is done by copyprop1 Folding statement: D.2147_8 = OBJ_TYPE_REF(D.2148_7;&s->0) (&s); Folded into: D.2147_8 = OBJ_TYPE_REF(foo;&s->0) (&s); void B() () { int (*__vtbl_ptr_type) () * D.2149; int (*__vtbl_ptr_type) () D.2148; int D.2147; bool D.2146; struct S s; <bb 2>: s._vptr.S = &_ZTV1S[2]; D.2147_8 = OBJ_TYPE_REF(foo;&s->0) (&s); return; } When copyprop chose to do constant propagation for whatever reason, it probably should do the folding, too. Either in substitute_and_fold or via its own ccp_fold_stmt. I am sure you know the best alternatives better than I do ;) Honza * cgraph.c (cgraph_clone_node): Do not handle vtable_method * cgraph.h (struct cgraph_local_info): Drop vtable_method. * cgraphunit.c (cgraph_copy_node_for_versioning): Drop vtable_method. * lto-cgraph.c (lto_output_node, input_overwrite_node): Drop vtable method. * gimple-fold.c (can_refer_decl_in_current_unit_p): Mention PR20991 in gimple-fold.c * varasm.c (mark_decl_referenced): Drop vtable_method handling code. * cp/class.c (cp_fold_obj_type_ref): Drop vtable_method. Index: cgraph.c =================================================================== *** cgraph.c (revision 172608) --- cgraph.c (working copy) *************** cgraph_clone_node (struct cgraph_node *n *** 2161,2167 **** new_node->local = n->local; new_node->local.externally_visible = false; new_node->local.local = true; - new_node->local.vtable_method = false; new_node->global = n->global; new_node->rtl = n->rtl; new_node->count = count; --- 2161,2166 ---- Index: cgraph.h =================================================================== *** cgraph.h (revision 172608) --- cgraph.h (working copy) *************** struct GTY(()) cgraph_local_info { *** 95,104 **** /* True when the function has been originally extern inline, but it is redefined now. */ unsigned redefined_extern_inline : 1; - - /* True if the function is going to be emitted in some other translation - unit, referenced from vtable. */ - unsigned vtable_method : 1; }; /* Information about the function that needs to be computed globally --- 95,100 ---- Index: cgraphunit.c =================================================================== *** cgraphunit.c (revision 172608) --- cgraphunit.c (working copy) *************** cgraph_copy_node_for_versioning (struct *** 1991,1997 **** new_version->local = old_version->local; new_version->local.externally_visible = false; new_version->local.local = true; - new_version->local.vtable_method = false; new_version->global = old_version->global; new_version->rtl = old_version->rtl; new_version->reachable = true; --- 1991,1996 ---- Index: cp/class.c =================================================================== *** cp/class.c (revision 172608) --- cp/class.c (working copy) *************** cp_fold_obj_type_ref (tree ref, tree kno *** 8402,8409 **** DECL_VINDEX (fndecl))); #endif - cgraph_get_node (fndecl)->local.vtable_method = true; - return build_address (fndecl); } --- 8402,8407 ---- Index: lto-cgraph.c =================================================================== *** lto-cgraph.c (revision 172608) --- lto-cgraph.c (working copy) *************** lto_output_node (struct lto_simple_outpu *** 491,497 **** bp_pack_value (&bp, node->local.finalized, 1); bp_pack_value (&bp, node->local.can_change_signature, 1); bp_pack_value (&bp, node->local.redefined_extern_inline, 1); - bp_pack_value (&bp, node->local.vtable_method, 1); bp_pack_value (&bp, node->needed, 1); bp_pack_value (&bp, node->address_taken, 1); bp_pack_value (&bp, node->abstract_and_needed, 1); --- 491,496 ---- *************** input_overwrite_node (struct lto_file_de *** 927,933 **** node->local.finalized = bp_unpack_value (bp, 1); node->local.can_change_signature = bp_unpack_value (bp, 1); node->local.redefined_extern_inline = bp_unpack_value (bp, 1); - node->local.vtable_method = bp_unpack_value (bp, 1); node->needed = bp_unpack_value (bp, 1); node->address_taken = bp_unpack_value (bp, 1); node->abstract_and_needed = bp_unpack_value (bp, 1); --- 926,931 ---- Index: gimple-fold.c =================================================================== *** gimple-fold.c (revision 172608) --- gimple-fold.c (working copy) *************** can_refer_decl_in_current_unit_p (tree d *** 80,86 **** return true; /* We are not at ltrans stage; so don't worry about WHOPR. Also when still gimplifying all referred comdat functions will be ! produced. */ if (!flag_ltrans && (!DECL_COMDAT (decl) || !cgraph_function_flags_ready)) return true; /* If we already output the function body, we are safe. */ --- 80,89 ---- return true; /* We are not at ltrans stage; so don't worry about WHOPR. Also when still gimplifying all referred comdat functions will be ! produced. ! ??? as observed in PR20991 for already optimized out comdat virtual functions ! we may not neccesarily give up because the copy will be output elsewhere when ! corresponding vtable is output. */ if (!flag_ltrans && (!DECL_COMDAT (decl) || !cgraph_function_flags_ready)) return true; /* If we already output the function body, we are safe. */ Index: varasm.c =================================================================== *** varasm.c (revision 172608) --- varasm.c (working copy) *************** mark_decl_referenced (tree decl) *** 2201,2208 **** definition. */ struct cgraph_node *node = cgraph_get_create_node (decl); if (!DECL_EXTERNAL (decl) ! && (!node->local.vtable_method || !cgraph_global_info_ready ! || !node->local.finalized)) cgraph_mark_needed_node (node); } else if (TREE_CODE (decl) == VAR_DECL) --- 2201,2207 ---- definition. */ struct cgraph_node *node = cgraph_get_create_node (decl); if (!DECL_EXTERNAL (decl) ! && !node->local.finalized) cgraph_mark_needed_node (node); } else if (TREE_CODE (decl) == VAR_DECL)