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