Hello,
When doing PGO or autofdo we should first read the FDO info and
create speculative edges based on it.
Later speculation is made by ipa-devirt and ipa-prop. If profile feedback
is available (i.e. edge->speculative is true) we do not want to add another
speculation. First we do not know how to redistribute probabilities and
profile info should be more accurate.
ipa-devirt already has check
if (e->speculative)
{
if (dump_file)
fprintf (dump_file, "Call is already speculated\n\n");
stats.nspeculated++;
/* When dumping see if we agree with speculation. */
if (!dump_file)
continue;
}
...
/* This is reached only when dumping; check if we agree or
disagree
with the speculation. */
if (e->speculative)
{
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");
stats.nok++;
}
else
{
fprintf (dump_file, "We disagree with speculation\n\n");
stats.nwrong++;
}
continue;
}
Similarly ipa-prop avoids double-speculation
/* If the edge is already speculated. */
if (speculative && ie->speculative)
{
if (dump_file)
{
cgraph_edge *e2 = ie->speculative_call_for_target (callee);
if (!e2)
{
if (dump_file)
fprintf (dump_file, "ipa-prop: Discovered call to a "
"speculative target (%s -> %s) but the call is "
"already speculated to different target. "
"Giving up.\n",
ie->caller->dump_name (), callee->dump_name ());
}
else
{
if (dump_file)
fprintf (dump_file,
"ipa-prop: Discovered call to a speculative target
"
"(%s -> %s) this agree with previous
speculation.\n",
ie->caller->dump_name (), callee->dump_name ());
}
}
return NULL;
}
So I wonder how the additional speculation is created at the first place?
Is it via ipa_merge_profiles?
Honza
On Fri, Jan 9, 2026 at 7:51 AM Kugan Vivekanandarajah <
[email protected]> wrote:
>
>
> > On 9 Jan 2026, at 5:48 pm, Kugan Vivekanandarajah <
> [email protected]> wrote:
> >
> > The issue is shows up in AutoFDO with:
> >
> > • Multiple speculative calls within a single function.
> > • Complex interactions between the AutoFDO early-inliner,
> devirtualization, and indirect call transformation.
> > • The ICE triggers when these calls are processed across different
> IPA passes that inadvertently disrupt the cgraph_edge linked-list adjacency.
> >
> > See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123496
> >
> > I have two patches that ensures the call-graph and call_site_hash
> invariants are maintained during edge creation/redirection.
> >
> > First patch measure that we don't create the same speculative edges are
> not adding from different optimisations
> > Send patch measure that the order is maintained.
> >
> > Bootstrapped and regression tested with now new regressions on
> aarch64-linux-gnu with no new regressions.
> >
> > Is this OK?
> >
>
> When creating speculative edges, ensure they remain adjacent in the callees
> list to satisfy verification requirements. The create_edge() function
> always
> inserts new edges at the head of the list, which can break adjacency when
> multiple speculative edges exist for the same call statement.
>
> gcc/ChangeLog:
>
> * cgraph.cc (cgraph_edge::make_speculative): Find the last existing
> speculative edge for the same call_stmt and insert the new edge
> adjacent to it, maintaining the verification invariant.
>
>
> Thanks,
> Kugan
>