Hi, This patch is to fix: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61776
It records func decls whose const/pure flags are reset during instrumentation. After the loop resetting const/pure flags, find out stmts calling those recorded funcs and perform cfg fixup on them. bootstrap and regression test pass on x86_64-linux-gnu. ok for trunk and gcc-4_9? Thanks, Wei. ChangeLog: 2014-07-21 Wei Mi <w...@google.com> PR middle-end/61776 * tree-profile.c (tree_profiling): Fix cfg after the const/pure flags of some funcs are reset after instrumentation. 2014-07-21 Wei Mi <w...@google.com> PR middle-end/61776 * testsuite/gcc.dg/pr61776.c: New test. Index: tree-profile.c =================================================================== --- tree-profile.c (revision 212442) +++ tree-profile.c (working copy) @@ -56,6 +56,7 @@ along with GCC; see the file COPYING3. #include "target.h" #include "tree-cfgcleanup.h" #include "tree-nested.h" +#include "pointer-set.h" static GTY(()) tree gcov_type_node; static GTY(()) tree tree_interval_profiler_fn; @@ -562,6 +563,9 @@ static unsigned int tree_profiling (void) { struct cgraph_node *node; + int i; + struct pointer_set_t *modified_constpure_decls; + vec<gimple> modified_constpure_stmts; /* This is a small-ipa pass that gets called only once, from cgraphunit.c:ipa_passes(). */ @@ -603,6 +607,9 @@ tree_profiling (void) pop_cfun (); } + modified_constpure_decls = pointer_set_create (); + modified_constpure_stmts.create (0); + /* Drop pure/const flags from instrumented functions. */ FOR_EACH_DEFINED_FUNCTION (node) { @@ -615,6 +622,11 @@ tree_profiling (void) if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) continue; + /* If the const/pure flag of node is about to change, record + node->decl in modified_constpure_decls. */ + if (DECL_PURE_P (node->decl) || TREE_READONLY (node->decl)) + pointer_set_insert (modified_constpure_decls, node->decl); + cgraph_set_const_flag (node, false, false); cgraph_set_pure_flag (node, false, false); } @@ -623,6 +635,7 @@ tree_profiling (void) FOR_EACH_DEFINED_FUNCTION (node) { basic_block bb; + gimple stmt; if (!gimple_has_body_p (node->decl) || !(!node->clone_of @@ -642,10 +655,29 @@ tree_profiling (void) { gimple stmt = gsi_stmt (gsi); if (is_gimple_call (stmt)) - update_stmt (stmt); + { + tree decl = gimple_call_fndecl(stmt); + if (decl && pointer_set_contains (modified_constpure_decls, + decl)) + modified_constpure_stmts.safe_push (stmt); + update_stmt (stmt); + } } } + /* The const/pure flag of the decl of call stmt in modified_constpure_stmts + is changed because of instrumentation. Split block if the call stmt is not + the last stmt of bb and the call stmt ends bb. */ + FOR_EACH_VEC_ELT (modified_constpure_stmts, i, stmt) + { + basic_block bb = gimple_bb (stmt); + + if (stmt != gsi_stmt (gsi_last_bb (bb)) + && stmt_ends_bb_p (stmt)) + split_block (bb, stmt); + } + modified_constpure_stmts.release (); + /* re-merge split blocks. */ cleanup_tree_cfg (); update_ssa (TODO_update_ssa); @@ -657,6 +689,7 @@ tree_profiling (void) handle_missing_profiles (); + pointer_set_destroy (modified_constpure_decls); del_node_map (); return 0; } Index: testsuite/gcc.dg/pr61776.c =================================================================== --- testsuite/gcc.dg/pr61776.c (revision 0) +++ testsuite/gcc.dg/pr61776.c (revision 0) @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fprofile-generate" } */ + +#include <setjmp.h> + +int cond1, cond2; + +int goo() __attribute__((noinline)); + +int goo() { + if (cond1) + return 1; + else + return 2; +} + +jmp_buf env; +int foo() { + int a; + + setjmp(env); + if (cond2) + a = goo(); + else + a = 3; + return a; +}