Move libcds 1.6.0 from SVN
[libcds.git] / cds / compiler / vc / x86 / cxx11_atomic.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_COMPILER_VC_X86_CXX11_ATOMIC_H
4 #define __CDS_COMPILER_VC_X86_CXX11_ATOMIC_H
5
6 #include <intrin.h>
7 #include <emmintrin.h>  // for 64bit atomic load/store
8 #include <cds/details/is_aligned.h>
9
10 #pragma intrinsic( _InterlockedIncrement )
11 #pragma intrinsic( _InterlockedDecrement )
12 #pragma intrinsic( _InterlockedCompareExchange )
13 //#pragma intrinsic( _InterlockedCompareExchangePointer )   // On the x86 architecture, _InterlockedCompareExchangePointer is a macro that calls _InterlockedCompareExchange
14 #pragma intrinsic( _InterlockedCompareExchange16 )
15 #pragma intrinsic( _InterlockedCompareExchange64 )
16 #pragma intrinsic( _InterlockedExchange )
17 //#pragma intrinsic( _InterlockedExchangePointer )  // On the x86 architecture, _InterlockedExchangePointer is a macro that calls _InterlockedExchange
18 #pragma intrinsic( _InterlockedExchangeAdd )
19 #pragma intrinsic( _InterlockedXor )
20 #pragma intrinsic( _InterlockedOr )
21 #pragma intrinsic( _InterlockedAnd )
22 #pragma intrinsic( _interlockedbittestandset )
23 #if _MSC_VER >= 1600
24 #   pragma intrinsic( _InterlockedCompareExchange8 )
25 #   pragma intrinsic( _InterlockedExchange8 )
26 #   pragma intrinsic( _InterlockedExchange16 )
27 #endif
28
29 //@cond
30 namespace cds { namespace cxx11_atomics {
31     namespace platform { CDS_CXX11_INLINE_NAMESPACE namespace vc { CDS_CXX11_INLINE_NAMESPACE namespace x86 {
32
33         static inline void fence_before( memory_order order ) CDS_NOEXCEPT
34         {
35             switch(order) {
36             case memory_order_relaxed:
37             case memory_order_acquire:
38             case memory_order_consume:
39                 break;
40             case memory_order_release:
41             case memory_order_acq_rel:
42                 CDS_COMPILER_RW_BARRIER;
43                 break;
44             case memory_order_seq_cst:
45                 CDS_COMPILER_RW_BARRIER;
46                 break;
47             }
48         }
49
50         static inline void fence_after( memory_order order ) CDS_NOEXCEPT
51         {
52             switch(order) {
53             case memory_order_acquire:
54             case memory_order_acq_rel:
55                 CDS_COMPILER_RW_BARRIER;
56                 break;
57             case memory_order_relaxed:
58             case memory_order_consume:
59             case memory_order_release:
60                 break;
61             case memory_order_seq_cst:
62                 CDS_COMPILER_RW_BARRIER;
63                 break;
64             }
65         }
66
67
68         static inline void fence_after_load(memory_order order) CDS_NOEXCEPT
69         {
70             switch(order) {
71             case memory_order_relaxed:
72             case memory_order_release:
73                 break;
74             case memory_order_acquire:
75             case memory_order_acq_rel:
76                 CDS_COMPILER_RW_BARRIER;
77                 break;
78             case memory_order_consume:
79                 break;
80             case memory_order_seq_cst:
81                 __asm { mfence };
82                 break;
83             default:;
84             }
85         }
86
87         //-----------------------------------------------------------------------------
88         // fences
89         //-----------------------------------------------------------------------------
90         static inline void thread_fence(memory_order order) CDS_NOEXCEPT
91         {
92             switch(order)
93             {
94                 case memory_order_relaxed:
95                 case memory_order_consume:
96                     break;
97                 case memory_order_release:
98                 case memory_order_acquire:
99                 case memory_order_acq_rel:
100                     CDS_COMPILER_RW_BARRIER;
101                     break;
102                 case memory_order_seq_cst:
103                     __asm { mfence };
104                     break;
105                 default:;
106             }
107         }
108
109         static inline void signal_fence(memory_order order) CDS_NOEXCEPT
110         {
111             // C++11: 29.8.8: only compiler optimization, no hardware instructions
112             switch(order)
113             {
114                 case memory_order_relaxed:
115                     break;
116                 case memory_order_consume:
117                 case memory_order_release:
118                 case memory_order_acquire:
119                 case memory_order_acq_rel:
120                 case memory_order_seq_cst:
121                     CDS_COMPILER_RW_BARRIER;
122                     break;
123                 default:;
124             }
125         }
126
127         //-----------------------------------------------------------------------------
128         // atomic flag primitives
129         //-----------------------------------------------------------------------------
130
131         typedef unsigned char atomic_flag_type;
132         static inline bool atomic_flag_tas( atomic_flag_type volatile * pFlag, memory_order /*order*/ ) CDS_NOEXCEPT
133         {
134             return _interlockedbittestandset( (long volatile *) pFlag, 0 ) != 0;
135         }
136
137         static inline void atomic_flag_clear( atomic_flag_type volatile * pFlag, memory_order order ) CDS_NOEXCEPT
138         {
139             assert( order != memory_order_acquire
140                 && order != memory_order_acq_rel
141                 );
142
143             fence_before( order );
144             *pFlag = 0;
145             fence_after( order );
146         }
147
148
149         //-----------------------------------------------------------------------------
150         // 8bit primitives
151         //-----------------------------------------------------------------------------
152
153 #if _MSC_VER >= 1600
154 #   pragma warning(push)
155         // Disable warning C4800: 'char' : forcing value to bool 'true' or 'false' (performance warning)
156 #   pragma warning( disable: 4800 )
157 #endif
158         template <typename T>
159         static inline bool cas8_strong( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
160         {
161             static_assert( sizeof(T) == 1, "Illegal operand size"  );
162
163 #       if _MSC_VER >= 1600
164             T prev = expected;
165             expected = (T) _InterlockedCompareExchange8( reinterpret_cast<char volatile*>(pDest), (char) desired, (char) expected );
166             return expected == prev;
167 #       else
168             bool bRet = false;
169             __asm {
170                 mov ecx, pDest;
171                 mov edx, expected;
172                 mov al, byte ptr [edx];
173                 mov ah, desired;
174                 lock cmpxchg byte ptr [ecx], ah;
175                 mov byte ptr [edx], al;
176                 setz bRet;
177             }
178             return bRet;
179 #       endif
180         }
181 #if _MSC_VER >= 1600
182 #   pragma warning(pop)
183 #endif
184
185         template <typename T>
186         static inline bool cas8_weak( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
187         {
188             return cas8_strong( pDest, expected, desired, mo_success, mo_fail );
189         }
190
191 #if _MSC_VER >= 1600
192 #   pragma warning(push)
193     // Disable warning C4800: 'char' : forcing value to bool 'true' or 'false' (performance warning)
194 #   pragma warning( disable: 4800 )
195 #endif
196         template <typename T>
197         static inline T exchange8( T volatile * pDest, T v, memory_order order ) CDS_NOEXCEPT
198         {
199             static_assert( sizeof(T) == 1, "Illegal operand size" );
200
201 #       if _MSC_VER >= 1600
202             return (T) _InterlockedExchange8( reinterpret_cast<char volatile *>(pDest), (char) v );
203 #       else
204             __asm {
205                 mov al, v;
206                 mov ecx, pDest;
207                 lock xchg byte ptr [ecx], al;
208             }
209 #       endif
210         }
211 #if _MSC_VER >= 1600
212 #   pragma warning(pop)
213 #endif
214
215         template <typename T>
216         static inline void store8( T volatile * pDest, T src, memory_order order ) CDS_NOEXCEPT
217         {
218             static_assert( sizeof(T) == 1, "Illegal operand size" );
219             assert( order ==  memory_order_relaxed
220                 || order ==  memory_order_release
221                 || order == memory_order_seq_cst
222                 );
223             assert( pDest != NULL );
224
225             if ( order != memory_order_seq_cst ) {
226                 fence_before( order );
227                 *pDest = src;
228             }
229             else {
230                 exchange8( pDest, src, order );
231             }
232         }
233
234         template <typename T>
235         static inline T load8( T volatile const * pSrc, memory_order order ) CDS_NOEXCEPT
236         {
237             static_assert( sizeof(T) == 1, "Illegal operand size" );
238             assert( order ==  memory_order_relaxed
239                 || order ==  memory_order_consume
240                 || order ==  memory_order_acquire
241                 || order == memory_order_seq_cst
242                 );
243             assert( pSrc != NULL );
244
245             T v = *pSrc;
246             fence_after_load( order );
247             return v;
248         }
249
250         //-----------------------------------------------------------------------------
251         // 16bit primitives
252         //-----------------------------------------------------------------------------
253
254         template <typename T>
255         static inline T exchange16( T volatile * pDest, T v, memory_order /*order*/ ) CDS_NOEXCEPT
256         {
257             static_assert( sizeof(T) == 2, "Illegal operand size" );
258             assert( cds::details::is_aligned( pDest, 2 ));
259
260 #       if _MSC_VER >= 1600
261             return (T) _InterlockedExchange16( (short volatile *) pDest, (short) v );
262 #       else
263             __asm {
264                 mov ax, v;
265                 mov ecx, pDest;
266                 lock xchg word ptr [ecx], ax;
267             }
268 #       endif
269         }
270
271         template <typename T>
272         static inline void store16( T volatile * pDest, T src, memory_order order ) CDS_NOEXCEPT
273         {
274             static_assert( sizeof(T) == 2, "Illegal operand size" );
275             assert( order ==  memory_order_relaxed
276                 || order ==  memory_order_release
277                 || order == memory_order_seq_cst
278                 );
279             assert( pDest != NULL );
280             assert( cds::details::is_aligned( pDest, 2 ));
281
282             if ( order != memory_order_seq_cst ) {
283                 fence_before( order );
284                 *pDest = src;
285             }
286             else {
287                 exchange16( pDest, src, order );
288             }
289         }
290
291         template <typename T>
292         static inline T load16( T volatile const * pSrc, memory_order order ) CDS_NOEXCEPT
293         {
294             static_assert( sizeof(T) == 2, "Illegal operand size" );
295             assert( order ==  memory_order_relaxed
296                 || order ==  memory_order_consume
297                 || order ==  memory_order_acquire
298                 || order ==  memory_order_seq_cst
299                 );
300             assert( pSrc != NULL );
301             assert( cds::details::is_aligned( pSrc, 2 ));
302
303             T v = *pSrc;
304             fence_after_load( order );
305             return v;
306         }
307
308         template <typename T>
309         static inline bool cas16_strong( T volatile * pDest, T& expected, T desired, memory_order /*mo_success*/, memory_order /*mo_fail*/ ) CDS_NOEXCEPT
310         {
311             static_assert( sizeof(T) == 2, "Illegal operand size" );
312             assert( cds::details::is_aligned( pDest, 2 ));
313
314             // _InterlockedCompareExchange behave as read-write memory barriers
315             T prev = expected;
316             expected = (T) _InterlockedCompareExchange16( (short *) pDest, (short) desired, (short) expected );
317             return expected == prev;
318         }
319
320         template <typename T>
321         static inline bool cas16_weak( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
322         {
323             return cas16_strong( pDest, expected, desired, mo_success, mo_fail );
324         }
325
326         //-----------------------------------------------------------------------------
327         // 32bit primitives
328         //-----------------------------------------------------------------------------
329
330         template <typename T>
331         static inline T exchange32( T volatile * pDest, T v, memory_order /*order*/ ) CDS_NOEXCEPT
332         {
333             static_assert( sizeof(T) == 4, "Illegal operand size" );
334             assert( cds::details::is_aligned( pDest, 4 ));
335
336             return (T) _InterlockedExchange( (long *) pDest, (long) v );
337         }
338
339         template <typename T>
340         static inline void store32( T volatile * pDest, T src, memory_order order ) CDS_NOEXCEPT
341         {
342             static_assert( sizeof(T) == 4, "Illegal operand size" );
343             assert( order ==  memory_order_relaxed
344                 || order ==  memory_order_release
345                 || order == memory_order_seq_cst
346                 );
347             assert( pDest != NULL );
348             assert( cds::details::is_aligned( pDest, 4 ));
349
350             if ( order != memory_order_seq_cst ) {
351                 fence_before( order );
352                 *pDest = src;
353             }
354             else {
355                 exchange32( pDest, src, order );
356             }
357         }
358
359         template <typename T>
360         static inline T load32( T volatile const * pSrc, memory_order order ) CDS_NOEXCEPT
361         {
362             static_assert( sizeof(T) == 4, "Illegal operand size" );
363             assert( order ==  memory_order_relaxed
364                 || order ==  memory_order_consume
365                 || order ==  memory_order_acquire
366                 || order ==  memory_order_seq_cst
367                 );
368             assert( pSrc != NULL );
369             assert( cds::details::is_aligned( pSrc, 4 ));
370
371             T v( *pSrc );
372             fence_after_load( order );
373             return v;
374         }
375
376         template <typename T>
377         static inline bool cas32_strong( T volatile * pDest, T& expected, T desired, memory_order /*mo_success*/, memory_order /*mo_fail*/ ) CDS_NOEXCEPT
378         {
379             static_assert( sizeof(T) == 4, "Illegal operand size" );
380             assert( cds::details::is_aligned( pDest, 4 ));
381
382             // _InterlockedCompareExchange behave as read-write memory barriers
383             T prev = expected;
384             expected = (T) _InterlockedCompareExchange( (long *) pDest, (long) desired, (long) expected );
385             return expected == prev;
386         }
387
388         template <typename T>
389         static inline bool cas32_weak( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
390         {
391             return cas32_strong( pDest, expected, desired, mo_success, mo_fail );
392         }
393
394         // fetch_xxx may be emulated via cas32
395         // If the platform has special fetch_xxx instruction
396         // then it should define CDS_ATOMIC_fetch32_xxx_defined macro
397
398 #       define CDS_ATOMIC_fetch32_add_defined
399         template <typename T>
400         static inline T fetch32_add( T volatile * pDest, T v, memory_order /*order*/) CDS_NOEXCEPT
401         {
402             static_assert( sizeof(T) == 4, "Illegal operand size" );
403             assert( cds::details::is_aligned( pDest, 4 ));
404
405             // _InterlockedExchangeAdd behave as read-write memory barriers
406             return (T) _InterlockedExchangeAdd( (long *) pDest, (long) v );
407         }
408
409         //-----------------------------------------------------------------------------
410         // 64bit primitives
411         //-----------------------------------------------------------------------------
412
413         template <typename T>
414         static inline bool cas64_strong( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
415         {
416             static_assert( sizeof(T) == 8, "Illegal operand size" );
417             assert( cds::details::is_aligned( pDest, 8 ));
418
419             // _InterlockedCompareExchange behave as read-write memory barriers
420             T prev = expected;
421             expected = (T) _InterlockedCompareExchange64( (__int64 *) pDest, (__int64) desired, (__int64) expected );
422             return expected == prev;
423         }
424
425         template <typename T>
426         static inline bool cas64_weak( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
427         {
428             return cas64_strong( pDest, expected, desired, mo_success, mo_fail );
429         }
430
431         template <typename T>
432         static inline T load64( T volatile const * pSrc, memory_order order ) CDS_NOEXCEPT
433         {
434             static_assert( sizeof(T) == 8, "Illegal operand size" );
435             assert( order ==  memory_order_relaxed
436                 || order ==  memory_order_consume
437                 || order ==  memory_order_acquire
438                 || order ==  memory_order_seq_cst
439                 );
440             assert( pSrc != NULL );
441             assert( cds::details::is_aligned( pSrc, 8 ));
442
443             // Atomically loads 64bit value by SSE intrinsics
444             __m128i volatile v = _mm_loadl_epi64( (__m128i const *) pSrc );
445             fence_after_load( order );
446             return (T) v.m128i_i64[0];
447         }
448
449
450         template <typename T>
451         static inline T exchange64( T volatile * pDest, T v, memory_order order ) CDS_NOEXCEPT
452         {
453             static_assert( sizeof(T) == 8, "Illegal operand size" );
454
455             T cur = load64( pDest, memory_order_relaxed );
456             do {
457             } while (!cas64_weak( pDest, cur, v, order, memory_order_relaxed ));
458             return cur;
459         }
460
461         template <typename T>
462         static inline void store64( T volatile * pDest, T val, memory_order order ) CDS_NOEXCEPT
463         {
464             static_assert( sizeof(T) == 8, "Illegal operand size" );
465             assert( order ==  memory_order_relaxed
466                 || order ==  memory_order_release
467                 || order == memory_order_seq_cst
468                 );
469             assert( pDest != NULL );
470             assert( cds::details::is_aligned( pDest, 8 ));
471
472             if ( order != memory_order_seq_cst ) {
473                 __m128i v;
474                 v.m128i_i64[0] = val;
475                 fence_before( order );
476                 _mm_storel_epi64( (__m128i *) pDest, v );
477             }
478             else {
479                 exchange64( pDest, val, order );
480             }
481         }
482
483
484         //-----------------------------------------------------------------------------
485         // pointer primitives
486         //-----------------------------------------------------------------------------
487
488         template <typename T>
489         static inline T * exchange_ptr( T * volatile * pDest, T * v, memory_order order ) CDS_NOEXCEPT
490         {
491             static_assert( sizeof(T *) == sizeof(void *), "Illegal operand size" );
492             return (T *) _InterlockedExchange( (long volatile *) pDest, (uintptr_t) v );
493             //return (T *) _InterlockedExchangePointer( (void * volatile *) pDest, reinterpret_cast<void *>(v) );
494         }
495
496         template <typename T>
497         static inline void store_ptr( T * volatile * pDest, T * src, memory_order order ) CDS_NOEXCEPT
498         {
499             static_assert( sizeof(T *) == sizeof(void *), "Illegal operand size" );
500             assert( order ==  memory_order_relaxed
501                 || order ==  memory_order_release
502                 || order == memory_order_seq_cst
503                 );
504             assert( pDest != NULL );
505
506             if ( order != memory_order_seq_cst ) {
507                 fence_before( order );
508                 *pDest = src;
509             }
510             else {
511                 exchange_ptr( pDest, src, order );
512             }
513         }
514
515         template <typename T>
516         static inline T * load_ptr( T * volatile const * pSrc, memory_order order ) CDS_NOEXCEPT
517         {
518             static_assert( sizeof(T *) == sizeof(void *), "Illegal operand size" );
519             assert( order ==  memory_order_relaxed
520                 || order ==  memory_order_consume
521                 || order ==  memory_order_acquire
522                 || order ==  memory_order_seq_cst
523                 );
524             assert( pSrc != NULL );
525
526             T * v = *pSrc;
527             fence_after_load( order );
528             return v;
529         }
530
531         template <typename T>
532         static inline bool cas_ptr_strong( T * volatile * pDest, T *& expected, T * desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
533         {
534             static_assert( sizeof(T *) == sizeof(void *), "Illegal operand size" );
535
536             // _InterlockedCompareExchangePointer behave as read-write memory barriers
537             T * prev = expected;
538             expected = (T *) _InterlockedCompareExchange( (long volatile *) pDest, (uintptr_t) desired, (uintptr_t) prev );
539             return expected == prev;
540         }
541
542         template <typename T>
543         static inline bool cas_ptr_weak( T * volatile * pDest, T *& expected, T * desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
544         {
545             return cas_ptr_strong( pDest, expected, desired, mo_success, mo_fail );
546         }
547     }} // namespace vc::x86
548
549 #ifndef CDS_CXX11_INLINE_NAMESPACE_SUPPORT
550     using namespace vc::x86;
551 #endif
552     } // namespace platform
553 }}  // namespace cds::cxx11_atomics
554 //@endcond
555
556 #endif // #ifndef __CDS_COMPILER_VC_X86_CXX11_ATOMIC_H