Home | History | Annotate | Line # | Download | only in include
      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