From 4b685e144da6c5a196714ba7ef2fdae1fdf140e2 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sun, 10 May 2009 13:36:11 +0200 Subject: [PATCH] re PR middle-end/40084 (Revision 147294 failed 483.xalancbmk in SPEC CPU 2006 at -O3) PR middle-end/40084 * cgraph.c (cgraph_update_edges_for_call_stmt_node): Take old_call argument; rewrite. (cgraph_update_edges_for_call_stmt): Take old_decl argument. * cgraph.h (cgraph_update_edges_for_call_stmt): Update prototype. * tree-inline.c (copy_bb): Set frequency correctly. (fold_marked_statements): Update call of cgraph_update_edges_for_call_stmt. From-SVN: r147337 --- gcc/ChangeLog | 10 ++++++ gcc/cgraph.c | 77 +++++++++++++++++++++++++++++------------------ gcc/cgraph.h | 2 +- gcc/tree-inline.c | 9 ++++-- 4 files changed, 64 insertions(+), 34 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 687757cbb84..932044d37ef 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2009-05-10 Jan Hubicka + + PR middle-end/40084 + * cgraph.c (cgraph_update_edges_for_call_stmt_node): Take old_call argument; + rewrite. + (cgraph_update_edges_for_call_stmt): Take old_decl argument. + * cgraph.h (cgraph_update_edges_for_call_stmt): Update prototype. + * tree-inline.c (copy_bb): Set frequency correctly. + (fold_marked_statements): Update call of cgraph_update_edges_for_call_stmt. + 2009-05-10 Joseph Myers * config/arc/arc.c (arc_handle_interrupt_attribute): Use %qE for diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 2f68d94e3dd..5d2cc1d6634 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -898,64 +898,81 @@ cgraph_redirect_edge_callee (struct cgraph_edge *e, struct cgraph_node *n) /* Update or remove the corresponding cgraph edge if a GIMPLE_CALL - OLD_STMT changed into NEW_STMT. */ + OLD_STMT changed into NEW_STMT. OLD_CALL is gimple_call_fndecl + of OLD_STMT if it was previously call statement. */ static void cgraph_update_edges_for_call_stmt_node (struct cgraph_node *node, - gimple old_stmt, gimple new_stmt) + gimple old_stmt, tree old_call, gimple new_stmt) { - tree new_call = (is_gimple_call (new_stmt)) ? gimple_call_fn (new_stmt) : 0; - tree old_call = (is_gimple_call (old_stmt)) ? gimple_call_fn (old_stmt) : 0; + tree new_call = (is_gimple_call (new_stmt)) ? gimple_call_fndecl (new_stmt) : 0; + /* We are seeing indirect calls, then there is nothing to update. */ + if (!new_call && !old_call) + return; + /* See if we turned indirect call into direct call or folded call to one builtin + into different bultin. */ if (old_call != new_call) { struct cgraph_edge *e = cgraph_edge (node, old_stmt); struct cgraph_edge *ne = NULL; - tree new_decl; + gcov_type count; + int frequency; + int loop_nest; if (e) { - gcov_type count = e->count; - int frequency = e->frequency; - int loop_nest = e->loop_nest; - + /* See if the call is already there. It might be because of indirect + inlining already found it. */ + if (new_call && e->callee->decl == new_call) + return; + + /* Otherwise remove edge and create new one; we can't simply redirect + since function has changed, so inline plan and other information + attached to edge is invalid. */ cgraph_remove_edge (e); - if (new_call) - { - new_decl = gimple_call_fndecl (new_stmt); - if (new_decl) - { - ne = cgraph_create_edge (node, cgraph_node (new_decl), - new_stmt, count, frequency, - loop_nest); - gcc_assert (ne->inline_failed); - } - } + count = e->count; + frequency = e->frequency; + loop_nest = e->loop_nest; + } + else + { + /* We are seeing new direct call; compute profile info based on BB. */ + basic_block bb = gimple_bb (new_stmt); + count = bb->count; + frequency = compute_call_stmt_bb_frequency (current_function_decl, + bb); + loop_nest = bb->loop_depth; } - } - else if (old_stmt != new_stmt) - { - struct cgraph_edge *e = cgraph_edge (node, old_stmt); - if (e) - cgraph_set_call_stmt (e, new_stmt); + if (new_call) + { + ne = cgraph_create_edge (node, cgraph_node (new_call), + new_stmt, count, frequency, + loop_nest); + gcc_assert (ne->inline_failed); + } } + /* We only updated the call stmt; update pointer in cgraph edge.. */ + else if (old_stmt != new_stmt) + cgraph_set_call_stmt (cgraph_edge (node, old_stmt), new_stmt); } /* Update or remove the corresponding cgraph edge if a GIMPLE_CALL - OLD_STMT changed into NEW_STMT. */ + OLD_STMT changed into NEW_STMT. OLD_DECL is gimple_call_fndecl + of OLD_STMT before it was updated (updating can happen inplace). */ void -cgraph_update_edges_for_call_stmt (gimple old_stmt, gimple new_stmt) +cgraph_update_edges_for_call_stmt (gimple old_stmt, tree old_decl, gimple new_stmt) { struct cgraph_node *orig = cgraph_node (cfun->decl); struct cgraph_node *node; - cgraph_update_edges_for_call_stmt_node (orig, old_stmt, new_stmt); + cgraph_update_edges_for_call_stmt_node (orig, old_stmt, old_decl, new_stmt); if (orig->clones) for (node = orig->clones; node != orig;) { - cgraph_update_edges_for_call_stmt_node (node, old_stmt, new_stmt); + cgraph_update_edges_for_call_stmt_node (node, old_stmt, old_decl, new_stmt); if (node->clones) node = node->clones; else if (node->next_sibling_clone) diff --git a/gcc/cgraph.h b/gcc/cgraph.h index b94fcffbc77..c1a1a0ab922 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -385,7 +385,7 @@ void cgraph_create_edge_including_clones (struct cgraph_node *, struct cgraph_node *, gimple, gcov_type, int, int, cgraph_inline_failed_t); -void cgraph_update_edges_for_call_stmt (gimple, gimple); +void cgraph_update_edges_for_call_stmt (gimple, tree, gimple); struct cgraph_local_info *cgraph_local_info (tree); struct cgraph_global_info *cgraph_global_info (tree); struct cgraph_rtl_info *cgraph_rtl_info (tree); diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 0a383768b04..403b5a0a17c 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1522,7 +1522,8 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, gcc_assert (dest->needed || !dest->analyzed); if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES) cgraph_create_edge_including_clones (id->dst_node, dest, stmt, - bb->count, CGRAPH_FREQ_BASE, + bb->count, + compute_call_stmt_bb_frequency (id->dst_node->decl, bb), bb->loop_depth, CIF_ORIGINALLY_INDIRECT_CALL); else @@ -3542,6 +3543,7 @@ fold_marked_statements (int first, struct pointer_set_t *statements) if (pointer_set_contains (statements, gsi_stmt (gsi))) { gimple old_stmt = gsi_stmt (gsi); + tree old_decl = is_gimple_call (old_stmt) ? gimple_call_fndecl (old_stmt) : 0; if (fold_stmt (&gsi)) { @@ -3550,8 +3552,9 @@ fold_marked_statements (int first, struct pointer_set_t *statements) gimple new_stmt = gsi_stmt (gsi); update_stmt (new_stmt); - if (is_gimple_call (old_stmt)) - cgraph_update_edges_for_call_stmt (old_stmt, new_stmt); + if (is_gimple_call (old_stmt) + || is_gimple_call (new_stmt)) + cgraph_update_edges_for_call_stmt (old_stmt, old_decl, new_stmt); if (maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt)) gimple_purge_dead_eh_edges (BASIC_BLOCK (first)); -- 2.30.2