From 72b3bc895f023bf451357659cfe96c966945bdf9 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Fri, 20 Mar 2020 22:06:24 +0100 Subject: Fix verifier ICE on wrong comdat local flag [PR93347] gcc/ChangeLog: 2020-03-20 Jan Hubicka PR ipa/93347 * cgraph.c (symbol_table::create_edge): Update calls_comdat_local flag. (cgraph_edge::redirect_callee): Move here; likewise. (cgraph_node::remove_callees): Update calls_comdat_local flag. (cgraph_node::verify_node): Verify that calls_comdat_local flag match reality. (cgraph_node::check_calls_comdat_local_p): New member function. * cgraph.h (cgraph_node::check_calls_comdat_local_p): Declare. (cgraph_edge::redirect_callee): Move offline. * ipa-fnsummary.c (compute_fn_summary): Do not compute calls_comdat_local flag here. * ipa-inline-transform.c (inline_call): Fix updating of calls_comdat_local flag. * ipa-split.c (split_function): Use true instead of 1 to set the flag. * symtab.c (symtab_node::add_to_same_comdat_group): Update calls_comdat_local flag. gcc/testsuite/ChangeLog: 2020-03-20 Jan Hubicka * g++.dg/torture/pr93347.C: New test. --- gcc/cgraph.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 4 deletions(-) (limited to 'gcc/cgraph.c') diff --git a/gcc/cgraph.c b/gcc/cgraph.c index b41dea1..6b780f8 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -557,7 +557,8 @@ cgraph_node::get_create (tree decl) } /* Mark ALIAS as an alias to DECL. DECL_NODE is cgraph node representing - the function body is associated with (not necessarily cgraph_node (DECL). */ + the function body is associated with + (not necessarily cgraph_node (DECL)). */ cgraph_node * cgraph_node::create_alias (tree alias, tree target) @@ -914,6 +915,10 @@ symbol_table::create_edge (cgraph_node *caller, cgraph_node *callee, else edge->in_polymorphic_cdtor = caller->thunk.thunk_p; + if (callee && symtab->state != LTO_STREAMING + && edge->callee->comdat_local_p ()) + edge->caller->calls_comdat_local = true; + return edge; } @@ -1341,6 +1346,34 @@ cgraph_edge::make_direct (cgraph_edge *edge, cgraph_node *callee) return edge; } +/* Redirect callee of the edge to N. The function does not update underlying + call expression. */ + +void +cgraph_edge::redirect_callee (cgraph_node *n) +{ + bool loc = callee->comdat_local_p (); + /* Remove from callers list of the current callee. */ + remove_callee (); + + /* Insert to callers list of the new callee. */ + set_callee (n); + + if (!inline_failed) + return; + if (!loc && n->comdat_local_p ()) + { + cgraph_node *to = caller->inlined_to ? caller->inlined_to : caller; + to->calls_comdat_local = true; + } + else if (loc && !n->comdat_local_p ()) + { + cgraph_node *to = caller->inlined_to ? caller->inlined_to : caller; + gcc_checking_assert (to->calls_comdat_local); + to->calls_comdat_local = to->check_calls_comdat_local_p (); + } +} + /* If necessary, change the function declaration in the call statement associated with E so that it corresponds to the edge callee. Speculations can be resolved in the process and EDGE can be removed and deallocated. @@ -1674,6 +1707,8 @@ cgraph_node::remove_callees (void) { cgraph_edge *e, *f; + calls_comdat_local = false; + /* It is sufficient to remove the edges from the lists of callers of the callees. The callee list of the node can be zapped with one assignment. */ @@ -3369,10 +3404,18 @@ cgraph_node::verify_node (void) error ("inline clone is forced to output"); error_found = true; } - if (calls_comdat_local && !same_comdat_group) + if (symtab->state != LTO_STREAMING) { - error ("calls_comdat_local is set outside of a comdat group"); - error_found = true; + if (calls_comdat_local && !same_comdat_group) + { + error ("calls_comdat_local is set outside of a comdat group"); + error_found = true; + } + if (!inlined_to && calls_comdat_local != check_calls_comdat_local_p ()) + { + error ("invalid calls_comdat_local flag"); + error_found = true; + } } if (DECL_IS_MALLOC (decl) && !POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (decl)))) @@ -4044,6 +4087,19 @@ cgraph_edge::num_speculative_call_targets_p (void) return indirect_info ? indirect_info->num_speculative_call_targets : 0; } +/* Check if function calls comdat local. This is used to recompute + calls_comdat_local flag after function transformations. */ +bool +cgraph_node::check_calls_comdat_local_p () +{ + for (cgraph_edge *e = callees; e; e = e->next_callee) + if (e->inline_failed + ? e->callee->comdat_local_p () + : e->callee->check_calls_comdat_local_p ()) + return true; + return false; +} + /* A stashed copy of "symtab" for use by selftest::symbol_table_test. This needs to be a global so that it can be a GC root, and thus prevent the stashed copy from being garbage-collected if the GC runs -- cgit v1.1