News for hackers. Stuff that matters.
Re:Three new utility functions in C++23 by apaprocki on Wednesday November 09, 2022 @08:01AM (#33530952)
One thing people are missing is that you may need to use this to satisfy conditions that the compiler might encounter to emit a warning (or error if equivalent of -Werror is enabled). If you have strict warnings on, but no way to tell the compiler that a location should not be reachable, you wind up in situations where you are doing something like `assert(!"not reached!")` and it won't be enabled in all build types. This is similar to how `__attribute__((noreturn))` is used in a "fatal" function that isn't always enabled but needs to convey its intention to static analyzers so that they stop evaluating branches past that call.
Re:Three new utility functions in C++23 by gpderetta on Wednesday November 09, 2022 @08:55AM (#33531612)
For that abort() is just fine. Being UB, unreachable is more about optimizations .
Re:Three new utility functions in C++23 by dahfizz on Wednesday November 09, 2022 @09:10AM (#33531814)
>> and it won't be enabled in all build types.

The typical usecase would to wrap this in a #define, so that it aborts on a debug build but you get faster code in a production build.

Re:Three new utility functions in C++23 by apaprocki on Wednesday November 09, 2022 @10:41AM (#33533152)
The literal example in the Clang documentation is not about optimization:

> For example, without the __builtin_unreachable in the example below, the compiler assumes that the inline asm can fall through and prints a “function declared ‘noreturn’ should not return” warning.

    void myabort(void) __attribute__((noreturn));
    void myabort(void) {
      asm("int3");
      __builtin_unreachable();
    }
Re:Three new utility functions in C++23 by gpderetta on Wednesday November 09, 2022 @10:46AM (#33533262)
Right elsethread I said that it is both about optimizations and static analysis. That's a static analysis case.
Re:Three new utility functions in C++23 by apaprocki on Wednesday November 09, 2022 @11:11AM (#33533659)
It seems like optimization cases where this makes sense are generally of the sort where `noreturn` can't be used because it is conditional. That makes sense to me (although, could this have covered most use cases by making `noreturn` support being passed the name of a function argument?).

One example was interesting, though. I could see someone believing these might produce the same optimized assembly (-O2):

  void a(int& x, int& y) {
    if (&x == &y) __builtin_unreachable();
    x ^= y; y ^= x; x ^= y;
  }
  
  void b(int& __restrict x, int& __restrict y) {
    x ^= y; y ^= x; x ^= y;
  }
However, it produces:

  a(int&, int&):                               # @a(int&, int&)
        mov     eax, dword ptr [rdi]
        xor     eax, dword ptr [rsi]
        mov     dword ptr [rdi], eax
        xor     eax, dword ptr [rsi]
        mov     dword ptr [rsi], eax
        xor     dword ptr [rdi], eax
        ret
  b(int&, int&):                               # @b(int&, int&)
        mov     eax, dword ptr [rsi]
        mov     ecx, dword ptr [rdi]
        mov     dword ptr [rsi], ecx
        mov     dword ptr [rdi], eax
        ret
Is this something compiler contributors would optimize once they know about it? Similar question probably exists with using `__builtin_unreachable` if values aren't aligned versus `__builtin_assume_aligned`.

I'd love to see these things illustrated with more real-world examples.

Re:Three new utility functions in C++23 by CJefferson on Wednesday November 09, 2022 @02:24PM (#33536580)
Technically these would still produce different results if y started two bytes after x -- I can't remember if that is itself legal however!
Re:Three new utility functions in C++23 by gpderetta on Wednesday November 09, 2022 @03:45PM (#33537580)
No that wouldn't be legal. Distinct objects can't partially overlap, unless one is a subject of the other.
Re:Three new utility functions in C++23 by gpderetta on Wednesday November 09, 2022 @03:48PM (#33537609)
Attempting to emulate restricted with __builtin_unreachable has been one of the first thing I tried when I learned about unreachable. I periodically try again, but generally I have been underwhelmed with trying to give gcc value range informations with it.
Re:Three new utility functions in C++23 by a1369209993 on Wednesday November 09, 2022 @08:33PM (#33540987)
> the compiler assumes that the inline asm can fall through and prints a "function declared 'noreturn' should not return" warning.

It actually can (Hint: what happens if the operating system `iret`s from its int 3 handler?), although it's probably not a issue in practice. Regardless, you don't need __builtin_unreachable to write:

  void myabort(void) __attribute__((noreturn));
  void myabort(void) {
    asm("int3");
    myabort(); // might need `return myabort();` to force TCO,
    // but gcc doesn't like that and it should work anyway
    }
  # Assuming tail-call optimization etcetera, this produces:
  myabort:
    int3
    jmp myabort
which is a correct implementation.

However, if you're implementing built-in/standard functions like abort, you presumably know what compiler you're using and don't need a std interface in the first place. There's zero legitimate reason to use a undefined-behaviour-based `unreachable` in application code.