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