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 ATOMIC_SUPPORT_H |
10 | #define ATOMIC_SUPPORT_H |
11 | |
12 | #include "__config" |
13 | #include "memory" // for __libcpp_relaxed_load |
14 | |
15 | #if defined(__clang__) && __has_builtin(__atomic_load_n) \ |
16 | && __has_builtin(__atomic_store_n) \ |
17 | && __has_builtin(__atomic_add_fetch) \ |
18 | && __has_builtin(__atomic_exchange_n) \ |
19 | && __has_builtin(__atomic_compare_exchange_n) \ |
20 | && defined(__ATOMIC_RELAXED) \ |
21 | && defined(__ATOMIC_CONSUME) \ |
22 | && defined(__ATOMIC_ACQUIRE) \ |
23 | && defined(__ATOMIC_RELEASE) \ |
24 | && defined(__ATOMIC_ACQ_REL) \ |
25 | && defined(__ATOMIC_SEQ_CST) |
26 | # define _LIBCPP_HAS_ATOMIC_BUILTINS |
27 | #elif !defined(__clang__) && defined(_GNUC_VER) && _GNUC_VER >= 407 |
28 | # define _LIBCPP_HAS_ATOMIC_BUILTINS |
29 | #endif |
30 | |
31 | #if !defined(_LIBCPP_HAS_ATOMIC_BUILTINS) && !defined(_LIBCPP_HAS_NO_THREADS) |
32 | # if defined(_LIBCPP_WARNING) |
33 | _LIBCPP_WARNING("Building libc++ without __atomic builtins is unsupported" ) |
34 | # else |
35 | # warning Building libc++ without __atomic builtins is unsupported |
36 | # endif |
37 | #endif |
38 | |
39 | _LIBCPP_BEGIN_NAMESPACE_STD |
40 | |
41 | namespace { |
42 | |
43 | #if defined(_LIBCPP_HAS_ATOMIC_BUILTINS) && !defined(_LIBCPP_HAS_NO_THREADS) |
44 | |
45 | enum __libcpp_atomic_order { |
46 | _AO_Relaxed = __ATOMIC_RELAXED, |
47 | _AO_Consume = __ATOMIC_CONSUME, |
48 | _AO_Acquire = __ATOMIC_ACQUIRE, |
49 | _AO_Release = __ATOMIC_RELEASE, |
50 | _AO_Acq_Rel = __ATOMIC_ACQ_REL, |
51 | _AO_Seq = __ATOMIC_SEQ_CST |
52 | }; |
53 | |
54 | template <class _ValueType, class _FromType> |
55 | inline _LIBCPP_INLINE_VISIBILITY |
56 | void __libcpp_atomic_store(_ValueType* __dest, _FromType __val, |
57 | int __order = _AO_Seq) |
58 | { |
59 | __atomic_store_n(__dest, __val, __order); |
60 | } |
61 | |
62 | template <class _ValueType, class _FromType> |
63 | inline _LIBCPP_INLINE_VISIBILITY |
64 | void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val) |
65 | { |
66 | __atomic_store_n(__dest, __val, _AO_Relaxed); |
67 | } |
68 | |
69 | template <class _ValueType> |
70 | inline _LIBCPP_INLINE_VISIBILITY |
71 | _ValueType __libcpp_atomic_load(_ValueType const* __val, |
72 | int __order = _AO_Seq) |
73 | { |
74 | return __atomic_load_n(__val, __order); |
75 | } |
76 | |
77 | template <class _ValueType, class _AddType> |
78 | inline _LIBCPP_INLINE_VISIBILITY |
79 | _ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a, |
80 | int __order = _AO_Seq) |
81 | { |
82 | return __atomic_add_fetch(__val, __a, __order); |
83 | } |
84 | |
85 | template <class _ValueType> |
86 | inline _LIBCPP_INLINE_VISIBILITY |
87 | _ValueType __libcpp_atomic_exchange(_ValueType* __target, |
88 | _ValueType __value, int __order = _AO_Seq) |
89 | { |
90 | return __atomic_exchange_n(__target, __value, __order); |
91 | } |
92 | |
93 | template <class _ValueType> |
94 | inline _LIBCPP_INLINE_VISIBILITY |
95 | bool __libcpp_atomic_compare_exchange(_ValueType* __val, |
96 | _ValueType* __expected, _ValueType __after, |
97 | int __success_order = _AO_Seq, |
98 | int __fail_order = _AO_Seq) |
99 | { |
100 | return __atomic_compare_exchange_n(__val, __expected, __after, true, |
101 | __success_order, __fail_order); |
102 | } |
103 | |
104 | #else // _LIBCPP_HAS_NO_THREADS |
105 | |
106 | enum __libcpp_atomic_order { |
107 | _AO_Relaxed, |
108 | _AO_Consume, |
109 | _AO_Acquire, |
110 | _AO_Release, |
111 | _AO_Acq_Rel, |
112 | _AO_Seq |
113 | }; |
114 | |
115 | template <class _ValueType, class _FromType> |
116 | inline _LIBCPP_INLINE_VISIBILITY |
117 | void __libcpp_atomic_store(_ValueType* __dest, _FromType __val, |
118 | int = 0) |
119 | { |
120 | *__dest = __val; |
121 | } |
122 | |
123 | template <class _ValueType, class _FromType> |
124 | inline _LIBCPP_INLINE_VISIBILITY |
125 | void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val) |
126 | { |
127 | *__dest = __val; |
128 | } |
129 | |
130 | template <class _ValueType> |
131 | inline _LIBCPP_INLINE_VISIBILITY |
132 | _ValueType __libcpp_atomic_load(_ValueType const* __val, |
133 | int = 0) |
134 | { |
135 | return *__val; |
136 | } |
137 | |
138 | template <class _ValueType, class _AddType> |
139 | inline _LIBCPP_INLINE_VISIBILITY |
140 | _ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a, |
141 | int = 0) |
142 | { |
143 | return *__val += __a; |
144 | } |
145 | |
146 | template <class _ValueType> |
147 | inline _LIBCPP_INLINE_VISIBILITY |
148 | _ValueType __libcpp_atomic_exchange(_ValueType* __target, |
149 | _ValueType __value, int __order = _AO_Seq) |
150 | { |
151 | _ValueType old = *__target; |
152 | *__target = __value; |
153 | return old; |
154 | } |
155 | |
156 | template <class _ValueType> |
157 | inline _LIBCPP_INLINE_VISIBILITY |
158 | bool __libcpp_atomic_compare_exchange(_ValueType* __val, |
159 | _ValueType* __expected, _ValueType __after, |
160 | int = 0, int = 0) |
161 | { |
162 | if (*__val == *__expected) { |
163 | *__val = __after; |
164 | return true; |
165 | } |
166 | *__expected = *__val; |
167 | return false; |
168 | } |
169 | |
170 | #endif // _LIBCPP_HAS_NO_THREADS |
171 | |
172 | } // end namespace |
173 | |
174 | _LIBCPP_END_NAMESPACE_STD |
175 | |
176 | #endif // ATOMIC_SUPPORT_H |
177 | |