From 3a4f036a4c4f4671a4672ab5b48cf9bdb79457f7 Mon Sep 17 00:00:00 2001 From: hubicka Date: Sat, 16 Aug 2014 09:10:23 +0000 Subject: [PATCH] * ipa-utils.h (ipa_polymorphic_call_context): Turn into class; add ctors. (possible_polymorphic_call_targets, dump_possible_polymorphic_call_targets, possible_polymorphic_call_target_p, possible_polymorphic_call_target_p): Simplify. (get_dynamic_type): Remove. * ipa-devirt.c (ipa_dummy_polymorphic_call_context): Remove. (clear_speculation): Bring to ipa-deivrt.h (get_class_context): Rename to ... (ipa_polymorphic_call_context::restrict_to_inner_class): ... this one. (contains_type_p): Update. (get_dynamic_type): Rename to ... ipa_polymorphic_call_context::get_dynamic_type(): ... this one. (possible_polymorphic_call_targets): UPdate. * tree-ssa-pre.c (eliminate_dom_walker::before_dom_children): Update. * ipa-prop.c (ipa_analyze_call_uses): Update. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@214060 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 17 +++++ gcc/ipa-devirt.c | 198 ++++++++++++++++++++++++----------------------------- gcc/ipa-prop.c | 6 +- gcc/ipa-utils.h | 82 +++++++++++++++------- gcc/tree-ssa-pre.c | 3 +- 5 files changed, 170 insertions(+), 136 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0e6a9294f50..13a15ef7bf9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2014-08-15 Jan Hubicka + + * ipa-utils.h (ipa_polymorphic_call_context): Turn into class; add ctors. + (possible_polymorphic_call_targets, dump_possible_polymorphic_call_targets, + possible_polymorphic_call_target_p, possible_polymorphic_call_target_p): Simplify. + (get_dynamic_type): Remove. + * ipa-devirt.c (ipa_dummy_polymorphic_call_context): Remove. + (clear_speculation): Bring to ipa-deivrt.h + (get_class_context): Rename to ... + (ipa_polymorphic_call_context::restrict_to_inner_class): ... this one. + (contains_type_p): Update. + (get_dynamic_type): Rename to ... + ipa_polymorphic_call_context::get_dynamic_type(): ... this one. + (possible_polymorphic_call_targets): UPdate. + * tree-ssa-pre.c (eliminate_dom_walker::before_dom_children): Update. + * ipa-prop.c (ipa_analyze_call_uses): Update. + 2014-08-15 Oleg Endo * doc/invoke.texi (SH options): Document missing processor variant diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c index ff206eee259..ba57b86cf4d 100644 --- a/gcc/ipa-devirt.c +++ b/gcc/ipa-devirt.c @@ -141,10 +141,6 @@ static bool odr_types_equivalent_p (tree, tree, bool, bool *, static bool odr_violation_reported = false; -/* Dummy polymorphic call context. */ - -const ipa_polymorphic_call_context ipa_dummy_polymorphic_call_context - = {0, 0, NULL, NULL, false, true, true}; /* Pointer set of all call targets appearing in the cache. */ static hash_set *cached_polymorphic_call_targets; @@ -1853,23 +1849,13 @@ contains_polymorphic_type_p (const_tree type) return false; } -/* Clear speculative info from CONTEXT. */ - -static void -clear_speculation (ipa_polymorphic_call_context *context) -{ - context->speculative_outer_type = NULL; - context->speculative_offset = 0; - context->speculative_maybe_derived_type = false; -} - -/* CONTEXT->OUTER_TYPE is a type of memory object where object of EXPECTED_TYPE - is contained at CONTEXT->OFFSET. Walk the memory representation of - CONTEXT->OUTER_TYPE and find the outermost class type that match - EXPECTED_TYPE or contain EXPECTED_TYPE as a base. Update CONTEXT +/* THIS->OUTER_TYPE is a type of memory object where object of EXPECTED_TYPE + is contained at THIS->OFFSET. Walk the memory representation of + THIS->OUTER_TYPE and find the outermost class type that match + EXPECTED_TYPE or contain EXPECTED_TYPE as a base. Update THIS to represent it. - For example when CONTEXT represents type + For example when THIS represents type class A { int a; @@ -1880,32 +1866,31 @@ clear_speculation (ipa_polymorphic_call_context *context) sizeof(int). If we can not find corresponding class, give up by setting - CONTEXT->OUTER_TYPE to EXPECTED_TYPE and CONTEXT->OFFSET to NULL. + THIS->OUTER_TYPE to EXPECTED_TYPE and THIS->OFFSET to NULL. Return true when lookup was sucesful. */ -static bool -get_class_context (ipa_polymorphic_call_context *context, - tree expected_type) +bool +ipa_polymorphic_call_context::restrict_to_inner_class (tree expected_type) { - tree type = context->outer_type; - HOST_WIDE_INT offset = context->offset; + tree type = outer_type; + HOST_WIDE_INT cur_offset = offset; bool speculative = false; bool speculation_valid = false; bool valid = false; - if (!context->outer_type) + if (!outer_type) { - type = context->outer_type = expected_type; - context->offset = offset = 0; + type = outer_type = expected_type; + offset = cur_offset = 0; } - if (context->speculative_outer_type == context->outer_type - && (!context->maybe_derived_type - || context->speculative_maybe_derived_type)) + if (speculative_outer_type == outer_type + && (!maybe_derived_type + || speculative_maybe_derived_type)) { - context->speculative_outer_type = NULL; - context->speculative_offset = 0; - context->speculative_maybe_derived_type = false; + speculative_outer_type = NULL; + speculative_offset = 0; + speculative_maybe_derived_type = false; } /* See if speculative type seem to be derrived from outer_type. @@ -1917,14 +1902,14 @@ get_class_context (ipa_polymorphic_call_context *context, MAYBE_DERIVED_TYPE is false and we have full non-speculative information or the loop bellow will correctly update SPECULATIVE_OUTER_TYPE and SPECULATIVE_MAYBE_DERIVED_TYPE. */ - if (context->speculative_outer_type - && context->speculative_offset >= context->offset - && contains_type_p (context->speculative_outer_type, - context->offset - context->speculative_offset, - context->outer_type)) - speculation_valid = context->maybe_derived_type; + if (speculative_outer_type + && speculative_offset >= offset + && contains_type_p (speculative_outer_type, + offset - speculative_offset, + outer_type)) + speculation_valid = maybe_derived_type; else - clear_speculation (context); + clear_speculation (); /* Find the sub-object the constant actually refers to and mark whether it is an artificial one (as opposed to a user-defined one). @@ -1950,19 +1935,19 @@ get_class_context (ipa_polymorphic_call_context *context, gcc_assert (valid); /* If we did not match the offset, just give up on speculation. */ - if (offset != 0 - || (types_same_for_odr (context->speculative_outer_type, - context->outer_type) - && (context->maybe_derived_type - == context->speculative_maybe_derived_type))) - clear_speculation (context); + if (cur_offset != 0 + || (types_same_for_odr (speculative_outer_type, + outer_type) + && (maybe_derived_type + == speculative_maybe_derived_type))) + clear_speculation (); return true; } else { /* Type can not contain itself on an non-zero offset. In that case just give up. */ - if (offset != 0) + if (cur_offset != 0) { valid = false; goto give_up; @@ -1971,17 +1956,17 @@ get_class_context (ipa_polymorphic_call_context *context, /* If speculation is not valid or we determined type precisely, we are done. */ if (!speculation_valid - || !context->maybe_derived_type) + || !maybe_derived_type) { - clear_speculation (context); + clear_speculation (); return true; } /* Otherwise look into speculation now. */ else { speculative = true; - type = context->speculative_outer_type; - offset = context->speculative_offset; + type = speculative_outer_type; + cur_offset = speculative_offset; continue; } } @@ -1997,7 +1982,7 @@ get_class_context (ipa_polymorphic_call_context *context, pos = int_bit_position (fld); size = tree_to_uhwi (DECL_SIZE (fld)); - if (pos <= offset && (pos + size) > offset) + if (pos <= cur_offset && (pos + size) > cur_offset) break; } @@ -2005,23 +1990,23 @@ get_class_context (ipa_polymorphic_call_context *context, goto give_up; type = TYPE_MAIN_VARIANT (TREE_TYPE (fld)); - offset -= pos; + cur_offset -= pos; /* DECL_ARTIFICIAL represents a basetype. */ if (!DECL_ARTIFICIAL (fld)) { if (!speculative) { - context->outer_type = type; - context->offset = offset; + outer_type = type; + offset = cur_offset; /* As soon as we se an field containing the type, we know we are not looking for derivations. */ - context->maybe_derived_type = false; + maybe_derived_type = false; } else { - context->speculative_outer_type = type; - context->speculative_offset = offset; - context->speculative_maybe_derived_type = false; + speculative_outer_type = type; + speculative_offset = cur_offset; + speculative_maybe_derived_type = false; } } } @@ -2033,19 +2018,19 @@ get_class_context (ipa_polymorphic_call_context *context, if (!tree_fits_shwi_p (TYPE_SIZE (subtype)) || !tree_to_shwi (TYPE_SIZE (subtype)) <= 0) goto give_up; - offset = offset % tree_to_shwi (TYPE_SIZE (subtype)); + cur_offset = cur_offset % tree_to_shwi (TYPE_SIZE (subtype)); type = subtype; if (!speculative) { - context->outer_type = type; - context->offset = offset; - context->maybe_derived_type = false; + outer_type = type; + offset = cur_offset; + maybe_derived_type = false; } else { - context->speculative_outer_type = type; - context->speculative_offset = offset; - context->speculative_maybe_derived_type = false; + speculative_outer_type = type; + speculative_offset = cur_offset; + speculative_maybe_derived_type = false; } } /* Give up on anything else. */ @@ -2056,13 +2041,13 @@ get_class_context (ipa_polymorphic_call_context *context, /* If we failed to find subtype we look for, give up and fall back to the most generic query. */ give_up: - clear_speculation (context); + clear_speculation (); if (valid) return true; - context->outer_type = expected_type; - context->offset = 0; - context->maybe_derived_type = true; - context->maybe_in_construction = true; + outer_type = expected_type; + offset = 0; + maybe_derived_type = true; + maybe_in_construction = true; /* POD can be changed to an instance of a polymorphic type by placement new. Here we play safe and assume that any non-polymorphic type is POD. */ @@ -2071,7 +2056,7 @@ give_up: || !polymorphic_type_binfo_p (TYPE_BINFO (type))) && (!TYPE_SIZE (type) || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST - || (offset + tree_to_uhwi (TYPE_SIZE (expected_type)) <= + || (cur_offset + tree_to_uhwi (TYPE_SIZE (expected_type)) <= tree_to_uhwi (TYPE_SIZE (type))))) return true; return false; @@ -2083,10 +2068,10 @@ static bool contains_type_p (tree outer_type, HOST_WIDE_INT offset, tree otr_type) { - ipa_polymorphic_call_context context = {offset, 0, - TYPE_MAIN_VARIANT (outer_type), - NULL, false, true, false}; - return get_class_context (&context, otr_type); + ipa_polymorphic_call_context context; + context.offset = offset; + context.outer_type = TYPE_MAIN_VARIANT (outer_type); + return context.restrict_to_inner_class (otr_type); } /* Lookup base of BINFO that has virtual table VTABLE with OFFSET. */ @@ -2834,7 +2819,7 @@ check_stmt_for_type_change (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data) return false; } -/* CONTEXT is polymorphic call context obtained from get_polymorphic_context. +/* THIS is polymorphic call context obtained from get_polymorphic_context. OTR_OBJECT is pointer to the instance returned by OBJ_TYPE_REF_OBJECT. INSTANCE is pointer to the outer instance as returned by get_polymorphic_context. To avoid creation of temporary expressions, @@ -2851,11 +2836,10 @@ check_stmt_for_type_change (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data) So it is not suitable for use withing fold_stmt and similar uses. */ bool -get_dynamic_type (tree instance, - ipa_polymorphic_call_context *context, - tree otr_object, - tree otr_type, - gimple call) +ipa_polymorphic_call_context::get_dynamic_type (tree instance, + tree otr_object, + tree otr_type, + gimple call) { struct type_change_info tci; ao_ref ao; @@ -2863,7 +2847,7 @@ get_dynamic_type (tree instance, tree instance_ref = NULL; gimple stmt = call; - if (!context->maybe_in_construction && !context->maybe_derived_type) + if (!maybe_in_construction && !maybe_derived_type) return false; /* We need to obtain refernce to virtual table pointer. It is better @@ -2916,11 +2900,11 @@ get_dynamic_type (tree instance, or from INSTANCE with offset OFFSET. */ if (base_ref && ((TREE_CODE (base_ref) == MEM_REF - && ((offset2 == context->offset + && ((offset2 == offset && TREE_OPERAND (base_ref, 0) == instance) || (!offset2 && TREE_OPERAND (base_ref, 0) == otr_object))) || (DECL_P (instance) && base_ref == instance - && offset2 == context->offset))) + && offset2 == offset))) { stmt = SSA_NAME_DEF_STMT (ref); instance_ref = ref_exp; @@ -2959,13 +2943,13 @@ get_dynamic_type (tree instance, print_generic_expr (dump_file, otr_object, TDF_SLIM); fprintf (dump_file, " Outer instance pointer: "); print_generic_expr (dump_file, instance, TDF_SLIM); - fprintf (dump_file, " offset: %i (bits)", (int)context->offset); + fprintf (dump_file, " offset: %i (bits)", (int)offset); fprintf (dump_file, " vtbl reference: "); print_generic_expr (dump_file, instance_ref, TDF_SLIM); fprintf (dump_file, "\n"); } - tci.offset = context->offset; + tci.offset = offset; tci.instance = instance; tci.vtbl_ptr_ref = instance_ref; gcc_assert (TREE_CODE (instance) != MEM_REF); @@ -3021,17 +3005,17 @@ get_dynamic_type (tree instance, and we can stop, we will never see the calls into constructors of sub-objects in this code. - Therefore if the static outer type was found (context->outer_type) + Therefore if the static outer type was found (outer_type) we can safely ignore tci.speculative that is set on calls and give up only if there was dyanmic type store that may affect given variable (seen_unanalyzed_store) */ if (!tci.type_maybe_changed) { - if (!context->outer_type || tci.seen_unanalyzed_store) + if (!outer_type || tci.seen_unanalyzed_store) return false; - if (context->maybe_in_construction) - context->maybe_in_construction = false; + if (maybe_in_construction) + maybe_in_construction = false; if (dump_file) fprintf (dump_file, " No dynamic type change found.\n"); return true; @@ -3044,25 +3028,25 @@ get_dynamic_type (tree instance, if (!tci.speculative /* Again in instances located in static storage we are interested only in constructor stores. */ - || (context->outer_type + || (outer_type && !tci.seen_unanalyzed_store - && context->offset == tci.offset + && offset == tci.offset && types_same_for_odr (tci.known_current_type, - context->outer_type))) + outer_type))) { - context->outer_type = tci.known_current_type; - context->offset = tci.known_current_offset; - context->maybe_in_construction = false; - context->maybe_derived_type = false; + outer_type = tci.known_current_type; + offset = tci.known_current_offset; + maybe_in_construction = false; + maybe_derived_type = false; if (dump_file) fprintf (dump_file, " Determined dynamic type.\n"); } - else if (!context->speculative_outer_type - || context->speculative_maybe_derived_type) + else if (!speculative_outer_type + || speculative_maybe_derived_type) { - context->speculative_outer_type = tci.known_current_type; - context->speculative_offset = tci.known_current_offset; - context->speculative_maybe_derived_type = false; + speculative_outer_type = tci.known_current_type; + speculative_offset = tci.known_current_offset; + speculative_maybe_derived_type = false; if (dump_file) fprintf (dump_file, " Determined speculative dynamic type.\n"); } @@ -3253,7 +3237,7 @@ possible_polymorphic_call_targets (tree otr_type, /* Do not bother to compute speculative info when user do not asks for it. */ if (!speculative_targetsp || !context.speculative_outer_type) - clear_speculation (&context); + context.clear_speculation (); type = get_odr_type (otr_type, true); @@ -3263,7 +3247,7 @@ possible_polymorphic_call_targets (tree otr_type, /* Lookup the outer class type we want to walk. */ if ((context.outer_type || context.speculative_outer_type) - && !get_class_context (&context, otr_type)) + && !context.restrict_to_inner_class (otr_type)) { if (completep) *completep = false; @@ -3274,7 +3258,7 @@ possible_polymorphic_call_targets (tree otr_type, return nodes; } - /* Check that get_class_context kept the main variant. */ + /* Check that restrict_to_inner_class kept the main variant. */ gcc_assert (!context.outer_type || TYPE_MAIN_VARIANT (context.outer_type) == context.outer_type); diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index 612f2276844..a4556f1a494 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -2356,9 +2356,9 @@ ipa_analyze_call_uses (struct func_body_info *fbi, gimple call) &otr_type, &otr_token, &context, call); - if (get_dynamic_type (instance, &context, - OBJ_TYPE_REF_OBJECT (target), - otr_type, call)) + if (context.get_dynamic_type (instance, + OBJ_TYPE_REF_OBJECT (target), + otr_type, call)) { gcc_assert (TREE_CODE (otr_type) == RECORD_TYPE); cs->indirect_info->polymorphic = true; diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h index 30adc6907d2..d4980ebaf13 100644 --- a/gcc/ipa-utils.h +++ b/gcc/ipa-utils.h @@ -36,7 +36,9 @@ struct ipa_dfs_info { /* Context of polymorphic call. This is used by ipa-devirt walkers of the type inheritance graph. */ -struct ipa_polymorphic_call_context { + +class ipa_polymorphic_call_context { +public: /* The called object appears in an object of type OUTER_TYPE at offset OFFSET. When information is not 100% reliable, we use SPECULATIVE_OUTER_TYPE and SPECULATIVE_OFFSET. */ @@ -51,10 +53,58 @@ struct ipa_polymorphic_call_context { /* True if speculative outer object may be of derived type. We always speculate that construction does not happen. */ bool speculative_maybe_derived_type; + + /* Build empty "I know nothing" context. */ + ipa_polymorphic_call_context (); + + /* Build polymorphic call context for indirect call E. */ + ipa_polymorphic_call_context (cgraph_edge *e); + + /* Make context non-speculative. */ + void clear_speculation (); + + /* Walk container types and modify context to point to actual class + containing EXPECTED_TYPE as base class. */ + bool restrict_to_inner_class (tree expected_type); + + /* Look for vtable stores or constructor calls to work out dynamic type + of memory location. */ + bool get_dynamic_type (tree, tree, tree, gimple); }; -/* Context representing "I know nothing". */ -extern const ipa_polymorphic_call_context ipa_dummy_polymorphic_call_context; +/* Build polymorphic call context for indirect call E. */ + +inline +ipa_polymorphic_call_context::ipa_polymorphic_call_context (cgraph_edge *e) +{ + offset = e->indirect_info->offset; + speculative_offset = e->indirect_info->speculative_offset; + outer_type = e->indirect_info->outer_type; + speculative_outer_type = e->indirect_info->speculative_outer_type; + maybe_in_construction = e->indirect_info->maybe_in_construction; + maybe_derived_type = e->indirect_info->maybe_derived_type; + speculative_maybe_derived_type = e->indirect_info->speculative_maybe_derived_type; +} + +/* Build empty "I know nothing" context. */ + +inline +ipa_polymorphic_call_context::ipa_polymorphic_call_context () + : offset(0), speculative_offset(0), outer_type(NULL), + speculative_outer_type(NULL), maybe_in_construction(false), + maybe_derived_type(false), speculative_maybe_derived_type(false) +{ +} + +/* Make context non-speculative. */ + +inline void +ipa_polymorphic_call_context::clear_speculation () +{ + speculative_outer_type = NULL; + speculative_offset = 0; + speculative_maybe_derived_type = false; +} /* In ipa-utils.c */ void ipa_print_order (FILE*, const char *, struct cgraph_node**, int); @@ -95,7 +145,6 @@ tree get_polymorphic_call_info (tree, tree, tree *, HOST_WIDE_INT *, ipa_polymorphic_call_context *, gimple call = NULL); -bool get_dynamic_type (tree, ipa_polymorphic_call_context *, tree, tree, gimple); bool get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *, tree, tree, HOST_WIDE_INT); bool decl_maybe_in_construction_p (tree, tree, gimple, tree); @@ -121,13 +170,7 @@ possible_polymorphic_call_targets (struct cgraph_edge *e, int *nonconstruction_targets = NULL) { gcc_checking_assert (e->indirect_info->polymorphic); - ipa_polymorphic_call_context context = {e->indirect_info->offset, - e->indirect_info->speculative_offset, - e->indirect_info->outer_type, - e->indirect_info->speculative_outer_type, - e->indirect_info->maybe_in_construction, - e->indirect_info->maybe_derived_type, - e->indirect_info->speculative_maybe_derived_type}; + ipa_polymorphic_call_context context(e); return possible_polymorphic_call_targets (e->indirect_info->otr_type, e->indirect_info->otr_token, context, @@ -163,13 +206,7 @@ inline void dump_possible_polymorphic_call_targets (FILE *f, struct cgraph_edge *e) { gcc_checking_assert (e->indirect_info->polymorphic); - ipa_polymorphic_call_context context = {e->indirect_info->offset, - e->indirect_info->speculative_offset, - e->indirect_info->outer_type, - e->indirect_info->speculative_outer_type, - e->indirect_info->maybe_in_construction, - e->indirect_info->maybe_derived_type, - e->indirect_info->speculative_maybe_derived_type}; + ipa_polymorphic_call_context context(e); dump_possible_polymorphic_call_targets (f, e->indirect_info->otr_type, e->indirect_info->otr_token, context); @@ -182,11 +219,7 @@ inline bool possible_polymorphic_call_target_p (struct cgraph_edge *e, struct cgraph_node *n) { - ipa_polymorphic_call_context context = {e->indirect_info->offset, 0, - e->indirect_info->outer_type, NULL, - e->indirect_info->maybe_in_construction, - e->indirect_info->maybe_derived_type, - false}; + ipa_polymorphic_call_context context(e); return possible_polymorphic_call_target_p (e->indirect_info->otr_type, e->indirect_info->otr_token, context, n); @@ -199,10 +232,11 @@ inline bool possible_polymorphic_call_target_p (tree call, struct cgraph_node *n) { + ipa_polymorphic_call_context context; return possible_polymorphic_call_target_p (obj_type_ref_class (call), tree_to_uhwi (OBJ_TYPE_REF_TOKEN (call)), - ipa_dummy_polymorphic_call_context, + context, n); } #endif /* GCC_IPA_UTILS_H */ diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index 0e968d5e22c..f191ec05af3 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -4374,8 +4374,7 @@ eliminate_dom_walker::before_dom_children (basic_block b) fn, &otr_type, &otr_token, &context, stmt); - get_dynamic_type (instance, &context, - OBJ_TYPE_REF_OBJECT (fn), otr_type, stmt); + context.get_dynamic_type (instance, OBJ_TYPE_REF_OBJECT (fn), otr_type, stmt); vec targets = possible_polymorphic_call_targets (obj_type_ref_class (fn), -- 2.11.4.GIT