Jan Hubicka
2014-10-03 19:56:47 UTC
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;
}
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;
}