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
41namespace {
42
43#if defined(_LIBCPP_HAS_ATOMIC_BUILTINS) && !defined(_LIBCPP_HAS_NO_THREADS)
44
45enum __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
54template <class _ValueType, class _FromType>
55inline _LIBCPP_INLINE_VISIBILITY
56void __libcpp_atomic_store(_ValueType* __dest, _FromType __val,
57                           int __order = _AO_Seq)
58{
59    __atomic_store_n(__dest, __val, __order);
60}
61
62template <class _ValueType, class _FromType>
63inline _LIBCPP_INLINE_VISIBILITY
64void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val)
65{
66    __atomic_store_n(__dest, __val, _AO_Relaxed);
67}
68
69template <class _ValueType>
70inline _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
77template <class _ValueType, class _AddType>
78inline _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
85template <class _ValueType>
86inline _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
93template <class _ValueType>
94inline _LIBCPP_INLINE_VISIBILITY
95bool __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
106enum __libcpp_atomic_order {
107    _AO_Relaxed,
108    _AO_Consume,
109    _AO_Acquire,
110    _AO_Release,
111    _AO_Acq_Rel,
112    _AO_Seq
113};
114
115template <class _ValueType, class _FromType>
116inline _LIBCPP_INLINE_VISIBILITY
117void __libcpp_atomic_store(_ValueType* __dest, _FromType __val,
118                           int = 0)
119{
120    *__dest = __val;
121}
122
123template <class _ValueType, class _FromType>
124inline _LIBCPP_INLINE_VISIBILITY
125void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val)
126{
127    *__dest = __val;
128}
129
130template <class _ValueType>
131inline _LIBCPP_INLINE_VISIBILITY
132_ValueType __libcpp_atomic_load(_ValueType const* __val,
133                                int = 0)
134{
135    return *__val;
136}
137
138template <class _ValueType, class _AddType>
139inline _LIBCPP_INLINE_VISIBILITY
140_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a,
141                               int = 0)
142{
143    return *__val += __a;
144}
145
146template <class _ValueType>
147inline _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
156template <class _ValueType>
157inline _LIBCPP_INLINE_VISIBILITY
158bool __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