diff options
author | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-12-10 20:50:47 +0000 |
---|---|---|
committer | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-12-10 20:50:47 +0000 |
commit | ee3f5fc0f04108d47a518ce7efadd87eb51a9cc3 (patch) | |
tree | 4b7897c70e32ed3a7ade0ed23cc48ffbcd023f09 /gcc/cgraph.c | |
parent | 0c54ae75e67742522f331dce5db1fe0983d42ca6 (diff) | |
download | gcc-ee3f5fc0f04108d47a518ce7efadd87eb51a9cc3.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@155140 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cgraph.c')
-rw-r--r-- | gcc/cgraph.c | 60 |
1 files changed, 45 insertions, 15 deletions
diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 651618c4232..a3efdfc0ce1 100644 --- a/gcc/cgraph.c +++ b/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) |