1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7
8 // UNSUPPORTED: c++03, c++11, c++14, c++17
9 // XFAIL: !has-64-bit-atomics
10 // XFAIL: !has-1024-bit-atomics
11
12 // MSVC warning C4310: cast truncates constant value
13 // ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4310
14
15 // bool compare_exchange_weak(T&, T, memory_order, memory_order) const noexcept;
16 // bool compare_exchange_weak(T&, T, memory_order = memory_order::seq_cst) const noexcept;
17
18 #include <atomic>
19 #include <concepts>
20 #include <cassert>
21 #include <type_traits>
22
23 #include "atomic_helpers.h"
24 #include "test_helper.h"
25 #include "test_macros.h"
26
27 template <typename T>
28 struct TestCompareExchangeWeak {
operator ()TestCompareExchangeWeak29 void operator()() const {
30 {
31 T x(T(1));
32 std::atomic_ref<T> const a(x);
33
34 T t(T(1));
35 std::same_as<bool> decltype(auto) y = a.compare_exchange_weak(t, T(2));
36 assert(y == true);
37 assert(a == T(2));
38 assert(t == T(1));
39 y = a.compare_exchange_weak(t, T(3));
40 assert(y == false);
41 assert(a == T(2));
42 assert(t == T(2));
43
44 ASSERT_NOEXCEPT(a.compare_exchange_weak(t, T(2)));
45 }
46 {
47 T x(T(1));
48 std::atomic_ref<T> const a(x);
49
50 T t(T(1));
51 std::same_as<bool> decltype(auto) y = a.compare_exchange_weak(t, T(2), std::memory_order_seq_cst);
52 assert(y == true);
53 assert(a == T(2));
54 assert(t == T(1));
55 y = a.compare_exchange_weak(t, T(3), std::memory_order_seq_cst);
56 assert(y == false);
57 assert(a == T(2));
58 assert(t == T(2));
59
60 ASSERT_NOEXCEPT(a.compare_exchange_weak(t, T(2), std::memory_order_seq_cst));
61 }
62 {
63 T x(T(1));
64 std::atomic_ref<T> const a(x);
65
66 T t(T(1));
67 std::same_as<bool> decltype(auto) y =
68 a.compare_exchange_weak(t, T(2), std::memory_order_release, std::memory_order_relaxed);
69 assert(y == true);
70 assert(a == T(2));
71 assert(t == T(1));
72 y = a.compare_exchange_weak(t, T(3), std::memory_order_release, std::memory_order_relaxed);
73 assert(y == false);
74 assert(a == T(2));
75 assert(t == T(2));
76
77 ASSERT_NOEXCEPT(a.compare_exchange_weak(t, T(2), std::memory_order_release, std::memory_order_relaxed));
78 }
79
80 // success memory_order::release
81 {
82 auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
83 // could fail spuriously, so put it in a loop
84 while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::release, std::memory_order::relaxed)) {
85 }
86 };
87
88 auto load = [](std::atomic_ref<T> const& x) { return x.load(std::memory_order::acquire); };
89 test_acquire_release<T>(store, load);
90
91 auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
92 // could fail spuriously, so put it in a loop
93 while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::release)) {
94 }
95 };
96 test_acquire_release<T>(store_one_arg, load);
97 }
98
99 // success memory_order::acquire
100 {
101 auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
102 auto load = [](std::atomic_ref<T> const& x) {
103 auto val = x.load(std::memory_order::relaxed);
104 while (!x.compare_exchange_weak(val, val, std::memory_order::acquire, std::memory_order::relaxed)) {
105 }
106 return val;
107 };
108 test_acquire_release<T>(store, load);
109
110 auto load_one_arg = [](std::atomic_ref<T> const& x) {
111 auto val = x.load(std::memory_order::relaxed);
112 while (!x.compare_exchange_weak(val, val, std::memory_order::acquire)) {
113 }
114 return val;
115 };
116 test_acquire_release<T>(store, load_one_arg);
117 }
118
119 // success memory_order::acq_rel
120 {
121 auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
122 // could fail spuriously, so put it in a loop
123 while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::acq_rel, std::memory_order::relaxed)) {
124 }
125 };
126 auto load = [](std::atomic_ref<T> const& x) {
127 auto val = x.load(std::memory_order::relaxed);
128 while (!x.compare_exchange_weak(val, val, std::memory_order::acq_rel, std::memory_order::relaxed)) {
129 }
130 return val;
131 };
132 test_acquire_release<T>(store, load);
133
134 auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
135 // could fail spuriously, so put it in a loop
136 while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::acq_rel)) {
137 }
138 };
139 auto load_one_arg = [](std::atomic_ref<T> const& x) {
140 auto val = x.load(std::memory_order::relaxed);
141 while (!x.compare_exchange_weak(val, val, std::memory_order::acq_rel)) {
142 }
143 return val;
144 };
145 test_acquire_release<T>(store_one_arg, load_one_arg);
146 }
147
148 // success memory_order::seq_cst
149 {
150 auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
151 // could fail spuriously, so put it in a loop
152 while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::seq_cst, std::memory_order::relaxed)) {
153 }
154 };
155 auto load = [](std::atomic_ref<T> const& x) {
156 auto val = x.load(std::memory_order::relaxed);
157 while (!x.compare_exchange_weak(val, val, std::memory_order::seq_cst, std::memory_order::relaxed)) {
158 }
159 return val;
160 };
161 test_seq_cst<T>(store, load);
162
163 auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
164 // could fail spuriously, so put it in a loop
165 while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::seq_cst)) {
166 }
167 };
168 auto load_one_arg = [](std::atomic_ref<T> const& x) {
169 auto val = x.load(std::memory_order::relaxed);
170 while (!x.compare_exchange_weak(val, val, std::memory_order::seq_cst)) {
171 }
172 return val;
173 };
174 test_seq_cst<T>(store_one_arg, load_one_arg);
175 }
176
177 // failure memory_order::acquire
178 {
179 auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
180 auto load = [](std::atomic_ref<T> const& x) {
181 auto result = x.load(std::memory_order::relaxed);
182 T unexpected(T(255));
183 bool r =
184 x.compare_exchange_weak(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::acquire);
185 assert(!r);
186 return result;
187 };
188 test_acquire_release<T>(store, load);
189
190 auto load_one_arg = [](std::atomic_ref<T> const& x) {
191 auto result = x.load(std::memory_order::relaxed);
192 T unexpected(T(255));
193 bool r = x.compare_exchange_weak(unexpected, unexpected, std::memory_order::acquire);
194 assert(!r);
195 return result;
196 };
197 test_acquire_release<T>(store, load_one_arg);
198
199 // acq_rel replaced by acquire
200 auto load_one_arg_acq_rel = [](std::atomic_ref<T> const& x) {
201 auto result = x.load(std::memory_order::relaxed);
202 T unexpected(T(255));
203 bool r = x.compare_exchange_weak(unexpected, unexpected, std::memory_order::acq_rel);
204 assert(!r);
205 return result;
206 };
207 test_acquire_release<T>(store, load_one_arg_acq_rel);
208 }
209
210 // failure memory_order::seq_cst
211 {
212 auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::seq_cst); };
213 auto load = [](std::atomic_ref<T> const& x) {
214 auto result = x.load(std::memory_order::relaxed);
215 T unexpected(T(255));
216 bool r =
217 x.compare_exchange_weak(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::seq_cst);
218 assert(!r);
219 return result;
220 };
221 test_seq_cst<T>(store, load);
222 }
223 }
224 };
225
main(int,char **)226 int main(int, char**) {
227 TestEachAtomicType<TestCompareExchangeWeak>()();
228 return 0;
229 }
230