Add __c11_atomic_fetch_nand builtin to language extensions and support __atomic_fetch_nand libcall in compiler-rt.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Looks good to me, thanks!
I missed the clang patches, but it looks as if they didn't update clang's LanguageExtensions.html to document the new builtins - please can you add them?
I missed the clang patches, but it looks as if they didn't update clang's LanguageExtensions.html to document the new builtins - please can you add them?
Looks __atomic_fetch_nand is a GNU compatible builtin and it has been mentioned roughly since https://reviews.llvm.org/D10847#C226804NL1718. Do we have to document these GNU compatible __atomic_* builtins in another section?
Ah, it looks as if you didn't add the __c11_ variant of the builtin? Please can you add this?
The GCC builtins paint the ABI into a corner. They accept non-_Atomic-qualified types (the C11 spec guarantees only that these operations work on _Atomic types). The goal of the original C++ specification was to allow implementations to use atomic operations for register-sized chunks and fall back to an implementation with an inline lock for larger types, so std::atomic<T> would either have a single field of T or a std::atomic_flag field and a T field, depending on the size of T. The goal of the C11 import was to allow _Atomic(T) to be ABI-compatible with std::atomic<T>. Implementing this requires that _Atomic(T) be allowed to have a different representation to T. GCC messed this up and defined builtins that took a T*, not an _Atomic(T*), which forced all GCC-compatible ABIs to have the same representation for T and _Atomic(T). This, in turn, meant that the atomics support library couldn't use inline locks, and had to maintain a pool of locks to use for different types. This, in turn, means that _Atomic(T) silently fails in surprising ways in shared memory, some of the time, depending on the target CPU. This is a horrible mess and I would like to ensure that we always provide builtins that allow target ABIs to do the right thing, even if Linux and *BSD are trapped in a broken ABI by GCC and legacy compatibility.
Add __c11_atomic_fetch_nand in clang; Use __c11_atomic_fetch_nand to implement lock-free __atomic_fetch_nand libcall; Updated LanguageExtensions.rst.
The GCC builtins paint the ABI into a corner. They accept non-_Atomic-qualified types (the C11 spec guarantees only that these operations work on _Atomic types). The goal of the original C++ specification was to allow implementations to use atomic operations for register-sized chunks and fall back to an implementation with an inline lock for larger types, so std::atomic<T> would either have a single field of T or a std::atomic_flag field and a T field, depending on the size of T. The goal of the C11 import was to allow _Atomic(T) to be ABI-compatible with std::atomic<T>. Implementing this requires that _Atomic(T) be allowed to have a different representation to T. GCC messed this up and defined builtins that took a T*, not an _Atomic(T*), which forced all GCC-compatible ABIs to have the same representation for T and _Atomic(T). This, in turn, meant that the atomics support library couldn't use inline locks, and had to maintain a pool of locks to use for different types. This, in turn, means that _Atomic(T) silently fails in surprising ways in shared memory, some of the time, depending on the target CPU. This is a horrible mess and I would like to ensure that we always provide builtins that allow target ABIs to do the right thing, even if Linux and *BSD are trapped in a broken ABI by GCC and legacy compatibility.
Good to know, thanks for your detailed explanation!
compiler-rt/lib/builtins/atomic.c | ||
---|---|---|
339 | Same as ATOMIC_RMW now, isn't it? |
compiler-rt/lib/builtins/atomic.c | ||
---|---|---|
339 | Not totally. The ATOMIC_RMW macro also accept binary op sign as its argument, i.e., in the form a op b. However, nand is ~(a & b). |
Same as ATOMIC_RMW now, isn't it?