Warning: This file is not a C or C++ file. It does not have highlighting.
| 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 |
Warning: This file is not a C or C++ file. It does not have highlighting.
