summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog25
-rw-r--r--gcc/cgraph.c8
-rw-r--r--gcc/cgraph.h5
-rw-r--r--gcc/ipa-devirt.c222
-rw-r--r--gcc/ipa-prop.c8
-rw-r--r--gcc/ipa-utils.h26
6 files changed, 251 insertions, 43 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8f1a133261e..484a5e18101 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,30 @@
2014-07-28 Jan Hubicka <hubicka@ucw.cz>
+ * 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.
+
+2014-07-28 Jan Hubicka <hubicka@ucw.cz>
+
* gimple-fold.c (fold_gimple_assign): Fix condition guarding
ipa-devirt path; fix thinko there.
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index a5d07496f0a..52f9985694a 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -973,10 +973,15 @@ cgraph_node::create_indirect_edge (gimple call_stmt, int ecf_flags,
edge->indirect_info->otr_token = otr_token;
edge->indirect_info->otr_type = otr_type;
edge->indirect_info->outer_type = context.outer_type;
+ edge->indirect_info->speculative_outer_type
+ = context.speculative_outer_type;
edge->indirect_info->offset = context.offset;
+ edge->indirect_info->speculative_offset = context.speculative_offset;
edge->indirect_info->maybe_in_construction
= context.maybe_in_construction;
edge->indirect_info->maybe_derived_type = context.maybe_derived_type;
+ edge->indirect_info->speculative_maybe_derived_type
+ = context.speculative_maybe_derived_type;
}
edge->next_callee = indirect_calls;
@@ -3043,12 +3048,9 @@ cgraph_node::get_body (void)
data = lto_get_section_data (file_data, LTO_section_function_body,
name, &len);
if (!data)
- {
- debug ();
fatal_error ("%s: section %s is missing",
file_data->file_name,
name);
- }
gcc_assert (DECL_STRUCT_FUNCTION (decl) == NULL);
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index f8f76c42d6c..d8651e2f6f3 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -1243,11 +1243,11 @@ struct GTY(()) cgraph_indirect_call_info
was actually used in the polymorphic resides within a larger structure.
If agg_contents is set, the field contains the offset within the aggregate
from which the address to call was loaded. */
- HOST_WIDE_INT offset;
+ HOST_WIDE_INT offset, speculative_offset;
/* OBJ_TYPE_REF_TOKEN of a polymorphic call (if polymorphic is set). */
HOST_WIDE_INT otr_token;
/* Type of the object from OBJ_TYPE_REF_OBJECT. */
- tree otr_type, outer_type;
+ tree otr_type, outer_type, speculative_outer_type;
/* Index of the parameter that is called. */
int param_index;
/* ECF flags determined from the caller. */
@@ -1270,6 +1270,7 @@ struct GTY(()) cgraph_indirect_call_info
unsigned by_ref : 1;
unsigned int maybe_in_construction : 1;
unsigned int maybe_derived_type : 1;
+ unsigned int speculative_maybe_derived_type : 1;
};
struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"))) cgraph_edge {
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. */
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 9c65076440b..576e59acc20 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -4693,6 +4693,7 @@ ipa_write_indirect_edge_info (struct output_block *ob,
bp_pack_value (&bp, ii->by_ref, 1);
bp_pack_value (&bp, ii->maybe_in_construction, 1);
bp_pack_value (&bp, ii->maybe_derived_type, 1);
+ bp_pack_value (&bp, ii->speculative_maybe_derived_type, 1);
streamer_write_bitpack (&bp);
if (ii->polymorphic)
@@ -4700,6 +4701,9 @@ ipa_write_indirect_edge_info (struct output_block *ob,
streamer_write_hwi (ob, ii->otr_token);
stream_write_tree (ob, ii->otr_type, true);
stream_write_tree (ob, ii->outer_type, true);
+ stream_write_tree (ob, ii->speculative_outer_type, true);
+ if (ii->speculative_outer_type)
+ streamer_write_hwi (ob, ii->speculative_offset);
}
}
@@ -4723,11 +4727,15 @@ ipa_read_indirect_edge_info (struct lto_input_block *ib,
ii->by_ref = bp_unpack_value (&bp, 1);
ii->maybe_in_construction = bp_unpack_value (&bp, 1);
ii->maybe_derived_type = bp_unpack_value (&bp, 1);
+ ii->speculative_maybe_derived_type = bp_unpack_value (&bp, 1);
if (ii->polymorphic)
{
ii->otr_token = (HOST_WIDE_INT) streamer_read_hwi (ib);
ii->otr_type = stream_read_tree (ib, data_in);
ii->outer_type = stream_read_tree (ib, data_in);
+ ii->speculative_outer_type = stream_read_tree (ib, data_in);
+ if (ii->speculative_outer_type)
+ ii->speculative_offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
}
}
diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h
index bb2e0d50d6b..12543048289 100644
--- a/gcc/ipa-utils.h
+++ b/gcc/ipa-utils.h
@@ -38,13 +38,19 @@ struct ipa_dfs_info {
type inheritance graph. */
struct ipa_polymorphic_call_context {
/* The called object appears in an object of type OUTER_TYPE
- at offset OFFSET. */
+ at offset OFFSET. When information is not 100% reliable, we
+ use SPECULATIVE_OUTER_TYPE and SPECULATIVE_OFFSET. */
HOST_WIDE_INT offset;
+ HOST_WIDE_INT speculative_offset;
tree outer_type;
+ tree speculative_outer_type;
/* True if outer object may be in construction or destruction. */
bool maybe_in_construction;
/* True if outer object may be of derived type. */
bool maybe_derived_type;
+ /* True if speculative outer object may be of derived type. We always
+ speculate that construction does not happen. */
+ bool speculative_maybe_derived_type;
};
/* Context representing "I know nothing". */
@@ -89,6 +95,7 @@ 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, 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);
@@ -114,9 +121,12 @@ possible_polymorphic_call_targets (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->maybe_derived_type,
+ e->indirect_info->speculative_maybe_derived_type};
return possible_polymorphic_call_targets (e->indirect_info->otr_type,
e->indirect_info->otr_token,
context,
@@ -153,9 +163,12 @@ 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->maybe_derived_type,
+ e->indirect_info->speculative_maybe_derived_type};
dump_possible_polymorphic_call_targets (f, e->indirect_info->otr_type,
e->indirect_info->otr_token,
context);
@@ -168,10 +181,11 @@ inline bool
possible_polymorphic_call_target_p (struct cgraph_edge *e,
struct cgraph_node *n)
{
- ipa_polymorphic_call_context context = {e->indirect_info->offset,
- e->indirect_info->outer_type,
+ 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};
+ e->indirect_info->maybe_derived_type,
+ false};
return possible_polymorphic_call_target_p (e->indirect_info->otr_type,
e->indirect_info->otr_token,
context, n);