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