Hi, this patch adds basic tracking of what types may be in construction because the call appears in a polymorphic cdtor.
Bootstrapped/regtested x86_64-linux, comitted. Honza * cgraph.h (struct indirect_call_info): Add IN_POLYMORPHIC_CDTOR * lto-cgraph.c (lto_output_edge, input_edge): Stream in_polymorphic_cdtor * cgraph.c (symbol_table::create_edge): Compute in_polymorphic_cdtor. (cgraph_edge::make_speculative): Copy in_polymorphic_cdtor. * cgraphclones.c (cgraph_edge::clone): Likewise. * ipa-prop.c (update_jump_functions_after_inlining, try_make_edge_direct_virtual_call): Pass in_polymorphic_cdtor to possible_dynamic_type_change. (decl_maybe_in_construction_p): Allow empty OUTER_TYPE and BASE. (ipa_polymorphic_call_context::possible_dynamic_type_change): Add IN_POLY_CDOTR argument. Index: cgraph.h =================================================================== --- cgraph.h (revision 215870) +++ cgraph.h (working copy) @@ -1333,7 +1333,7 @@ public: void offset_by (HOST_WIDE_INT); /* Use when we can not track dynamic type change. This speculatively assume type change is not happening. */ - void possible_dynamic_type_change (tree otr_type = NULL); + void possible_dynamic_type_change (bool, tree otr_type = NULL); /* Assume that both THIS and a given context is valid and strenghten THIS if possible. Return true if any strenghtening was made. If actual type the context is being used in is known, OTR_TYPE should be @@ -1512,6 +1512,9 @@ struct GTY((chain_next ("%h.next_caller" Optimizers may later redirect direct call to clone, so 1) and 3) do not need to necesarily agree with destination. */ unsigned int speculative : 1; + /* Set to true when caller is a constructor or destructor of polymorphic + type. */ + unsigned in_polymorphic_cdtor : 1; private: /* Remove the edge from the list of the callers of the callee. */ Index: lto-cgraph.c =================================================================== --- lto-cgraph.c (revision 215870) +++ lto-cgraph.c (working copy) @@ -284,6 +284,7 @@ lto_output_edge (struct lto_simple_outpu bp_pack_value (&bp, edge->speculative, 1); bp_pack_value (&bp, edge->call_stmt_cannot_inline_p, 1); bp_pack_value (&bp, edge->can_throw_external, 1); + bp_pack_value (&bp, edge->in_polymorphic_cdtor, 1); if (edge->indirect_unknown_callee) { int flags = edge->indirect_info->ecf_flags; @@ -1366,6 +1367,7 @@ input_edge (struct lto_input_block *ib, edge->inline_failed = inline_failed; edge->call_stmt_cannot_inline_p = bp_unpack_value (&bp, 1); edge->can_throw_external = bp_unpack_value (&bp, 1); + edge->in_polymorphic_cdtor = bp_unpack_value (&bp, 1); if (indirect) { if (bp_unpack_value (&bp, 1)) Index: cgraph.c =================================================================== --- cgraph.c (revision 215870) +++ cgraph.c (working copy) @@ -819,6 +819,12 @@ symbol_table::create_edge (cgraph_node * edge->indirect_inlining_edge = 0; edge->speculative = false; edge->indirect_unknown_callee = indir_unknown_callee; + if (flag_devirtualize && call_stmt && DECL_STRUCT_FUNCTION (caller->decl)) + edge->in_polymorphic_cdtor + = decl_maybe_in_construction_p (NULL, NULL, call_stmt, + caller->decl); + else + edge->in_polymorphic_cdtor = caller->thunk.thunk_p; if (call_stmt && caller->call_site_hash) cgraph_add_edge_to_call_site_hash (edge); @@ -1033,6 +1039,7 @@ cgraph_edge::make_speculative (cgraph_no else e2->can_throw_external = can_throw_external; e2->lto_stmt_uid = lto_stmt_uid; + e2->in_polymorphic_cdtor = in_polymorphic_cdtor; count -= e2->count; frequency -= e2->frequency; symtab->call_edge_duplication_hooks (this, e2); Index: cgraphclones.c =================================================================== --- cgraphclones.c (revision 215870) +++ cgraphclones.c (working copy) @@ -159,6 +159,7 @@ cgraph_edge::clone (cgraph_node *n, gimp new_edge->can_throw_external = can_throw_external; new_edge->call_stmt_cannot_inline_p = call_stmt_cannot_inline_p; new_edge->speculative = speculative; + new_edge->in_polymorphic_cdtor = in_polymorphic_cdtor; if (update_original) { count -= new_edge->count; Index: ipa-prop.c =================================================================== --- ipa-prop.c (revision 215870) +++ ipa-prop.c (working copy) @@ -2652,7 +2652,7 @@ update_jump_functions_after_inlining (st /* TODO: Make type preserved safe WRT contexts. */ if (!dst->value.ancestor.agg_preserved) - ctx.possible_dynamic_type_change (); + ctx.possible_dynamic_type_change (e->in_polymorphic_cdtor); ctx.offset_by (dst->value.ancestor.offset); if (!ctx.useless_p ()) { @@ -2722,7 +2722,7 @@ update_jump_functions_after_inlining (st /* TODO: Make type preserved safe WRT contexts. */ if (!dst->value.ancestor.agg_preserved) - ctx.possible_dynamic_type_change (); + ctx.possible_dynamic_type_change (e->in_polymorphic_cdtor); if (!ctx.useless_p ()) { if (!dst_ctx) @@ -3128,7 +3128,8 @@ try_make_edge_direct_virtual_call (struc /* TODO: We want to record if type change happens. Old code did not do that that seems like a bug. */ - ctx.possible_dynamic_type_change (ie->indirect_info->otr_type); + ctx.possible_dynamic_type_change (ie->in_polymorphic_cdtor, + ie->indirect_info->otr_type); updated = ie->indirect_info->context.combine_with (ctx, ie->indirect_info->otr_type); Index: ipa-polymorphic-call.c =================================================================== --- ipa-polymorphic-call.c (revision 215870) +++ ipa-polymorphic-call.c (working copy) @@ -475,6 +475,11 @@ contains_type_p (tree outer_type, HOST_W (not dynamically allocated) and we want to disprove the fact that it may be in construction at invocation of CALL. + BASE represents memory location where instance is stored. + If BASE is NULL, it is assumed to be global memory. + OUTER_TYPE is known type of the instance or NULL if not + known. + For the variable to be in construction we actually need to be in constructor of corresponding global variable or the inline stack of CALL must contain the constructor. @@ -486,8 +491,9 @@ bool decl_maybe_in_construction_p (tree base, tree outer_type, gimple call, tree function) { - outer_type = TYPE_MAIN_VARIANT (outer_type); - gcc_assert (DECL_P (base)); + if (outer_type) + outer_type = TYPE_MAIN_VARIANT (outer_type); + gcc_assert (!base || DECL_P (base)); /* After inlining the code unification optimizations may invalidate inline stacks. Also we need to give up on global variables after @@ -498,7 +504,7 @@ decl_maybe_in_construction_p (tree base, /* Pure functions can not do any changes on the dynamic type; that require writting to memory. */ - if (!auto_var_in_fn_p (base, function) + if (base && !auto_var_in_fn_p (base, function) && flags_from_decl_or_type (function) & (ECF_PURE | ECF_CONST)) return false; @@ -517,7 +523,7 @@ decl_maybe_in_construction_p (tree base, argument (pointer to the instance). */ fn = DECL_ABSTRACT_ORIGIN (fn); if (!fn - || !is_global_var (base) + || (!base || !is_global_var (base)) || TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE || (!DECL_CXX_CONSTRUCTOR_P (fn) && !DECL_CXX_DESTRUCTOR_P (fn))) @@ -526,17 +532,20 @@ decl_maybe_in_construction_p (tree base, if (flags_from_decl_or_type (fn) & (ECF_PURE | ECF_CONST)) continue; - /* FIXME: this can go away once we have ODR types equivalency on - LTO level. */ - if (in_lto_p && !polymorphic_type_binfo_p (TYPE_BINFO (outer_type))) - return true; tree type = TYPE_MAIN_VARIANT (method_class_type (TREE_TYPE (fn))); - if (types_same_for_odr (type, outer_type)) + + if (!outer_type || !types_odr_comparable (type, outer_type)) + { + if (TREE_CODE (type) == RECORD_TYPE + && TYPE_BINFO (type) + && polymorphic_type_binfo_p (TYPE_BINFO (type))) + return true; + } + else if (types_same_for_odr (type, outer_type)) return true; } - if (TREE_CODE (base) == VAR_DECL - && is_global_var (base)) + if (!base || (TREE_CODE (base) == VAR_DECL && is_global_var (base))) { if (TREE_CODE (TREE_TYPE (function)) != METHOD_TYPE || (!DECL_CXX_CONSTRUCTOR_P (function) @@ -553,12 +562,15 @@ decl_maybe_in_construction_p (tree base, && !DECL_CXX_DESTRUCTOR_P (function))) return false; } - /* FIXME: this can go away once we have ODR types equivalency on - LTO level. */ - if (in_lto_p && !polymorphic_type_binfo_p (TYPE_BINFO (outer_type))) - return true; tree type = TYPE_MAIN_VARIANT (method_class_type (TREE_TYPE (function))); - if (types_same_for_odr (type, outer_type)) + if (!outer_type || !types_odr_comparable (type, outer_type)) + { + if (TREE_CODE (type) == RECORD_TYPE + && TYPE_BINFO (type) + && polymorphic_type_binfo_p (TYPE_BINFO (type))) + return true; + } + else if (types_same_for_odr (type, outer_type)) return true; } return false; @@ -2009,10 +2021,11 @@ ipa_polymorphic_call_context::make_specu type change is not happening. */ void -ipa_polymorphic_call_context::possible_dynamic_type_change (tree otr_type) +ipa_polymorphic_call_context::possible_dynamic_type_change (bool in_poly_cdtor, + tree otr_type) { if (dynamic) make_speculative (otr_type); - else + else if (in_poly_cdtor) maybe_in_construction = true; }