19729cf09SDimitry Andric //===----------------------------------------------------------------------===////
29729cf09SDimitry Andric //
39729cf09SDimitry Andric //                     The LLVM Compiler Infrastructure
49729cf09SDimitry Andric //
59729cf09SDimitry Andric // This file is dual licensed under the MIT and the University of Illinois Open
69729cf09SDimitry Andric // Source Licenses. See LICENSE.TXT for details.
79729cf09SDimitry Andric //
89729cf09SDimitry Andric //===----------------------------------------------------------------------===////
99729cf09SDimitry Andric 
109729cf09SDimitry Andric #ifndef ATOMIC_SUPPORT_H
119729cf09SDimitry Andric #define ATOMIC_SUPPORT_H
129729cf09SDimitry Andric 
139729cf09SDimitry Andric #include "__config"
149729cf09SDimitry Andric #include "memory" // for __libcpp_relaxed_load
159729cf09SDimitry Andric 
169729cf09SDimitry Andric #if defined(__clang__) && __has_builtin(__atomic_load_n)             \
179729cf09SDimitry Andric                        && __has_builtin(__atomic_store_n)            \
189729cf09SDimitry Andric                        && __has_builtin(__atomic_add_fetch)          \
19*b2c7081bSDimitry Andric                        && __has_builtin(__atomic_exchange_n)         \
209729cf09SDimitry Andric                        && __has_builtin(__atomic_compare_exchange_n) \
219729cf09SDimitry Andric                        && defined(__ATOMIC_RELAXED)                  \
229729cf09SDimitry Andric                        && defined(__ATOMIC_CONSUME)                  \
239729cf09SDimitry Andric                        && defined(__ATOMIC_ACQUIRE)                  \
249729cf09SDimitry Andric                        && defined(__ATOMIC_RELEASE)                  \
259729cf09SDimitry Andric                        && defined(__ATOMIC_ACQ_REL)                  \
269729cf09SDimitry Andric                        && defined(__ATOMIC_SEQ_CST)
279729cf09SDimitry Andric #   define _LIBCPP_HAS_ATOMIC_BUILTINS
289729cf09SDimitry Andric #elif !defined(__clang__) && defined(_GNUC_VER) && _GNUC_VER >= 407
299729cf09SDimitry Andric #   define _LIBCPP_HAS_ATOMIC_BUILTINS
309729cf09SDimitry Andric #endif
319729cf09SDimitry Andric 
329729cf09SDimitry Andric #if !defined(_LIBCPP_HAS_ATOMIC_BUILTINS) && !defined(_LIBCPP_HAS_NO_THREADS)
335517e702SDimitry Andric # if defined(_LIBCPP_WARNING)
349729cf09SDimitry Andric     _LIBCPP_WARNING("Building libc++ without __atomic builtins is unsupported")
359729cf09SDimitry Andric # else
369729cf09SDimitry Andric #   warning Building libc++ without __atomic builtins is unsupported
379729cf09SDimitry Andric # endif
389729cf09SDimitry Andric #endif
399729cf09SDimitry Andric 
409729cf09SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
419729cf09SDimitry Andric 
429729cf09SDimitry Andric namespace {
439729cf09SDimitry Andric 
449729cf09SDimitry Andric #if defined(_LIBCPP_HAS_ATOMIC_BUILTINS) && !defined(_LIBCPP_HAS_NO_THREADS)
459729cf09SDimitry Andric 
469729cf09SDimitry Andric enum __libcpp_atomic_order {
479729cf09SDimitry Andric     _AO_Relaxed = __ATOMIC_RELAXED,
489729cf09SDimitry Andric     _AO_Consume = __ATOMIC_CONSUME,
49aed8d94eSDimitry Andric     _AO_Acquire = __ATOMIC_ACQUIRE,
509729cf09SDimitry Andric     _AO_Release = __ATOMIC_RELEASE,
519729cf09SDimitry Andric     _AO_Acq_Rel = __ATOMIC_ACQ_REL,
529729cf09SDimitry Andric     _AO_Seq     = __ATOMIC_SEQ_CST
539729cf09SDimitry Andric };
549729cf09SDimitry Andric 
559729cf09SDimitry Andric template <class _ValueType, class _FromType>
569729cf09SDimitry Andric inline _LIBCPP_INLINE_VISIBILITY
579729cf09SDimitry Andric void __libcpp_atomic_store(_ValueType* __dest, _FromType __val,
589729cf09SDimitry Andric                            int __order = _AO_Seq)
599729cf09SDimitry Andric {
609729cf09SDimitry Andric     __atomic_store_n(__dest, __val, __order);
619729cf09SDimitry Andric }
629729cf09SDimitry Andric 
639729cf09SDimitry Andric template <class _ValueType, class _FromType>
649729cf09SDimitry Andric inline _LIBCPP_INLINE_VISIBILITY
__libcpp_relaxed_store(_ValueType * __dest,_FromType __val)659729cf09SDimitry Andric void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val)
669729cf09SDimitry Andric {
679729cf09SDimitry Andric     __atomic_store_n(__dest, __val, _AO_Relaxed);
689729cf09SDimitry Andric }
699729cf09SDimitry Andric 
709729cf09SDimitry Andric template <class _ValueType>
719729cf09SDimitry Andric inline _LIBCPP_INLINE_VISIBILITY
729729cf09SDimitry Andric _ValueType __libcpp_atomic_load(_ValueType const* __val,
739729cf09SDimitry Andric                                 int __order = _AO_Seq)
749729cf09SDimitry Andric {
759729cf09SDimitry Andric     return __atomic_load_n(__val, __order);
769729cf09SDimitry Andric }
779729cf09SDimitry Andric 
789729cf09SDimitry Andric template <class _ValueType, class _AddType>
799729cf09SDimitry Andric inline _LIBCPP_INLINE_VISIBILITY
809729cf09SDimitry Andric _ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a,
819729cf09SDimitry Andric                                int __order = _AO_Seq)
829729cf09SDimitry Andric {
839729cf09SDimitry Andric     return __atomic_add_fetch(__val, __a, __order);
849729cf09SDimitry Andric }
859729cf09SDimitry Andric 
869729cf09SDimitry Andric template <class _ValueType>
879729cf09SDimitry Andric inline _LIBCPP_INLINE_VISIBILITY
88*b2c7081bSDimitry Andric _ValueType __libcpp_atomic_exchange(_ValueType* __target,
89*b2c7081bSDimitry Andric                                     _ValueType __value, int __order = _AO_Seq)
90*b2c7081bSDimitry Andric {
91*b2c7081bSDimitry Andric     return __atomic_exchange_n(__target, __value, __order);
92*b2c7081bSDimitry Andric }
93*b2c7081bSDimitry Andric 
94*b2c7081bSDimitry Andric template <class _ValueType>
95*b2c7081bSDimitry Andric inline _LIBCPP_INLINE_VISIBILITY
969729cf09SDimitry Andric bool __libcpp_atomic_compare_exchange(_ValueType* __val,
979729cf09SDimitry Andric     _ValueType* __expected, _ValueType __after,
989729cf09SDimitry Andric     int __success_order = _AO_Seq,
999729cf09SDimitry Andric     int __fail_order = _AO_Seq)
1009729cf09SDimitry Andric {
1019729cf09SDimitry Andric     return __atomic_compare_exchange_n(__val, __expected, __after, true,
1029729cf09SDimitry Andric                                        __success_order, __fail_order);
1039729cf09SDimitry Andric }
1049729cf09SDimitry Andric 
1059729cf09SDimitry Andric #else // _LIBCPP_HAS_NO_THREADS
1069729cf09SDimitry Andric 
1079729cf09SDimitry Andric enum __libcpp_atomic_order {
1089729cf09SDimitry Andric     _AO_Relaxed,
1099729cf09SDimitry Andric     _AO_Consume,
1109729cf09SDimitry Andric     _AO_Acquire,
1119729cf09SDimitry Andric     _AO_Release,
1129729cf09SDimitry Andric     _AO_Acq_Rel,
1139729cf09SDimitry Andric     _AO_Seq
1149729cf09SDimitry Andric };
1159729cf09SDimitry Andric 
1169729cf09SDimitry Andric template <class _ValueType, class _FromType>
1179729cf09SDimitry Andric inline _LIBCPP_INLINE_VISIBILITY
1189729cf09SDimitry Andric void __libcpp_atomic_store(_ValueType* __dest, _FromType __val,
1199729cf09SDimitry Andric                            int = 0)
1209729cf09SDimitry Andric {
1219729cf09SDimitry Andric     *__dest = __val;
1229729cf09SDimitry Andric }
1239729cf09SDimitry Andric 
1249729cf09SDimitry Andric template <class _ValueType, class _FromType>
1259729cf09SDimitry Andric inline _LIBCPP_INLINE_VISIBILITY
1269729cf09SDimitry Andric void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val)
1279729cf09SDimitry Andric {
1289729cf09SDimitry Andric     *__dest = __val;
1299729cf09SDimitry Andric }
1309729cf09SDimitry Andric 
1319729cf09SDimitry Andric template <class _ValueType>
1329729cf09SDimitry Andric inline _LIBCPP_INLINE_VISIBILITY
1339729cf09SDimitry Andric _ValueType __libcpp_atomic_load(_ValueType const* __val,
1349729cf09SDimitry Andric                                 int = 0)
1359729cf09SDimitry Andric {
1369729cf09SDimitry Andric     return *__val;
1379729cf09SDimitry Andric }
1389729cf09SDimitry Andric 
1399729cf09SDimitry Andric template <class _ValueType, class _AddType>
1409729cf09SDimitry Andric inline _LIBCPP_INLINE_VISIBILITY
1419729cf09SDimitry Andric _ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a,
1429729cf09SDimitry Andric                                int = 0)
1439729cf09SDimitry Andric {
1449729cf09SDimitry Andric     return *__val += __a;
1459729cf09SDimitry Andric }
1469729cf09SDimitry Andric 
1479729cf09SDimitry Andric template <class _ValueType>
1489729cf09SDimitry Andric inline _LIBCPP_INLINE_VISIBILITY
149*b2c7081bSDimitry Andric _ValueType __libcpp_atomic_exchange(_ValueType* __target,
150*b2c7081bSDimitry Andric                                     _ValueType __value, int __order = _AO_Seq)
151*b2c7081bSDimitry Andric {
152*b2c7081bSDimitry Andric     _ValueType old = *__target;
153*b2c7081bSDimitry Andric     *__target = __value;
154*b2c7081bSDimitry Andric     return old;
155*b2c7081bSDimitry Andric }
156*b2c7081bSDimitry Andric 
157*b2c7081bSDimitry Andric template <class _ValueType>
158*b2c7081bSDimitry Andric inline _LIBCPP_INLINE_VISIBILITY
1599729cf09SDimitry Andric bool __libcpp_atomic_compare_exchange(_ValueType* __val,
1609729cf09SDimitry Andric     _ValueType* __expected, _ValueType __after,
1619729cf09SDimitry Andric     int = 0, int = 0)
1629729cf09SDimitry Andric {
1639729cf09SDimitry Andric     if (*__val == *__expected) {
1649729cf09SDimitry Andric         *__val = __after;
1659729cf09SDimitry Andric         return true;
1669729cf09SDimitry Andric     }
1679729cf09SDimitry Andric     *__expected = *__val;
1689729cf09SDimitry Andric     return false;
1699729cf09SDimitry Andric }
1709729cf09SDimitry Andric 
1719729cf09SDimitry Andric #endif // _LIBCPP_HAS_NO_THREADS
1729729cf09SDimitry Andric 
1739729cf09SDimitry Andric } // end namespace
1749729cf09SDimitry Andric 
1759729cf09SDimitry Andric _LIBCPP_END_NAMESPACE_STD
1769729cf09SDimitry Andric 
1779729cf09SDimitry Andric #endif // ATOMIC_SUPPORT_H
178