Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #161738

Re: naked switches

From David Brown <david.brown@hesbynett.no>
Newsgroups comp.lang.c
Subject Re: naked switches
Date 2021-07-08 09:16 +0200
Organization A noiseless patient Spider
Message-ID <sc68nr$ilo$1@dont-email.me> (permalink)
References <06a0049a-2d7d-40f0-899a-fb35c9a15d5fn@googlegroups.com> <20210707175722.828@kylheku.com>

Show all headers | View raw


On 08/07/2021 03:57, Kaz Kylheku wrote:
> On 2021-07-07, Robert Finch <robfi680@gmail.com> wrote:
>> I have been working on a C/C++ like compiler. One feature supported in
>> the compiler is naked switches. A naked switch omits the range
>> checking code that is normally associated with the switch statement.
>> Omitting this code can improve performance at the risk of a crash if
>> invalid cases are processed. I am wondering if there is a similar
>> option in other C compilers? Or would this just be an automatic
>> optimization at high levels?
> 
> I've not heard of such an option. 

Nor have I.  I'd suggest that it is a /really/ bad idea, since it
changes the semantics of the language.  It would be possible to have it
as a feature written in a way that screams "this is not a switch
statement as you know it", calling it "__naked_switch(...)" or
something.  But it would be simpler, clearer, safer, more portable and
more flexible to implement "__builtin_unreachable" as you suggest here.



> Some modern compilers aggressively
> optimize on the assumption that there is no undefined behavior.
> 
> Now, I will tell you a fantasy.
> 

It is no fantasy.  Some people really get their knickers in a twist
about it, but IMHO it is a good thing.

> A conforming C implementation is free to assume that no undefined
> behavior occurs because in that case no requirements apply.
> 
> For instance, if it is obvious that some pieces of code can only be
> reached if the program has invoked undefined behavior, then that code
> can be removed as if it were unreachable.  There is no requirement that
> anything work at all after undefined behavior.
> 
> This concept allows you to encode assertions about properties like this:
> 
>   #define undefined_behavior (0/0)
> 
>   if (x < 1 || x > 12)
>     perpetrate_undefined_behavior();
> 
>   switch (x)
> 
> Because undefined behavior happens if x is outside the range 1 to 12,
> the assumption that the program is free of undefined behavior logically
> implies that x is not outside of that range.
> 
> Therefore, the if statement can be optimized away, and the switch
> statement.
> 
> A simpler way to express the above situation is this:
> 
>   switch (x) {
>   // ... cases 1 to 12 ..
>     break;
>   // out of range cases:
>   default: 0/0; // division by zero: undefined
>   }
> 
> Basically we divert the out-of-range cases to an obvious, explicitly
> defined undefined behavior. Then we hope that the compiler infers that,
> since undefined does not happen, x can be assumed not to be outside of
> the 1 to 12 range, and so why bother checking.
> 
> How well that works in practice, you have to determine experimentally.
> 
> Experimentally, I'm not able to get GCC to eliminate the check for x
> being above 9 in this code:
> 
> 
>   switch (x) {
>   case 0: return "zero";
>   case 1: return "one";
>   case 2: return "two";
>   case 3: return "three";
>   case 4: return "four";
>   case 5: return "five";
>   case 6: return "six";
>   case 7: return "seven";
>   case 8: return "eight";
>   case 9: return "nine";
>   default: exit(x/0);
>   }
> 
> The best that happens is that x is compared to 9, and if it is above,
> a branch takes place to a label, where the "ud2" instruction is executed.
> There is no division and no call to exit.
> 

You might think "0 / 0" would be a good case for undefined behaviour
(and therefore "can't happen" optimisations), but it's not really.  On
many targets, actually executing "0 / 0" will cause a specific exception
or trap behaviour.  And while the C standards say nothing about what
will happen here, and call it "undefined behaviour", target-specific
details and implementation-specific details may vary.  The same applies
to anything else undefined in the C standards, such as dereferencing a
null pointer.

In addition, compilers often try to be helpful.  If it appears that you
have accidentally tried to do something impossible at run-time,
executing an implementation-specific "trap" instruction is a good choice
- it gives the developer a better chance of finding the problem and
limiting the damage than happily launching nasal demons.  So gcc
generates "ud2" instructions sometimes for x86, and similar instructions
for other processors.  (You can get this intentionally with
"__builtin_trap()".)

So the best choice is a compiler-specific explicit "undefined behaviour"
indicator, since there is no standard feature here.  For gcc and
compatible compilers, that is (as you know), __builtin_unreachable().


> Basically, this "optimize based on defined behavior" business is the
> programmer's enemy. It will not do the obvious optimizations you want,
> but it will shoot you in the foot when you accidentally introduce some
> undefined behavior, or use some formally undefined "classic" idiom that
> has nevertheless worked on pretty much every compiler over forty yeras.
> 
> Now, GCC even has a way to explicitly assert "if we reach this point
> in the program, the behavior is undefined". Even that is not getting rid
> of the range test for me:
> 
> const char *fun(int x)
> {
>   switch (x) {
>   case 0: return "zero";
>   case 1: return "one";
>   case 2: return "two";
>   case 3: return "three";
>   case 4: return "four";
>   case 5: return "five";
>   case 6: return "six";
>   case 7: return "seven";
>   case 8: return "eight";
>   case 9: return "nine";
>   default: __builtin_unreachable();
>   }
> }
> 
> Worse, gcc (version 7.5.0 on Ubuntu 18) is not emitting the ud2
> instruction in this case, as it does for a null pointer dereference or
> division by zero. It just generates code that returns from the function.
> 
> Maybe there is some option you're supposed to use for this, but I can't
> find it.
> 

The trick is to use gcc 8 or newer :-)

Back to comp.lang.c | Previous | NextPrevious in thread | Next in thread | Find similar | Unroll thread


Thread

naked switches Robert Finch <robfi680@gmail.com> - 2021-07-07 16:39 -0700
  Re: naked switches Bart <bc@freeuk.com> - 2021-07-08 01:26 +0100
  Re: naked switches Kaz Kylheku <563-365-8930@kylheku.com> - 2021-07-08 01:57 +0000
    Re: naked switches David Brown <david.brown@hesbynett.no> - 2021-07-08 09:16 +0200
  Re: naked switches Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-07-08 01:00 -0700
    Re: naked switches Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-07-08 03:25 -0700
      Re: naked switches Robert Finch <robfi680@gmail.com> - 2021-07-08 06:58 -0700
        Re: naked switches Bart <bc@freeuk.com> - 2021-07-08 15:52 +0100
        Re: naked switches David Brown <david.brown@hesbynett.no> - 2021-07-08 17:52 +0200
          Re: naked switches Bart <bc@freeuk.com> - 2021-07-08 17:51 +0100
            Re: naked switches David Brown <david.brown@hesbynett.no> - 2021-07-09 10:01 +0200
              Re: naked switches Bart <bc@freeuk.com> - 2021-07-09 11:09 +0100
                Re: naked switches David Brown <david.brown@hesbynett.no> - 2021-07-09 13:14 +0200
                Re: naked switches Manfred <noname@add.invalid> - 2021-07-09 15:35 +0200
                Re: naked switches David Brown <david.brown@hesbynett.no> - 2021-07-09 16:51 +0200
                Re: naked switches Manfred <noname@add.invalid> - 2021-07-09 18:23 +0200
                Re: naked switches Bart <bc@freeuk.com> - 2021-07-09 16:07 +0100
                Re: naked switches Manfred <noname@add.invalid> - 2021-07-09 18:41 +0200
                Re: naked switches David Brown <david.brown@hesbynett.no> - 2021-07-10 11:02 +0200
                Re: naked switches David Brown <david.brown@hesbynett.no> - 2021-07-09 19:20 +0200
                Re: naked switches Robert Finch <robfi680@gmail.com> - 2021-07-09 10:46 -0700
                Re: naked switches Kaz Kylheku <563-365-8930@kylheku.com> - 2021-07-09 19:56 +0000
                Re: naked switches Bart <bc@freeuk.com> - 2021-07-09 22:01 +0100
                Re: naked switches Robert Finch <robfi680@gmail.com> - 2021-07-09 15:07 -0700
                Re: naked switches Bart <bc@freeuk.com> - 2021-07-09 23:30 +0100
                Re: naked switches David Brown <david.brown@hesbynett.no> - 2021-07-10 12:17 +0200
          Re: naked switches Robert Finch <robfi680@gmail.com> - 2021-07-08 10:18 -0700
            Re: naked switches Bart <bc@freeuk.com> - 2021-07-08 18:43 +0100
              Re: naked switches Robert Finch <robfi680@gmail.com> - 2021-07-08 15:32 -0700
            Re: naked switches Kaz Kylheku <563-365-8930@kylheku.com> - 2021-07-08 17:47 +0000
              Re: naked switches Robert Finch <robfi680@gmail.com> - 2021-07-08 15:45 -0700
                Re: naked switches David Brown <david.brown@hesbynett.no> - 2021-07-09 10:27 +0200
                Re: naked switches Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-07-09 11:13 +0100
                Re: naked switches David Brown <david.brown@hesbynett.no> - 2021-07-09 13:30 +0200
                Re: naked switches Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-07-11 00:39 -0700
                Re: naked switches scott@slp53.sl.home (Scott Lurndal) - 2021-07-11 14:06 +0000
                Re: naked switches Robert Finch <robfi680@gmail.com> - 2021-07-11 08:01 -0700
                Re: naked switches Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-07-16 03:53 -0700
                Re: naked switches scott@slp53.sl.home (Scott Lurndal) - 2021-07-16 14:47 +0000
                Re: naked switches Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-09-30 06:09 -0700
                Re: naked switches Robert Finch <robfi680@gmail.com> - 2021-09-30 07:03 -0700
                Re: naked switches Bart <bc@freeuk.com> - 2021-07-09 13:44 +0100
                Re: naked switches David Brown <david.brown@hesbynett.no> - 2021-07-10 13:28 +0200
                Re: naked switches Bart <bc@freeuk.com> - 2021-07-10 13:04 +0100
                Re: naked switches David Brown <david.brown@hesbynett.no> - 2021-07-10 15:39 +0200
                Re: naked switches Bart <bc@freeuk.com> - 2021-07-10 15:08 +0100
                Re: naked switches David Brown <david.brown@hesbynett.no> - 2021-07-10 17:34 +0200
                Re: naked switches Bart <bc@freeuk.com> - 2021-07-10 17:47 +0100
              Re: naked switches Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-07-11 00:57 -0700
                Re: naked switches Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-07-16 03:51 -0700
        Re: naked switches Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-07-08 11:40 -0700
          Re: naked switches David Brown <david.brown@hesbynett.no> - 2021-07-09 10:38 +0200
  Re: naked switches Kaz Kylheku <563-365-8930@kylheku.com> - 2021-07-08 17:33 +0000
    Re: naked switches scott@slp53.sl.home (Scott Lurndal) - 2021-07-08 17:47 +0000
      Re: naked switches Kaz Kylheku <563-365-8930@kylheku.com> - 2021-07-08 17:58 +0000
        Re: naked switches scott@slp53.sl.home (Scott Lurndal) - 2021-07-08 19:13 +0000
          Re: naked switches Kaz Kylheku <563-365-8930@kylheku.com> - 2021-07-09 02:30 +0000
        Re: naked switches David Brown <david.brown@hesbynett.no> - 2021-07-09 10:41 +0200
  Re: naked switches Bonita Montero <Bonita.Montero@gmail.com> - 2021-09-30 18:04 +0200

csiph-web