re PR middle-end/42228 (verify_cgraph_node failed:node has wrong clone_of)

PR middle-end/42228
	PR middle-end/42110
	* cgraph.c (cgraph_create_edge_including_clones): Add old_stmt parameter;
	update edge if it already exists.
	(cgraph_remove_node): Handle correctly cases where we are removing node having
	clones.
	* cgraph.h (cgraph_create_edge_including_clones): Declare.
	(verify_cgraph_node): Add missing error_found = true code.
	(cgraph_materialize_all_clones): Remove call edges of dead nodes.
	* ipa.c (cgraph_remove_unreachable_nodes): Correctly look for master
	clone; fix double linked list removal.
	* tree-inline.c (copy_bb): Update cgraph_create_edge_including_clones call;
	fix frequency of newly created edge.

	* g++.dg/torture/pr42110.C: new file.

From-SVN: r155140
This commit is contained in:
Jan Hubicka 2009-12-10 21:50:47 +01:00 committed by Jan Hubicka
parent 604df1167c
commit 47cb0d7da1
8 changed files with 118 additions and 20 deletions

View File

@ -1,3 +1,19 @@
2009-12-10 Jan Hubicka <jh@suse.cz>
PR middle-end/42228
PR middle-end/42110
* cgraph.c (cgraph_create_edge_including_clones): Add old_stmt parameter;
update edge if it already exists.
(cgraph_remove_node): Handle correctly cases where we are removing node having
clones.
* cgraph.h (cgraph_create_edge_including_clones): Declare.
(verify_cgraph_node): Add missing error_found = true code.
(cgraph_materialize_all_clones): Remove call edges of dead nodes.
* ipa.c (cgraph_remove_unreachable_nodes): Correctly look for master
clone; fix double linked list removal.
* tree-inline.c (copy_bb): Update cgraph_create_edge_including_clones call;
fix frequency of newly created edge.
2009-12-10 Bernd Schmidt <bernd.schmidt@analog.com>
PR rtl-opt/42216

View File

@ -829,7 +829,8 @@ cgraph_set_call_stmt_including_clones (struct cgraph_node *orig,
}
/* Like cgraph_create_edge walk the clone tree and update all clones sharing
same function body.
same function body. If clones already have edge for OLD_STMT; only
update the edge same way as cgraph_set_call_stmt_including_clones does.
TODO: COUNT and LOOP_DEPTH should be properly distributed based on relative
frequencies of the clones. */
@ -837,6 +838,7 @@ cgraph_set_call_stmt_including_clones (struct cgraph_node *orig,
void
cgraph_create_edge_including_clones (struct cgraph_node *orig,
struct cgraph_node *callee,
gimple old_stmt,
gimple stmt, gcov_type count,
int freq, int loop_depth,
cgraph_inline_failed_t reason)
@ -854,9 +856,15 @@ cgraph_create_edge_including_clones (struct cgraph_node *orig,
if (node)
while (node != orig)
{
/* It is possible that we already constant propagated into the clone
and turned indirect call into dirrect call. */
if (!cgraph_edge (node, stmt))
struct cgraph_edge *edge = cgraph_edge (node, old_stmt);
/* It is possible that clones already contain the edge while
master didn't. Either we promoted indirect call into direct
call in the clone or we are processing clones of unreachable
master where edges has been rmeoved. */
if (edge)
cgraph_set_call_stmt (edge, stmt);
else if (!cgraph_edge (node, stmt))
{
edge = cgraph_create_edge (node, callee, stmt, count,
freq, loop_depth);
@ -1337,11 +1345,15 @@ cgraph_remove_node (struct cgraph_node *node)
= next_inline_clone->prev_sibling_clone;
if (next_inline_clone->prev_sibling_clone)
{
gcc_assert (node->clones != next_inline_clone);
next_inline_clone->prev_sibling_clone->next_sibling_clone
= next_inline_clone->next_sibling_clone;
}
else
node->clones = next_inline_clone->next_sibling_clone;
{
gcc_assert (node->clones == next_inline_clone);
node->clones = next_inline_clone->next_sibling_clone;
}
new_clones = node->clones;
node->clones = NULL;
@ -1355,6 +1367,8 @@ cgraph_remove_node (struct cgraph_node *node)
next_inline_clone->next_sibling_clone = NULL;
if (node->clone_of)
{
if (node->clone_of->clones)
node->clone_of->clones->prev_sibling_clone = next_inline_clone;
next_inline_clone->next_sibling_clone = node->clone_of->clones;
node->clone_of->clones = next_inline_clone;
}
@ -1389,8 +1403,6 @@ cgraph_remove_node (struct cgraph_node *node)
}
}
else
gcc_assert (node->clone_of);
if (node->prev_sibling_clone)
node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
else if (node->clone_of)
@ -1399,15 +1411,33 @@ cgraph_remove_node (struct cgraph_node *node)
node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
if (node->clones)
{
struct cgraph_node *n;
struct cgraph_node *n, *next;
for (n = node->clones; n->next_sibling_clone; n = n->next_sibling_clone)
n->clone_of = node->clone_of;
n->clone_of = node->clone_of;
n->next_sibling_clone = node->clone_of->clones;
if (node->clone_of->clones)
node->clone_of->clones->prev_sibling_clone = n;
node->clone_of->clones = node->clones;
if (node->clone_of)
{
for (n = node->clones; n->next_sibling_clone; n = n->next_sibling_clone)
n->clone_of = node->clone_of;
n->clone_of = node->clone_of;
n->next_sibling_clone = node->clone_of->clones;
if (node->clone_of->clones)
node->clone_of->clones->prev_sibling_clone = n;
node->clone_of->clones = node->clones;
}
else
{
/* We are removing node with clones. this makes clones inconsistent,
but assume they will be removed subsequently and just keep clone
tree intact. This can happen in unreachable function removal since
we remove unreachable functions in random order, not by bottom-up
walk of clone trees. */
for (n = node->clones; n; n = next)
{
next = n->next_sibling_clone;
n->next_sibling_clone = NULL;
n->prev_sibling_clone = NULL;
n->clone_of = NULL;
}
}
}
while (node->same_body)

View File

@ -445,7 +445,7 @@ void cgraph_set_call_stmt (struct cgraph_edge *, gimple);
void cgraph_set_call_stmt_including_clones (struct cgraph_node *, gimple, gimple);
void cgraph_create_edge_including_clones (struct cgraph_node *,
struct cgraph_node *,
gimple, gcov_type, int, int,
gimple, gimple, gcov_type, int, int,
cgraph_inline_failed_t);
void cgraph_update_edges_for_call_stmt (gimple, tree, gimple);
struct cgraph_local_info *cgraph_local_info (tree);

View File

@ -749,6 +749,7 @@ verify_cgraph_node (struct cgraph_node *node)
{
error ("edge points to same body alias:");
debug_tree (e->callee->decl);
error_found = true;
}
else if (!clone_of_p (cgraph_node (decl), e->callee)
&& !e->callee->global.inlined_to)
@ -757,6 +758,7 @@ verify_cgraph_node (struct cgraph_node *node)
debug_tree (e->callee->decl);
fprintf (stderr," Instead of:");
debug_tree (decl);
error_found = true;
}
e->aux = (void *)1;
}
@ -2248,6 +2250,9 @@ cgraph_materialize_all_clones (void)
}
}
}
for (node = cgraph_nodes; node; node = node->next)
if (!node->analyzed && node->callees)
cgraph_node_remove_callees (node);
if (cgraph_dump_file)
fprintf (cgraph_dump_file, "Updating call sites\n");
for (node = cgraph_nodes; node; node = node->next)

View File

@ -179,11 +179,21 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
first = e->callee;
}
}
/* We can freely remove inline clones even if they are cloned, however if
function is clone of real clone, we must keep it around in order to
make materialize_clones produce function body with the changes
applied. */
while (node->clone_of && !node->clone_of->aux && !gimple_has_body_p (node->decl))
{
bool noninline = node->clone_of->decl != node->decl;
node = node->clone_of;
node->aux = first;
first = node;
if (noninline)
{
node->aux = first;
first = node;
break;
}
}
}
@ -244,6 +254,9 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
node->clone_of->clones = node->next_sibling_clone;
if (node->next_sibling_clone)
node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
node->clone_of = NULL;
node->next_sibling_clone = NULL;
node->prev_sibling_clone = NULL;
}
else
cgraph_remove_node (node);

View File

@ -1,3 +1,8 @@
2009-12-10 Jan Hubicka <jh@suse.cz>
PR middle-end/42110
* g++.dg/torture/pr42110.C: new file.
2009-12-10 Daniel Franke <franke.daniel@gmail.com>
PR fortran/34402

View File

@ -0,0 +1,27 @@
/* { dg-do compile } */
bool foo();
struct A
{
A* fooA() { if (foo()) foo(); return this; }
virtual void barA(char);
};
template<int> struct B
{
A *p, *q;
void fooB(char c) { p->fooA()->barA(c); }
};
template<int N> inline void bar(B<N> b) { b.fooB(0); }
extern template void bar(B<0>);
void (*f)(B<0>) = bar;
void baz()
{
B<0>().fooB(0);
}

View File

@ -1694,13 +1694,15 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
|| !id->src_node->analyzed);
if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES)
cgraph_create_edge_including_clones
(id->dst_node, dest, stmt, bb->count,
(id->dst_node, dest, orig_stmt, stmt, bb->count,
compute_call_stmt_bb_frequency (id->dst_node->decl,
copy_basic_block),
bb->loop_depth, CIF_ORIGINALLY_INDIRECT_CALL);
else
cgraph_create_edge (id->dst_node, dest, stmt,
bb->count, CGRAPH_FREQ_BASE,
bb->count,
compute_call_stmt_bb_frequency
(id->dst_node->decl, copy_basic_block),
bb->loop_depth)->inline_failed
= CIF_ORIGINALLY_INDIRECT_CALL;
if (dump_file)