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_weak(T&, T, memory_order, memory_order) const noexcept;
1642ba740aSDamien L-G // bool compare_exchange_weak(T&, T, memory_order = memory_order::seq_cst) const noexcept;
1742ba740aSDamien L-G
1842ba740aSDamien L-G #include <atomic>
1942ba740aSDamien L-G #include <concepts>
2042ba740aSDamien L-G #include <cassert>
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 TestCompareExchangeWeak {
operator ()TestCompareExchangeWeak2942ba740aSDamien 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_weak(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_weak(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_weak(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_weak(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_weak(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_weak(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_weak(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_weak(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_weak(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 // could fail spuriously, so put it in a loop
8442ba740aSDamien L-G while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::release, std::memory_order::relaxed)) {
8542ba740aSDamien L-G }
8642ba740aSDamien L-G };
8742ba740aSDamien L-G
8842ba740aSDamien L-G auto load = [](std::atomic_ref<T> const& x) { return x.load(std::memory_order::acquire); };
8942ba740aSDamien L-G test_acquire_release<T>(store, load);
9042ba740aSDamien L-G
9142ba740aSDamien L-G auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
9242ba740aSDamien L-G // could fail spuriously, so put it in a loop
9342ba740aSDamien L-G while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::release)) {
9442ba740aSDamien L-G }
9542ba740aSDamien L-G };
9642ba740aSDamien L-G test_acquire_release<T>(store_one_arg, load);
9742ba740aSDamien L-G }
9842ba740aSDamien L-G
9942ba740aSDamien L-G // success memory_order::acquire
10042ba740aSDamien L-G {
10142ba740aSDamien L-G auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
10242ba740aSDamien L-G auto load = [](std::atomic_ref<T> const& x) {
10342ba740aSDamien L-G auto val = x.load(std::memory_order::relaxed);
10442ba740aSDamien L-G while (!x.compare_exchange_weak(val, val, std::memory_order::acquire, std::memory_order::relaxed)) {
10542ba740aSDamien L-G }
10642ba740aSDamien L-G return val;
10742ba740aSDamien L-G };
10842ba740aSDamien L-G test_acquire_release<T>(store, load);
10942ba740aSDamien L-G
11042ba740aSDamien L-G auto load_one_arg = [](std::atomic_ref<T> const& x) {
11142ba740aSDamien L-G auto val = x.load(std::memory_order::relaxed);
11242ba740aSDamien L-G while (!x.compare_exchange_weak(val, val, std::memory_order::acquire)) {
11342ba740aSDamien L-G }
11442ba740aSDamien L-G return val;
11542ba740aSDamien L-G };
11642ba740aSDamien L-G test_acquire_release<T>(store, load_one_arg);
11742ba740aSDamien L-G }
11842ba740aSDamien L-G
11942ba740aSDamien L-G // success memory_order::acq_rel
12042ba740aSDamien L-G {
12142ba740aSDamien L-G auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
12242ba740aSDamien L-G // could fail spuriously, so put it in a loop
12342ba740aSDamien L-G while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::acq_rel, std::memory_order::relaxed)) {
12442ba740aSDamien L-G }
12542ba740aSDamien L-G };
12642ba740aSDamien L-G auto load = [](std::atomic_ref<T> const& x) {
12742ba740aSDamien L-G auto val = x.load(std::memory_order::relaxed);
12842ba740aSDamien L-G while (!x.compare_exchange_weak(val, val, std::memory_order::acq_rel, std::memory_order::relaxed)) {
12942ba740aSDamien L-G }
13042ba740aSDamien L-G return val;
13142ba740aSDamien L-G };
13242ba740aSDamien L-G test_acquire_release<T>(store, load);
13342ba740aSDamien L-G
13442ba740aSDamien L-G auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
13542ba740aSDamien L-G // could fail spuriously, so put it in a loop
13642ba740aSDamien L-G while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::acq_rel)) {
13742ba740aSDamien L-G }
13842ba740aSDamien L-G };
13942ba740aSDamien L-G auto load_one_arg = [](std::atomic_ref<T> const& x) {
14042ba740aSDamien L-G auto val = x.load(std::memory_order::relaxed);
14142ba740aSDamien L-G while (!x.compare_exchange_weak(val, val, std::memory_order::acq_rel)) {
14242ba740aSDamien L-G }
14342ba740aSDamien L-G return val;
14442ba740aSDamien L-G };
14542ba740aSDamien L-G test_acquire_release<T>(store_one_arg, load_one_arg);
14642ba740aSDamien L-G }
14742ba740aSDamien L-G
14842ba740aSDamien L-G // success memory_order::seq_cst
14942ba740aSDamien L-G {
15042ba740aSDamien L-G auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
15142ba740aSDamien L-G // could fail spuriously, so put it in a loop
15242ba740aSDamien L-G while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::seq_cst, std::memory_order::relaxed)) {
15342ba740aSDamien L-G }
15442ba740aSDamien L-G };
15542ba740aSDamien L-G auto load = [](std::atomic_ref<T> const& x) {
15642ba740aSDamien L-G auto val = x.load(std::memory_order::relaxed);
15742ba740aSDamien L-G while (!x.compare_exchange_weak(val, val, std::memory_order::seq_cst, std::memory_order::relaxed)) {
15842ba740aSDamien L-G }
15942ba740aSDamien L-G return val;
16042ba740aSDamien L-G };
16142ba740aSDamien L-G test_seq_cst<T>(store, load);
16242ba740aSDamien L-G
16342ba740aSDamien L-G auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
16442ba740aSDamien L-G // could fail spuriously, so put it in a loop
16542ba740aSDamien L-G while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::seq_cst)) {
16642ba740aSDamien L-G }
16742ba740aSDamien L-G };
16842ba740aSDamien L-G auto load_one_arg = [](std::atomic_ref<T> const& x) {
16942ba740aSDamien L-G auto val = x.load(std::memory_order::relaxed);
17042ba740aSDamien L-G while (!x.compare_exchange_weak(val, val, std::memory_order::seq_cst)) {
17142ba740aSDamien L-G }
17242ba740aSDamien L-G return val;
17342ba740aSDamien L-G };
17442ba740aSDamien L-G test_seq_cst<T>(store_one_arg, load_one_arg);
17542ba740aSDamien L-G }
17642ba740aSDamien L-G
17742ba740aSDamien L-G // failure memory_order::acquire
17842ba740aSDamien L-G {
17942ba740aSDamien L-G auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
18042ba740aSDamien L-G auto load = [](std::atomic_ref<T> const& x) {
18142ba740aSDamien L-G auto result = x.load(std::memory_order::relaxed);
18242ba740aSDamien L-G T unexpected(T(255));
18342ba740aSDamien L-G bool r =
18442ba740aSDamien L-G x.compare_exchange_weak(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::acquire);
18542ba740aSDamien L-G assert(!r);
18642ba740aSDamien L-G return result;
18742ba740aSDamien L-G };
18842ba740aSDamien L-G test_acquire_release<T>(store, load);
18942ba740aSDamien L-G
19042ba740aSDamien L-G auto load_one_arg = [](std::atomic_ref<T> const& x) {
19142ba740aSDamien L-G auto result = x.load(std::memory_order::relaxed);
19242ba740aSDamien L-G T unexpected(T(255));
19342ba740aSDamien L-G bool r = x.compare_exchange_weak(unexpected, unexpected, std::memory_order::acquire);
19442ba740aSDamien L-G assert(!r);
19542ba740aSDamien L-G return result;
19642ba740aSDamien L-G };
19742ba740aSDamien L-G test_acquire_release<T>(store, load_one_arg);
19842ba740aSDamien L-G
19942ba740aSDamien L-G // acq_rel replaced by acquire
20042ba740aSDamien L-G auto load_one_arg_acq_rel = [](std::atomic_ref<T> const& x) {
20142ba740aSDamien L-G auto result = x.load(std::memory_order::relaxed);
20242ba740aSDamien L-G T unexpected(T(255));
20342ba740aSDamien L-G bool r = x.compare_exchange_weak(unexpected, unexpected, std::memory_order::acq_rel);
20442ba740aSDamien L-G assert(!r);
20542ba740aSDamien L-G return result;
20642ba740aSDamien L-G };
20742ba740aSDamien L-G test_acquire_release<T>(store, load_one_arg_acq_rel);
20842ba740aSDamien L-G }
20942ba740aSDamien L-G
21042ba740aSDamien L-G // failure memory_order::seq_cst
21142ba740aSDamien L-G {
21242ba740aSDamien L-G auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::seq_cst); };
21342ba740aSDamien L-G auto load = [](std::atomic_ref<T> const& x) {
21442ba740aSDamien L-G auto result = x.load(std::memory_order::relaxed);
21542ba740aSDamien L-G T unexpected(T(255));
21642ba740aSDamien L-G bool r =
21742ba740aSDamien L-G x.compare_exchange_weak(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::seq_cst);
21842ba740aSDamien L-G assert(!r);
21942ba740aSDamien L-G return result;
22042ba740aSDamien L-G };
22142ba740aSDamien L-G test_seq_cst<T>(store, load);
22242ba740aSDamien L-G }
22342ba740aSDamien L-G }
22442ba740aSDamien L-G };
22542ba740aSDamien L-G
main(int,char **)22642ba740aSDamien L-G int main(int, char**) {
22742ba740aSDamien L-G TestEachAtomicType<TestCompareExchangeWeak>()();
22842ba740aSDamien L-G return 0;
22942ba740aSDamien L-G }
230