Commit 5ce97055 by Jan Hubicka Committed by Jan Hubicka

ipa-prop.h (ipa_get_controlled_uses): Add hack to avoid ICE when speculation is added.


	* ipa-prop.h (ipa_get_controlled_uses): Add hack to avoid ICE
	when speculation is added.
	(ipa_edge_args): Add polymorphic_call_contexts.
	(ipa_get_ith_polymorhic_call_context): New accesor.
	(ipa_make_edge_direct_to_target): Add SPECULATIVE parameter.
	* ipa-prop.c (ipa_print_node_jump_functions_for_edge): Print contexts.
	(ipa_compute_jump_functions_for_edge): Compute contexts.
	(update_jump_functions_after_inlining): Update contexts.
	(ipa_make_edge_direct_to_target): Add SPECULATIVE argument;
	update dumping; add speculative edge creation.
	(try_make_edge_direct_virtual_call): Add CTX_PTR parameter; handle
	context updating.
	(update_indirect_edges_after_inlining): Pass down context.
	(ipa_edge_duplication_hook): Duplicate contexts.
	(ipa_write_node_info): Stream out contexts.
	(ipa_read_node_info): Stream in contexts.
	* ipa-devirt.c (type_all_derivations_known_p): Avoid ICE on non-ODR
	types.
	(try_speculative_devirtualization): New function.
	* ipa-utils.h (try_speculative_devirtualization): Declare.

From-SVN: r215794
parent 9fbbb20d
2014-10-01 Jan Hubicka <hubicka@ucw.cz> 2014-10-01 Jan Hubicka <hubicka@ucw.cz>
* ipa-prop.h (ipa_get_controlled_uses): Add hack to avoid ICE
when speculation is added.
(ipa_edge_args): Add polymorphic_call_contexts.
(ipa_get_ith_polymorhic_call_context): New accesor.
(ipa_make_edge_direct_to_target): Add SPECULATIVE parameter.
* ipa-prop.c (ipa_print_node_jump_functions_for_edge): Print contexts.
(ipa_compute_jump_functions_for_edge): Compute contexts.
(update_jump_functions_after_inlining): Update contexts.
(ipa_make_edge_direct_to_target): Add SPECULATIVE argument;
update dumping; add speculative edge creation.
(try_make_edge_direct_virtual_call): Add CTX_PTR parameter; handle
context updating.
(update_indirect_edges_after_inlining): Pass down context.
(ipa_edge_duplication_hook): Duplicate contexts.
(ipa_write_node_info): Stream out contexts.
(ipa_read_node_info): Stream in contexts.
* ipa-devirt.c (type_all_derivations_known_p): Avoid ICE on non-ODR
types.
(try_speculative_devirtualization): New function.
* ipa-utils.h (try_speculative_devirtualization): Declare.
2014-10-01 Jan Hubicka <hubicka@ucw.cz>
* ipa.c (walk_polymorphic_call_targets): Avoid ICE when * ipa.c (walk_polymorphic_call_targets): Avoid ICE when
dumping during WPA. dumping during WPA.
...@@ -224,6 +224,9 @@ type_all_derivations_known_p (const_tree t) ...@@ -224,6 +224,9 @@ type_all_derivations_known_p (const_tree t)
return true; return true;
if (flag_ltrans) if (flag_ltrans)
return false; return false;
/* Non-C++ types may have IDENTIFIER_NODE here, do not crash. */
if (!TYPE_NAME (t) || TREE_CODE (TYPE_NAME (t)) != TYPE_DECL)
return true;
if (type_in_anonymous_namespace_p (t)) if (type_in_anonymous_namespace_p (t))
return true; return true;
return (decl_function_context (TYPE_NAME (t)) != NULL); return (decl_function_context (TYPE_NAME (t)) != NULL);
...@@ -2734,6 +2737,43 @@ decl_warning_cmp (const void *p1, const void *p2) ...@@ -2734,6 +2737,43 @@ decl_warning_cmp (const void *p1, const void *p2)
return t2->count - t1->count; return t2->count - t1->count;
} }
/* Try speculatively devirtualize call to OTR_TYPE with OTR_TOKEN with
context CTX. */
struct cgraph_node *
try_speculative_devirtualization (tree otr_type, HOST_WIDE_INT otr_token,
ipa_polymorphic_call_context ctx)
{
vec <cgraph_node *>targets
= possible_polymorphic_call_targets
(otr_type, otr_token, ctx, NULL, NULL, true);
unsigned int i;
struct cgraph_node *likely_target = NULL;
for (i = 0; i < targets.length (); i++)
if (likely_target_p (targets[i]))
{
if (likely_target)
return NULL;
likely_target = targets[i];
}
if (!likely_target
||!likely_target->definition
|| DECL_EXTERNAL (likely_target->decl))
return NULL;
/* Don't use an implicitly-declared destructor (c++/58678). */
struct cgraph_node *non_thunk_target
= likely_target->function_symbol ();
if (DECL_ARTIFICIAL (non_thunk_target->decl))
return NULL;
if (likely_target->get_availability () <= AVAIL_INTERPOSABLE
&& likely_target->can_be_discarded_p ())
return NULL;
return likely_target;
}
/* The ipa-devirt pass. /* The ipa-devirt pass.
When polymorphic call has only one likely target in the unit, When polymorphic call has only one likely target in the unit,
turn it into speculative call. */ turn it into speculative call. */
......
...@@ -364,6 +364,8 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs) ...@@ -364,6 +364,8 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
fprintf (f, "\n"); fprintf (f, "\n");
} }
} }
if (IPA_EDGE_REF (cs)->polymorphic_call_contexts)
ipa_get_ith_polymorhic_call_context (IPA_EDGE_REF (cs), i)->dump (f);
} }
} }
...@@ -1876,10 +1878,13 @@ ipa_compute_jump_functions_for_edge (struct func_body_info *fbi, ...@@ -1876,10 +1878,13 @@ ipa_compute_jump_functions_for_edge (struct func_body_info *fbi,
struct ipa_edge_args *args = IPA_EDGE_REF (cs); struct ipa_edge_args *args = IPA_EDGE_REF (cs);
gimple call = cs->call_stmt; gimple call = cs->call_stmt;
int n, arg_num = gimple_call_num_args (call); int n, arg_num = gimple_call_num_args (call);
bool useful_context = false;
if (arg_num == 0 || args->jump_functions) if (arg_num == 0 || args->jump_functions)
return; return;
vec_safe_grow_cleared (args->jump_functions, arg_num); vec_safe_grow_cleared (args->jump_functions, arg_num);
if (flag_devirtualize)
vec_safe_grow_cleared (args->polymorphic_call_contexts, arg_num);
if (gimple_call_internal_p (call)) if (gimple_call_internal_p (call))
return; return;
...@@ -1891,6 +1896,16 @@ ipa_compute_jump_functions_for_edge (struct func_body_info *fbi, ...@@ -1891,6 +1896,16 @@ ipa_compute_jump_functions_for_edge (struct func_body_info *fbi,
struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, n); struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, n);
tree arg = gimple_call_arg (call, n); tree arg = gimple_call_arg (call, n);
tree param_type = ipa_get_callee_param_type (cs, n); tree param_type = ipa_get_callee_param_type (cs, n);
if (flag_devirtualize && POINTER_TYPE_P (TREE_TYPE (arg)))
{
struct ipa_polymorphic_call_context context (cs->caller->decl,
arg, cs->call_stmt,
NULL);
/* TODO: We should also handle dynamic types. */
*ipa_get_ith_polymorhic_call_context (args, n) = context;
if (!context.useless_p ())
useful_context = true;
}
if (is_gimple_ip_invariant (arg)) if (is_gimple_ip_invariant (arg))
ipa_set_jf_constant (jfunc, arg, cs); ipa_set_jf_constant (jfunc, arg, cs);
...@@ -1963,6 +1978,8 @@ ipa_compute_jump_functions_for_edge (struct func_body_info *fbi, ...@@ -1963,6 +1978,8 @@ ipa_compute_jump_functions_for_edge (struct func_body_info *fbi,
|| POINTER_TYPE_P (param_type))) || POINTER_TYPE_P (param_type)))
determine_locally_known_aggregate_parts (call, arg, param_type, jfunc); determine_locally_known_aggregate_parts (call, arg, param_type, jfunc);
} }
if (!useful_context)
vec_free (args->polymorphic_call_contexts);
} }
/* Compute jump functions for all edges - both direct and indirect - outgoing /* Compute jump functions for all edges - both direct and indirect - outgoing
...@@ -2608,11 +2625,15 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs, ...@@ -2608,11 +2625,15 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
struct ipa_jump_func *dst = ipa_get_ith_jump_func (args, i); struct ipa_jump_func *dst = ipa_get_ith_jump_func (args, i);
struct ipa_polymorphic_call_context *dst_ctx
= ipa_get_ith_polymorhic_call_context (args, i);
if (dst->type == IPA_JF_ANCESTOR) if (dst->type == IPA_JF_ANCESTOR)
{ {
struct ipa_jump_func *src; struct ipa_jump_func *src;
int dst_fid = dst->value.ancestor.formal_id; int dst_fid = dst->value.ancestor.formal_id;
struct ipa_polymorphic_call_context *src_ctx
= ipa_get_ith_polymorhic_call_context (top, dst_fid);
/* Variable number of arguments can cause havoc if we try to access /* Variable number of arguments can cause havoc if we try to access
one that does not exist in the inlined edge. So make sure we one that does not exist in the inlined edge. So make sure we
...@@ -2625,6 +2646,22 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs, ...@@ -2625,6 +2646,22 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
src = ipa_get_ith_jump_func (top, dst_fid); src = ipa_get_ith_jump_func (top, dst_fid);
if (src_ctx && !src_ctx->useless_p ())
{
struct ipa_polymorphic_call_context ctx = *src_ctx;
/* TODO: Make type preserved safe WRT contexts. */
if (!dst->value.ancestor.agg_preserved)
ctx.make_speculative ();
ctx.offset_by (dst->value.ancestor.offset);
if (!ctx.useless_p ())
{
vec_safe_grow_cleared (args->polymorphic_call_contexts,
count);
dst_ctx = ipa_get_ith_polymorhic_call_context (args, i);
}
}
if (src->agg.items if (src->agg.items
&& (dst->value.ancestor.agg_preserved || !src->agg.by_ref)) && (dst->value.ancestor.agg_preserved || !src->agg.by_ref))
{ {
...@@ -2676,7 +2713,27 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs, ...@@ -2676,7 +2713,27 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
int dst_fid = dst->value.pass_through.formal_id; int dst_fid = dst->value.pass_through.formal_id;
src = ipa_get_ith_jump_func (top, dst_fid); src = ipa_get_ith_jump_func (top, dst_fid);
bool dst_agg_p = ipa_get_jf_pass_through_agg_preserved (dst); bool dst_agg_p = ipa_get_jf_pass_through_agg_preserved (dst);
struct ipa_polymorphic_call_context *src_ctx
= ipa_get_ith_polymorhic_call_context (top, dst_fid);
if (src_ctx && !src_ctx->useless_p ())
{
struct ipa_polymorphic_call_context ctx = *src_ctx;
/* TODO: Make type preserved safe WRT contexts. */
if (!dst->value.ancestor.agg_preserved)
ctx.make_speculative ();
if (!ctx.useless_p ())
{
if (!dst_ctx)
{
vec_safe_grow_cleared (args->polymorphic_call_contexts,
count);
dst_ctx = ipa_get_ith_polymorhic_call_context (args, i);
}
dst_ctx->combine_with (ctx);
}
}
switch (src->type) switch (src->type)
{ {
case IPA_JF_UNKNOWN: case IPA_JF_UNKNOWN:
...@@ -2754,11 +2811,13 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs, ...@@ -2754,11 +2811,13 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
} }
} }
/* If TARGET is an addr_expr of a function declaration, make it the destination /* If TARGET is an addr_expr of a function declaration, make it the
of an indirect edge IE and return the edge. Otherwise, return NULL. */ (SPECULATIVE)destination of an indirect edge IE and return the edge.
Otherwise, return NULL. */
struct cgraph_edge * struct cgraph_edge *
ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target) ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
bool speculative)
{ {
struct cgraph_node *callee; struct cgraph_node *callee;
struct inline_edge_summary *es = inline_edge_summary (ie); struct inline_edge_summary *es = inline_edge_summary (ie);
...@@ -2829,9 +2888,10 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target) ...@@ -2829,9 +2888,10 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target)
if (dump_file && !unreachable) if (dump_file && !unreachable)
{ {
fprintf (dump_file, "ipa-prop: Discovered %s call to a known target " fprintf (dump_file, "ipa-prop: Discovered %s call to a %s target "
"(%s/%i -> %s/%i), for stmt ", "(%s/%i -> %s/%i), for stmt ",
ie->indirect_info->polymorphic ? "a virtual" : "an indirect", ie->indirect_info->polymorphic ? "a virtual" : "an indirect",
speculative ? "speculative" : "known",
xstrdup (ie->caller->name ()), xstrdup (ie->caller->name ()),
ie->caller->order, ie->caller->order,
xstrdup (callee->name ()), xstrdup (callee->name ()),
...@@ -2849,7 +2909,20 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target) ...@@ -2849,7 +2909,20 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target)
"converting indirect call in %s to direct call to %s\n", "converting indirect call in %s to direct call to %s\n",
ie->caller->name (), callee->name ()); ie->caller->name (), callee->name ());
} }
if (!speculative)
ie = ie->make_direct (callee); ie = ie->make_direct (callee);
else
{
if (!callee->can_be_discarded_p ())
{
cgraph_node *alias;
alias = dyn_cast<cgraph_node *> (callee->noninterposable_alias ());
if (alias)
callee = alias;
}
ie = ie->make_speculative
(callee, ie->count * 8 / 10, ie->frequency * 8 / 10);
}
es = inline_edge_summary (ie); es = inline_edge_summary (ie);
es->call_stmt_size -= (eni_size_weights.indirect_call_cost es->call_stmt_size -= (eni_size_weights.indirect_call_cost
- eni_size_weights.call_cost); - eni_size_weights.call_cost);
...@@ -3035,14 +3108,33 @@ ipa_impossible_devirt_target (struct cgraph_edge *ie, tree target) ...@@ -3035,14 +3108,33 @@ ipa_impossible_devirt_target (struct cgraph_edge *ie, tree target)
static struct cgraph_edge * static struct cgraph_edge *
try_make_edge_direct_virtual_call (struct cgraph_edge *ie, try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
struct ipa_jump_func *jfunc, struct ipa_jump_func *jfunc,
struct ipa_node_params *new_root_info) struct ipa_node_params *new_root_info,
struct ipa_polymorphic_call_context *ctx_ptr)
{ {
tree binfo, target; tree binfo, target = NULL;
bool speculative = false;
bool updated = false;
if (!flag_devirtualize) if (!flag_devirtualize)
return NULL; return NULL;
/* First try to do lookup via known virtual table pointer value. */ /* If this is call of a function parameter, restrict its type
based on knowlede of the context. */
if (ctx_ptr && !ie->indirect_info->by_ref)
{
struct ipa_polymorphic_call_context ctx = *ctx_ptr;
ctx.offset_by (ie->indirect_info->offset);
/* 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);
updated = ie->indirect_info->context.combine_with
(ctx, ie->indirect_info->otr_type);
}
/* Try to do lookup via known virtual table pointer value. */
if (!ie->indirect_info->by_ref) if (!ie->indirect_info->by_ref)
{ {
tree vtable; tree vtable;
...@@ -3068,14 +3160,18 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie, ...@@ -3068,14 +3160,18 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
binfo = ipa_value_from_jfunc (new_root_info, jfunc); binfo = ipa_value_from_jfunc (new_root_info, jfunc);
if (!binfo) if (binfo && TREE_CODE (binfo) != TREE_BINFO)
return NULL;
if (TREE_CODE (binfo) != TREE_BINFO)
{ {
ipa_polymorphic_call_context context (binfo, struct ipa_polymorphic_call_context ctx (binfo,
ie->indirect_info->otr_type, ie->indirect_info->otr_type,
ie->indirect_info->offset); ie->indirect_info->offset);
updated |= ie->indirect_info->context.combine_with
(ctx, ie->indirect_info->otr_type);
}
if (updated)
{
ipa_polymorphic_call_context context (ie);
vec <cgraph_node *>targets; vec <cgraph_node *>targets;
bool final; bool final;
...@@ -3083,29 +3179,49 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie, ...@@ -3083,29 +3179,49 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
(ie->indirect_info->otr_type, (ie->indirect_info->otr_type,
ie->indirect_info->otr_token, ie->indirect_info->otr_token,
context, &final); context, &final);
if (!final || targets.length () > 1) if (final && targets.length () <= 1)
return NULL; {
if (targets.length () == 1) if (targets.length () == 1)
target = targets[0]->decl; target = targets[0]->decl;
else else
target = ipa_impossible_devirt_target (ie, NULL_TREE); target = ipa_impossible_devirt_target (ie, NULL_TREE);
} }
else else if (flag_devirtualize_speculatively
&& !ie->speculative && ie->maybe_hot_p ())
{
cgraph_node *n = try_speculative_devirtualization (ie->indirect_info->otr_type,
ie->indirect_info->otr_token,
ie->indirect_info->context);
if (n)
{
target = n->decl;
speculative = true;
}
}
}
if (binfo && TREE_CODE (binfo) == TREE_BINFO)
{ {
binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset, binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset,
ie->indirect_info->otr_type); ie->indirect_info->otr_type);
if (binfo) if (binfo)
target = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token, {
tree t = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token,
binfo); binfo);
else if (t)
return NULL; {
gcc_assert (!target || speculative || target == t);
target = t;
speculative = false;
}
}
} }
if (target) if (target)
{ {
if (!possible_polymorphic_call_target_p (ie, cgraph_node::get (target))) if (!possible_polymorphic_call_target_p (ie, cgraph_node::get_create (target)))
target = ipa_impossible_devirt_target (ie, target); target = ipa_impossible_devirt_target (ie, target);
return ipa_make_edge_direct_to_target (ie, target); return ipa_make_edge_direct_to_target (ie, target, speculative);
} }
else else
return NULL; return NULL;
...@@ -3157,8 +3273,13 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs, ...@@ -3157,8 +3273,13 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
if (!flag_indirect_inlining) if (!flag_indirect_inlining)
new_direct_edge = NULL; new_direct_edge = NULL;
else if (ici->polymorphic) else if (ici->polymorphic)
{
ipa_polymorphic_call_context *ctx;
ctx = ipa_get_ith_polymorhic_call_context (top, param_index);
new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc, new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc,
new_root_info); new_root_info,
ctx);
}
else else
new_direct_edge = try_make_edge_direct_simple_call (ie, jfunc, new_direct_edge = try_make_edge_direct_simple_call (ie, jfunc,
new_root_info); new_root_info);
...@@ -3523,6 +3644,9 @@ ipa_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst, ...@@ -3523,6 +3644,9 @@ ipa_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
new_args = IPA_EDGE_REF (dst); new_args = IPA_EDGE_REF (dst);
new_args->jump_functions = vec_safe_copy (old_args->jump_functions); new_args->jump_functions = vec_safe_copy (old_args->jump_functions);
if (old_args->polymorphic_call_contexts)
new_args->polymorphic_call_contexts
= vec_safe_copy (old_args->polymorphic_call_contexts);
for (i = 0; i < vec_safe_length (old_args->jump_functions); i++) for (i = 0; i < vec_safe_length (old_args->jump_functions); i++)
{ {
...@@ -4751,17 +4875,29 @@ ipa_write_node_info (struct output_block *ob, struct cgraph_node *node) ...@@ -4751,17 +4875,29 @@ ipa_write_node_info (struct output_block *ob, struct cgraph_node *node)
{ {
struct ipa_edge_args *args = IPA_EDGE_REF (e); struct ipa_edge_args *args = IPA_EDGE_REF (e);
streamer_write_uhwi (ob, ipa_get_cs_argument_count (args)); streamer_write_uhwi (ob,
ipa_get_cs_argument_count (args) * 2
+ (args->polymorphic_call_contexts != NULL));
for (j = 0; j < ipa_get_cs_argument_count (args); j++) for (j = 0; j < ipa_get_cs_argument_count (args); j++)
{
ipa_write_jump_function (ob, ipa_get_ith_jump_func (args, j)); ipa_write_jump_function (ob, ipa_get_ith_jump_func (args, j));
if (args->polymorphic_call_contexts != NULL)
ipa_get_ith_polymorhic_call_context (args, j)->stream_out (ob);
}
} }
for (e = node->indirect_calls; e; e = e->next_callee) for (e = node->indirect_calls; e; e = e->next_callee)
{ {
struct ipa_edge_args *args = IPA_EDGE_REF (e); struct ipa_edge_args *args = IPA_EDGE_REF (e);
streamer_write_uhwi (ob, ipa_get_cs_argument_count (args)); streamer_write_uhwi (ob,
ipa_get_cs_argument_count (args) * 2
+ (args->polymorphic_call_contexts != NULL));
for (j = 0; j < ipa_get_cs_argument_count (args); j++) for (j = 0; j < ipa_get_cs_argument_count (args); j++)
{
ipa_write_jump_function (ob, ipa_get_ith_jump_func (args, j)); ipa_write_jump_function (ob, ipa_get_ith_jump_func (args, j));
if (args->polymorphic_call_contexts != NULL)
ipa_get_ith_polymorhic_call_context (args, j)->stream_out (ob);
}
ipa_write_indirect_edge_info (ob, e); ipa_write_indirect_edge_info (ob, e);
} }
} }
...@@ -4794,26 +4930,42 @@ ipa_read_node_info (struct lto_input_block *ib, struct cgraph_node *node, ...@@ -4794,26 +4930,42 @@ ipa_read_node_info (struct lto_input_block *ib, struct cgraph_node *node,
{ {
struct ipa_edge_args *args = IPA_EDGE_REF (e); struct ipa_edge_args *args = IPA_EDGE_REF (e);
int count = streamer_read_uhwi (ib); int count = streamer_read_uhwi (ib);
bool contexts_computed = count & 1;
count /= 2;
if (!count) if (!count)
continue; continue;
vec_safe_grow_cleared (args->jump_functions, count); vec_safe_grow_cleared (args->jump_functions, count);
if (contexts_computed)
vec_safe_grow_cleared (args->polymorphic_call_contexts, count);
for (k = 0; k < ipa_get_cs_argument_count (args); k++) for (k = 0; k < ipa_get_cs_argument_count (args); k++)
{
ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), e, ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), e,
data_in); data_in);
if (contexts_computed)
ipa_get_ith_polymorhic_call_context (args, k)->stream_in (ib, data_in);
}
} }
for (e = node->indirect_calls; e; e = e->next_callee) for (e = node->indirect_calls; e; e = e->next_callee)
{ {
struct ipa_edge_args *args = IPA_EDGE_REF (e); struct ipa_edge_args *args = IPA_EDGE_REF (e);
int count = streamer_read_uhwi (ib); int count = streamer_read_uhwi (ib);
bool contexts_computed = count & 1;
count /= 2;
if (count) if (count)
{ {
vec_safe_grow_cleared (args->jump_functions, count); vec_safe_grow_cleared (args->jump_functions, count);
if (contexts_computed)
vec_safe_grow_cleared (args->polymorphic_call_contexts, count);
for (k = 0; k < ipa_get_cs_argument_count (args); k++) for (k = 0; k < ipa_get_cs_argument_count (args); k++)
{
ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), e, ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), e,
data_in); data_in);
if (contexts_computed)
ipa_get_ith_polymorhic_call_context (args, k)->stream_in (ib, data_in);
}
} }
ipa_read_indirect_edge_info (ib, data_in, e); ipa_read_indirect_edge_info (ib, data_in, e);
} }
......
...@@ -432,7 +432,10 @@ ipa_set_param_used (struct ipa_node_params *info, int i, bool val) ...@@ -432,7 +432,10 @@ ipa_set_param_used (struct ipa_node_params *info, int i, bool val)
static inline int static inline int
ipa_get_controlled_uses (struct ipa_node_params *info, int i) ipa_get_controlled_uses (struct ipa_node_params *info, int i)
{ {
/* FIXME: introducing speuclation causes out of bounds access here. */
if (info->descriptors.length () > (unsigned)i)
return info->descriptors[i].controlled_uses; return info->descriptors[i].controlled_uses;
return IPA_UNDESCRIBED_USE;
} }
/* Set the controlled counter of a given parameter. */ /* Set the controlled counter of a given parameter. */
...@@ -479,6 +482,7 @@ struct GTY(()) ipa_edge_args ...@@ -479,6 +482,7 @@ struct GTY(()) ipa_edge_args
{ {
/* Vector of the callsite's jump function of each parameter. */ /* Vector of the callsite's jump function of each parameter. */
vec<ipa_jump_func, va_gc> *jump_functions; vec<ipa_jump_func, va_gc> *jump_functions;
vec<ipa_polymorphic_call_context, va_gc> *polymorphic_call_contexts;
}; };
/* ipa_edge_args access functions. Please use these to access fields that /* ipa_edge_args access functions. Please use these to access fields that
...@@ -502,6 +506,16 @@ ipa_get_ith_jump_func (struct ipa_edge_args *args, int i) ...@@ -502,6 +506,16 @@ ipa_get_ith_jump_func (struct ipa_edge_args *args, int i)
return &(*args->jump_functions)[i]; return &(*args->jump_functions)[i];
} }
/* Returns a pointer to the polymorphic call context for the ith argument.
NULL if contexts are not computed. */
static inline struct ipa_polymorphic_call_context *
ipa_get_ith_polymorhic_call_context (struct ipa_edge_args *args, int i)
{
if (!args->polymorphic_call_contexts)
return NULL;
return &(*args->polymorphic_call_contexts)[i];
}
/* Types of vectors holding the infos. */ /* Types of vectors holding the infos. */
/* Vector where the parameter infos are actually stored. */ /* Vector where the parameter infos are actually stored. */
...@@ -585,7 +599,8 @@ tree ipa_get_indirect_edge_target (struct cgraph_edge *ie, ...@@ -585,7 +599,8 @@ tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
vec<tree> , vec<tree> ,
vec<tree> , vec<tree> ,
vec<ipa_agg_jump_function_p> ); vec<ipa_agg_jump_function_p> );
struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree); struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree,
bool speculative = false);
tree ipa_binfo_from_known_type_jfunc (struct ipa_jump_func *); tree ipa_binfo_from_known_type_jfunc (struct ipa_jump_func *);
tree ipa_impossible_devirt_target (struct cgraph_edge *, tree); tree ipa_impossible_devirt_target (struct cgraph_edge *, tree);
......
...@@ -82,6 +82,8 @@ bool contains_polymorphic_type_p (const_tree); ...@@ -82,6 +82,8 @@ bool contains_polymorphic_type_p (const_tree);
void register_odr_type (tree); void register_odr_type (tree);
bool types_must_be_same_for_odr (tree, tree); bool types_must_be_same_for_odr (tree, tree);
bool types_odr_comparable (tree, tree); bool types_odr_comparable (tree, tree);
cgraph_node *try_speculative_devirtualization (tree, HOST_WIDE_INT,
ipa_polymorphic_call_context);
/* Return vector containing possible targets of polymorphic call E. /* Return vector containing possible targets of polymorphic call E.
If COMPLETEP is non-NULL, store true if the list is complette. If COMPLETEP is non-NULL, store true if the list is complette.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment