1// RUN: %clang_builtins %s %librt -o %t && %run %t
2// REQUIRES: librt_has_atomic
3//===-- atomic_test.c - Test support functions for atomic operations ------===//
4//
5// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6// See https://llvm.org/LICENSE.txt for license information.
7// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8//
9//===----------------------------------------------------------------------===//
10//
11// This file performs some simple testing of the support functions for the
12// atomic builtins. All tests are single-threaded, so this is only a sanity
13// check.
14//
15//===----------------------------------------------------------------------===//
16
17#include <stdbool.h>
18#include <stdint.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#undef NDEBUG
23#include <assert.h>
24
25// We directly test the library atomic functions, not using the C builtins. This
26// should avoid confounding factors, ensuring that we actually test the
27// functions themselves, regardless of how the builtins are lowered. We need to
28// use asm labels because we can't redeclare the builtins.
29// Note: we need to prepend an underscore to this name for e.g. macOS.
30#define _STRINGIFY(x) #x
31#define STRINGIFY(x) _STRINGIFY(x)
32#define EXTERNAL_NAME(name) asm(STRINGIFY(__USER_LABEL_PREFIX__) #name)
33
34bool __atomic_is_lock_free_c(size_t size, void *ptr)
35 EXTERNAL_NAME(__atomic_is_lock_free);
36
37void __atomic_load_c(int size, void *src, void *dest,
38 int model) EXTERNAL_NAME(__atomic_load);
39
40uint8_t __atomic_load_1(uint8_t *src, int model);
41uint16_t __atomic_load_2(uint16_t *src, int model);
42uint32_t __atomic_load_4(uint32_t *src, int model);
43uint64_t __atomic_load_8(uint64_t *src, int model);
44
45void __atomic_store_c(int size, void *dest, const void *src,
46 int model) EXTERNAL_NAME(__atomic_store);
47
48void __atomic_store_1(uint8_t *dest, uint8_t val, int model);
49void __atomic_store_2(uint16_t *dest, uint16_t val, int model);
50void __atomic_store_4(uint32_t *dest, uint32_t val, int model);
51void __atomic_store_8(uint64_t *dest, uint64_t val, int model);
52
53void __atomic_exchange_c(int size, void *ptr, const void *val, void *old,
54 int model) EXTERNAL_NAME(__atomic_exchange);
55
56uint8_t __atomic_exchange_1(uint8_t *dest, uint8_t val, int model);
57uint16_t __atomic_exchange_2(uint16_t *dest, uint16_t val, int model);
58uint32_t __atomic_exchange_4(uint32_t *dest, uint32_t val, int model);
59uint64_t __atomic_exchange_8(uint64_t *dest, uint64_t val, int model);
60
61int __atomic_compare_exchange_c(int size, void *ptr, void *expected,
62 const void *desired, int success, int failure)
63 EXTERNAL_NAME(__atomic_compare_exchange);
64
65bool __atomic_compare_exchange_1(uint8_t *ptr, uint8_t *expected,
66 uint8_t desired, int success, int failure);
67bool __atomic_compare_exchange_2(uint16_t *ptr, uint16_t *expected,
68 uint16_t desired, int success, int failure);
69bool __atomic_compare_exchange_4(uint32_t *ptr, uint32_t *expected,
70 uint32_t desired, int success, int failure);
71bool __atomic_compare_exchange_8(uint64_t *ptr, uint64_t *expected,
72 uint64_t desired, int success, int failure);
73
74uint8_t __atomic_fetch_add_1(uint8_t *ptr, uint8_t val, int model);
75uint16_t __atomic_fetch_add_2(uint16_t *ptr, uint16_t val, int model);
76uint32_t __atomic_fetch_add_4(uint32_t *ptr, uint32_t val, int model);
77uint64_t __atomic_fetch_add_8(uint64_t *ptr, uint64_t val, int model);
78
79uint8_t __atomic_fetch_sub_1(uint8_t *ptr, uint8_t val, int model);
80uint16_t __atomic_fetch_sub_2(uint16_t *ptr, uint16_t val, int model);
81uint32_t __atomic_fetch_sub_4(uint32_t *ptr, uint32_t val, int model);
82uint64_t __atomic_fetch_sub_8(uint64_t *ptr, uint64_t val, int model);
83
84uint8_t __atomic_fetch_and_1(uint8_t *ptr, uint8_t val, int model);
85uint16_t __atomic_fetch_and_2(uint16_t *ptr, uint16_t val, int model);
86uint32_t __atomic_fetch_and_4(uint32_t *ptr, uint32_t val, int model);
87uint64_t __atomic_fetch_and_8(uint64_t *ptr, uint64_t val, int model);
88
89uint8_t __atomic_fetch_or_1(uint8_t *ptr, uint8_t val, int model);
90uint16_t __atomic_fetch_or_2(uint16_t *ptr, uint16_t val, int model);
91uint32_t __atomic_fetch_or_4(uint32_t *ptr, uint32_t val, int model);
92uint64_t __atomic_fetch_or_8(uint64_t *ptr, uint64_t val, int model);
93
94uint8_t __atomic_fetch_xor_1(uint8_t *ptr, uint8_t val, int model);
95uint16_t __atomic_fetch_xor_2(uint16_t *ptr, uint16_t val, int model);
96uint32_t __atomic_fetch_xor_4(uint32_t *ptr, uint32_t val, int model);
97uint64_t __atomic_fetch_xor_8(uint64_t *ptr, uint64_t val, int model);
98
99// We conditionally test the *_16 atomic function variants based on the same
100// condition that compiler_rt (atomic.c) uses to conditionally generate them.
101// Currently atomic.c tests if __SIZEOF_INT128__ is defined (which can be the
102// case on 32-bit platforms, by using -fforce-enable-int128), instead of using
103// CRT_HAS_128BIT.
104
105#ifdef __SIZEOF_INT128__
106#define TEST_16
107#endif
108
109#ifdef TEST_16
110typedef __uint128_t uint128_t;
111typedef uint128_t maxuint_t;
112uint128_t __atomic_load_16(uint128_t *src, int model);
113void __atomic_store_16(uint128_t *dest, uint128_t val, int model);
114uint128_t __atomic_exchange_16(uint128_t *dest, uint128_t val, int model);
115bool __atomic_compare_exchange_16(uint128_t *ptr, uint128_t *expected,
116 uint128_t desired, int success, int failure);
117uint128_t __atomic_fetch_add_16(uint128_t *ptr, uint128_t val, int model);
118uint128_t __atomic_fetch_sub_16(uint128_t *ptr, uint128_t val, int model);
119uint128_t __atomic_fetch_and_16(uint128_t *ptr, uint128_t val, int model);
120uint128_t __atomic_fetch_or_16(uint128_t *ptr, uint128_t val, int model);
121uint128_t __atomic_fetch_xor_16(uint128_t *ptr, uint128_t val, int model);
122#else
123typedef uint64_t maxuint_t;
124#endif
125
126#define U8(value) ((uint8_t)(value))
127#define U16(value) ((uint16_t)(value))
128#define U32(value) ((uint32_t)(value))
129#define U64(value) ((uint64_t)(value))
130
131#ifdef TEST_16
132#define V ((((uint128_t)0x4243444546474849) << 64) | 0x4a4b4c4d4e4f5051)
133#define ONES ((((uint128_t)0x0101010101010101) << 64) | 0x0101010101010101)
134#else
135#define V 0x4243444546474849
136#define ONES 0x0101010101010101
137#endif
138
139#define LEN(array) (sizeof(array) / sizeof(array[0]))
140
141__attribute__((aligned(16))) static const char data[] = {
142 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
143 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
144 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
145 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
146};
147
148uint8_t a8, b8;
149uint16_t a16, b16;
150uint32_t a32, b32;
151uint64_t a64, b64;
152#ifdef TEST_16
153uint128_t a128, b128;
154#endif
155
156void set_a_values(maxuint_t value) {
157 a8 = U8(value);
158 a16 = U16(value);
159 a32 = U32(value);
160 a64 = U64(value);
161#ifdef TEST_16
162 a128 = value;
163#endif
164}
165
166void set_b_values(maxuint_t value) {
167 b8 = U8(value);
168 b16 = U16(value);
169 b32 = U32(value);
170 b64 = U64(value);
171#ifdef TEST_16
172 b128 = value;
173#endif
174}
175
176void test_loads(void) {
177 static int atomic_load_models[] = {
178 __ATOMIC_RELAXED,
179 __ATOMIC_CONSUME,
180 __ATOMIC_ACQUIRE,
181 __ATOMIC_SEQ_CST,
182 };
183
184 for (int m = 0; m < LEN(atomic_load_models); m++) {
185 int model = atomic_load_models[m];
186
187 // Test with aligned data.
188 for (int n = 1; n <= LEN(data); n++) {
189 __attribute__((aligned(16))) char dst[LEN(data)] = {0};
190 __atomic_load_c(n, data, dst, model);
191 if (memcmp(dst, data, n) != 0)
192 abort();
193 }
194
195 // Test with unaligned data.
196 for (int n = 1; n < LEN(data); n++) {
197 __attribute__((aligned(16))) char dst[LEN(data)] = {0};
198 __atomic_load_c(n, data + 1, dst + 1, model);
199 if (memcmp(dst + 1, data + 1, n) != 0)
200 abort();
201 }
202
203 set_a_values(V + m);
204 if (__atomic_load_1(&a8, model) != U8(V + m))
205 abort();
206 if (__atomic_load_2(&a16, model) != U16(V + m))
207 abort();
208 if (__atomic_load_4(&a32, model) != U32(V + m))
209 abort();
210 if (__atomic_load_8(&a64, model) != U64(V + m))
211 abort();
212#ifdef TEST_16
213 if (__atomic_load_16(&a128, model) != V + m)
214 abort();
215#endif
216 }
217}
218
219void test_stores(void) {
220 static int atomic_store_models[] = {
221 __ATOMIC_RELAXED,
222 __ATOMIC_RELEASE,
223 __ATOMIC_SEQ_CST,
224 };
225
226 for (int m = 0; m < LEN(atomic_store_models); m++) {
227 int model = atomic_store_models[m];
228
229 // Test with aligned data.
230 for (int n = 1; n <= LEN(data); n++) {
231 __attribute__((aligned(16))) char dst[LEN(data)];
232 __atomic_store_c(n, dst, data, model);
233 if (memcmp(data, dst, n) != 0)
234 abort();
235 }
236
237 // Test with unaligned data.
238 for (int n = 1; n < LEN(data); n++) {
239 __attribute__((aligned(16))) char dst[LEN(data)];
240 __atomic_store_c(n, dst + 1, data + 1, model);
241 if (memcmp(data + 1, dst + 1, n) != 0)
242 abort();
243 }
244
245 __atomic_store_1(&a8, U8(V + m), model);
246 if (a8 != U8(V + m))
247 abort();
248 __atomic_store_2(&a16, U16(V + m), model);
249 if (a16 != U16(V + m))
250 abort();
251 __atomic_store_4(&a32, U32(V + m), model);
252 if (a32 != U32(V + m))
253 abort();
254 __atomic_store_8(&a64, U64(V + m), model);
255 if (a64 != U64(V + m))
256 abort();
257#ifdef TEST_16
258 __atomic_store_16(&a128, V + m, model);
259 if (a128 != V + m)
260 abort();
261#endif
262 }
263}
264
265void test_exchanges(void) {
266 static int atomic_exchange_models[] = {
267 __ATOMIC_RELAXED,
268 __ATOMIC_ACQUIRE,
269 __ATOMIC_RELEASE,
270 __ATOMIC_ACQ_REL,
271 __ATOMIC_SEQ_CST,
272 };
273
274 set_a_values(V);
275
276 for (int m = 0; m < LEN(atomic_exchange_models); m++) {
277 int model = atomic_exchange_models[m];
278
279 // Test with aligned data.
280 for (int n = 1; n <= LEN(data); n++) {
281 __attribute__((aligned(16))) char dst[LEN(data)];
282 __attribute__((aligned(16))) char old[LEN(data)];
283 for (int i = 0; i < LEN(dst); i++)
284 dst[i] = i + m;
285 __atomic_exchange_c(n, dst, data, old, model);
286 for (int i = 0; i < n; i++) {
287 if (dst[i] != 0x10 + i || old[i] != i + m)
288 abort();
289 }
290 }
291
292 // Test with unaligned data.
293 for (int n = 1; n < LEN(data); n++) {
294 __attribute__((aligned(16))) char dst[LEN(data)];
295 __attribute__((aligned(16))) char old[LEN(data)];
296 for (int i = 1; i < LEN(dst); i++)
297 dst[i] = i - 1 + m;
298 __atomic_exchange_c(n, dst + 1, data + 1, old + 1, model);
299 for (int i = 1; i < n; i++) {
300 if (dst[i] != 0x10 + i || old[i] != i - 1 + m)
301 abort();
302 }
303 }
304
305 if (__atomic_exchange_1(&a8, U8(V + m + 1), model) != U8(V + m))
306 abort();
307 if (__atomic_exchange_2(&a16, U16(V + m + 1), model) != U16(V + m))
308 abort();
309 if (__atomic_exchange_4(&a32, U32(V + m + 1), model) != U32(V + m))
310 abort();
311 if (__atomic_exchange_8(&a64, U64(V + m + 1), model) != U64(V + m))
312 abort();
313#ifdef TEST_16
314 if (__atomic_exchange_16(&a128, V + m + 1, model) != V + m)
315 abort();
316#endif
317 }
318}
319
320void test_compare_exchanges(void) {
321 static int atomic_compare_exchange_models[] = {
322 __ATOMIC_RELAXED,
323 __ATOMIC_CONSUME,
324 __ATOMIC_ACQUIRE,
325 __ATOMIC_SEQ_CST,
326 __ATOMIC_RELEASE,
327 __ATOMIC_ACQ_REL,
328 };
329
330 for (int m1 = 0; m1 < LEN(atomic_compare_exchange_models); m1++) {
331 // Skip the last two: __ATOMIC_RELEASE and __ATOMIC_ACQ_REL.
332 // See <http://wg21.link/p0418> for details.
333 for (int m2 = 0; m2 < LEN(atomic_compare_exchange_models) - 2; m2++) {
334 int m_succ = atomic_compare_exchange_models[m1];
335 int m_fail = atomic_compare_exchange_models[m2];
336
337 // Test with aligned data.
338 for (int n = 1; n <= LEN(data); n++) {
339 __attribute__((aligned(16))) char dst[LEN(data)] = {0};
340 __attribute__((aligned(16))) char exp[LEN(data)] = {0};
341 if (!__atomic_compare_exchange_c(n, dst, exp, data, m_succ, m_fail))
342 abort();
343 if (memcmp(dst, data, n) != 0)
344 abort();
345 if (__atomic_compare_exchange_c(n, dst, exp, data, m_succ, m_fail))
346 abort();
347 if (memcmp(exp, data, n) != 0)
348 abort();
349 }
350
351 // Test with unaligned data.
352 for (int n = 1; n < LEN(data); n++) {
353 __attribute__((aligned(16))) char dst[LEN(data)] = {0};
354 __attribute__((aligned(16))) char exp[LEN(data)] = {0};
355 if (!__atomic_compare_exchange_c(n, dst + 1, exp + 1, data + 1,
356 m_succ, m_fail))
357 abort();
358 if (memcmp(dst + 1, data + 1, n) != 0)
359 abort();
360 if (__atomic_compare_exchange_c(n, dst + 1, exp + 1, data + 1, m_succ,
361 m_fail))
362 abort();
363 if (memcmp(exp + 1, data + 1, n) != 0)
364 abort();
365 }
366
367 set_a_values(ONES);
368 set_b_values(ONES * 2);
369
370 if (__atomic_compare_exchange_1(&a8, &b8, U8(V + m1), m_succ, m_fail))
371 abort();
372 if (a8 != U8(ONES) || b8 != U8(ONES))
373 abort();
374 if (!__atomic_compare_exchange_1(&a8, &b8, U8(V + m1), m_succ, m_fail))
375 abort();
376 if (a8 != U8(V + m1) || b8 != U8(ONES))
377 abort();
378
379 if (__atomic_compare_exchange_2(&a16, &b16, U16(V + m1), m_succ, m_fail))
380 abort();
381 if (a16 != U16(ONES) || b16 != U16(ONES))
382 abort();
383 if (!__atomic_compare_exchange_2(&a16, &b16, U16(V + m1), m_succ, m_fail))
384 abort();
385 if (a16 != U16(V + m1) || b16 != U16(ONES))
386 abort();
387
388 if (__atomic_compare_exchange_4(&a32, &b32, U32(V + m1), m_succ, m_fail))
389 abort();
390 if (a32 != U32(ONES) || b32 != U32(ONES))
391 abort();
392 if (!__atomic_compare_exchange_4(&a32, &b32, U32(V + m1), m_succ, m_fail))
393 abort();
394 if (a32 != U32(V + m1) || b32 != U32(ONES))
395 abort();
396
397 if (__atomic_compare_exchange_8(&a64, &b64, U64(V + m1), m_succ, m_fail))
398 abort();
399 if (a64 != U64(ONES) || b64 != U64(ONES))
400 abort();
401 if (!__atomic_compare_exchange_8(&a64, &b64, U64(V + m1), m_succ, m_fail))
402 abort();
403 if (a64 != U64(V + m1) || b64 != U64(ONES))
404 abort();
405
406#ifdef TEST_16
407 if (__atomic_compare_exchange_16(&a128, &b128, V + m1, m_succ, m_fail))
408 abort();
409 if (a128 != ONES || b128 != ONES)
410 abort();
411 if (!__atomic_compare_exchange_16(&a128, &b128, V + m1, m_succ, m_fail))
412 abort();
413 if (a128 != V + m1 || b128 != ONES)
414 abort();
415#endif
416 }
417 }
418}
419
420void test_fetch_op(void) {
421 static int atomic_fetch_models[] = {
422 __ATOMIC_RELAXED,
423 __ATOMIC_CONSUME,
424 __ATOMIC_ACQUIRE,
425 __ATOMIC_RELEASE,
426 __ATOMIC_ACQ_REL,
427 __ATOMIC_SEQ_CST,
428 };
429
430 for (int m = 0; m < LEN(atomic_fetch_models); m++) {
431 int model = atomic_fetch_models[m];
432
433 // Fetch add.
434
435 set_a_values(V + m);
436 set_b_values(0);
437 b8 = __atomic_fetch_add_1(&a8, U8(ONES), model);
438 if (b8 != U8(V + m) || a8 != U8(V + m + ONES))
439 abort();
440 b16 = __atomic_fetch_add_2(&a16, U16(ONES), model);
441 if (b16 != U16(V + m) || a16 != U16(V + m + ONES))
442 abort();
443 b32 = __atomic_fetch_add_4(&a32, U32(ONES), model);
444 if (b32 != U32(V + m) || a32 != U32(V + m + ONES))
445 abort();
446 b64 = __atomic_fetch_add_8(&a64, U64(ONES), model);
447 if (b64 != U64(V + m) || a64 != U64(V + m + ONES))
448 abort();
449#ifdef TEST_16
450 b128 = __atomic_fetch_add_16(&a128, ONES, model);
451 if (b128 != V + m || a128 != V + m + ONES)
452 abort();
453#endif
454
455 // Fetch sub.
456
457 set_a_values(V + m);
458 set_b_values(0);
459 b8 = __atomic_fetch_sub_1(&a8, U8(ONES), model);
460 if (b8 != U8(V + m) || a8 != U8(V + m - ONES))
461 abort();
462 b16 = __atomic_fetch_sub_2(&a16, U16(ONES), model);
463 if (b16 != U16(V + m) || a16 != U16(V + m - ONES))
464 abort();
465 b32 = __atomic_fetch_sub_4(&a32, U32(ONES), model);
466 if (b32 != U32(V + m) || a32 != U32(V + m - ONES))
467 abort();
468 b64 = __atomic_fetch_sub_8(&a64, U64(ONES), model);
469 if (b64 != U64(V + m) || a64 != U64(V + m - ONES))
470 abort();
471#ifdef TEST_16
472 b128 = __atomic_fetch_sub_16(&a128, ONES, model);
473 if (b128 != V + m || a128 != V + m - ONES)
474 abort();
475#endif
476
477 // Fetch and.
478
479 set_a_values(V + m);
480 set_b_values(0);
481 b8 = __atomic_fetch_and_1(&a8, U8(V + m), model);
482 if (b8 != U8(V + m) || a8 != U8(V + m))
483 abort();
484 b16 = __atomic_fetch_and_2(&a16, U16(V + m), model);
485 if (b16 != U16(V + m) || a16 != U16(V + m))
486 abort();
487 b32 = __atomic_fetch_and_4(&a32, U32(V + m), model);
488 if (b32 != U32(V + m) || a32 != U32(V + m))
489 abort();
490 b64 = __atomic_fetch_and_8(&a64, U64(V + m), model);
491 if (b64 != U64(V + m) || a64 != U64(V + m))
492 abort();
493#ifdef TEST_16
494 b128 = __atomic_fetch_and_16(&a128, V + m, model);
495 if (b128 != V + m || a128 != V + m)
496 abort();
497#endif
498
499 // Fetch or.
500
501 set_a_values(V + m);
502 set_b_values(0);
503 b8 = __atomic_fetch_or_1(&a8, U8(ONES), model);
504 if (b8 != U8(V + m) || a8 != U8((V + m) | ONES))
505 abort();
506 b16 = __atomic_fetch_or_2(&a16, U16(ONES), model);
507 if (b16 != U16(V + m) || a16 != U16((V + m) | ONES))
508 abort();
509 b32 = __atomic_fetch_or_4(&a32, U32(ONES), model);
510 if (b32 != U32(V + m) || a32 != U32((V + m) | ONES))
511 abort();
512 b64 = __atomic_fetch_or_8(&a64, U64(ONES), model);
513 if (b64 != U64(V + m) || a64 != U64((V + m) | ONES))
514 abort();
515#ifdef TEST_16
516 b128 = __atomic_fetch_or_16(&a128, ONES, model);
517 if (b128 != V + m || a128 != ((V + m) | ONES))
518 abort();
519#endif
520
521 // Fetch xor.
522
523 set_a_values(V + m);
524 set_b_values(0);
525 b8 = __atomic_fetch_xor_1(&a8, U8(ONES), model);
526 if (b8 != U8(V + m) || a8 != U8((V + m) ^ ONES))
527 abort();
528 b16 = __atomic_fetch_xor_2(&a16, U16(ONES), model);
529 if (b16 != U16(V + m) || a16 != U16((V + m) ^ ONES))
530 abort();
531 b32 = __atomic_fetch_xor_4(&a32, U32(ONES), model);
532 if (b32 != U32(V + m) || a32 != U32((V + m) ^ ONES))
533 abort();
534 b64 = __atomic_fetch_xor_8(&a64, U64(ONES), model);
535 if (b64 != U64(V + m) || a64 != U64((V + m) ^ ONES))
536 abort();
537#ifdef TEST_16
538 b128 = __atomic_fetch_xor_16(&a128, ONES, model);
539 if (b128 != (V + m) || a128 != ((V + m) ^ ONES))
540 abort();
541#endif
542
543 // Check signed integer overflow behavior
544
545 set_a_values(V + m);
546 __atomic_fetch_add_1(&a8, U8(V), model);
547 if (a8 != U8(V * 2 + m))
548 abort();
549 __atomic_fetch_sub_1(&a8, U8(V), model);
550 if (a8 != U8(V + m))
551 abort();
552 __atomic_fetch_add_2(&a16, U16(V), model);
553 if (a16 != U16(V * 2 + m))
554 abort();
555 __atomic_fetch_sub_2(&a16, U16(V), model);
556 if (a16 != U16(V + m))
557 abort();
558 __atomic_fetch_add_4(&a32, U32(V), model);
559 if (a32 != U32(V * 2 + m))
560 abort();
561 __atomic_fetch_sub_4(&a32, U32(V), model);
562 if (a32 != U32(V + m))
563 abort();
564 __atomic_fetch_add_8(&a64, U64(V), model);
565 if (a64 != U64(V * 2 + m))
566 abort();
567 __atomic_fetch_sub_8(&a64, U64(V), model);
568 if (a64 != U64(V + m))
569 abort();
570#ifdef TEST_16
571 __atomic_fetch_add_16(&a128, V, model);
572 if (a128 != V * 2 + m)
573 abort();
574 __atomic_fetch_sub_16(&a128, V, model);
575 if (a128 != V + m)
576 abort();
577#endif
578 }
579}
580
581void test_is_lock_free(void) {
582 // The result of __atomic_is_lock_free is architecture dependent, so we only
583 // check for a true return value for the sizes where we know that at compile
584 // time that they are supported. If __atomic_always_lock_free() returns false
585 // for a given size, we can only check that __atomic_is_lock_free() returns
586 // false for unaligned values.
587 // Note: This assumption will have to be revisited when we support an
588 // architecture that allows for unaligned atomics.
589 // XXX: Do any architectures report true for unaligned atomics?
590
591 // All atomic.c implementations fall back to the non-specialized case for
592 // size=0, so despite the operation being a no-op, they still take locks and
593 // therefore __atomic_is_lock_free should return false.
594 assert(!__atomic_is_lock_free_c(0, NULL) && "size zero should never be lock-free");
595 assert(!__atomic_is_lock_free_c(0, (void *)8) && "size zero should never be lock-free");
596
597 if (__atomic_always_lock_free(1, 0)) {
598 assert(__atomic_is_lock_free_c(1, NULL) && "aligned size=1 should always be lock-free");
599 assert(__atomic_is_lock_free_c(1, (void *)1) && "aligned size=1 should always be lock-free");
600 }
601
602 if (__atomic_always_lock_free(2, 0)) {
603 assert(__atomic_is_lock_free_c(2, NULL) && "aligned size=2 should always be lock-free");
604 assert(__atomic_is_lock_free_c(2, (void *)2) && "aligned size=2 should always be lock-free");
605 }
606 assert(!__atomic_is_lock_free_c(2, (void *)1) && "unaligned size=2 should not be lock-free");
607
608 if (__atomic_always_lock_free(4, 0)) {
609 assert(__atomic_is_lock_free_c(4, NULL) && "aligned size=4 should always be lock-free");
610 assert(__atomic_is_lock_free_c(4, (void *)4) && "aligned size=4 should always be lock-free");
611 }
612 assert(!__atomic_is_lock_free_c(4, (void *)3) && "unaligned size=4 should not be lock-free");
613 assert(!__atomic_is_lock_free_c(4, (void *)2) && "unaligned size=4 should not be lock-free");
614 assert(!__atomic_is_lock_free_c(4, (void *)1) && "unaligned size=4 should not be lock-free");
615
616 if (__atomic_always_lock_free(8, 0)) {
617 assert(__atomic_is_lock_free_c(8, NULL) && "aligned size=8 should always be lock-free");
618 assert(__atomic_is_lock_free_c(8, (void *)8) && "aligned size=8 should always be lock-free");
619 }
620 assert(!__atomic_is_lock_free_c(8, (void *)7) && "unaligned size=8 should not be lock-free");
621 assert(!__atomic_is_lock_free_c(8, (void *)4) && "unaligned size=8 should not be lock-free");
622 assert(!__atomic_is_lock_free_c(8, (void *)2) && "unaligned size=8 should not be lock-free");
623 assert(!__atomic_is_lock_free_c(8, (void *)1) && "unaligned size=8 should not be lock-free");
624
625 if (__atomic_always_lock_free(16, 0)) {
626 assert(__atomic_is_lock_free_c(16, NULL) && "aligned size=16 should always be lock-free");
627 assert(__atomic_is_lock_free_c(16, (void *)16) && "aligned size=16 should always be lock-free");
628 }
629 assert(!__atomic_is_lock_free_c(16, (void *)15) && "unaligned size=16 should not be lock-free");
630 assert(!__atomic_is_lock_free_c(16, (void *)8) && "unaligned size=16 should not be lock-free");
631 assert(!__atomic_is_lock_free_c(16, (void *)4) && "unaligned size=16 should not be lock-free");
632 assert(!__atomic_is_lock_free_c(16, (void *)2) && "unaligned size=16 should not be lock-free");
633 assert(!__atomic_is_lock_free_c(16, (void *)1) && "unaligned size=16 should not be lock-free");
634
635 // In the current implementation > 16 bytes are never lock-free:
636 assert(!__atomic_is_lock_free_c(32, NULL) && "aligned size=32 should not be lock-free");
637 assert(!__atomic_is_lock_free_c(32, (void*)32) && "aligned size=32 should not be lock-free");
638 assert(!__atomic_is_lock_free_c(32, (void*)31) && "unaligned size=32 should not be lock-free");
639
640 // We also don't support non-power-of-two sizes:
641 assert(!__atomic_is_lock_free_c(3, NULL) && "aligned size=3 should not be lock-free");
642 assert(!__atomic_is_lock_free_c(5, NULL) && "aligned size=5 should not be lock-free");
643 assert(!__atomic_is_lock_free_c(6, NULL) && "aligned size=6 should not be lock-free");
644 assert(!__atomic_is_lock_free_c(7, NULL) && "aligned size=7 should not be lock-free");
645 assert(!__atomic_is_lock_free_c(9, NULL) && "aligned size=9 should not be lock-free");
646 assert(!__atomic_is_lock_free_c(10, NULL) && "aligned size=10 should not be lock-free");
647 assert(!__atomic_is_lock_free_c(11, NULL) && "aligned size=11 should not be lock-free");
648 assert(!__atomic_is_lock_free_c(12, NULL) && "aligned size=12 should not be lock-free");
649 assert(!__atomic_is_lock_free_c(13, NULL) && "aligned size=13 should not be lock-free");
650 assert(!__atomic_is_lock_free_c(14, NULL) && "aligned size=14 should not be lock-free");
651 assert(!__atomic_is_lock_free_c(15, NULL) && "aligned size=15 should not be lock-free");
652 assert(!__atomic_is_lock_free_c(17, NULL) && "aligned size=17 should not be lock-free");
653}
654
655int main() {
656 test_loads();
657 test_stores();
658 test_exchanges();
659 test_compare_exchanges();
660 test_fetch_op();
661 test_is_lock_free();
662 return 0;
663}
664