diff mbox

Fix fake edge handling in branch_prob (PR middle-end/44777)

Message ID 20120105000527.GG18937@tyan-ft48-01.lab.bos.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Jan. 5, 2012, 12:05 a.m. UTC
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  <jakub@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.


	Jakub
diff mbox

Patch

--- 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);
+}