Hi! This testcase fails with corrupted profile info error. The problem is that we have a basic block which starts with a computed goto target label (thus has an EDGE_ABNORMAL predecessor and wants an EDGE_FAKE predecessor from entry) and ends with a non-const/pure call (which incidentally doesn't ever return directly, exits through a non-local goto), thus wants an EDGE_FAKE edge to exit. Unfortunately when constructing the spanning tree we would just add the fake edge from entry and not the fake edge to exit, because entry and exit blocks are already in the same union and because of the first fake edge this block is unioned with it too. The following patch fixes that by splitting such basic blocks after labels, so that counter updating can be inserted on the new edge (and thus inside of the block). This fixed the testcase, unfortunately regressed tree-prof/pr34999.c on i686. The problem there is the weirdo split of __builtin_setjmp into __builtin_setjmp_{setup,receiver,dispatcher}. As the block containing (solely __builtin_setjmp_receiver (resp. dispatcher) has both EDGE_ABNORMAL incoming and outgoing edges, it has EDGE_FAKE from entry as well as EDGE_FAKE to exit. The patch would try to insert the counter adjustments in between __builtin_setjmp_setup and __builtin_setjmp_receiver, which apparently at least on some targets the expander isn't able to handle well. Optimizations decided to cache some 64-bit counter values in registers, due to high register pressure were spilled, but in between __builtin_setjmp_setup and __builtin_setjmp_receiver the hard frame pointer isn't valid, the code adjusts it/restores it, so we were reading through incorrect frame pointer value. These edges (to/from __builtin_setjmp_dispatcher bb) are really artificial and thus I think it is safe to keep status quo for them and avoid inserting instrumentation there.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2012-01-04 Jakub Jelinek <ja...@redhat.com> PR middle-end/44777 * profile.c (branch_prob): Split bbs that have exit edge and need a fake entry edge too. * gcc.dg/tree-prof/pr44777.c: New test. --- gcc/profile.c.jj 2011-12-21 19:24:35.000000000 +0100 +++ gcc/profile.c 2012-01-04 15:39:41.002668865 +0100 @@ -1040,6 +1040,41 @@ branch_prob (void) fprintf (dump_file, "Adding fake entry edge to bb %i\n", bb->index); make_edge (ENTRY_BLOCK_PTR, bb, EDGE_FAKE); + /* Avoid bbs that have both fake entry edge and also some + exit edge. One of those edges wouldn't be added to the + spanning tree, but we can't instrument any of them. */ + if (have_exit_edge || need_exit_edge) + { + gimple_stmt_iterator gsi; + gimple first; + tree fndecl; + + gsi = gsi_after_labels (bb); + gcc_checking_assert (!gsi_end_p (gsi)); + first = gsi_stmt (gsi); + if (is_gimple_debug (first)) + { + gsi_next_nondebug (&gsi); + gcc_checking_assert (!gsi_end_p (gsi)); + first = gsi_stmt (gsi); + } + /* Don't split the bbs containing __builtin_setjmp_receiver + or __builtin_setjmp_dispatcher calls. These are very + special and don't expect anything to be inserted before + them. */ + if (!is_gimple_call (first) + || (fndecl = gimple_call_fndecl (first)) == NULL + || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL + || (DECL_FUNCTION_CODE (fndecl) != BUILT_IN_SETJMP_RECEIVER + && (DECL_FUNCTION_CODE (fndecl) + != BUILT_IN_SETJMP_DISPATCHER))) + { + if (dump_file) + fprintf (dump_file, "Splitting bb %i after labels\n", + bb->index); + split_block_after_labels (bb); + } + } } } --- gcc/testsuite/gcc.dg/tree-prof/pr44777.c.jj 2012-01-04 15:44:46.007904541 +0100 +++ gcc/testsuite/gcc.dg/tree-prof/pr44777.c 2012-01-04 15:47:29.469958984 +0100 @@ -0,0 +1,43 @@ +/* PR middle-end/44777 */ +/* { dg-options "-O0" } */ +/* A variant of gcc.c-torture/execute/comp-goto-2.c. */ + +extern void abort (void); +extern void exit (int); + +#ifdef STACK_SIZE +#define DEPTH ((STACK_SIZE) / 512 + 1) +#else +#define DEPTH 1000 +#endif + +#if ! defined (NO_LABEL_VALUES) && !defined (NO_TRAMPOLINES) +int +x (int a) +{ + __label__ xlab; + void y (int a) + { + void *x = &&llab; + if (a==-1) + goto *x; + if (a==0) + goto xlab; + llab: + y (a-1); + } + y (a); + xlab:; + return a; +} +#endif + +int +main () +{ +#if ! defined (NO_LABEL_VALUES) && !defined (NO_TRAMPOLINES) + if (x (DEPTH) != DEPTH) + abort (); +#endif + exit (0); +} Jakub