Commit 44210a96 by Martin Jambor Committed by Martin Jambor

ipa-prop.h (ipa_get_jf_pass_through_type_preserved): use agg_preserved flag instead.

2014-11-14  Martin Jambor  <mjambor@suse.cz>

	* ipa-prop.h (ipa_get_jf_pass_through_type_preserved): use
	agg_preserved flag instead.
	(ipa_get_jf_ancestor_type_preserved): Likewise.
	(ipa_node_params): Rename known_vals to known_csts, update all users.
	New field known_contexts.
	(ipa_get_indirect_edge_target): Update prototype.
	(ipcp_poly_ctx_values_pool): Declare.
	(ipa_context_from_jfunc): Likewise.
	* ipa-inline.h (estimate_ipcp_clone_size_and_time): Updated prototype.
	* cgraph.h (ipa_polymorphic_call_context): New method equal_to.  New
	parameter newline of method dump.
	* ipa-cp.c (ctxlat): New field.
	(ipcp_values_pool): Renamed to ipcp_cst_values_pool, updated all users.
	(ipcp_poly_ctx_values_pool):New variable.
	(ipa_get_poly_ctx_lat): New function.
	(print_ipcp_constant_value): New overloaded function for contexts.
	(print_all_lattices): Also print contexts.
	(ipa_topo_info): New field contexts;
	(set_all_contains_variable): Also set the flag in the context lattice.
	(initialize_node_lattices): Likewise for flag bottom.
	(ipa_get_jf_ancestor_result): Removed BINFO handling.
	(ipa_value_from_jfunc): Likewise.
	(ipa_context_from_jfunc): New function.
	(values_equal_for_ipcp_p): New overloaded function for contexts.
	(allocate_and_init_ipcp_value): Construct the value.
	(allocate_and_init_ipcp_value): New overloaded function for contexts.
	(propagate_scalar_accross_jump_function): Removed handling of
	KNOWN_TYPE jump functions.
	(propagate_context_accross_jump_function): New function.
	(propagate_constants_accross_call): Also propagate contexts.
	(ipa_get_indirect_edge_target_1): Work on contexts rather than BINFOs.
	(ipa_get_indirect_edge_target): Likewise.
	(devirtualization_time_bonus): Likewise.
	(gather_context_independent_values): Create and populate known_contexts
	vector rather than known_binfos.
	(perform_estimation_of_a_value): Work on contexts rather than BINFOs.
	(estimate_local_effects): Likewise.
	(add_all_node_vals_to_toposort): Also add contexts to teir topological
	sort.
	(ipcp_propagate_stage): Also propagate effects of contexts.
	(ipcp_discover_new_direct_edges): Receive and pass known_contexts to
	ipa_get_indirect_edge_target_1.
	(cgraph_edge_brings_value_p): New overloaded function for contexts.
	(create_specialized_node): Work on contexts rather than BINFOs.
	(find_more_contexts_for_caller_subset): New function.
	(known_contexts_useful_p): New function.
	(copy_useful_known_contexts): Likewise.
	(modify_known_vectors_with_val): Likewise.
	(ipcp_val_in_agg_replacements_p): Renamed to
	ipcp_val_agg_replacement_ok_p, return true for all offset indicating
	non-aggregate.
	(ipcp_val_agg_replacement_ok_p): New overloaded function for contexts.
	(decide_about_value): Work on contexts rather than BINFOs.
	(decide_whether_version_node): Likewise.
	(ipcp_driver): Initialize the new alloc pool.
	* ipa-prop.c (ipa_print_node_jump_functions_for_edge): Prettify
	printing of edge contexts.
	(ipa_set_ancestor_jf): Replace assert with conditional setting of
	type_preserved to false.
	(update_jump_functions_after_inlining): Use access function instead of
	reading agg_preserved directly.  Store combined context in the ancestor
	case.
	(try_make_edge_direct_virtual_call): Work on contexts rather than
	BINFOs.
	(update_indirect_edges_after_inlining): Get context from
	ipa_context_from_jfunc.
	(ipa_free_node_params_substructures): Free also known_contexts.
	(ipa_free_all_structures_after_ipa_cp): Free the new alloc pool.
	(ipa_free_all_structures_after_iinln): Likewise.
	* ipa-inline-analysis.c (evaluate_properties_for_edge): Work on
	contexts rather than BINFOs.
	(estimate_edge_devirt_benefit): Likewise.
	(estimate_edge_size_and_time): Likewise.
	(estimate_calls_size_and_time): Likewise.
	(estimate_node_size_and_time): Likewise.
	(estimate_ipcp_clone_size_and_time): Likewise.
	(do_estimate_edge_time): Likewise.
	(do_estimate_edge_size): Likewise.
	(do_estimate_edge_hints): Likewise.
	* ipa-polymorphic-call.c (ipa_polymorphic_call_context::dump): New
	parameter newline, ouput newline only when it is set.
	(ipa_polymorphic_call_context::equal_to): New method.

testsuite/
	* g++.dg/ipa/devirt-11.C: Dont't run ipa-cp, remove times constraint
	from the dump scan.
	* g++.dg/ipa/devirt-21.C: Xfail.
	* g++.dg/ipa/devirt-24.C: Likewise.
	* g++.dg/ipa/devirt-10.C: Removed times constraint from the dump scan.
	* g++.dg/ipa/devirt-41.C: Updated the dump scan.
	* g++.dg/ipa/devirt-44.C: Likewise.
	* g++.dg/ipa/devirt-43.C: Xfail.

From-SVN: r217587
parent c0cb5055
2014-11-14 Martin Jambor <mjambor@suse.cz> 2014-11-14 Martin Jambor <mjambor@suse.cz>
* ipa-prop.h (ipa_get_jf_pass_through_type_preserved): use
agg_preserved flag instead.
(ipa_get_jf_ancestor_type_preserved): Likewise.
(ipa_node_params): Rename known_vals to known_csts, update all users.
New field known_contexts.
(ipa_get_indirect_edge_target): Update prototype.
(ipcp_poly_ctx_values_pool): Declare.
(ipa_context_from_jfunc): Likewise.
* ipa-inline.h (estimate_ipcp_clone_size_and_time): Updated prototype.
* cgraph.h (ipa_polymorphic_call_context): New method equal_to. New
parameter newline of method dump.
* ipa-cp.c (ctxlat): New field.
(ipcp_values_pool): Renamed to ipcp_cst_values_pool, updated all users.
(ipcp_poly_ctx_values_pool):New variable.
(ipa_get_poly_ctx_lat): New function.
(print_ipcp_constant_value): New overloaded function for contexts.
(print_all_lattices): Also print contexts.
(ipa_topo_info): New field contexts;
(set_all_contains_variable): Also set the flag in the context lattice.
(initialize_node_lattices): Likewise for flag bottom.
(ipa_get_jf_ancestor_result): Removed BINFO handling.
(ipa_value_from_jfunc): Likewise.
(ipa_context_from_jfunc): New function.
(values_equal_for_ipcp_p): New overloaded function for contexts.
(allocate_and_init_ipcp_value): Construct the value.
(allocate_and_init_ipcp_value): New overloaded function for contexts.
(propagate_scalar_accross_jump_function): Removed handling of
KNOWN_TYPE jump functions.
(propagate_context_accross_jump_function): New function.
(propagate_constants_accross_call): Also propagate contexts.
(ipa_get_indirect_edge_target_1): Work on contexts rather than BINFOs.
(ipa_get_indirect_edge_target): Likewise.
(devirtualization_time_bonus): Likewise.
(gather_context_independent_values): Create and populate known_contexts
vector rather than known_binfos.
(perform_estimation_of_a_value): Work on contexts rather than BINFOs.
(estimate_local_effects): Likewise.
(add_all_node_vals_to_toposort): Also add contexts to teir topological
sort.
(ipcp_propagate_stage): Also propagate effects of contexts.
(ipcp_discover_new_direct_edges): Receive and pass known_contexts to
ipa_get_indirect_edge_target_1.
(cgraph_edge_brings_value_p): New overloaded function for contexts.
(create_specialized_node): Work on contexts rather than BINFOs.
(find_more_contexts_for_caller_subset): New function.
(known_contexts_useful_p): New function.
(copy_useful_known_contexts): Likewise.
(modify_known_vectors_with_val): Likewise.
(ipcp_val_in_agg_replacements_p): Renamed to
ipcp_val_agg_replacement_ok_p, return true for all offset indicating
non-aggregate.
(ipcp_val_agg_replacement_ok_p): New overloaded function for contexts.
(decide_about_value): Work on contexts rather than BINFOs.
(decide_whether_version_node): Likewise.
(ipcp_driver): Initialize the new alloc pool.
* ipa-prop.c (ipa_print_node_jump_functions_for_edge): Prettify
printing of edge contexts.
(ipa_set_ancestor_jf): Replace assert with conditional setting of
type_preserved to false.
(update_jump_functions_after_inlining): Use access function instead of
reading agg_preserved directly. Store combined context in the ancestor
case.
(try_make_edge_direct_virtual_call): Work on contexts rather than
BINFOs.
(update_indirect_edges_after_inlining): Get context from
ipa_context_from_jfunc.
(ipa_free_node_params_substructures): Free also known_contexts.
(ipa_free_all_structures_after_ipa_cp): Free the new alloc pool.
(ipa_free_all_structures_after_iinln): Likewise.
* ipa-inline-analysis.c (evaluate_properties_for_edge): Work on
contexts rather than BINFOs.
(estimate_edge_devirt_benefit): Likewise.
(estimate_edge_size_and_time): Likewise.
(estimate_calls_size_and_time): Likewise.
(estimate_node_size_and_time): Likewise.
(estimate_ipcp_clone_size_and_time): Likewise.
(do_estimate_edge_time): Likewise.
(do_estimate_edge_size): Likewise.
(do_estimate_edge_hints): Likewise.
* ipa-polymorphic-call.c (ipa_polymorphic_call_context::dump): New
parameter newline, ouput newline only when it is set.
(ipa_polymorphic_call_context::equal_to): New method.
2014-11-14 Martin Jambor <mjambor@suse.cz>
* ipa-cp.c (ipcp_value_source): Converted to a template class. All * ipa-cp.c (ipcp_value_source): Converted to a template class. All
users converted to the same specialization as the using class/function users converted to the same specialization as the using class/function
or specialization on tree. or specialization on tree.
...@@ -1387,9 +1387,12 @@ public: ...@@ -1387,9 +1387,12 @@ public:
/* Return TRUE if context is fully useless. */ /* Return TRUE if context is fully useless. */
bool useless_p () const; bool useless_p () const;
/* Return TRUE if this context conveys the same information as X. */
bool equal_to (const ipa_polymorphic_call_context &x) const;
/* Dump human readable context to F. */ /* Dump human readable context to F. If NEWLINE is true, it will be
void dump (FILE *f) const; terminated by a newline. */
void dump (FILE *f, bool newline = true) const;
void DEBUG_FUNCTION debug () const; void DEBUG_FUNCTION debug () const;
/* LTO streaming. */ /* LTO streaming. */
......
...@@ -223,7 +223,8 @@ void initialize_inline_failed (struct cgraph_edge *); ...@@ -223,7 +223,8 @@ void initialize_inline_failed (struct cgraph_edge *);
int estimate_time_after_inlining (struct cgraph_node *, struct cgraph_edge *); int estimate_time_after_inlining (struct cgraph_node *, struct cgraph_edge *);
int estimate_size_after_inlining (struct cgraph_node *, struct cgraph_edge *); int estimate_size_after_inlining (struct cgraph_node *, struct cgraph_edge *);
void estimate_ipcp_clone_size_and_time (struct cgraph_node *, void estimate_ipcp_clone_size_and_time (struct cgraph_node *,
vec<tree>, vec<tree>, vec<tree>,
vec<ipa_polymorphic_call_context>,
vec<ipa_agg_jump_function_p>, vec<ipa_agg_jump_function_p>,
int *, int *, inline_hints *); int *, int *, inline_hints *);
int do_estimate_growth (struct cgraph_node *); int do_estimate_growth (struct cgraph_node *);
......
...@@ -599,10 +599,11 @@ decl_maybe_in_construction_p (tree base, tree outer_type, ...@@ -599,10 +599,11 @@ decl_maybe_in_construction_p (tree base, tree outer_type,
return false; return false;
} }
/* Dump human readable context to F. */ /* Dump human readable context to F. If NEWLINE is true, it will be terminated
by a newline. */
void void
ipa_polymorphic_call_context::dump (FILE *f) const ipa_polymorphic_call_context::dump (FILE *f, bool newline) const
{ {
fprintf (f, " "); fprintf (f, " ");
if (invalid) if (invalid)
...@@ -634,7 +635,8 @@ ipa_polymorphic_call_context::dump (FILE *f) const ...@@ -634,7 +635,8 @@ ipa_polymorphic_call_context::dump (FILE *f) const
speculative_offset); speculative_offset);
} }
} }
fprintf(f, "\n"); if (newline)
fprintf(f, "\n");
} }
/* Print context to stderr. */ /* Print context to stderr. */
...@@ -2130,3 +2132,47 @@ ipa_polymorphic_call_context::possible_dynamic_type_change (bool in_poly_cdtor, ...@@ -2130,3 +2132,47 @@ ipa_polymorphic_call_context::possible_dynamic_type_change (bool in_poly_cdtor,
else if (in_poly_cdtor) else if (in_poly_cdtor)
maybe_in_construction = true; maybe_in_construction = true;
} }
/* Return TRUE if this context conveys the same information as OTHER. */
bool
ipa_polymorphic_call_context::equal_to
(const ipa_polymorphic_call_context &x) const
{
if (useless_p ())
return x.useless_p ();
if (invalid)
return x.invalid;
if (x.useless_p () || x.invalid)
return false;
if (outer_type)
{
if (!x.outer_type
|| !types_odr_comparable (outer_type, x.outer_type)
|| !types_same_for_odr (outer_type, x.outer_type)
|| offset != x.offset
|| maybe_in_construction != x.maybe_in_construction
|| maybe_derived_type != x.maybe_derived_type
|| dynamic != x.dynamic)
return false;
}
else if (x.outer_type)
return false;
if (speculative_outer_type)
{
if (!x.speculative_outer_type
|| !types_odr_comparable (speculative_outer_type,
x.speculative_outer_type)
|| !types_same_for_odr (speculative_outer_type,
x.speculative_outer_type)
|| speculative_offset != x.speculative_offset
|| speculative_maybe_derived_type != x.speculative_maybe_derived_type)
return false;
}
else if (x.speculative_outer_type)
return false;
return true;
}
...@@ -380,8 +380,14 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs) ...@@ -380,8 +380,14 @@ 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); struct ipa_polymorphic_call_context *ctx
= ipa_get_ith_polymorhic_call_context (IPA_EDGE_REF (cs), i);
if (ctx && !ctx->useless_p ())
{
fprintf (f, " Context: ");
ctx->dump (dump_file);
}
} }
} }
...@@ -559,7 +565,8 @@ ipa_set_ancestor_jf (struct ipa_jump_func *jfunc, HOST_WIDE_INT offset, ...@@ -559,7 +565,8 @@ ipa_set_ancestor_jf (struct ipa_jump_func *jfunc, HOST_WIDE_INT offset,
type = NULL_TREE; type = NULL_TREE;
if (type) if (type)
type = TYPE_MAIN_VARIANT (type); type = TYPE_MAIN_VARIANT (type);
gcc_assert (!type_preserved || contains_polymorphic_type_p (type)); if (!type || !contains_polymorphic_type_p (type))
type_preserved = false;
jfunc->type = IPA_JF_ANCESTOR; jfunc->type = IPA_JF_ANCESTOR;
jfunc->value.ancestor.formal_id = formal_id; jfunc->value.ancestor.formal_id = formal_id;
jfunc->value.ancestor.offset = offset; jfunc->value.ancestor.offset = offset;
...@@ -2622,9 +2629,12 @@ combine_known_type_and_ancestor_jfs (struct ipa_jump_func *src, ...@@ -2622,9 +2629,12 @@ combine_known_type_and_ancestor_jfs (struct ipa_jump_func *src,
+ ipa_get_jf_ancestor_offset (dst); + ipa_get_jf_ancestor_offset (dst);
combined_type = ipa_get_jf_ancestor_type (dst); combined_type = ipa_get_jf_ancestor_type (dst);
ipa_set_jf_known_type (dst, combined_offset, if (combined_type)
ipa_get_jf_known_type_base_type (src), ipa_set_jf_known_type (dst, combined_offset,
combined_type); ipa_get_jf_known_type_base_type (src),
combined_type);
else
dst->type = IPA_JF_UNKNOWN;
} }
/* Update the jump functions associated with call graph edge E when the call /* Update the jump functions associated with call graph edge E when the call
...@@ -2669,7 +2679,7 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs, ...@@ -2669,7 +2679,7 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
struct ipa_polymorphic_call_context ctx = *src_ctx; struct ipa_polymorphic_call_context ctx = *src_ctx;
/* TODO: Make type preserved safe WRT contexts. */ /* TODO: Make type preserved safe WRT contexts. */
if (!dst->value.ancestor.agg_preserved) if (!ipa_get_jf_ancestor_type_preserved (dst))
ctx.possible_dynamic_type_change (e->in_polymorphic_cdtor); ctx.possible_dynamic_type_change (e->in_polymorphic_cdtor);
ctx.offset_by (dst->value.ancestor.offset); ctx.offset_by (dst->value.ancestor.offset);
if (!ctx.useless_p ()) if (!ctx.useless_p ())
...@@ -2678,6 +2688,7 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs, ...@@ -2678,6 +2688,7 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
count); count);
dst_ctx = ipa_get_ith_polymorhic_call_context (args, i); dst_ctx = ipa_get_ith_polymorhic_call_context (args, i);
} }
dst_ctx->combine_with (ctx);
} }
if (src->agg.items if (src->agg.items
...@@ -2739,7 +2750,7 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs, ...@@ -2739,7 +2750,7 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
struct ipa_polymorphic_call_context ctx = *src_ctx; struct ipa_polymorphic_call_context ctx = *src_ctx;
/* TODO: Make type preserved safe WRT contexts. */ /* TODO: Make type preserved safe WRT contexts. */
if (!dst->value.ancestor.agg_preserved) if (!ipa_get_jf_pass_through_type_preserved (dst))
ctx.possible_dynamic_type_change (e->in_polymorphic_cdtor); ctx.possible_dynamic_type_change (e->in_polymorphic_cdtor);
if (!ctx.useless_p ()) if (!ctx.useless_p ())
{ {
...@@ -3152,41 +3163,24 @@ ipa_impossible_devirt_target (struct cgraph_edge *ie, tree target) ...@@ -3152,41 +3163,24 @@ ipa_impossible_devirt_target (struct cgraph_edge *ie, tree target)
/* Try to find a destination for indirect edge IE that corresponds to a virtual /* Try to find a destination for indirect edge IE that corresponds to a virtual
call based on a formal parameter which is described by jump function JFUNC call based on a formal parameter which is described by jump function JFUNC
and if it can be determined, make it direct and return the direct edge. and if it can be determined, make it direct and return the direct edge.
Otherwise, return NULL. NEW_ROOT_INFO is the node info that JFUNC lattices Otherwise, return NULL. CTX describes the polymorphic context that the
are relative to. */ parameter the call is based on brings along with it. */
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_polymorphic_call_context ctx)
struct ipa_polymorphic_call_context *ctx_ptr)
{ {
tree binfo, target = NULL; tree target = NULL;
bool speculative = false; bool speculative = false;
bool updated = false;
if (!flag_devirtualize) if (!flag_devirtualize)
return NULL; return NULL;
/* If this is call of a function parameter, restrict its type gcc_assert (!ie->indirect_info->by_ref);
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);
if (ie->indirect_info->vptr_changed)
ctx.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
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. */ /* Try to do lookup via known virtual table pointer value. */
if (!ie->indirect_info->by_ref if (!ie->indirect_info->vptr_changed || flag_devirtualize_speculatively)
&& (!ie->indirect_info->vptr_changed || flag_devirtualize_speculatively))
{ {
tree vtable; tree vtable;
unsigned HOST_WIDE_INT offset; unsigned HOST_WIDE_INT offset;
...@@ -3217,67 +3211,44 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie, ...@@ -3217,67 +3211,44 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
} }
} }
binfo = ipa_value_from_jfunc (new_root_info, jfunc); ipa_polymorphic_call_context ie_context (ie);
vec <cgraph_node *>targets;
if (binfo && TREE_CODE (binfo) != TREE_BINFO) bool final;
{
struct ipa_polymorphic_call_context ctx (binfo, ctx.offset_by (ie->indirect_info->offset);
ie->indirect_info->otr_type, if (ie->indirect_info->vptr_changed)
ie->indirect_info->offset); ctx.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
updated |= ie->indirect_info->context.combine_with ie->indirect_info->otr_type);
(ctx, ie->indirect_info->otr_type); ctx.combine_with (ie_context, ie->indirect_info->otr_type);
targets = possible_polymorphic_call_targets
(ie->indirect_info->otr_type,
ie->indirect_info->otr_token,
ctx, &final);
if (final && targets.length () <= 1)
{
if (targets.length () == 1)
target = targets[0]->decl;
else
target = ipa_impossible_devirt_target (ie, NULL_TREE);
} }
else if (!target && flag_devirtualize_speculatively
if (updated) && !ie->speculative && ie->maybe_hot_p ())
{ {
ipa_polymorphic_call_context context (ie); cgraph_node *n;
vec <cgraph_node *>targets; n = try_speculative_devirtualization (ie->indirect_info->otr_type,
bool final; ie->indirect_info->otr_token,
ie->indirect_info->context);
targets = possible_polymorphic_call_targets if (n)
(ie->indirect_info->otr_type,
ie->indirect_info->otr_token,
context, &final);
if (final && targets.length () <= 1)
{
if (targets.length () == 1)
target = targets[0]->decl;
else
target = ipa_impossible_devirt_target (ie, NULL_TREE);
}
else if (!target && 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,
ie->indirect_info->otr_type);
if (binfo)
{ {
tree t = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token, target = n->decl;
binfo); speculative = true;
if (t)
{
target = t;
speculative = false;
}
} }
} }
if (target) if (target)
{ {
if (!possible_polymorphic_call_target_p (ie, cgraph_node::get_create (target))) if (!possible_polymorphic_call_target_p
(ie, cgraph_node::get_create (target)))
{ {
if (speculative) if (speculative)
return NULL; return NULL;
...@@ -3336,11 +3307,9 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs, ...@@ -3336,11 +3307,9 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
new_direct_edge = NULL; new_direct_edge = NULL;
else if (ici->polymorphic) else if (ici->polymorphic)
{ {
ipa_polymorphic_call_context *ctx; ipa_polymorphic_call_context ctx;
ctx = ipa_get_ith_polymorhic_call_context (top, param_index); ctx = ipa_context_from_jfunc (new_root_info, cs, param_index, jfunc);
new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc, new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc, ctx);
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,
...@@ -3474,7 +3443,7 @@ propagate_controlled_uses (struct cgraph_edge *cs) ...@@ -3474,7 +3443,7 @@ propagate_controlled_uses (struct cgraph_edge *cs)
{ {
struct cgraph_node *n; struct cgraph_node *n;
struct ipa_ref *ref; struct ipa_ref *ref;
tree t = new_root_info->known_vals[src_idx]; tree t = new_root_info->known_csts[src_idx];
if (t && TREE_CODE (t) == ADDR_EXPR if (t && TREE_CODE (t) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL && TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL
...@@ -3617,7 +3586,8 @@ ipa_free_node_params_substructures (struct ipa_node_params *info) ...@@ -3617,7 +3586,8 @@ ipa_free_node_params_substructures (struct ipa_node_params *info)
free (info->lattices); free (info->lattices);
/* Lattice values and their sources are deallocated with their alocation /* Lattice values and their sources are deallocated with their alocation
pool. */ pool. */
info->known_vals.release (); info->known_csts.release ();
info->known_contexts.release ();
memset (info, 0, sizeof (*info)); memset (info, 0, sizeof (*info));
} }
...@@ -3892,7 +3862,8 @@ ipa_free_all_structures_after_ipa_cp (void) ...@@ -3892,7 +3862,8 @@ ipa_free_all_structures_after_ipa_cp (void)
ipa_free_all_edge_args (); ipa_free_all_edge_args ();
ipa_free_all_node_params (); ipa_free_all_node_params ();
free_alloc_pool (ipcp_sources_pool); free_alloc_pool (ipcp_sources_pool);
free_alloc_pool (ipcp_values_pool); free_alloc_pool (ipcp_cst_values_pool);
free_alloc_pool (ipcp_poly_ctx_values_pool);
free_alloc_pool (ipcp_agg_lattice_pool); free_alloc_pool (ipcp_agg_lattice_pool);
ipa_unregister_cgraph_hooks (); ipa_unregister_cgraph_hooks ();
if (ipa_refdesc_pool) if (ipa_refdesc_pool)
...@@ -3911,8 +3882,10 @@ ipa_free_all_structures_after_iinln (void) ...@@ -3911,8 +3882,10 @@ ipa_free_all_structures_after_iinln (void)
ipa_unregister_cgraph_hooks (); ipa_unregister_cgraph_hooks ();
if (ipcp_sources_pool) if (ipcp_sources_pool)
free_alloc_pool (ipcp_sources_pool); free_alloc_pool (ipcp_sources_pool);
if (ipcp_values_pool) if (ipcp_cst_values_pool)
free_alloc_pool (ipcp_values_pool); free_alloc_pool (ipcp_cst_values_pool);
if (ipcp_poly_ctx_values_pool)
free_alloc_pool (ipcp_poly_ctx_values_pool);
if (ipcp_agg_lattice_pool) if (ipcp_agg_lattice_pool)
free_alloc_pool (ipcp_agg_lattice_pool); free_alloc_pool (ipcp_agg_lattice_pool);
if (ipa_refdesc_pool) if (ipa_refdesc_pool)
......
...@@ -278,13 +278,14 @@ ipa_get_jf_pass_through_agg_preserved (struct ipa_jump_func *jfunc) ...@@ -278,13 +278,14 @@ ipa_get_jf_pass_through_agg_preserved (struct ipa_jump_func *jfunc)
return jfunc->value.pass_through.agg_preserved; return jfunc->value.pass_through.agg_preserved;
} }
/* Return the type_preserved flag of a pass through jump function JFUNC. */ /* Return true if pass through jump function JFUNC preserves type
information. */
static inline bool static inline bool
ipa_get_jf_pass_through_type_preserved (struct ipa_jump_func *jfunc) ipa_get_jf_pass_through_type_preserved (struct ipa_jump_func *jfunc)
{ {
gcc_checking_assert (jfunc->type == IPA_JF_PASS_THROUGH); gcc_checking_assert (jfunc->type == IPA_JF_PASS_THROUGH);
return jfunc->value.pass_through.type_preserved; return jfunc->value.pass_through.agg_preserved;
} }
/* Return the offset of an ancestor jump function JFUNC. */ /* Return the offset of an ancestor jump function JFUNC. */
...@@ -324,13 +325,13 @@ ipa_get_jf_ancestor_agg_preserved (struct ipa_jump_func *jfunc) ...@@ -324,13 +325,13 @@ ipa_get_jf_ancestor_agg_preserved (struct ipa_jump_func *jfunc)
return jfunc->value.ancestor.agg_preserved; return jfunc->value.ancestor.agg_preserved;
} }
/* Return the type_preserved flag of an ancestor jump function JFUNC. */ /* Return true if ancestor jump function JFUNC presrves type information. */
static inline bool static inline bool
ipa_get_jf_ancestor_type_preserved (struct ipa_jump_func *jfunc) ipa_get_jf_ancestor_type_preserved (struct ipa_jump_func *jfunc)
{ {
gcc_checking_assert (jfunc->type == IPA_JF_ANCESTOR); gcc_checking_assert (jfunc->type == IPA_JF_ANCESTOR);
return jfunc->value.ancestor.type_preserved; return jfunc->value.ancestor.agg_preserved;
} }
/* Summary describing a single formal parameter. */ /* Summary describing a single formal parameter. */
...@@ -363,9 +364,12 @@ struct ipa_node_params ...@@ -363,9 +364,12 @@ struct ipa_node_params
/* Only for versioned nodes this field would not be NULL, /* Only for versioned nodes this field would not be NULL,
it points to the node that IPA cp cloned from. */ it points to the node that IPA cp cloned from. */
struct cgraph_node *ipcp_orig_node; struct cgraph_node *ipcp_orig_node;
/* If this node is an ipa-cp clone, these are the known values that describe /* If this node is an ipa-cp clone, these are the known constants that
what it has been specialized for. */ describe what it has been specialized for. */
vec<tree> known_vals; vec<tree> known_csts;
/* If this node is an ipa-cp clone, these are the known polymorphic contexts
that describe what it has been specialized for. */
vec<ipa_polymorphic_call_context> known_contexts;
/* Whether the param uses analysis and jump function computation has already /* Whether the param uses analysis and jump function computation has already
been performed. */ been performed. */
unsigned analysis_done : 1; unsigned analysis_done : 1;
...@@ -592,7 +596,7 @@ bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs, ...@@ -592,7 +596,7 @@ bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
/* Indirect edge and binfo processing. */ /* Indirect edge and binfo processing. */
tree ipa_get_indirect_edge_target (struct cgraph_edge *ie, tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
vec<tree> , vec<tree> ,
vec<tree> , vec<ipa_polymorphic_call_context>,
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); bool speculative = false);
...@@ -615,7 +619,8 @@ void ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node); ...@@ -615,7 +619,8 @@ void ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node);
void ipa_print_all_jump_functions (FILE * f); void ipa_print_all_jump_functions (FILE * f);
void ipcp_verify_propagated_values (void); void ipcp_verify_propagated_values (void);
extern alloc_pool ipcp_values_pool; extern alloc_pool ipcp_cst_values_pool;
extern alloc_pool ipcp_poly_ctx_values_pool;
extern alloc_pool ipcp_sources_pool; extern alloc_pool ipcp_sources_pool;
extern alloc_pool ipcp_agg_lattice_pool; extern alloc_pool ipcp_agg_lattice_pool;
...@@ -716,6 +721,10 @@ int ipa_get_param_decl_index (struct ipa_node_params *, tree); ...@@ -716,6 +721,10 @@ int ipa_get_param_decl_index (struct ipa_node_params *, tree);
tree ipa_value_from_jfunc (struct ipa_node_params *info, tree ipa_value_from_jfunc (struct ipa_node_params *info,
struct ipa_jump_func *jfunc); struct ipa_jump_func *jfunc);
unsigned int ipcp_transform_function (struct cgraph_node *node); unsigned int ipcp_transform_function (struct cgraph_node *node);
ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *,
cgraph_edge *,
int,
ipa_jump_func *);
void ipa_dump_param (FILE *, struct ipa_node_params *info, int i); void ipa_dump_param (FILE *, struct ipa_node_params *info, int i);
bool ipa_modify_expr (tree *, bool, ipa_parm_adjustment_vec); bool ipa_modify_expr (tree *, bool, ipa_parm_adjustment_vec);
ipa_parm_adjustment *ipa_get_adjustment_candidate (tree **, bool *, ipa_parm_adjustment *ipa_get_adjustment_candidate (tree **, bool *,
......
2014-11-14 Martin Jambor <mjambor@suse.cz>
* g++.dg/ipa/devirt-11.C: Dont't run ipa-cp, remove times constraint
from the dump scan.
* g++.dg/ipa/devirt-21.C: Xfail.
* g++.dg/ipa/devirt-24.C: Likewise.
* g++.dg/ipa/devirt-10.C: Removed times constraint from the dump scan.
* g++.dg/ipa/devirt-41.C: Updated the dump scan.
* g++.dg/ipa/devirt-44.C: Likewise.
* g++.dg/ipa/devirt-43.C: Xfail.
2014-11-14 Jonathan Wakely <jwakely@redhat.com> 2014-11-14 Jonathan Wakely <jwakely@redhat.com>
* g++.dg/abi/abi-tag11.C: New. * g++.dg/abi/abi-tag11.C: New.
......
...@@ -27,8 +27,6 @@ struct wxBufferedPaintDC : public wxBufferedDC { ...@@ -27,8 +27,6 @@ struct wxBufferedPaintDC : public wxBufferedDC {
void OnPaint(wxPaintEvent & event) { void OnPaint(wxPaintEvent & event) {
wxBufferedPaintDC dc; wxBufferedPaintDC dc;
} }
/* IPA-CP should really discover both cases, but for time being the second is handled by inliner. */ /* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 2 "cp" } } */
/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "inline" } } */
/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "cp" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */ /* { dg-final { cleanup-ipa-dump "inline" } } */
/* { dg-final { cleanup-ipa-dump "cp" } } */ /* { dg-final { cleanup-ipa-dump "cp" } } */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O2 -fdump-ipa-inline -fno-devirtualize-speculatively" } */ /* { dg-options "-O2 -fno-ipa-cp -fdump-ipa-inline -fno-devirtualize-speculatively" } */
int baz (); int baz ();
struct A struct A
{ {
...@@ -42,7 +42,5 @@ bar () ...@@ -42,7 +42,5 @@ bar ()
baz (); baz ();
c + d; c + d;
} }
/* While inlining function called once we should devirtualize a new call to fn3. /* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target" "inline" } } */
Because fn2 is already removed, we should not devirtualize. */
/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */ /* { dg-final { cleanup-ipa-dump "inline" } } */
...@@ -37,5 +37,5 @@ main() ...@@ -37,5 +37,5 @@ main()
{ {
class C c; class C c;
} }
/* { dg-final { scan-ipa-dump "Discovered a virtual call to" "cp" { xfail *-*-* } } } */ /* { dg-final { scan-ipa-dump "Discovered a virtual call to" "cp" } } */
/* { dg-final { cleanup-ipa-dump "cp" } } */ /* { dg-final { cleanup-ipa-dump "cp" } } */
...@@ -36,7 +36,7 @@ C *b = new (C); ...@@ -36,7 +36,7 @@ C *b = new (C);
sort(f, *b); sort(f, *b);
} }
} }
/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "inline" } } */ /* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "inline" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */ /* { dg-final { cleanup-ipa-dump "inline" } } */
/* { dg-final { scan-ipa-dump-times "Aggregate passed by reference" 1 "cp" } } */ /* { dg-final { scan-ipa-dump-times "Aggregate passed by reference" 1 "cp" } } */
/* { dg-final { cleanup-ipa-dump "cp" } } */ /* { dg-final { cleanup-ipa-dump "cp" } } */
...@@ -26,6 +26,6 @@ main() ...@@ -26,6 +26,6 @@ main()
Because the type is in static storage, we know it won't change type in dostuff Because the type is in static storage, we know it won't change type in dostuff
and from callstack we can tell that is is not in construction/destruction. */ and from callstack we can tell that is is not in construction/destruction. */
/* { dg-final { scan-ipa-dump-times "First type is base of second" 1 "inline" } } */ /* { dg-final { scan-ipa-dump "Second type is base of first" "inline" } } */
/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "inline" } } */ /* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */ /* { dg-final { cleanup-ipa-dump "inline" } } */
...@@ -23,5 +23,5 @@ t(struct B *b) ...@@ -23,5 +23,5 @@ t(struct B *b)
of type B. This makes A fully specified and we know C::foo is unlikely. of type B. This makes A fully specified and we know C::foo is unlikely.
FIXME: We could most probably can devirtualize unconditonally because dereference of b in FIXME: We could most probably can devirtualize unconditonally because dereference of b in
&b->a makes the type known. GIMPLE does not represent this. */ &b->a makes the type known. GIMPLE does not represent this. */
/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a speculative target" 1 "inline" } } */ /* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a speculative target" 1 "inline" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */ /* { dg-final { cleanup-ipa-dump "inline" } } */
...@@ -26,7 +26,7 @@ main() ...@@ -26,7 +26,7 @@ main()
/* Here one invocation of foo is while type is in construction, while other is not. /* Here one invocation of foo is while type is in construction, while other is not.
Check that we handle that. */ Check that we handle that. */
/* { dg-final { scan-ipa-dump-times "First type is base of second" 1 "inline" } } */ /* { dg-final { scan-ipa-dump "Second type is base of first" "inline" } } */
/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*A::foo" 1 "inline" } } */ /* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*A::foo" 1 "inline" } } */
/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*B::foo" 1 "inline" } } */ /* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*B::foo" 1 "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */ /* { dg-final { cleanup-ipa-dump "inline" } } */
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