mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-12-04 17:24:15 +08:00
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:
parent
60d9e9fc19
commit
4081ada2c7
@ -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>
|
2014-10-02 Teresa Johnson <tejohnson@google.com>
|
||||||
|
|
||||||
* tree-ssa-threadupdate.c (freqs_to_counts_path): Scale frequencies
|
* tree-ssa-threadupdate.c (freqs_to_counts_path): Scale frequencies
|
||||||
|
21
gcc/cgraph.h
21
gcc/cgraph.h
@ -1281,15 +1281,17 @@ public:
|
|||||||
tree outer_type;
|
tree outer_type;
|
||||||
tree speculative_outer_type;
|
tree speculative_outer_type;
|
||||||
/* True if outer object may be in construction or destruction. */
|
/* 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. */
|
/* 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
|
/* True if speculative outer object may be of derived type. We always
|
||||||
speculate that construction does not happen. */
|
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
|
/* True if the context is invalid and all calls should be redirected
|
||||||
to BUILTIN_UNREACHABLE. */
|
to BUILTIN_UNREACHABLE. */
|
||||||
bool invalid;
|
unsigned invalid : 1;
|
||||||
|
/* True if the outer type is dynamic. */
|
||||||
|
unsigned dynamic : 1;
|
||||||
|
|
||||||
/* Build empty "I know nothing" context. */
|
/* Build empty "I know nothing" context. */
|
||||||
ipa_polymorphic_call_context ();
|
ipa_polymorphic_call_context ();
|
||||||
@ -1329,12 +1331,9 @@ public:
|
|||||||
|
|
||||||
/* Adjust all offsets in contexts by given number of bits. */
|
/* Adjust all offsets in contexts by given number of bits. */
|
||||||
void offset_by (HOST_WIDE_INT);
|
void offset_by (HOST_WIDE_INT);
|
||||||
/* Take non-speculative info, merge it with speculative and clear speculatoin.
|
/* Use when we can not track dynamic type change. This speculatively assume
|
||||||
Used when we no longer manage to keep track of actual outer type, but we
|
type change is not happening. */
|
||||||
think it is still there.
|
void possible_dynamic_type_change (tree otr_type = NULL);
|
||||||
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);
|
|
||||||
/* Assume that both THIS and a given context is valid and strenghten THIS
|
/* Assume that both THIS and a given context is valid and strenghten THIS
|
||||||
if possible. Return true if any strenghtening was made.
|
if possible. Return true if any strenghtening was made.
|
||||||
If actual type the context is being used in is known, OTR_TYPE should be
|
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);
|
bool set_by_invariant (tree, tree, HOST_WIDE_INT);
|
||||||
void clear_outer_type (tree otr_type = NULL);
|
void clear_outer_type (tree otr_type = NULL);
|
||||||
bool speculation_consistent_p (tree, HOST_WIDE_INT, bool, tree);
|
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. */
|
/* Structure containing additional information about an indirect call. */
|
||||||
@ -2662,6 +2662,7 @@ ipa_polymorphic_call_context::clear_outer_type (tree otr_type)
|
|||||||
offset = 0;
|
offset = 0;
|
||||||
maybe_derived_type = true;
|
maybe_derived_type = true;
|
||||||
maybe_in_construction = true;
|
maybe_in_construction = true;
|
||||||
|
dynamic = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adjust all offsets in contexts by OFF bits. */
|
/* Adjust all offsets in contexts by OFF bits. */
|
||||||
|
@ -167,8 +167,11 @@ ipa_polymorphic_call_context::restrict_to_inner_class (tree otr_type,
|
|||||||
type = otr_type;
|
type = otr_type;
|
||||||
cur_offset = 0;
|
cur_offset = 0;
|
||||||
|
|
||||||
/* If derived type is not allowed, we know that the context is invalid. */
|
/* If derived type is not allowed, we know that the context is invalid.
|
||||||
if (!maybe_derived_type)
|
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 ();
|
clear_speculation ();
|
||||||
invalid = true;
|
invalid = true;
|
||||||
@ -575,7 +578,7 @@ ipa_polymorphic_call_context::dump (FILE *f) const
|
|||||||
fprintf (f, "nothing known");
|
fprintf (f, "nothing known");
|
||||||
if (outer_type || offset)
|
if (outer_type || offset)
|
||||||
{
|
{
|
||||||
fprintf (f, "Outer type:");
|
fprintf (f, "Outer type%s:", dynamic ? " (dynamic)":"");
|
||||||
print_generic_expr (f, outer_type, TDF_SLIM);
|
print_generic_expr (f, outer_type, TDF_SLIM);
|
||||||
if (maybe_derived_type)
|
if (maybe_derived_type)
|
||||||
fprintf (f, " (or a 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_in_construction, 1);
|
||||||
bp_pack_value (&bp, maybe_derived_type, 1);
|
bp_pack_value (&bp, maybe_derived_type, 1);
|
||||||
bp_pack_value (&bp, speculative_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, outer_type != NULL, 1);
|
||||||
bp_pack_value (&bp, offset != 0, 1);
|
bp_pack_value (&bp, offset != 0, 1);
|
||||||
bp_pack_value (&bp, speculative_outer_type != NULL, 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_in_construction = bp_unpack_value (&bp, 1);
|
||||||
maybe_derived_type = bp_unpack_value (&bp, 1);
|
maybe_derived_type = bp_unpack_value (&bp, 1);
|
||||||
speculative_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 outer_type_p = bp_unpack_value (&bp, 1);
|
||||||
bool offset_p = bp_unpack_value (&bp, 1);
|
bool offset_p = bp_unpack_value (&bp, 1);
|
||||||
bool speculative_outer_type_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)
|
ipa_polymorphic_call_context::set_by_decl (tree base, HOST_WIDE_INT off)
|
||||||
{
|
{
|
||||||
gcc_assert (DECL_P (base));
|
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));
|
outer_type = TYPE_MAIN_VARIANT (TREE_TYPE (base));
|
||||||
offset = off;
|
offset = off;
|
||||||
clear_speculation ();
|
|
||||||
/* Make very conservative assumption that all objects
|
/* Make very conservative assumption that all objects
|
||||||
may be in construction.
|
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. */
|
get_dynamic_type or decl_maybe_in_construction_p. */
|
||||||
maybe_in_construction = true;
|
maybe_in_construction = true;
|
||||||
maybe_derived_type = false;
|
maybe_derived_type = false;
|
||||||
|
dynamic = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CST is an invariant (address of decl), try to get meaningful
|
/* 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;
|
return;
|
||||||
}
|
}
|
||||||
set_by_decl (base, offset + offset2);
|
set_by_decl (base, offset + offset2);
|
||||||
if (maybe_in_construction && stmt)
|
if (outer_type && maybe_in_construction && stmt)
|
||||||
maybe_in_construction
|
maybe_in_construction
|
||||||
= decl_maybe_in_construction_p (base,
|
= decl_maybe_in_construction_p (base,
|
||||||
outer_type,
|
outer_type,
|
||||||
@ -889,6 +901,8 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dynamic = true;
|
||||||
|
|
||||||
/* If the function is constructor or destructor, then
|
/* If the function is constructor or destructor, then
|
||||||
the type is possibly in construction, but we know
|
the type is possibly in construction, but we know
|
||||||
it is not derived type. */
|
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.outer_type = type;
|
||||||
context.maybe_in_construction = false;
|
context.maybe_in_construction = false;
|
||||||
context.maybe_derived_type = false;
|
context.maybe_derived_type = false;
|
||||||
|
context.dynamic = true;
|
||||||
/* If we failed to find the inner type, we know that the call
|
/* If we failed to find the inner type, we know that the call
|
||||||
would be undefined for type produced here. */
|
would be undefined for type produced here. */
|
||||||
if (!context.restrict_to_inner_class (tci->otr_type))
|
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
|
if (!tci.type_maybe_changed
|
||||||
|| (outer_type
|
|| (outer_type
|
||||||
|
&& !dynamic
|
||||||
&& !tci.seen_unanalyzed_store
|
&& !tci.seen_unanalyzed_store
|
||||||
&& !tci.multiple_types_encountered
|
&& !tci.multiple_types_encountered
|
||||||
&& offset == tci.offset
|
&& 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);
|
outer_type = TYPE_MAIN_VARIANT (tci.known_current_type);
|
||||||
offset = tci.known_current_offset;
|
offset = tci.known_current_offset;
|
||||||
|
dynamic = true;
|
||||||
maybe_in_construction = false;
|
maybe_in_construction = false;
|
||||||
maybe_derived_type = false;
|
maybe_derived_type = false;
|
||||||
if (dump_file)
|
if (dump_file)
|
||||||
@ -1599,6 +1616,12 @@ ipa_polymorphic_call_context::speculation_consistent_p (tree spec_outer_type,
|
|||||||
{
|
{
|
||||||
if (!flag_devirtualize_speculatively)
|
if (!flag_devirtualize_speculatively)
|
||||||
return false;
|
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 we know nothing, speculation is always good. */
|
||||||
if (!outer_type)
|
if (!outer_type)
|
||||||
return true;
|
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))
|
if (types_must_be_same_for_odr (spec_outer_type, outer_type))
|
||||||
return maybe_derived_type && !spec_maybe_derived_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 speculation does not contain the type in question, ignore it. */
|
||||||
if (otr_type
|
if (otr_type
|
||||||
&& !contains_type_p (spec_outer_type, spec_offset, otr_type, false, true))
|
&& !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;
|
outer_type = ctx.outer_type;
|
||||||
offset = ctx.offset;
|
offset = ctx.offset;
|
||||||
|
dynamic = ctx.dynamic;
|
||||||
maybe_in_construction = ctx.maybe_in_construction;
|
maybe_in_construction = ctx.maybe_in_construction;
|
||||||
maybe_derived_type = ctx.maybe_derived_type;
|
maybe_derived_type = ctx.maybe_derived_type;
|
||||||
updated = true;
|
updated = true;
|
||||||
@ -1822,6 +1841,11 @@ ipa_polymorphic_call_context::combine_with (ipa_polymorphic_call_context ctx,
|
|||||||
updated = true;
|
updated = true;
|
||||||
maybe_derived_type = false;
|
maybe_derived_type = false;
|
||||||
}
|
}
|
||||||
|
if (dynamic && !ctx.dynamic)
|
||||||
|
{
|
||||||
|
updated = true;
|
||||||
|
dynamic = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* If we know the type precisely, there is not much to improve. */
|
/* If we know the type precisely, there is not much to improve. */
|
||||||
else if (!maybe_derived_type && !maybe_in_construction
|
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;
|
outer_type = ctx.outer_type;
|
||||||
maybe_derived_type = ctx.maybe_derived_type;
|
maybe_derived_type = ctx.maybe_derived_type;
|
||||||
offset = ctx.offset;
|
offset = ctx.offset;
|
||||||
|
dynamic = ctx.dynamic;
|
||||||
updated = true;
|
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_in_construction = ctx.maybe_in_construction;
|
||||||
maybe_derived_type = ctx.maybe_derived_type;
|
maybe_derived_type = ctx.maybe_derived_type;
|
||||||
offset = ctx.offset;
|
offset = ctx.offset;
|
||||||
|
dynamic = ctx.dynamic;
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1952,7 +1978,10 @@ invalidate:
|
|||||||
|
|
||||||
/* Take non-speculative info, merge it with speculative and clear speculation.
|
/* 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
|
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
|
void
|
||||||
ipa_polymorphic_call_context::make_speculative (tree otr_type)
|
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,
|
spec_maybe_derived_type,
|
||||||
otr_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;
|
||||||
|
}
|
||||||
|
@ -2652,7 +2652,7 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
|
|||||||
|
|
||||||
/* TODO: Make type preserved safe WRT contexts. */
|
/* TODO: Make type preserved safe WRT contexts. */
|
||||||
if (!dst->value.ancestor.agg_preserved)
|
if (!dst->value.ancestor.agg_preserved)
|
||||||
ctx.make_speculative ();
|
ctx.possible_dynamic_type_change ();
|
||||||
ctx.offset_by (dst->value.ancestor.offset);
|
ctx.offset_by (dst->value.ancestor.offset);
|
||||||
if (!ctx.useless_p ())
|
if (!ctx.useless_p ())
|
||||||
{
|
{
|
||||||
@ -2722,7 +2722,7 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
|
|||||||
|
|
||||||
/* TODO: Make type preserved safe WRT contexts. */
|
/* TODO: Make type preserved safe WRT contexts. */
|
||||||
if (!dst->value.ancestor.agg_preserved)
|
if (!dst->value.ancestor.agg_preserved)
|
||||||
ctx.make_speculative ();
|
ctx.possible_dynamic_type_change ();
|
||||||
if (!ctx.useless_p ())
|
if (!ctx.useless_p ())
|
||||||
{
|
{
|
||||||
if (!dst_ctx)
|
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.
|
/* TODO: We want to record if type change happens.
|
||||||
Old code did not do that that seems like a bug. */
|
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
|
updated = ie->indirect_info->context.combine_with
|
||||||
(ctx, ie->indirect_info->otr_type);
|
(ctx, ie->indirect_info->otr_type);
|
||||||
|
Loading…
Reference in New Issue
Block a user