[compiler-rt] 00530de - [compiler-rt] Implement __atomic_is_lock_free
Alex Richardson via llvm-commits
llvm-commits at lists.llvm.org
Fri Jan 8 04:48:53 PST 2021
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;
}
More information about the llvm-commits
mailing list