re PR c/39252 (Request new feature __builtin_unreachable ())
authorDavid Daney <ddaney@caviumnetworks.com>
Thu, 11 Jun 2009 23:55:45 +0000 (23:55 +0000)
committerDavid Daney <daney@gcc.gnu.org>
Thu, 11 Jun 2009 23:55:45 +0000 (23:55 +0000)
2009-06-11  David Daney  <ddaney@caviumnetworks.com>

PR c/39252
* doc/extend.texi ( __builtin_unreachable): Document new builtin.
* builtins.c (expand_builtin_unreachable): New function.
(expand_builtin): Handle BUILT_IN_UNREACHABLE case.
* builtins.def (BUILT_IN_UNREACHABLE): Add new builtin.
* cfgcleanup.c (try_optimize_cfg): Delete empty blocks with no
successors.
* cfgrtl.c (rtl_verify_flow_info): Handle empty blocks when
searching for missing barriers.

2009-06-11  David Daney  <ddaney@caviumnetworks.com>

PR c/39252
* gcc.dg/builtin-unreachable-1.c: New test.
* gcc.dg/builtin-unreachable-2.c: Same.

From-SVN: r148403

gcc/ChangeLog
gcc/builtins.c
gcc/builtins.def
gcc/cfgcleanup.c
gcc/cfgrtl.c
gcc/doc/extend.texi
gcc/system.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtin-unreachable-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/builtin-unreachable-2.c [new file with mode: 0644]

index b90d23de1a289beea8252734cdb494eb3b65e66a..7a19b5be40d373a3e1c4f6e03ceb4eaef2720019 100644 (file)
@@ -1,3 +1,15 @@
+2009-06-11  David Daney  <ddaney@caviumnetworks.com>
+
+       PR c/39252
+       * doc/extend.texi ( __builtin_unreachable): Document new builtin.
+       * builtins.c (expand_builtin_unreachable): New function.
+       (expand_builtin): Handle BUILT_IN_UNREACHABLE case.
+       * builtins.def (BUILT_IN_UNREACHABLE): Add new builtin.
+       * cfgcleanup.c (try_optimize_cfg): Delete empty blocks with no
+       successors.
+       * cfgrtl.c (rtl_verify_flow_info): Handle empty blocks when
+       searching for missing barriers.
+
 2009-06-11  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>
 
        * config/darwin.h (LINK_COMMAND_SPEC): Adjust spec to link libcov
index a555e4fa14bec2a0bc8802d92e52497a307b0638..98919780e286843fb43bfe33096cbe9c7839754e 100644 (file)
@@ -5298,6 +5298,17 @@ expand_builtin_trap (void)
   emit_barrier ();
 }
 
+/* Expand a call to __builtin_unreachable.  We do nothing except emit
+   a barrier saying that control flow will not pass here.
+
+   It is the responsibility of the program being compiled to ensure
+   that control flow does never reach __builtin_unreachable.  */
+static void
+expand_builtin_unreachable (void)
+{
+  emit_barrier ();
+}
+
 /* Expand EXP, a call to fabs, fabsf or fabsl.
    Return NULL_RTX if a normal call should be emitted rather than expanding
    the function inline.  If convenient, the result should be placed
@@ -6795,6 +6806,10 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       expand_builtin_trap ();
       return const0_rtx;
 
+    case BUILT_IN_UNREACHABLE:
+      expand_builtin_unreachable ();
+      return const0_rtx;
+
     case BUILT_IN_PRINTF:
       target = expand_builtin_printf (exp, target, mode, false);
       if (target)
index 3f4e251c3fdaaf95856fbc12074c74313e4cf20a..8d1693605a6dd7fbc45471d41f09676062be7026 100644 (file)
@@ -698,6 +698,7 @@ DEF_GCC_BUILTIN        (BUILT_IN_SETJMP, "setjmp", BT_FN_INT_PTR, ATTR_NULL)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_STRFMON, "strfmon", BT_FN_SSIZE_STRING_SIZE_CONST_STRING_VAR, ATTR_FORMAT_STRFMON_NOTHROW_3_4)
 DEF_LIB_BUILTIN        (BUILT_IN_STRFTIME, "strftime", BT_FN_SIZE_STRING_SIZE_CONST_STRING_CONST_PTR, ATTR_FORMAT_STRFTIME_NOTHROW_3_0)
 DEF_GCC_BUILTIN        (BUILT_IN_TRAP, "trap", BT_FN_VOID, ATTR_NORETURN_NOTHROW_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UNREACHABLE, "unreachable", BT_FN_VOID, ATTR_NORETURN_NOTHROW_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_UNWIND_INIT, "unwind_init", BT_FN_VOID, ATTR_NULL)
 DEF_GCC_BUILTIN        (BUILT_IN_UPDATE_SETJMP_BUF, "update_setjmp_buf", BT_FN_VOID_PTR_INT, ATTR_NULL)
 DEF_GCC_BUILTIN        (BUILT_IN_VA_COPY, "va_copy", BT_FN_VOID_VALIST_REF_VALIST_ARG, ATTR_NOTHROW_LIST)
index 8da967a4ee0efa4efc68941b6ae8c54814d64ad6..a8b38d7247272cab7d48901bab43351f80cdbf84 100644 (file)
@@ -1873,8 +1873,12 @@ try_optimize_cfg (int mode)
              edge s;
              bool changed_here = false;
 
-             /* Delete trivially dead basic blocks.  */
-             if (EDGE_COUNT (b->preds) == 0)
+             /* Delete trivially dead basic blocks.  This is either
+                blocks with no predecessors, or empty blocks with no
+                successors.  Empty blocks may result from expanding
+                __builtin_unreachable ().  */
+             if (EDGE_COUNT (b->preds) == 0
+                 || (EDGE_COUNT (b->succs) == 0 && BB_HEAD (b) == BB_END (b)))
                {
                  c = b->prev_bb;
                  if (dump_file)
index 040d4184e61423b75254b25d7b22aea01c222918..3129ce6bc66c56018bbdcb1e12a571d61471ad44 100644 (file)
@@ -2046,15 +2046,17 @@ rtl_verify_flow_info (void)
          rtx insn;
 
          /* Ensure existence of barrier in BB with no fallthru edges.  */
-         for (insn = BB_END (bb); !insn || !BARRIER_P (insn);
-              insn = NEXT_INSN (insn))
-           if (!insn
-               || NOTE_INSN_BASIC_BLOCK_P (insn))
+         for (insn = NEXT_INSN (BB_END (bb)); ; insn = NEXT_INSN (insn))
+           {
+             if (!insn || NOTE_INSN_BASIC_BLOCK_P (insn))
                {
                  error ("missing barrier after block %i", bb->index);
                  err = 1;
                  break;
                }
+             if (BARRIER_P (insn))
+               break;
+           }
        }
       else if (e->src != ENTRY_BLOCK_PTR
               && e->dest != EXIT_BLOCK_PTR)
index 222d7e0e132574a7d53bed6ecc47bd482e1198d7..6817af5d6aa130f1f99a63ece5772114caf83752 100644 (file)
@@ -6815,6 +6815,61 @@ intentionally executing an illegal instruction) or by calling
 you should not rely on any particular implementation.
 @end deftypefn
 
+@deftypefn {Built-in Function} void __builtin_unreachable (void)
+If control flow reaches the point of the @code{__builtin_unreachable},
+the program is undefined.  It is useful in situations where the
+compiler cannot deduce the unreachability of the code.
+
+One such case is immediately following an @code{asm} statement that
+will either never terminate, or one that transfers control elsewhere
+and never returns.  In this example, without the
+@code{__builtin_unreachable}, GCC would issue a warning that control
+reaches the end of a non-void function.  It would also generate code
+to return after the @code{asm}.
+
+@smallexample
+int f (int c, int v)
+@{
+  if (c)
+    @{
+      return v;
+    @}
+  else
+    @{
+      asm("jmp error_handler");
+      __builtin_unreachable ();
+    @}
+@}
+@end smallexample
+
+Because the @code{asm} statement unconditionally transfers control out
+of the function, control will never reach the end of the function
+body.  The @code{__builtin_unreachable} is in fact unreachable and
+communicates this fact to the compiler.
+
+Another use for @code{__builtin_unreachable} is following a call a
+function that never returns but that is not declared
+@code{__attribute__((noreturn))}, as in this example:
+
+@smallexample
+void function_that_never_returns (void);
+
+int g (int c)
+@{
+  if (c)
+    @{
+      return 1;
+    @}
+  else
+    @{
+      function_that_never_returns ();
+      __builtin_unreachable ();
+    @}
+@}
+@end smallexample
+
+@end deftypefn
+
 @deftypefn {Built-in Function} void __builtin___clear_cache (char *@var{begin}, char *@var{end})
 This function is used to flush the processor's instruction cache for
 the region of memory between @var{begin} inclusive and @var{end}
index 51d9c995c3cf86783d6d22ccdc58264e36e6e678..3bb61ce8490844a4f9f07975e0c4179da19910c4 100644 (file)
@@ -576,14 +576,20 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN;
 #if ENABLE_ASSERT_CHECKING
 #define gcc_assert(EXPR)                                               \
    ((void)(!(EXPR) ? fancy_abort (__FILE__, __LINE__, __FUNCTION__), 0 : 0))
+#elif (__GNUC__ == 4) && (__GNUC_MINOR__) && 0
+#define gcc_assert(EXPR) do { if (EXPR) __builtin_unreachable (); } while (0)
 #else
 /* Include EXPR, so that unused variable warnings do not occur.  */
 #define gcc_assert(EXPR) ((void)(0 && (EXPR)))
 #endif
 
+#if !ENABLE_ASSERT_CHECKING && (__GNUC__ == 4) && (__GNUC_MINOR__) && 0
+#define gcc_unreachable()  __builtin_unreachable ()
+#else
 /* Use gcc_unreachable() to mark unreachable locations (like an
    unreachable default case of a switch.  Do not use gcc_assert(0).  */
 #define gcc_unreachable() (fancy_abort (__FILE__, __LINE__, __FUNCTION__))
+#endif
 
 /* Provide a fake boolean type.  We make no attempt to use the
    C99 _Bool, as it may not be available in the bootstrap compiler,
index d49243f41d58d7684d2ce56be852a97ba1280e89..8d1a113d6ba92b6c744aeb968b48b05cb6c3f785 100644 (file)
@@ -1,3 +1,9 @@
+2009-06-11  David Daney  <ddaney@caviumnetworks.com>
+
+       PR c/39252
+       * gcc.dg/builtin-unreachable-1.c: New test.
+       * gcc.dg/builtin-unreachable-2.c: Same.
+
 2009-06-11  Paul Thomas  <pault@gcc.gnu.org>
 
        PR fortran/40402
diff --git a/gcc/testsuite/gcc.dg/builtin-unreachable-1.c b/gcc/testsuite/gcc.dg/builtin-unreachable-1.c
new file mode 100644 (file)
index 0000000..165da3f
--- /dev/null
@@ -0,0 +1,17 @@
+/* Check that __builtin_unreachable() prevents the 'control reaches
+   end of non-void function' diagnostic.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wreturn-type" } */
+int
+f(int a, int b)
+{
+  if (a)
+    {
+      return b;
+    }
+  else
+    {
+      asm ("bug");
+      __builtin_unreachable();
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-unreachable-2.c b/gcc/testsuite/gcc.dg/builtin-unreachable-2.c
new file mode 100644 (file)
index 0000000..13bdb9f
--- /dev/null
@@ -0,0 +1,20 @@
+/* Check that __builtin_unreachable() is a no-return function thus
+   causing the dead call to foo() to be removed.  The comparison is
+   dead too, and should be removed.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized -fdump-rtl-cse1" } */
+void foo (void);
+
+int
+f (int i)
+{
+  if (i > 1)
+    __builtin_unreachable();
+  if (i > 1)
+    foo ();
+  return 1;
+}
+/* { dg-final { scan-tree-dump-not "foo" "optimized" } } */
+/* { dg-final { scan-rtl-dump-not "\\(if_then_else" "cse1" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
+/* { dg-final { cleanup-rtl-dump "cse1" } } */