[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:
parent
f60ea691a9
commit
491d045957
797
libcxx/docs/DesignDocs/AtomicDesign.rst
Normal file
797
libcxx/docs/DesignDocs/AtomicDesign.rst
Normal 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.
|
||||
@ -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>`_
|
||||
|
||||
@ -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><atomic> 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><atomic> 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<long long> A;
|
||||
int foo() { return A.compare_exchange_strong(w, x); }
|
||||
|
||||
TU2.cc
|
||||
-----------
|
||||
extern atomic<long long> 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>
|
||||
@ -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><atomic> 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><atomic> 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 <= 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 <= 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 <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) <font color="#C80000">// if (*obj == *exp)</font>
|
||||
{
|
||||
std::memcpy(const_cast<T*>(obj), &desr, sizeof(T)); <font color="#C80000">// *obj = desr;</font>
|
||||
return true;
|
||||
}
|
||||
std::memcpy(exp, const_cast<T*>(obj), sizeof(T)); <font color="#C80000">// *exp = *obj;</font>
|
||||
return false;
|
||||
}
|
||||
|
||||
<font color="#C80000">// May spuriously return false (even if *obj == *exp)</font>
|
||||
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) <font color="#C80000">// if (*obj == *exp)</font>
|
||||
{
|
||||
std::memcpy(const_cast<T*>(obj), &desr, sizeof(T)); <font color="#C80000">// *obj = desr;</font>
|
||||
return true;
|
||||
}
|
||||
std::memcpy(exp, const_cast<T*>(obj), sizeof(T)); <font color="#C80000">// *exp = *obj;</font>
|
||||
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);
|
||||
}
|
||||
</pre></blockquote>
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -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><atomic> 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><atomic> 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>
|
||||
@ -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><atomic> 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><atomic> design</h1>
|
||||
<!--*********************************************************************-->
|
||||
|
||||
<p>
|
||||
The <tt><atomic></tt> header is one of the most closely coupled headers to
|
||||
the compiler. Ideally when you invoke any function from
|
||||
<tt><atomic></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><atomic></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><atomic></tt>. Without this second
|
||||
goal, then practically speaking, the libc++ <tt><atomic></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><atomic></tt> with minimal effort.
|
||||
</p>
|
||||
|
||||
<h2>The minimal work that must be done for a conforming <tt><atomic></tt></h2>
|
||||
|
||||
<p>
|
||||
The only "atomic" operations that must actually be lock free in
|
||||
<tt><atomic></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<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;
|
||||
}
|
||||
</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><atomic></tt> header!
|
||||
</p>
|
||||
|
||||
<h2>Recommended work for a higher performance <tt><atomic></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 <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);
|
||||
}
|
||||
</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><atomic></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 & 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>
|
||||
@ -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 }
|
||||
@ -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>
|
||||
@ -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>
|
||||
@ -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>
|
||||
@ -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 <atomic> 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><atomic></tt></a></li>
|
||||
<li><a href="type_traits_design.html"><tt><type_traits></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>
|
||||
@ -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);
|
||||
}
|
||||
@ -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>
|
||||
@ -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<T></tt></td>
|
||||
<td bgcolor="#80FF80"><tt>__is_union(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_class<T></tt></td>
|
||||
<td bgcolor="#96B9FF"><tt>__is_class(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_enum<T></tt></td>
|
||||
<td bgcolor="#96B9FF"><tt>__is_enum(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_pod<T></tt></td>
|
||||
<td bgcolor="#80FF80"><tt>__is_pod(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>has_virtual_destructor<T></tt></td>
|
||||
<td bgcolor="#80FF80"><tt>__has_virtual_destructor(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_constructible<T, Args...></tt></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_default_constructible<T></tt></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_copy_constructible<T></tt></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_move_constructible<T></tt></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_assignable<T, U></tt></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_copy_assignable<T></tt></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_move_assignable<T></tt></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_destructible<T></tt></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_trivially_constructible<T, Args...></tt></td>
|
||||
<td bgcolor="#80FF80"><tt>__is_trivially_constructible(T, U)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_trivially_default_constructible<T></tt></td>
|
||||
<td bgcolor="#80FF80"><tt>__has_trivial_constructor(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_trivially_copy_constructible<T></tt></td>
|
||||
<td><tt>__has_trivial_copy(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_trivially_move_constructible<T></tt></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_trivially_assignable<T, U></tt></td>
|
||||
<td bgcolor="#80FF80"><tt>__is_trivially_assignable(T, U)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_trivially_copy_assignable<T></tt></td>
|
||||
<td><tt>__has_trivial_assign(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_trivially_move_assignable<T></tt></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_trivially_destructible<T></tt></td>
|
||||
<td bgcolor="#80FF80"><tt>__has_trivial_destructor(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_nothrow_constructible<T, Args...></tt></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_nothrow_default_constructible<T></tt></td>
|
||||
<td><tt>__has_nothrow_constructor(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_nothrow_copy_constructible<T></tt></td>
|
||||
<td><tt>__has_nothrow_copy(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_nothrow_move_constructible<T></tt></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_nothrow_assignable<T, U></tt></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_nothrow_copy_assignable<T></tt></td>
|
||||
<td><tt>__has_nothrow_assign(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_nothrow_move_assignable<T></tt></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_nothrow_destructible<T></tt></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_trivial<T></tt></td>
|
||||
<td bgcolor="#80FF80"><tt>__is_trivial(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_trivially_copyable<T></tt></td>
|
||||
<td bgcolor="#80FF80"><tt>__is_trivially_copyable(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_standard_layout<T></tt></td>
|
||||
<td bgcolor="#80FF80"><tt>__is_standard_layout(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_literal_type<T></tt></td>
|
||||
<td bgcolor="#80FF80"><tt>__is_literal_type(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_convertible<T, U></tt></td>
|
||||
<td bgcolor="#80FF80"><tt>__is_convertible_to(T, U)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_base_of<T, U></tt></td>
|
||||
<td bgcolor="#80FF80"><tt>__is_base_of(T, U)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>underlying_type<T></tt></td>
|
||||
<td bgcolor="#80FF80"><tt>__underlying_type(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_polymorphic<T></tt></td>
|
||||
<td><tt>__is_polymorphic(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_empty<T></tt></td>
|
||||
<td><tt>__is_empty(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>is_abstract<T></tt></td>
|
||||
<td><tt>__is_abstract(T)</tt></td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</blockquote>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -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 §[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 §[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><span></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>
|
||||
Loading…
x
Reference in New Issue
Block a user