Author: Alex Richardson Date: 2021-01-08T12:48:22Z New Revision: 00530dee5d1295dc20ebafdd9a8a79662f41513e
URL: https://github.com/llvm/llvm-project/commit/00530dee5d1295dc20ebafdd9a8a79662f41513e DIFF: https://github.com/llvm/llvm-project/commit/00530dee5d1295dc20ebafdd9a8a79662f41513e.diff LOG: [compiler-rt] Implement __atomic_is_lock_free This function is called by the __atomic_is_lock_free() builtin if the value cannot be resolved to true at compile time. Lack of this function is causing the non-lockfree atomics tests in libc++ to not be run (see D91911) This function is also added in D85044, but that review also adds support for using lock-free atomics in more cases, whereas this is a minimal change that just adds __atomic_is_lock_free() for the implementation of atomic.c. Reviewed By: ldionne Differential Revision: https://reviews.llvm.org/D92302 Added: Modified: compiler-rt/lib/builtins/atomic.c compiler-rt/test/builtins/Unit/atomic_test.c Removed: ################################################################################ diff --git a/compiler-rt/lib/builtins/atomic.c b/compiler-rt/lib/builtins/atomic.c index b20369d0c48b..f48cdc10ccf7 100644 --- a/compiler-rt/lib/builtins/atomic.c +++ b/compiler-rt/lib/builtins/atomic.c @@ -36,6 +36,8 @@ #pragma redefine_extname __atomic_exchange_c SYMBOL_NAME(__atomic_exchange) #pragma redefine_extname __atomic_compare_exchange_c SYMBOL_NAME( \ __atomic_compare_exchange) +#pragma redefine_extname __atomic_is_lock_free_c SYMBOL_NAME( \ + __atomic_is_lock_free) /// Number of locks. This allocates one page on 32-bit platforms, two on /// 64-bit. This can be specified externally if a diff erent trade between @@ -157,6 +159,14 @@ static __inline Lock *lock_for_pointer(void *ptr) { } \ } while (0) +/// Whether atomic operations for the given size (and alignment) are lock-free. +bool __atomic_is_lock_free_c(size_t size, void *ptr) { +#define LOCK_FREE_ACTION(type) return true; + LOCK_FREE_CASES(ptr); +#undef LOCK_FREE_ACTION + return false; +} + /// An atomic load operation. This is atomic with respect to the source /// pointer only. void __atomic_load_c(int size, void *src, void *dest, int model) { diff --git a/compiler-rt/test/builtins/Unit/atomic_test.c b/compiler-rt/test/builtins/Unit/atomic_test.c index 7c00841e2c0b..c51299834161 100644 --- a/compiler-rt/test/builtins/Unit/atomic_test.c +++ b/compiler-rt/test/builtins/Unit/atomic_test.c @@ -19,6 +19,8 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#undef NDEBUG +#include <assert.h> // We directly test the library atomic functions, not using the C builtins. This // should avoid confounding factors, ensuring that we actually test the @@ -29,6 +31,9 @@ #define STRINGIFY(x) _STRINGIFY(x) #define EXTERNAL_NAME(name) asm(STRINGIFY(__USER_LABEL_PREFIX__) #name) +bool __atomic_is_lock_free_c(size_t size, void *ptr) + EXTERNAL_NAME(__atomic_is_lock_free); + void __atomic_load_c(int size, void *src, void *dest, int model) EXTERNAL_NAME(__atomic_load); @@ -573,11 +578,86 @@ void test_fetch_op(void) { } } +void test_is_lock_free(void) { + // The result of __atomic_is_lock_free is architecture dependent, so we only + // check for a true return value for the sizes where we know that at compile + // time that they are supported. If __atomic_always_lock_free() returns false + // for a given size, we can only check that __atomic_is_lock_free() returns + // false for unaligned values. + // Note: This assumption will have to be revisited when we support an + // architecture that allows for unaligned atomics. + // XXX: Do any architectures report true for unaligned atomics? + + // All atomic.c implementations fall back to the non-specialized case for + // size=0, so despite the operation being a no-op, they still take locks and + // therefore __atomic_is_lock_free should return false. + assert(!__atomic_is_lock_free_c(0, NULL) && "size zero should never be lock-free"); + assert(!__atomic_is_lock_free_c(0, (void *)8) && "size zero should never be lock-free"); + + if (__atomic_always_lock_free(1, 0)) { + assert(__atomic_is_lock_free_c(1, NULL) && "aligned size=1 should always be lock-free"); + assert(__atomic_is_lock_free_c(1, (void *)1) && "aligned size=1 should always be lock-free"); + } + + if (__atomic_always_lock_free(2, 0)) { + assert(__atomic_is_lock_free_c(2, NULL) && "aligned size=2 should always be lock-free"); + assert(__atomic_is_lock_free_c(2, (void *)2) && "aligned size=2 should always be lock-free"); + } + assert(!__atomic_is_lock_free_c(2, (void *)1) && "unaligned size=2 should not be lock-free"); + + if (__atomic_always_lock_free(4, 0)) { + assert(__atomic_is_lock_free_c(4, NULL) && "aligned size=4 should always be lock-free"); + assert(__atomic_is_lock_free_c(4, (void *)4) && "aligned size=4 should always be lock-free"); + } + assert(!__atomic_is_lock_free_c(4, (void *)3) && "unaligned size=4 should not be lock-free"); + assert(!__atomic_is_lock_free_c(4, (void *)2) && "unaligned size=4 should not be lock-free"); + assert(!__atomic_is_lock_free_c(4, (void *)1) && "unaligned size=4 should not be lock-free"); + + if (__atomic_always_lock_free(8, 0)) { + assert(__atomic_is_lock_free_c(8, NULL) && "aligned size=8 should always be lock-free"); + assert(__atomic_is_lock_free_c(8, (void *)8) && "aligned size=8 should always be lock-free"); + } + assert(!__atomic_is_lock_free_c(8, (void *)7) && "unaligned size=8 should not be lock-free"); + assert(!__atomic_is_lock_free_c(8, (void *)4) && "unaligned size=8 should not be lock-free"); + assert(!__atomic_is_lock_free_c(8, (void *)2) && "unaligned size=8 should not be lock-free"); + assert(!__atomic_is_lock_free_c(8, (void *)1) && "unaligned size=8 should not be lock-free"); + + if (__atomic_always_lock_free(16, 0)) { + assert(__atomic_is_lock_free_c(16, NULL) && "aligned size=16 should always be lock-free"); + assert(__atomic_is_lock_free_c(16, (void *)16) && "aligned size=16 should always be lock-free"); + } + assert(!__atomic_is_lock_free_c(16, (void *)15) && "unaligned size=16 should not be lock-free"); + assert(!__atomic_is_lock_free_c(16, (void *)8) && "unaligned size=16 should not be lock-free"); + assert(!__atomic_is_lock_free_c(16, (void *)4) && "unaligned size=16 should not be lock-free"); + assert(!__atomic_is_lock_free_c(16, (void *)2) && "unaligned size=16 should not be lock-free"); + assert(!__atomic_is_lock_free_c(16, (void *)1) && "unaligned size=16 should not be lock-free"); + + // In the current implementation > 16 bytes are never lock-free: + assert(!__atomic_is_lock_free_c(32, NULL) && "aligned size=32 should not be lock-free"); + assert(!__atomic_is_lock_free_c(32, (void*)32) && "aligned size=32 should not be lock-free"); + assert(!__atomic_is_lock_free_c(32, (void*)31) && "unaligned size=32 should not be lock-free"); + + // We also don't support non-power-of-two sizes: + assert(!__atomic_is_lock_free_c(3, NULL) && "aligned size=3 should not be lock-free"); + assert(!__atomic_is_lock_free_c(5, NULL) && "aligned size=5 should not be lock-free"); + assert(!__atomic_is_lock_free_c(6, NULL) && "aligned size=6 should not be lock-free"); + assert(!__atomic_is_lock_free_c(7, NULL) && "aligned size=7 should not be lock-free"); + assert(!__atomic_is_lock_free_c(9, NULL) && "aligned size=9 should not be lock-free"); + assert(!__atomic_is_lock_free_c(10, NULL) && "aligned size=10 should not be lock-free"); + assert(!__atomic_is_lock_free_c(11, NULL) && "aligned size=11 should not be lock-free"); + assert(!__atomic_is_lock_free_c(12, NULL) && "aligned size=12 should not be lock-free"); + assert(!__atomic_is_lock_free_c(13, NULL) && "aligned size=13 should not be lock-free"); + assert(!__atomic_is_lock_free_c(14, NULL) && "aligned size=14 should not be lock-free"); + assert(!__atomic_is_lock_free_c(15, NULL) && "aligned size=15 should not be lock-free"); + assert(!__atomic_is_lock_free_c(17, NULL) && "aligned size=17 should not be lock-free"); +} + int main() { test_loads(); test_stores(); test_exchanges(); test_compare_exchanges(); test_fetch_op(); + test_is_lock_free(); return 0; } _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits