Document number: P3306R0.
Date: 2024-5-21.
Authors: Gonzalo Brito Gadeschi, Damien Lebrun-Grandie.
Reply to: Gonzalo Brito Gadeschi <gonzalob _at_ nvidia.com>.
Audience: SG1, SG6.
Table of Contents
Atomic Read-Modify-Write Improvements
Extends read-modify-write atomic APIs with commonly requested functionality that is already available in some pre-existing implementations as an extension: integer shl, shr, mod, nand, div, mul, and floating-point div and mul.
Motivation
Without these extensions, users are required to implement this functionality by themselves on top of the atomic types, e.g., via user-specified CAS-loops. These loops complicate compiler optimizations and high-quality forward progress.
Design
The following APIs are commonly requested, and available in some implementations, like Kokkos atomic_fetch_<op> or Rust's Atomic:
- Integer shl, shr, mod, nand.
- Integer and floating-point div, mul.
These follow the same semantics as the scalar operations, e.g., in terms of what uses exhibit undefined or implementation-defined behavior.
Wording
Add feature test macro to <version>
synopsis:
#define __cpp_lib_atomic_fetch_ext 202XXXL
Add following functions for <op>
in {mod, nand, div, mul}
, immediately below atomic_fetch_xor_explicit
:
namespace std {
...
template<class T>
T atomic_fetch_<op>(volatile atomic<T>*,
typename atomic<T>::value_type) noexcept;
template<class T>
T atomic_fetch_<op>(atomic<T>*,
typename atomic<T>::value_type) noexcept;
template<class T>
T atomic_fetch_<op>_explicit(volatile atomic<T>*,
typename atomic<T>::value_type,
memory_order) noexcept;
template<class T>
T atomic_fetch_<op>_explicit(atomic<T>*,
typename atomic<T>::value_type,
memory_order) noexcept;
...
}
Add following functions for <op>
in {shl, shr}
, immediately afterwards:
namespace std {
...
template<class T>
T atomic_fetch_<op>(volatile atomic<T>*,
const unsigned) noexcept;
template<class T>
T atomic_fetch_<op>(atomic<T>*,
const unsigned) noexcept;
template<class T>
T atomic_fetch_<op>_explicit(volatile atomic<T>*,
const unsigned,
memory_order) noexcept;
template<class T>
T atomic_fetch_<op>_explicit(atomic<T>*,
const unsigned,
memory_order) noexcept;
...
}
Add following functions immediately afterwards:
...
template<class T, typename BinaryOp>
T atomic_fetch_<op>(volatile atomic<T>*, BinaryOp&& bop,
typename atomic<T>::value_type) noexcept;
template<class T, typename BinaryOp>
T atomic_fetch_<op>(atomic<T>*,
typename atomic<T>::value_type) noexcept;
template<class T, typename BinaryOp>
T atomic_fetch_<op>_explicit(volatile atomic<T>*,
typename atomic<T>::value_type,
memory_order) noexcept;
template<class T, typename BinaryOp>
T atomic_fetch_<op>_explicit(atomic<T>*,
typename atomic<T>::value_type,
memory_order) noexcept;
...
Modify tab:atomic.types.int.comp as follows:
key |
op |
computation |
add |
+ |
addition |
sub |
- |
subtraction |
mul |
* |
multiplication |
div |
/ |
division |
mod |
% |
modulo |
max |
|
maximum |
min |
|
minimum |
and |
& |
bitwise and |
or |
| |
bitwise inclusive or |
xor |
^ |
bitwise exclusive or |
nand |
|
bitwise and-not |
shl |
<< |
left shift |
shr |
>> |
right shift |
For each <op>
in {mod, nand, div, mul}
, add following public functions to [atomics.ref.int] specialization, immediately below fetch_xor
:
namespace std {
template <> struct atomic_ref<integral> {
...
integral fetch_<op>(integral, memory_order = memory_order::seq_cst) const noexcept;
integral fetch_<op>(integral, memory_order = memory_order::seq_cst) const noexcept;
...
};
}
For each <op>
in {shl, shr}
, add following public functions to [atomics.ref.int] specialization, immediately below fetch_xor
:
namespace std {
template <> struct atomic_ref<integral> {
...
integral fetch_<op>(const unsigned, memory_order = memory_order::seq_cst) const noexcept;
integral fetch_<op>(const unsigned, memory_order = memory_order::seq_cst) const noexcept;
...
};
}
For each <op>
in {mul, div}
, add following public functions to [atomics.ref.float] specialization, immediately below fetch_sub
:
namespace std {
template <> struct atomic_ref<floating-point> {
...
floating-point fetch_<op>(floating-point, memory_order = memory_order::seq_cst) const noexcept;
floating-point fetch_<op>(floating-point, memory_order = memory_order::seq_cst) const noexcept;
...
};
}
For each <op>
in {mod, nand, div, mul}
, add following public functions to [atomics.types.int] specialization, immediately below fetch_xor
:
namespace std {
template <> struct atomic<integral> {
...
integral fetch_<op>(integral, memory_order = memory_order::seq_cst) const noexcept;
integral fetch_<op>(integral, memory_order = memory_order::seq_cst) const noexcept;
...
};
}
For each <op>
in {shl, shr}
, add following public functions to [atomics.types.int] specialization, immediately below fetch_xor
:
namespace std {
template <> struct atomic<integral> {
...
integral fetch_<op>(const unsigned, memory_order = memory_order::seq_cst) const noexcept;
integral fetch_<op>(const unsigned, memory_order = memory_order::seq_cst) const noexcept;
...
};
}
For each <op>
in {mul, div}
, add following public functions to [atomics.types.float] specialization, immediately below fetch_sub
:
namespace std {
template <> struct atomic<floating-point> {
...
floating-point fetch_<op>(floating-point, memory_order = memory_order::seq_cst) const noexcept;
floating-point fetch_<op>(floating-point, memory_order success = memory_order::seq_cst) const noexcept;
...
};
}
Document number: P3306R0.
Date: 2024-5-21.
Authors: Gonzalo Brito Gadeschi, Damien Lebrun-Grandie.
Reply to: Gonzalo Brito Gadeschi <gonzalob _at_ nvidia.com>.
Audience: SG1, SG6.
Table of Contents
Atomic Read-Modify-Write Improvements
Extends read-modify-write atomic APIs with commonly requested functionality that is already available in some pre-existing implementations as an extension: integer shl, shr, mod, nand, div, mul, and floating-point div and mul.
Motivation
Without these extensions, users are required to implement this functionality by themselves on top of the atomic types, e.g., via user-specified CAS-loops. These loops complicate compiler optimizations and high-quality forward progress.
Design
The following APIs are commonly requested, and available in some implementations, like Kokkos atomic_fetch_<op> or Rust's Atomic:
These follow the same semantics as the scalar operations, e.g., in terms of what uses exhibit undefined or implementation-defined behavior.
Wording
Add feature test macro to
<version>
synopsis:Add following functions for
<op>
in{mod, nand, div, mul}
, immediately belowatomic_fetch_xor_explicit
:Add following functions for
<op>
in{shl, shr}
, immediately afterwards:Add following functions immediately afterwards:
Modify tab:atomic.types.int.comp as follows:
+
-
*
/
%
&
|
^
<<
>>
For each
<op>
in{mod, nand, div, mul}
, add following public functions to [atomics.ref.int] specialization, immediately belowfetch_xor
:For each
<op>
in{shl, shr}
, add following public functions to [atomics.ref.int] specialization, immediately belowfetch_xor
:For each
<op>
in{mul, div}
, add following public functions to [atomics.ref.float] specialization, immediately belowfetch_sub
:For each
<op>
in{mod, nand, div, mul}
, add following public functions to [atomics.types.int] specialization, immediately belowfetch_xor
:For each
<op>
in{shl, shr}
, add following public functions to [atomics.types.int] specialization, immediately belowfetch_xor
:For each
<op>
in{mul, div}
, add following public functions to [atomics.types.float] specialization, immediately belowfetch_sub
: