for (e = n->indirect_calls; e; e = e->next_callee)
if (e->indirect_info->polymorphic)
{
- struct cgraph_node *likely_target = NULL;
void *cache_token;
bool final;
nmultiple++;
continue;
}
+ auto_vec <cgraph_node *, 20> likely_targets;
for (i = 0; i < targets.length (); i++)
if (likely_target_p (targets[i]))
{
- if (likely_target)
+ if ((int)likely_targets.length () >= param_max_devirt_targets)
{
- likely_target = NULL;
+ likely_targets.truncate (0);
if (dump_file)
- fprintf (dump_file, "More than one likely target\n\n");
+ fprintf (dump_file, "More than %i likely targets\n\n",
+ param_max_devirt_targets);
nmultiple++;
break;
}
- likely_target = targets[i];
+ likely_targets.safe_push (targets[i]);
}
- if (!likely_target)
+ if (!likely_targets.length ())
{
bad_call_targets.add (cache_token);
continue;
with the speculation. */
if (e->speculative)
{
- bool found = e->speculative_call_for_target (likely_target);
+ bool found = false;
+ for (cgraph_node * likely_target: likely_targets)
+ if (e->speculative_call_for_target (likely_target))
+ {
+ found = true;
+ break;
+ }
if (found)
{
fprintf (dump_file, "We agree with speculation\n\n");
}
continue;
}
- if (!likely_target->definition)
+ bool first = true;
+ unsigned speculative_id = 0;
+ for (cgraph_node * likely_target: likely_targets)
{
- if (dump_file)
- fprintf (dump_file, "Target is not a definition\n\n");
- nnotdefined++;
- continue;
- }
- /* Do not introduce new references to external symbols. While we
- can handle these just well, it is common for programs to
- incorrectly with headers defining methods they are linked
- with. */
- if (DECL_EXTERNAL (likely_target->decl))
- {
- if (dump_file)
- fprintf (dump_file, "Target is external\n\n");
- nexternal++;
- continue;
- }
- /* Don't use an implicitly-declared destructor (c++/58678). */
- struct cgraph_node *non_thunk_target
- = likely_target->function_symbol ();
- if (DECL_ARTIFICIAL (non_thunk_target->decl))
- {
- if (dump_file)
- fprintf (dump_file, "Target is artificial\n\n");
- nartificial++;
- continue;
- }
- if (likely_target->get_availability () <= AVAIL_INTERPOSABLE
- && likely_target->can_be_discarded_p ())
- {
- if (dump_file)
- fprintf (dump_file, "Target is overwritable\n\n");
- noverwritable++;
- continue;
- }
- else if (dbg_cnt (devirt))
- {
- if (dump_enabled_p ())
- {
- dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, e->call_stmt,
- "speculatively devirtualizing call "
- "in %s to %s\n",
- n->dump_name (),
- likely_target->dump_name ());
- }
- if (!likely_target->can_be_discarded_p ())
+ if (!likely_target->definition)
+ {
+ if (dump_file)
+ fprintf (dump_file, "Target is not a definition\n\n");
+ nnotdefined++;
+ continue;
+ }
+ /* Do not introduce new references to external symbols. While we
+ can handle these just well, it is common for programs to
+ incorrectly with headers defining methods they are linked
+ with. */
+ if (DECL_EXTERNAL (likely_target->decl))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Target is external\n\n");
+ nexternal++;
+ continue;
+ }
+ /* Don't use an implicitly-declared destructor (c++/58678). */
+ struct cgraph_node *non_thunk_target
+ = likely_target->function_symbol ();
+ if (DECL_ARTIFICIAL (non_thunk_target->decl))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Target is artificial\n\n");
+ nartificial++;
+ continue;
+ }
+ if (likely_target->get_availability () <= AVAIL_INTERPOSABLE
+ && likely_target->can_be_discarded_p ())
{
- cgraph_node *alias;
- alias = dyn_cast<cgraph_node *> (likely_target->noninterposable_alias ());
- if (alias)
- likely_target = alias;
+ if (dump_file)
+ fprintf (dump_file, "Target is overwritable\n\n");
+ noverwritable++;
+ continue;
}
- nconverted++;
- update = true;
- e->make_speculative
- (likely_target, e->count.apply_scale (8, 10));
+ else if (dbg_cnt (devirt))
+ {
+ if (dump_enabled_p ())
+ {
+ dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, e->call_stmt,
+ "speculatively devirtualizing call "
+ "in %s to %s\n",
+ n->dump_name (),
+ likely_target->dump_name ());
+ }
+ if (!likely_target->can_be_discarded_p ())
+ {
+ cgraph_node *alias;
+ alias = dyn_cast<cgraph_node *> (likely_target->noninterposable_alias ());
+ if (alias)
+ likely_target = alias;
+ }
+ if (first)
+ nconverted++;
+ first = false;
+ update = true;
+ e->make_speculative
+ (likely_target,
+ e->count.apply_scale (8, 10 * likely_targets.length ()),
+ speculative_id++);
+ }
+ }
+ if (speculative_id > 1 && dump_enabled_p ())
+ {
+ dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, e->call_stmt,
+ "devirtualized call in %s to %i targets\n",
+ n->dump_name (),
+ speculative_id);
}
}
if (update)