From 4081ada2c7ae718f509dc403f83a4a08f2a6fe4a Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Fri, 3 Oct 2014 07:42:47 +0200 Subject: [PATCH] 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 --- gcc/ChangeLog | 19 ++++++++++++ gcc/cgraph.h | 21 +++++++------ gcc/ipa-polymorphic-call.c | 63 +++++++++++++++++++++++++++++++------- gcc/ipa-prop.c | 6 ++-- 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 + + * 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 * 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); -- 2.30.2