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_strong(T&, T, memory_order, memory_order) const noexcept;
16 // bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) const noexcept;
17
18 #include <atomic>
19 #include <cassert>
20 #include <concepts>
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 TestCompareExchangeStrong {
operator ()TestCompareExchangeStrong29 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_strong(t, T(2));
36 assert(y == true);
37 assert(a == T(2));
38 assert(t == T(1));
39 y = a.compare_exchange_strong(t, T(3));
40 assert(y == false);
41 assert(a == T(2));
42 assert(t == T(2));
43
44 ASSERT_NOEXCEPT(a.compare_exchange_strong(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_strong(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_strong(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_strong(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_strong(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_strong(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_strong(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 auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::release, std::memory_order::relaxed);
84 assert(r);
85 };
86
87 auto load = [](std::atomic_ref<T> const& x) { return x.load(std::memory_order::acquire); };
88 test_acquire_release<T>(store, load);
89
90 auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
91 auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::release);
92 assert(r);
93 };
94 test_acquire_release<T>(store_one_arg, load);
95 }
96
97 // success memory_order::acquire
98 {
99 auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
100
101 auto load = [](std::atomic_ref<T> const& x) {
102 auto val = x.load(std::memory_order::relaxed);
103 while (!x.compare_exchange_strong(val, val, std::memory_order::acquire, std::memory_order::relaxed)) {
104 }
105 return val;
106 };
107 test_acquire_release<T>(store, load);
108
109 auto load_one_arg = [](std::atomic_ref<T> const& x) {
110 auto val = x.load(std::memory_order::relaxed);
111 while (!x.compare_exchange_strong(val, val, std::memory_order::acquire)) {
112 }
113 return val;
114 };
115 test_acquire_release<T>(store, load_one_arg);
116 }
117
118 // success memory_order::acq_rel
119 {
120 auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
121 auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::acq_rel, std::memory_order::relaxed);
122 assert(r);
123 };
124 auto load = [](std::atomic_ref<T> const& x) {
125 auto val = x.load(std::memory_order::relaxed);
126 while (!x.compare_exchange_strong(val, val, std::memory_order::acq_rel, std::memory_order::relaxed)) {
127 }
128 return val;
129 };
130 test_acquire_release<T>(store, load);
131
132 auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
133 auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::acq_rel);
134 assert(r);
135 };
136 auto load_one_arg = [](std::atomic_ref<T> const& x) {
137 auto val = x.load(std::memory_order::relaxed);
138 while (!x.compare_exchange_strong(val, val, std::memory_order::acq_rel)) {
139 }
140 return val;
141 };
142 test_acquire_release<T>(store_one_arg, load_one_arg);
143 }
144
145 // success memory_order::seq_cst
146 {
147 auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
148 auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::seq_cst, std::memory_order::relaxed);
149 assert(r);
150 };
151 auto load = [](std::atomic_ref<T> const& x) {
152 auto val = x.load(std::memory_order::relaxed);
153 while (!x.compare_exchange_strong(val, val, std::memory_order::seq_cst, std::memory_order::relaxed)) {
154 }
155 return val;
156 };
157 test_seq_cst<T>(store, load);
158
159 auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
160 auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::seq_cst);
161 assert(r);
162 };
163 auto load_one_arg = [](std::atomic_ref<T> const& x) {
164 auto val = x.load(std::memory_order::relaxed);
165 while (!x.compare_exchange_strong(val, val, std::memory_order::seq_cst)) {
166 }
167 return val;
168 };
169 test_seq_cst<T>(store_one_arg, load_one_arg);
170 }
171
172 // failure memory_order::acquire
173 {
174 auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
175 auto load = [](std::atomic_ref<T> const& x) {
176 auto result = x.load(std::memory_order::relaxed);
177 T unexpected(T(255));
178 bool r =
179 x.compare_exchange_strong(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::acquire);
180 assert(!r);
181 return result;
182 };
183 test_acquire_release<T>(store, load);
184
185 auto load_one_arg = [](std::atomic_ref<T> const& x) {
186 auto result = x.load(std::memory_order::relaxed);
187 T unexpected(T(255));
188 bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order::acquire);
189 assert(!r);
190 return result;
191 };
192 test_acquire_release<T>(store, load_one_arg);
193
194 // acq_rel replaced by acquire
195 auto load_one_arg_acq_rel = [](std::atomic_ref<T> const& x) {
196 auto result = x.load(std::memory_order::relaxed);
197 T unexpected(T(255));
198 bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order::acq_rel);
199 assert(!r);
200 return result;
201 };
202 test_acquire_release<T>(store, load_one_arg_acq_rel);
203 }
204
205 // failure memory_order::seq_cst
206 {
207 auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::seq_cst); };
208 auto load = [](std::atomic_ref<T> const& x) {
209 auto result = x.load(std::memory_order::relaxed);
210 T unexpected(T(255));
211 bool r =
212 x.compare_exchange_strong(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::seq_cst);
213 assert(!r);
214 return result;
215 };
216 test_seq_cst<T>(store, load);
217 }
218 }
219 };
220
main(int,char **)221 int main(int, char**) {
222 TestEachAtomicType<TestCompareExchangeStrong>()();
223 return 0;
224 }
225