aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Daney <ddaney@caviumnetworks.com>2009-06-11 23:55:45 +0000
committerDavid Daney <daney@gcc.gnu.org>2009-06-11 23:55:45 +0000
commit468059bcbb8efdb31fd90369dc2ed122126413fe (patch)
tree33e26cb48c7e5455995d1edba975d67cf78cad99
parentf43def61eaf4f2e1f73c5af6ad806955b8f09949 (diff)
downloadgcc-468059bcbb8efdb31fd90369dc2ed122126413fe.zip
gcc-468059bcbb8efdb31fd90369dc2ed122126413fe.tar.gz
gcc-468059bcbb8efdb31fd90369dc2ed122126413fe.tar.bz2
re PR c/39252 (Request new feature __builtin_unreachable ())
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
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/builtins.c15
-rw-r--r--gcc/builtins.def1
-rw-r--r--gcc/cfgcleanup.c8
-rw-r--r--gcc/cfgrtl.c10
-rw-r--r--gcc/doc/extend.texi55
-rw-r--r--gcc/system.h6
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.dg/builtin-unreachable-1.c17
-rw-r--r--gcc/testsuite/gcc.dg/builtin-unreachable-2.c20
10 files changed, 144 insertions, 6 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b90d23d..7a19b5b 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/builtins.c b/gcc/builtins.c
index a555e4f..9891978 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -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)
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 3f4e251..8d16936 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -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)
diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c
index 8da967a..a8b38d7 100644
--- a/gcc/cfgcleanup.c
+++ b/gcc/cfgcleanup.c
@@ -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)
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index 040d418..3129ce6 100644
--- a/gcc/cfgrtl.c
+++ b/gcc/cfgrtl.c
@@ -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)
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 222d7e0..6817af5 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -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}
diff --git a/gcc/system.h b/gcc/system.h
index 51d9c99..3bb61ce 100644
--- a/gcc/system.h
+++ b/gcc/system.h
@@ -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,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d49243f..8d1a113 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..165da3f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-unreachable-1.c
@@ -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
index 0000000..13bdb9f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-unreachable-2.c
@@ -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" } } */