99#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_ATOMIC_H
1010#define LLVM_LIBC_SRC___SUPPORT_CPP_ATOMIC_H
1111
12+ #include " src/__support/CPP/type_traits/has_unique_object_representations.h"
1213#include " src/__support/macros/attributes.h"
1314#include " src/__support/macros/config.h"
1415#include " src/__support/macros/properties/architectures.h"
@@ -47,12 +48,11 @@ template <typename T> struct Atomic {
4748 " constructible, move constructible, copy assignable, "
4849 " and move assignable." );
4950
51+ static_assert (cpp::has_unique_object_representations_v<T>,
52+ " atomic<T> in libc only support types whose values has unique "
53+ " object representations." );
54+
5055private:
51- // The value stored should be appropriately aligned so that
52- // hardware instructions used to perform atomic operations work
53- // correctly.
54- static constexpr int ALIGNMENT = sizeof (T) > alignof (T) ? sizeof(T)
55- : alignof(T);
5656 // type conversion helper to avoid long c++ style casts
5757 LIBC_INLINE static int order (MemoryOrder mem_ord) {
5858 return static_cast <int >(mem_ord);
@@ -62,6 +62,18 @@ template <typename T> struct Atomic {
6262 return static_cast <int >(mem_scope);
6363 }
6464
65+ LIBC_INLINE static T *addressof (T &ref) { return __builtin_addressof (ref); }
66+
67+ // require types that are 1, 2, 4, 8, or 16 bytes in length to be aligned to
68+ // at least their size to be potentially
69+ // used lock-free
70+ LIBC_INLINE_VAR static constexpr size_t MIN_ALIGNMENT =
71+ (sizeof (T) & (sizeof (T) - 1 )) || (sizeof (T) > 16 ) ? 0 : sizeof (T);
72+
73+ LIBC_INLINE_VAR static constexpr size_t ALIGNMENT = alignof (T) > MIN_ALIGNMENT
74+ ? alignof (T)
75+ : MIN_ALIGNMENT;
76+
6577public:
6678 using value_type = T;
6779
@@ -87,9 +99,10 @@ template <typename T> struct Atomic {
8799 [[maybe_unused]] MemoryScope mem_scope = MemoryScope::DEVICE) {
88100 T res;
89101#if __has_builtin(__scoped_atomic_load)
90- __scoped_atomic_load (&val, &res, order (mem_ord), scope (mem_scope));
102+ __scoped_atomic_load (addressof (val), addressof (res), order (mem_ord),
103+ scope (mem_scope));
91104#else
92- __atomic_load (& val, & res, order (mem_ord));
105+ __atomic_load (addressof ( val), addressof ( res) , order (mem_ord));
93106#endif
94107 return res;
95108 }
@@ -104,36 +117,39 @@ template <typename T> struct Atomic {
104117 store (T rhs, MemoryOrder mem_ord = MemoryOrder::SEQ_CST,
105118 [[maybe_unused]] MemoryScope mem_scope = MemoryScope::DEVICE) {
106119#if __has_builtin(__scoped_atomic_store)
107- __scoped_atomic_store (&val, &rhs, order (mem_ord), scope (mem_scope));
120+ __scoped_atomic_store (addressof (val), addressof (rhs), order (mem_ord),
121+ scope (mem_scope));
108122#else
109- __atomic_store (& val, & rhs, order (mem_ord));
123+ __atomic_store (addressof ( val), addressof ( rhs) , order (mem_ord));
110124#endif
111125 }
112126
113127 // Atomic compare exchange
114128 LIBC_INLINE bool compare_exchange_strong (
115129 T &expected, T desired, MemoryOrder mem_ord = MemoryOrder::SEQ_CST,
116130 [[maybe_unused]] MemoryScope mem_scope = MemoryScope::DEVICE) {
117- return __atomic_compare_exchange (&val, &expected, &desired, false ,
118- order (mem_ord), order (mem_ord));
131+ return __atomic_compare_exchange (addressof (val), addressof (expected),
132+ addressof (desired), false , order (mem_ord),
133+ order (mem_ord));
119134 }
120135
121136 // Atomic compare exchange (separate success and failure memory orders)
122137 LIBC_INLINE bool compare_exchange_strong (
123138 T &expected, T desired, MemoryOrder success_order,
124139 MemoryOrder failure_order,
125140 [[maybe_unused]] MemoryScope mem_scope = MemoryScope::DEVICE) {
126- return __atomic_compare_exchange (&val, &expected, &desired, false ,
127- order (success_order) ,
128- order (failure_order));
141+ return __atomic_compare_exchange (
142+ addressof (val), addressof (expected), addressof (desired), false ,
143+ order (success_order), order (failure_order));
129144 }
130145
131146 // Atomic compare exchange (weak version)
132147 LIBC_INLINE bool compare_exchange_weak (
133148 T &expected, T desired, MemoryOrder mem_ord = MemoryOrder::SEQ_CST,
134149 [[maybe_unused]] MemoryScope mem_scope = MemoryScope::DEVICE) {
135- return __atomic_compare_exchange (&val, &expected, &desired, true ,
136- order (mem_ord), order (mem_ord));
150+ return __atomic_compare_exchange (addressof (val), addressof (expected),
151+ addressof (desired), true , order (mem_ord),
152+ order (mem_ord));
137153 }
138154
139155 // Atomic compare exchange (weak version with separate success and failure
@@ -142,20 +158,21 @@ template <typename T> struct Atomic {
142158 T &expected, T desired, MemoryOrder success_order,
143159 MemoryOrder failure_order,
144160 [[maybe_unused]] MemoryScope mem_scope = MemoryScope::DEVICE) {
145- return __atomic_compare_exchange (&val, &expected, &desired, true ,
146- order (success_order) ,
147- order (failure_order));
161+ return __atomic_compare_exchange (
162+ addressof (val), addressof (expected), addressof (desired), true ,
163+ order (success_order), order (failure_order));
148164 }
149165
150166 LIBC_INLINE T
151167 exchange (T desired, MemoryOrder mem_ord = MemoryOrder::SEQ_CST,
152168 [[maybe_unused]] MemoryScope mem_scope = MemoryScope::DEVICE) {
153169 T ret;
154170#if __has_builtin(__scoped_atomic_exchange)
155- __scoped_atomic_exchange (& val, & desired, &ret, order (mem_ord ),
156- scope (mem_scope));
171+ __scoped_atomic_exchange (addressof ( val), addressof ( desired), addressof (ret ),
172+ order (mem_ord), scope (mem_scope));
157173#else
158- __atomic_exchange (&val, &desired, &ret, order (mem_ord));
174+ __atomic_exchange (addressof (val), addressof (desired), addressof (ret),
175+ order (mem_ord));
159176#endif
160177 return ret;
161178 }
@@ -165,10 +182,10 @@ template <typename T> struct Atomic {
165182 [[maybe_unused]] MemoryScope mem_scope = MemoryScope::DEVICE) {
166183 static_assert (cpp::is_integral_v<T>, " T must be an integral type." );
167184#if __has_builtin(__scoped_atomic_fetch_add)
168- return __scoped_atomic_fetch_add (& val, increment, order (mem_ord),
185+ return __scoped_atomic_fetch_add (addressof ( val) , increment, order (mem_ord),
169186 scope (mem_scope));
170187#else
171- return __atomic_fetch_add (& val, increment, order (mem_ord));
188+ return __atomic_fetch_add (addressof ( val) , increment, order (mem_ord));
172189#endif
173190 }
174191
@@ -177,10 +194,10 @@ template <typename T> struct Atomic {
177194 [[maybe_unused]] MemoryScope mem_scope = MemoryScope::DEVICE) {
178195 static_assert (cpp::is_integral_v<T>, " T must be an integral type." );
179196#if __has_builtin(__scoped_atomic_fetch_or)
180- return __scoped_atomic_fetch_or (& val, mask, order (mem_ord),
197+ return __scoped_atomic_fetch_or (addressof ( val) , mask, order (mem_ord),
181198 scope (mem_scope));
182199#else
183- return __atomic_fetch_or (& val, mask, order (mem_ord));
200+ return __atomic_fetch_or (addressof ( val) , mask, order (mem_ord));
184201#endif
185202 }
186203
@@ -189,10 +206,10 @@ template <typename T> struct Atomic {
189206 [[maybe_unused]] MemoryScope mem_scope = MemoryScope::DEVICE) {
190207 static_assert (cpp::is_integral_v<T>, " T must be an integral type." );
191208#if __has_builtin(__scoped_atomic_fetch_and)
192- return __scoped_atomic_fetch_and (& val, mask, order (mem_ord),
209+ return __scoped_atomic_fetch_and (addressof ( val) , mask, order (mem_ord),
193210 scope (mem_scope));
194211#else
195- return __atomic_fetch_and (& val, mask, order (mem_ord));
212+ return __atomic_fetch_and (addressof ( val) , mask, order (mem_ord));
196213#endif
197214 }
198215
@@ -201,10 +218,10 @@ template <typename T> struct Atomic {
201218 [[maybe_unused]] MemoryScope mem_scope = MemoryScope::DEVICE) {
202219 static_assert (cpp::is_integral_v<T>, " T must be an integral type." );
203220#if __has_builtin(__scoped_atomic_fetch_sub)
204- return __scoped_atomic_fetch_sub (& val, decrement, order (mem_ord),
221+ return __scoped_atomic_fetch_sub (addressof ( val) , decrement, order (mem_ord),
205222 scope (mem_scope));
206223#else
207- return __atomic_fetch_sub (& val, decrement, order (mem_ord));
224+ return __atomic_fetch_sub (addressof ( val) , decrement, order (mem_ord));
208225#endif
209226 }
210227
0 commit comments