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