mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 14:59:39 +02:00
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.
This commit is contained in:
@@ -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); }
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user