[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.
This commit is contained in:
Louis Dionne 2021-06-08 11:15:27 -04:00
parent f60ea691a9
commit 491d045957
15 changed files with 805 additions and 1980 deletions

View File

@ -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.

View File

@ -165,17 +165,18 @@ Design Documents
.. toctree::
:maxdepth: 1
DesignDocs/DebugMode
DesignDocs/CapturingConfigInfo
DesignDocs/ABIVersioning
DesignDocs/AtomicDesign
DesignDocs/CapturingConfigInfo
DesignDocs/DebugMode
DesignDocs/ExperimentalFeatures
DesignDocs/VisibilityMacros
DesignDocs/ThreadingSupportAPI
DesignDocs/FileTimeType
DesignDocs/FeatureTestMacros
DesignDocs/ExtendedCXX03Support
DesignDocs/UniquePtrTrivialAbi
DesignDocs/FeatureTestMacros
DesignDocs/FileTimeType
DesignDocs/NoexceptPolicy
DesignDocs/ThreadingSupportAPI
DesignDocs/UniquePtrTrivialAbi
DesignDocs/VisibilityMacros
* `<atomic> design <http://libcxx.llvm.org/atomic_design.html>`_
* `<type_traits> design <http://libcxx.llvm.org/type_traits_design.html>`_

View File

@ -1,91 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>&lt;atomic&gt; design</title>
<link type="text/css" rel="stylesheet" href="menu.css">
<link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
<div id="menu">
<div>
<a href="https://llvm.org/">LLVM Home</a>
</div>
<div class="submenu">
<label>libc++ Info</label>
<a href="/index.html">About</a>
</div>
<div class="submenu">
<label>Quick Links</label>
<a href="https://lists.llvm.org/mailman/listinfo/cfe-dev">cfe-dev</a>
<a href="https://lists.llvm.org/mailman/listinfo/cfe-commits">cfe-commits</a>
<a href="https://bugs.llvm.org/">Bug Reports</a>
<a href="https://github.com/llvm/llvm-project/tree/main/libcxx/">Browse Sources</a>
</div>
</div>
<div id="content">
<!--*********************************************************************-->
<h1>&lt;atomic&gt; design</h1>
<!--*********************************************************************-->
<p>
There are currently 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.
</p>
<ol type="A">
<li>
<a href="atomic_design_a.html">Minimal work for the library</a>
</li>
<li>
<a href="atomic_design_b.html">Something in between</a>
</li>
<li>
<a href="atomic_design_c.html">Minimal work for the front end</a>
</li>
</ol>
<p>
With any design, the (back end) compiler writer should note:
</p>
<blockquote>
<p>
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.
</p>
<p>
Example:
</p>
<blockquote><pre>
TU1.cc
-----------
extern atomic&lt;long long&gt; A;
int foo() { return A.compare_exchange_strong(w, x); }
TU2.cc
-----------
extern atomic&lt;long long&gt; A;
void bar() { return A.compare_exchange_strong(y, z); }
</pre></blockquote>
</blockquote>
<p>
If only <em>one</em> of these calls to <tt>compare_exchange_strong</tt> 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.
</p>
</div>
</body>
</html>

View File

@ -1,308 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>&lt;atomic&gt; design</title>
<link type="text/css" rel="stylesheet" href="menu.css">
<link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
<div id="menu">
<div>
<a href="https://llvm.org/">LLVM Home</a>
</div>
<div class="submenu">
<label>libc++ Info</label>
<a href="/index.html">About</a>
</div>
<div class="submenu">
<label>Quick Links</label>
<a href="https://lists.llvm.org/mailman/listinfo/cfe-dev">cfe-dev</a>
<a href="https://lists.llvm.org/mailman/listinfo/cfe-commits">cfe-commits</a>
<a href="https://bugs.llvm.org/">Bug Reports</a>
<a href="https://github.com/llvm/llvm-project/tree/main/libcxx/">Browse Sources</a>
</div>
</div>
<div id="content">
<!--*********************************************************************-->
<h1>&lt;atomic&gt; design</h1>
<!--*********************************************************************-->
<p>
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 <tt>memory_order_seq_cst</tt>).
</p>
<p>
Ultimate efficiency is preferred over run time error checking. Undefined
behavior is acceptable when the inputs do not conform as defined below.
</p>
<blockquote><pre>
<font color="#C80000">// In every intrinsic signature below, type* atomic_obj may be a pointer to a</font>
<font color="#C80000">// volatile-qualified type.</font>
<font color="#C80000">// Memory ordering values map to the following meanings:</font>
<font color="#C80000">// memory_order_relaxed == 0</font>
<font color="#C80000">// memory_order_consume == 1</font>
<font color="#C80000">// memory_order_acquire == 2</font>
<font color="#C80000">// memory_order_release == 3</font>
<font color="#C80000">// memory_order_acq_rel == 4</font>
<font color="#C80000">// memory_order_seq_cst == 5</font>
<font color="#C80000">// type must be trivially copyable</font>
<font color="#C80000">// type represents a "type argument"</font>
bool __atomic_is_lock_free(type);
<font color="#C80000">// type must be trivially copyable</font>
<font color="#C80000">// Behavior is defined for mem_ord = 0, 1, 2, 5</font>
type __atomic_load(const type* atomic_obj, int mem_ord);
<font color="#C80000">// type must be trivially copyable</font>
<font color="#C80000">// Behavior is defined for mem_ord = 0, 3, 5</font>
void __atomic_store(type* atomic_obj, type desired, int mem_ord);
<font color="#C80000">// type must be trivially copyable</font>
<font color="#C80000">// Behavior is defined for mem_ord = [0 ... 5]</font>
type __atomic_exchange(type* atomic_obj, type desired, int mem_ord);
<font color="#C80000">// type must be trivially copyable</font>
<font color="#C80000">// Behavior is defined for mem_success = [0 ... 5],</font>
<font color="#C80000">// mem_failure &lt;= mem_success</font>
<font color="#C80000">// mem_failure != 3</font>
<font color="#C80000">// mem_failure != 4</font>
bool __atomic_compare_exchange_strong(type* atomic_obj,
type* expected, type desired,
int mem_success, int mem_failure);
<font color="#C80000">// type must be trivially copyable</font>
<font color="#C80000">// Behavior is defined for mem_success = [0 ... 5],</font>
<font color="#C80000">// mem_failure &lt;= mem_success</font>
<font color="#C80000">// mem_failure != 3</font>
<font color="#C80000">// mem_failure != 4</font>
bool __atomic_compare_exchange_weak(type* atomic_obj,
type* expected, type desired,
int mem_success, int mem_failure);
<font color="#C80000">// type is one of: char, signed char, unsigned char, short, unsigned short, int,</font>
<font color="#C80000">// unsigned int, long, unsigned long, long long, unsigned long long,</font>
<font color="#C80000">// char16_t, char32_t, wchar_t</font>
<font color="#C80000">// Behavior is defined for mem_ord = [0 ... 5]</font>
type __atomic_fetch_add(type* atomic_obj, type operand, int mem_ord);
<font color="#C80000">// type is one of: char, signed char, unsigned char, short, unsigned short, int,</font>
<font color="#C80000">// unsigned int, long, unsigned long, long long, unsigned long long,</font>
<font color="#C80000">// char16_t, char32_t, wchar_t</font>
<font color="#C80000">// Behavior is defined for mem_ord = [0 ... 5]</font>
type __atomic_fetch_sub(type* atomic_obj, type operand, int mem_ord);
<font color="#C80000">// type is one of: char, signed char, unsigned char, short, unsigned short, int,</font>
<font color="#C80000">// unsigned int, long, unsigned long, long long, unsigned long long,</font>
<font color="#C80000">// char16_t, char32_t, wchar_t</font>
<font color="#C80000">// Behavior is defined for mem_ord = [0 ... 5]</font>
type __atomic_fetch_and(type* atomic_obj, type operand, int mem_ord);
<font color="#C80000">// type is one of: char, signed char, unsigned char, short, unsigned short, int,</font>
<font color="#C80000">// unsigned int, long, unsigned long, long long, unsigned long long,</font>
<font color="#C80000">// char16_t, char32_t, wchar_t</font>
<font color="#C80000">// Behavior is defined for mem_ord = [0 ... 5]</font>
type __atomic_fetch_or(type* atomic_obj, type operand, int mem_ord);
<font color="#C80000">// type is one of: char, signed char, unsigned char, short, unsigned short, int,</font>
<font color="#C80000">// unsigned int, long, unsigned long, long long, unsigned long long,</font>
<font color="#C80000">// char16_t, char32_t, wchar_t</font>
<font color="#C80000">// Behavior is defined for mem_ord = [0 ... 5]</font>
type __atomic_fetch_xor(type* atomic_obj, type operand, int mem_ord);
<font color="#C80000">// Behavior is defined for mem_ord = [0 ... 5]</font>
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);
<font color="#C80000">// Behavior is defined for mem_ord = [0 ... 5]</font>
void __atomic_thread_fence(int mem_ord);
void __atomic_signal_fence(int mem_ord);
</pre></blockquote>
<p>
If desired the intrinsics taking a single <tt>mem_ord</tt> parameter can default
this argument to 5.
</p>
<p>
If desired the intrinsics taking two ordering parameters can default
<tt>mem_success</tt> to 5, and <tt>mem_failure</tt> to
<tt>translate_memory_order(mem_success)</tt> where
<tt>translate_memory_order(mem_success)</tt> is defined as:
</p>
<blockquote><pre>
int
translate_memory_order(int o)
{
switch (o)
{
case 4:
return 2;
case 3:
return 0;
}
return o;
}
</pre></blockquote>
<p>
Below are representative C++ implementations of all of the operations. Their
purpose is to document the desired semantics of each operation, assuming
<tt>memory_order_seq_cst</tt>. This is essentially the code that will be called
if the front end calls out to compiler-rt.
</p>
<blockquote><pre>
template &lt;class T&gt;
T
__atomic_load(T const volatile* obj)
{
unique_lock&lt;mutex&gt; _(some_mutex);
return *obj;
}
template &lt;class T&gt;
void
__atomic_store(T volatile* obj, T desr)
{
unique_lock&lt;mutex&gt; _(some_mutex);
*obj = desr;
}
template &lt;class T&gt;
T
__atomic_exchange(T volatile* obj, T desr)
{
unique_lock&lt;mutex&gt; _(some_mutex);
T r = *obj;
*obj = desr;
return r;
}
template &lt;class T&gt;
bool
__atomic_compare_exchange_strong(T volatile* obj, T* exp, T desr)
{
unique_lock&lt;mutex&gt; _(some_mutex);
if (std::memcmp(const_cast&lt;T*&gt;(obj), exp, sizeof(T)) == 0) <font color="#C80000">// if (*obj == *exp)</font>
{
std::memcpy(const_cast&lt;T*&gt;(obj), &amp;desr, sizeof(T)); <font color="#C80000">// *obj = desr;</font>
return true;
}
std::memcpy(exp, const_cast&lt;T*&gt;(obj), sizeof(T)); <font color="#C80000">// *exp = *obj;</font>
return false;
}
<font color="#C80000">// May spuriously return false (even if *obj == *exp)</font>
template &lt;class T&gt;
bool
__atomic_compare_exchange_weak(T volatile* obj, T* exp, T desr)
{
unique_lock&lt;mutex&gt; _(some_mutex);
if (std::memcmp(const_cast&lt;T*&gt;(obj), exp, sizeof(T)) == 0) <font color="#C80000">// if (*obj == *exp)</font>
{
std::memcpy(const_cast&lt;T*&gt;(obj), &amp;desr, sizeof(T)); <font color="#C80000">// *obj = desr;</font>
return true;
}
std::memcpy(exp, const_cast&lt;T*&gt;(obj), sizeof(T)); <font color="#C80000">// *exp = *obj;</font>
return false;
}
template &lt;class T&gt;
T
__atomic_fetch_add(T volatile* obj, T operand)
{
unique_lock&lt;mutex&gt; _(some_mutex);
T r = *obj;
*obj += operand;
return r;
}
template &lt;class T&gt;
T
__atomic_fetch_sub(T volatile* obj, T operand)
{
unique_lock&lt;mutex&gt; _(some_mutex);
T r = *obj;
*obj -= operand;
return r;
}
template &lt;class T&gt;
T
__atomic_fetch_and(T volatile* obj, T operand)
{
unique_lock&lt;mutex&gt; _(some_mutex);
T r = *obj;
*obj &amp;= operand;
return r;
}
template &lt;class T&gt;
T
__atomic_fetch_or(T volatile* obj, T operand)
{
unique_lock&lt;mutex&gt; _(some_mutex);
T r = *obj;
*obj |= operand;
return r;
}
template &lt;class T&gt;
T
__atomic_fetch_xor(T volatile* obj, T operand)
{
unique_lock&lt;mutex&gt; _(some_mutex);
T r = *obj;
*obj ^= operand;
return r;
}
void*
__atomic_fetch_add(void* volatile* obj, ptrdiff_t operand)
{
unique_lock&lt;mutex&gt; _(some_mutex);
void* r = *obj;
(char*&amp;)(*obj) += operand;
return r;
}
void*
__atomic_fetch_sub(void* volatile* obj, ptrdiff_t operand)
{
unique_lock&lt;mutex&gt; _(some_mutex);
void* r = *obj;
(char*&amp;)(*obj) -= operand;
return r;
}
void __atomic_thread_fence()
{
unique_lock&lt;mutex&gt; _(some_mutex);
}
void __atomic_signal_fence()
{
unique_lock&lt;mutex&gt; _(some_mutex);
}
</pre></blockquote>
</div>
</body>
</html>

View File

@ -1,249 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>&lt;atomic&gt; design</title>
<link type="text/css" rel="stylesheet" href="menu.css">
<link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
<div id="menu">
<div>
<a href="https://llvm.org/">LLVM Home</a>
</div>
<div class="submenu">
<label>libc++ Info</label>
<a href="/index.html">About</a>
</div>
<div class="submenu">
<label>Quick Links</label>
<a href="https://lists.llvm.org/mailman/listinfo/cfe-dev">cfe-dev</a>
<a href="https://lists.llvm.org/mailman/listinfo/cfe-commits">cfe-commits</a>
<a href="https://bugs.llvm.org/">Bug Reports</a>
<a href="https://github.com/llvm/llvm-project/tree/main/libcxx/">Browse Sources</a>
</div>
</div>
<div id="content">
<!--*********************************************************************-->
<h1>&lt;atomic&gt; design</h1>
<!--*********************************************************************-->
<p>
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.
</p>
<blockquote><pre>
<font color="#C80000">// type must be trivially copyable</font>
bool __atomic_is_lock_free(const type* atomic_obj);
<font color="#C80000">// type must be trivially copyable</font>
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);
<font color="#C80000">// type must be trivially copyable</font>
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);
<font color="#C80000">// type must be trivially copyable</font>
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);
<font color="#C80000">// type must be trivially copyable</font>
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);
<font color="#C80000">// type must be trivially copyable</font>
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);
<font color="#C80000">// type is one of: char, signed char, unsigned char, short, unsigned short, int,</font>
<font color="#C80000">// unsigned int, long, unsigned long, long long, unsigned long long,</font>
<font color="#C80000">// char16_t, char32_t, wchar_t</font>
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);
<font color="#C80000">// type is one of: char, signed char, unsigned char, short, unsigned short, int,</font>
<font color="#C80000">// unsigned int, long, unsigned long, long long, unsigned long long,</font>
<font color="#C80000">// char16_t, char32_t, wchar_t</font>
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);
<font color="#C80000">// type is one of: char, signed char, unsigned char, short, unsigned short, int,</font>
<font color="#C80000">// unsigned int, long, unsigned long, long long, unsigned long long,</font>
<font color="#C80000">// char16_t, char32_t, wchar_t</font>
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);
<font color="#C80000">// type is one of: char, signed char, unsigned char, short, unsigned short, int,</font>
<font color="#C80000">// unsigned int, long, unsigned long, long long, unsigned long long,</font>
<font color="#C80000">// char16_t, char32_t, wchar_t</font>
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);
<font color="#C80000">// type is one of: char, signed char, unsigned char, short, unsigned short, int,</font>
<font color="#C80000">// unsigned int, long, unsigned long, long long, unsigned long long,</font>
<font color="#C80000">// char16_t, char32_t, wchar_t</font>
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();
</pre></blockquote>
</div>
</body>
</html>

View File

@ -1,457 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>&lt;atomic&gt; design</title>
<link type="text/css" rel="stylesheet" href="menu.css">
<link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
<div id="menu">
<div>
<a href="https://llvm.org/">LLVM Home</a>
</div>
<div class="submenu">
<label>libc++ Info</label>
<a href="/index.html">About</a>
</div>
<div class="submenu">
<label>Quick Links</label>
<a href="https://lists.llvm.org/mailman/listinfo/cfe-dev">cfe-dev</a>
<a href="https://lists.llvm.org/mailman/listinfo/cfe-commits">cfe-commits</a>
<a href="https://bugs.llvm.org/">Bug Reports</a>
<a href="https://github.com/llvm/llvm-project/tree/main/libcxx/">Browse Sources</a>
</div>
</div>
<div id="content">
<!--*********************************************************************-->
<h1>&lt;atomic&gt; design</h1>
<!--*********************************************************************-->
<p>
The <tt>&lt;atomic&gt;</tt> header is one of the most closely coupled headers to
the compiler. Ideally when you invoke any function from
<tt>&lt;atomic&gt;</tt>, 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++
<tt>&lt;atomic&gt;</tt> 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 <tt>&lt;atomic&gt;</tt>. Without this second
goal, then practically speaking, the libc++ <tt>&lt;atomic&gt;</tt> header would
be doomed to be a barely supported, second class citizen on almost every
platform.
</p>
<p>Goals:</p>
<blockquote><ul>
<li>Optimal code generation for atomic operations</li>
<li>Minimal effort for the compiler to achieve goal 1 on any given platform</li>
<li>Conformance to the C++0X draft standard</li>
</ul></blockquote>
<p>
The purpose of this document is to inform compiler writers what they need to do
to enable a high performance libc++ <tt>&lt;atomic&gt;</tt> with minimal effort.
</p>
<h2>The minimal work that must be done for a conforming <tt>&lt;atomic&gt;</tt></h2>
<p>
The only "atomic" operations that must actually be lock free in
<tt>&lt;atomic&gt;</tt> are represented by the following compiler intrinsics:
</p>
<blockquote><pre>
__atomic_flag__
__atomic_exchange_seq_cst(__atomic_flag__ volatile* obj, __atomic_flag__ desr)
{
unique_lock&lt;mutex&gt; _(some_mutex);
__atomic_flag__ result = *obj;
*obj = desr;
return result;
}
void
__atomic_store_seq_cst(__atomic_flag__ volatile* obj, __atomic_flag__ desr)
{
unique_lock&lt;mutex&gt; _(some_mutex);
*obj = desr;
}
</pre></blockquote>
<p>
Where:
</p>
<blockquote><ul>
<li>
If <tt>__has_feature(__atomic_flag)</tt> evaluates to 1 in the preprocessor then
the compiler must define <tt>__atomic_flag__</tt> (e.g. as a typedef to
<tt>int</tt>).
</li>
<li>
If <tt>__has_feature(__atomic_flag)</tt> evaluates to 0 in the preprocessor then
the library defines <tt>__atomic_flag__</tt> as a typedef to <tt>bool</tt>.
</li>
<li>
<p>
To communicate that the above intrinsics are available, the compiler must
arrange for <tt>__has_feature</tt> to return 1 when fed the intrinsic name
appended with an '_' and the mangled type name of <tt>__atomic_flag__</tt>.
</p>
<p>
For example if <tt>__atomic_flag__</tt> is <tt>unsigned int</tt>:
</p>
<blockquote><pre>
__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)
{
// ...
}
</pre></blockquote>
</li>
</ul></blockquote>
<p>
That's it! Compiler writers do the above and you've got a fully conforming
(though sub-par performance) <tt>&lt;atomic&gt;</tt> header!
</p>
<h2>Recommended work for a higher performance <tt>&lt;atomic&gt;</tt></h2>
<p>
It would be good if the above intrinsics worked with all integral types plus
<tt>void*</tt>. 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 <tt>__atomic_exchange_seq_cst</tt> works
for all types except for <tt>long long</tt> and <tt>unsigned long long</tt>
then:
</p>
<blockquote><pre>
__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*
</pre></blockquote>
<p>
Note that only the <tt>__has_feature</tt> flag is decorated with the argument
type. The name of the compiler intrinsic is not decorated, but instead works
like a C++ overloaded function.
</p>
<p>
Additionally there are other intrinsics besides
<tt>__atomic_exchange_seq_cst</tt> and <tt>__atomic_store_seq_cst</tt>. 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.
</p>
<p>
Below is the complete list of <i>sequentially consistent</i> 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 <em>any</em> type!
</p>
<blockquote><pre>
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 &lt;class T&gt;
T
__atomic_load_seq_cst(T const volatile* obj)
{
unique_lock&lt;mutex&gt; _(some_mutex);
return *obj;
}
template &lt;class T&gt;
void
__atomic_store_seq_cst(T volatile* obj, T desr)
{
unique_lock&lt;mutex&gt; _(some_mutex);
*obj = desr;
}
template &lt;class T&gt;
T
__atomic_exchange_seq_cst(T volatile* obj, T desr)
{
unique_lock&lt;mutex&gt; _(some_mutex);
T r = *obj;
*obj = desr;
return r;
}
template &lt;class T&gt;
bool
__atomic_compare_exchange_strong_seq_cst_seq_cst(T volatile* obj, T* exp, T desr)
{
unique_lock&lt;mutex&gt; _(some_mutex);
if (std::memcmp(const_cast&lt;T*&gt;(obj), exp, sizeof(T)) == 0)
{
std::memcpy(const_cast&lt;T*&gt;(obj), &amp;desr, sizeof(T));
return true;
}
std::memcpy(exp, const_cast&lt;T*&gt;(obj), sizeof(T));
return false;
}
template &lt;class T&gt;
bool
__atomic_compare_exchange_weak_seq_cst_seq_cst(T volatile* obj, T* exp, T desr)
{
unique_lock&lt;mutex&gt; _(some_mutex);
if (std::memcmp(const_cast&lt;T*&gt;(obj), exp, sizeof(T)) == 0)
{
std::memcpy(const_cast&lt;T*&gt;(obj), &amp;desr, sizeof(T));
return true;
}
std::memcpy(exp, const_cast&lt;T*&gt;(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 &lt;class T&gt;
T
__atomic_fetch_add_seq_cst(T volatile* obj, T operand)
{
unique_lock&lt;mutex&gt; _(some_mutex);
T r = *obj;
*obj += operand;
return r;
}
template &lt;class T&gt;
T
__atomic_fetch_sub_seq_cst(T volatile* obj, T operand)
{
unique_lock&lt;mutex&gt; _(some_mutex);
T r = *obj;
*obj -= operand;
return r;
}
template &lt;class T&gt;
T
__atomic_fetch_and_seq_cst(T volatile* obj, T operand)
{
unique_lock&lt;mutex&gt; _(some_mutex);
T r = *obj;
*obj &amp;= operand;
return r;
}
template &lt;class T&gt;
T
__atomic_fetch_or_seq_cst(T volatile* obj, T operand)
{
unique_lock&lt;mutex&gt; _(some_mutex);
T r = *obj;
*obj |= operand;
return r;
}
template &lt;class T&gt;
T
__atomic_fetch_xor_seq_cst(T volatile* obj, T operand)
{
unique_lock&lt;mutex&gt; _(some_mutex);
T r = *obj;
*obj ^= operand;
return r;
}
void*
__atomic_fetch_add_seq_cst(void* volatile* obj, ptrdiff_t operand)
{
unique_lock&lt;mutex&gt; _(some_mutex);
void* r = *obj;
(char*&amp;)(*obj) += operand;
return r;
}
void*
__atomic_fetch_sub_seq_cst(void* volatile* obj, ptrdiff_t operand)
{
unique_lock&lt;mutex&gt; _(some_mutex);
void* r = *obj;
(char*&amp;)(*obj) -= operand;
return r;
}
void __atomic_thread_fence_seq_cst()
{
unique_lock&lt;mutex&gt; _(some_mutex);
}
void __atomic_signal_fence_seq_cst()
{
unique_lock&lt;mutex&gt; _(some_mutex);
}
</pre></blockquote>
<p>
One should consult the (currently draft)
<a href="https://wg21.link/n3126">C++ standard</a>
for the details of the definitions for these operations. For example
<tt>__atomic_compare_exchange_weak_seq_cst_seq_cst</tt> is allowed to fail
spuriously while <tt>__atomic_compare_exchange_strong_seq_cst_seq_cst</tt> is
not.
</p>
<p>
If on your platform the lock-free definition of
<tt>__atomic_compare_exchange_weak_seq_cst_seq_cst</tt> would be the same as
<tt>__atomic_compare_exchange_strong_seq_cst_seq_cst</tt>, you may omit the
<tt>__atomic_compare_exchange_weak_seq_cst_seq_cst</tt> intrinsic without a
performance cost. The library will prefer your implementation of
<tt>__atomic_compare_exchange_strong_seq_cst_seq_cst</tt> over its own
definition for implementing
<tt>__atomic_compare_exchange_weak_seq_cst_seq_cst</tt>. That is, the library
will arrange for <tt>__atomic_compare_exchange_weak_seq_cst_seq_cst</tt> to call
<tt>__atomic_compare_exchange_strong_seq_cst_seq_cst</tt> if you supply an
intrinsic for the strong version but not the weak.
</p>
<h2>Taking advantage of weaker memory synchronization</h2>
<p>
So far all of the intrinsics presented require a <em>sequentially
consistent</em> memory ordering. That is, no loads or stores can move across
the operation (just as if the library had locked that internal mutex). But
<tt>&lt;atomic&gt;</tt> supports weaker memory ordering operations. In all,
there are six memory orderings (listed here from strongest to weakest):
</p>
<blockquote><pre>
memory_order_seq_cst
memory_order_acq_rel
memory_order_release
memory_order_acquire
memory_order_consume
memory_order_relaxed
</pre></blockquote>
<p>
(See the
<a href="https://wg21.link/n3126">C++ standard</a>
for the detailed definitions of each of these orderings).
</p>
<p>
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 <tt>mfence</tt> instruction on the x86.
</p>
<p>
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 <tt>seq_cst</tt>, and if that doesn't
exist, then the library takes over and does the job with a <tt>mutex</tt>. This
is a compile-time search &amp; selection operation. At run time, the
application will only see the few inlined assembly instructions for the selected
intrinsic.
</p>
<p>
Each intrinsic is appended with the 7-letter name of the memory ordering it
addresses. For example a <tt>load</tt> with <tt>relaxed</tt> ordering is
defined by:
</p>
<blockquote><pre>
T __atomic_load_relaxed(const volatile T* obj);
</pre></blockquote>
<p>
And announced with:
</p>
<blockquote><pre>
__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
...
</pre></blockquote>
<p>
The <tt>__atomic_compare_exchange_strong(weak)</tt> intrinsics are parameterized
on two memory orderings. The first ordering applies when the operation returns
<tt>true</tt> and the second ordering applies when the operation returns
<tt>false</tt>.
</p>
<p>
Not every memory ordering is appropriate for every operation. <tt>exchange</tt>
and the <tt>fetch_<i>op</i></tt> operations support all 6. But <tt>load</tt>
only supports <tt>relaxed</tt>, <tt>consume</tt>, <tt>acquire</tt> and <tt>seq_cst</tt>.
<tt>store</tt>
only supports <tt>relaxed</tt>, <tt>release</tt>, and <tt>seq_cst</tt>. The
<tt>compare_exchange</tt> operations support the following 16 combinations out
of the possible 36:
</p>
<blockquote><pre>
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
</pre></blockquote>
<p>
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.
</p>
</div>
</body>
</html>

View File

@ -1,27 +0,0 @@
html { margin: 0px; } body { margin: 8px; }
html, body {
padding:0px;
font-size:small; font-family:"Lucida Grande", "Lucida Sans Unicode", Arial, Verdana, Helvetica, sans-serif; background-color: #fff; color: #222;
line-height:1.5;
}
h1, h2, h3, tt { color: #000 }
h1 { padding-top:0px; margin-top:0px;}
h2 { color:#333333; padding-top:0.5em; }
h3 { padding-top: 0.5em; margin-bottom: -0.25em; color:#2d58b7}
li { padding-bottom: 0.5em; }
ul { padding-left:1.5em; }
/* Slides */
IMG.img_slide {
display: block;
margin-left: auto;
margin-right: auto
}
.itemTitle { color:#2d58b7 }
/* Tables */
tr { vertical-align:top }

View File

@ -1,14 +0,0 @@
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0; url=docs/Cxx1yStatus.html">
<script type="text/javascript">
window.location.href = "docs/Cxx1yStatus.html"
</script>
<title>libc++ C++14 Status</title>
</head>
<body>
If you are not redirected automatically, follow this <a href='docs/Cxx1yStatus.html'>link to new documentation</a>.
</body>
</html>

View File

@ -1,14 +0,0 @@
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0; url=docs/Cxx1zStatus.html">
<script type="text/javascript">
window.location.href = "docs/Cxx1zStatus.html"
</script>
<title>libc++ C++17 Status</title>
</head>
<body>
If you are not redirected automatically, follow this <a href='docs/Cxx1zStatus.html'>link to new documentation</a>.
</body>
</html>

View File

@ -1,14 +0,0 @@
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0; url=docs/Cxx2aStatus.html">
<script type="text/javascript">
window.location.href = "docs/Cxx2aStatus.html"
</script>
<title>libc++ C++20 Status</title>
</head>
<body>
If you are not redirected automatically, follow this <a href='docs/Cxx2aStatus.html'>link to new documentation</a>.
</body>
</html>

View File

@ -1,234 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>"libc++" C++ Standard Library</title>
<link type="text/css" rel="stylesheet" href="menu.css">
<link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
<div id="menu">
<div>
<a href="https://llvm.org/">LLVM Home</a>
</div>
<div class="submenu">
<label>libc++ Info</label>
<a href="/index.html">About</a>
</div>
<div class="submenu">
<label>Quick Links</label>
<a href="https://libcxxabi.llvm.org/">libc++abi</a>
<a href="https://lists.llvm.org/mailman/listinfo/libcxx-dev">libcxx-dev</a>
<a href="https://lists.llvm.org/mailman/listinfo/libcxx-commits">libcxx-commits</a>
<a href="https://bugs.llvm.org/">Bug Reports</a>
<a href="https://github.com/llvm/llvm-project/tree/main/libcxx/">Browse Sources</a>
</div>
</div>
<div id="content">
<!--*********************************************************************-->
<h1>"libc++" C++ Standard Library</h1>
<!--*********************************************************************-->
<p>libc++ is an implementation of the C++ standard library, targeting
C++11, C++14 and above.</p>
<p>All of the code in libc++ is <a
href="https://llvm.org/docs/DeveloperPolicy.html#copyright-license-and-patents">dual licensed</a>
under the MIT license and the UIUC License (a BSD-like license).</p>
<!--=====================================================================-->
<h2>New Documentation Coming Soon!</h2>
<!--=====================================================================-->
<p> Looking for documentation on how to use, build and test libc++? If so
checkout the new libc++ documentation.</p>
<p><a href="https://libcxx.llvm.org/docs/">
Click here for the new libc++ documentation.</a></p>
<!--=====================================================================-->
<h2 id="goals">Features and Goals</h2>
<!--=====================================================================-->
<ul>
<li>Correctness as defined by the C++11 standard.</li>
<li>Fast execution.</li>
<li>Minimal memory use.</li>
<li>Fast compile times.</li>
<li>ABI compatibility with gcc's libstdc++ for some low-level features
such as exception objects, rtti and memory allocation.</li>
<li>Extensive unit tests.</li>
</ul>
<!--=====================================================================-->
<h2 id="why">Why a new C++ Standard Library for C++11?</h2>
<!--=====================================================================-->
<p>After its initial introduction, many people have asked "why start a new
library instead of contributing to an existing library?" (like Apache's
libstdcxx, GNU's libstdc++, STLport, etc). There are many contributing
reasons, but some of the major ones are:</p>
<ul>
<li><p>From years of experience (including having implemented the standard
library before), we've learned many things about implementing
the standard containers which require ABI breakage and fundamental changes
to how they are implemented. For example, it is generally accepted that
building std::string using the "short string optimization" instead of
using Copy On Write (COW) is a superior approach for multicore
machines (particularly in C++11, which has rvalue references). Breaking
ABI compatibility with old versions of the library was
determined to be critical to achieving the performance goals of
libc++.</p></li>
<li><p>Mainline libstdc++ has switched to GPL3, a license which the developers
of libc++ cannot use. libstdc++ 4.2 (the last GPL2 version) could be
independently extended to support C++11, but this would be a fork of the
codebase (which is often seen as worse for a project than starting a new
independent one). Another problem with libstdc++ is that it is tightly
integrated with G++ development, tending to be tied fairly closely to the
matching version of G++.</p>
</li>
<li><p>STLport and the Apache libstdcxx library are two other popular
candidates, but both lack C++11 support. Our experience (and the
experience of libstdc++ developers) is that adding support for C++11 (in
particular rvalue references and move-only types) requires changes to
almost every class and function, essentially amounting to a rewrite.
Faced with a rewrite, we decided to start from scratch and evaluate every
design decision from first principles based on experience.</p>
<p>Further, both projects are apparently abandoned: STLport 5.2.1 was
released in Oct'08, and STDCXX 4.2.1 in May'08.</p>
</ul>
<!--=====================================================================-->
<h2 id="requirements">Platform Support</h2>
<!--=====================================================================-->
<p>
libc++ is known to work on the following platforms, using g++ and
clang. Note that functionality provided by &lt;atomic&gt; is only functional with
clang.
</p>
<ul>
<li>Mac OS X i386</li>
<li>Mac OS X x86_64</li>
<li>FreeBSD 10+ i386</li>
<li>FreeBSD 10+ x86_64</li>
<li>FreeBSD 10+ ARM</li>
<li>Linux i386</li>
<li>Linux x86_64</li>
</ul>
<p>
The library also supports Windows (both MSVC-style environments,
built with clang-cl, and MinGW environments), although support for
Windows is less mature than for the platforms listed above.
</p>
<!--=====================================================================-->
<h2 id="dir-structure">Current Status</h2>
<!--=====================================================================-->
<p>libc++ is a 100% complete C++11 implementation on Apple's OS X. </p>
<p>LLVM and Clang can self host in C++ and C++11 mode with libc++ on Linux.</p>
<p>libc++ is also a 100% complete C++14 implementation. A list of new features and
changes for C++14 can be found <a href="cxx1y_status.html">here</a>.</p>
<p>libc++'s C++17 implementation is not yet complete. A list of features and changes
for C++17 can be found <a href="cxx1z_status.html">here</a>.</p>
<p>A list of features and changes for the next C++ standard, known here as
"C++2a" (probably to be C++20) can be found <a href="cxx2a_status.html">here</a>.</p>
<p>Implementation of the post-C++14 Technical Specifications is in progress. A list of features
and the current status of these features can be found <a href="ts1z_status.html">here</a>.</p>
<p>As features get moved from the Technical Specifications into the main standard, we
will (after a period for migration) remove them from the TS implementation. This
process is detailed <a href="DesignDocs/ExperimentalFeatures.html">here</a>.</p>
<!--======================================================================-->
<h2 id="buildbots">Build Bots</h2>
<!--======================================================================-->
<p>The latest libc++ build results can be found at the following locations.</p>
<ul>
<li><a href="http://lab.llvm.org:8011/console">
Buildbot libc++ builders
</a></li>
<li><a href="http://lab.llvm.org:8080/green/view/Libcxx/">
Jenkins libc++ builders
</a></li>
</ul>
<!--=====================================================================-->
<h2>Get it and get involved!</h2>
<!--=====================================================================-->
<p>First please review our
<a href="https://llvm.org/docs/DeveloperPolicy.html">Developer's Policy</a>.
The documentation for building and using libc++ can be found below.
<ul>
<li><a href="https://libcxx.llvm.org/docs/UsingLibcxx.html">
<b>Using libc++</b></a>
Documentation on using the library in your programs</li>
<li><a href="https://libcxx.llvm.org/docs/BuildingLibcxx.html">
<b>Building libc++</b></a>
Documentation on building the library using CMake</li>
<li><a href="https://libcxx.llvm.org/docs/TestingLibcxx.html">
<b>Testing libc++</b></a>
Documentation for developers wishing to test the library</li>
</ul>
<!--=====================================================================-->
<h3>Notes and Known Issues</h3>
<!--=====================================================================-->
<p>
<ul>
<li>
Building libc++ with <code>-fno-rtti</code> is not supported. However
linking against it with <code>-fno-rtti</code> is supported.
</li>
</ul>
</p>
<p>Send discussions to the
<a href="https://lists.llvm.org/mailman/listinfo/libcxx-dev">libc++ mailing list</a>.</p>
<!--=====================================================================-->
<h2>Bug reports and patches</h2>
<!--=====================================================================-->
<p>
If you think you've found a bug in libc++, please report it using
the <a href="https://bugs.llvm.org/">LLVM Bugzilla</a>. If you're not sure, you
can post a message to the <a href="https://lists.llvm.org/mailman/listinfo/libcxx-dev">libcxx-dev</a>
mailing list or on IRC.
</p>
<p>
If you want to contribute a patch to libc++, the best place for that is
<a href="https://llvm.org/docs/Phabricator.html">Phabricator</a>. Please
add libcxx-commits as a subscriber.
</p>
<!--=====================================================================-->
<h2>Design Documents</h2>
<!--=====================================================================-->
<ul>
<li><a href="atomic_design.html"><tt>&lt;atomic&gt;</tt></a></li>
<li><a href="type_traits_design.html"><tt>&lt;type_traits&gt;</tt></a></li>
<li><a href="https://cplusplusmusings.wordpress.com/2012/07/05/clang-and-standard-libraries-on-mac-os-x/">Excellent notes by Marshall Clow</a></li>
</ul>
</div>
</body>
</html>

View File

@ -1,39 +0,0 @@
/***************/
/* page layout */
/***************/
[id=menu] {
position:fixed;
width:25ex;
}
[id=content] {
/* ***** EDIT THIS VALUE IF CONTENT OVERLAPS MENU ***** */
position:absolute;
left:29ex;
padding-right:4ex;
}
/**************/
/* menu style */
/**************/
#menu .submenu {
padding-top:1em;
display:block;
}
#menu label {
display:block;
font-weight: bold;
text-align: center;
background-color: rgb(192,192,192);
}
#menu a {
padding:0 .2em;
display:block;
text-align: center;
background-color: rgb(235,235,235);
}
#menu a:visited {
color:rgb(100,50,100);
}

View File

@ -1,108 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>libc++ Fundamentals TS Status</title>
<link type="text/css" rel="stylesheet" href="menu.css">
<link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
<div id="menu">
<div>
<a href="https://llvm.org/">LLVM Home</a>
</div>
<div class="submenu">
<label>libc++ Info</label>
<a href="/index.html">About</a>
</div>
<div class="submenu">
<label>Quick Links</label>
<a href="https://lists.llvm.org/mailman/listinfo/cfe-dev">cfe-dev</a>
<a href="https://lists.llvm.org/mailman/listinfo/cfe-commits">cfe-commits</a>
<a href="https://bugs.llvm.org/">Bug Reports</a>
<a href="https://github.com/llvm/llvm-project/tree/main/libcxx/">Browse Sources</a>
</div>
</div>
<div id="content">
<!--*********************************************************************-->
<h1>Post-C++14 TS Implementation Status</h1>
<!--*********************************************************************-->
<p>In November 2014, the C++ standard committee approved the draft for the next version of the C++ standard, known as "C++1z" (probably to be C++17)</p>
<p>In addition, there are several "Technical Specifications", that consist of new features that are proposed, but not yet accepted for C++1z.</p>
<p>This page shows the status of libc++; the status of clang's support of the language features is <a href="https://clang.llvm.org/cxx_status.html">here</a>.</p>
<h3>Technical Specifications</h3>
<table id="TS" border="1">
<tr><th>Paper Number</th><th>Paper Title</th><th>TS</th></tr>
<tr><td><a href="https://wg21.link/n4023">4023</a></td><td>C++ Extensions for Library Fundamentals</td><td>Library Fundamentals 1</td></tr>
<tr><td><a href="https://wg21.link/n3940">3940</a></td><td>Technical Specification - File System</td><td>File System</td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td><a href="https://wg21.link/n4273">4273</a></td><td>Uniform Container Erasure.</td><td>Library Fundamentals 2</td></tr>
<tr><td><a href="https://wg21.link/n4061">4061</a></td><td>Greatest Common Divisor and Least Common Multiple.</td><td>Library Fundamentals 2</td></tr>
<tr><td><a href="https://wg21.link/n4257">4257</a></td><td>Delimited iterators.</td><td>Library Fundamentals 2</td></tr>
<tr><td><a href="https://wg21.link/n4282">4282</a></td><td>The World's Dumbest Smart Pointer.</td><td>Library Fundamentals 2</td></tr>
<tr><td></td><td></td><td></td></tr>
</table>
<h3>Features in Library Fundamentals 1</h3>
<table id="Features" border="1">
<tr><th>Feature Name</th><th>Status</th></tr>
<tr><td>Uses-allocator construction</td><td>Not started</td></tr>
<tr><td>Changes to std::shared_ptr and weak_ptr</td><td>Not started</td></tr>
<tr><td>Additions to std::function</td><td>Not started</td></tr>
<tr><td>Additions to std::promise</td><td>Not started</td></tr>
<tr><td>Additions to std::packaged_task</td><td>Not started</td></tr>
<tr><td></td><td></td></tr>
<tr><td>Class erased_type</td><td>Complete</td></tr>
<tr><td>Calling a function with a tuple of arguments</td><td>Complete</td></tr>
<tr><td>Type traits (_v)</td><td>Complete</td></tr>
<tr><td>Other type transformations</td><td>Not started</td></tr>
<tr><td>Compile-time Rational Arithmetic</td><td>Implementation in progress</td></tr>
<tr><td>Time Utilities</td><td>Complete</td></tr>
<tr><td>System Error Support</td><td>Complete</td></tr>
<tr><td></td><td></td></tr>
<tr><td>Class memory_resource</td><td>Complete</td></tr>
<tr><td>Class template polymorphic_allocator</td><td>Complete</td></tr>
<tr><td>Template alias resource_adaptor</td><td>Complete</td></tr>
<tr><td>Global memory resources</td><td>Complete</td></tr>
<tr><td>Pool resource classes</td><td>Implementation in progress</td></tr>
<tr><td>Class monotonic_buffer_resource</td><td>Implementation in progress</td></tr>
<tr><td>Alias templates using polymorphic memory resource</td><td>Complete</td></tr>
<tr><td></td><td></td></tr>
<tr><td>Searchers</td><td>Complete</td></tr>
<tr><td>Optional Objects</td><td>Initial implementation complete</td></tr>
<tr><td>class any</td><td>Complete</td></tr>
<tr><td>string_view</td><td>Complete</td></tr>
<tr><td>memory</td><td>Implementation in progress</td></tr>
<tr><td>Algorithms library</td><td>Complete</td></tr>
</table>
<h3>Features in Library Fundamentals 2</h3>
<table id="Features" border="1">
<tr><th>Feature Name</th><th>Status</th></tr>
<!-- <tr><td></td><td></td></tr> -->
</table>
<h3>Features in Filesystem</h3>
<table id="Features" border="1">
<tr><th>Feature Name</th><th>Status</th><th>First released version</th></tr>
<tr><td>All features</td><td>Complete</td><td>3.9</td></tr>
</table>
<p>Last Updated: 17-June-2016</p>
</div>
</body>
</html>

View File

@ -1,285 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>type traits intrinsic design</title>
<link type="text/css" rel="stylesheet" href="menu.css">
<link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
<div id="menu">
<div>
<a href="https://llvm.org/">LLVM Home</a>
</div>
<div class="submenu">
<label>libc++ Info</label>
<a href="/index.html">About</a>
</div>
<div class="submenu">
<label>Quick Links</label>
<a href="https://lists.llvm.org/mailman/listinfo/cfe-dev">cfe-dev</a>
<a href="https://lists.llvm.org/mailman/listinfo/cfe-commits">cfe-commits</a>
<a href="https://bugs.llvm.org/">Bug Reports</a>
<a href="https://github.com/llvm/llvm-project/tree/main/libcxx/">Browse Sources</a>
</div>
</div>
<div id="content">
<!--*********************************************************************-->
<h1>Type traits intrinsic design</h1>
<!--*********************************************************************-->
<p>
This is a survey of the type traits intrinsics clang has, and those needed.
The names and definitions of several of the needed type traits has recently
changed. Please see:
<a href="https://wg21.link/n3142">N3142</a>.
</p>
<blockquote>
<table border="1">
<caption>Legend</caption>
<tr>
<td>clang supplies it and it is absolutely necessary</td>
<td bgcolor="#80FF80"><tt>some_trait(T)</tt></td>
</tr>
<tr>
<td>clang supplies it and it is useful</td>
<td bgcolor="#96B9FF"><tt>some_trait(T)</tt></td>
</tr>
<tr>
<td>clang supplies it and it is not needed</td>
<td><tt>some_trait(T)</tt></td>
</tr>
<tr>
<td>clang does not supply it and it is not needed</td>
<td></td>
</tr>
<tr>
<td>clang does not supply it and it is absolutely necessary</td>
<td bgcolor="#FF5965"><tt>some_trait(T)</tt></td>
</tr>
</table>
<p></p>
<table border="1">
<caption>Needed type traits vs clang type traits</caption>
<tr>
<th>libc++ Needs</th>
<th>clang Has</th>
</tr>
<tr>
<td><tt>is_union&lt;T&gt;</tt></td>
<td bgcolor="#80FF80"><tt>__is_union(T)</tt></td>
</tr>
<tr>
<td><tt>is_class&lt;T&gt;</tt></td>
<td bgcolor="#96B9FF"><tt>__is_class(T)</tt></td>
</tr>
<tr>
<td><tt>is_enum&lt;T&gt;</tt></td>
<td bgcolor="#96B9FF"><tt>__is_enum(T)</tt></td>
</tr>
<tr>
<td><tt>is_pod&lt;T&gt;</tt></td>
<td bgcolor="#80FF80"><tt>__is_pod(T)</tt></td>
</tr>
<tr>
<td><tt>has_virtual_destructor&lt;T&gt;</tt></td>
<td bgcolor="#80FF80"><tt>__has_virtual_destructor(T)</tt></td>
</tr>
<tr>
<td><tt>is_constructible&lt;T, Args...&gt;</tt></td>
<td></td>
</tr>
<tr>
<td><tt>is_default_constructible&lt;T&gt;</tt></td>
<td></td>
</tr>
<tr>
<td><tt>is_copy_constructible&lt;T&gt;</tt></td>
<td></td>
</tr>
<tr>
<td><tt>is_move_constructible&lt;T&gt;</tt></td>
<td></td>
</tr>
<tr>
<td><tt>is_assignable&lt;T, U&gt;</tt></td>
<td></td>
</tr>
<tr>
<td><tt>is_copy_assignable&lt;T&gt;</tt></td>
<td></td>
</tr>
<tr>
<td><tt>is_move_assignable&lt;T&gt;</tt></td>
<td></td>
</tr>
<tr>
<td><tt>is_destructible&lt;T&gt;</tt></td>
<td></td>
</tr>
<tr>
<td><tt>is_trivially_constructible&lt;T, Args...&gt;</tt></td>
<td bgcolor="#80FF80"><tt>__is_trivially_constructible(T, U)</tt></td>
</tr>
<tr>
<td><tt>is_trivially_default_constructible&lt;T&gt;</tt></td>
<td bgcolor="#80FF80"><tt>__has_trivial_constructor(T)</tt></td>
</tr>
<tr>
<td><tt>is_trivially_copy_constructible&lt;T&gt;</tt></td>
<td><tt>__has_trivial_copy(T)</tt></td>
</tr>
<tr>
<td><tt>is_trivially_move_constructible&lt;T&gt;</tt></td>
<td></td>
</tr>
<tr>
<td><tt>is_trivially_assignable&lt;T, U&gt;</tt></td>
<td bgcolor="#80FF80"><tt>__is_trivially_assignable(T, U)</tt></td>
</tr>
<tr>
<td><tt>is_trivially_copy_assignable&lt;T&gt;</tt></td>
<td><tt>__has_trivial_assign(T)</tt></td>
</tr>
<tr>
<td><tt>is_trivially_move_assignable&lt;T&gt;</tt></td>
<td></td>
</tr>
<tr>
<td><tt>is_trivially_destructible&lt;T&gt;</tt></td>
<td bgcolor="#80FF80"><tt>__has_trivial_destructor(T)</tt></td>
</tr>
<tr>
<td><tt>is_nothrow_constructible&lt;T, Args...&gt;</tt></td>
<td></td>
</tr>
<tr>
<td><tt>is_nothrow_default_constructible&lt;T&gt;</tt></td>
<td><tt>__has_nothrow_constructor(T)</tt></td>
</tr>
<tr>
<td><tt>is_nothrow_copy_constructible&lt;T&gt;</tt></td>
<td><tt>__has_nothrow_copy(T)</tt></td>
</tr>
<tr>
<td><tt>is_nothrow_move_constructible&lt;T&gt;</tt></td>
<td></td>
</tr>
<tr>
<td><tt>is_nothrow_assignable&lt;T, U&gt;</tt></td>
<td></td>
</tr>
<tr>
<td><tt>is_nothrow_copy_assignable&lt;T&gt;</tt></td>
<td><tt>__has_nothrow_assign(T)</tt></td>
</tr>
<tr>
<td><tt>is_nothrow_move_assignable&lt;T&gt;</tt></td>
<td></td>
</tr>
<tr>
<td><tt>is_nothrow_destructible&lt;T&gt;</tt></td>
<td></td>
</tr>
<tr>
<td><tt>is_trivial&lt;T&gt;</tt></td>
<td bgcolor="#80FF80"><tt>__is_trivial(T)</tt></td>
</tr>
<tr>
<td><tt>is_trivially_copyable&lt;T&gt;</tt></td>
<td bgcolor="#80FF80"><tt>__is_trivially_copyable(T)</tt></td>
</tr>
<tr>
<td><tt>is_standard_layout&lt;T&gt;</tt></td>
<td bgcolor="#80FF80"><tt>__is_standard_layout(T)</tt></td>
</tr>
<tr>
<td><tt>is_literal_type&lt;T&gt;</tt></td>
<td bgcolor="#80FF80"><tt>__is_literal_type(T)</tt></td>
</tr>
<tr>
<td><tt>is_convertible&lt;T, U&gt;</tt></td>
<td bgcolor="#80FF80"><tt>__is_convertible_to(T, U)</tt></td>
</tr>
<tr>
<td><tt>is_base_of&lt;T, U&gt;</tt></td>
<td bgcolor="#80FF80"><tt>__is_base_of(T, U)</tt></td>
</tr>
<tr>
<td><tt>underlying_type&lt;T&gt;</tt></td>
<td bgcolor="#80FF80"><tt>__underlying_type(T)</tt></td>
</tr>
<tr>
<td><tt>is_polymorphic&lt;T&gt;</tt></td>
<td><tt>__is_polymorphic(T)</tt></td>
</tr>
<tr>
<td><tt>is_empty&lt;T&gt;</tt></td>
<td><tt>__is_empty(T)</tt></td>
</tr>
<tr>
<td><tt>is_abstract&lt;T&gt;</tt></td>
<td><tt>__is_abstract(T)</tt></td>
</tr>
</table>
</blockquote>
</div>
</body>
</html>

View File

@ -1,133 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>libc++ Upcoming Meeting Status</title>
<link type="text/css" rel="stylesheet" href="menu.css">
<link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
<div id="menu">
<div>
<a href="https://llvm.org/">LLVM Home</a>
</div>
<div class="submenu">
<label>libc++ Info</label>
<a href="/index.html">About</a>
</div>
<div class="submenu">
<label>Quick Links</label>
<a href="https://lists.llvm.org/mailman/listinfo/cfe-dev">cfe-dev</a>
<a href="https://lists.llvm.org/mailman/listinfo/cfe-commits">cfe-commits</a>
<a href="https://bugs.llvm.org/">Bug Reports</a>
<a href="https://github.com/llvm/llvm-project/tree/main/libcxx/">Browse Sources</a>
</div>
</div>
<div id="content">
<!--*********************************************************************-->
<h1>libc++ Upcoming Meeting Status</h1>
<!--*********************************************************************-->
<p>This is a temporary page; please check the c++2a status <a href="cxx2a_status.html">here</a></p>
<p>This page shows the status of the papers and issues that are expected to be adopted in the next WG21 Meeting.</p>
<p>The groups that have contributed papers:
<ul>
<li>LWG - Library working group</li>
<li>CWG - Core Language Working group</li>
<li>SG1 - Study group #1 (Concurrency working group)</li>
</ul>
</p>
<h3>Paper Status</h3>
<table border="1">
<tr><th>Paper #</th><th>Group</th><th>Paper Name</th><th>Meeting</th><th>Status</th></tr>
</table>
<h3>Library Working group Issues Status</h3>
<table id="issues" border="1">
<tr><th>Issue #</th><th>Issue Name</th><th>Meeting</th><th>Status</th></tr>
<tr><td><a href="https://wg21.link/LWG3231">3231</a></td><td><tt>year_month_day_last::day</tt> specification does not cover <tt>!ok()</tt> values</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3225">3225</a></td><td><tt>zoned_time</tt> converting constructor shall not be <tt>noexcept</tt></td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3190">3190</a></td><td><tt>std::allocator::allocate</tt> sometimes returns too little storage</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3218">3218</a></td><td>Modifier for <tt>%d</tt> parse flag does not match POSIX and <tt>format</tt> specification</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3224">3224</a></td><td><tt>zoned_time</tt> constructor from <tt>TimeZonePtr</tt> does not specify initialization of <tt>tp_</tt></td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3230">3230</a></td><td>Format specifier <tt>%y/%Y</tt> is missing locale alternative versions</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3232">3232</a></td><td>Inconsistency in <tt>zoned_time</tt> deduction guides</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3222">3222</a></td><td>P0574R1 introduced preconditions on non-existent parameters</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3221">3221</a></td><td>Result of <tt>year_month</tt> arithmetic with <tt>months</tt> is ambiguous</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3235">3235</a></td><td><code>parse</code> manipulator without abbreviation is not callable</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3246">3246</a></td><td>What are the constraints on the template parameter of <tt>basic_format_arg</tt>?</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3253">3253</a></td><td><tt>basic_syncbuf::basic_syncbuf()</tt> should not be explicit</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3245">3245</a></td><td>Unnecessary restriction on <tt>'%p'</tt> parse specifier</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3244">3244</a></td><td>Constraints for <tt>Source</tt> in &sect;[fs.path.req] insufficiently constrainty</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3241">3241</a></td><td><tt>chrono-spec</tt> grammar ambiguity in &sect;[time.format]</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3257">3257</a></td><td>Missing feature testing macro update from P0858</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3256">3256</a></td><td>Feature testing macro for <tt>constexpr</tt> algorithms</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3273">3273</a></td><td>Specify <tt>weekday_indexed</tt> to range of <tt>[0, 7]</tt></td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3070">3070</a></td><td><tt>path::lexically_relative</tt> causes surprising results if a filename can also be a <i>root-name</i></td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3266">3266</a></td><td><tt>to_chars(bool)</tt> should be deleted</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3272">3272</a></td><td><tt>%I%p</tt> should parse/format <tt>duration</tt> since midnight</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3259">3259</a></td><td>The definition of <i>constexpr iterators</i> should be adjusted</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3103">3103</a></td><td>Errors in taking subview of <tt>span</tt> should be ill-formed where possible</td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3274">3274</a></td><td>Missing feature test macro for <tt>&lt;span&gt;</tt></td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3276">3276</a></td><td>Class <tt>split_view::outer_iterator::value_type</tt> should inherit from <tt>view_interface</tt></td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3277">3277</a></td><td>Pre-increment on prvalues is not a requirement of <tt>weakly_incrementable</tt></td><td>Belfast</td><td></td></tr>
<tr><td><a href="https://wg21.link/LWG3149">3149</a></td><td><tt>DefaultConstructible</tt> should require default initialization</td><td>Belfast</td><td></td></tr>
</table>
<h3>Issues to "Review"</h3>
<table border="1">
<tr><th>Issue #</th><th>Issue Name</th><th>Meeting</th><th>Status</th></tr>
</table>
<h3>Comments about the papers</h3>
<ul>
</ul>
<h3>Comments about the issues</h3>
<ul>
<li>3231 - </li>
<li>3225 - </li>
<li>3190 - </li>
<li>3218 - </li>
<li>3224 - </li>
<li>3230 - </li>
<li>3232 - </li>
<li>3222 - </li>
<li>3221 - </li>
<li>3235 - </li>
<li>3246 - </li>
<li>3253 - </li>
<li>3245 - </li>
<li>3244 - </li>
<li>3241 - </li>
<li>3257 - </li>
<li>3256 - </li>
<li>3273 - </li>
<li>3070 - </li>
<li>3266 - </li>
<li>3272 - </li>
<li>3259 - </li>
<li>3103 - </li>
<li>3274 - </li>
<li>3276 - </li>
<li>3277 - </li>
<li>3149 - </li>
</ul>
<p>Last Updated: 22-Oct-2019</p>
</div>
</body>
</html>