1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // XFAIL: !has-64-bit-atomics |
10 | |
11 | // <atomic> |
12 | |
13 | // template <> |
14 | // struct atomic<integral> |
15 | // { |
16 | // bool is_lock_free() const volatile; |
17 | // bool is_lock_free() const; |
18 | // void store(integral desr, memory_order m = memory_order_seq_cst) volatile; |
19 | // void store(integral desr, memory_order m = memory_order_seq_cst); |
20 | // integral load(memory_order m = memory_order_seq_cst) const volatile; |
21 | // integral load(memory_order m = memory_order_seq_cst) const; |
22 | // operator integral() const volatile; |
23 | // operator integral() const; |
24 | // integral exchange(integral desr, |
25 | // memory_order m = memory_order_seq_cst) volatile; |
26 | // integral exchange(integral desr, memory_order m = memory_order_seq_cst); |
27 | // bool compare_exchange_weak(integral& expc, integral desr, |
28 | // memory_order s, memory_order f) volatile; |
29 | // bool compare_exchange_weak(integral& expc, integral desr, |
30 | // memory_order s, memory_order f); |
31 | // bool compare_exchange_strong(integral& expc, integral desr, |
32 | // memory_order s, memory_order f) volatile; |
33 | // bool compare_exchange_strong(integral& expc, integral desr, |
34 | // memory_order s, memory_order f); |
35 | // bool compare_exchange_weak(integral& expc, integral desr, |
36 | // memory_order m = memory_order_seq_cst) volatile; |
37 | // bool compare_exchange_weak(integral& expc, integral desr, |
38 | // memory_order m = memory_order_seq_cst); |
39 | // bool compare_exchange_strong(integral& expc, integral desr, |
40 | // memory_order m = memory_order_seq_cst) volatile; |
41 | // bool compare_exchange_strong(integral& expc, integral desr, |
42 | // memory_order m = memory_order_seq_cst); |
43 | // |
44 | // integral |
45 | // fetch_add(integral op, memory_order m = memory_order_seq_cst) volatile; |
46 | // integral fetch_add(integral op, memory_order m = memory_order_seq_cst); |
47 | // integral |
48 | // fetch_sub(integral op, memory_order m = memory_order_seq_cst) volatile; |
49 | // integral fetch_sub(integral op, memory_order m = memory_order_seq_cst); |
50 | // integral |
51 | // fetch_and(integral op, memory_order m = memory_order_seq_cst) volatile; |
52 | // integral fetch_and(integral op, memory_order m = memory_order_seq_cst); |
53 | // integral |
54 | // fetch_or(integral op, memory_order m = memory_order_seq_cst) volatile; |
55 | // integral fetch_or(integral op, memory_order m = memory_order_seq_cst); |
56 | // integral |
57 | // fetch_xor(integral op, memory_order m = memory_order_seq_cst) volatile; |
58 | // integral fetch_xor(integral op, memory_order m = memory_order_seq_cst); |
59 | // |
60 | // atomic() = default; |
61 | // constexpr atomic(integral desr); |
62 | // atomic(const atomic&) = delete; |
63 | // atomic& operator=(const atomic&) = delete; |
64 | // atomic& operator=(const atomic&) volatile = delete; |
65 | // integral operator=(integral desr) volatile; |
66 | // integral operator=(integral desr); |
67 | // |
68 | // integral operator++(int) volatile; |
69 | // integral operator++(int); |
70 | // integral operator--(int) volatile; |
71 | // integral operator--(int); |
72 | // integral operator++() volatile; |
73 | // integral operator++(); |
74 | // integral operator--() volatile; |
75 | // integral operator--(); |
76 | // integral operator+=(integral op) volatile; |
77 | // integral operator+=(integral op); |
78 | // integral operator-=(integral op) volatile; |
79 | // integral operator-=(integral op); |
80 | // integral operator&=(integral op) volatile; |
81 | // integral operator&=(integral op); |
82 | // integral operator|=(integral op) volatile; |
83 | // integral operator|=(integral op); |
84 | // integral operator^=(integral op) volatile; |
85 | // integral operator^=(integral op); |
86 | // }; |
87 | |
88 | #include <atomic> |
89 | #include <cassert> |
90 | #include <cstdint> |
91 | #include <new> |
92 | |
93 | #include <cmpxchg_loop.h> |
94 | |
95 | #include "test_macros.h" |
96 | |
97 | template <class A, class T> |
98 | void |
99 | do_test() |
100 | { |
101 | A obj(T(0)); |
102 | assert(obj == T(0)); |
103 | { |
104 | bool lockfree = obj.is_lock_free(); |
105 | (void)lockfree; |
106 | #if TEST_STD_VER >= 17 |
107 | if (A::is_always_lock_free) |
108 | assert(lockfree); |
109 | #endif |
110 | } |
111 | obj.store(T(0)); |
112 | assert(obj == T(0)); |
113 | obj.store(T(1), std::memory_order_release); |
114 | assert(obj == T(1)); |
115 | assert(obj.load() == T(1)); |
116 | assert(obj.load(std::memory_order_acquire) == T(1)); |
117 | assert(obj.exchange(T(2)) == T(1)); |
118 | assert(obj == T(2)); |
119 | assert(obj.exchange(T(3), std::memory_order_relaxed) == T(2)); |
120 | assert(obj == T(3)); |
121 | T x = obj; |
122 | assert(cmpxchg_weak_loop(obj, x, T(2)) == true); |
123 | assert(obj == T(2)); |
124 | assert(x == T(3)); |
125 | assert(obj.compare_exchange_weak(x, T(1)) == false); |
126 | assert(obj == T(2)); |
127 | assert(x == T(2)); |
128 | x = T(2); |
129 | assert(obj.compare_exchange_strong(x, T(1)) == true); |
130 | assert(obj == T(1)); |
131 | assert(x == T(2)); |
132 | assert(obj.compare_exchange_strong(x, T(0)) == false); |
133 | assert(obj == T(1)); |
134 | assert(x == T(1)); |
135 | assert((obj = T(0)) == T(0)); |
136 | assert(obj == T(0)); |
137 | assert(obj++ == T(0)); |
138 | assert(obj == T(1)); |
139 | assert(++obj == T(2)); |
140 | assert(obj == T(2)); |
141 | assert(--obj == T(1)); |
142 | assert(obj == T(1)); |
143 | assert(obj-- == T(1)); |
144 | assert(obj == T(0)); |
145 | obj = T(2); |
146 | assert((obj += T(3)) == T(5)); |
147 | assert(obj == T(5)); |
148 | assert((obj -= T(3)) == T(2)); |
149 | assert(obj == T(2)); |
150 | assert((obj |= T(5)) == T(7)); |
151 | assert(obj == T(7)); |
152 | assert((obj &= T(0xF)) == T(7)); |
153 | assert(obj == T(7)); |
154 | assert((obj ^= T(0xF)) == T(8)); |
155 | assert(obj == T(8)); |
156 | |
157 | { |
158 | TEST_ALIGNAS_TYPE(A) char storage[sizeof(A)] = {23}; |
159 | A& zero = *new (storage) A(); |
160 | assert(zero == 0); |
161 | zero.~A(); |
162 | } |
163 | } |
164 | |
165 | template <class A, class T> |
166 | void test() |
167 | { |
168 | do_test<A, T>(); |
169 | do_test<volatile A, T>(); |
170 | } |
171 | |
172 | |
173 | int main(int, char**) |
174 | { |
175 | test<std::atomic_char, char>(); |
176 | test<std::atomic_schar, signed char>(); |
177 | test<std::atomic_uchar, unsigned char>(); |
178 | test<std::atomic_short, short>(); |
179 | test<std::atomic_ushort, unsigned short>(); |
180 | test<std::atomic_int, int>(); |
181 | test<std::atomic_uint, unsigned int>(); |
182 | test<std::atomic_long, long>(); |
183 | test<std::atomic_ulong, unsigned long>(); |
184 | test<std::atomic_llong, long long>(); |
185 | test<std::atomic_ullong, unsigned long long>(); |
186 | #if TEST_STD_VER > 17 && defined(__cpp_char8_t) |
187 | test<std::atomic_char8_t, char8_t>(); |
188 | #endif |
189 | test<std::atomic_char16_t, char16_t>(); |
190 | test<std::atomic_char32_t, char32_t>(); |
191 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
192 | test<std::atomic_wchar_t, wchar_t>(); |
193 | #endif |
194 | |
195 | test<std::atomic_int8_t, int8_t>(); |
196 | test<std::atomic_uint8_t, uint8_t>(); |
197 | test<std::atomic_int16_t, int16_t>(); |
198 | test<std::atomic_uint16_t, uint16_t>(); |
199 | test<std::atomic_int32_t, int32_t>(); |
200 | test<std::atomic_uint32_t, uint32_t>(); |
201 | test<std::atomic_int64_t, int64_t>(); |
202 | test<std::atomic_uint64_t, uint64_t>(); |
203 | |
204 | test<volatile std::atomic_char, char>(); |
205 | test<volatile std::atomic_schar, signed char>(); |
206 | test<volatile std::atomic_uchar, unsigned char>(); |
207 | test<volatile std::atomic_short, short>(); |
208 | test<volatile std::atomic_ushort, unsigned short>(); |
209 | test<volatile std::atomic_int, int>(); |
210 | test<volatile std::atomic_uint, unsigned int>(); |
211 | test<volatile std::atomic_long, long>(); |
212 | test<volatile std::atomic_ulong, unsigned long>(); |
213 | test<volatile std::atomic_llong, long long>(); |
214 | test<volatile std::atomic_ullong, unsigned long long>(); |
215 | test<volatile std::atomic_char16_t, char16_t>(); |
216 | test<volatile std::atomic_char32_t, char32_t>(); |
217 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
218 | test<volatile std::atomic_wchar_t, wchar_t>(); |
219 | #endif |
220 | |
221 | test<volatile std::atomic_int8_t, int8_t>(); |
222 | test<volatile std::atomic_uint8_t, uint8_t>(); |
223 | test<volatile std::atomic_int16_t, int16_t>(); |
224 | test<volatile std::atomic_uint16_t, uint16_t>(); |
225 | test<volatile std::atomic_int32_t, int32_t>(); |
226 | test<volatile std::atomic_uint32_t, uint32_t>(); |
227 | test<volatile std::atomic_int64_t, int64_t>(); |
228 | test<volatile std::atomic_uint64_t, uint64_t>(); |
229 | |
230 | return 0; |
231 | } |
232 | |