[libcxx-commits] [libcxx] [libc++] Refactor atomic_{unsigned, signed}_lock_free (PR #73041)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Nov 21 13:21:45 PST 2023
https://github.com/ldionne created https://github.com/llvm/llvm-project/pull/73041
Their definition was a bit roundabout and it was actually wrong since atomic_unsigned_lock_free would be a signed type whenever __cxx_contention_t is lock free, which is most of the time.
Fixes #72968
>From fe3bc0f3f9b472578454f18d31e094e637a4fbc2 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Tue, 21 Nov 2023 16:15:58 -0500
Subject: [PATCH] [libc++] Refactor atomic_{unsigned,signed}_lock_free
Their definition was a bit roundabout and it was actually wrong since
atomic_unsigned_lock_free would be a signed type whenever __cxx_contention_t
is lock free, which is most of the time.
Fixes #72968
---
libcxx/include/__atomic/aliases.h | 51 ++++++++++++--------------
libcxx/include/atomic | 3 ++
libcxx/test/std/atomics/types.pass.cpp | 5 +++
3 files changed, 31 insertions(+), 28 deletions(-)
diff --git a/libcxx/include/__atomic/aliases.h b/libcxx/include/__atomic/aliases.h
index e2f9fae4094ef23..0fa289de54b0f12 100644
--- a/libcxx/include/__atomic/aliases.h
+++ b/libcxx/include/__atomic/aliases.h
@@ -15,6 +15,7 @@
#include <__atomic/is_always_lock_free.h>
#include <__config>
#include <__type_traits/conditional.h>
+#include <__type_traits/make_unsigned.h>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
@@ -80,36 +81,30 @@ using atomic_ptrdiff_t = atomic<ptrdiff_t>;
using atomic_intmax_t = atomic<intmax_t>;
using atomic_uintmax_t = atomic<uintmax_t>;
-// atomic_*_lock_free : prefer the contention type most highly, then the largest lock-free type
+// C++20 atomic_{signed,unsigned}_lock_free: prefer the contention type most highly, then the largest lock-free type
+#if _LIBCPP_STD_VER >= 20
+# if ATOMIC_LLONG_LOCK_FREE == 2
+using __largest_lock_free_type = long long;
+# elif ATOMIC_INT_LOCK_FREE == 2
+using __largest_lock_free_type = int;
+# elif ATOMIC_SHORT_LOCK_FREE == 2
+using __largest_lock_free_type = short;
+# elif ATOMIC_CHAR_LOCK_FREE == 2
+using __largest_lock_free_type = char;
+# else
+# define _LIBCPP_NO_LOCK_FREE_TYPES // There are no lockfree types (this can happen in freestanding)
+# endif
-#if _LIBCPP_STD_VER >= 17
-# define _LIBCPP_CONTENTION_LOCK_FREE ::std::__libcpp_is_always_lock_free<__cxx_contention_t>::__value
-#else
-# define _LIBCPP_CONTENTION_LOCK_FREE false
-#endif
-
-#if ATOMIC_LLONG_LOCK_FREE == 2
-using __libcpp_signed_lock_free = __conditional_t<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, long long>;
-using __libcpp_unsigned_lock_free =
- __conditional_t<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, unsigned long long>;
-#elif ATOMIC_INT_LOCK_FREE == 2
-using __libcpp_signed_lock_free = __conditional_t<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, int>;
-using __libcpp_unsigned_lock_free = __conditional_t<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, unsigned int>;
-#elif ATOMIC_SHORT_LOCK_FREE == 2
-using __libcpp_signed_lock_free = __conditional_t<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, short>;
-using __libcpp_unsigned_lock_free = __conditional_t<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, unsigned short>;
-#elif ATOMIC_CHAR_LOCK_FREE == 2
-using __libcpp_signed_lock_free = __conditional_t<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, char>;
-using __libcpp_unsigned_lock_free = __conditional_t<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, unsigned char>;
-#else
-// No signed/unsigned lock-free types
-# define _LIBCPP_NO_LOCK_FREE_TYPES
-#endif
+# ifndef _LIBCPP_NO_LOCK_FREE_TYPES
+using __contention_t_or_largest =
+ __conditional_t<__libcpp_is_always_lock_free<__cxx_contention_t>::__value,
+ __cxx_contention_t,
+ __largest_lock_free_type>;
-#if !defined(_LIBCPP_NO_LOCK_FREE_TYPES)
-using atomic_signed_lock_free = atomic<__libcpp_signed_lock_free>;
-using atomic_unsigned_lock_free = atomic<__libcpp_unsigned_lock_free>;
-#endif
+using atomic_signed_lock_free = atomic<__contention_t_or_largest>;
+using atomic_unsigned_lock_free = atomic<make_unsigned_t<__contention_t_or_largest>>;
+# endif // !_LIBCPP_NO_LOCK_FREE_TYPES
+#endif // C++20
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/atomic b/libcxx/include/atomic
index 2f122a707bdc33a..1a4be926e57086a 100644
--- a/libcxx/include/atomic
+++ b/libcxx/include/atomic
@@ -448,6 +448,9 @@ typedef atomic<ptrdiff_t> atomic_ptrdiff_t;
typedef atomic<intmax_t> atomic_intmax_t;
typedef atomic<uintmax_t> atomic_uintmax_t;
+typedef see-below atomic_signed_lock_free; // since C++20
+typedef see-below atomic_unsigned_lock_free; // since C++20
+
// flag type and operations
typedef struct atomic_flag
diff --git a/libcxx/test/std/atomics/types.pass.cpp b/libcxx/test/std/atomics/types.pass.cpp
index deaa45dcddcaa16..cebf66ee7f1af03 100644
--- a/libcxx/test/std/atomics/types.pass.cpp
+++ b/libcxx/test/std/atomics/types.pass.cpp
@@ -175,7 +175,12 @@ int main(int, char**)
#if TEST_STD_VER >= 20
test<std::atomic_signed_lock_free::value_type>();
+ static_assert(std::is_signed_v<std::atomic_signed_lock_free::value_type>);
+ static_assert(std::is_integral_v<std::atomic_signed_lock_free::value_type>);
+
test<std::atomic_unsigned_lock_free::value_type>();
+ static_assert(std::is_unsigned_v<std::atomic_unsigned_lock_free::value_type>);
+ static_assert(std::is_integral_v<std::atomic_unsigned_lock_free::value_type>);
/*
test<std::shared_ptr<int>>();
*/
More information about the libcxx-commits
mailing list