summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2014-10-03 05:42:47 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2014-10-03 05:42:47 +0000
commitc500eb01b146e0778253c9342b31cf2fb116dcdd (patch)
treeb9737fb423d0d6d55ae7190b20d8a112e6ff3062 /gcc
parent73f46f88d1ad13e19c8b754746c0bdd8a0d02645 (diff)
downloadgcc-c500eb01b146e0778253c9342b31cf2fb116dcdd.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@215833 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog19
-rw-r--r--gcc/cgraph.h21
-rw-r--r--gcc/ipa-polymorphic-call.c63
-rw-r--r--gcc/ipa-prop.c6
4 files changed, 85 insertions, 24 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 75dd0b5ceac..955d57a4a87 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index fb41b01cf34..8bc6fc945d1 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -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. */
diff --git a/gcc/ipa-polymorphic-call.c b/gcc/ipa-polymorphic-call.c
index e71d3ba6661..4f0c360b8cf 100644
--- a/gcc/ipa-polymorphic-call.c
+++ b/gcc/ipa-polymorphic-call.c
@@ -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;
+}
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index b2430b8dff5..5ac5dc5200b 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -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);