diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h index 79c1b31ccc4..6c5b83a0818 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 306667e3c63..3ec218afa09 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 - inline _ITp - atomic_fetch_min_explicit(__atomic_base<_ITp>* __a, - __atomic_val_t<_ITp> __i, + template + 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 - inline _ITp - atomic_fetch_min_explicit(volatile __atomic_base<_ITp>* __a, - __atomic_val_t<_ITp> __i, + template + 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 - inline _ITp - atomic_fetch_max_explicit(__atomic_base<_ITp>* __a, - __atomic_val_t<_ITp> __i, + template + 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 - inline _ITp - atomic_fetch_max_explicit(volatile __atomic_base<_ITp>* __a, - __atomic_val_t<_ITp> __i, + template + 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 - inline _ITp - atomic_fetch_min(__atomic_base<_ITp>* __a, - __atomic_val_t<_ITp> __i) noexcept + template + 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 - inline _ITp - atomic_fetch_min(volatile __atomic_base<_ITp>* __a, - __atomic_val_t<_ITp> __i) noexcept + template + 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 - inline _ITp - atomic_fetch_max(__atomic_base<_ITp>* __a, - __atomic_val_t<_ITp> __i) noexcept + template + 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 - inline _ITp - atomic_fetch_max(volatile __atomic_base<_ITp>* __a, - __atomic_val_t<_ITp> __i) noexcept + template + 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 00000000000..aca0c3157e0 --- /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 +#include + +void test01() { + long arr[10] = {}; + + const auto mo = std::memory_order_relaxed; + std::atomic 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 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 00000000000..25eef63ba99 --- /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 +#include + +void test01() { + long arr[10] = {}; + long *value; + + { + const auto mo = std::memory_order_relaxed; + std::atomic_ref a(value); + bool ok = a.is_lock_free(); + if constexpr (std::atomic_ref::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 a(value); + bool ok = a.is_lock_free(); + if constexpr (std::atomic_ref::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(); +}