re PR target/82158 (_Noreturn functions that do return clobber caller's registers...
authorJakub Jelinek <jakub@redhat.com>
Fri, 20 Oct 2017 07:35:48 +0000 (09:35 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 20 Oct 2017 07:35:48 +0000 (09:35 +0200)
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.

From-SVN: r253926

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/noreturn-1.c [new file with mode: 0644]
gcc/tree-cfg.c

index f28e70a37766fc1a8b384b14f4aa1ec6df210697..42d98733299d3cb8b0b4d27d50b3e356894769f8 100644 (file)
@@ -1,5 +1,10 @@
 2017-10-20  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 ().
+
        PR sanitizer/82595
        * config/gnu-user.h (LIBTSAN_EARLY_SPEC): Add libtsan_preinit.o
        for -fsanitize=thread link of executables.
index d3b3be3699d3ba855931ead97f92a0155c83051b..35cc34e6cb20660b511ccddb78e4e8a9d2a185b7 100644 (file)
@@ -1,5 +1,8 @@
 2017-10-20  Jakub Jelinek  <jakub@redhat.com>
 
+       PR target/82158
+       * gcc.dg/tree-ssa/noreturn-1.c: New test.
+
        PR target/82370
        * gcc.target/i386/avx-pr82370.c: New test.
        * gcc.target/i386/avx2-pr82370.c: New test.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/noreturn-1.c b/gcc/testsuite/gcc.dg/tree-ssa/noreturn-1.c
new file mode 100644 (file)
index 0000000..ae7ee42
--- /dev/null
@@ -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" } */
index a7c7348ed298e0e22b48464c59e81d900f7ee1f3..ae1cdb33f53af277b12c6c5c3becda8b10103110 100644 (file)
@@ -9077,13 +9077,29 @@ pass_warn_function_return::execute (function *fun)
       && 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;