diff mbox series

Slightly optimize noreturn functions (PR target/82158)

Message ID 20171019192510.GS14653@tucnak
State New
Headers show
Series Slightly optimize noreturn functions (PR target/82158) | expand

Commit Message

Jakub Jelinek Oct. 19, 2017, 7:25 p.m. UTC
Hi!

The following patch, when optimizing, replaces GIMPLE_RETURN in
noreturn functions right after warning about them with __builtin_unreachable
().  The advantage of that is that we don't emit unnecessary epilogues for
them and perhaps optimize away some other useless computations if the only
side-effect of those is feeding the return value.

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

2017-10-19  Jakub Jelinek  <jakub@redhat.com>

	PR target/82158
	* tree-cfg.c (pass_warn_function_return::execute): In noreturn
	functions when optimizing replace GIMPLE_RETURN stmts with
	calls to __builtin_unreachable ().

	* gcc.dg/tree-ssa/noreturn-1.c: New test.


	Jakub

Comments

Richard Biener Oct. 20, 2017, 6:28 a.m. UTC | #1
On October 19, 2017 9:25:10 PM GMT+02:00, Jakub Jelinek <jakub@redhat.com> wrote:
>Hi!
>
>The following patch, when optimizing, replaces GIMPLE_RETURN in
>noreturn functions right after warning about them with
>__builtin_unreachable
>().  The advantage of that is that we don't emit unnecessary epilogues
>for
>them and perhaps optimize away some other useless computations if the
>only
>side-effect of those is feeding the return value.
>
>Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK. 

Richard. 

>2017-10-19  Jakub Jelinek  <jakub@redhat.com>
>
>	PR target/82158
>	* tree-cfg.c (pass_warn_function_return::execute): In noreturn
>	functions when optimizing replace GIMPLE_RETURN stmts with
>	calls to __builtin_unreachable ().
>
>	* gcc.dg/tree-ssa/noreturn-1.c: New test.
>
>--- gcc/tree-cfg.c.jj	2017-10-10 22:04:09.000000000 +0200
>+++ gcc/tree-cfg.c	2017-10-19 18:41:04.843653944 +0200
>@@ -9084,13 +9084,29 @@ pass_warn_function_return::execute (func
>       && EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (fun)->preds) > 0)
>     {
>       location = UNKNOWN_LOCATION;
>-      FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (fun)->preds)
>+      for (ei = ei_start (EXIT_BLOCK_PTR_FOR_FN (fun)->preds);
>+	   (e = ei_safe_edge (ei)); )
> 	{
> 	  last = last_stmt (e->src);
> 	  if ((gimple_code (last) == GIMPLE_RETURN
> 	       || gimple_call_builtin_p (last, BUILT_IN_RETURN))
>-	      && (location = gimple_location (last)) != UNKNOWN_LOCATION)
>+	      && location == UNKNOWN_LOCATION
>+	      && (location = gimple_location (last)) != UNKNOWN_LOCATION
>+	      && !optimize)
> 	    break;
>+	  /* When optimizing, replace return stmts in noreturn functions
>+	     with __builtin_unreachable () call.  */
>+	  if (optimize && gimple_code (last) == GIMPLE_RETURN)
>+	    {
>+	      tree fndecl = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
>+	      gimple *new_stmt = gimple_build_call (fndecl, 0);
>+	      gimple_set_location (new_stmt, gimple_location (last));
>+	      gimple_stmt_iterator gsi = gsi_for_stmt (last);
>+	      gsi_replace (&gsi, new_stmt, true);
>+	      remove_edge (e);
>+	    }
>+	  else
>+	    ei_next (&ei);
> 	}
>       if (location == UNKNOWN_LOCATION)
> 	location = cfun->function_end_locus;
>--- gcc/testsuite/gcc.dg/tree-ssa/noreturn-1.c.jj	2017-10-19
>18:50:53.861660409 +0200
>+++ gcc/testsuite/gcc.dg/tree-ssa/noreturn-1.c	2017-10-19
>18:55:32.270354804 +0200
>@@ -0,0 +1,42 @@
>+/* { dg-do compile } *
>+/* { dg-options "-O2 -fdump-tree-ssa -std=gnu11" } */
>+/* { dg-final { scan-tree-dump-times "__builtin_unreachable" 4 "ssa" }
>} */
>+
>+void bar1 (void);
>+void bar2 (void);
>+void bar3 (void);
>+void bar4 (void);
>+
>+_Noreturn void
>+foo1 (int *p, int y)
>+{
>+  bar1 ();
>+  *p = y;
>+  return;	/* { dg-warning "function declared 'noreturn' has a 'return'
>statement" } */
>+}		/* { dg-warning "'noreturn' function does return" "" { target *-*-*
>} .-1 } */
>+
>+_Noreturn void
>+foo2 (int *p, int y)
>+{
>+  bar2 ();
>+  *p = y;
>+}		/* { dg-warning "'noreturn' function does return" } */
>+
>+_Noreturn void
>+foo3 (int *p, int y)
>+{
>+  if (y > 10)
>+    return;	/* { dg-warning "function declared 'noreturn' has a
>'return' statement" } */
>+  bar3 ();
>+  *p = y;
>+  return;	/* { dg-warning "function declared 'noreturn' has a 'return'
>statement" } */
>+}		/* { dg-warning "'noreturn' function does return" } */
>+
>+_Noreturn void
>+foo4 (int *p, int y)
>+{
>+  if (y > 10)
>+    return;	/* { dg-warning "function declared 'noreturn' has a
>'return' statement" } */
>+  bar4 ();
>+  *p = y;
>+}		/* { dg-warning "'noreturn' function does return" } */
>
>	Jakub
diff mbox series

Patch

--- gcc/tree-cfg.c.jj	2017-10-10 22:04:09.000000000 +0200
+++ gcc/tree-cfg.c	2017-10-19 18:41:04.843653944 +0200
@@ -9084,13 +9084,29 @@  pass_warn_function_return::execute (func
       && EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (fun)->preds) > 0)
     {
       location = UNKNOWN_LOCATION;
-      FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (fun)->preds)
+      for (ei = ei_start (EXIT_BLOCK_PTR_FOR_FN (fun)->preds);
+	   (e = ei_safe_edge (ei)); )
 	{
 	  last = last_stmt (e->src);
 	  if ((gimple_code (last) == GIMPLE_RETURN
 	       || gimple_call_builtin_p (last, BUILT_IN_RETURN))
-	      && (location = gimple_location (last)) != UNKNOWN_LOCATION)
+	      && location == UNKNOWN_LOCATION
+	      && (location = gimple_location (last)) != UNKNOWN_LOCATION
+	      && !optimize)
 	    break;
+	  /* When optimizing, replace return stmts in noreturn functions
+	     with __builtin_unreachable () call.  */
+	  if (optimize && gimple_code (last) == GIMPLE_RETURN)
+	    {
+	      tree fndecl = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
+	      gimple *new_stmt = gimple_build_call (fndecl, 0);
+	      gimple_set_location (new_stmt, gimple_location (last));
+	      gimple_stmt_iterator gsi = gsi_for_stmt (last);
+	      gsi_replace (&gsi, new_stmt, true);
+	      remove_edge (e);
+	    }
+	  else
+	    ei_next (&ei);
 	}
       if (location == UNKNOWN_LOCATION)
 	location = cfun->function_end_locus;
--- gcc/testsuite/gcc.dg/tree-ssa/noreturn-1.c.jj	2017-10-19 18:50:53.861660409 +0200
+++ gcc/testsuite/gcc.dg/tree-ssa/noreturn-1.c	2017-10-19 18:55:32.270354804 +0200
@@ -0,0 +1,42 @@ 
+/* { dg-do compile } *
+/* { dg-options "-O2 -fdump-tree-ssa -std=gnu11" } */
+/* { dg-final { scan-tree-dump-times "__builtin_unreachable" 4 "ssa" } } */
+
+void bar1 (void);
+void bar2 (void);
+void bar3 (void);
+void bar4 (void);
+
+_Noreturn void
+foo1 (int *p, int y)
+{
+  bar1 ();
+  *p = y;
+  return;	/* { dg-warning "function declared 'noreturn' has a 'return' statement" } */
+}		/* { dg-warning "'noreturn' function does return" "" { target *-*-* } .-1 } */
+
+_Noreturn void
+foo2 (int *p, int y)
+{
+  bar2 ();
+  *p = y;
+}		/* { dg-warning "'noreturn' function does return" } */
+
+_Noreturn void
+foo3 (int *p, int y)
+{
+  if (y > 10)
+    return;	/* { dg-warning "function declared 'noreturn' has a 'return' statement" } */
+  bar3 ();
+  *p = y;
+  return;	/* { dg-warning "function declared 'noreturn' has a 'return' statement" } */
+}		/* { dg-warning "'noreturn' function does return" } */
+
+_Noreturn void
+foo4 (int *p, int y)
+{
+  if (y > 10)
+    return;	/* { dg-warning "function declared 'noreturn' has a 'return' statement" } */
+  bar4 ();
+  *p = y;
+}		/* { dg-warning "'noreturn' function does return" } */