cgraph.h (ipa_polymorphic_call_context): Turn bools into bitfields...

* cgraph.h (ipa_polymorphic_call_context):
	Turn bools into bitfields; add DYNAMIC; make MAKE_SPECULATIVE
	private, add POSSIBLE_DYNAMIC_TYPE_CHANGE.
	* ipa-polymorphic-call.c
	(ipa_polymorphic_call_context::restrict_to_inner_class): Allow accesses
	past end of dynamic types.
	(ipa_polymorphic_call_context::stream_out,
	speculative_outer_type): Stream dynamic flag.
	(ipa_polymorphic_call_context::set_by_decl): Clear DYNAMIC.
	(ipa_polymorphic_call_context::ipa_polymorphic_call_context):
	Clear DYNAMIC.
	(ipa_polymorphic_call_context::get_dynamic_type): Use DYNAMIC;
	set it.
	(ipa_polymorphic_call_context::combine_with): Propagate dynamic.
	* ipa-prop.c (update_jump_functions_after_inlining,
	try_make_edge_direct_virtual_call): Use possible_dynamic_type_change.

From-SVN: r215833
This commit is contained in:
Jan Hubicka 2014-10-03 07:42:47 +02:00 committed by Jan Hubicka
parent 60d9e9fc19
commit 4081ada2c7
4 changed files with 85 additions and 24 deletions

View File

@ -1,3 +1,22 @@
2014-10-02 Jan Hubicka <hubicka@ucw.cz>
* cgraph.h (ipa_polymorphic_call_context):
Turn bools into bitfields; add DYNAMIC; make MAKE_SPECULATIVE
private, add POSSIBLE_DYNAMIC_TYPE_CHANGE.
* ipa-polymorphic-call.c
(ipa_polymorphic_call_context::restrict_to_inner_class): Allow accesses
past end of dynamic types.
(ipa_polymorphic_call_context::stream_out,
speculative_outer_type): Stream dynamic flag.
(ipa_polymorphic_call_context::set_by_decl): Clear DYNAMIC.
(ipa_polymorphic_call_context::ipa_polymorphic_call_context):
Clear DYNAMIC.
(ipa_polymorphic_call_context::get_dynamic_type): Use DYNAMIC;
set it.
(ipa_polymorphic_call_context::combine_with): Propagate dynamic.
* ipa-prop.c (update_jump_functions_after_inlining,
try_make_edge_direct_virtual_call): Use possible_dynamic_type_change.
2014-10-02 Teresa Johnson <tejohnson@google.com>
* tree-ssa-threadupdate.c (freqs_to_counts_path): Scale frequencies

View File

@ -1281,15 +1281,17 @@ public:
tree outer_type;
tree speculative_outer_type;
/* True if outer object may be in construction or destruction. */
bool maybe_in_construction;
unsigned maybe_in_construction : 1;
/* True if outer object may be of derived type. */
bool maybe_derived_type;
unsigned maybe_derived_type : 1;
/* True if speculative outer object may be of derived type. We always
speculate that construction does not happen. */
bool speculative_maybe_derived_type;
unsigned speculative_maybe_derived_type : 1;
/* True if the context is invalid and all calls should be redirected
to BUILTIN_UNREACHABLE. */
bool invalid;
unsigned invalid : 1;
/* True if the outer type is dynamic. */
unsigned dynamic : 1;
/* Build empty "I know nothing" context. */
ipa_polymorphic_call_context ();
@ -1329,12 +1331,9 @@ public:
/* Adjust all offsets in contexts by given number of bits. */
void offset_by (HOST_WIDE_INT);
/* Take non-speculative info, merge it with speculative and clear speculatoin.
Used when we no longer manage to keep track of actual outer type, but we
think it is still there.
If OTR_TYPE is set, the transformation can be done more effectively assuming
that context is going to be used only that way. */
void make_speculative (tree otr_type = NULL);
/* 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);
/* 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
@ -1358,6 +1357,7 @@ private:
bool set_by_invariant (tree, tree, HOST_WIDE_INT);
void clear_outer_type (tree otr_type = NULL);
bool speculation_consistent_p (tree, HOST_WIDE_INT, bool, tree);
void make_speculative (tree otr_type = NULL);
};
/* Structure containing additional information about an indirect call. */
@ -2662,6 +2662,7 @@ ipa_polymorphic_call_context::clear_outer_type (tree otr_type)
offset = 0;
maybe_derived_type = true;
maybe_in_construction = true;
dynamic = true;
}
/* Adjust all offsets in contexts by OFF bits. */

View File

@ -167,8 +167,11 @@ ipa_polymorphic_call_context::restrict_to_inner_class (tree otr_type,
type = otr_type;
cur_offset = 0;
/* If derived type is not allowed, we know that the context is invalid. */
if (!maybe_derived_type)
/* If derived type is not allowed, we know that the context is invalid.
For dynamic types, we really do not have information about
size of the memory location. It is possible that completely
different type is stored after outer_type. */
if (!maybe_derived_type && !dynamic)
{
clear_speculation ();
invalid = true;
@ -575,7 +578,7 @@ ipa_polymorphic_call_context::dump (FILE *f) const
fprintf (f, "nothing known");
if (outer_type || offset)
{
fprintf (f, "Outer type:");
fprintf (f, "Outer type%s:", dynamic ? " (dynamic)":"");
print_generic_expr (f, outer_type, TDF_SLIM);
if (maybe_derived_type)
fprintf (f, " (or a derived type)");
@ -618,6 +621,7 @@ ipa_polymorphic_call_context::stream_out (struct output_block *ob) const
bp_pack_value (&bp, maybe_in_construction, 1);
bp_pack_value (&bp, maybe_derived_type, 1);
bp_pack_value (&bp, speculative_maybe_derived_type, 1);
bp_pack_value (&bp, dynamic, 1);
bp_pack_value (&bp, outer_type != NULL, 1);
bp_pack_value (&bp, offset != 0, 1);
bp_pack_value (&bp, speculative_outer_type != NULL, 1);
@ -648,6 +652,7 @@ ipa_polymorphic_call_context::stream_in (struct lto_input_block *ib,
maybe_in_construction = bp_unpack_value (&bp, 1);
maybe_derived_type = bp_unpack_value (&bp, 1);
speculative_maybe_derived_type = bp_unpack_value (&bp, 1);
dynamic = bp_unpack_value (&bp, 1);
bool outer_type_p = bp_unpack_value (&bp, 1);
bool offset_p = bp_unpack_value (&bp, 1);
bool speculative_outer_type_p = bp_unpack_value (&bp, 1);
@ -679,10 +684,16 @@ void
ipa_polymorphic_call_context::set_by_decl (tree base, HOST_WIDE_INT off)
{
gcc_assert (DECL_P (base));
clear_speculation ();
if (!contains_polymorphic_type_p (TREE_TYPE (base)))
{
clear_outer_type ();
offset = off;
return;
}
outer_type = TYPE_MAIN_VARIANT (TREE_TYPE (base));
offset = off;
clear_speculation ();
/* Make very conservative assumption that all objects
may be in construction.
@ -690,6 +701,7 @@ ipa_polymorphic_call_context::set_by_decl (tree base, HOST_WIDE_INT off)
get_dynamic_type or decl_maybe_in_construction_p. */
maybe_in_construction = true;
maybe_derived_type = false;
dynamic = false;
}
/* CST is an invariant (address of decl), try to get meaningful
@ -832,7 +844,7 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
return;
}
set_by_decl (base, offset + offset2);
if (maybe_in_construction && stmt)
if (outer_type && maybe_in_construction && stmt)
maybe_in_construction
= decl_maybe_in_construction_p (base,
outer_type,
@ -889,6 +901,8 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
return;
}
dynamic = true;
/* If the function is constructor or destructor, then
the type is possibly in construction, but we know
it is not derived type. */
@ -1192,6 +1206,7 @@ record_known_type (struct type_change_info *tci, tree type, HOST_WIDE_INT offset
context.outer_type = type;
context.maybe_in_construction = false;
context.maybe_derived_type = false;
context.dynamic = true;
/* If we failed to find the inner type, we know that the call
would be undefined for type produced here. */
if (!context.restrict_to_inner_class (tci->otr_type))
@ -1540,6 +1555,7 @@ ipa_polymorphic_call_context::get_dynamic_type (tree instance,
if (!tci.type_maybe_changed
|| (outer_type
&& !dynamic
&& !tci.seen_unanalyzed_store
&& !tci.multiple_types_encountered
&& offset == tci.offset
@ -1563,6 +1579,7 @@ ipa_polymorphic_call_context::get_dynamic_type (tree instance,
{
outer_type = TYPE_MAIN_VARIANT (tci.known_current_type);
offset = tci.known_current_offset;
dynamic = true;
maybe_in_construction = false;
maybe_derived_type = false;
if (dump_file)
@ -1599,6 +1616,12 @@ ipa_polymorphic_call_context::speculation_consistent_p (tree spec_outer_type,
{
if (!flag_devirtualize_speculatively)
return false;
/* Non-polymorphic types are useless for deriving likely polymorphic
call targets. */
if (!spec_outer_type || !contains_polymorphic_type_p (spec_outer_type))
return false;
/* If we know nothing, speculation is always good. */
if (!outer_type)
return true;
@ -1614,11 +1637,6 @@ ipa_polymorphic_call_context::speculation_consistent_p (tree spec_outer_type,
if (types_must_be_same_for_odr (spec_outer_type, outer_type))
return maybe_derived_type && !spec_maybe_derived_type;
/* Non-polymorphic types are useless for deriving likely polymorphic
call targets. */
if (!contains_polymorphic_type_p (spec_outer_type))
return false;
/* If speculation does not contain the type in question, ignore it. */
if (otr_type
&& !contains_type_p (spec_outer_type, spec_offset, otr_type, false, true))
@ -1792,6 +1810,7 @@ ipa_polymorphic_call_context::combine_with (ipa_polymorphic_call_context ctx,
{
outer_type = ctx.outer_type;
offset = ctx.offset;
dynamic = ctx.dynamic;
maybe_in_construction = ctx.maybe_in_construction;
maybe_derived_type = ctx.maybe_derived_type;
updated = true;
@ -1822,6 +1841,11 @@ ipa_polymorphic_call_context::combine_with (ipa_polymorphic_call_context ctx,
updated = true;
maybe_derived_type = false;
}
if (dynamic && !ctx.dynamic)
{
updated = true;
dynamic = false;
}
}
/* If we know the type precisely, there is not much to improve. */
else if (!maybe_derived_type && !maybe_in_construction
@ -1856,6 +1880,7 @@ ipa_polymorphic_call_context::combine_with (ipa_polymorphic_call_context ctx,
outer_type = ctx.outer_type;
maybe_derived_type = ctx.maybe_derived_type;
offset = ctx.offset;
dynamic = ctx.dynamic;
updated = true;
}
@ -1906,6 +1931,7 @@ ipa_polymorphic_call_context::combine_with (ipa_polymorphic_call_context ctx,
maybe_in_construction = ctx.maybe_in_construction;
maybe_derived_type = ctx.maybe_derived_type;
offset = ctx.offset;
dynamic = ctx.dynamic;
updated = true;
}
}
@ -1952,7 +1978,10 @@ invalidate:
/* Take non-speculative info, merge it with speculative and clear speculation.
Used when we no longer manage to keep track of actual outer type, but we
think it is still there. */
think it is still there.
If OTR_TYPE is set, the transformation can be done more effectively assuming
that context is going to be used only that way. */
void
ipa_polymorphic_call_context::make_speculative (tree otr_type)
@ -1975,3 +2004,15 @@ ipa_polymorphic_call_context::make_speculative (tree otr_type)
spec_maybe_derived_type,
otr_type);
}
/* Use when we can not track dynamic type change. This speculatively assume
type change is not happening. */
void
ipa_polymorphic_call_context::possible_dynamic_type_change (tree otr_type)
{
if (dynamic)
make_speculative (otr_type);
else
maybe_in_construction = true;
}

View File

@ -2652,7 +2652,7 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
/* TODO: Make type preserved safe WRT contexts. */
if (!dst->value.ancestor.agg_preserved)
ctx.make_speculative ();
ctx.possible_dynamic_type_change ();
ctx.offset_by (dst->value.ancestor.offset);
if (!ctx.useless_p ())
{
@ -2722,7 +2722,7 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
/* TODO: Make type preserved safe WRT contexts. */
if (!dst->value.ancestor.agg_preserved)
ctx.make_speculative ();
ctx.possible_dynamic_type_change ();
if (!ctx.useless_p ())
{
if (!dst_ctx)
@ -3128,7 +3128,7 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
/* TODO: We want to record if type change happens.
Old code did not do that that seems like a bug. */
ctx.make_speculative (ie->indirect_info->otr_type);
ctx.possible_dynamic_type_change (ie->indirect_info->otr_type);
updated = ie->indirect_info->context.combine_with
(ctx, ie->indirect_info->otr_type);