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  <ja...@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

Reply via email to