[libc++] Remove the old HTML documentation
This commit finishes moving the <atomic> design documents to the RST
documentation and removes the old documentation. https://libcxx.llvm.org
is already pointing to the new documentation only now, so the removal of
the old documentation is really a NFC.
I went over the old documentation and I don't think we're leaving anything
important behind - I think everything important was mentionned in the RST
documentation anyway.
diff --git a/libcxx/docs/DesignDocs/AtomicDesign.rst b/libcxx/docs/DesignDocs/AtomicDesign.rst
new file mode 100644
index 0000000..4b28ab2
--- /dev/null
+++ b/libcxx/docs/DesignDocs/AtomicDesign.rst
@@ -0,0 +1,797 @@
+
+====================
+``<atomic>`` Design
+====================
+
+There were originally 3 designs under consideration. They differ in where most
+of the implementation work is done. The functionality exposed to the customer
+should be identical (and conforming) for all three designs.
+
+
+Design A: Minimal work for the library
+======================================
+The compiler supplies all of the intrinsics as described below. This list of
+intrinsics roughly parallels the requirements of the C and C++ atomics proposals.
+The C and C++ library implementations simply drop through to these intrinsics.
+Anything the platform does not support in hardware, the compiler
+arranges for a (compiler-rt) library call to be made which will do the job with
+a mutex, and in this case ignoring the memory ordering parameter (effectively
+implementing ``memory_order_seq_cst``).
+
+Ultimate efficiency is preferred over run time error checking. Undefined
+behavior is acceptable when the inputs do not conform as defined below.
+
+.. code-block:: cpp
+
+ // In every intrinsic signature below, type* atomic_obj may be a pointer to a
+ // volatile-qualified type. Memory ordering values map to the following meanings:
+ // memory_order_relaxed == 0
+ // memory_order_consume == 1
+ // memory_order_acquire == 2
+ // memory_order_release == 3
+ // memory_order_acq_rel == 4
+ // memory_order_seq_cst == 5
+
+ // type must be trivially copyable
+ // type represents a "type argument"
+ bool __atomic_is_lock_free(type);
+
+ // type must be trivially copyable
+ // Behavior is defined for mem_ord = 0, 1, 2, 5
+ type __atomic_load(const type* atomic_obj, int mem_ord);
+
+ // type must be trivially copyable
+ // Behavior is defined for mem_ord = 0, 3, 5
+ void __atomic_store(type* atomic_obj, type desired, int mem_ord);
+
+ // type must be trivially copyable
+ // Behavior is defined for mem_ord = [0 ... 5]
+ type __atomic_exchange(type* atomic_obj, type desired, int mem_ord);
+
+ // type must be trivially copyable
+ // Behavior is defined for mem_success = [0 ... 5],
+ // mem_failure <= mem_success
+ // mem_failure != 3
+ // mem_failure != 4
+ bool __atomic_compare_exchange_strong(type* atomic_obj,
+ type* expected, type desired,
+ int mem_success, int mem_failure);
+
+ // type must be trivially copyable
+ // Behavior is defined for mem_success = [0 ... 5],
+ // mem_failure <= mem_success
+ // mem_failure != 3
+ // mem_failure != 4
+ bool __atomic_compare_exchange_weak(type* atomic_obj,
+ type* expected, type desired,
+ int mem_success, int mem_failure);
+
+ // type is one of: char, signed char, unsigned char, short, unsigned short, int,
+ // unsigned int, long, unsigned long, long long, unsigned long long,
+ // char16_t, char32_t, wchar_t
+ // Behavior is defined for mem_ord = [0 ... 5]
+ type __atomic_fetch_add(type* atomic_obj, type operand, int mem_ord);
+
+ // type is one of: char, signed char, unsigned char, short, unsigned short, int,
+ // unsigned int, long, unsigned long, long long, unsigned long long,
+ // char16_t, char32_t, wchar_t
+ // Behavior is defined for mem_ord = [0 ... 5]
+ type __atomic_fetch_sub(type* atomic_obj, type operand, int mem_ord);
+
+ // type is one of: char, signed char, unsigned char, short, unsigned short, int,
+ // unsigned int, long, unsigned long, long long, unsigned long long,
+ // char16_t, char32_t, wchar_t
+ // Behavior is defined for mem_ord = [0 ... 5]
+ type __atomic_fetch_and(type* atomic_obj, type operand, int mem_ord);
+
+ // type is one of: char, signed char, unsigned char, short, unsigned short, int,
+ // unsigned int, long, unsigned long, long long, unsigned long long,
+ // char16_t, char32_t, wchar_t
+ // Behavior is defined for mem_ord = [0 ... 5]
+ type __atomic_fetch_or(type* atomic_obj, type operand, int mem_ord);
+
+ // type is one of: char, signed char, unsigned char, short, unsigned short, int,
+ // unsigned int, long, unsigned long, long long, unsigned long long,
+ // char16_t, char32_t, wchar_t
+ // Behavior is defined for mem_ord = [0 ... 5]
+ type __atomic_fetch_xor(type* atomic_obj, type operand, int mem_ord);
+
+ // Behavior is defined for mem_ord = [0 ... 5]
+ void* __atomic_fetch_add(void** atomic_obj, ptrdiff_t operand, int mem_ord);
+ void* __atomic_fetch_sub(void** atomic_obj, ptrdiff_t operand, int mem_ord);
+
+ // Behavior is defined for mem_ord = [0 ... 5]
+ void __atomic_thread_fence(int mem_ord);
+ void __atomic_signal_fence(int mem_ord);
+
+If desired the intrinsics taking a single ``mem_ord`` parameter can default
+this argument to 5.
+
+If desired the intrinsics taking two ordering parameters can default ``mem_success``
+to 5, and ``mem_failure`` to ``translate_memory_order(mem_success)`` where
+``translate_memory_order(mem_success)`` is defined as:
+
+.. code-block:: cpp
+
+ int translate_memory_order(int o) {
+ switch (o) {
+ case 4:
+ return 2;
+ case 3:
+ return 0;
+ }
+ return o;
+ }
+
+Below are representative C++ implementations of all of the operations. Their
+purpose is to document the desired semantics of each operation, assuming
+``memory_order_seq_cst``. This is essentially the code that will be called
+if the front end calls out to compiler-rt.
+
+.. code-block:: cpp
+
+ template <class T>
+ T __atomic_load(T const volatile* obj) {
+ unique_lock<mutex> _(some_mutex);
+ return *obj;
+ }
+
+ template <class T>
+ void __atomic_store(T volatile* obj, T desr) {
+ unique_lock<mutex> _(some_mutex);
+ *obj = desr;
+ }
+
+ template <class T>
+ T __atomic_exchange(T volatile* obj, T desr) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj = desr;
+ return r;
+ }
+
+ template <class T>
+ bool __atomic_compare_exchange_strong(T volatile* obj, T* exp, T desr) {
+ unique_lock<mutex> _(some_mutex);
+ if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0) // if (*obj == *exp)
+ {
+ std::memcpy(const_cast<T*>(obj), &desr, sizeof(T)); // *obj = desr;
+ return true;
+ }
+ std::memcpy(exp, const_cast<T*>(obj), sizeof(T)); // *exp = *obj;
+ return false;
+ }
+
+ // May spuriously return false (even if *obj == *exp)
+ template <class T>
+ bool __atomic_compare_exchange_weak(T volatile* obj, T* exp, T desr) {
+ unique_lock<mutex> _(some_mutex);
+ if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0) // if (*obj == *exp)
+ {
+ std::memcpy(const_cast<T*>(obj), &desr, sizeof(T)); // *obj = desr;
+ return true;
+ }
+ std::memcpy(exp, const_cast<T*>(obj), sizeof(T)); // *exp = *obj;
+ return false;
+ }
+
+ template <class T>
+ T __atomic_fetch_add(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj += operand;
+ return r;
+ }
+
+ template <class T>
+ T __atomic_fetch_sub(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj -= operand;
+ return r;
+ }
+
+ template <class T>
+ T __atomic_fetch_and(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj &= operand;
+ return r;
+ }
+
+ template <class T>
+ T __atomic_fetch_or(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj |= operand;
+ return r;
+ }
+
+ template <class T>
+ T __atomic_fetch_xor(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj ^= operand;
+ return r;
+ }
+
+ void* __atomic_fetch_add(void* volatile* obj, ptrdiff_t operand) {
+ unique_lock<mutex> _(some_mutex);
+ void* r = *obj;
+ (char*&)(*obj) += operand;
+ return r;
+ }
+
+ void* __atomic_fetch_sub(void* volatile* obj, ptrdiff_t operand) {
+ unique_lock<mutex> _(some_mutex);
+ void* r = *obj;
+ (char*&)(*obj) -= operand;
+ return r;
+ }
+
+ void __atomic_thread_fence() {
+ unique_lock<mutex> _(some_mutex);
+ }
+
+ void __atomic_signal_fence() {
+ unique_lock<mutex> _(some_mutex);
+ }
+
+
+Design B: Something in between
+==============================
+This is a variation of design A which puts the burden on the library to arrange
+for the correct manipulation of the run time memory ordering arguments, and only
+calls the compiler for well-defined memory orderings. I think of this design as
+the worst of A and C, instead of the best of A and C. But I offer it as an
+option in the spirit of completeness.
+
+.. code-block:: cpp
+
+ // type must be trivially copyable
+ bool __atomic_is_lock_free(const type* atomic_obj);
+
+ // type must be trivially copyable
+ type __atomic_load_relaxed(const volatile type* atomic_obj);
+ type __atomic_load_consume(const volatile type* atomic_obj);
+ type __atomic_load_acquire(const volatile type* atomic_obj);
+ type __atomic_load_seq_cst(const volatile type* atomic_obj);
+
+ // type must be trivially copyable
+ type __atomic_store_relaxed(volatile type* atomic_obj, type desired);
+ type __atomic_store_release(volatile type* atomic_obj, type desired);
+ type __atomic_store_seq_cst(volatile type* atomic_obj, type desired);
+
+ // type must be trivially copyable
+ type __atomic_exchange_relaxed(volatile type* atomic_obj, type desired);
+ type __atomic_exchange_consume(volatile type* atomic_obj, type desired);
+ type __atomic_exchange_acquire(volatile type* atomic_obj, type desired);
+ type __atomic_exchange_release(volatile type* atomic_obj, type desired);
+ type __atomic_exchange_acq_rel(volatile type* atomic_obj, type desired);
+ type __atomic_exchange_seq_cst(volatile type* atomic_obj, type desired);
+
+ // type must be trivially copyable
+ bool __atomic_compare_exchange_strong_relaxed_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_strong_consume_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_strong_consume_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_strong_acquire_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_strong_acquire_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_strong_acquire_acquire(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_strong_release_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_strong_release_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_strong_release_acquire(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_strong_acq_rel_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_strong_acq_rel_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_strong_acq_rel_acquire(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_strong_seq_cst_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_strong_seq_cst_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_strong_seq_cst_acquire(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_strong_seq_cst_seq_cst(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+
+ // type must be trivially copyable
+ bool __atomic_compare_exchange_weak_relaxed_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_weak_consume_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_weak_consume_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_weak_acquire_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_weak_acquire_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_weak_acquire_acquire(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_weak_release_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_weak_release_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_weak_release_acquire(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_weak_acq_rel_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_weak_acq_rel_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_weak_acq_rel_acquire(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_weak_seq_cst_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_weak_seq_cst_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_weak_seq_cst_acquire(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+ bool __atomic_compare_exchange_weak_seq_cst_seq_cst(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+
+ // type is one of: char, signed char, unsigned char, short, unsigned short, int,
+ // unsigned int, long, unsigned long, long long, unsigned long long,
+ // char16_t, char32_t, wchar_t
+ type __atomic_fetch_add_relaxed(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_add_consume(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_add_acquire(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_add_release(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_add_acq_rel(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_add_seq_cst(volatile type* atomic_obj, type operand);
+
+ // type is one of: char, signed char, unsigned char, short, unsigned short, int,
+ // unsigned int, long, unsigned long, long long, unsigned long long,
+ // char16_t, char32_t, wchar_t
+ type __atomic_fetch_sub_relaxed(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_sub_consume(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_sub_acquire(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_sub_release(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_sub_acq_rel(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_sub_seq_cst(volatile type* atomic_obj, type operand);
+
+ // type is one of: char, signed char, unsigned char, short, unsigned short, int,
+ // unsigned int, long, unsigned long, long long, unsigned long long,
+ // char16_t, char32_t, wchar_t
+ type __atomic_fetch_and_relaxed(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_and_consume(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_and_acquire(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_and_release(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_and_acq_rel(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_and_seq_cst(volatile type* atomic_obj, type operand);
+
+ // type is one of: char, signed char, unsigned char, short, unsigned short, int,
+ // unsigned int, long, unsigned long, long long, unsigned long long,
+ // char16_t, char32_t, wchar_t
+ type __atomic_fetch_or_relaxed(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_or_consume(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_or_acquire(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_or_release(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_or_acq_rel(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_or_seq_cst(volatile type* atomic_obj, type operand);
+
+ // type is one of: char, signed char, unsigned char, short, unsigned short, int,
+ // unsigned int, long, unsigned long, long long, unsigned long long,
+ // char16_t, char32_t, wchar_t
+ type __atomic_fetch_xor_relaxed(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_xor_consume(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_xor_acquire(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_xor_release(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_xor_acq_rel(volatile type* atomic_obj, type operand);
+ type __atomic_fetch_xor_seq_cst(volatile type* atomic_obj, type operand);
+
+ void* __atomic_fetch_add_relaxed(void* volatile* atomic_obj, ptrdiff_t operand);
+ void* __atomic_fetch_add_consume(void* volatile* atomic_obj, ptrdiff_t operand);
+ void* __atomic_fetch_add_acquire(void* volatile* atomic_obj, ptrdiff_t operand);
+ void* __atomic_fetch_add_release(void* volatile* atomic_obj, ptrdiff_t operand);
+ void* __atomic_fetch_add_acq_rel(void* volatile* atomic_obj, ptrdiff_t operand);
+ void* __atomic_fetch_add_seq_cst(void* volatile* atomic_obj, ptrdiff_t operand);
+
+ void* __atomic_fetch_sub_relaxed(void* volatile* atomic_obj, ptrdiff_t operand);
+ void* __atomic_fetch_sub_consume(void* volatile* atomic_obj, ptrdiff_t operand);
+ void* __atomic_fetch_sub_acquire(void* volatile* atomic_obj, ptrdiff_t operand);
+ void* __atomic_fetch_sub_release(void* volatile* atomic_obj, ptrdiff_t operand);
+ void* __atomic_fetch_sub_acq_rel(void* volatile* atomic_obj, ptrdiff_t operand);
+ void* __atomic_fetch_sub_seq_cst(void* volatile* atomic_obj, ptrdiff_t operand);
+
+ void __atomic_thread_fence_relaxed();
+ void __atomic_thread_fence_consume();
+ void __atomic_thread_fence_acquire();
+ void __atomic_thread_fence_release();
+ void __atomic_thread_fence_acq_rel();
+ void __atomic_thread_fence_seq_cst();
+
+ void __atomic_signal_fence_relaxed();
+ void __atomic_signal_fence_consume();
+ void __atomic_signal_fence_acquire();
+ void __atomic_signal_fence_release();
+ void __atomic_signal_fence_acq_rel();
+ void __atomic_signal_fence_seq_cst();
+
+Design C: Minimal work for the front end
+========================================
+The ``<atomic>`` header is one of the most closely coupled headers to the compiler.
+Ideally when you invoke any function from ``<atomic>``, it should result in highly
+optimized assembly being inserted directly into your application -- assembly that
+is not otherwise representable by higher level C or C++ expressions. The design of
+the libc++ ``<atomic>`` header started with this goal in mind. A secondary, but
+still very important goal is that the compiler should have to do minimal work to
+facilitate the implementation of ``<atomic>``. Without this second goal, then
+practically speaking, the libc++ ``<atomic>`` header would be doomed to be a
+barely supported, second class citizen on almost every platform.
+
+Goals:
+
+- Optimal code generation for atomic operations
+- Minimal effort for the compiler to achieve goal 1 on any given platform
+- Conformance to the C++0X draft standard
+
+The purpose of this document is to inform compiler writers what they need to do
+to enable a high performance libc++ ``<atomic>`` with minimal effort.
+
+The minimal work that must be done for a conforming ``<atomic>``
+----------------------------------------------------------------
+The only "atomic" operations that must actually be lock free in
+``<atomic>`` are represented by the following compiler intrinsics:
+
+.. code-block:: cpp
+
+ __atomic_flag__ __atomic_exchange_seq_cst(__atomic_flag__ volatile* obj, __atomic_flag__ desr) {
+ unique_lock<mutex> _(some_mutex);
+ __atomic_flag__ result = *obj;
+ *obj = desr;
+ return result;
+ }
+
+ void __atomic_store_seq_cst(__atomic_flag__ volatile* obj, __atomic_flag__ desr) {
+ unique_lock<mutex> _(some_mutex);
+ *obj = desr;
+ }
+
+Where:
+
+- If ``__has_feature(__atomic_flag)`` evaluates to 1 in the preprocessor then
+ the compiler must define ``__atomic_flag__`` (e.g. as a typedef to ``int``).
+- If ``__has_feature(__atomic_flag)`` evaluates to 0 in the preprocessor then
+ the library defines ``__atomic_flag__`` as a typedef to ``bool``.
+- To communicate that the above intrinsics are available, the compiler must
+ arrange for ``__has_feature`` to return 1 when fed the intrinsic name
+ appended with an '_' and the mangled type name of ``__atomic_flag__``.
+
+For example if ``__atomic_flag__`` is ``unsigned int``:
+
+.. code-block:: cpp
+
+ // __has_feature(__atomic_flag) == 1
+ // __has_feature(__atomic_exchange_seq_cst_j) == 1
+ // __has_feature(__atomic_store_seq_cst_j) == 1
+
+ typedef unsigned int __atomic_flag__;
+
+ unsigned int __atomic_exchange_seq_cst(unsigned int volatile*, unsigned int) {
+ // ...
+ }
+
+ void __atomic_store_seq_cst(unsigned int volatile*, unsigned int) {
+ // ...
+ }
+
+That's it! Compiler writers do the above and you've got a fully conforming
+(though sub-par performance) ``<atomic>`` header!
+
+
+Recommended work for a higher performance ``<atomic>``
+------------------------------------------------------
+It would be good if the above intrinsics worked with all integral types plus
+``void*``. Because this may not be possible to do in a lock-free manner for
+all integral types on all platforms, a compiler must communicate each type that
+an intrinsic works with. For example, if ``__atomic_exchange_seq_cst`` works
+for all types except for ``long long`` and ``unsigned long long`` then:
+
+.. code-block:: cpp
+
+ __has_feature(__atomic_exchange_seq_cst_b) == 1 // bool
+ __has_feature(__atomic_exchange_seq_cst_c) == 1 // char
+ __has_feature(__atomic_exchange_seq_cst_a) == 1 // signed char
+ __has_feature(__atomic_exchange_seq_cst_h) == 1 // unsigned char
+ __has_feature(__atomic_exchange_seq_cst_Ds) == 1 // char16_t
+ __has_feature(__atomic_exchange_seq_cst_Di) == 1 // char32_t
+ __has_feature(__atomic_exchange_seq_cst_w) == 1 // wchar_t
+ __has_feature(__atomic_exchange_seq_cst_s) == 1 // short
+ __has_feature(__atomic_exchange_seq_cst_t) == 1 // unsigned short
+ __has_feature(__atomic_exchange_seq_cst_i) == 1 // int
+ __has_feature(__atomic_exchange_seq_cst_j) == 1 // unsigned int
+ __has_feature(__atomic_exchange_seq_cst_l) == 1 // long
+ __has_feature(__atomic_exchange_seq_cst_m) == 1 // unsigned long
+ __has_feature(__atomic_exchange_seq_cst_Pv) == 1 // void*
+
+Note that only the ``__has_feature`` flag is decorated with the argument
+type. The name of the compiler intrinsic is not decorated, but instead works
+like a C++ overloaded function.
+
+Additionally, there are other intrinsics besides ``__atomic_exchange_seq_cst``
+and ``__atomic_store_seq_cst``. They are optional. But if the compiler can
+generate faster code than provided by the library, then clients will benefit
+from the compiler writer's expertise and knowledge of the targeted platform.
+
+Below is the complete list of *sequentially consistent* intrinsics, and
+their library implementations. Template syntax is used to indicate the desired
+overloading for integral and ``void*`` types. The template does not represent a
+requirement that the intrinsic operate on **any** type!
+
+.. code-block:: cpp
+
+ // T is one of:
+ // bool, char, signed char, unsigned char, short, unsigned short,
+ // int, unsigned int, long, unsigned long,
+ // long long, unsigned long long, char16_t, char32_t, wchar_t, void*
+
+ template <class T>
+ T __atomic_load_seq_cst(T const volatile* obj) {
+ unique_lock<mutex> _(some_mutex);
+ return *obj;
+ }
+
+ template <class T>
+ void __atomic_store_seq_cst(T volatile* obj, T desr) {
+ unique_lock<mutex> _(some_mutex);
+ *obj = desr;
+ }
+
+ template <class T>
+ T __atomic_exchange_seq_cst(T volatile* obj, T desr) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj = desr;
+ return r;
+ }
+
+ template <class T>
+ bool __atomic_compare_exchange_strong_seq_cst_seq_cst(T volatile* obj, T* exp, T desr) {
+ unique_lock<mutex> _(some_mutex);
+ if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0) {
+ std::memcpy(const_cast<T*>(obj), &desr, sizeof(T));
+ return true;
+ }
+ std::memcpy(exp, const_cast<T*>(obj), sizeof(T));
+ return false;
+ }
+
+ template <class T>
+ bool __atomic_compare_exchange_weak_seq_cst_seq_cst(T volatile* obj, T* exp, T desr) {
+ unique_lock<mutex> _(some_mutex);
+ if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0)
+ {
+ std::memcpy(const_cast<T*>(obj), &desr, sizeof(T));
+ return true;
+ }
+ std::memcpy(exp, const_cast<T*>(obj), sizeof(T));
+ return false;
+ }
+
+ // T is one of:
+ // char, signed char, unsigned char, short, unsigned short,
+ // int, unsigned int, long, unsigned long,
+ // long long, unsigned long long, char16_t, char32_t, wchar_t
+
+ template <class T>
+ T __atomic_fetch_add_seq_cst(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj += operand;
+ return r;
+ }
+
+ template <class T>
+ T __atomic_fetch_sub_seq_cst(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj -= operand;
+ return r;
+ }
+
+ template <class T>
+ T __atomic_fetch_and_seq_cst(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj &= operand;
+ return r;
+ }
+
+ template <class T>
+ T __atomic_fetch_or_seq_cst(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj |= operand;
+ return r;
+ }
+
+ template <class T>
+ T __atomic_fetch_xor_seq_cst(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj ^= operand;
+ return r;
+ }
+
+ void* __atomic_fetch_add_seq_cst(void* volatile* obj, ptrdiff_t operand) {
+ unique_lock<mutex> _(some_mutex);
+ void* r = *obj;
+ (char*&)(*obj) += operand;
+ return r;
+ }
+
+ void* __atomic_fetch_sub_seq_cst(void* volatile* obj, ptrdiff_t operand) {
+ unique_lock<mutex> _(some_mutex);
+ void* r = *obj;
+ (char*&)(*obj) -= operand;
+ return r;
+ }
+
+ void __atomic_thread_fence_seq_cst() {
+ unique_lock<mutex> _(some_mutex);
+ }
+
+ void __atomic_signal_fence_seq_cst() {
+ unique_lock<mutex> _(some_mutex);
+ }
+
+One should consult the (currently draft) `C++ Standard <https://wg21.link/n3126>`_
+for the details of the definitions for these operations. For example,
+``__atomic_compare_exchange_weak_seq_cst_seq_cst`` is allowed to fail
+spuriously while ``__atomic_compare_exchange_strong_seq_cst_seq_cst`` is not.
+
+If on your platform the lock-free definition of ``__atomic_compare_exchange_weak_seq_cst_seq_cst``
+would be the same as ``__atomic_compare_exchange_strong_seq_cst_seq_cst``, you may omit the
+``__atomic_compare_exchange_weak_seq_cst_seq_cst`` intrinsic without a performance cost. The
+library will prefer your implementation of ``__atomic_compare_exchange_strong_seq_cst_seq_cst``
+over its own definition for implementing ``__atomic_compare_exchange_weak_seq_cst_seq_cst``.
+That is, the library will arrange for ``__atomic_compare_exchange_weak_seq_cst_seq_cst`` to call
+``__atomic_compare_exchange_strong_seq_cst_seq_cst`` if you supply an intrinsic for the strong
+version but not the weak.
+
+Taking advantage of weaker memory synchronization
+-------------------------------------------------
+So far, all of the intrinsics presented require a **sequentially consistent** memory ordering.
+That is, no loads or stores can move across the operation (just as if the library had locked
+that internal mutex). But ``<atomic>`` supports weaker memory ordering operations. In all,
+there are six memory orderings (listed here from strongest to weakest):
+
+.. code-block:: cpp
+
+ memory_order_seq_cst
+ memory_order_acq_rel
+ memory_order_release
+ memory_order_acquire
+ memory_order_consume
+ memory_order_relaxed
+
+(See the `C++ Standard <https://wg21.link/n3126>`_ for the detailed definitions of each of these orderings).
+
+On some platforms, the compiler vendor can offer some or even all of the above
+intrinsics at one or more weaker levels of memory synchronization. This might
+lead for example to not issuing an ``mfence`` instruction on the x86.
+
+If the compiler does not offer any given operation, at any given memory ordering
+level, the library will automatically attempt to call the next highest memory
+ordering operation. This continues up to ``seq_cst``, and if that doesn't
+exist, then the library takes over and does the job with a ``mutex``. This
+is a compile-time search and selection operation. At run time, the application
+will only see the few inlined assembly instructions for the selected intrinsic.
+
+Each intrinsic is appended with the 7-letter name of the memory ordering it
+addresses. For example a ``load`` with ``relaxed`` ordering is defined by:
+
+.. code-block:: cpp
+
+ T __atomic_load_relaxed(const volatile T* obj);
+
+And announced with:
+
+.. code-block:: cpp
+
+ __has_feature(__atomic_load_relaxed_b) == 1 // bool
+ __has_feature(__atomic_load_relaxed_c) == 1 // char
+ __has_feature(__atomic_load_relaxed_a) == 1 // signed char
+ ...
+
+The ``__atomic_compare_exchange_strong(weak)`` intrinsics are parameterized
+on two memory orderings. The first ordering applies when the operation returns
+``true`` and the second ordering applies when the operation returns ``false``.
+
+Not every memory ordering is appropriate for every operation. ``exchange``
+and the ``fetch_XXX`` operations support all 6. But ``load`` only supports
+``relaxed``, ``consume``, ``acquire`` and ``seq_cst``. ``store`` only supports
+``relaxed``, ``release``, and ``seq_cst``. The ``compare_exchange`` operations
+support the following 16 combinations out of the possible 36:
+
+.. code-block:: cpp
+
+ relaxed_relaxed
+ consume_relaxed
+ consume_consume
+ acquire_relaxed
+ acquire_consume
+ acquire_acquire
+ release_relaxed
+ release_consume
+ release_acquire
+ acq_rel_relaxed
+ acq_rel_consume
+ acq_rel_acquire
+ seq_cst_relaxed
+ seq_cst_consume
+ seq_cst_acquire
+ seq_cst_seq_cst
+
+Again, the compiler supplies intrinsics only for the strongest orderings where
+it can make a difference. The library takes care of calling the weakest
+supplied intrinsic that is as strong or stronger than the customer asked for.
+
+Note about ABI
+==============
+With any design, the (back end) compiler writer should note that the decision to
+implement lock-free operations on any given type (or not) is an ABI-binding decision.
+One can not change from treating a type as not lock free, to lock free (or vice-versa)
+without breaking your ABI.
+
+For example:
+
+**TU1.cpp**:
+
+.. code-block:: cpp
+
+ extern atomic<long long> A;
+ int foo() { return A.compare_exchange_strong(w, x); }
+
+
+**TU2.cpp**:
+
+.. code-block:: cpp
+
+ extern atomic<long long> A;
+ void bar() { return A.compare_exchange_strong(y, z); }
+
+If only **one** of these calls to ``compare_exchange_strong`` is implemented with
+mutex-locked code, then that mutex-locked code will not be executed mutually
+exclusively of the one implemented in a lock-free manner.