Commit 468059bc by David Daney Committed by David Daney

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
parent f43def61
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> 2009-06-11 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
* config/darwin.h (LINK_COMMAND_SPEC): Adjust spec to link libcov * config/darwin.h (LINK_COMMAND_SPEC): Adjust spec to link libcov
......
...@@ -5298,6 +5298,17 @@ expand_builtin_trap (void) ...@@ -5298,6 +5298,17 @@ expand_builtin_trap (void)
emit_barrier (); 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. /* Expand EXP, a call to fabs, fabsf or fabsl.
Return NULL_RTX if a normal call should be emitted rather than expanding Return NULL_RTX if a normal call should be emitted rather than expanding
the function inline. If convenient, the result should be placed 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, ...@@ -6795,6 +6806,10 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
expand_builtin_trap (); expand_builtin_trap ();
return const0_rtx; return const0_rtx;
case BUILT_IN_UNREACHABLE:
expand_builtin_unreachable ();
return const0_rtx;
case BUILT_IN_PRINTF: case BUILT_IN_PRINTF:
target = expand_builtin_printf (exp, target, mode, false); target = expand_builtin_printf (exp, target, mode, false);
if (target) if (target)
......
...@@ -698,6 +698,7 @@ DEF_GCC_BUILTIN (BUILT_IN_SETJMP, "setjmp", BT_FN_INT_PTR, ATTR_NULL) ...@@ -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_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_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_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_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_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) DEF_GCC_BUILTIN (BUILT_IN_VA_COPY, "va_copy", BT_FN_VOID_VALIST_REF_VALIST_ARG, ATTR_NOTHROW_LIST)
......
...@@ -1873,8 +1873,12 @@ try_optimize_cfg (int mode) ...@@ -1873,8 +1873,12 @@ try_optimize_cfg (int mode)
edge s; edge s;
bool changed_here = false; bool changed_here = false;
/* Delete trivially dead basic blocks. */ /* Delete trivially dead basic blocks. This is either
if (EDGE_COUNT (b->preds) == 0) 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; c = b->prev_bb;
if (dump_file) if (dump_file)
......
...@@ -2046,15 +2046,17 @@ rtl_verify_flow_info (void) ...@@ -2046,15 +2046,17 @@ rtl_verify_flow_info (void)
rtx insn; rtx insn;
/* Ensure existence of barrier in BB with no fallthru edges. */ /* Ensure existence of barrier in BB with no fallthru edges. */
for (insn = BB_END (bb); !insn || !BARRIER_P (insn); for (insn = NEXT_INSN (BB_END (bb)); ; insn = NEXT_INSN (insn))
insn = NEXT_INSN (insn)) {
if (!insn if (!insn || NOTE_INSN_BASIC_BLOCK_P (insn))
|| NOTE_INSN_BASIC_BLOCK_P (insn))
{ {
error ("missing barrier after block %i", bb->index); error ("missing barrier after block %i", bb->index);
err = 1; err = 1;
break; break;
} }
if (BARRIER_P (insn))
break;
}
} }
else if (e->src != ENTRY_BLOCK_PTR else if (e->src != ENTRY_BLOCK_PTR
&& e->dest != EXIT_BLOCK_PTR) && e->dest != EXIT_BLOCK_PTR)
......
...@@ -6815,6 +6815,61 @@ intentionally executing an illegal instruction) or by calling ...@@ -6815,6 +6815,61 @@ intentionally executing an illegal instruction) or by calling
you should not rely on any particular implementation. you should not rely on any particular implementation.
@end deftypefn @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}) @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 This function is used to flush the processor's instruction cache for
the region of memory between @var{begin} inclusive and @var{end} the region of memory between @var{begin} inclusive and @var{end}
......
...@@ -576,14 +576,20 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN; ...@@ -576,14 +576,20 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN;
#if ENABLE_ASSERT_CHECKING #if ENABLE_ASSERT_CHECKING
#define gcc_assert(EXPR) \ #define gcc_assert(EXPR) \
((void)(!(EXPR) ? fancy_abort (__FILE__, __LINE__, __FUNCTION__), 0 : 0)) ((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 #else
/* Include EXPR, so that unused variable warnings do not occur. */ /* Include EXPR, so that unused variable warnings do not occur. */
#define gcc_assert(EXPR) ((void)(0 && (EXPR))) #define gcc_assert(EXPR) ((void)(0 && (EXPR)))
#endif #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 /* Use gcc_unreachable() to mark unreachable locations (like an
unreachable default case of a switch. Do not use gcc_assert(0). */ unreachable default case of a switch. Do not use gcc_assert(0). */
#define gcc_unreachable() (fancy_abort (__FILE__, __LINE__, __FUNCTION__)) #define gcc_unreachable() (fancy_abort (__FILE__, __LINE__, __FUNCTION__))
#endif
/* Provide a fake boolean type. We make no attempt to use the /* Provide a fake boolean type. We make no attempt to use the
C99 _Bool, as it may not be available in the bootstrap compiler, C99 _Bool, as it may not be available in the bootstrap compiler,
......
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> 2009-06-11 Paul Thomas <pault@gcc.gnu.org>
PR fortran/40402 PR fortran/40402
......
/* 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();
}
}
/* 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" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment