https://gcc.gnu.org/g:0772974fec9d1e35c412fc6fcbe9754c7cb57eb0
commit r16-7714-g0772974fec9d1e35c412fc6fcbe9754c7cb57eb0 Author: Yuao Ma <[email protected]> Date: Wed Feb 25 20:44:07 2026 +0800 libstdc++: complete P0493R5 with pointer support Previous implementations of fetch_min/max only supported integers, not handling pointers. To complete the paper, we need to implement support for pointers as well. This patch adds the missing functionality and test cases. libstdc++-v3/ChangeLog: * include/bits/atomic_base.h (__atomic_base<_PTp*>::fetch_min, __atomic_base<_PTp*>::fetch_max, __atomic_ref<_Pt, false, false, true>::fetch_min, __atomic_ref<_Pt, false, false, true>::fetch_max): Define new functions. * include/std/atomic (atomic<_Tp*>::fetch_min, atomic<_Tp*>::fetch_max): Likewise. (atomic_fetch_min_explicit, atomic_fetch_max_explicit, atomic_fetch_min, atomic_fetch_max): Change parameter from __atomic_base<_ITp>* to atomic<_Tp>*. * testsuite/29_atomics/atomic/pointer_fetch_minmax.cc: New test. * testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc: New test. Diff: --- libstdc++-v3/include/bits/atomic_base.h | 34 +++++++++ libstdc++-v3/include/std/atomic | 86 ++++++++++++++-------- .../29_atomics/atomic/pointer_fetch_minmax.cc | 53 +++++++++++++ .../29_atomics/atomic_ref/pointer_fetch_minmax.cc | 71 ++++++++++++++++++ 4 files changed, 212 insertions(+), 32 deletions(-) diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h index 79c1b31ccc41..6c5b83a08182 100644 --- a/libstdc++-v3/include/bits/atomic_base.h +++ b/libstdc++-v3/include/bits/atomic_base.h @@ -983,6 +983,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION fetch_sub(ptrdiff_t __d, memory_order __m = memory_order_seq_cst) volatile noexcept { return __atomic_fetch_sub(&_M_p, _S_type_size(__d), int(__m)); } + +#if __glibcxx_atomic_min_max + _GLIBCXX_ALWAYS_INLINE __pointer_type + fetch_min(__pointer_type __p, + memory_order __m = memory_order_seq_cst) noexcept + { return __atomic_impl::__fetch_min(&_M_p, __p, __m); } + + _GLIBCXX_ALWAYS_INLINE __pointer_type + fetch_min(__pointer_type __p, + memory_order __m = memory_order_seq_cst) volatile noexcept + { return __atomic_impl::__fetch_min(&_M_p, __p, __m); } + + _GLIBCXX_ALWAYS_INLINE __pointer_type + fetch_max(__pointer_type __p, + memory_order __m = memory_order_seq_cst) noexcept + { return __atomic_impl::__fetch_max(&_M_p, __p, __m); } + + _GLIBCXX_ALWAYS_INLINE __pointer_type + fetch_max(__pointer_type __p, + memory_order __m = memory_order_seq_cst) volatile noexcept + { return __atomic_impl::__fetch_max(&_M_p, __p, __m); } +#endif }; namespace __atomic_impl @@ -1976,6 +1998,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION memory_order __m = memory_order_seq_cst) const noexcept { return __atomic_impl::fetch_sub(this->_M_ptr, _S_type_size(__d), __m); } +#if __glibcxx_atomic_min_max + _GLIBCXX_ALWAYS_INLINE value_type + fetch_min(value_type __i, + memory_order __m = memory_order_seq_cst) const noexcept + { return __atomic_impl::__fetch_min(this->_M_ptr, __i, __m); } + + _GLIBCXX_ALWAYS_INLINE value_type + fetch_max(value_type __i, + memory_order __m = memory_order_seq_cst) const noexcept + { return __atomic_impl::__fetch_max(this->_M_ptr, __i, __m); } +#endif + value_type operator++(int) const noexcept { return fetch_add(1); } diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic index 306667e3c633..3ec218afa096 100644 --- a/libstdc++-v3/include/std/atomic +++ b/libstdc++-v3/include/std/atomic @@ -718,6 +718,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif return _M_b.fetch_sub(__d, __m); } + +#if __glibcxx_atomic_min_max + __pointer_type + fetch_min(__pointer_type __p, + memory_order __m = memory_order_seq_cst) noexcept + { return _M_b.fetch_min(__p, __m); } + + __pointer_type + fetch_min(__pointer_type __p, + memory_order __m = memory_order_seq_cst) volatile noexcept + { return _M_b.fetch_min(__p, __m); } + + __pointer_type + fetch_max(__pointer_type __p, + memory_order __m = memory_order_seq_cst) noexcept + { return _M_b.fetch_max(__p, __m); } + + __pointer_type + fetch_max(__pointer_type __p, + memory_order __m = memory_order_seq_cst) volatile noexcept + { return _M_b.fetch_max(__p, __m); } +#endif }; @@ -1574,31 +1596,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __a->fetch_xor(__i, __m); } #ifdef __cpp_lib_atomic_min_max - template<typename _ITp> - inline _ITp - atomic_fetch_min_explicit(__atomic_base<_ITp>* __a, - __atomic_val_t<_ITp> __i, + template<typename _Tp> + inline _Tp + atomic_fetch_min_explicit(atomic<_Tp>* __a, + __atomic_val_t<_Tp> __i, memory_order __m) noexcept { return __a->fetch_min(__i, __m); } - template<typename _ITp> - inline _ITp - atomic_fetch_min_explicit(volatile __atomic_base<_ITp>* __a, - __atomic_val_t<_ITp> __i, + template<typename _Tp> + inline _Tp + atomic_fetch_min_explicit(volatile atomic<_Tp>* __a, + __atomic_val_t<_Tp> __i, memory_order __m) noexcept { return __a->fetch_min(__i, __m); } - template<typename _ITp> - inline _ITp - atomic_fetch_max_explicit(__atomic_base<_ITp>* __a, - __atomic_val_t<_ITp> __i, + template<typename _Tp> + inline _Tp + atomic_fetch_max_explicit(atomic<_Tp>* __a, + __atomic_val_t<_Tp> __i, memory_order __m) noexcept { return __a->fetch_max(__i, __m); } - template<typename _ITp> - inline _ITp - atomic_fetch_max_explicit(volatile __atomic_base<_ITp>* __a, - __atomic_val_t<_ITp> __i, + template<typename _Tp> + inline _Tp + atomic_fetch_max_explicit(volatile atomic<_Tp>* __a, + __atomic_val_t<_Tp> __i, memory_order __m) noexcept { return __a->fetch_max(__i, __m); } #endif @@ -1664,28 +1686,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return atomic_fetch_xor_explicit(__a, __i, memory_order_seq_cst); } #ifdef __cpp_lib_atomic_min_max - template<typename _ITp> - inline _ITp - atomic_fetch_min(__atomic_base<_ITp>* __a, - __atomic_val_t<_ITp> __i) noexcept + template<typename _Tp> + inline _Tp + atomic_fetch_min(atomic<_Tp>* __a, + __atomic_val_t<_Tp> __i) noexcept { return atomic_fetch_min_explicit(__a, __i, memory_order_seq_cst); } - template<typename _ITp> - inline _ITp - atomic_fetch_min(volatile __atomic_base<_ITp>* __a, - __atomic_val_t<_ITp> __i) noexcept + template<typename _Tp> + inline _Tp + atomic_fetch_min(volatile atomic<_Tp>* __a, + __atomic_val_t<_Tp> __i) noexcept { return atomic_fetch_min_explicit(__a, __i, memory_order_seq_cst); } - template<typename _ITp> - inline _ITp - atomic_fetch_max(__atomic_base<_ITp>* __a, - __atomic_val_t<_ITp> __i) noexcept + template<typename _Tp> + inline _Tp + atomic_fetch_max(atomic<_Tp>* __a, + __atomic_val_t<_Tp> __i) noexcept { return atomic_fetch_max_explicit(__a, __i, memory_order_seq_cst); } - template<typename _ITp> - inline _ITp - atomic_fetch_max(volatile __atomic_base<_ITp>* __a, - __atomic_val_t<_ITp> __i) noexcept + template<typename _Tp> + inline _Tp + atomic_fetch_max(volatile atomic<_Tp>* __a, + __atomic_val_t<_Tp> __i) noexcept { return atomic_fetch_max_explicit(__a, __i, memory_order_seq_cst); } #endif diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/pointer_fetch_minmax.cc b/libstdc++-v3/testsuite/29_atomics/atomic/pointer_fetch_minmax.cc new file mode 100644 index 000000000000..aca0c3157e0c --- /dev/null +++ b/libstdc++-v3/testsuite/29_atomics/atomic/pointer_fetch_minmax.cc @@ -0,0 +1,53 @@ +// { dg-do run { target c++26 } } +// { dg-require-atomic-cmpxchg-word "" } +// { dg-add-options libatomic } + +#include <atomic> +#include <testsuite_hooks.h> + +void test01() { + long arr[10] = {}; + + const auto mo = std::memory_order_relaxed; + std::atomic<long *> a(arr); + + auto v = atomic_fetch_max(&a, arr + 5); + VERIFY(v == arr); + VERIFY(a == arr + 5); + v = atomic_fetch_max_explicit(&a, arr + 2, mo); + VERIFY(v == arr + 5); + VERIFY(a == arr + 5); + + v = atomic_fetch_min(&a, arr + 3); + VERIFY(v == arr + 5); + VERIFY(a == arr + 3); + v = atomic_fetch_min_explicit(&a, arr + 5, mo); + VERIFY(v == arr + 3); + VERIFY(a == arr + 3); +} + +void test02() { + char arr[10] = {}; + + const auto mo = std::memory_order_relaxed; + std::atomic<char *> a(arr); + + auto v = atomic_fetch_max(&a, arr + 5); + VERIFY(v == arr); + VERIFY(a == arr + 5); + v = atomic_fetch_max_explicit(&a, arr + 2, mo); + VERIFY(v == arr + 5); + VERIFY(a == arr + 5); + + v = atomic_fetch_min(&a, arr + 3); + VERIFY(v == arr + 5); + VERIFY(a == arr + 3); + v = atomic_fetch_min_explicit(&a, arr + 5, mo); + VERIFY(v == arr + 3); + VERIFY(a == arr + 3); +} + +int main() { + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc new file mode 100644 index 000000000000..25eef63ba992 --- /dev/null +++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc @@ -0,0 +1,71 @@ +// { dg-do run { target c++26 } } +// { dg-require-atomic-cmpxchg-word "" } +// { dg-add-options libatomic } + +#include <atomic> +#include <testsuite_hooks.h> + +void test01() { + long arr[10] = {}; + long *value; + + { + const auto mo = std::memory_order_relaxed; + std::atomic_ref<long *> a(value); + bool ok = a.is_lock_free(); + if constexpr (std::atomic_ref<long *>::is_always_lock_free) + VERIFY(ok); + a = arr; + + auto v = a.fetch_max(arr + 5); + VERIFY(v == arr); + VERIFY(a == arr + 5); + v = a.fetch_max(arr + 2, mo); + VERIFY(v == arr + 5); + VERIFY(a == arr + 5); + + v = a.fetch_min(arr + 3); + VERIFY(v == arr + 5); + VERIFY(a == arr + 3); + v = a.fetch_min(arr + 5, mo); + VERIFY(v == arr + 3); + VERIFY(a == arr + 3); + } + + VERIFY(value == arr + 3); +} + +void test02() { + char arr[10] = {}; + char *value; + + { + const auto mo = std::memory_order_relaxed; + std::atomic_ref<char *> a(value); + bool ok = a.is_lock_free(); + if constexpr (std::atomic_ref<char *>::is_always_lock_free) + VERIFY(ok); + a = arr; + + auto v = a.fetch_max(arr + 5); + VERIFY(v == arr); + VERIFY(a == arr + 5); + v = a.fetch_max(arr + 2, mo); + VERIFY(v == arr + 5); + VERIFY(a == arr + 5); + + v = a.fetch_min(arr + 3); + VERIFY(v == arr + 5); + VERIFY(a == arr + 3); + v = a.fetch_min(arr + 5, mo); + VERIFY(v == arr + 3); + VERIFY(a == arr + 3); + } + + VERIFY(value == arr + 3); +} + +int main() { + test01(); + test02(); +}
