a2c9eaca822f80857737424694f8cfe860c18964
[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_atomic {
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 );
63             assert( cds::details::is_aligned( pSrc, 8 ));
64             CDS_UNUSED( order );
65
66             T CDS_DATA_ALIGNMENT(8) v;
67             __asm__ __volatile__(
68                 "movq   (%[pSrc]), %[v]   ;   \n\t"
69                 : [v] "=x" (v)
70                 : [pSrc] "r" (pSrc)
71                 :
72             );
73             return v;
74         }
75
76
77         template <typename T>
78         static inline T exchange64( T volatile * pDest, T v, memory_order order ) CDS_NOEXCEPT
79         {
80             static_assert( sizeof(T) == 8, "Illegal size of operand" );
81             assert( cds::details::is_aligned( pDest, 8 ));
82
83             T cur = load64( pDest, memory_order_relaxed );
84             do {
85             } while (!cas64_weak( pDest, cur, v, order, memory_order_relaxed ));
86             return cur;
87         }
88
89         template <typename T>
90         static inline void store64( T volatile * pDest, T val, memory_order order ) CDS_NOEXCEPT
91         {
92             static_assert( sizeof(T) == 8, "Illegal size of operand" );
93             assert( order ==  memory_order_relaxed
94                 || order ==  memory_order_release
95                 || order == memory_order_seq_cst
96                 );
97             assert( pDest );
98             assert( cds::details::is_aligned( pDest, 8 ));
99
100             if ( order != memory_order_seq_cst ) {
101                 fence_before( order );
102                 // Atomically stores 64bit value by SSE instruction
103                 __asm__ __volatile__(
104                     "movq       %[val], (%[pDest])   ;   \n\t"
105                     :
106                     : [val] "x" (val), [pDest] "r" (pDest)
107                     : "memory"
108                     );
109             }
110             else {
111                 exchange64( pDest, val, order );
112             }
113         }
114
115
116         //-----------------------------------------------------------------------------
117         // pointer primitives
118         //-----------------------------------------------------------------------------
119
120         template <typename T>
121         static inline T * exchange_ptr( T * volatile * pDest, T * v, memory_order order ) CDS_NOEXCEPT
122         {
123             static_assert( sizeof(T *) == sizeof(void *), "Illegal size of operand" );
124
125             return (T *) exchange32( (uint32_t volatile *) pDest, (uint32_t) v, order );
126         }
127
128         template <typename T>
129         static inline void store_ptr( T * volatile * pDest, T * src, memory_order order ) CDS_NOEXCEPT
130         {
131             static_assert( sizeof(T *) == sizeof(void *), "Illegal size of operand" );
132             assert( order ==  memory_order_relaxed
133                 || order ==  memory_order_release
134                 || order == memory_order_seq_cst
135                 );
136             assert( pDest );
137
138             if ( order != memory_order_seq_cst ) {
139                 fence_before( order );
140                 *pDest = src;
141             }
142             else {
143                 exchange_ptr( pDest, src, order );
144             }
145         }
146
147         template <typename T>
148         static inline T * load_ptr( T * volatile const * pSrc, memory_order order ) CDS_NOEXCEPT
149         {
150             static_assert( sizeof(T *) == sizeof(void *), "Illegal size of operand" );
151             assert( order ==  memory_order_relaxed
152                 || order ==  memory_order_consume
153                 || order ==  memory_order_acquire
154                 || order ==  memory_order_seq_cst
155                 );
156             assert( pSrc );
157
158             T * v = *pSrc;
159             fence_after_load( order );
160             return v;
161         }
162
163         template <typename T>
164         static inline bool cas_ptr_strong( T * volatile * pDest, T *& expected, T * desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
165         {
166             static_assert( sizeof(T *) == sizeof(void *), "Illegal size of operand" );
167
168             return cas32_strong( (uint32_t volatile *) pDest, *reinterpret_cast<uint32_t *>( &expected ), (uint32_t) desired, mo_success, mo_fail );
169         }
170
171         template <typename T>
172         static inline bool cas_ptr_weak( T * volatile * pDest, T *& expected, T * desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
173         {
174             return cas_ptr_strong( pDest, expected, desired, mo_success, mo_fail );
175         }
176     }} // namespace gcc::x86
177
178 #ifndef CDS_CXX11_INLINE_NAMESPACE_SUPPORT
179         using namespace gcc::x86;
180 #endif
181     }   // namespace platform
182 }}  // namespace cds::cxx11_atomic
183 //@endcond
184
185 #endif // #ifndef __CDS_COMPILER_GCC_X86_CXX11_ATOMIC_H