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
This commit is contained in:
Jan Hubicka 2014-07-30 09:48:13 +02:00 committed by Jan Hubicka
parent bb3ec3881e
commit a0fd33735a
4 changed files with 122 additions and 30 deletions

View File

@ -1,3 +1,18 @@
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>
* config/vxworksae.h (VXWORKS_OVERRIDE_OPTIONS): Define.

View File

@ -588,7 +588,7 @@ Wmissing-noreturn
Common Alias(Wsuggest-attribute=noreturn)
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
Woverflow

View File

@ -1615,7 +1615,7 @@ struct polymorphic_call_target_d
ipa_polymorphic_call_context context;
odr_type type;
vec <cgraph_node *> targets;
int nonconstruction_targets;
int speculative_targets;
bool complete;
};
@ -1770,8 +1770,8 @@ get_class_context (ipa_polymorphic_call_context *context,
if (!context->outer_type)
{
context->outer_type = expected_type;
context->offset = offset;
type = context->outer_type = expected_type;
context->offset = offset = 0;
}
/* 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
@ -1807,6 +1807,10 @@ get_class_context (ipa_polymorphic_call_context *context,
/* On a match, just return what we found. */
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))
{
if (speculative)
@ -2518,9 +2522,10 @@ devirt_variable_node_removal_hook (varpool_node *n,
in the target cache. If user needs to visit every target list
just once, it can memoize them.
NONCONSTRUCTION_TARGETS specify number of targets with asumption that
the type is not in the construction. Those targets appear first in the
vector returned.
SPECULATION_TARGETS specify number of targets that are speculatively
likely. These include targets specified by the speculative part
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
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,
ipa_polymorphic_call_context context,
bool *completep,
void **cache_token,
int *nonconstruction_targetsp)
int *speculative_targetsp)
{
static struct cgraph_node_hook_list *node_removal_hook_holder;
pointer_set_t *inserted;
@ -2557,8 +2562,8 @@ possible_polymorphic_call_targets (tree otr_type,
*completep = false;
if (cache_token)
*cache_token = NULL;
if (nonconstruction_targetsp)
*nonconstruction_targetsp = 0;
if (speculative_targetsp)
*speculative_targetsp = 0;
return nodes;
}
@ -2569,8 +2574,8 @@ possible_polymorphic_call_targets (tree otr_type,
*completep = true;
if (cache_token)
*cache_token = NULL;
if (nonconstruction_targetsp)
*nonconstruction_targetsp = 0;
if (speculative_targetsp)
*speculative_targetsp = 0;
return nodes;
}
@ -2581,15 +2586,15 @@ possible_polymorphic_call_targets (tree otr_type,
|| TYPE_MAIN_VARIANT (context.outer_type) == context.outer_type);
/* 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))
{
if (completep)
*completep = false;
if (cache_token)
*cache_token = NULL;
if (nonconstruction_targetsp)
*nonconstruction_targetsp = 0;
if (speculative_targetsp)
*speculative_targetsp = 0;
return nodes;
}
@ -2638,8 +2643,8 @@ possible_polymorphic_call_targets (tree otr_type,
{
if (completep)
*completep = (*slot)->complete;
if (nonconstruction_targetsp)
*nonconstruction_targetsp = (*slot)->nonconstruction_targets;
if (speculative_targetsp)
*speculative_targetsp = (*slot)->speculative_targets;
return (*slot)->targets;
}
@ -2653,10 +2658,57 @@ possible_polymorphic_call_targets (tree otr_type,
(*slot)->type = type;
(*slot)->otr_token = otr_token;
(*slot)->context = context;
(*slot)->speculative_targets = 0;
inserted = 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. */
binfo = get_binfo_at_offset (TYPE_BINFO (outer_type->type),
context.offset, otr_type);
@ -2713,7 +2765,8 @@ possible_polymorphic_call_targets (tree otr_type,
}
/* 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,
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,
(*slot)->complete = complete;
if (completep)
*completep = complete;
if (nonconstruction_targetsp)
*nonconstruction_targetsp = (*slot)->nonconstruction_targets;
if (speculative_targetsp)
*speculative_targetsp = (*slot)->speculative_targets;
pointer_set_destroy (inserted);
pointer_set_destroy (matched_vtables);
@ -2763,13 +2816,13 @@ dump_possible_polymorphic_call_targets (FILE *f,
bool final;
odr_type type = get_odr_type (TYPE_MAIN_VARIANT (otr_type), false);
unsigned int i;
int nonconstruction;
int speculative;
if (!type)
return;
targets = possible_polymorphic_call_targets (otr_type, otr_token,
ctx,
&final, NULL, &nonconstruction);
&final, NULL, &speculative);
fprintf (f, " Targets of polymorphic call of type %i:", type->id);
print_generic_expr (f, type->type, TDF_SLIM);
fprintf (f, " token %i\n", (int)otr_token);
@ -2780,18 +2833,25 @@ dump_possible_polymorphic_call_targets (FILE *f,
fprintf (f, " at offset "HOST_WIDE_INT_PRINT_DEC"\n",
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." :
"This is partial list; extra targets may be defined in other units.",
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++)
{
char *name = NULL;
if (i == (unsigned)nonconstruction)
fprintf (f, "\n If the type is in construction,"
" then additional tarets are:\n"
if (i == (unsigned)speculative)
fprintf (f, "\n Targets that are not likely:\n"
" ");
if (in_lto_p)
name = cplus_demangle_v3 (targets[i]->asm_name (), 0);
@ -2921,10 +2981,10 @@ ipa_devirt (void)
struct cgraph_node *likely_target = NULL;
void *cache_token;
bool final;
int nonconstruction_targets;
int speculative_targets;
vec <cgraph_node *>targets
= possible_polymorphic_call_targets
(e, &final, &cache_token, &nonconstruction_targets);
(e, &final, &cache_token, &speculative_targets);
unsigned int i;
if (dump_file)
@ -2963,7 +3023,7 @@ ipa_devirt (void)
{
if (likely_target)
{
if (i < (unsigned) nonconstruction_targets)
if (i < (unsigned) speculative_targets)
{
likely_target = NULL;
if (dump_file)

View File

@ -0,0 +1,17 @@
/* { 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" } } */