142ba740aSDamien L-G //
242ba740aSDamien L-G // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
342ba740aSDamien L-G // See https://llvm.org/LICENSE.txt for license information.
442ba740aSDamien L-G // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
542ba740aSDamien L-G //
642ba740aSDamien L-G //===----------------------------------------------------------------------===//
742ba740aSDamien L-G
842ba740aSDamien L-G // UNSUPPORTED: c++03, c++11, c++14, c++17
942ba740aSDamien L-G // XFAIL: !has-64-bit-atomics
1042ba740aSDamien L-G // XFAIL: !has-1024-bit-atomics
1142ba740aSDamien L-G
12*266fac83SStephan T. Lavavej // MSVC warning C4310: cast truncates constant value
13*266fac83SStephan T. Lavavej // ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4310
14*266fac83SStephan T. Lavavej
1542ba740aSDamien L-G // bool compare_exchange_strong(T&, T, memory_order, memory_order) const noexcept;
1642ba740aSDamien L-G // bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) const noexcept;
1742ba740aSDamien L-G
1842ba740aSDamien L-G #include <atomic>
1942ba740aSDamien L-G #include <cassert>
2042ba740aSDamien L-G #include <concepts>
2142ba740aSDamien L-G #include <type_traits>
2242ba740aSDamien L-G
2342ba740aSDamien L-G #include "atomic_helpers.h"
2442ba740aSDamien L-G #include "test_helper.h"
2542ba740aSDamien L-G #include "test_macros.h"
2642ba740aSDamien L-G
2742ba740aSDamien L-G template <typename T>
2842ba740aSDamien L-G struct TestCompareExchangeStrong {
operator ()TestCompareExchangeStrong2942ba740aSDamien L-G void operator()() const {
3042ba740aSDamien L-G {
3142ba740aSDamien L-G T x(T(1));
3242ba740aSDamien L-G std::atomic_ref<T> const a(x);
3342ba740aSDamien L-G
3442ba740aSDamien L-G T t(T(1));
3542ba740aSDamien L-G std::same_as<bool> decltype(auto) y = a.compare_exchange_strong(t, T(2));
3642ba740aSDamien L-G assert(y == true);
3742ba740aSDamien L-G assert(a == T(2));
3842ba740aSDamien L-G assert(t == T(1));
3942ba740aSDamien L-G y = a.compare_exchange_strong(t, T(3));
4042ba740aSDamien L-G assert(y == false);
4142ba740aSDamien L-G assert(a == T(2));
4242ba740aSDamien L-G assert(t == T(2));
4342ba740aSDamien L-G
4442ba740aSDamien L-G ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2)));
4542ba740aSDamien L-G }
4642ba740aSDamien L-G {
4742ba740aSDamien L-G T x(T(1));
4842ba740aSDamien L-G std::atomic_ref<T> const a(x);
4942ba740aSDamien L-G
5042ba740aSDamien L-G T t(T(1));
5142ba740aSDamien L-G std::same_as<bool> decltype(auto) y = a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst);
5242ba740aSDamien L-G assert(y == true);
5342ba740aSDamien L-G assert(a == T(2));
5442ba740aSDamien L-G assert(t == T(1));
5542ba740aSDamien L-G y = a.compare_exchange_strong(t, T(3), std::memory_order_seq_cst);
5642ba740aSDamien L-G assert(y == false);
5742ba740aSDamien L-G assert(a == T(2));
5842ba740aSDamien L-G assert(t == T(2));
5942ba740aSDamien L-G
6042ba740aSDamien L-G ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst));
6142ba740aSDamien L-G }
6242ba740aSDamien L-G {
6342ba740aSDamien L-G T x(T(1));
6442ba740aSDamien L-G std::atomic_ref<T> const a(x);
6542ba740aSDamien L-G
6642ba740aSDamien L-G T t(T(1));
6742ba740aSDamien L-G std::same_as<bool> decltype(auto) y =
6842ba740aSDamien L-G a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed);
6942ba740aSDamien L-G assert(y == true);
7042ba740aSDamien L-G assert(a == T(2));
7142ba740aSDamien L-G assert(t == T(1));
7242ba740aSDamien L-G y = a.compare_exchange_strong(t, T(3), std::memory_order_release, std::memory_order_relaxed);
7342ba740aSDamien L-G assert(y == false);
7442ba740aSDamien L-G assert(a == T(2));
7542ba740aSDamien L-G assert(t == T(2));
7642ba740aSDamien L-G
7742ba740aSDamien L-G ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed));
7842ba740aSDamien L-G }
7942ba740aSDamien L-G
8042ba740aSDamien L-G // success memory_order::release
8142ba740aSDamien L-G {
8242ba740aSDamien L-G auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
8342ba740aSDamien L-G auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::release, std::memory_order::relaxed);
8442ba740aSDamien L-G assert(r);
8542ba740aSDamien L-G };
8642ba740aSDamien L-G
8742ba740aSDamien L-G auto load = [](std::atomic_ref<T> const& x) { return x.load(std::memory_order::acquire); };
8842ba740aSDamien L-G test_acquire_release<T>(store, load);
8942ba740aSDamien L-G
9042ba740aSDamien L-G auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
9142ba740aSDamien L-G auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::release);
9242ba740aSDamien L-G assert(r);
9342ba740aSDamien L-G };
9442ba740aSDamien L-G test_acquire_release<T>(store_one_arg, load);
9542ba740aSDamien L-G }
9642ba740aSDamien L-G
9742ba740aSDamien L-G // success memory_order::acquire
9842ba740aSDamien L-G {
9942ba740aSDamien L-G auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
10042ba740aSDamien L-G
10142ba740aSDamien L-G auto load = [](std::atomic_ref<T> const& x) {
10242ba740aSDamien L-G auto val = x.load(std::memory_order::relaxed);
10342ba740aSDamien L-G while (!x.compare_exchange_strong(val, val, std::memory_order::acquire, std::memory_order::relaxed)) {
10442ba740aSDamien L-G }
10542ba740aSDamien L-G return val;
10642ba740aSDamien L-G };
10742ba740aSDamien L-G test_acquire_release<T>(store, load);
10842ba740aSDamien L-G
10942ba740aSDamien L-G auto load_one_arg = [](std::atomic_ref<T> const& x) {
11042ba740aSDamien L-G auto val = x.load(std::memory_order::relaxed);
11142ba740aSDamien L-G while (!x.compare_exchange_strong(val, val, std::memory_order::acquire)) {
11242ba740aSDamien L-G }
11342ba740aSDamien L-G return val;
11442ba740aSDamien L-G };
11542ba740aSDamien L-G test_acquire_release<T>(store, load_one_arg);
11642ba740aSDamien L-G }
11742ba740aSDamien L-G
11842ba740aSDamien L-G // success memory_order::acq_rel
11942ba740aSDamien L-G {
12042ba740aSDamien L-G auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
12142ba740aSDamien L-G auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::acq_rel, std::memory_order::relaxed);
12242ba740aSDamien L-G assert(r);
12342ba740aSDamien L-G };
12442ba740aSDamien L-G auto load = [](std::atomic_ref<T> const& x) {
12542ba740aSDamien L-G auto val = x.load(std::memory_order::relaxed);
12642ba740aSDamien L-G while (!x.compare_exchange_strong(val, val, std::memory_order::acq_rel, std::memory_order::relaxed)) {
12742ba740aSDamien L-G }
12842ba740aSDamien L-G return val;
12942ba740aSDamien L-G };
13042ba740aSDamien L-G test_acquire_release<T>(store, load);
13142ba740aSDamien L-G
13242ba740aSDamien L-G auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
13342ba740aSDamien L-G auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::acq_rel);
13442ba740aSDamien L-G assert(r);
13542ba740aSDamien L-G };
13642ba740aSDamien L-G auto load_one_arg = [](std::atomic_ref<T> const& x) {
13742ba740aSDamien L-G auto val = x.load(std::memory_order::relaxed);
13842ba740aSDamien L-G while (!x.compare_exchange_strong(val, val, std::memory_order::acq_rel)) {
13942ba740aSDamien L-G }
14042ba740aSDamien L-G return val;
14142ba740aSDamien L-G };
14242ba740aSDamien L-G test_acquire_release<T>(store_one_arg, load_one_arg);
14342ba740aSDamien L-G }
14442ba740aSDamien L-G
14542ba740aSDamien L-G // success memory_order::seq_cst
14642ba740aSDamien L-G {
14742ba740aSDamien L-G auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
14842ba740aSDamien L-G auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::seq_cst, std::memory_order::relaxed);
14942ba740aSDamien L-G assert(r);
15042ba740aSDamien L-G };
15142ba740aSDamien L-G auto load = [](std::atomic_ref<T> const& x) {
15242ba740aSDamien L-G auto val = x.load(std::memory_order::relaxed);
15342ba740aSDamien L-G while (!x.compare_exchange_strong(val, val, std::memory_order::seq_cst, std::memory_order::relaxed)) {
15442ba740aSDamien L-G }
15542ba740aSDamien L-G return val;
15642ba740aSDamien L-G };
15742ba740aSDamien L-G test_seq_cst<T>(store, load);
15842ba740aSDamien L-G
15942ba740aSDamien L-G auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
16042ba740aSDamien L-G auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::seq_cst);
16142ba740aSDamien L-G assert(r);
16242ba740aSDamien L-G };
16342ba740aSDamien L-G auto load_one_arg = [](std::atomic_ref<T> const& x) {
16442ba740aSDamien L-G auto val = x.load(std::memory_order::relaxed);
16542ba740aSDamien L-G while (!x.compare_exchange_strong(val, val, std::memory_order::seq_cst)) {
16642ba740aSDamien L-G }
16742ba740aSDamien L-G return val;
16842ba740aSDamien L-G };
16942ba740aSDamien L-G test_seq_cst<T>(store_one_arg, load_one_arg);
17042ba740aSDamien L-G }
17142ba740aSDamien L-G
17242ba740aSDamien L-G // failure memory_order::acquire
17342ba740aSDamien L-G {
17442ba740aSDamien L-G auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
17542ba740aSDamien L-G auto load = [](std::atomic_ref<T> const& x) {
17642ba740aSDamien L-G auto result = x.load(std::memory_order::relaxed);
17742ba740aSDamien L-G T unexpected(T(255));
17842ba740aSDamien L-G bool r =
17942ba740aSDamien L-G x.compare_exchange_strong(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::acquire);
18042ba740aSDamien L-G assert(!r);
18142ba740aSDamien L-G return result;
18242ba740aSDamien L-G };
18342ba740aSDamien L-G test_acquire_release<T>(store, load);
18442ba740aSDamien L-G
18542ba740aSDamien L-G auto load_one_arg = [](std::atomic_ref<T> const& x) {
18642ba740aSDamien L-G auto result = x.load(std::memory_order::relaxed);
18742ba740aSDamien L-G T unexpected(T(255));
18842ba740aSDamien L-G bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order::acquire);
18942ba740aSDamien L-G assert(!r);
19042ba740aSDamien L-G return result;
19142ba740aSDamien L-G };
19242ba740aSDamien L-G test_acquire_release<T>(store, load_one_arg);
19342ba740aSDamien L-G
19442ba740aSDamien L-G // acq_rel replaced by acquire
19542ba740aSDamien L-G auto load_one_arg_acq_rel = [](std::atomic_ref<T> const& x) {
19642ba740aSDamien L-G auto result = x.load(std::memory_order::relaxed);
19742ba740aSDamien L-G T unexpected(T(255));
19842ba740aSDamien L-G bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order::acq_rel);
19942ba740aSDamien L-G assert(!r);
20042ba740aSDamien L-G return result;
20142ba740aSDamien L-G };
20242ba740aSDamien L-G test_acquire_release<T>(store, load_one_arg_acq_rel);
20342ba740aSDamien L-G }
20442ba740aSDamien L-G
20542ba740aSDamien L-G // failure memory_order::seq_cst
20642ba740aSDamien L-G {
20742ba740aSDamien L-G auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::seq_cst); };
20842ba740aSDamien L-G auto load = [](std::atomic_ref<T> const& x) {
20942ba740aSDamien L-G auto result = x.load(std::memory_order::relaxed);
21042ba740aSDamien L-G T unexpected(T(255));
21142ba740aSDamien L-G bool r =
21242ba740aSDamien L-G x.compare_exchange_strong(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::seq_cst);
21342ba740aSDamien L-G assert(!r);
21442ba740aSDamien L-G return result;
21542ba740aSDamien L-G };
21642ba740aSDamien L-G test_seq_cst<T>(store, load);
21742ba740aSDamien L-G }
21842ba740aSDamien L-G }
21942ba740aSDamien L-G };
22042ba740aSDamien L-G
main(int,char **)22142ba740aSDamien L-G int main(int, char**) {
22242ba740aSDamien L-G TestEachAtomicType<TestCompareExchangeStrong>()();
22342ba740aSDamien L-G return 0;
22442ba740aSDamien L-G }
225