Bug 39252 - Request new feature __builtin_unreachable ()
Summary: Request new feature __builtin_unreachable ()
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.4.0
: P3 enhancement
Target Milestone: 4.5.0
Assignee: David Daney
URL:
Keywords: patch
Depends on:
Blocks:
 
Reported: 2009-02-19 20:42 UTC by H. Peter Anvin
Modified: 2009-06-12 00:29 UTC (History)
6 users (show)

See Also:
Host: All
Target: All
Build: All
Known to work:
Known to fail:
Last reconfirmed: 2009-02-20 09:57:15


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description H. Peter Anvin 2009-02-19 20:42:11 UTC
In the Linux kernel, we use assembly constructs (asm volatile) which trap or otherwise terminate execution.  gcc doesn't know about this, so it doesn't terminate its flow analysis.  These assembly constructs are more complex than a simple __builtin_trap(); will permit -- we have tried using assembly constructs in conjunction with __builtin_trap(); but that relies too much on undefined behaviour.

A much better solution would be to give us __builtin_not_reached(); which is simply an annotation truncating the flow of control at that point.  You can think of it from an implementation perspective as __builtin_trap(); that doesn't actually generate any code.  This allows any arbitrary assembly that truncates the flow of control to be annotated as such, without the overhead of a compiler-generated catch loop which is never actually reached.
Comment 1 H.J. Lu 2009-02-19 20:51:09 UTC
So __builtin_not_reached is just __builtin_trap which doesn't generate
any insn. It shouldn't be too hard to implement.
Comment 2 Andrew Pinski 2009-02-19 21:50:29 UTC
Why again is __builtin_trap not useful for this purpose? You mention about "assembly constructs"  but why not instead implement those as builtins instead of providing something which really can be abused?
Comment 3 H. Peter Anvin 2009-02-19 21:58:26 UTC
Two reasons:

1. We have no control over what instruction __builtin_trap() will generate.
2. We require the address of the faulting instruction.

In particular, we currently have a construct which looks like:

#ifdef CONFIG_X86_32
# define __BUG_C0       "2:\t.long 1b, %c0\n"
#else
# define __BUG_C0       "2:\t.long 1b - 2b, %c0 - 2b\n"
#endif

#define BUG()                                                   \
do {                                                            \
        asm volatile("1:\tud2\n"                                \
                     ".pushsection __bug_table,\"a\"\n"         \
                     __BUG_C0                                   \
                     "\t.word %c1, 0\n"                         \
                     "\t.org 2b+%c2\n"                          \
                     ".popsection"                              \
                     : : "i" (__FILE__), "i" (__LINE__),        \
                     "i" (sizeof(struct bug_entry)));           \
        for (;;) ;                                              \
} while (0)
Comment 4 Andrew Pinski 2009-02-19 22:14:12 UTC
Still you can make a builtin that does that.  Even if it is a target builtin.  I think of having a target builtin is better than creating a generic __builtin_not_reached.
Comment 5 H. Peter Anvin 2009-02-19 22:21:43 UTC
Let me respectfully disagree, and explain why.

*You* can just create a builtin, but for us (the Linux kernel community) we stare a multi-year pipeline in the face whenever we have to request a gcc change.  This feature would allow us to do arbitrary trapping constructs via the existing generic asm feature, without having to do wait for this pipeline to flush every time we want to do something new.

In theory, ALL asm() constructs could be turned into builtins, and on some level, that would be the right thing to do.  However, I think you can see why this is completely unrealistic, at least with anything less than us forking gcc and have an ad hoc compiler for the kernel.

Yes, this feature can be abused.  So can *any* use of asm().
Comment 6 Jakub Jelinek 2009-02-19 23:02:45 UTC
Wouldn't be a special "noreturn" clobber in inline asm better suited for this then?
Comment 7 H. Peter Anvin 2009-02-20 04:34:35 UTC
A "noreturn" clobber would work just as well, obviously.
Comment 8 Richard Biener 2009-02-20 09:57:15 UTC
Though __builtin_not_reached () can be used to implement __builtin_assume (),
so it may be more generally useful.  if (i > 0) __builtin_not_reached (); will
make GCC assume that i <= 0 on the other edge (of course we'd have to preserve
this until some point to take advantage of it).
Comment 9 H. Peter Anvin 2009-03-01 22:34:05 UTC
> Though __builtin_not_reached () can be used to implement __builtin_assume (),
> so it may be more generally useful.  if (i > 0) __builtin_not_reached (); will
> make GCC assume that i <= 0 on the other edge (of course we'd have to preserve
> this until some point to take advantage of it).

This seems rather elegant to me, although I'm happy to get this feature in any form.
Comment 10 Richard Biener 2009-03-01 22:41:55 UTC
Oh, patches welcome!
Comment 11 David Daney 2009-06-09 20:12:11 UTC
This is essentially __builtin_unreachable() for which I am working on a patch.

http://gcc.gnu.org/ml/gcc-patches/2009-06/msg00787.html
Comment 12 David Daney 2009-06-09 20:16:13 UTC
(In reply to comment #6)
> Wouldn't be a special "noreturn" clobber in inline asm better suited for this
> then?
> 

See: http://gcc.gnu.org/ml/gcc-patches/2000-01/msg00190.html for an opposing opinion.
Comment 13 David Daney 2009-06-11 23:55:57 UTC
Subject: Bug 39252

Author: daney
Date: Thu Jun 11 23:55:45 2009
New Revision: 148403

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=148403
Log:
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.

Added:
    trunk/gcc/testsuite/gcc.dg/builtin-unreachable-1.c
    trunk/gcc/testsuite/gcc.dg/builtin-unreachable-2.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/builtins.c
    trunk/gcc/builtins.def
    trunk/gcc/cfgcleanup.c
    trunk/gcc/cfgrtl.c
    trunk/gcc/doc/extend.texi
    trunk/gcc/system.h
    trunk/gcc/testsuite/ChangeLog

Comment 14 David Daney 2009-06-12 00:29:39 UTC
Fixed by the patch.