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