Replace NULL with nullptr
[libcds.git] / cds / compiler / gcc / sparc / cxx11_atomic.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_COMPILER_GCC_SPARC_CXX11_ATOMIC_H
4 #define __CDS_COMPILER_GCC_SPARC_CXX11_ATOMIC_H
5
6 #include <cstdint>
7
8 /*
9     Source:
10
11     1. [Doug Lea "JSR-133 Cookbook for Compiler Writers]:
12
13         Acquire semantics: load; LoadLoad+LoadStore
14         Release semantics: LoadStore+StoreStore; store
15
16     2. boost::atomic library by Helge Bahman
17     3. OpenSparc source code
18 */
19
20 #if CDS_OS_TYPE == CDS_OS_LINUX
21 #   define CDS_SPARC_RMO_MEMORY_MODEL
22 #endif
23
24 #define CDS_SPARC_MB_FULL    "membar #Sync \n\t"
25 #ifdef CDS_SPARC_RMO_MEMORY_MODEL
26         // RMO memory model (Linux only?..) Untested
27 #   define CDS_SPARC_MB_LL_LS       "membar #LoadLoad|#LoadStore \n\t"
28 #   define CDS_SPARC_MB_LS_SS       "membar #LoadStore|#StoreStore \n\t"
29 #   define CDS_SPARC_MB_LL_LS_SS    "membar #LoadLoad|#LoadStore|#StoreStore \n\t"
30 #else
31         // TSO memory model (default; Solaris uses this model)
32 #   define CDS_SPARC_MB_LL_LS
33 #   define CDS_SPARC_MB_LS_SS
34 #   define CDS_SPARC_MB_LL_LS_SS
35 #endif
36
37 #define CDS_SPARC_MB_ACQ        CDS_SPARC_MB_LL_LS
38 #define CDS_SPARC_MB_REL        CDS_SPARC_MB_LS_SS
39 #define CDS_SPARC_MB_ACQ_REL    CDS_SPARC_MB_LL_LS_SS
40 #define CDS_SPARC_MB_SEQ_CST    CDS_SPARC_MB_FULL
41
42 //@cond
43 namespace cds { namespace cxx11_atomics {
44     namespace platform { CDS_CXX11_INLINE_NAMESPACE namespace gcc { CDS_CXX11_INLINE_NAMESPACE namespace Sparc {
45
46         static inline void fence_before( memory_order order ) CDS_NOEXCEPT
47         {
48             switch(order) {
49             case memory_order_relaxed:
50             case memory_order_acquire:
51             case memory_order_consume:
52                 break;
53             case memory_order_release:
54             case memory_order_acq_rel:
55                 __asm__ __volatile__ ( "" CDS_SPARC_MB_REL ::: "memory" );
56                 break;
57             case memory_order_seq_cst:
58                 __asm__ __volatile__ ( "" CDS_SPARC_MB_FULL ::: "memory" );
59                 break;
60             }
61         }
62
63         static inline void fence_after( memory_order order ) CDS_NOEXCEPT
64         {
65             switch(order) {
66             case memory_order_relaxed:
67             case memory_order_consume:
68             case memory_order_release:
69                 break;
70             case memory_order_acquire:
71             case memory_order_acq_rel:
72                 __asm__ __volatile__ ( "" CDS_SPARC_MB_ACQ ::: "memory" );
73                 break;
74             case memory_order_seq_cst:
75                 __asm__ __volatile__ ( "" CDS_SPARC_MB_FULL ::: "memory" );
76                 break;
77             }
78         }
79
80
81         //-----------------------------------------------------------------------------
82         // fences
83         //-----------------------------------------------------------------------------
84         static inline void thread_fence(memory_order order) CDS_NOEXCEPT
85         {
86             switch(order)
87             {
88                 case memory_order_relaxed:
89                 case memory_order_consume:
90                     break;
91                 case memory_order_acquire:
92                     __asm__ __volatile__ ( "" CDS_SPARC_MB_ACQ ::: "memory" );
93                     break;
94                 case memory_order_release:
95                     __asm__ __volatile__ ( "" CDS_SPARC_MB_REL ::: "memory" );
96                     break;
97                 case memory_order_acq_rel:
98                     __asm__ __volatile__ ( "" CDS_SPARC_MB_ACQ_REL ::: "memory" );
99                     break;
100                 case memory_order_seq_cst:
101                     __asm__ __volatile__ ( "" CDS_SPARC_MB_SEQ_CST ::: "memory"  );
102                     break;
103                 default:;
104             }
105         }
106
107         static inline void signal_fence(memory_order order) CDS_NOEXCEPT
108         {
109             // C++11: 29.8.8: only compiler optimization, no hardware instructions
110             switch(order)
111             {
112                 case memory_order_relaxed:
113                     break;
114                 case memory_order_consume:
115                 case memory_order_release:
116                 case memory_order_acquire:
117                 case memory_order_acq_rel:
118                 case memory_order_seq_cst:
119                     CDS_COMPILER_RW_BARRIER;
120                     break;
121                 default:;
122             }
123         }
124
125         //-----------------------------------------------------------------------------
126         // atomic flag primitives
127         //-----------------------------------------------------------------------------
128
129         typedef unsigned char atomic_flag_type;
130         static inline bool atomic_flag_tas( atomic_flag_type volatile * pFlag, memory_order order ) CDS_NOEXCEPT
131         {
132             atomic_flag_type fCur;
133             fence_before( order );
134             __asm__ __volatile__(
135                 "ldstub    [%[pFlag]], %[fCur] \n\t"
136                 : [fCur] "=r"(fCur)
137                 : [pFlag] "r"(pFlag)
138                 : "memory", "cc"
139                 );
140             fence_after( order );
141             return fCur != 0;
142         }
143
144         static inline void atomic_flag_clear( atomic_flag_type volatile * pFlag, memory_order order ) CDS_NOEXCEPT
145         {
146             fence_before( order );
147             __asm__ __volatile__(
148                 CDS_SPARC_MB_REL
149                 "stub    %%g0, [%[pFlag]] \n\t"
150                 :: [pFlag] "r"(pFlag)
151                 : "memory"
152             );
153             fence_after( order );
154         }
155
156         //-----------------------------------------------------------------------------
157         // 32bit primitives
158         //-----------------------------------------------------------------------------
159
160         template <typename T>
161         static inline void store32( T volatile * pDest, T src, memory_order order ) CDS_NOEXCEPT
162         {
163             static_assert( sizeof(T) == 4, "Illegal size of operand" );
164             assert( order ==  memory_order_relaxed
165                 || order ==  memory_order_release
166                 || order == memory_order_seq_cst
167                 );
168             assert( pDest );
169
170             fence_before(order);
171             *pDest = src;
172             fence_after(order);
173         }
174
175         template <typename T>
176         static inline T load32( T volatile const * pSrc, memory_order order ) CDS_NOEXCEPT
177         {
178             static_assert( sizeof(T) == 4, "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             fence_before(order);
187             T v = *pSrc;
188             fence_after(order);
189             return v;
190         }
191
192         template <typename T>
193         static inline bool cas32_strong( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
194         {
195             static_assert( sizeof(T) == 4, "Illegal size of operand" );
196             assert( pDest );
197
198             fence_before( mo_success );
199             __asm__ __volatile__(
200                 "cas [%[pDest]], %[expected], %[desired]"
201                 : [desired] "+r" (desired)
202                 : [pDest] "r" (pDest), [expected] "r" (expected)
203                 : "memory"
204                 );
205
206             // desired contains current value
207
208             bool bSuccess = desired == expected;
209             if ( bSuccess )
210                 fence_after( mo_success );
211             else {
212                 fence_after(mo_fail);
213                 expected = desired;
214             }
215
216             return bSuccess;
217         }
218
219         template <typename T>
220         static inline bool cas32_weak( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
221         {
222             return cas32_strong( pDest, expected, desired, mo_success, mo_fail );
223         }
224
225         template <typename T>
226         static inline T exchange32( T volatile * pDest, T v, memory_order order ) CDS_NOEXCEPT
227         {
228             static_assert( sizeof(T) == 4, "Illegal size of operand" );
229             assert( pDest );
230
231             // This primitive could be implemented via "swap" instruction but "swap" is deprecated in UltraSparc
232
233             T cur = load32( pDest, memory_order_relaxed );
234             do {} while ( !cas32_strong( pDest, cur, v, order, memory_order_relaxed ));
235             return cur;
236         }
237
238         //-----------------------------------------------------------------------------
239         // 64bit primitives
240         //-----------------------------------------------------------------------------
241
242         template <typename T>
243         static inline T load64( T volatile const * pSrc, memory_order order ) CDS_NOEXCEPT
244         {
245             static_assert( sizeof(T) == 8, "Illegal size of operand" );
246             assert( order ==  memory_order_relaxed
247                 || order ==  memory_order_consume
248                 || order ==  memory_order_acquire
249                 || order ==  memory_order_seq_cst
250                 );
251             assert( pSrc );
252
253             fence_before(order);
254             T v = *pSrc;
255             fence_after(order);
256             return v;
257         }
258
259         template <typename T>
260         static inline void store64( T volatile * pDest, T val, memory_order order ) CDS_NOEXCEPT
261         {
262             static_assert( sizeof(T) == 8, "Illegal size of operand" );
263             assert( order ==  memory_order_relaxed
264                 || order ==  memory_order_release
265                 || order == memory_order_seq_cst
266                 );
267             assert( pDest );
268
269             fence_before(order);
270             *pDest = val;
271             fence_after(order);
272
273         }
274
275         template <typename T>
276         static inline bool cas64_strong( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
277         {
278             static_assert( sizeof(T) == 8, "Illegal size of operand" );
279             assert( pDest );
280
281             fence_before( mo_success );
282             __asm__ __volatile__(
283                 "casx [%[pDest]], %[expected], %[desired]"
284                 : [desired] "+r" (desired)
285                 : [pDest] "r" (pDest), [expected] "r" (expected)
286                 : "memory"
287                 );
288
289             // desired contains current value
290
291             bool bSuccess = desired == expected;
292             if ( bSuccess ) {
293                 fence_after( mo_success );
294             }
295             else {
296                 fence_after(mo_fail);
297                 expected = desired;
298             }
299
300             return bSuccess;
301         }
302
303         template <typename T>
304         static inline bool cas64_weak( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
305         {
306             return cas64_strong( pDest, expected, desired, mo_success, mo_fail );
307         }
308
309         template <typename T>
310         static inline T exchange64( T volatile * pDest, T v, memory_order order ) CDS_NOEXCEPT
311         {
312             static_assert( sizeof(T) == 8, "Illegal size of operand" );
313             assert( pDest );
314
315             T cur = load64( pDest, memory_order_relaxed );
316             do {} while ( !cas64_strong( pDest, cur, v, order, memory_order_relaxed ));
317             return cur;
318         }
319
320         //-----------------------------------------------------------------------------
321         // 8bit primitives
322         //-----------------------------------------------------------------------------
323
324         template <typename T>
325         static inline void store8( T volatile * pDest, T src, memory_order order ) CDS_NOEXCEPT
326         {
327             static_assert( sizeof(T) == 1, "Illegal size of operand" );
328             assert( order ==  memory_order_relaxed
329                 || order ==  memory_order_release
330                 || order == memory_order_seq_cst
331                 );
332             assert( pDest );
333
334             fence_before( order );
335             *pDest = src;
336             fence_after( order );
337         }
338
339         template <typename T>
340         static inline T load8( T volatile const * pSrc, memory_order order ) CDS_NOEXCEPT
341         {
342             static_assert( sizeof(T) == 1, "Illegal size of operand" );
343             assert( order ==  memory_order_relaxed
344                 || order ==  memory_order_consume
345                 || order ==  memory_order_acquire
346                 || order == memory_order_seq_cst
347                 );
348             assert( pSrc );
349
350             fence_before( order );
351             T v = *pSrc;
352             fence_after( order );
353             return v;
354         }
355
356         template <typename T>
357         static inline bool cas8_strong( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
358         {
359             static_assert( sizeof(T) == 1, "Illegal size of operand" );
360             assert( pDest );
361
362             union u32 {
363                 uint32_t    w;
364                 T           c[4];
365             };
366             static_assert( sizeof(u32) == sizeof(uint32_t), "Argument size error" );
367
368             u32 volatile *  pDest32 = (u32 *)( uintptr_t( pDest ) & ~0x03 );
369             size_t const  nCharIdx = (size_t)( uintptr_t( pDest ) & 0x03 );
370             u32 uExpected;
371             u32 uDesired;
372
373             bool bSuccess;
374             for (;;) {
375                 uExpected.w =
376                     uDesired.w = pDest32->w;
377                 uExpected.c[nCharIdx] = expected;
378                 uDesired.c[nCharIdx] = desired;
379
380                 bSuccess = cas32_weak( reinterpret_cast<uint32_t volatile *>(pDest32), uExpected.w, uDesired.w, mo_success, mo_fail );
381                 if ( bSuccess || uExpected.c[nCharIdx] != expected )
382                     break;
383             }
384
385             expected = uExpected.c[nCharIdx];
386             return bSuccess;
387         }
388
389         template <typename T>
390         static inline bool cas8_weak( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
391         {
392             static_assert( sizeof(T) == 1, "Illegal size of operand" );
393             assert( pDest );
394
395             union u32 {
396                 uint32_t    w;
397                 T           c[4];
398             };
399             static_assert( sizeof(u32) == sizeof(uint32_t), "Argument size error" );
400
401             u32 volatile * pDest32 = (u32 *)( uintptr_t( pDest ) & ~0x03 );
402             size_t const  nCharIdx = (size_t)( uintptr_t( pDest ) & 0x03 );
403             u32 uExpected;
404             u32 uDesired;
405
406             uExpected.w =
407                 uDesired.w = pDest32->w;
408             uExpected.c[nCharIdx] = expected;
409             uDesired.c[nCharIdx] = desired;
410
411             bool bSuccess = cas32_weak( reinterpret_cast<uint32_t volatile *>(pDest32), uExpected.w, uDesired.w, mo_success, mo_fail );
412
413             expected = uExpected.c[nCharIdx];
414             return bSuccess;
415         }
416
417         template <typename T>
418         static inline T exchange8( T volatile * pDest, T v, memory_order order ) CDS_NOEXCEPT
419         {
420             static_assert( sizeof(T) == 1, "Illegal size of operand" );
421             assert( pDest );
422
423             T cur = load8( pDest, memory_order_relaxed );
424             do {} while ( !cas8_strong( pDest, cur, v, order, memory_order_relaxed ));
425             return cur;
426         }
427
428         //-----------------------------------------------------------------------------
429         // 16bit primitives
430         //-----------------------------------------------------------------------------
431
432         template <typename T>
433         static inline T load16( T volatile const * pSrc, memory_order order ) CDS_NOEXCEPT
434         {
435             static_assert( sizeof(T) == 2, "Illegal size of operand" );
436             assert( order ==  memory_order_relaxed
437                 || order ==  memory_order_consume
438                 || order ==  memory_order_acquire
439                 || order ==  memory_order_seq_cst
440                 );
441             assert( pSrc );
442
443             fence_before( order );
444             T v = *pSrc;
445             fence_after( order );
446             return v;
447         }
448
449         template <typename T>
450         static inline void store16( T volatile * pDest, T src, memory_order order ) CDS_NOEXCEPT
451         {
452             static_assert( sizeof(T) == 2, "Illegal size of operand" );
453             assert( order ==  memory_order_relaxed
454                 || order ==  memory_order_release
455                 || order == memory_order_seq_cst
456                 );
457             assert( pDest );
458
459             fence_before(order);
460             *pDest = src;
461             fence_after(order);
462         }
463
464         template <typename T>
465         static inline bool cas16_strong( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
466         {
467             static_assert( sizeof(T) == 2, "Illegal size of operand" );
468             assert( pDest );
469
470             union u32 {
471                 uint32_t    w;
472                 T           c[2];
473             };
474             static_assert( sizeof(u32) == sizeof(uint32_t), "Argument size error" );
475
476             u32 volatile *  pDest32 = (u32 *)( uintptr_t( pDest ) & ~0x03 );
477             size_t const  nIdx = (size_t)( (uintptr_t( pDest ) >> 1) & 0x01 );
478             u32 uExpected;
479             u32 uDesired;
480
481             bool bSuccess;
482             for (;;) {
483                 uExpected.w =
484                     uDesired.w = pDest32->w;
485                 uExpected.c[nIdx] = expected;
486                 uDesired.c[nIdx] = desired;
487
488                 bSuccess = cas32_weak( reinterpret_cast<uint32_t volatile *>(pDest32), uExpected.w, uDesired.w, mo_success, mo_fail );
489                 if ( bSuccess || uExpected.c[nIdx] != expected )
490                     break;
491             }
492
493             expected = uExpected.c[nIdx];
494             return bSuccess;
495         }
496
497         template <typename T>
498         static inline bool cas16_weak( T volatile * pDest, T& expected, T desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
499         {
500             static_assert( sizeof(T) == 2, "Illegal size of operand" );
501             assert( pDest );
502
503             union u32 {
504                 uint32_t    w;
505                 T           c[2];
506             };
507             static_assert( sizeof(u32) == sizeof(uint32_t), "Argument size error" );
508
509             u32 volatile * pDest32 = (u32 *)( uintptr_t( pDest ) & ~0x03 );
510             size_t const  nIdx = (size_t)( (uintptr_t( pDest ) >> 1) & 0x01 );
511             u32 uExpected;
512             u32 uDesired;
513
514             uExpected.w =
515                 uDesired.w = pDest32->w;
516             uExpected.c[nIdx] = expected;
517             uDesired.c[nIdx] = desired;
518
519             bool bSuccess = cas32_weak( reinterpret_cast<uint32_t volatile *>(pDest32), uExpected.w, uDesired.w, mo_success, mo_fail );
520
521             expected = uExpected.c[nIdx];
522             return bSuccess;
523         }
524
525         template <typename T>
526         static inline T exchange16( T volatile * pDest, T v, memory_order order ) CDS_NOEXCEPT
527         {
528             static_assert( sizeof(T) == 2, "Illegal size of operand" );
529             assert( pDest );
530
531             T cur = load16( pDest, memory_order_relaxed );
532             do {} while ( !cas16_strong( pDest, cur, v, order, memory_order_relaxed ));
533             return cur;
534         }
535
536         //-----------------------------------------------------------------------------
537         // pointer primitives
538         //-----------------------------------------------------------------------------
539
540         template <typename T>
541         static inline void store_ptr( T * volatile * pDest, T * src, memory_order order ) CDS_NOEXCEPT
542         {
543             static_assert( sizeof(T *) == sizeof(void *), "Illegal size of operand" );
544             assert( order ==  memory_order_relaxed
545                 || order ==  memory_order_release
546                 || order == memory_order_seq_cst
547                 );
548             assert( pDest );
549
550             fence_before(order);
551             *pDest = src;
552             fence_after(order);
553         }
554
555         template <typename T>
556         static inline T * load_ptr( T * volatile const * pSrc, memory_order order ) CDS_NOEXCEPT
557         {
558             static_assert( sizeof(T *) == sizeof(void *), "Illegal size of operand" );
559             assert( order ==  memory_order_relaxed
560                 || order ==  memory_order_consume
561                 || order ==  memory_order_acquire
562                 || order ==  memory_order_seq_cst
563                 );
564             assert( pSrc );
565
566             fence_before( order );
567             T * v = *pSrc;
568             fence_after( order );
569             return v;
570         }
571
572         template <typename T>
573         static inline bool cas_ptr_strong( T * volatile * pDest, T *& expected, T * desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
574         {
575             static_assert( sizeof(T *) == sizeof(void *), "Illegal size of operand" );
576
577             return cas64_strong( (uint64_t volatile *) pDest, *reinterpret_cast<uint64_t *>( &expected ), (uint64_t) desired, mo_success, mo_fail );
578         }
579
580         template <typename T>
581         static inline bool cas_ptr_weak( T * volatile * pDest, T *& expected, T * desired, memory_order mo_success, memory_order mo_fail ) CDS_NOEXCEPT
582         {
583             return cas_ptr_strong( pDest, expected, desired, mo_success, mo_fail );
584         }
585
586         template <typename T>
587         static inline T * exchange_ptr( T * volatile * pDest, T * v, memory_order order ) CDS_NOEXCEPT
588         {
589             static_assert( sizeof(T *) == sizeof(void *), "Illegal size of operand" );
590             return (T *) exchange64( (uint64_t volatile *) pDest, (uint64_t) v, order );
591         }
592
593     }} // namespace gcc::Sparc
594
595 #ifndef CDS_CXX11_INLINE_NAMESPACE_SUPPORT
596     using namespace gcc::Sparc;
597 #endif
598     }   // namespace platform
599 }}  // namespace cds::cxx11_atomics
600 //@endcond
601
602 #undef CDS_SPARC_MB_ACQ
603 #undef CDS_SPARC_MB_REL
604 #undef CDS_SPARC_MB_SEQ_CST
605 #undef CDS_SPARC_MB_FULL
606 #undef CDS_SPARC_MB_LL_LS
607 #undef CDS_SPARC_MB_LS_SS
608 #undef CDS_SPARC_MB_LL_LS_SS
609
610 #endif // #ifndef __CDS_COMPILER_GCC_AMD64_CXX11_ATOMIC_H