Move libcds 1.6.0 from SVN
[libcds.git] / cds / compiler / gcc / x86 / cxx11_atomic.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_COMPILER_GCC_X86_CXX11_ATOMIC_H
4 #define __CDS_COMPILER_GCC_X86_CXX11_ATOMIC_H
5
6 #include <cstdint>
7 #include <cds/compiler/gcc/x86/cxx11_atomic32.h>
8
9 //@cond
10 namespace cds { namespace cxx11_atomics {
11     namespace platform { CDS_CXX11_INLINE_NAMESPACE namespace gcc { CDS_CXX11_INLINE_NAMESPACE namespace x86 {
12
13         //-----------------------------------------------------------------------------
14         // 64bit primitives
15         //-----------------------------------------------------------------------------
16
17         template <typename T>
18         static inline bool cas64_strong( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
19         {
20             static_assert( sizeof(T) == 8, "Illegal size of operand" );
21             assert( cds::details::is_aligned( pDest, 8 ));
22
23             uint32_t ebxStore;
24             T prev = expected;
25
26             fence_before(mo_success);
27
28             // We must save EBX in PIC mode
29             __asm__ __volatile__ (
30                 "movl %%ebx, %[ebxStore]\n"
31                 "movl %[desiredLo], %%ebx\n"
32                 "lock; cmpxchg8b 0(%[pDest])\n"
33                 "movl %[ebxStore], %%ebx\n"
34                 : [prev] "=A" (prev), [ebxStore] "=m" (ebxStore)
35                 : [desiredLo] "D" ((int)desired), [desiredHi] "c" ((int)(desired >> 32)), [pDest] "S" (pDest), "0" (prev)
36                 : "memory");
37             bool success = (prev == expected);
38             if (success)
39                 fence_after(mo_success);
40             else {
41                 fence_after(mo_fail);
42                 expected = prev;
43             }
44             return success;
45         }
46
47         template <typename T>
48         static inline bool cas64_weak( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
49         {
50             return cas64_strong( pDest, expected, desired, mo_success, mo_fail );
51         }
52
53         template <typename T>
54         static inline T load64( T volatile const * pSrc, memory_order order ) CDS_NOEXCEPT
55         {
56             static_assert( sizeof(T) == 8, "Illegal size of operand" );
57             assert( order ==  memory_order_relaxed
58                 || order ==  memory_order_consume
59                 || order ==  memory_order_acquire
60                 || order ==  memory_order_seq_cst
61                 );
62             assert( pSrc != NULL );
63             assert( cds::details::is_aligned( pSrc, 8 ));
64
65             T CDS_DATA_ALIGNMENT(8) v;
66             __asm__ __volatile__(
67                 "movq   (%[pSrc]), %[v]   ;   \n\t"
68                 : [v] "=x" (v)
69                 : [pSrc] "r" (pSrc)
70                 :
71             );
72             return v;
73         }
74
75
76         template <typename T>
77         static inline T exchange64( T volatile * pDest, T v, memory_order order ) CDS_NOEXCEPT
78         {
79             static_assert( sizeof(T) == 8, "Illegal size of operand" );
80             assert( cds::details::is_aligned( pDest, 8 ));
81
82             T cur = load64( pDest, memory_order_relaxed );
83             do {
84             } while (!cas64_weak( pDest, cur, v, order, memory_order_relaxed ));
85             return cur;
86         }
87
88         template <typename T>
89         static inline void store64( T volatile * pDest, T val, memory_order order ) CDS_NOEXCEPT
90         {
91             static_assert( sizeof(T) == 8, "Illegal size of operand" );
92             assert( order ==  memory_order_relaxed
93                 || order ==  memory_order_release
94                 || order == memory_order_seq_cst
95                 );
96             assert( pDest != NULL );
97             assert( cds::details::is_aligned( pDest, 8 ));
98
99             if ( order != memory_order_seq_cst ) {
100                 fence_before( order );
101                 // Atomically stores 64bit value by SSE instruction
102                 __asm__ __volatile__(
103                     "movq       %[val], (%[pDest])   ;   \n\t"
104                     :
105                     : [val] "x" (val), [pDest] "r" (pDest)
106                     : "memory"
107                     );
108             }
109             else {
110                 exchange64( pDest, val, order );
111             }
112         }
113
114
115         //-----------------------------------------------------------------------------
116         // pointer primitives
117         //-----------------------------------------------------------------------------
118
119         template <typename T>
120         static inline T * exchange_ptr( T * volatile * pDest, T * v, memory_order order ) CDS_NOEXCEPT
121         {
122             static_assert( sizeof(T *) == sizeof(void *), "Illegal size of operand" );
123
124             return (T *) exchange32( (uint32_t volatile *) pDest, (uint32_t) v, order );
125         }
126
127         template <typename T>
128         static inline void store_ptr( T * volatile * pDest, T * src, memory_order order ) CDS_NOEXCEPT
129         {
130             static_assert( sizeof(T *) == sizeof(void *), "Illegal size of operand" );
131             assert( order ==  memory_order_relaxed
132                 || order ==  memory_order_release
133                 || order == memory_order_seq_cst
134                 );
135             assert( pDest != NULL );
136
137             if ( order != memory_order_seq_cst ) {
138                 fence_before( order );
139                 *pDest = src;
140             }
141             else {
142                 exchange_ptr( pDest, src, order );
143             }
144         }
145
146         template <typename T>
147         static inline T * load_ptr( T * volatile const * pSrc, memory_order order ) CDS_NOEXCEPT
148         {
149             static_assert( sizeof(T *) == sizeof(void *), "Illegal size of operand" );
150             assert( order ==  memory_order_relaxed
151                 || order ==  memory_order_consume
152                 || order ==  memory_order_acquire
153                 || order ==  memory_order_seq_cst
154                 );
155             assert( pSrc != NULL );
156
157             T * v = *pSrc;
158             fence_after_load( order );
159             return v;
160         }
161
162         template <typename T>
163         static inline bool cas_ptr_strong( T * volatile * pDest, T *& expected, T * desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
164         {
165             static_assert( sizeof(T *) == sizeof(void *), "Illegal size of operand" );
166
167             return cas32_strong( (uint32_t volatile *) pDest, *reinterpret_cast<uint32_t *>( &expected ), (uint32_t) desired, mo_success, mo_fail );
168         }
169
170         template <typename T>
171         static inline bool cas_ptr_weak( T * volatile * pDest, T *& expected, T * desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
172         {
173             return cas_ptr_strong( pDest, expected, desired, mo_success, mo_fail );
174         }
175     }} // namespace gcc::x86
176
177 #ifndef CDS_CXX11_INLINE_NAMESPACE_SUPPORT
178         using namespace gcc::x86;
179 #endif
180     }   // namespace platform
181 }}  // namespace cds::cxx11_atomics
182 //@endcond
183
184 #endif // #ifndef __CDS_COMPILER_GCC_X86_CXX11_ATOMIC_H