xref: /llvm-project/libcxx/include/__atomic/support/gcc.h (revision 0e34f3f4968d8d32a64e26777541f939deb2274c)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef _LIBCPP___ATOMIC_SUPPORT_GCC_H
10 #define _LIBCPP___ATOMIC_SUPPORT_GCC_H
11 
12 #include <__atomic/memory_order.h>
13 #include <__atomic/to_gcc_order.h>
14 #include <__config>
15 #include <__memory/addressof.h>
16 #include <__type_traits/enable_if.h>
17 #include <__type_traits/is_assignable.h>
18 #include <__type_traits/remove_const.h>
19 
20 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
21 #  pragma GCC system_header
22 #endif
23 
24 //
25 // This file implements support for GCC-style atomics
26 //
27 
28 _LIBCPP_BEGIN_NAMESPACE_STD
29 
30 // [atomics.types.generic]p1 guarantees _Tp is trivially copyable. Because
31 // the default operator= in an object is not volatile, a byte-by-byte copy
32 // is required.
33 template <typename _Tp, typename _Tv, __enable_if_t<is_assignable<_Tp&, _Tv>::value, int> = 0>
34 _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_assign_volatile(_Tp& __a_value, _Tv const& __val) {
35   __a_value = __val;
36 }
37 template <typename _Tp, typename _Tv, __enable_if_t<is_assignable<_Tp&, _Tv>::value, int> = 0>
38 _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_assign_volatile(_Tp volatile& __a_value, _Tv volatile const& __val) {
39   volatile char* __to         = reinterpret_cast<volatile char*>(std::addressof(__a_value));
40   volatile char* __end        = __to + sizeof(_Tp);
41   volatile const char* __from = reinterpret_cast<volatile const char*>(std::addressof(__val));
42   while (__to != __end)
43     *__to++ = *__from++;
44 }
45 
46 template <typename _Tp>
47 struct __cxx_atomic_base_impl {
48   _LIBCPP_HIDE_FROM_ABI
49 #ifndef _LIBCPP_CXX03_LANG
50   __cxx_atomic_base_impl() _NOEXCEPT = default;
51 #else
52   __cxx_atomic_base_impl() _NOEXCEPT : __a_value() {
53   }
54 #endif // _LIBCPP_CXX03_LANG
55   _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp value) _NOEXCEPT : __a_value(value) {}
56   _Tp __a_value;
57 };
58 
59 template <typename _Tp>
60 _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val) {
61   __cxx_atomic_assign_volatile(__a->__a_value, __val);
62 }
63 
64 template <typename _Tp>
65 _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val) {
66   __a->__a_value = __val;
67 }
68 
69 _LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_thread_fence(memory_order __order) {
70   __atomic_thread_fence(__to_gcc_order(__order));
71 }
72 
73 _LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_signal_fence(memory_order __order) {
74   __atomic_signal_fence(__to_gcc_order(__order));
75 }
76 
77 template <typename _Tp>
78 _LIBCPP_HIDE_FROM_ABI void
79 __cxx_atomic_store(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) {
80   __atomic_store(std::addressof(__a->__a_value), std::addressof(__val), __to_gcc_order(__order));
81 }
82 
83 template <typename _Tp>
84 _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_store(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) {
85   __atomic_store(std::addressof(__a->__a_value), std::addressof(__val), __to_gcc_order(__order));
86 }
87 
88 template <typename _Tp>
89 _LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_load(const volatile __cxx_atomic_base_impl<_Tp>* __a, memory_order __order) {
90   _Tp __ret;
91   __atomic_load(std::addressof(__a->__a_value), std::addressof(__ret), __to_gcc_order(__order));
92   return __ret;
93 }
94 
95 template <typename _Tp>
96 _LIBCPP_HIDE_FROM_ABI void
97 __cxx_atomic_load_inplace(const volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp* __dst, memory_order __order) {
98   __atomic_load(std::addressof(__a->__a_value), __dst, __to_gcc_order(__order));
99 }
100 
101 template <typename _Tp>
102 _LIBCPP_HIDE_FROM_ABI void
103 __cxx_atomic_load_inplace(const __cxx_atomic_base_impl<_Tp>* __a, _Tp* __dst, memory_order __order) {
104   __atomic_load(std::addressof(__a->__a_value), __dst, __to_gcc_order(__order));
105 }
106 
107 template <typename _Tp>
108 _LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_load(const __cxx_atomic_base_impl<_Tp>* __a, memory_order __order) {
109   _Tp __ret;
110   __atomic_load(std::addressof(__a->__a_value), std::addressof(__ret), __to_gcc_order(__order));
111   return __ret;
112 }
113 
114 template <typename _Tp>
115 _LIBCPP_HIDE_FROM_ABI _Tp
116 __cxx_atomic_exchange(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __value, memory_order __order) {
117   _Tp __ret;
118   __atomic_exchange(
119       std::addressof(__a->__a_value), std::addressof(__value), std::addressof(__ret), __to_gcc_order(__order));
120   return __ret;
121 }
122 
123 template <typename _Tp>
124 _LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp>* __a, _Tp __value, memory_order __order) {
125   _Tp __ret;
126   __atomic_exchange(
127       std::addressof(__a->__a_value), std::addressof(__value), std::addressof(__ret), __to_gcc_order(__order));
128   return __ret;
129 }
130 
131 template <typename _Tp>
132 _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
133     volatile __cxx_atomic_base_impl<_Tp>* __a,
134     _Tp* __expected,
135     _Tp __value,
136     memory_order __success,
137     memory_order __failure) {
138   return __atomic_compare_exchange(
139       std::addressof(__a->__a_value),
140       __expected,
141       std::addressof(__value),
142       false,
143       __to_gcc_order(__success),
144       __to_gcc_failure_order(__failure));
145 }
146 
147 template <typename _Tp>
148 _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
149     __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) {
150   return __atomic_compare_exchange(
151       std::addressof(__a->__a_value),
152       __expected,
153       std::addressof(__value),
154       false,
155       __to_gcc_order(__success),
156       __to_gcc_failure_order(__failure));
157 }
158 
159 template <typename _Tp>
160 _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
161     volatile __cxx_atomic_base_impl<_Tp>* __a,
162     _Tp* __expected,
163     _Tp __value,
164     memory_order __success,
165     memory_order __failure) {
166   return __atomic_compare_exchange(
167       std::addressof(__a->__a_value),
168       __expected,
169       std::addressof(__value),
170       true,
171       __to_gcc_order(__success),
172       __to_gcc_failure_order(__failure));
173 }
174 
175 template <typename _Tp>
176 _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
177     __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) {
178   return __atomic_compare_exchange(
179       std::addressof(__a->__a_value),
180       __expected,
181       std::addressof(__value),
182       true,
183       __to_gcc_order(__success),
184       __to_gcc_failure_order(__failure));
185 }
186 
187 template <typename _Tp>
188 struct __skip_amt {
189   enum { value = 1 };
190 };
191 
192 template <typename _Tp>
193 struct __skip_amt<_Tp*> {
194   enum { value = sizeof(_Tp) };
195 };
196 
197 // FIXME: Haven't figured out what the spec says about using arrays with
198 // atomic_fetch_add. Force a failure rather than creating bad behavior.
199 template <typename _Tp>
200 struct __skip_amt<_Tp[]> {};
201 template <typename _Tp, int n>
202 struct __skip_amt<_Tp[n]> {};
203 
204 template <typename _Tp, typename _Td>
205 _LIBCPP_HIDE_FROM_ABI _Tp
206 __cxx_atomic_fetch_add(volatile __cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) {
207   return __atomic_fetch_add(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order));
208 }
209 
210 template <typename _Tp, typename _Td>
211 _LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) {
212   return __atomic_fetch_add(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order));
213 }
214 
215 template <typename _Tp, typename _Td>
216 _LIBCPP_HIDE_FROM_ABI _Tp
217 __cxx_atomic_fetch_sub(volatile __cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) {
218   return __atomic_fetch_sub(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order));
219 }
220 
221 template <typename _Tp, typename _Td>
222 _LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) {
223   return __atomic_fetch_sub(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order));
224 }
225 
226 template <typename _Tp>
227 _LIBCPP_HIDE_FROM_ABI _Tp
228 __cxx_atomic_fetch_and(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) {
229   return __atomic_fetch_and(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order));
230 }
231 
232 template <typename _Tp>
233 _LIBCPP_HIDE_FROM_ABI _Tp
234 __cxx_atomic_fetch_and(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) {
235   return __atomic_fetch_and(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order));
236 }
237 
238 template <typename _Tp>
239 _LIBCPP_HIDE_FROM_ABI _Tp
240 __cxx_atomic_fetch_or(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) {
241   return __atomic_fetch_or(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order));
242 }
243 
244 template <typename _Tp>
245 _LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_or(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) {
246   return __atomic_fetch_or(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order));
247 }
248 
249 template <typename _Tp>
250 _LIBCPP_HIDE_FROM_ABI _Tp
251 __cxx_atomic_fetch_xor(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) {
252   return __atomic_fetch_xor(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order));
253 }
254 
255 template <typename _Tp>
256 _LIBCPP_HIDE_FROM_ABI _Tp
257 __cxx_atomic_fetch_xor(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) {
258   return __atomic_fetch_xor(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order));
259 }
260 
261 #define __cxx_atomic_is_lock_free(__s) __atomic_is_lock_free(__s, 0)
262 
263 _LIBCPP_END_NAMESPACE_STD
264 
265 #endif // _LIBCPP___ATOMIC_SUPPORT_GCC_H
266