summaryrefslogtreecommitdiff
path: root/gcc/ipa-devirt.c
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2014-07-29 09:39:06 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2014-07-29 09:39:06 +0000
commit283c87508473e0e2710bf7851babf7c49c70ff4d (patch)
tree17a1672ffb371dd2e673d37baa24eda5b181647f /gcc/ipa-devirt.c
parent722b598302cbaebca0283a57a29bc48043f18678 (diff)
downloadgcc-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.c222
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. */