summaryrefslogtreecommitdiff
path: root/gcc/ipa-devirt.c
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2014-07-30 07:48:13 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2014-07-30 07:48:13 +0000
commit01cb9cf792422ba7809475a477e859cfa93d176d (patch)
treebb01706109f71a5e58004af1b340b038a77eb8d7 /gcc/ipa-devirt.c
parent4dd4ac768fa98463bcb31e949d64c9b5a7120331 (diff)
downloadgcc-01cb9cf792422ba7809475a477e859cfa93d176d.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@213232 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/ipa-devirt.c')
-rw-r--r--gcc/ipa-devirt.c118
1 files changed, 89 insertions, 29 deletions
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index 4b5b2a659c0..1c6d19dbc88 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -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)