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 // bool compare_exchange_strong(T&, T, memory_order, memory_order) const noexcept; 13 // bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) const noexcept; 14 15 #include <atomic> 16 #include <cassert> 17 #include <concepts> 18 #include <type_traits> 19 20 #include "atomic_helpers.h" 21 #include "test_helper.h" 22 #include "test_macros.h" 23 24 template <typename T> 25 struct TestCompareExchangeStrong { 26 void operator()() const { 27 { 28 T x(T(1)); 29 std::atomic_ref<T> const a(x); 30 31 T t(T(1)); 32 std::same_as<bool> decltype(auto) y = a.compare_exchange_strong(t, T(2)); 33 assert(y == true); 34 assert(a == T(2)); 35 assert(t == T(1)); 36 y = a.compare_exchange_strong(t, T(3)); 37 assert(y == false); 38 assert(a == T(2)); 39 assert(t == T(2)); 40 41 ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2))); 42 } 43 { 44 T x(T(1)); 45 std::atomic_ref<T> const a(x); 46 47 T t(T(1)); 48 std::same_as<bool> decltype(auto) y = a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst); 49 assert(y == true); 50 assert(a == T(2)); 51 assert(t == T(1)); 52 y = a.compare_exchange_strong(t, T(3), std::memory_order_seq_cst); 53 assert(y == false); 54 assert(a == T(2)); 55 assert(t == T(2)); 56 57 ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst)); 58 } 59 { 60 T x(T(1)); 61 std::atomic_ref<T> const a(x); 62 63 T t(T(1)); 64 std::same_as<bool> decltype(auto) y = 65 a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed); 66 assert(y == true); 67 assert(a == T(2)); 68 assert(t == T(1)); 69 y = a.compare_exchange_strong(t, T(3), std::memory_order_release, std::memory_order_relaxed); 70 assert(y == false); 71 assert(a == T(2)); 72 assert(t == T(2)); 73 74 ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed)); 75 } 76 77 // success memory_order::release 78 { 79 auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) { 80 auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::release, std::memory_order::relaxed); 81 assert(r); 82 }; 83 84 auto load = [](std::atomic_ref<T> const& x) { return x.load(std::memory_order::acquire); }; 85 test_acquire_release<T>(store, load); 86 87 auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) { 88 auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::release); 89 assert(r); 90 }; 91 test_acquire_release<T>(store_one_arg, load); 92 } 93 94 // success memory_order::acquire 95 { 96 auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); }; 97 98 auto load = [](std::atomic_ref<T> const& x) { 99 auto val = x.load(std::memory_order::relaxed); 100 while (!x.compare_exchange_strong(val, val, std::memory_order::acquire, std::memory_order::relaxed)) { 101 } 102 return val; 103 }; 104 test_acquire_release<T>(store, load); 105 106 auto load_one_arg = [](std::atomic_ref<T> const& x) { 107 auto val = x.load(std::memory_order::relaxed); 108 while (!x.compare_exchange_strong(val, val, std::memory_order::acquire)) { 109 } 110 return val; 111 }; 112 test_acquire_release<T>(store, load_one_arg); 113 } 114 115 // success memory_order::acq_rel 116 { 117 auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) { 118 auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::acq_rel, std::memory_order::relaxed); 119 assert(r); 120 }; 121 auto load = [](std::atomic_ref<T> const& x) { 122 auto val = x.load(std::memory_order::relaxed); 123 while (!x.compare_exchange_strong(val, val, std::memory_order::acq_rel, std::memory_order::relaxed)) { 124 } 125 return val; 126 }; 127 test_acquire_release<T>(store, load); 128 129 auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) { 130 auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::acq_rel); 131 assert(r); 132 }; 133 auto load_one_arg = [](std::atomic_ref<T> const& x) { 134 auto val = x.load(std::memory_order::relaxed); 135 while (!x.compare_exchange_strong(val, val, std::memory_order::acq_rel)) { 136 } 137 return val; 138 }; 139 test_acquire_release<T>(store_one_arg, load_one_arg); 140 } 141 142 // success memory_order::seq_cst 143 { 144 auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) { 145 auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::seq_cst, std::memory_order::relaxed); 146 assert(r); 147 }; 148 auto load = [](std::atomic_ref<T> const& x) { 149 auto val = x.load(std::memory_order::relaxed); 150 while (!x.compare_exchange_strong(val, val, std::memory_order::seq_cst, std::memory_order::relaxed)) { 151 } 152 return val; 153 }; 154 test_seq_cst<T>(store, load); 155 156 auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) { 157 auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::seq_cst); 158 assert(r); 159 }; 160 auto load_one_arg = [](std::atomic_ref<T> const& x) { 161 auto val = x.load(std::memory_order::relaxed); 162 while (!x.compare_exchange_strong(val, val, std::memory_order::seq_cst)) { 163 } 164 return val; 165 }; 166 test_seq_cst<T>(store_one_arg, load_one_arg); 167 } 168 169 // failure memory_order::acquire 170 { 171 auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); }; 172 auto load = [](std::atomic_ref<T> const& x) { 173 auto result = x.load(std::memory_order::relaxed); 174 T unexpected(T(255)); 175 bool r = 176 x.compare_exchange_strong(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::acquire); 177 assert(!r); 178 return result; 179 }; 180 test_acquire_release<T>(store, load); 181 182 auto load_one_arg = [](std::atomic_ref<T> const& x) { 183 auto result = x.load(std::memory_order::relaxed); 184 T unexpected(T(255)); 185 bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order::acquire); 186 assert(!r); 187 return result; 188 }; 189 test_acquire_release<T>(store, load_one_arg); 190 191 // acq_rel replaced by acquire 192 auto load_one_arg_acq_rel = [](std::atomic_ref<T> const& x) { 193 auto result = x.load(std::memory_order::relaxed); 194 T unexpected(T(255)); 195 bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order::acq_rel); 196 assert(!r); 197 return result; 198 }; 199 test_acquire_release<T>(store, load_one_arg_acq_rel); 200 } 201 202 // failure memory_order::seq_cst 203 { 204 auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::seq_cst); }; 205 auto load = [](std::atomic_ref<T> const& x) { 206 auto result = x.load(std::memory_order::relaxed); 207 T unexpected(T(255)); 208 bool r = 209 x.compare_exchange_strong(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::seq_cst); 210 assert(!r); 211 return result; 212 }; 213 test_seq_cst<T>(store, load); 214 } 215 } 216 }; 217 218 int main(int, char**) { 219 TestEachAtomicType<TestCompareExchangeStrong>()(); 220 return 0; 221 } 222