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:
parent
604df1167c
commit
47cb0d7da1
|
@ -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
|
||||
|
|
60
gcc/cgraph.c
60
gcc/cgraph.c
|
@ -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)
|
||||
|
|
17
gcc/ipa.c
17
gcc/ipa.c
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue