fprintf (dump_file, "Speculative call turned into direct call.\n");
edge = e2;
e2 = tmp;
- /* FIXME: If EDGE is inlined, we should scale up the frequencies and counts
- in the functions inlined through it. */
+ /* FIXME: If EDGE is inlined, we should scale up the frequencies
+ and counts in the functions inlined through it. */
}
edge->count += e2->count;
if (edge->num_speculative_call_targets_p ())
/* If we are redirecting speculative call, make it non-speculative. */
if (edge->speculative)
{
- edge = resolve_speculation (edge, callee->decl);
+ cgraph_edge *found = NULL;
+ cgraph_edge *direct, *next;
+ ipa_ref *ref;
+
+ edge->speculative_call_info (direct, edge, ref);
- /* On successful speculation just return the pre existing direct edge. */
- if (!edge->indirect_unknown_callee)
- return edge;
+ /* Look all speculative targets and remove all but one corresponding
+ to callee (if it exists).
+ If there is only one target we can save one extra call to
+ speculative_call_info. */
+ if (edge->num_speculative_call_targets_p () != 1)
+ for (direct = edge->caller->callees; direct; direct = next)
+ {
+ next = direct->next_callee;
+ if (direct->call_stmt == edge->call_stmt
+ && direct->lto_stmt_uid == edge->lto_stmt_uid)
+ {
+ direct->speculative_call_info (direct, edge, ref);
+
+ /* Compare ref not direct->callee. Direct edge is possibly
+ inlined or redirected. */
+ if (!ref->referred->semantically_equivalent_p (callee))
+ edge = direct->resolve_speculation (direct, NULL);
+ else
+ {
+ gcc_checking_assert (!found);
+ found = direct;
+ }
+ }
+ }
+ else if (!ref->referred->semantically_equivalent_p (callee))
+ edge = direct->resolve_speculation (direct, NULL);
+ else
+ found = direct;
+
+ /* On successful speculation just remove the indirect edge and
+ return the pre existing direct edge.
+ It is important to not remove it and redirect because the direct
+ edge may be inlined or redirected. */
+ if (found)
+ {
+ resolve_speculation (edge, callee->decl);
+ gcc_checking_assert (!found->speculative);
+ return found;
+ }
+ gcc_checking_assert (!edge->speculative);
}
edge->indirect_unknown_callee = 0;
/* If there already is an direct call (i.e. as a result of inliner's
substitution), forget about speculating. */
if (decl)
- e = resolve_speculation (e, decl);
+ e = make_direct (e, cgraph_node::get (decl));
else
{
/* Expand speculation into GIMPLE code. */
basic_block this_block;
gimple_stmt_iterator gsi;
bool error_found = false;
+ int i;
+ ipa_ref *ref = NULL;
if (seen_error ())
return;
cgraph_debug_gimple_stmt (this_cfun, e->call_stmt);
error_found = true;
}
+ if (e->call_stmt && e->lto_stmt_uid)
+ {
+ error ("edge has both cal_stmt and lto_stmt_uid set");
+ error_found = true;
+ }
}
bool check_comdat = comdat_local_p ();
for (e = callers; e; e = e->next_caller)
fprintf (stderr, "\n");
error_found = true;
}
+ if (e->call_stmt && e->lto_stmt_uid)
+ {
+ error ("edge has both cal_stmt and lto_stmt_uid set");
+ error_found = true;
+ }
}
for (e = indirect_calls; e; e = e->next_callee)
{
if (this_cfun->cfg)
{
hash_set<gimple *> stmts;
- int i;
- ipa_ref *ref = NULL;
/* Reach the trees by walking over the CFG, and note the
enclosing basic-blocks in the call edges. */
/* No CFG available?! */
gcc_unreachable ();
+ for (i = 0; iterate_reference (i, ref); i++)
+ if (ref->stmt && ref->lto_stmt_uid)
+ {
+ error ("reference has both cal_stmt and lto_stmt_uid set");
+ error_found = true;
+ }
+
for (e = callees; e; e = e->next_callee)
{
if (!e->aux && !e->speculative)
edge->count.stream_out (ob->main_stream);
bp = bitpack_create (ob->main_stream);
- uid = (!gimple_has_body_p (edge->caller->decl) || edge->caller->thunk.thunk_p
- ? edge->lto_stmt_uid : gimple_uid (edge->call_stmt) + 1);
+ uid = !edge->call_stmt ? edge->lto_stmt_uid
+ : gimple_uid (edge->call_stmt) + 1;
bp_pack_enum (&bp, cgraph_inline_failed_t,
CIF_N_REASONS, edge->inline_failed);
+ gcc_checking_assert (uid || edge->caller->thunk.thunk_p);
bp_pack_var_len_unsigned (&bp, uid);
bp_pack_value (&bp, edge->speculative_id, 16);
bp_pack_value (&bp, edge->indirect_inlining_edge, 1);
{
struct bitpack_d bp;
int nref;
- int uid = ref->lto_stmt_uid;
+ int uid = !ref->stmt ? ref->lto_stmt_uid : gimple_uid (ref->stmt) + 1;
struct cgraph_node *node;
bp = bitpack_create (ob->main_stream);
fatal_error (input_location,
"Cgraph edge statement index out of range");
cedge->call_stmt = as_a <gcall *> (stmts[cedge->lto_stmt_uid - 1]);
+ cedge->lto_stmt_uid = 0;
if (!cedge->call_stmt)
fatal_error (input_location,
"Cgraph edge statement index not found");
fatal_error (input_location,
"Cgraph edge statement index out of range");
cedge->call_stmt = as_a <gcall *> (stmts[cedge->lto_stmt_uid - 1]);
+ cedge->lto_stmt_uid = 0;
if (!cedge->call_stmt)
fatal_error (input_location, "Cgraph edge statement index not found");
}
fatal_error (input_location,
"Reference statement index out of range");
ref->stmt = stmts[ref->lto_stmt_uid - 1];
+ ref->lto_stmt_uid = 0;
if (!ref->stmt)
fatal_error (input_location, "Reference statement index not found");
}