diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5c5c8848e43..450214646c1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,13 @@ 2008-01-30 Jakub Jelinek + PR middle-end/34969 + * cgraph.h (cgraph_update_edges_for_call_stmt): New prototype. + * cgraph.c (cgraph_update_edges_for_call_stmt): New function. + * tree-inline.c (fold_marked_statements): Call + cgraph_update_edges_for_call_stmt if folding a call statement. + * cgraphunit.c (verify_cgraph_node): Set cfun to this_cfun for + debug_generic_stmt calls, reset it back afterwards. + PR c/35017 * c-decl.c (start_decl): Don't pedwarn about TREE_READONLY static decls. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 8c7bc5da442..649915e4618 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -1,5 +1,6 @@ /* Callgraph handling code. - Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 + Free Software Foundation, Inc. Contributed by Jan Hubicka This file is part of GCC. @@ -440,6 +441,51 @@ cgraph_redirect_edge_callee (struct cgraph_edge *e, struct cgraph_node *n) e->callee = n; } +/* Update or remove corresponding cgraph edge if a call OLD_CALL + in OLD_STMT changed into NEW_STMT. */ + +void +cgraph_update_edges_for_call_stmt (tree old_stmt, tree old_call, + tree new_stmt) +{ + tree new_call = get_call_expr_in (new_stmt); + struct cgraph_node *node = cgraph_node (cfun->decl); + + if (old_call != new_call) + { + struct cgraph_edge *e = cgraph_edge (node, old_stmt); + struct cgraph_edge *ne = NULL; + tree new_decl; + + if (e) + { + gcov_type count = e->count; + int frequency = e->frequency; + int loop_nest = e->loop_nest; + + cgraph_remove_edge (e); + if (new_call) + { + new_decl = get_callee_fndecl (new_call); + if (new_decl) + { + ne = cgraph_create_edge (node, cgraph_node (new_decl), + new_stmt, count, frequency, + loop_nest); + gcc_assert (ne->inline_failed); + } + } + } + } + else if (old_stmt != new_stmt) + { + struct cgraph_edge *e = cgraph_edge (node, old_stmt); + + if (e) + cgraph_set_call_stmt (e, new_stmt); + } +} + /* Remove all callees from the node. */ void diff --git a/gcc/cgraph.h b/gcc/cgraph.h index baed1a6fef3..89ffeb6c45c 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -1,5 +1,6 @@ /* Callgraph handling code. - Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 + Free Software Foundation, Inc. Contributed by Jan Hubicka This file is part of GCC. @@ -303,6 +304,7 @@ struct cgraph_node *cgraph_node (tree); struct cgraph_node *cgraph_node_for_asm (tree asmname); struct cgraph_edge *cgraph_edge (struct cgraph_node *, tree); void cgraph_set_call_stmt (struct cgraph_edge *, tree); +void cgraph_update_edges_for_call_stmt (tree, tree, tree); 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/cgraphunit.c b/gcc/cgraphunit.c index 07b597f7bca..0d6a9fed9fc 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -658,6 +658,7 @@ verify_cgraph_node (struct cgraph_node *node) struct cgraph_edge *e; struct cgraph_node *main_clone; struct function *this_cfun = DECL_STRUCT_FUNCTION (node->decl); + struct function *saved_cfun = cfun; basic_block this_block; block_stmt_iterator bsi; bool error_found = false; @@ -666,6 +667,8 @@ verify_cgraph_node (struct cgraph_node *node) return; timevar_push (TV_CGRAPH_VERIFY); + /* debug_generic_stmt needs correct cfun */ + set_cfun (this_cfun); for (e = node->callees; e; e = e->next_callee) if (e->aux) { @@ -808,6 +811,7 @@ verify_cgraph_node (struct cgraph_node *node) dump_cgraph_node (stderr, node); internal_error ("verify_cgraph_node failed"); } + set_cfun (saved_cfun); timevar_pop (TV_CGRAPH_VERIFY); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 11239a5e9cc..5369f58ec08 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2008-01-30 Jakub Jelinek + PR middle-end/34969 + * gcc.dg/pr34969.c: New test. + PR c/35017 * gcc.dg/inline-25.c: New test. * gcc.dg/inline-26.c: New test. diff --git a/gcc/testsuite/gcc.dg/pr34969.c b/gcc/testsuite/gcc.dg/pr34969.c new file mode 100644 index 00000000000..02f7dd1aaac --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr34969.c @@ -0,0 +1,15 @@ +/* PR middle-end/34969 */ +/* { dg-do compile } */ +/* { dg-options "-O -fipa-cp -ffast-math" } */ + +double +foo (double x) +{ + return x * x; +} + +double +bar (void) +{ + return foo (0); +} diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index d2ef9619eb2..b683f20a70e 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -2942,11 +2942,17 @@ fold_marked_statements (int first, struct pointer_set_t *statements) if (pointer_set_contains (statements, bsi_stmt (bsi))) { tree old_stmt = bsi_stmt (bsi); + tree old_call = get_call_expr_in (old_stmt); + if (fold_stmt (bsi_stmt_ptr (bsi))) { update_stmt (bsi_stmt (bsi)); - if (maybe_clean_or_replace_eh_stmt (old_stmt, bsi_stmt (bsi))) - tree_purge_dead_eh_edges (BASIC_BLOCK (first)); + if (old_call) + cgraph_update_edges_for_call_stmt (old_stmt, old_call, + bsi_stmt (bsi)); + if (maybe_clean_or_replace_eh_stmt (old_stmt, + bsi_stmt (bsi))) + tree_purge_dead_eh_edges (BASIC_BLOCK (first)); } } }