[PATCH 7/8] libstdc++: Use new atomic fetch min/max builtins in std::atomic
soumyaa@nvidia.com
soumyaa@nvidia.com
Tue Sep 2 08:59:58 GMT 2025
From: Soumya AR <soumyaa@nvidia.com>
This patch enables libstdc++ to implement C++26's atomic min/max operations
through the newly added compiler builtins.
Similar to the __atomic_fetch_addable and __atomic_fetch_subtractable concepts,
we implement the following concepts for min/max operations:
__atomic_fetch_minable
__atomic_fetch_maxable
__atomic_min_fetchable
__atomic_max_fetchable
Is this naming scheme ok?
IMPORTANT: These functions are currently not guarded by a check for C++26. Would
appreciate comments on how we want that to be done in libstdc++.
Bootstrapped and regression tested on aarch64-linux-gnu and x86_64-linux-gnu.
Cross-compiled and regression tested for arm-linux-gnueabihf-armv7-a and
aarch64-linux-gnu without LSE.
Signed-off-by: Soumya AR <soumyaa@nvidia.com>
libstdc++-v3/ChangeLog:
* include/bits/atomic_base.h: Add fetch_max and fetch_min
member functions.
* include/std/atomic: Extend for atomic_fetch_max, atomic_fetch_min,
atomic_fetch_min_explicit, atomic_fetch_max_explicit.
* include/c_compatibility/stdatomic.h:
(atomic_fetch_max): Add using-declaration.
(atomic_fetch_max_explicit): Likewise.
(atomic_fetch_min): Likewise.
(atomic_fetch_min_explicit): Likewise.
* testsuite/29_atomics/atomic_integral/nonmembers.cc: Add tests
for non-member min/max functions.
* testsuite/29_atomics/atomic_ref/integral.cc: Extend for
min/max operations.
* testsuite/29_atomics/headers/stdatomic.h/c_compat.cc: Verify
C compatibility macros.
* testsuite/29_atomics/atomic_integral/fetch_minmax.cc: New test.
* testsuite/29_atomics/atomic_integral/fetch_minmax_order.cc: New test.
---
libstdc++-v3/include/bits/atomic_base.h | 156 ++++++++++++++++
.../include/c_compatibility/stdatomic.h | 4 +
libstdc++-v3/include/std/atomic | 52 ++++++
.../atomic_integral/fetch_minmax.cc | 168 ++++++++++++++++++
.../atomic_integral/fetch_minmax_order.cc | 116 ++++++++++++
.../29_atomics/atomic_integral/nonmembers.cc | 24 +++
.../29_atomics/atomic_ref/integral.cc | 51 +++++-
.../headers/stdatomic.h/c_compat.cc | 4 +
8 files changed, 573 insertions(+), 2 deletions(-)
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_integral/fetch_minmax.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_integral/fetch_minmax_order.cc
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 92d1269493f..eec65161584 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -674,6 +674,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
fetch_xor(__int_type __i,
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return __atomic_fetch_xor(&_M_i, __i, int(__m)); }
+
+ _GLIBCXX_ALWAYS_INLINE __int_type
+ fetch_min(__int_type __i,
+ memory_order __m = memory_order_seq_cst) noexcept
+ { return __atomic_fetch_min(&_M_i, __i, int(__m)); }
+
+ _GLIBCXX_ALWAYS_INLINE __int_type
+ fetch_min(__int_type __i,
+ memory_order __m = memory_order_seq_cst) volatile noexcept
+ { return __atomic_fetch_min(&_M_i, __i, int(__m)); }
+
+ _GLIBCXX_ALWAYS_INLINE __int_type
+ fetch_max(__int_type __i,
+ memory_order __m = memory_order_seq_cst) noexcept
+ { return __atomic_fetch_max(&_M_i, __i, int(__m)); }
+
+ _GLIBCXX_ALWAYS_INLINE __int_type
+ fetch_max(__int_type __i,
+ memory_order __m = memory_order_seq_cst) volatile noexcept
+ { return __atomic_fetch_max(&_M_i, __i, int(__m)); }
};
@@ -1183,6 +1203,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
fetch_xor(_Tp* __ptr, _Val<_Tp> __i, memory_order __m) noexcept
{ return __atomic_fetch_xor(__ptr, __i, int(__m)); }
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE _Tp
+ fetch_min(_Tp* __ptr, _Val<_Tp> __i, memory_order __m) noexcept
+ { return __atomic_fetch_min(__ptr, __i, int(__m)); }
+
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE _Tp
+ fetch_max(_Tp* __ptr, _Val<_Tp> __i, memory_order __m) noexcept
+ { return __atomic_fetch_max(__ptr, __i, int(__m)); }
+
template<typename _Tp>
_GLIBCXX_ALWAYS_INLINE _Tp
__add_fetch(_Tp* __ptr, _Diff<_Tp> __i) noexcept
@@ -1293,6 +1323,92 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __newval;
}
}
+
+ template<typename _Tp>
+ concept __atomic_fetch_minable
+ = requires (_Tp __t) { __atomic_fetch_min(&__t, __t, 0); };
+
+ template<typename _Tp>
+ _Tp
+ __fetch_min(_Tp* __ptr, _Val<_Tp> __i, memory_order __m) noexcept
+ {
+ if constexpr (__atomic_fetch_minable<_Tp>)
+ return __atomic_fetch_min(__ptr, __i, int(__m));
+ else
+ {
+ _Val<_Tp> __oldval = load (__ptr, memory_order_relaxed);
+ _Val<_Tp> __newval = __oldval < __i ? __oldval : __i;
+ while (!compare_exchange_weak (__ptr, __oldval, __newval, __m,
+ memory_order_relaxed))
+ __newval = __oldval < __i ? __oldval : __i;
+ return __oldval;
+ }
+ }
+
+ template<typename _Tp>
+ concept __atomic_fetch_maxable
+ = requires (_Tp __t) { __atomic_fetch_max(&__t, __t, 0); };
+
+ template<typename _Tp>
+ _Tp
+ __fetch_max(_Tp* __ptr, _Val<_Tp> __i, memory_order __m) noexcept
+ {
+ if constexpr (__atomic_fetch_maxable<_Tp>)
+ return __atomic_fetch_max(__ptr, __i, int(__m));
+ else
+ {
+ _Val<_Tp> __oldval = load (__ptr, memory_order_relaxed);
+ _Val<_Tp> __newval = __oldval > __i ? __oldval : __i;
+ while (!compare_exchange_weak (__ptr, __oldval, __newval, __m,
+ memory_order_relaxed))
+ __newval = __oldval > __i ? __oldval : __i;
+ return __oldval;
+ }
+ }
+
+ template<typename _Tp>
+ concept __atomic_min_fetchable
+ = requires (_Tp __t) { __atomic_min_fetch(&__t, __t, 0); };
+
+ template<typename _Tp>
+ _Tp
+ __min_fetch(_Tp* __ptr, _Val<_Tp> __i) noexcept
+ {
+ if constexpr (__atomic_min_fetchable<_Tp>)
+ return __atomic_min_fetch(__ptr, __i, __ATOMIC_SEQ_CST);
+ else
+ {
+ _Val<_Tp> __oldval = load (__ptr, memory_order_relaxed);
+ _Val<_Tp> __newval = __oldval < __i ? __oldval : __i;
+ while (!compare_exchange_weak (__ptr, __oldval, __newval,
+ memory_order_seq_cst,
+ memory_order_relaxed))
+ __newval = __oldval < __i ? __oldval : __i;
+ return __newval;
+ }
+ }
+
+ template<typename _Tp>
+ concept __atomic_max_fetchable
+ = requires (_Tp __t) { __atomic_max_fetch(&__t, __t, 0); };
+
+ template<typename _Tp>
+ _Tp
+ __max_fetch(_Tp* __ptr, _Val<_Tp> __i) noexcept
+ {
+ if constexpr (__atomic_max_fetchable<_Tp>)
+ return __atomic_max_fetch(__ptr, __i, __ATOMIC_SEQ_CST);
+ else
+ {
+ _Val<_Tp> __oldval = load (__ptr, memory_order_relaxed);
+ _Val<_Tp> __newval = __oldval > __i ? __oldval : __i;
+ while (!compare_exchange_weak (__ptr, __oldval, __newval,
+ memory_order_seq_cst,
+ memory_order_relaxed))
+ __newval = __oldval > __i ? __oldval : __i;
+ return __newval;
+ }
+ }
} // namespace __atomic_impl
// base class for atomic<floating-point-type>
@@ -1487,6 +1603,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return __atomic_impl::__fetch_sub_flt(&_M_fp, __i, __m); }
+ value_type
+ fetch_min(value_type __i,
+ memory_order __m = memory_order_seq_cst) noexcept
+ { return __atomic_impl::__fetch_min(&_M_fp, __i, __m); }
+
+ value_type
+ fetch_min(value_type __i,
+ memory_order __m = memory_order_seq_cst) volatile noexcept
+ { return __atomic_impl::__fetch_min(&_M_fp, __i, __m); }
+
+ value_type
+ fetch_max(value_type __i,
+ memory_order __m = memory_order_seq_cst) noexcept
+ { return __atomic_impl::__fetch_max(&_M_fp, __i, __m); }
+
+ value_type
+ fetch_max(value_type __i,
+ memory_order __m = memory_order_seq_cst) volatile noexcept
+ { return __atomic_impl::__fetch_max(&_M_fp, __i, __m); }
+
value_type
operator+=(value_type __i) noexcept
{ return __atomic_impl::__add_fetch_flt(&_M_fp, __i); }
@@ -1765,6 +1901,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
memory_order __m = memory_order_seq_cst) const noexcept
{ return __atomic_impl::fetch_xor(_M_ptr, __i, __m); }
+ value_type
+ fetch_min(value_type __i,
+ memory_order __m = memory_order_seq_cst) const noexcept
+ { return __atomic_impl::fetch_min(_M_ptr, __i, __m); }
+
+ value_type
+ fetch_max(value_type __i,
+ memory_order __m = memory_order_seq_cst) const noexcept
+ { return __atomic_impl::fetch_max(_M_ptr, __i, __m); }
+
_GLIBCXX_ALWAYS_INLINE value_type
operator++(int) const noexcept
{ return fetch_add(1); }
@@ -1925,6 +2071,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
memory_order __m = memory_order_seq_cst) const noexcept
{ return __atomic_impl::__fetch_sub_flt(_M_ptr, __i, __m); }
+ value_type
+ fetch_min(value_type __i,
+ memory_order __m = memory_order_seq_cst) const noexcept
+ { return __atomic_impl::__fetch_min(_M_ptr, __i, __m); }
+
+ value_type
+ fetch_max(value_type __i,
+ memory_order __m = memory_order_seq_cst) const noexcept
+ { return __atomic_impl::__fetch_max(_M_ptr, __i, __m); }
+
value_type
operator+=(value_type __i) const noexcept
{ return __atomic_impl::__add_fetch_flt(_M_ptr, __i); }
diff --git a/libstdc++-v3/include/c_compatibility/stdatomic.h b/libstdc++-v3/include/c_compatibility/stdatomic.h
index 72b9446eb17..177dd2f240e 100644
--- a/libstdc++-v3/include/c_compatibility/stdatomic.h
+++ b/libstdc++-v3/include/c_compatibility/stdatomic.h
@@ -118,6 +118,10 @@ using std::atomic_fetch_xor;
using std::atomic_fetch_xor_explicit;
using std::atomic_fetch_and;
using std::atomic_fetch_and_explicit;
+using std::atomic_fetch_min;
+using std::atomic_fetch_min_explicit;
+using std::atomic_fetch_max;
+using std::atomic_fetch_max_explicit;
using std::atomic_flag_test_and_set;
using std::atomic_flag_test_and_set_explicit;
using std::atomic_flag_clear;
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 9b1aca0fc09..4865df27aa1 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -1564,6 +1564,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
memory_order __m) noexcept
{ return __a->fetch_xor(__i, __m); }
+ template<typename _ITp>
+ inline _ITp
+ atomic_fetch_min_explicit(__atomic_base<_ITp>* __a,
+ __atomic_val_t<_ITp> __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,
+ 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,
+ 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,
+ memory_order __m) noexcept
+ { return __a->fetch_max(__i, __m); }
+
template<typename _ITp>
inline _ITp
atomic_fetch_add(atomic<_ITp>* __a,
@@ -1624,6 +1652,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__atomic_val_t<_ITp> __i) noexcept
{ return atomic_fetch_xor_explicit(__a, __i, memory_order_seq_cst); }
+ template<typename _ITp>
+ inline _ITp
+ atomic_fetch_min(__atomic_base<_ITp>* __a,
+ __atomic_val_t<_ITp> __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
+ { 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
+ { 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
+ { return atomic_fetch_max_explicit(__a, __i, memory_order_seq_cst); }
+
#ifdef __cpp_lib_atomic_float
template<>
struct atomic<float> : __atomic_float<float>
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/fetch_minmax.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/fetch_minmax.cc
new file mode 100644
index 00000000000..5293a349aaf
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/fetch_minmax.cc
@@ -0,0 +1,168 @@
+// Copyright The GNU Toolchain Authors.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++26 } }
+
+#include <atomic>
+#include <limits>
+#include <testsuite_hooks.h>
+
+template<typename T>
+void test_signed()
+{
+ std::atomic<T> a;
+ const std::memory_order mo = std::memory_order_relaxed;
+ T expected = 0;
+ T value = 0;
+
+ a.store(100);
+ value = a.fetch_min(50);
+ VERIFY( value == 100 );
+ VERIFY( a.load() == 50 );
+
+ value = a.fetch_min(75, mo);
+ VERIFY( value == 50 );
+ VERIFY( a.load() == 50 );
+
+ value = a.fetch_min(25);
+ VERIFY( value == 50 );
+ VERIFY( a.load() == 25 );
+
+ a.store(-10);
+ value = a.fetch_min(-20);
+ VERIFY( value == -10 );
+ VERIFY( a.load() == -20 );
+
+ value = a.fetch_min(-5, mo);
+ VERIFY( value == -20 );
+ VERIFY( a.load() == -20 );
+
+ a.store(10);
+ value = a.fetch_min(-5);
+ VERIFY( value == 10 );
+ VERIFY( a.load() == -5 );
+
+ a.store(20);
+ value = a.fetch_max(50);
+ VERIFY( value == 20 );
+ VERIFY( a.load() == 50 );
+
+ value = a.fetch_max(30, mo);
+ VERIFY( value == 50 );
+ VERIFY( a.load() == 50 );
+
+ value = a.fetch_max(100);
+ VERIFY( value == 50 );
+ VERIFY( a.load() == 100 );
+
+ a.store(-50);
+ value = a.fetch_max(-20);
+ VERIFY( value == -50 );
+ VERIFY( a.load() == -20 );
+
+ value = a.fetch_max(-10, mo);
+ VERIFY( value == -20 );
+ VERIFY( a.load() == -10 );
+
+ a.store(-10);
+ value = a.fetch_max(5);
+ VERIFY( value == -10 );
+ VERIFY( a.load() == 5 );
+
+ T min_val = std::numeric_limits<T>::min();
+ T max_val = std::numeric_limits<T>::max();
+
+ a.store(0);
+ value = a.fetch_min(min_val);
+ VERIFY( value == 0 );
+ VERIFY( a.load() == min_val );
+
+ a.store(0);
+ value = a.fetch_max(max_val);
+ VERIFY( value == 0 );
+ VERIFY( a.load() == max_val );
+}
+
+template<typename T>
+void test_unsigned()
+{
+ std::atomic<T> a;
+ const std::memory_order mo = std::memory_order_relaxed;
+ T expected = 0;
+ T value = 0;
+
+ a.store(100);
+ value = a.fetch_min(50);
+ VERIFY( value == 100 );
+ VERIFY( a.load() == 50 );
+
+ value = a.fetch_min(75, mo);
+ VERIFY( value == 50 );
+ VERIFY( a.load() == 50 );
+
+ value = a.fetch_min(25);
+ VERIFY( value == 50 );
+ VERIFY( a.load() == 25 );
+
+ a.store(20);
+ value = a.fetch_max(50);
+ VERIFY( value == 20 );
+ VERIFY( a.load() == 50 );
+
+ value = a.fetch_max(30, mo);
+ VERIFY( value == 50 );
+ VERIFY( a.load() == 50 );
+
+ value = a.fetch_max(100);
+ VERIFY( value == 50 );
+ VERIFY( a.load() == 100 );
+
+ T min_val = std::numeric_limits<T>::min();
+ T max_val = std::numeric_limits<T>::max();
+
+ a.store(10);
+ value = a.fetch_min(min_val);
+ VERIFY( value == 10 );
+ VERIFY( a.load() == min_val );
+
+ a.store(10);
+ value = a.fetch_max(max_val);
+ VERIFY( value == 10 );
+ VERIFY( a.load() == max_val );
+}
+
+int main()
+{
+ test_signed<signed char>();
+ test_signed<short>();
+ test_signed<int>();
+ test_signed<long>();
+ test_signed<long long>();
+
+ test_unsigned<unsigned char>();
+ test_unsigned<unsigned short>();
+ test_unsigned<unsigned int>();
+ test_unsigned<unsigned long>();
+ test_unsigned<unsigned long long>();
+
+ return 0;
+}
\ No newline at end of file
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/fetch_minmax_order.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/fetch_minmax_order.cc
new file mode 100644
index 00000000000..3ed6f2e2e6f
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/fetch_minmax_order.cc
@@ -0,0 +1,116 @@
+// Copyright The GNU Toolchain Authors.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++26 } }
+
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test_memory_orderings()
+{
+ std::atomic<int> a;
+ int v;
+
+ a.store(100);
+ v = a.fetch_min(50, std::memory_order_relaxed);
+ VERIFY( v == 100 );
+ VERIFY( a.load(std::memory_order_relaxed) == 50 );
+
+ a.store(100);
+ v = a.fetch_min(50, std::memory_order_consume);
+ VERIFY( v == 100 );
+ VERIFY( a.load() == 50 );
+
+ a.store(100);
+ v = a.fetch_min(50, std::memory_order_acquire);
+ VERIFY( v == 100 );
+ VERIFY( a.load() == 50 );
+
+ a.store(100);
+ v = a.fetch_min(50, std::memory_order_release);
+ VERIFY( v == 100 );
+ VERIFY( a.load() == 50 );
+
+ a.store(100);
+ v = a.fetch_min(50, std::memory_order_acq_rel);
+ VERIFY( v == 100 );
+ VERIFY( a.load() == 50 );
+
+ a.store(100);
+ v = a.fetch_min(50, std::memory_order_seq_cst);
+ VERIFY( v == 100 );
+ VERIFY( a.load() == 50 );
+
+ a.store(20);
+ v = a.fetch_max(50, std::memory_order_relaxed);
+ VERIFY( v == 20 );
+ VERIFY( a.load(std::memory_order_relaxed) == 50 );
+
+ a.store(20);
+ v = a.fetch_max(50, std::memory_order_consume);
+ VERIFY( v == 20 );
+ VERIFY( a.load() == 50 );
+
+ a.store(20);
+ v = a.fetch_max(50, std::memory_order_acquire);
+ VERIFY( v == 20 );
+ VERIFY( a.load() == 50 );
+
+ a.store(20);
+ v = a.fetch_max(50, std::memory_order_release);
+ VERIFY( v == 20 );
+ VERIFY( a.load() == 50 );
+
+ a.store(20);
+ v = a.fetch_max(50, std::memory_order_acq_rel);
+ VERIFY( v == 20 );
+ VERIFY( a.load() == 50 );
+
+ a.store(20);
+ v = a.fetch_max(50, std::memory_order_seq_cst);
+ VERIFY( v == 20 );
+ VERIFY( a.load() == 50 );
+}
+
+// Test volatile atomic operations
+void test_volatile()
+{
+ volatile std::atomic<int> va;
+ int v;
+
+ va.store(100);
+ v = va.fetch_min(50);
+ VERIFY( v == 100 );
+ VERIFY( va.load() == 50 );
+
+ va.store(20);
+ v = va.fetch_max(50, std::memory_order_relaxed);
+ VERIFY( v == 20 );
+ VERIFY( va.load() == 50 );
+}
+
+int main()
+{
+ test_memory_orderings();
+ test_volatile();
+ return 0;
+}
\ No newline at end of file
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/nonmembers.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/nonmembers.cc
index a07d9700ff4..3fb86db65b1 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_integral/nonmembers.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/nonmembers.cc
@@ -111,6 +111,22 @@ test01()
static_assert( std::is_same<decltype(r37), int>::value, "" );
auto r38 = atomic_fetch_xor_explicit(&a, l, mo);
static_assert( std::is_same<decltype(r38), long>::value, "" );
+ auto r39 = atomic_fetch_min(&v, i);
+ static_assert( std::is_same<decltype(r39), int>::value, "" );
+ auto r40 = atomic_fetch_min(&a, l);
+ static_assert( std::is_same<decltype(r40), long>::value, "" );
+ auto r41 = atomic_fetch_min_explicit(&v, i, mo);
+ static_assert( std::is_same<decltype(r41), int>::value, "" );
+ auto r42 = atomic_fetch_min_explicit(&a, l, mo);
+ static_assert( std::is_same<decltype(r42), long>::value, "" );
+ auto r43 = atomic_fetch_max(&v, i);
+ static_assert( std::is_same<decltype(r43), int>::value, "" );
+ auto r44 = atomic_fetch_max(&a, l);
+ static_assert( std::is_same<decltype(r44), long>::value, "" );
+ auto r45 = atomic_fetch_max_explicit(&v, i, mo);
+ static_assert( std::is_same<decltype(r45), int>::value, "" );
+ auto r46 = atomic_fetch_max_explicit(&a, l, mo);
+ static_assert( std::is_same<decltype(r46), long>::value, "" );
}
void
@@ -160,4 +176,12 @@ test02()
atomic_fetch_xor(&a, i);
atomic_fetch_xor_explicit(&v, i, mo);
atomic_fetch_xor_explicit(&a, i, mo);
+ atomic_fetch_min(&v, i);
+ atomic_fetch_min(&a, i);
+ atomic_fetch_min_explicit(&v, i, mo);
+ atomic_fetch_min_explicit(&a, i, mo);
+ atomic_fetch_max(&v, i);
+ atomic_fetch_max(&a, i);
+ atomic_fetch_max_explicit(&v, i, mo);
+ atomic_fetch_max_explicit(&a, i, mo);
}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/integral.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/integral.cc
index f6b68ebc598..d1ca1dc852c 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_ref/integral.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/integral.cc
@@ -155,9 +155,38 @@ test01()
v = a ^= 0x121;
VERIFY( v == 0x022 );
VERIFY( a == 0x022 );
+
+
+ a = 100;
+ v = a.fetch_min(50);
+ VERIFY( v == 100 );
+ VERIFY( a == 50 );
+
+ v = a.fetch_min(75, mo);
+ VERIFY( v == 50 );
+ VERIFY( a == 50 );
+
+ a = -10;
+ v = a.fetch_min(-20);
+ VERIFY( v == -10 );
+ VERIFY( a == -20 );
+
+ a = 20;
+ v = a.fetch_max(50);
+ VERIFY( v == 20 );
+ VERIFY( a == 50 );
+
+ v = a.fetch_max(30, mo);
+ VERIFY( v == 50 );
+ VERIFY( a == 50 );
+
+ a = -50;
+ v = a.fetch_max(-20);
+ VERIFY( v == -50 );
+ VERIFY( a == -20 );
}
- VERIFY( value == 0x022 );
+ VERIFY( value == -20 );
}
void
@@ -292,9 +321,27 @@ test02()
v = a ^= 0x12;
VERIFY( v == 0x24 );
VERIFY( a == 0x24 );
+
+ a = 100;
+ v = a.fetch_min(50);
+ VERIFY( v == 100 );
+ VERIFY( a == 50 );
+
+ v = a.fetch_min(75, mo);
+ VERIFY( v == 50 );
+ VERIFY( a == 50 );
+
+ a = 20;
+ v = a.fetch_max(50);
+ VERIFY( v == 20 );
+ VERIFY( a == 50 );
+
+ v = a.fetch_max(30, mo);
+ VERIFY( v == 50 );
+ VERIFY( a == 50 );
}
- VERIFY( value == 0x24 );
+ VERIFY( value == 50 );
}
void
test03()
diff --git a/libstdc++-v3/testsuite/29_atomics/headers/stdatomic.h/c_compat.cc b/libstdc++-v3/testsuite/29_atomics/headers/stdatomic.h/c_compat.cc
index bcdb969b0c0..2e4c73c456c 100644
--- a/libstdc++-v3/testsuite/29_atomics/headers/stdatomic.h/c_compat.cc
+++ b/libstdc++-v3/testsuite/29_atomics/headers/stdatomic.h/c_compat.cc
@@ -131,6 +131,10 @@ static_assert( requires (::atomic_int* i, int* e) {
::atomic_fetch_or_explicit(i, 1, memory_order_relaxed);
::atomic_fetch_xor(i, 1);
::atomic_fetch_xor_explicit(i, 1, memory_order_relaxed);
+ ::atomic_fetch_min(i, 1);
+ ::atomic_fetch_min_explicit(i, 1, memory_order_relaxed);
+ ::atomic_fetch_max(i, 1);
+ ::atomic_fetch_max_explicit(i, 1, memory_order_relaxed);
} );
static_assert( requires (::atomic_flag* f) {
--
2.44.0
More information about the Libstdc++
mailing list