xref: /freebsd/contrib/llvm-project/libcxx/src/include/atomic_support.h (revision e32fecd0c2c3ee37c47ee100f169e7eb0282a873)
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(_LIBCPP_COMPILER_GCC)
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 = _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