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// FIXME: This file is copied from libcxx/src/include/atomic_support.h. Instead
10// of duplicating the file in libc++abi we should require that the libc++
11// sources are available when building libc++abi.
12
13#ifndef ATOMIC_SUPPORT_H
14#define ATOMIC_SUPPORT_H
15
16#include "__config"
17#include "memory" // for __libcpp_relaxed_load
18
19#if defined(__clang__) && __has_builtin(__atomic_load_n) \
20 && __has_builtin(__atomic_store_n) \
21 && __has_builtin(__atomic_add_fetch) \
22 && __has_builtin(__atomic_exchange_n) \
23 && __has_builtin(__atomic_compare_exchange_n) \
24 && defined(__ATOMIC_RELAXED) \
25 && defined(__ATOMIC_CONSUME) \
26 && defined(__ATOMIC_ACQUIRE) \
27 && defined(__ATOMIC_RELEASE) \
28 && defined(__ATOMIC_ACQ_REL) \
29 && defined(__ATOMIC_SEQ_CST)
30# define _LIBCXXABI_HAS_ATOMIC_BUILTINS
31#elif !defined(__clang__) && defined(_GNUC_VER) && _GNUC_VER >= 407
32# define _LIBCXXABI_HAS_ATOMIC_BUILTINS
33#endif
34
35#if !defined(_LIBCXXABI_HAS_ATOMIC_BUILTINS) && !defined(_LIBCXXABI_HAS_NO_THREADS)
36# if defined(_LIBCPP_WARNING)
37 _LIBCPP_WARNING("Building libc++ without __atomic builtins is unsupported")
38# else
39# warning Building libc++ without __atomic builtins is unsupported
40# endif
41#endif
42
43_LIBCPP_BEGIN_NAMESPACE_STD
44
45namespace {
46
47#if defined(_LIBCXXABI_HAS_ATOMIC_BUILTINS) && !defined(_LIBCXXABI_HAS_NO_THREADS)
48
49enum __libcpp_atomic_order {
50 _AO_Relaxed = __ATOMIC_RELAXED,
51 _AO_Consume = __ATOMIC_CONSUME,
52 _AO_Acquire = __ATOMIC_ACQUIRE,
53 _AO_Release = __ATOMIC_RELEASE,
54 _AO_Acq_Rel = __ATOMIC_ACQ_REL,
55 _AO_Seq = __ATOMIC_SEQ_CST
56};
57
58template <class _ValueType, class _FromType>
59inline _LIBCPP_INLINE_VISIBILITY
60void __libcpp_atomic_store(_ValueType* __dest, _FromType __val,
61 int __order = _AO_Seq)
62{
63 __atomic_store_n(__dest, __val, __order);
64}
65
66template <class _ValueType, class _FromType>
67inline _LIBCPP_INLINE_VISIBILITY
68void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val)
69{
70 __atomic_store_n(__dest, __val, _AO_Relaxed);
71}
72
73template <class _ValueType>
74inline _LIBCPP_INLINE_VISIBILITY
75_ValueType __libcpp_atomic_load(_ValueType const* __val,
76 int __order = _AO_Seq)
77{
78 return __atomic_load_n(__val, __order);
79}
80
81template <class _ValueType, class _AddType>
82inline _LIBCPP_INLINE_VISIBILITY
83_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a,
84 int __order = _AO_Seq)
85{
86 return __atomic_add_fetch(__val, __a, __order);
87}
88
89template <class _ValueType>
90inline _LIBCPP_INLINE_VISIBILITY
91_ValueType __libcpp_atomic_exchange(_ValueType* __target,
92 _ValueType __value, int __order = _AO_Seq)
93{
94 return __atomic_exchange_n(__target, __value, __order);
95}
96
97template <class _ValueType>
98inline _LIBCPP_INLINE_VISIBILITY
99bool __libcpp_atomic_compare_exchange(_ValueType* __val,
100 _ValueType* __expected, _ValueType __after,
101 int __success_order = _AO_Seq,
102 int __fail_order = _AO_Seq)
103{
104 return __atomic_compare_exchange_n(__val, __expected, __after, true,
105 __success_order, __fail_order);
106}
107
108#else // _LIBCPP_HAS_NO_THREADS
109
110enum __libcpp_atomic_order {
111 _AO_Relaxed,
112 _AO_Consume,
113 _AO_Acquire,
114 _AO_Release,
115 _AO_Acq_Rel,
116 _AO_Seq
117};
118
119template <class _ValueType, class _FromType>
120inline _LIBCPP_INLINE_VISIBILITY
121void __libcpp_atomic_store(_ValueType* __dest, _FromType __val,
122 int = 0)
123{
124 *__dest = __val;
125}
126
127template <class _ValueType, class _FromType>
128inline _LIBCPP_INLINE_VISIBILITY
129void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val)
130{
131 *__dest = __val;
132}
133
134template <class _ValueType>
135inline _LIBCPP_INLINE_VISIBILITY
136_ValueType __libcpp_atomic_load(_ValueType const* __val,
137 int = 0)
138{
139 return *__val;
140}
141
142template <class _ValueType, class _AddType>
143inline _LIBCPP_INLINE_VISIBILITY
144_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a,
145 int = 0)
146{
147 return *__val += __a;
148}
149
150template <class _ValueType>
151inline _LIBCPP_INLINE_VISIBILITY
152_ValueType __libcpp_atomic_exchange(_ValueType* __target,
153 _ValueType __value, int = _AO_Seq)
154{
155 _ValueType old = *__target;
156 *__target = __value;
157 return old;
158}
159
160template <class _ValueType>
161inline _LIBCPP_INLINE_VISIBILITY
162bool __libcpp_atomic_compare_exchange(_ValueType* __val,
163 _ValueType* __expected, _ValueType __after,
164 int = 0, int = 0)
165{
166 if (*__val == *__expected) {
167 *__val = __after;
168 return true;
169 }
170 *__expected = *__val;
171 return false;
172}
173
174#endif // _LIBCPP_HAS_NO_THREADS
175
176} // end namespace
177
178_LIBCPP_END_NAMESPACE_STD
179
180namespace {
181
182template <class IntType>
183class AtomicInt {
184public:
185 using MemoryOrder = std::__libcpp_atomic_order;
186
187 explicit AtomicInt(IntType *b) : b(b) {}
188 AtomicInt(AtomicInt const&) = delete;
189 AtomicInt& operator=(AtomicInt const&) = delete;
190
191 IntType load(MemoryOrder ord) {
192 return std::__libcpp_atomic_load(b, ord);
193 }
194 void store(IntType val, MemoryOrder ord) {
195 std::__libcpp_atomic_store(b, val, ord);
196 }
197 IntType exchange(IntType new_val, MemoryOrder ord) {
198 return std::__libcpp_atomic_exchange(b, new_val, ord);
199 }
200 bool compare_exchange(IntType *expected, IntType desired, MemoryOrder ord_success, MemoryOrder ord_failure) {
201 return std::__libcpp_atomic_compare_exchange(b, expected, desired, ord_success, ord_failure);
202 }
203
204private:
205 IntType *b;
206};
207
208} // end namespace
209
210#endif // ATOMIC_SUPPORT_H
211