Commit 2f28755f by Jan Hubicka Committed by Jan Hubicka

ipa-devirt.c (polymorphic_call_target_d): Add SPECULATIVE; reorder for better storage.


	* ipa-devirt.c (polymorphic_call_target_d): Add SPECULATIVE; reorder
	for better storage.
	(polymorphic_call_target_hasher::hash): Hash SPECULATIVE.
	(possible_polymorphic_call_targets): Instead of computing both
	speculative and non-speculative answers, do just one at a time.
	Replace NONSPECULATIVE_TARGETSP parameter with SPECULATIVE flag.
	(dump_targets): Break out from ...
	(dump_possible_polymorphic_call_targets): ... here; dump both speculative
	and non-speculative lists.
	(ipa_devirt): Update for new possible_polymorphic_call_targets API.
	* ipa-utils.h (possible_polymorphic_call_targets): Update.

	* testsuite/g++.dg/ipa/devirt-34.C: Update template.

From-SVN: r215614
parent 0be35aa0
2014-09-25 Jan Hubicka <hubicka@ucw.cz>
* ipa-devirt.c (polymorphic_call_target_d): Add SPECULATIVE; reorder
for better storage.
(polymorphic_call_target_hasher::hash): Hash SPECULATIVE.
(possible_polymorphic_call_targets): Instead of computing both
speculative and non-speculative answers, do just one at a time.
Replace NONSPECULATIVE_TARGETSP parameter with SPECULATIVE flag.
(dump_targets): Break out from ...
(dump_possible_polymorphic_call_targets): ... here; dump both speculative
and non-speculative lists.
(ipa_devirt): Update for new possible_polymorphic_call_targets API.
* ipa-utils.h (possible_polymorphic_call_targets): Update.
2014-09-25 Uros Bizjak <ubizjak@gmail.com> 2014-09-25 Uros Bizjak <ubizjak@gmail.com>
PR rtl-optimization/63348 PR rtl-optimization/63348
...@@ -1884,10 +1884,10 @@ struct polymorphic_call_target_d ...@@ -1884,10 +1884,10 @@ struct polymorphic_call_target_d
ipa_polymorphic_call_context context; ipa_polymorphic_call_context context;
odr_type type; odr_type type;
vec <cgraph_node *> targets; vec <cgraph_node *> targets;
int speculative_targets;
bool complete;
int type_warning;
tree decl_warning; tree decl_warning;
int type_warning;
bool complete;
bool speculative;
}; };
/* Polymorphic call target cache helpers. */ /* Polymorphic call target cache helpers. */
...@@ -1917,6 +1917,7 @@ polymorphic_call_target_hasher::hash (const value_type *odr_query) ...@@ -1917,6 +1917,7 @@ polymorphic_call_target_hasher::hash (const value_type *odr_query)
hstate.merge_hash (TYPE_UID (odr_query->context.speculative_outer_type)); hstate.merge_hash (TYPE_UID (odr_query->context.speculative_outer_type));
hstate.add_wide_int (odr_query->context.speculative_offset); hstate.add_wide_int (odr_query->context.speculative_offset);
} }
hstate.add_flag (odr_query->speculative);
hstate.add_flag (odr_query->context.maybe_in_construction); hstate.add_flag (odr_query->context.maybe_in_construction);
hstate.add_flag (odr_query->context.maybe_derived_type); hstate.add_flag (odr_query->context.maybe_derived_type);
hstate.add_flag (odr_query->context.speculative_maybe_derived_type); hstate.add_flag (odr_query->context.speculative_maybe_derived_type);
...@@ -1931,6 +1932,7 @@ polymorphic_call_target_hasher::equal (const value_type *t1, ...@@ -1931,6 +1932,7 @@ polymorphic_call_target_hasher::equal (const value_type *t1,
const compare_type *t2) const compare_type *t2)
{ {
return (t1->type == t2->type && t1->otr_token == t2->otr_token return (t1->type == t2->type && t1->otr_token == t2->otr_token
&& t1->speculative == t2->speculative
&& t1->context.offset == t2->context.offset && t1->context.offset == t2->context.offset
&& t1->context.speculative_offset == t2->context.speculative_offset && t1->context.speculative_offset == t2->context.speculative_offset
&& t1->context.outer_type == t2->context.outer_type && t1->context.outer_type == t2->context.outer_type
...@@ -3667,10 +3669,8 @@ struct final_warning_record *final_warning_records; ...@@ -3667,10 +3669,8 @@ struct final_warning_record *final_warning_records;
in the target cache. If user needs to visit every target list in the target cache. If user needs to visit every target list
just once, it can memoize them. just once, it can memoize them.
SPECULATION_TARGETS specify number of targets that are speculatively If SPECULATIVE is set, the list will not contain targets that
likely. These include targets specified by the speculative part are not speculatively taken.
of polymoprhic call context and also exclude all targets for classes
in construction.
Returned vector is placed into cache. It is NOT caller's responsibility Returned vector is placed into cache. It is NOT caller's responsibility
to free it. The vector can be freed on cgraph_remove_node call if to free it. The vector can be freed on cgraph_remove_node call if
...@@ -3682,7 +3682,7 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -3682,7 +3682,7 @@ possible_polymorphic_call_targets (tree otr_type,
ipa_polymorphic_call_context context, ipa_polymorphic_call_context context,
bool *completep, bool *completep,
void **cache_token, void **cache_token,
int *speculative_targetsp) bool speculative)
{ {
static struct cgraph_node_hook_list *node_removal_hook_holder; static struct cgraph_node_hook_list *node_removal_hook_holder;
vec <cgraph_node *> nodes = vNULL; vec <cgraph_node *> nodes = vNULL;
...@@ -3706,13 +3706,11 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -3706,13 +3706,11 @@ possible_polymorphic_call_targets (tree otr_type,
*completep = context.invalid; *completep = context.invalid;
if (cache_token) if (cache_token)
*cache_token = NULL; *cache_token = NULL;
if (speculative_targetsp)
*speculative_targetsp = 0;
return nodes; return nodes;
} }
/* Do not bother to compute speculative info when user do not asks for it. */ /* Do not bother to compute speculative info when user do not asks for it. */
if (!speculative_targetsp || !context.speculative_outer_type) if (!speculative || !context.speculative_outer_type)
context.clear_speculation (); context.clear_speculation ();
type = get_odr_type (otr_type, true); type = get_odr_type (otr_type, true);
...@@ -3730,8 +3728,6 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -3730,8 +3728,6 @@ possible_polymorphic_call_targets (tree otr_type,
*completep = true; *completep = true;
if (cache_token) if (cache_token)
*cache_token = NULL; *cache_token = NULL;
if (speculative_targetsp)
*speculative_targetsp = 0;
return nodes; return nodes;
} }
gcc_assert (!context.invalid); gcc_assert (!context.invalid);
...@@ -3783,6 +3779,7 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -3783,6 +3779,7 @@ possible_polymorphic_call_targets (tree otr_type,
/* Lookup cached answer. */ /* Lookup cached answer. */
key.type = type; key.type = type;
key.otr_token = otr_token; key.otr_token = otr_token;
key.speculative = speculative;
key.context = context; key.context = context;
slot = polymorphic_call_target_hash->find_slot (&key, INSERT); slot = polymorphic_call_target_hash->find_slot (&key, INSERT);
if (cache_token) if (cache_token)
...@@ -3791,15 +3788,13 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -3791,15 +3788,13 @@ possible_polymorphic_call_targets (tree otr_type,
{ {
if (completep) if (completep)
*completep = (*slot)->complete; *completep = (*slot)->complete;
if (speculative_targetsp)
*speculative_targetsp = (*slot)->speculative_targets;
if ((*slot)->type_warning && final_warning_records) if ((*slot)->type_warning && final_warning_records)
{ {
final_warning_records->type_warnings[(*slot)->type_warning - 1].count++; final_warning_records->type_warnings[(*slot)->type_warning - 1].count++;
final_warning_records->type_warnings[(*slot)->type_warning - 1].dyn_count final_warning_records->type_warnings[(*slot)->type_warning - 1].dyn_count
+= final_warning_records->dyn_count; += final_warning_records->dyn_count;
} }
if ((*slot)->decl_warning && final_warning_records) if (!speculative && (*slot)->decl_warning && final_warning_records)
{ {
struct decl_warn_count *c = struct decl_warn_count *c =
final_warning_records->decl_warnings.get ((*slot)->decl_warning); final_warning_records->decl_warnings.get ((*slot)->decl_warning);
...@@ -3819,7 +3814,7 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -3819,7 +3814,7 @@ possible_polymorphic_call_targets (tree otr_type,
(*slot)->type = type; (*slot)->type = type;
(*slot)->otr_token = otr_token; (*slot)->otr_token = otr_token;
(*slot)->context = context; (*slot)->context = context;
(*slot)->speculative_targets = 0; (*slot)->speculative = speculative;
hash_set<tree> inserted; hash_set<tree> inserted;
hash_set<tree> matched_vtables; hash_set<tree> matched_vtables;
...@@ -3864,9 +3859,10 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -3864,9 +3859,10 @@ possible_polymorphic_call_targets (tree otr_type,
&speculation_complete, &speculation_complete,
bases_to_consider, bases_to_consider,
false); false);
(*slot)->speculative_targets = nodes.length();
} }
if (!speculative || !nodes.length ())
{
/* First see virtual method of type itself. */ /* First see virtual method of type itself. */
binfo = get_binfo_at_offset (TYPE_BINFO (outer_type->type), binfo = get_binfo_at_offset (TYPE_BINFO (outer_type->type),
context.offset, otr_type); context.offset, otr_type);
...@@ -3916,7 +3912,7 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -3916,7 +3912,7 @@ possible_polymorphic_call_targets (tree otr_type,
if (!outer_type->all_derivations_known) if (!outer_type->all_derivations_known)
{ {
if (final_warning_records) if (!speculative && final_warning_records)
{ {
if (complete if (complete
&& nodes.length () == 1 && nodes.length () == 1
...@@ -3962,10 +3958,8 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -3962,10 +3958,8 @@ possible_polymorphic_call_targets (tree otr_type,
} }
} }
/* Finally walk bases, if asked to. */ if (!speculative)
if (!(*slot)->speculative_targets) {
(*slot)->speculative_targets = nodes.length();
/* Destructors are never called through construction virtual tables, /* Destructors are never called through construction virtual tables,
because the type is always known. One of entries may be cxa_pure_virtual because the type is always known. One of entries may be cxa_pure_virtual
so look to at least two of them. */ so look to at least two of them. */
...@@ -3987,14 +3981,14 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -3987,14 +3981,14 @@ possible_polymorphic_call_targets (tree otr_type,
for (i = 0; i < bases_to_consider.length(); i++) for (i = 0; i < bases_to_consider.length(); i++)
maybe_record_node (nodes, bases_to_consider[i], &inserted, can_refer, &complete); maybe_record_node (nodes, bases_to_consider[i], &inserted, can_refer, &complete);
} }
bases_to_consider.release(); }
}
bases_to_consider.release();
(*slot)->targets = nodes; (*slot)->targets = nodes;
(*slot)->complete = complete; (*slot)->complete = complete;
if (completep) if (completep)
*completep = complete; *completep = complete;
if (speculative_targetsp)
*speculative_targetsp = (*slot)->speculative_targets;
timevar_pop (TV_IPA_VIRTUAL_CALL); timevar_pop (TV_IPA_VIRTUAL_CALL);
return nodes; return nodes;
...@@ -4008,6 +4002,29 @@ add_decl_warning (const tree &key ATTRIBUTE_UNUSED, const decl_warn_count &value ...@@ -4008,6 +4002,29 @@ add_decl_warning (const tree &key ATTRIBUTE_UNUSED, const decl_warn_count &value
return true; return true;
} }
/* Dump target list TARGETS into FILE. */
static void
dump_targets (FILE *f, vec <cgraph_node *> targets)
{
unsigned int i;
for (i = 0; i < targets.length (); i++)
{
char *name = NULL;
if (in_lto_p)
name = cplus_demangle_v3 (targets[i]->asm_name (), 0);
fprintf (f, " %s/%i", name ? name : targets[i]->name (), targets[i]->order);
if (in_lto_p)
free (name);
if (!targets[i]->definition)
fprintf (f, " (no definition%s)",
DECL_DECLARED_INLINE_P (targets[i]->decl)
? " inline" : "");
}
fprintf (f, "\n");
}
/* Dump all possible targets of a polymorphic call. */ /* Dump all possible targets of a polymorphic call. */
void void
...@@ -4019,14 +4036,13 @@ dump_possible_polymorphic_call_targets (FILE *f, ...@@ -4019,14 +4036,13 @@ dump_possible_polymorphic_call_targets (FILE *f,
vec <cgraph_node *> targets; vec <cgraph_node *> targets;
bool final; bool final;
odr_type type = get_odr_type (TYPE_MAIN_VARIANT (otr_type), false); odr_type type = get_odr_type (TYPE_MAIN_VARIANT (otr_type), false);
unsigned int i; unsigned int len;
int speculative;
if (!type) if (!type)
return; return;
targets = possible_polymorphic_call_targets (otr_type, otr_token, targets = possible_polymorphic_call_targets (otr_type, otr_token,
ctx, ctx,
&final, NULL, &speculative); &final, NULL, false);
fprintf (f, " Targets of polymorphic call of type %i:", type->id); fprintf (f, " Targets of polymorphic call of type %i:", type->id);
print_generic_expr (f, type->type, TDF_SLIM); print_generic_expr (f, type->type, TDF_SLIM);
fprintf (f, " token %i\n", (int)otr_token); fprintf (f, " token %i\n", (int)otr_token);
...@@ -4039,23 +4055,19 @@ dump_possible_polymorphic_call_targets (FILE *f, ...@@ -4039,23 +4055,19 @@ dump_possible_polymorphic_call_targets (FILE *f,
ctx.maybe_in_construction ? " (base types included)" : "", ctx.maybe_in_construction ? " (base types included)" : "",
ctx.maybe_derived_type ? " (derived types included)" : "", ctx.maybe_derived_type ? " (derived types included)" : "",
ctx.speculative_maybe_derived_type ? " (speculative derived types included)" : ""); ctx.speculative_maybe_derived_type ? " (speculative derived types included)" : "");
for (i = 0; i < targets.length (); i++) len = targets.length ();
dump_targets (f, targets);
targets = possible_polymorphic_call_targets (otr_type, otr_token,
ctx,
&final, NULL, true);
gcc_assert (targets.length () <= len);
if (targets.length () != len)
{ {
char *name = NULL; fprintf (f, " Speculative targets:");
if (i == (unsigned)speculative) dump_targets (f, targets);
fprintf (f, "\n Targets that are not likely:\n"
" ");
if (in_lto_p)
name = cplus_demangle_v3 (targets[i]->asm_name (), 0);
fprintf (f, " %s/%i", name ? name : targets[i]->name (), targets[i]->order);
if (in_lto_p)
free (name);
if (!targets[i]->definition)
fprintf (f, " (no definition%s)",
DECL_DECLARED_INLINE_P (targets[i]->decl)
? " inline" : "");
} }
fprintf (f, "\n\n"); fprintf (f, "\n");
} }
...@@ -4241,16 +4253,19 @@ ipa_devirt (void) ...@@ -4241,16 +4253,19 @@ ipa_devirt (void)
struct cgraph_node *likely_target = NULL; struct cgraph_node *likely_target = NULL;
void *cache_token; void *cache_token;
bool final; bool final;
int speculative_targets;
if (final_warning_records) if (final_warning_records)
final_warning_records->dyn_count = e->count; final_warning_records->dyn_count = e->count;
vec <cgraph_node *>targets vec <cgraph_node *>targets
= possible_polymorphic_call_targets = possible_polymorphic_call_targets
(e, &final, &cache_token, &speculative_targets); (e, &final, &cache_token, true);
unsigned int i; unsigned int i;
/* Trigger warnings by calculating non-speculative targets. */
if (warn_suggest_final_methods || warn_suggest_final_types)
possible_polymorphic_call_targets (e);
if (dump_file) if (dump_file)
dump_possible_polymorphic_call_targets dump_possible_polymorphic_call_targets
(dump_file, e); (dump_file, e);
...@@ -4289,13 +4304,10 @@ ipa_devirt (void) ...@@ -4289,13 +4304,10 @@ ipa_devirt (void)
{ {
if (likely_target) if (likely_target)
{ {
if (i < (unsigned) speculative_targets)
{
likely_target = NULL; likely_target = NULL;
if (dump_file) if (dump_file)
fprintf (dump_file, "More than one likely target\n\n"); fprintf (dump_file, "More than one likely target\n\n");
nmultiple++; nmultiple++;
}
break; break;
} }
likely_target = targets[i]; likely_target = targets[i];
......
...@@ -62,7 +62,7 @@ possible_polymorphic_call_targets (tree, HOST_WIDE_INT, ...@@ -62,7 +62,7 @@ possible_polymorphic_call_targets (tree, HOST_WIDE_INT,
ipa_polymorphic_call_context, ipa_polymorphic_call_context,
bool *copletep = NULL, bool *copletep = NULL,
void **cache_token = NULL, void **cache_token = NULL,
int *nonconstruction_targets = NULL); bool speuclative = false);
odr_type get_odr_type (tree, bool insert = false); odr_type get_odr_type (tree, bool insert = false);
bool possible_polymorphic_call_target_p (tree ref, gimple stmt, struct cgraph_node *n); bool possible_polymorphic_call_target_p (tree ref, gimple stmt, struct cgraph_node *n);
void dump_possible_polymorphic_call_targets (FILE *, tree, HOST_WIDE_INT, void dump_possible_polymorphic_call_targets (FILE *, tree, HOST_WIDE_INT,
...@@ -92,7 +92,7 @@ inline vec <cgraph_node *> ...@@ -92,7 +92,7 @@ inline vec <cgraph_node *>
possible_polymorphic_call_targets (struct cgraph_edge *e, possible_polymorphic_call_targets (struct cgraph_edge *e,
bool *completep = NULL, bool *completep = NULL,
void **cache_token = NULL, void **cache_token = NULL,
int *nonconstruction_targets = NULL) bool speculative = false)
{ {
ipa_polymorphic_call_context context(e); ipa_polymorphic_call_context context(e);
...@@ -100,7 +100,7 @@ possible_polymorphic_call_targets (struct cgraph_edge *e, ...@@ -100,7 +100,7 @@ possible_polymorphic_call_targets (struct cgraph_edge *e,
e->indirect_info->otr_token, e->indirect_info->otr_token,
context, context,
completep, cache_token, completep, cache_token,
nonconstruction_targets); speculative);
} }
/* Same as above but taking OBJ_TYPE_REF as an parameter. */ /* Same as above but taking OBJ_TYPE_REF as an parameter. */
......
2014-09-25 Jan Hubicka <hubicka@ucw.cz>
* testsuite/g++.dg/ipa/devirt-34.C: Update template.
2014-09-25 James Greenhalgh <james.greenhalgh@arm.com> 2014-09-25 James Greenhalgh <james.greenhalgh@arm.com>
* gcc.target/aarch64/simd/vqshlb_1.c: New. * gcc.target/aarch64/simd/vqshlb_1.c: New.
......
...@@ -15,6 +15,6 @@ t(struct B *b) ...@@ -15,6 +15,6 @@ t(struct B *b)
/* We should guess that the pointer of type B probably points to an instance /* We should guess that the pointer of type B probably points to an instance
of B or its derivates and exclude A::t from list of likely targets. */ of B or its derivates and exclude A::t from list of likely targets. */
/* { dg-final { scan-ipa-dump "Targets that are not likely" "devirt" } } */ /* { dg-final { scan-ipa-dump "Speculative targets" "devirt" } } */
/* { dg-final { scan-ipa-dump "1 speculatively devirtualized" "devirt" } } */ /* { dg-final { scan-ipa-dump "1 speculatively devirtualized" "devirt" } } */
/* { dg-final { cleanup-ipa-dump "devirt" } } */ /* { dg-final { cleanup-ipa-dump "devirt" } } */
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