9be6c8a6b3cc73e4f761dbfb1646651204c73a46
[libcds.git] / cds / compiler / gcc / x86 / cxx11_atomic.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8     
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
29 */
30
31 #ifndef CDSLIB_COMPILER_GCC_X86_CXX11_ATOMIC_H
32 #define CDSLIB_COMPILER_GCC_X86_CXX11_ATOMIC_H
33
34 #include <cstdint>
35 #include <cds/compiler/gcc/x86/cxx11_atomic32.h>
36
37 //@cond
38 namespace cds { namespace cxx11_atomic {
39     namespace platform { CDS_CXX11_INLINE_NAMESPACE namespace gcc { CDS_CXX11_INLINE_NAMESPACE namespace x86 {
40
41         //-----------------------------------------------------------------------------
42         // 64bit primitives
43         //-----------------------------------------------------------------------------
44
45         template <typename T>
46         static inline bool cas64_strong( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
47         {
48             static_assert( sizeof(T) == 8, "Illegal size of operand" );
49             assert( cds::details::is_aligned( pDest, 8 ));
50
51             uint32_t ebxStore;
52             T prev = expected;
53
54             fence_before(mo_success);
55
56             // We must save EBX in PIC mode
57             __asm__ __volatile__ (
58                 "movl %%ebx, %[ebxStore]\n"
59                 "movl %[desiredLo], %%ebx\n"
60                 "lock; cmpxchg8b 0(%[pDest])\n"
61                 "movl %[ebxStore], %%ebx\n"
62                 : [prev] "=A" (prev), [ebxStore] "=m" (ebxStore)
63                 : [desiredLo] "D" ((int)desired), [desiredHi] "c" ((int)(desired >> 32)), [pDest] "S" (pDest), "0" (prev)
64                 : "memory");
65             bool success = (prev == expected);
66             if (success)
67                 fence_after(mo_success);
68             else {
69                 fence_after(mo_fail);
70                 expected = prev;
71             }
72             return success;
73         }
74
75         template <typename T>
76         static inline bool cas64_weak( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
77         {
78             return cas64_strong( pDest, expected, desired, mo_success, mo_fail );
79         }
80
81         template <typename T>
82         static inline T load64( T volatile const * pSrc, memory_order order ) CDS_NOEXCEPT
83         {
84             static_assert( sizeof(T) == 8, "Illegal size of operand" );
85             assert( order ==  memory_order_relaxed
86                 || order ==  memory_order_consume
87                 || order ==  memory_order_acquire
88                 || order ==  memory_order_seq_cst
89                 );
90             assert( pSrc );
91             assert( cds::details::is_aligned( pSrc, 8 ));
92             CDS_UNUSED( order );
93
94             T CDS_DATA_ALIGNMENT(8) v;
95             __asm__ __volatile__(
96                 "movq   (%[pSrc]), %[v]   ;   \n\t"
97                 : [v] "=x" (v)
98                 : [pSrc] "r" (pSrc)
99                 :
100             );
101             return v;
102         }
103
104
105         template <typename T>
106         static inline T exchange64( T volatile * pDest, T v, memory_order order ) CDS_NOEXCEPT
107         {
108             static_assert( sizeof(T) == 8, "Illegal size of operand" );
109             assert( cds::details::is_aligned( pDest, 8 ));
110
111             T cur = load64( pDest, memory_order_relaxed );
112             do {
113             } while (!cas64_weak( pDest, cur, v, order, memory_order_relaxed ));
114             return cur;
115         }
116
117         template <typename T>
118         static inline void store64( T volatile * pDest, T val, memory_order order ) CDS_NOEXCEPT
119         {
120             static_assert( sizeof(T) == 8, "Illegal size of operand" );
121             assert( order ==  memory_order_relaxed
122                 || order ==  memory_order_release
123                 || order == memory_order_seq_cst
124                 );
125             assert( pDest );
126             assert( cds::details::is_aligned( pDest, 8 ));
127
128             if ( order != memory_order_seq_cst ) {
129                 fence_before( order );
130                 // Atomically stores 64bit value by SSE instruction
131                 __asm__ __volatile__(
132                     "movq       %[val], (%[pDest])   ;   \n\t"
133                     :
134                     : [val] "x" (val), [pDest] "r" (pDest)
135                     : "memory"
136                     );
137             }
138             else {
139                 exchange64( pDest, val, order );
140             }
141         }
142
143
144         //-----------------------------------------------------------------------------
145         // pointer primitives
146         //-----------------------------------------------------------------------------
147
148         template <typename T>
149         static inline T * exchange_ptr( T * volatile * pDest, T * v, memory_order order ) CDS_NOEXCEPT
150         {
151             static_assert( sizeof(T *) == sizeof(void *), "Illegal size of operand" );
152
153             return (T *) exchange32( (uint32_t volatile *) pDest, (uint32_t) v, order );
154         }
155
156         template <typename T>
157         static inline void store_ptr( T * volatile * pDest, T * src, memory_order order ) CDS_NOEXCEPT
158         {
159             static_assert( sizeof(T *) == sizeof(void *), "Illegal size of operand" );
160             assert( order ==  memory_order_relaxed
161                 || order ==  memory_order_release
162                 || order == memory_order_seq_cst
163                 );
164             assert( pDest );
165
166             if ( order != memory_order_seq_cst ) {
167                 fence_before( order );
168                 *pDest = src;
169             }
170             else {
171                 exchange_ptr( pDest, src, order );
172             }
173         }
174
175         template <typename T>
176         static inline T * load_ptr( T * volatile const * pSrc, memory_order order ) CDS_NOEXCEPT
177         {
178             static_assert( sizeof(T *) == sizeof(void *), "Illegal size of operand" );
179             assert( order ==  memory_order_relaxed
180                 || order ==  memory_order_consume
181                 || order ==  memory_order_acquire
182                 || order ==  memory_order_seq_cst
183                 );
184             assert( pSrc );
185
186             T * v = *pSrc;
187             fence_after_load( order );
188             return v;
189         }
190
191         template <typename T>
192         static inline bool cas_ptr_strong( T * volatile * pDest, T *& expected, T * desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
193         {
194             static_assert( sizeof(T *) == sizeof(void *), "Illegal size of operand" );
195
196             return cas32_strong( (uint32_t volatile *) pDest, *reinterpret_cast<uint32_t *>( &expected ), (uint32_t) desired, mo_success, mo_fail );
197         }
198
199         template <typename T>
200         static inline bool cas_ptr_weak( T * volatile * pDest, T *& expected, T * desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
201         {
202             return cas_ptr_strong( pDest, expected, desired, mo_success, mo_fail );
203         }
204     }} // namespace gcc::x86
205
206 #ifndef CDS_CXX11_INLINE_NAMESPACE_SUPPORT
207         using namespace gcc::x86;
208 #endif
209     }   // namespace platform
210 }}  // namespace cds::cxx11_atomic
211 //@endcond
212
213 #endif // #ifndef CDSLIB_COMPILER_GCC_X86_CXX11_ATOMIC_H