diff mbox

Fix __builtin_setjmp handling (PR tree-optimization/60003)

Message ID 20140131212422.GZ892@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Jan. 31, 2014, 9:24 p.m. UTC
Hi!

As described in the PR, __builtin_setjmp_receiver isn't declared to
returns_twice, and thus after dce cfun->calls_setjmp might be no longer true.
At RTL __builtin_setjmp_receiver is handled as non-local label, so this
patch just forces cfun->has_nonlocal_label already in GIMPLE, so that
e.g. the inliner still sees stmt_can_make_nonlocal_goto.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2014-01-31  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/60003
	* gimple-low.c (lower_builtin_setjmp): Set cfun->has_nonlocal_label.
	* profile.c (branch_prob): Use gimple_call_builtin_p
	to check for BUILT_IN_SETJMP_RECEIVER.
	* tree-inline.c (copy_bb): Call notice_special_calls.

	* gcc.c-torture/execute/pr60003.c: New test.


	Jakub

Comments

Richard Biener Feb. 1, 2014, 5:49 a.m. UTC | #1
On January 31, 2014 10:24:22 PM GMT+01:00, Jakub Jelinek <jakub@redhat.com> wrote:
>Hi!
>
>As described in the PR, __builtin_setjmp_receiver isn't declared to
>returns_twice, and thus after dce cfun->calls_setjmp might be no longer
>true.
>At RTL __builtin_setjmp_receiver is handled as non-local label, so this
>patch just forces cfun->has_nonlocal_label already in GIMPLE, so that
>e.g. the inliner still sees stmt_can_make_nonlocal_goto.
>
>Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Ok.

Thanks,
Richard.

>2014-01-31  Jakub Jelinek  <jakub@redhat.com>
>
>	PR tree-optimization/60003
>	* gimple-low.c (lower_builtin_setjmp): Set cfun->has_nonlocal_label.
>	* profile.c (branch_prob): Use gimple_call_builtin_p
>	to check for BUILT_IN_SETJMP_RECEIVER.
>	* tree-inline.c (copy_bb): Call notice_special_calls.
>
>	* gcc.c-torture/execute/pr60003.c: New test.
>
>--- gcc/gimple-low.c.jj	2014-01-29 12:43:25.000000000 +0100
>+++ gcc/gimple-low.c	2014-01-31 10:02:38.843026680 +0100
>@@ -709,6 +709,12 @@ lower_builtin_setjmp (gimple_stmt_iterat
>   tree dest, t, arg;
>   gimple g;
>
>+  /* __builtin_setjmp_{setup,receiver} aren't ECF_RETURNS_TWICE and
>for RTL
>+     these builtins are modelled as non-local label jumps to the label
>+     that is passed to these two builtins, so pretend we have a
>non-local
>+     label during GIMPLE passes too.  See PR60003.  */ 
>+  cfun->has_nonlocal_label = true;
>+
>/* NEXT_LABEL is the label __builtin_longjmp will jump to.  Its address
>is
>passed to both __builtin_setjmp_setup and __builtin_setjmp_receiver. 
>*/
>   FORCED_LABEL (next_label) = 1;
>--- gcc/profile.c.jj	2014-01-29 12:43:25.000000000 +0100
>+++ gcc/profile.c	2014-01-31 10:18:00.450198256 +0100
>@@ -1104,7 +1104,6 @@ branch_prob (void)
> 	    {
> 	      gimple_stmt_iterator gsi;
> 	      gimple first;
>-	      tree fndecl;
> 
> 	      gsi = gsi_start_nondebug_after_labels_bb (bb);
> 	      gcc_checking_assert (!gsi_end_p (gsi));
>@@ -1114,10 +1113,7 @@ branch_prob (void)
> 		 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))
>+		  && (gimple_call_builtin_p (first, BUILT_IN_SETJMP_RECEIVER)
> 		      || (gimple_call_flags (first) & ECF_RETURNS_TWICE)
> 		      || (gimple_call_internal_p (first)
> 			  && (gimple_call_internal_fn (first)
>--- gcc/tree-inline.c.jj	2014-01-29 12:43:24.000000000 +0100
>+++ gcc/tree-inline.c	2014-01-31 10:19:13.849815593 +0100
>@@ -1745,7 +1745,6 @@ copy_bb (copy_body_data *id, basic_block
> 	  if (is_gimple_call (stmt))
> 	    {
> 	      struct cgraph_edge *edge;
>-	      int flags;
> 
> 	      switch (id->transform_call_graph_edges)
> 		{
>@@ -1868,11 +1867,7 @@ copy_bb (copy_body_data *id, basic_block
> 		    }
> 		}
> 
>-	      flags = gimple_call_flags (stmt);
>-	      if (flags & ECF_MAY_BE_ALLOCA)
>-		cfun->calls_alloca = true;
>-	      if (flags & ECF_RETURNS_TWICE)
>-		cfun->calls_setjmp = true;
>+	      notice_special_calls (stmt);
> 	    }
> 
> 	  maybe_duplicate_eh_stmt_fn (cfun, stmt, id->src_cfun, orig_stmt,
>--- gcc/testsuite/gcc.c-torture/execute/pr60003.c.jj	2014-01-31
>10:05:15.095205547 +0100
>+++ gcc/testsuite/gcc.c-torture/execute/pr60003.c	2014-01-31
>10:04:59.000000000 +0100
>@@ -0,0 +1,48 @@
>+/* PR tree-optimization/60003 */
>+
>+extern void abort (void);
>+
>+unsigned long long jmp_buf[5];
>+
>+__attribute__((noinline, noclone)) void
>+baz (void)
>+{
>+  __builtin_longjmp (&jmp_buf, 1);
>+}
>+
>+void
>+bar (void)
>+{
>+  baz ();
>+}
>+
>+__attribute__((noinline, noclone)) int
>+foo (int x)
>+{
>+  int a = 0;
>+
>+  if (__builtin_setjmp (&jmp_buf) == 0)
>+    {
>+      while (1)
>+	{
>+	  a = 1;
>+	  bar ();  /* OK if baz () instead */
>+	}
>+    }
>+  else
>+    {
>+      if (a == 0)
>+	return 0;
>+      else
>+	return x;
>+    }
>+}
>+
>+int
>+main ()
>+{
>+  if (foo (1) == 0)
>+    abort ();
>+
>+  return 0;
>+}
>
>	Jakub
diff mbox

Patch

--- gcc/gimple-low.c.jj	2014-01-29 12:43:25.000000000 +0100
+++ gcc/gimple-low.c	2014-01-31 10:02:38.843026680 +0100
@@ -709,6 +709,12 @@  lower_builtin_setjmp (gimple_stmt_iterat
   tree dest, t, arg;
   gimple g;

+  /* __builtin_setjmp_{setup,receiver} aren't ECF_RETURNS_TWICE and for RTL
+     these builtins are modelled as non-local label jumps to the label
+     that is passed to these two builtins, so pretend we have a non-local
+     label during GIMPLE passes too.  See PR60003.  */ 
+  cfun->has_nonlocal_label = true;
+
   /* NEXT_LABEL is the label __builtin_longjmp will jump to.  Its address is
      passed to both __builtin_setjmp_setup and __builtin_setjmp_receiver.  */
   FORCED_LABEL (next_label) = 1;
--- gcc/profile.c.jj	2014-01-29 12:43:25.000000000 +0100
+++ gcc/profile.c	2014-01-31 10:18:00.450198256 +0100
@@ -1104,7 +1104,6 @@  branch_prob (void)
 	    {
 	      gimple_stmt_iterator gsi;
 	      gimple first;
-	      tree fndecl;
 
 	      gsi = gsi_start_nondebug_after_labels_bb (bb);
 	      gcc_checking_assert (!gsi_end_p (gsi));
@@ -1114,10 +1113,7 @@  branch_prob (void)
 		 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))
+		  && (gimple_call_builtin_p (first, BUILT_IN_SETJMP_RECEIVER)
 		      || (gimple_call_flags (first) & ECF_RETURNS_TWICE)
 		      || (gimple_call_internal_p (first)
 			  && (gimple_call_internal_fn (first)
--- gcc/tree-inline.c.jj	2014-01-29 12:43:24.000000000 +0100
+++ gcc/tree-inline.c	2014-01-31 10:19:13.849815593 +0100
@@ -1745,7 +1745,6 @@  copy_bb (copy_body_data *id, basic_block
 	  if (is_gimple_call (stmt))
 	    {
 	      struct cgraph_edge *edge;
-	      int flags;
 
 	      switch (id->transform_call_graph_edges)
 		{
@@ -1868,11 +1867,7 @@  copy_bb (copy_body_data *id, basic_block
 		    }
 		}
 
-	      flags = gimple_call_flags (stmt);
-	      if (flags & ECF_MAY_BE_ALLOCA)
-		cfun->calls_alloca = true;
-	      if (flags & ECF_RETURNS_TWICE)
-		cfun->calls_setjmp = true;
+	      notice_special_calls (stmt);
 	    }
 
 	  maybe_duplicate_eh_stmt_fn (cfun, stmt, id->src_cfun, orig_stmt,
--- gcc/testsuite/gcc.c-torture/execute/pr60003.c.jj	2014-01-31 10:05:15.095205547 +0100
+++ gcc/testsuite/gcc.c-torture/execute/pr60003.c	2014-01-31 10:04:59.000000000 +0100
@@ -0,0 +1,48 @@ 
+/* PR tree-optimization/60003 */
+
+extern void abort (void);
+
+unsigned long long jmp_buf[5];
+
+__attribute__((noinline, noclone)) void
+baz (void)
+{
+  __builtin_longjmp (&jmp_buf, 1);
+}
+
+void
+bar (void)
+{
+  baz ();
+}
+
+__attribute__((noinline, noclone)) int
+foo (int x)
+{
+  int a = 0;
+
+  if (__builtin_setjmp (&jmp_buf) == 0)
+    {
+      while (1)
+	{
+	  a = 1;
+	  bar ();  /* OK if baz () instead */
+	}
+    }
+  else
+    {
+      if (a == 0)
+	return 0;
+      else
+	return x;
+    }
+}
+
+int
+main ()
+{
+  if (foo (1) == 0)
+    abort ();
+
+  return 0;
+}