diff options
author | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-07-29 09:39:06 +0000 |
---|---|---|
committer | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-07-29 09:39:06 +0000 |
commit | 283c87508473e0e2710bf7851babf7c49c70ff4d (patch) | |
tree | 17a1672ffb371dd2e673d37baa24eda5b181647f /gcc/ipa-devirt.c | |
parent | 722b598302cbaebca0283a57a29bc48043f18678 (diff) | |
download | gcc-283c87508473e0e2710bf7851babf7c49c70ff4d.tar.gz |
* cgraph.c (cgraph_node::create_indirect_edge): Copy speculative data.
* cgraph.h (cgraph_indirect_call_info): Add speculative data.
* gimple-fold.c (fold_gimple_assign): Fix check for virtual
call.
* ipa-devirt.c (ipa_dummy_polymorphic_call_context): Update
(contains_type_p): Forward declare.
(polymorphic_call_target_hasher::hash): Hash speculative info.
(polymorphic_call_target_hasher::equal): Compare speculative info.
(get_class_context): Handle speuclation.
(contains_type_p): Update.
(get_polymorphic_call_info_for_decl): Update.
(walk_ssa_copies): Break out from ...
(get_polymorphic_call_info): ... here; set speculative context
before giving up.
* ipa-prop.c (ipa_write_indirect_edge_info, ipa_read_indirect_edge_info):
Stream speculative context.
* ipa-utils.h (ipa_polymorphic_call_context): Add speculative info
(SPECULATIVE_OFFSET, SPECULATIVE_OUTER_TYPE,
SPECULATIVE_MAYBE_DERIVED_TYPE).
(possible_polymorphic_call_targets overriders): Update.
(dump_possible_polymorphic_call_targets overriders): Update.
(dump_possible_polymorphic_call_target_p overriders): Update.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@213152 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/ipa-devirt.c')
-rw-r--r-- | gcc/ipa-devirt.c | 222 |
1 files changed, 190 insertions, 32 deletions
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c index 127d58d775d..4b5b2a659c0 100644 --- a/gcc/ipa-devirt.c +++ b/gcc/ipa-devirt.c @@ -141,7 +141,7 @@ static bool odr_violation_reported = false; /* Dummy polymorphic call context. */ const ipa_polymorphic_call_context ipa_dummy_polymorphic_call_context - = {0, NULL, false, true}; + = {0, 0, NULL, NULL, false, true, true}; /* Pointer set of all call targets appearing in the cache. */ static pointer_set_t *cached_polymorphic_call_targets; @@ -175,6 +175,8 @@ struct GTY(()) odr_type_d bool odr_violated; }; +static bool contains_type_p (tree, HOST_WIDE_INT, tree); + /* Return true if BINFO corresponds to a type with virtual methods. @@ -1641,8 +1643,16 @@ polymorphic_call_target_hasher::hash (const value_type *odr_query) hash = iterative_hash_hashval_t (TYPE_UID (odr_query->context.outer_type), hash); hash = iterative_hash_host_wide_int (odr_query->context.offset, hash); + if (odr_query->context.speculative_outer_type) + { + hash = iterative_hash_hashval_t + (TYPE_UID (odr_query->context.speculative_outer_type), hash); + hash = iterative_hash_host_wide_int (odr_query->context.speculative_offset, + hash); + } return iterative_hash_hashval_t - (((int)odr_query->context.maybe_in_construction << 1) + (((int)odr_query->context.maybe_in_construction << 2) + | ((int)odr_query->context.speculative_maybe_derived_type << 1) | (int)odr_query->context.maybe_derived_type, hash); } @@ -1654,10 +1664,14 @@ polymorphic_call_target_hasher::equal (const value_type *t1, { return (t1->type == t2->type && t1->otr_token == t2->otr_token && t1->context.offset == t2->context.offset + && t1->context.speculative_offset == t2->context.speculative_offset && t1->context.outer_type == t2->context.outer_type + && t1->context.speculative_outer_type == t2->context.speculative_outer_type && t1->context.maybe_in_construction == t2->context.maybe_in_construction - && t1->context.maybe_derived_type == t2->context.maybe_derived_type); + && t1->context.maybe_derived_type == t2->context.maybe_derived_type + && (t1->context.speculative_maybe_derived_type + == t2->context.speculative_maybe_derived_type)); } /* Remove entry in polymorphic call target cache hash. */ @@ -1750,9 +1764,42 @@ get_class_context (ipa_polymorphic_call_context *context, { tree type = context->outer_type; HOST_WIDE_INT offset = context->offset; - + bool speculative = false; + bool speculation_valid = false; + bool valid = false; + + if (!context->outer_type) + { + context->outer_type = expected_type; + context->offset = offset; + } + /* See if speculative type seem to be derrived from outer_type. + Then speculation is valid only if it really is a derivate and derived types + are allowed. + + The test does not really look for derivate, but also accepts the case where + outer_type is a field of speculative_outer_type. In this case eiter + 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; + else + { + context->speculative_outer_type = NULL; + context->speculative_offset = 0; + context->speculative_maybe_derived_type = false; + } + /* Find the sub-object the constant actually refers to and mark whether it is - an artificial one (as opposed to a user-defined one). */ + an artificial one (as opposed to a user-defined one). + + This loop is performed twice; first time for outer_type and second time + for speculative_outer_type. The second iteration has SPECULATIVE set. */ while (true) { HOST_WIDE_INT pos, size; @@ -1762,12 +1809,51 @@ get_class_context (ipa_polymorphic_call_context *context, if (TREE_CODE (type) == TREE_CODE (expected_type) && types_same_for_odr (type, expected_type)) { - /* Type can not contain itself on an non-zero offset. In that case - just give up. */ - if (offset != 0) - goto give_up; - gcc_assert (offset == 0); - return true; + if (speculative) + { + gcc_assert (speculation_valid); + 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))) + { + context->speculative_outer_type = NULL; + context->speculative_offset = 0; + } + return true; + } + else + { + /* Type can not contain itself on an non-zero offset. In that case + just give up. */ + if (offset != 0) + { + valid = false; + goto give_up; + } + valid = true; + /* If speculation is not valid or we determined type precisely, + we are done. */ + if (!speculation_valid + || !context->maybe_derived_type) + { + context->speculative_outer_type = NULL; + context->speculative_offset = 0; + return true; + } + /* Otherwise look into speculation now. */ + else + { + speculative = true; + type = context->speculative_outer_type; + offset = context->speculative_offset; + continue; + } + } } /* Walk fields and find corresponding on at OFFSET. */ @@ -1792,11 +1878,20 @@ get_class_context (ipa_polymorphic_call_context *context, /* DECL_ARTIFICIAL represents a basetype. */ if (!DECL_ARTIFICIAL (fld)) { - context->outer_type = type; - context->offset = offset; - /* As soon as we se an field containing the type, - we know we are not looking for derivations. */ - context->maybe_derived_type = false; + if (!speculative) + { + context->outer_type = type; + context->offset = offset; + /* As soon as we se an field containing the type, + we know we are not looking for derivations. */ + context->maybe_derived_type = false; + } + else + { + context->speculative_outer_type = type; + context->speculative_offset = offset; + context->speculative_maybe_derived_type = false; + } } } else if (TREE_CODE (type) == ARRAY_TYPE) @@ -1809,9 +1904,18 @@ get_class_context (ipa_polymorphic_call_context *context, goto give_up; offset = offset % tree_to_shwi (TYPE_SIZE (subtype)); type = subtype; - context->outer_type = type; - context->offset = offset; - context->maybe_derived_type = false; + if (!speculative) + { + context->outer_type = type; + context->offset = offset; + context->maybe_derived_type = false; + } + else + { + context->speculative_outer_type = type; + context->speculative_offset = offset; + context->speculative_maybe_derived_type = false; + } } /* Give up on anything else. */ else @@ -1821,6 +1925,11 @@ 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: + context->speculative_outer_type = NULL; + context->speculative_offset = 0; + context->speculative_maybe_derived_type = false; + if (valid) + return true; context->outer_type = expected_type; context->offset = 0; context->maybe_derived_type = true; @@ -1831,7 +1940,8 @@ give_up: if ((TREE_CODE (type) != RECORD_TYPE || !TYPE_BINFO (type) || !polymorphic_type_binfo_p (TYPE_BINFO (type))) - && (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST + && (!TYPE_SIZE (type) + || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST || (offset + tree_to_uhwi (TYPE_SIZE (expected_type)) <= tree_to_uhwi (TYPE_SIZE (type))))) return true; @@ -1844,9 +1954,9 @@ static bool contains_type_p (tree outer_type, HOST_WIDE_INT offset, tree otr_type) { - ipa_polymorphic_call_context context = {offset, + ipa_polymorphic_call_context context = {offset, 0, TYPE_MAIN_VARIANT (outer_type), - false, true}; + NULL, false, true, false}; return get_class_context (&context, otr_type); } @@ -2054,6 +2164,9 @@ get_polymorphic_call_info_for_decl (ipa_polymorphic_call_context *context, context->outer_type = TYPE_MAIN_VARIANT (TREE_TYPE (base)); context->offset = offset; + context->speculative_outer_type = NULL; + context->speculative_offset = 0; + context->speculative_maybe_derived_type = true; /* Make very conservative assumption that all objects may be in construction. TODO: ipa-prop already contains code to tell better. @@ -2093,6 +2206,26 @@ get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *context, return true; } +/* See if OP is SSA name initialized as a copy or by single assignment. + If so, walk the SSA graph up. */ + +static tree +walk_ssa_copies (tree op) +{ + STRIP_NOPS (op); + while (TREE_CODE (op) == SSA_NAME + && !SSA_NAME_IS_DEFAULT_DEF (op) + && SSA_NAME_DEF_STMT (op) + && gimple_assign_single_p (SSA_NAME_DEF_STMT (op))) + { + if (gimple_assign_load_p (SSA_NAME_DEF_STMT (op))) + return op; + op = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (op)); + STRIP_NOPS (op); + } + return op; +} + /* Given REF call in FNDECL, determine class of the polymorphic call (OTR_TYPE), its token (OTR_TOKEN) and CONTEXT. CALL is optional argument giving the actual statement (usually call) where @@ -2112,6 +2245,9 @@ get_polymorphic_call_info (tree fndecl, *otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (ref)); /* Set up basic info in case we find nothing interesting in the analysis. */ + context->speculative_outer_type = NULL; + context->speculative_offset = 0; + context->speculative_maybe_derived_type = true; context->outer_type = TYPE_MAIN_VARIANT (*otr_type); context->offset = 0; base_pointer = OBJ_TYPE_REF_OBJECT (ref); @@ -2121,15 +2257,8 @@ get_polymorphic_call_info (tree fndecl, /* Walk SSA for outer object. */ do { - if (TREE_CODE (base_pointer) == SSA_NAME - && !SSA_NAME_IS_DEFAULT_DEF (base_pointer) - && SSA_NAME_DEF_STMT (base_pointer) - && gimple_assign_single_p (SSA_NAME_DEF_STMT (base_pointer))) - { - base_pointer = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (base_pointer)); - STRIP_NOPS (base_pointer); - } - else if (TREE_CODE (base_pointer) == ADDR_EXPR) + base_pointer = walk_ssa_copies (base_pointer); + if (TREE_CODE (base_pointer) == ADDR_EXPR) { HOST_WIDE_INT size, max_size; HOST_WIDE_INT offset2; @@ -2175,7 +2304,7 @@ get_polymorphic_call_info (tree fndecl, context->outer_type, call, current_function_decl); - return NULL; + return base_pointer; } else break; @@ -2259,6 +2388,35 @@ get_polymorphic_call_info (tree fndecl, return base_pointer; } } + + tree base_type = TREE_TYPE (base_pointer); + + if (TREE_CODE (base_pointer) == SSA_NAME + && SSA_NAME_IS_DEFAULT_DEF (base_pointer) + && TREE_CODE (SSA_NAME_VAR (base_pointer)) != PARM_DECL) + { + /* Use OTR_TOKEN = INT_MAX as a marker of probably type inconsistent + code sequences; we arrange the calls to be builtin_unreachable + later. */ + *otr_token = INT_MAX; + return base_pointer; + } + if (TREE_CODE (base_pointer) == SSA_NAME + && SSA_NAME_DEF_STMT (base_pointer) + && gimple_assign_single_p (SSA_NAME_DEF_STMT (base_pointer))) + base_type = TREE_TYPE (gimple_assign_rhs1 + (SSA_NAME_DEF_STMT (base_pointer))); + + if (POINTER_TYPE_P (base_type) + && contains_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (base_type)), + context->offset, + *otr_type)) + { + context->speculative_outer_type = TYPE_MAIN_VARIANT + (TREE_TYPE (base_type)); + context->speculative_offset = context->offset; + context->speculative_maybe_derived_type = true; + } /* TODO: There are multiple ways to derive a type. For instance if BASE_POINTER is passed to an constructor call prior our refernece. We do not make this type of flow sensitive analysis yet. */ |