[gcc r9-9291] ipa: Fix resolving speculations through cgraph_edge::set_call_stmt
Martin Jambor
jamborm@gcc.gnu.org
Wed Mar 17 10:35:06 GMT 2021
https://gcc.gnu.org/g:25fc4cb3ff7bb86d31ac886e04bbe5dd69db832e
commit r9-9291-g25fc4cb3ff7bb86d31ac886e04bbe5dd69db832e
Author: Martin Jambor <mjambor@suse.cz>
Date: Wed Mar 17 11:32:50 2021 +0100
ipa: Fix resolving speculations through cgraph_edge::set_call_stmt
In the PR 98078 testcase, speculative call-graph edges which were
created by IPA-CP are confirmed during inlining but
cgraph_edge::set_call_stmt does not take it very well.
The function enters the update_speculative branch and updates the
edges in the speculation bundle separately (by a recursive call), but
when it processes the first direct edge, most of the bundle actually
ceases to exist because it is devirtualized. It nevertheless goes on
to attempt to update the indirect edge (that has just been removed),
which surprisingly gets as far as adding the edge to the
call_site_hash, the same devirtualized edge for the second time, and
that triggers an assert.
Fixed by this patch which makes the function aware that it is about to
resolve a speculation and do so instead of updating components of
speculation. Also, it does so before dealing with the hash because
the speculation resolution code needs the hash to point to the first
speculative direct edge and also cleans the hash up by calling
update_call_stmt_hash_for_removing_direct_edge.
Bootstrapped and tested on x86_64-linux, also profile-LTO-bootstrapped
on the same system.
gcc/ChangeLog:
2021-01-20 Martin Jambor <mjambor@suse.cz>
PR ipa/98078
* cgraph.c (cgraph_edge::set_call_stmt): Do not update all
corresponding speculative edges if we are about to resolve
speculation. Make edge direct (and so resolve speculations) before
removing it from call_site_hash.
(cgraph_edge::make_direct): Relax the initial assert to allow calling
the function on speculative direct edges.
(cherry picked from commit b8188b7d7382e4a74af5dd6a125e76e8d43a68a5)
Diff:
---
gcc/cgraph.c | 49 +++++++++++++++++++++++++++----------------------
1 file changed, 27 insertions(+), 22 deletions(-)
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 1febb6369a0..3547db54d87 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -780,9 +780,22 @@ cgraph_edge::set_call_stmt (gcall *new_stmt, bool update_speculative)
{
tree decl;
+ cgraph_node *new_direct_callee = NULL;
+ if (indirect_unknown_callee
+ && (decl = gimple_call_fndecl (new_stmt)))
+ {
+ /* Constant propagation and especially inlining can turn an indirect call
+ into a direct one. */
+ new_direct_callee = cgraph_node::get (decl);
+ gcc_checking_assert (new_direct_callee);
+ }
+
/* Speculative edges has three component, update all of them
when asked to. */
- if (update_speculative && speculative)
+ if (update_speculative && speculative
+ /* If we are about to resolve the speculation by calling make_direct
+ below, do not bother going over all the speculative edges now. */
+ && !new_direct_callee)
{
cgraph_edge *direct, *indirect;
ipa_ref *ref;
@@ -794,28 +807,20 @@ cgraph_edge::set_call_stmt (gcall *new_stmt, bool update_speculative)
return;
}
- /* Only direct speculative edges go to call_site_hash. */
- if (caller->call_site_hash
- && (!speculative || !indirect_unknown_callee))
- {
- caller->call_site_hash->remove_elt_with_hash
- (call_stmt, cgraph_edge_hasher::hash (call_stmt));
- }
-
cgraph_edge *e = this;
+ if (new_direct_callee)
+ e = make_direct (new_direct_callee);
- call_stmt = new_stmt;
- if (indirect_unknown_callee
- && (decl = gimple_call_fndecl (new_stmt)))
+ /* Only direct speculative edges go to call_site_hash. */
+ if (e->caller->call_site_hash
+ && (!e->speculative || !e->indirect_unknown_callee))
{
- /* Constant propagation (and possibly also inlining?) can turn an
- indirect call into a direct one. */
- cgraph_node *new_callee = cgraph_node::get (decl);
-
- gcc_checking_assert (new_callee);
- e = make_direct (new_callee);
+ e->caller->call_site_hash->remove_elt_with_hash
+ (e->call_stmt, cgraph_edge_hasher::hash (e->call_stmt));
}
+ e->call_stmt = new_stmt;
+
function *fun = DECL_STRUCT_FUNCTION (e->caller->decl);
e->can_throw_external = stmt_can_throw_external (fun, new_stmt);
if (e->caller->call_site_hash)
@@ -1211,15 +1216,15 @@ cgraph_edge::resolve_speculation (tree callee_decl)
return edge;
}
-/* Make an indirect edge with an unknown callee an ordinary edge leading to
- CALLEE. DELTA is an integer constant that is to be added to the this
- pointer (first parameter) to compensate for skipping a thunk adjustment. */
+/* Turn an indirect edge with an unknown callee or a speculative edge into an
+ ordinary edge leading to CALLEE. Speculations can be resolved in the
+ process. Return the edge that now represents the call. */
cgraph_edge *
cgraph_edge::make_direct (cgraph_node *callee)
{
cgraph_edge *edge = this;
- gcc_assert (indirect_unknown_callee);
+ gcc_assert (indirect_unknown_callee || speculative);
/* If we are redirecting speculative call, make it non-speculative. */
if (indirect_unknown_callee && speculative)
More information about the Gcc-cvs
mailing list