/* Compare ref not direct->callee. Direct edge is possibly
inlined or redirected. */
if (!direct->speculative_call_target_ref ()
- ->referred->semantically_equivalent_p (callee))
+ ->referred->semantically_equivalent_p (callee)
+ || found)
edge = direct->resolve_speculation (direct, NULL);
else
- {
- gcc_checking_assert (!found);
- found = direct;
- }
+ found = direct;
}
/* On successful speculation just remove the indirect edge and
: caller->count);
}
+/* Expected frequency of executions within the function.
+ If edge is speculative, sum all its indirect targets. */
+
+sreal
+cgraph_edge::combined_sreal_frequency ()
+{
+ if (!speculative)
+ return sreal_frequency ();
+ cgraph_edge *e = this;
+ if (e->callee)
+ e = e->speculative_call_indirect_edge ();
+ sreal sum = e->sreal_frequency ();
+ for (e = e->first_speculative_call_target ();
+ e;
+ e = e->next_speculative_call_target ())
+ sum += e->sreal_frequency ();
+ return sum;
+}
+
/* During LTO stream in this can be used to check whether call can possibly
be internal to the current translation unit. */
/* Expected frequency of executions within the function. */
sreal sreal_frequency ();
+
+ /* Expected frequency of executions within the function.
+ If edge is speculative, sum all its indirect targets. */
+ sreal combined_sreal_frequency ();
private:
/* Unique id of the edge. */
int m_uid;
}
/* Calculate devirtualization time bonus for NODE, assuming we know information
- about arguments stored in AVALS. */
+ about arguments stored in AVALS.
-static int
+ FIXME: This function will also consider devirtualization of calls that are
+ known to be dead in the clone. */
+
+static sreal
devirtualization_time_bonus (struct cgraph_node *node,
ipa_auto_call_arg_values *avals)
{
struct cgraph_edge *ie;
- int res = 0;
+ sreal res = 0;
for (ie = node->indirect_calls; ie; ie = ie->next_callee)
{
continue;
/* Only bare minimum benefit for clearly un-inlineable targets. */
- res += 1;
+ int savings = 1;
callee = cgraph_node::get (target);
if (!callee || !callee->definition)
continue;
int max_inline_insns_auto
= opt_for_fn (callee->decl, param_max_inline_insns_auto);
if (size <= max_inline_insns_auto / 4)
- res += 31 / ((int)speculative + 1);
+ savings += 31 / ((int)speculative + 1);
else if (size <= max_inline_insns_auto / 2)
- res += 15 / ((int)speculative + 1);
+ savings += 15 / ((int)speculative + 1);
else if (size <= max_inline_insns_auto
|| DECL_DECLARED_INLINE_P (callee->decl))
- res += 7 / ((int)speculative + 1);
+ savings += 7 / ((int)speculative + 1);
+ res = res + ie->combined_sreal_frequency () * (sreal) savings;
}
return res;
ipa_auto_call_arg_values avals;
always_const = gather_context_independent_values (info, &avals, true,
&removable_params_cost);
- int devirt_bonus = devirtualization_time_bonus (node, &avals);
- if (always_const || devirt_bonus
+ sreal devirt_bonus = devirtualization_time_bonus (node, &avals);
+ if (always_const || devirt_bonus > 0
|| (removable_params_cost && clone_for_param_removal_p (node)))
{
struct caller_statistics stats;