Commit a0fd3373 by Jan Hubicka Committed by Jan Hubicka

devirt-34.C: New testcase.


	* g++.dg/ipa/devirt-34.C: New testcase.
	* ipa-devirt.c (polymorphic_call_target_d): Rename nonconstruction_targets
	to speculative_targets
	(get_class_context): Fix handling of contextes without outer type;
	avoid matching non-polymorphic types in LTO.
	(possible_polymorphic_call_targets): Trun nonconstruction_targetsp
	parameter to speculative_targetsp; handle speculation.
	(dump_possible_polymorphic_call_targets): Update dumping.

From-SVN: r213232
parent bb3ec388
2014-07-29 Jan Hubicka <hubicka@ucw.cz>
* g++.dg/ipa/devirt-34.C: New testcase.
* ipa-devirt.c (polymorphic_call_target_d): Rename nonconstruction_targets
to speculative_targets
(get_class_context): Fix handling of contextes without outer type;
avoid matching non-polymorphic types in LTO.
(possible_polymorphic_call_targets): Trun nonconstruction_targetsp
parameter to speculative_targetsp; handle speculation.
(dump_possible_polymorphic_call_targets): Update dumping.
2014-07-29 Jan Hubicka <hubicka@ucw.cz>
* common.opt (Wodr): Enable by default.
2014-07-29 Olivier Hainque <hainque@adacore.com> 2014-07-29 Olivier Hainque <hainque@adacore.com>
* config/vxworksae.h (VXWORKS_OVERRIDE_OPTIONS): Define. * config/vxworksae.h (VXWORKS_OVERRIDE_OPTIONS): Define.
......
...@@ -588,7 +588,7 @@ Wmissing-noreturn ...@@ -588,7 +588,7 @@ Wmissing-noreturn
Common Alias(Wsuggest-attribute=noreturn) Common Alias(Wsuggest-attribute=noreturn)
Wodr Wodr
Common Var(warn_odr_violations) Warning Common Var(warn_odr_violations) Init(1) Warning
Warn about some C++ One Definition Rule violations during link time optimization Warn about some C++ One Definition Rule violations during link time optimization
Woverflow Woverflow
......
...@@ -1615,7 +1615,7 @@ struct polymorphic_call_target_d ...@@ -1615,7 +1615,7 @@ 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 nonconstruction_targets; int speculative_targets;
bool complete; bool complete;
}; };
...@@ -1770,8 +1770,8 @@ get_class_context (ipa_polymorphic_call_context *context, ...@@ -1770,8 +1770,8 @@ get_class_context (ipa_polymorphic_call_context *context,
if (!context->outer_type) if (!context->outer_type)
{ {
context->outer_type = expected_type; type = context->outer_type = expected_type;
context->offset = offset; context->offset = offset = 0;
} }
/* See if speculative type seem to be derrived from outer_type. /* 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 Then speculation is valid only if it really is a derivate and derived types
...@@ -1807,6 +1807,10 @@ get_class_context (ipa_polymorphic_call_context *context, ...@@ -1807,6 +1807,10 @@ get_class_context (ipa_polymorphic_call_context *context,
/* On a match, just return what we found. */ /* On a match, just return what we found. */
if (TREE_CODE (type) == TREE_CODE (expected_type) if (TREE_CODE (type) == TREE_CODE (expected_type)
&& (!in_lto_p
|| (TREE_CODE (type) == RECORD_TYPE
&& TYPE_BINFO (type)
&& polymorphic_type_binfo_p (TYPE_BINFO (type))))
&& types_same_for_odr (type, expected_type)) && types_same_for_odr (type, expected_type))
{ {
if (speculative) if (speculative)
...@@ -2518,9 +2522,10 @@ devirt_variable_node_removal_hook (varpool_node *n, ...@@ -2518,9 +2522,10 @@ devirt_variable_node_removal_hook (varpool_node *n,
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.
NONCONSTRUCTION_TARGETS specify number of targets with asumption that SPECULATION_TARGETS specify number of targets that are speculatively
the type is not in the construction. Those targets appear first in the likely. These include targets specified by the speculative part
vector returned. 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
...@@ -2532,7 +2537,7 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -2532,7 +2537,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 *nonconstruction_targetsp) int *speculative_targetsp)
{ {
static struct cgraph_node_hook_list *node_removal_hook_holder; static struct cgraph_node_hook_list *node_removal_hook_holder;
pointer_set_t *inserted; pointer_set_t *inserted;
...@@ -2557,8 +2562,8 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -2557,8 +2562,8 @@ possible_polymorphic_call_targets (tree otr_type,
*completep = false; *completep = false;
if (cache_token) if (cache_token)
*cache_token = NULL; *cache_token = NULL;
if (nonconstruction_targetsp) if (speculative_targetsp)
*nonconstruction_targetsp = 0; *speculative_targetsp = 0;
return nodes; return nodes;
} }
...@@ -2569,8 +2574,8 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -2569,8 +2574,8 @@ possible_polymorphic_call_targets (tree otr_type,
*completep = true; *completep = true;
if (cache_token) if (cache_token)
*cache_token = NULL; *cache_token = NULL;
if (nonconstruction_targetsp) if (speculative_targetsp)
*nonconstruction_targetsp = 0; *speculative_targetsp = 0;
return nodes; return nodes;
} }
...@@ -2581,15 +2586,15 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -2581,15 +2586,15 @@ possible_polymorphic_call_targets (tree otr_type,
|| TYPE_MAIN_VARIANT (context.outer_type) == context.outer_type); || TYPE_MAIN_VARIANT (context.outer_type) == context.outer_type);
/* Lookup the outer class type we want to walk. */ /* Lookup the outer class type we want to walk. */
if (context.outer_type if ((context.outer_type || context.speculative_outer_type)
&& !get_class_context (&context, otr_type)) && !get_class_context (&context, otr_type))
{ {
if (completep) if (completep)
*completep = false; *completep = false;
if (cache_token) if (cache_token)
*cache_token = NULL; *cache_token = NULL;
if (nonconstruction_targetsp) if (speculative_targetsp)
*nonconstruction_targetsp = 0; *speculative_targetsp = 0;
return nodes; return nodes;
} }
...@@ -2638,8 +2643,8 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -2638,8 +2643,8 @@ possible_polymorphic_call_targets (tree otr_type,
{ {
if (completep) if (completep)
*completep = (*slot)->complete; *completep = (*slot)->complete;
if (nonconstruction_targetsp) if (speculative_targetsp)
*nonconstruction_targetsp = (*slot)->nonconstruction_targets; *speculative_targetsp = (*slot)->speculative_targets;
return (*slot)->targets; return (*slot)->targets;
} }
...@@ -2653,10 +2658,57 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -2653,10 +2658,57 @@ 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;
inserted = pointer_set_create (); inserted = pointer_set_create ();
matched_vtables = pointer_set_create (); matched_vtables = pointer_set_create ();
if (context.speculative_outer_type)
{
odr_type speculative_outer_type;
speculative_outer_type = get_odr_type (context.speculative_outer_type, true);
if (TYPE_FINAL_P (speculative_outer_type->type))
context.speculative_maybe_derived_type = false;
binfo = get_binfo_at_offset (TYPE_BINFO (speculative_outer_type->type),
context.speculative_offset, otr_type);
if (binfo)
target = gimple_get_virt_method_for_binfo (otr_token, binfo,
&can_refer);
else
target = NULL;
if (target)
{
/* In the case we get complete method, we don't need
to walk derivations. */
if (DECL_FINAL_P (target))
context.speculative_maybe_derived_type = false;
}
if (type_possibly_instantiated_p (speculative_outer_type->type))
maybe_record_node (nodes, target, inserted, can_refer, &complete);
if (binfo)
pointer_set_insert (matched_vtables, BINFO_VTABLE (binfo));
/* Next walk recursively all derived types. */
if (context.speculative_maybe_derived_type)
{
/* For anonymous namespace types we can attempt to build full type.
All derivations must be in this unit (unless we see partial unit). */
if (!type->all_derivations_known)
complete = false;
for (i = 0; i < speculative_outer_type->derived_types.length(); i++)
possible_polymorphic_call_targets_1 (nodes, inserted,
matched_vtables,
otr_type,
speculative_outer_type->derived_types[i],
otr_token, speculative_outer_type->type,
context.speculative_offset, &complete,
bases_to_consider,
false);
}
/* Finally walk bases, if asked to. */
(*slot)->speculative_targets = 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);
...@@ -2713,7 +2765,8 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -2713,7 +2765,8 @@ possible_polymorphic_call_targets (tree otr_type,
} }
/* Finally walk bases, if asked to. */ /* Finally walk bases, if asked to. */
(*slot)->nonconstruction_targets = nodes.length(); 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
...@@ -2742,8 +2795,8 @@ possible_polymorphic_call_targets (tree otr_type, ...@@ -2742,8 +2795,8 @@ possible_polymorphic_call_targets (tree otr_type,
(*slot)->complete = complete; (*slot)->complete = complete;
if (completep) if (completep)
*completep = complete; *completep = complete;
if (nonconstruction_targetsp) if (speculative_targetsp)
*nonconstruction_targetsp = (*slot)->nonconstruction_targets; *speculative_targetsp = (*slot)->speculative_targets;
pointer_set_destroy (inserted); pointer_set_destroy (inserted);
pointer_set_destroy (matched_vtables); pointer_set_destroy (matched_vtables);
...@@ -2763,13 +2816,13 @@ dump_possible_polymorphic_call_targets (FILE *f, ...@@ -2763,13 +2816,13 @@ dump_possible_polymorphic_call_targets (FILE *f,
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 i;
int nonconstruction; 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, &nonconstruction); &final, NULL, &speculative);
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);
...@@ -2780,18 +2833,25 @@ dump_possible_polymorphic_call_targets (FILE *f, ...@@ -2780,18 +2833,25 @@ dump_possible_polymorphic_call_targets (FILE *f,
fprintf (f, " at offset "HOST_WIDE_INT_PRINT_DEC"\n", fprintf (f, " at offset "HOST_WIDE_INT_PRINT_DEC"\n",
ctx.offset); ctx.offset);
} }
if (ctx.speculative_outer_type)
{
fprintf (f, " Speculatively contained in type:");
print_generic_expr (f, ctx.speculative_outer_type, TDF_SLIM);
fprintf (f, " at offset "HOST_WIDE_INT_PRINT_DEC"\n",
ctx.speculative_offset);
}
fprintf (f, " %s%s%s\n ", fprintf (f, " %s%s%s%s\n ",
final ? "This is a complete list." : final ? "This is a complete list." :
"This is partial list; extra targets may be defined in other units.", "This is partial list; extra targets may be defined in other units.",
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)" : "");
for (i = 0; i < targets.length (); i++) for (i = 0; i < targets.length (); i++)
{ {
char *name = NULL; char *name = NULL;
if (i == (unsigned)nonconstruction) if (i == (unsigned)speculative)
fprintf (f, "\n If the type is in construction," fprintf (f, "\n Targets that are not likely:\n"
" then additional tarets are:\n"
" "); " ");
if (in_lto_p) if (in_lto_p)
name = cplus_demangle_v3 (targets[i]->asm_name (), 0); name = cplus_demangle_v3 (targets[i]->asm_name (), 0);
...@@ -2921,10 +2981,10 @@ ipa_devirt (void) ...@@ -2921,10 +2981,10 @@ 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 nonconstruction_targets; int speculative_targets;
vec <cgraph_node *>targets vec <cgraph_node *>targets
= possible_polymorphic_call_targets = possible_polymorphic_call_targets
(e, &final, &cache_token, &nonconstruction_targets); (e, &final, &cache_token, &speculative_targets);
unsigned int i; unsigned int i;
if (dump_file) if (dump_file)
...@@ -2963,7 +3023,7 @@ ipa_devirt (void) ...@@ -2963,7 +3023,7 @@ ipa_devirt (void)
{ {
if (likely_target) if (likely_target)
{ {
if (i < (unsigned) nonconstruction_targets) if (i < (unsigned) speculative_targets)
{ {
likely_target = NULL; likely_target = NULL;
if (dump_file) if (dump_file)
......
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-ipa-devirt" } */
struct A {virtual int t(){return 42;}};
struct B:A {virtual int t(){return 1;}};
int
t(struct B *b)
{
struct A *a=b;
a->t();
}
/* 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. */
/* { dg-final { scan-ipa-dump "Targets that are not likely" "devirt" } } */
/* { dg-final { scan-ipa-dump "1 speculatively devirtualized" "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