Commit 47cb0d7d by Jan Hubicka Committed by Jan Hubicka

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
parent 604df116
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
......@@ -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)
......
......@@ -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);
......
......@@ -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)
......
......@@ -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);
......
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
......
/* { 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);
}
......@@ -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)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment