Update some copyrights
[mono.git] / mono / io-layer / atomic.h
1 /*
2  * atomic.h:  Atomic operations
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  * Copyright 2012 Xamarin Inc
9  */
10
11 #ifndef _WAPI_ATOMIC_H_
12 #define _WAPI_ATOMIC_H_
13
14 #if defined(__NetBSD__)
15 #include <sys/param.h>
16
17 #if __NetBSD_Version__ > 499004000
18 #include <sys/atomic.h>
19 #define HAVE_ATOMIC_OPS
20 #endif
21
22 #endif
23
24 #include <glib.h>
25
26 #include "mono/io-layer/wapi.h"
27
28 #if defined(__NetBSD__) && defined(HAVE_ATOMIC_OPS)
29
30 #define WAPI_ATOMIC_ASM
31 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
32        gint32 exch, gint32 comp)
33 {
34        return atomic_cas_32((uint32_t*)dest, comp, exch);
35 }
36
37 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
38 {
39        return atomic_cas_ptr(dest, comp, exch);
40 }
41
42 static inline gint32 InterlockedIncrement(volatile gint32 *val)
43 {
44        return atomic_inc_32_nv((uint32_t*)val);
45 }
46
47 static inline gint32 InterlockedDecrement(volatile gint32 *val)
48 {
49        return atomic_dec_32_nv((uint32_t*)val);
50 }
51
52 static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new_val)
53 {
54        return atomic_swap_32((uint32_t*)val, new_val);
55 }
56
57 static inline gpointer InterlockedExchangePointer(volatile gpointer *val,
58                gpointer new_val)
59 {
60        return atomic_swap_ptr(val, new_val);
61 }
62
63 static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
64 {
65        return atomic_add_32_nv((uint32_t*)val, add) - add;
66 }
67
68 #elif defined(__i386__) || defined(__x86_64__)
69 #define WAPI_ATOMIC_ASM
70
71 /*
72  * NB: The *Pointer() functions here assume that
73  * sizeof(pointer)==sizeof(gint32)
74  *
75  * NB2: These asm functions assume 486+ (some of the opcodes dont
76  * exist on 386).  If this becomes an issue, we can get configure to
77  * fall back to the non-atomic C versions of these calls.
78  */
79
80 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
81                                                 gint32 exch, gint32 comp)
82 {
83         gint32 old;
84
85         __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
86                               : "=m" (*dest), "=a" (old)
87                               : "r" (exch), "m" (*dest), "a" (comp));   
88         return(old);
89 }
90
91 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
92 {
93         gpointer old;
94
95         __asm__ __volatile__ ("lock; "
96 #if defined(__x86_64__)  && !defined(__native_client__)
97                               "cmpxchgq"
98 #else
99                               "cmpxchgl"
100 #endif
101                               " %2, %0"
102                               : "=m" (*dest), "=a" (old)
103                               : "r" (exch), "m" (*dest), "a" (comp));   
104
105         return(old);
106 }
107
108 static inline gint32 InterlockedIncrement(volatile gint32 *val)
109 {
110         gint32 tmp;
111         
112         __asm__ __volatile__ ("lock; xaddl %0, %1"
113                               : "=r" (tmp), "=m" (*val)
114                               : "0" (1), "m" (*val));
115
116         return(tmp+1);
117 }
118
119 static inline gint32 InterlockedDecrement(volatile gint32 *val)
120 {
121         gint32 tmp;
122         
123         __asm__ __volatile__ ("lock; xaddl %0, %1"
124                               : "=r" (tmp), "=m" (*val)
125                               : "0" (-1), "m" (*val));
126
127         return(tmp-1);
128 }
129
130 /*
131  * See
132  * http://msdn.microsoft.com/library/en-us/dnmag00/html/win320700.asp?frame=true
133  * for the reasons for using cmpxchg and a loop here.
134  *
135  * That url is no longer valid, but it's still in the google cache at the
136  * moment: http://www.google.com/search?q=cache:http://msdn.microsoft.com/library/en-us/dnmag00/html/win320700.asp?frame=true
137  *
138  * For the time being, http://msdn.microsoft.com/msdnmag/issues/0700/Win32/
139  * might work.  Bet it will change soon enough though.
140  */
141 static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new_val)
142 {
143         gint32 ret;
144         
145         __asm__ __volatile__ ("1:; lock; cmpxchgl %2, %0; jne 1b"
146                               : "=m" (*val), "=a" (ret)
147                               : "r" (new_val), "m" (*val), "a" (*val));
148
149         return(ret);
150 }
151
152 static inline gpointer InterlockedExchangePointer(volatile gpointer *val,
153                                                   gpointer new_val)
154 {
155         gpointer ret;
156         
157         __asm__ __volatile__ ("1:; lock; "
158 #if defined(__x86_64__)  && !defined(__native_client__)
159                               "cmpxchgq"
160 #else
161                               "cmpxchgl"
162 #endif
163                               " %2, %0; jne 1b"
164                               : "=m" (*val), "=a" (ret)
165                               : "r" (new_val), "m" (*val), "a" (*val));
166
167         return(ret);
168 }
169
170 static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
171 {
172         gint32 ret;
173         
174         __asm__ __volatile__ ("lock; xaddl %0, %1"
175                               : "=r" (ret), "=m" (*val)
176                               : "0" (add), "m" (*val));
177         
178         return(ret);
179 }
180
181 #elif (defined(sparc) || defined (__sparc__)) && defined(__GNUC__)
182 #define WAPI_ATOMIC_ASM
183
184 G_GNUC_UNUSED 
185 static inline gint32 InterlockedCompareExchange(volatile gint32 *_dest, gint32 _exch, gint32 _comp)
186 {
187        register volatile gint32 *dest asm("g1") = _dest;
188        register gint32 comp asm("o4") = _comp;
189        register gint32 exch asm("o5") = _exch;
190
191        __asm__ __volatile__(
192                /* cas [%%g1], %%o4, %%o5 */
193                ".word 0xdbe0500c"
194                : "=r" (exch)
195                : "0" (exch), "r" (dest), "r" (comp)
196                : "memory");
197
198        return exch;
199 }
200
201 G_GNUC_UNUSED 
202 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *_dest, gpointer _exch, gpointer _comp)
203 {
204        register volatile gpointer *dest asm("g1") = _dest;
205        register gpointer comp asm("o4") = _comp;
206        register gpointer exch asm("o5") = _exch;
207
208        __asm__ __volatile__(
209 #ifdef SPARCV9
210                /* casx [%%g1], %%o4, %%o5 */
211                ".word 0xdbf0500c"
212 #else
213                /* cas [%%g1], %%o4, %%o5 */
214                ".word 0xdbe0500c"
215 #endif
216                : "=r" (exch)
217                : "0" (exch), "r" (dest), "r" (comp)
218                : "memory");
219
220        return exch;
221 }
222
223 G_GNUC_UNUSED 
224 static inline gint32 InterlockedIncrement(volatile gint32 *_dest)
225 {
226        register volatile gint32 *dest asm("g1") = _dest;
227        register gint32 tmp asm("o4");
228        register gint32 ret asm("o5");
229
230        __asm__ __volatile__(
231                "1:     ld      [%%g1], %%o4\n\t"
232                "       add     %%o4, 1, %%o5\n\t"
233                /*      cas     [%%g1], %%o4, %%o5 */
234                "       .word   0xdbe0500c\n\t"
235                "       cmp     %%o4, %%o5\n\t"
236                "       bne     1b\n\t"
237                "        add    %%o5, 1, %%o5"
238                : "=&r" (tmp), "=&r" (ret)
239                : "r" (dest)
240                : "memory", "cc");
241
242         return ret;
243 }
244
245 G_GNUC_UNUSED 
246 static inline gint32 InterlockedDecrement(volatile gint32 *_dest)
247 {
248        register volatile gint32 *dest asm("g1") = _dest;
249        register gint32 tmp asm("o4");
250        register gint32 ret asm("o5");
251
252        __asm__ __volatile__(
253                "1:     ld      [%%g1], %%o4\n\t"
254                "       sub     %%o4, 1, %%o5\n\t"
255                /*      cas     [%%g1], %%o4, %%o5 */
256                "       .word   0xdbe0500c\n\t"
257                "       cmp     %%o4, %%o5\n\t"
258                "       bne     1b\n\t"
259                "        sub    %%o5, 1, %%o5"
260                : "=&r" (tmp), "=&r" (ret)
261                : "r" (dest)
262                : "memory", "cc");
263
264         return ret;
265 }
266
267 G_GNUC_UNUSED
268 static inline gint32 InterlockedExchange(volatile gint32 *_dest, gint32 exch)
269 {
270        register volatile gint32 *dest asm("g1") = _dest;
271        register gint32 tmp asm("o4");
272        register gint32 ret asm("o5");
273
274        __asm__ __volatile__(
275                "1:     ld      [%%g1], %%o4\n\t"
276                "       mov     %3, %%o5\n\t"
277                /*      cas     [%%g1], %%o4, %%o5 */
278                "       .word   0xdbe0500c\n\t"
279                "       cmp     %%o4, %%o5\n\t"
280                "       bne     1b\n\t"
281                "        nop"
282                : "=&r" (tmp), "=&r" (ret)
283                : "r" (dest), "r" (exch)
284                : "memory", "cc");
285
286         return ret;
287 }
288
289 G_GNUC_UNUSED
290 static inline gpointer InterlockedExchangePointer(volatile gpointer *_dest, gpointer exch)
291 {
292        register volatile gpointer *dest asm("g1") = _dest;
293        register gpointer tmp asm("o4");
294        register gpointer ret asm("o5");
295
296        __asm__ __volatile__(
297 #ifdef SPARCV9
298                "1:     ldx     [%%g1], %%o4\n\t"
299 #else
300                "1:     ld      [%%g1], %%o4\n\t"
301 #endif
302                "       mov     %3, %%o5\n\t"
303 #ifdef SPARCV9
304                /*      casx    [%%g1], %%o4, %%o5 */
305                "       .word   0xdbf0500c\n\t"
306 #else
307                /*      cas     [%%g1], %%o4, %%o5 */
308                "       .word   0xdbe0500c\n\t"
309 #endif
310                "       cmp     %%o4, %%o5\n\t"
311                "       bne     1b\n\t"
312                "        nop"
313                : "=&r" (tmp), "=&r" (ret)
314                : "r" (dest), "r" (exch)
315                : "memory", "cc");
316
317         return ret;
318 }
319
320 G_GNUC_UNUSED
321 static inline gint32 InterlockedExchangeAdd(volatile gint32 *_dest, gint32 add)
322 {
323        register volatile gint32 *dest asm("g1") = _dest;
324        register gint32 tmp asm("o4");
325        register gint32 ret asm("o5");
326
327        __asm__ __volatile__(
328                "1:     ld      [%%g1], %%o4\n\t"
329                "       add     %%o4, %3, %%o5\n\t"
330                /*      cas     [%%g1], %%o4, %%o5 */
331                "       .word   0xdbe0500c\n\t"
332                "       cmp     %%o4, %%o5\n\t"
333                "       bne     1b\n\t"
334                "        add    %%o5, %3, %%o5"
335                : "=&r" (tmp), "=&r" (ret)
336                : "r" (dest), "r" (add)
337                : "memory", "cc");
338
339         return ret;
340 }
341
342 #elif __s390__
343
344 #define WAPI_ATOMIC_ASM
345
346 static inline gint32 
347 InterlockedCompareExchange(volatile gint32 *dest,
348                            gint32 exch, gint32 comp)
349 {
350         gint32 old;
351
352         __asm__ __volatile__ ("\tLA\t1,%0\n"
353                               "\tLR\t%1,%3\n"
354                               "\tCS\t%1,%2,0(1)\n"
355                               : "+m" (*dest), "=&r" (old)
356                               : "r" (exch), "r" (comp)
357                               : "1", "cc");     
358         return(old);
359 }
360
361 #ifndef __s390x__
362 static inline gpointer
363 InterlockedCompareExchangePointer(volatile gpointer *dest,
364                            gpointer exch, gpointer comp)
365 {
366         gpointer old;
367
368         __asm__ __volatile__ ("\tLA\t1,%0\n"
369                               "\tLR\t%1,%3\n"
370                               "\tCS\t%1,%2,0(1)\n"
371                               : "+m" (*dest), "=&r" (old)
372                               : "r" (exch), "r" (comp)
373                               : "1", "cc");     
374         return(old);
375 }
376 # else
377 static inline gpointer 
378 InterlockedCompareExchangePointer(volatile gpointer *dest, 
379                                   gpointer exch, 
380                                   gpointer comp)
381 {
382         gpointer old;
383
384         __asm__ __volatile__ ("\tLA\t1,%0\n"
385                               "\tLGR\t%1,%3\n"
386                               "\tCSG\t%1,%2,0(1)\n"
387                               : "+m" (*dest), "=&r" (old)
388                               : "r" (exch), "r" (comp)
389                               : "1", "cc");
390
391         return(old);
392 }
393 # endif
394
395 # ifndef __s390x__
396 static inline gint32 
397 InterlockedIncrement(volatile gint32 *val)
398 {
399         gint32 tmp;
400         
401         __asm__ __volatile__ ("\tLA\t2,%1\n"
402                               "0:\tL\t%0,%1\n"
403                               "\tLR\t1,%0\n"
404                               "\tAHI\t1,1\n"
405                               "\tCS\t%0,1,0(2)\n"
406                               "\tJNZ\t0b\n"
407                               "\tLR\t%0,1"
408                               : "=r" (tmp), "+m" (*val)
409                               : : "1", "2", "cc");
410
411         return(tmp);
412 }
413 # else
414 static inline gint32 
415 InterlockedIncrement(volatile gint32 *val)
416 {
417         gint32 tmp;
418         
419         __asm__ __volatile__ ("\tLA\t2,%1\n"
420                               "0:\tLGF\t%0,%1\n"
421                               "\tLGFR\t1,%0\n"
422                               "\tAGHI\t1,1\n"
423                               "\tCS\t%0,1,0(2)\n"
424                               "\tJNZ\t0b\n"
425                               "\tLGFR\t%0,1"
426                               : "=r" (tmp), "+m" (*val)
427                               : : "1", "2", "cc");
428
429         return(tmp);
430 }
431 # endif
432
433 # ifndef __s390x__
434 static inline gint32 
435 InterlockedDecrement(volatile gint32 *val)
436 {
437         gint32 tmp;
438         
439         __asm__ __volatile__ ("\tLA\t2,%1\n"
440                               "0:\tL\t%0,%1\n"
441                               "\tLR\t1,%0\n"
442                               "\tAHI\t1,-1\n"
443                               "\tCS\t%0,1,0(2)\n"
444                               "\tJNZ\t0b\n"
445                               "\tLR\t%0,1"
446                               : "=r" (tmp), "+m" (*val)
447                               : : "1", "2", "cc");
448
449         return(tmp);
450 }
451 # else
452 static inline gint32 
453 InterlockedDecrement(volatile gint32 *val)
454 {
455         gint32 tmp;
456         
457         __asm__ __volatile__ ("\tLA\t2,%1\n"
458                               "0:\tLGF\t%0,%1\n"
459                               "\tLGFR\t1,%0\n"
460                               "\tAGHI\t1,-1\n"
461                               "\tCS\t%0,1,0(2)\n"
462                               "\tJNZ\t0b\n"
463                               "\tLGFR\t%0,1"
464                               : "=r" (tmp), "+m" (*val)
465                               : : "1", "2", "cc");
466
467         return(tmp);
468 }
469 # endif
470
471 static inline gint32 
472 InterlockedExchange(volatile gint32 *val, gint32 new_val)
473 {
474         gint32 ret;
475         
476         __asm__ __volatile__ ("\tLA\t1,%0\n"
477                               "0:\tL\t%1,%0\n"
478                               "\tCS\t%1,%2,0(1)\n"
479                               "\tJNZ\t0b"
480                               : "+m" (*val), "=&r" (ret)
481                               : "r" (new_val)
482                               : "1", "cc");
483
484         return(ret);
485 }
486
487 # ifndef __s390x__
488 static inline gpointer 
489 InterlockedExchangePointer(volatile gpointer *val, gpointer new_val)
490 {
491         gpointer ret;
492         
493         __asm__ __volatile__ ("\tLA\t1,%0\n"
494                               "0:\tL\t%1,%0\n"
495                               "\tCS\t%1,%2,0(1)\n"
496                               "\tJNZ\t0b"
497                               : "+m" (*val), "=&r" (ret)
498                               : "r" (new_val)
499                               : "1", "cc");
500
501         return(ret);
502 }
503 # else
504 static inline gpointer
505 InterlockedExchangePointer(volatile gpointer *val, gpointer new_val)
506 {
507         gpointer ret;
508         
509         __asm__ __volatile__ ("\tLA\t1,%0\n"
510                               "0:\tLG\t%1,%0\n"
511                               "\tCSG\t%1,%2,0(1)\n"
512                               "\tJNZ\t0b"
513                               : "+m" (*val), "=&r" (ret)
514                               : "r" (new_val)
515                               : "1", "cc");
516
517         return(ret);
518 }
519 # endif
520
521 # ifndef __s390x__
522 static inline gint32 
523 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
524 {
525         gint32 ret;
526
527         __asm__ __volatile__ ("\tLA\t2,%1\n"
528                               "0:\tL\t%0,%1\n"
529                               "\tLR\t1,%0\n"
530                               "\tAR\t1,%2\n"
531                               "\tCS\t%0,1,0(2)\n"
532                               "\tJNZ\t0b"
533                               : "=&r" (ret), "+m" (*val)
534                               : "r" (add) 
535                               : "1", "2", "cc");
536         
537         return(ret);
538 }
539 # else
540 static inline gint32 
541 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
542 {
543         gint32 ret;
544
545         __asm__ __volatile__ ("\tLA\t2,%1\n"
546                               "0:\tLGF\t%0,%1\n"
547                               "\tLGFR\t1,%0\n"
548                               "\tAGR\t1,%2\n"
549                               "\tCS\t%0,1,0(2)\n"
550                               "\tJNZ\t0b"
551                               : "=&r" (ret), "+m" (*val)
552                               : "r" (add) 
553                               : "1", "2", "cc");
554         
555         return(ret);
556 }
557 # endif
558
559 #elif defined(__mono_ppc__)
560 #define WAPI_ATOMIC_ASM
561
562 #ifdef G_COMPILER_CODEWARRIOR
563 static inline gint32 InterlockedIncrement(volatile register gint32 *val)
564 {
565         gint32 result = 0, tmp;
566         register gint32 result = 0;
567         register gint32 tmp;
568
569         asm
570         {
571                 @1:
572                         lwarx   tmp, 0, val
573                         addi    result, tmp, 1
574                         stwcx.  result, 0, val
575                         bne-    @1
576         }
577  
578         return result;
579 }
580
581 static inline gint32 InterlockedDecrement(register volatile gint32 *val)
582 {
583         register gint32 result = 0;
584         register gint32 tmp;
585
586         asm
587         {
588                 @1:
589                         lwarx   tmp, 0, val
590                         addi    result, tmp, -1
591                         stwcx.  result, 0, val
592                         bne-    @1
593         }
594
595         return result;
596 }
597 #define InterlockedCompareExchangePointer(dest,exch,comp) (void*)InterlockedCompareExchange((volatile gint32 *)(dest), (gint32)(exch), (gint32)(comp))
598
599 static inline gint32 InterlockedCompareExchange(volatile register gint32 *dest, register gint32 exch, register gint32 comp)
600 {
601         register gint32 tmp = 0;
602
603         asm
604         {
605                 @1:
606                         lwarx   tmp, 0, dest
607                         cmpw    tmp, comp
608                         bne-    @2
609                         stwcx.  exch, 0, dest
610                         bne-    @1
611                 @2:
612         }
613
614         return tmp;
615 }
616 static inline gint32 InterlockedExchange(register volatile gint32 *dest, register gint32 exch)
617 {
618         register gint32 tmp = 0;
619
620         asm
621         {
622                 @1:
623                         lwarx   tmp, 0, dest
624                         stwcx.  exch, 0, dest
625                         bne-    @1
626         }
627
628         return tmp;
629 }
630 #define InterlockedExchangePointer(dest,exch) (void*)InterlockedExchange((volatile gint32 *)(dest), (gint32)(exch))
631 #else
632
633 #if defined(__mono_ppc64__) && !defined(__mono_ilp32__)
634 #define LDREGX "ldarx"
635 #define STREGCXD "stdcx."
636 #define CMPREG "cmpd"
637 #else
638 #define LDREGX "lwarx"
639 #define STREGCXD "stwcx."
640 #define CMPREG "cmpw"
641 #endif
642
643 static inline gint32 InterlockedIncrement(volatile gint32 *val)
644 {
645         gint32 result = 0, tmp;
646
647         __asm__ __volatile__ ("\n1:\n\t"
648                               "lwarx  %0, 0, %2\n\t"
649                               "addi   %1, %0, 1\n\t"
650                               "stwcx. %1, 0, %2\n\t"
651                               "bne-   1b"
652                               : "=&b" (result), "=&b" (tmp): "r" (val): "cc", "memory");
653         return result + 1;
654 }
655
656 static inline gint32 InterlockedDecrement(volatile gint32 *val)
657 {
658         gint32 result = 0, tmp;
659
660         __asm__ __volatile__ ("\n1:\n\t"
661                               "lwarx  %0, 0, %2\n\t"
662                               "addi   %1, %0, -1\n\t"
663                               "stwcx. %1, 0, %2\n\t"
664                               "bne-   1b"
665                               : "=&b" (result), "=&b" (tmp): "r" (val): "cc", "memory");
666         return result - 1;
667 }
668
669 static inline gpointer InterlockedCompareExchangePointer (volatile gpointer *dest,
670                                                 gpointer exch, gpointer comp)
671 {
672         gpointer tmp = NULL;
673
674         __asm__ __volatile__ ("\n1:\n\t"
675                              LDREGX " %0, 0, %1\n\t"
676                              CMPREG " %0, %2\n\t" 
677                              "bne-    2f\n\t"
678                              STREGCXD " %3, 0, %1\n\t"
679                              "bne-    1b\n"
680                              "2:"
681                              : "=&r" (tmp)
682                              : "b" (dest), "r" (comp), "r" (exch): "cc", "memory");
683         return(tmp);
684 }
685
686 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
687                                                 gint32 exch, gint32 comp) {
688         gint32 tmp = 0;
689
690         __asm__ __volatile__ ("\n1:\n\t"
691                              "lwarx   %0, 0, %1\n\t"
692                              "cmpw    %0, %2\n\t" 
693                              "bne-    2f\n\t"
694                              "stwcx.  %3, 0, %1\n\t"
695                              "bne-    1b\n"
696                              "2:"
697                              : "=&r" (tmp)
698                              : "b" (dest), "r" (comp), "r" (exch): "cc", "memory");
699         return(tmp);
700 }
701
702 static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
703 {
704         gint32 tmp = 0;
705
706         __asm__ __volatile__ ("\n1:\n\t"
707                               "lwarx  %0, 0, %2\n\t"
708                               "stwcx. %3, 0, %2\n\t"
709                               "bne    1b"
710                               : "=r" (tmp) : "0" (tmp), "b" (dest), "r" (exch): "cc", "memory");
711         return(tmp);
712 }
713
714 static inline gpointer InterlockedExchangePointer (volatile gpointer *dest, gpointer exch)
715 {
716         gpointer tmp = NULL;
717
718         __asm__ __volatile__ ("\n1:\n\t"
719                               LDREGX " %0, 0, %2\n\t"
720                               STREGCXD " %3, 0, %2\n\t"
721                               "bne    1b"
722                               : "=r" (tmp) : "0" (tmp), "b" (dest), "r" (exch): "cc", "memory");
723         return(tmp);
724 }
725
726 static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
727 {
728         gint32 result, tmp;
729         __asm__ __volatile__ ("\n1:\n\t"
730                               "lwarx  %0, 0, %2\n\t"
731                               "add    %1, %0, %3\n\t"
732                               "stwcx. %1, 0, %2\n\t"
733                               "bne    1b"
734                               : "=&r" (result), "=&r" (tmp)
735                               : "r" (dest), "r" (add) : "cc", "memory");
736         return(result);
737 }
738
739 #undef LDREGX
740 #undef STREGCXD
741 #undef CMPREG
742
743 #endif /* !G_COMPILER_CODEWARRIOR */
744
745 #elif defined(__arm__)
746 #define WAPI_ATOMIC_ASM
747
748 /*
749  * Atomic operations on ARM doesn't contain memory barriers, and the runtime code
750  * depends on this, so we add them explicitly.
751  */
752
753 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp)
754 {
755 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__)
756         gint32 ret, tmp;
757         __asm__ __volatile__ (  "1:\n"
758                                 "dmb\n"
759                                 "mov    %0, #0\n"
760                                 "ldrex %1, [%2]\n"
761                                 "teq    %1, %3\n"
762                                 "it eq\n"
763                                 "strexeq %0, %4, [%2]\n"
764                                 "teq %0, #0\n"
765                                 "bne 1b\n"
766                                 "dmb\n"
767                                 : "=&r" (tmp), "=&r" (ret)
768                                 : "r" (dest), "r" (comp), "r" (exch)
769                                 : "memory", "cc");
770
771         return ret;
772 #else
773         gint32 a, b;
774
775         __asm__ __volatile__ (    "0:\n\t"
776                                   "ldr %1, [%2]\n\t"
777                                   "cmp %1, %4\n\t"
778                                   "mov %0, %1\n\t"
779                                   "bne 1f\n\t"
780                                   "swp %0, %3, [%2]\n\t"
781                                   "cmp %0, %1\n\t"
782                                   "swpne %3, %0, [%2]\n\t"
783                                   "bne 0b\n\t"
784                                   "1:"
785                                   : "=&r" (a), "=&r" (b)
786                                   : "r" (dest), "r" (exch), "r" (comp)
787                                   : "cc", "memory");
788
789         return a;
790 #endif
791 }
792
793 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
794 {
795 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__)
796         gpointer ret, tmp;
797         __asm__ __volatile__ (
798                                 "dmb\n"
799                                 "1:\n"
800                                 "mov    %0, #0\n"
801                                 "ldrex %1, [%2]\n"
802                                 "teq    %1, %3\n"
803                                 "it eq\n"
804                                 "strexeq %0, %4, [%2]\n"
805                                 "teq %0, #0\n"
806                                 "bne 1b\n"
807                                 "dmb\n"
808                                 : "=&r" (tmp), "=&r" (ret)
809                                 : "r" (dest), "r" (comp), "r" (exch)
810                                 : "memory", "cc");
811
812         return ret;
813 #else
814         gpointer a, b;
815
816         __asm__ __volatile__ (    "0:\n\t"
817                                   "ldr %1, [%2]\n\t"
818                                   "cmp %1, %4\n\t"
819                                   "mov %0, %1\n\t"
820                                   "bne 1f\n\t"
821                                   "swpeq %0, %3, [%2]\n\t"
822                                   "cmp %0, %1\n\t"
823                                   "swpne %3, %0, [%2]\n\t"
824                                   "bne 0b\n\t"
825                                   "1:"
826                                   : "=&r" (a), "=&r" (b)
827                                   : "r" (dest), "r" (exch), "r" (comp)
828                                   : "cc", "memory");
829
830         return a;
831 #endif
832 }
833
834 static inline gint32 InterlockedIncrement(volatile gint32 *dest)
835 {
836 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__)
837         gint32 ret, flag;
838         __asm__ __volatile__ (
839                                 "dmb\n"
840                                 "1:\n"
841                                 "ldrex %0, [%2]\n"
842                                 "add %0, %0, %3\n"
843                                 "strex %1, %0, [%2]\n"
844                                 "teq %1, #0\n"
845                                 "bne 1b\n"
846                                 "dmb\n"
847                                 : "=&r" (ret), "=&r" (flag)
848                                 : "r" (dest), "r" (1)
849                                 : "memory", "cc");
850
851         return ret;
852 #else
853         gint32 a, b, c;
854
855         __asm__ __volatile__ (  "0:\n\t"
856                                 "ldr %0, [%3]\n\t"
857                                 "add %1, %0, %4\n\t"
858                                 "swp %2, %1, [%3]\n\t"
859                                 "cmp %0, %2\n\t"
860                                 "swpne %1, %2, [%3]\n\t"
861                                 "bne 0b"
862                                 : "=&r" (a), "=&r" (b), "=&r" (c)
863                                 : "r" (dest), "r" (1)
864                                 : "cc", "memory");
865
866         return b;
867 #endif
868 }
869
870 static inline gint32 InterlockedDecrement(volatile gint32 *dest)
871 {
872 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__)
873         gint32 ret, flag;
874         __asm__ __volatile__ (
875                                 "dmb\n"
876                                 "1:\n"
877                                 "ldrex %0, [%2]\n"
878                                 "sub %0, %0, %3\n"
879                                 "strex %1, %0, [%2]\n"
880                                 "teq %1, #0\n"
881                                 "bne 1b\n"
882                                 "dmb\n"
883                                 : "=&r" (ret), "=&r" (flag)
884                                 : "r" (dest), "r" (1)
885                                 : "memory", "cc");
886
887         return ret;
888 #else
889         gint32 a, b, c;
890
891         __asm__ __volatile__ (  "0:\n\t"
892                                 "ldr %0, [%3]\n\t"
893                                 "add %1, %0, %4\n\t"
894                                 "swp %2, %1, [%3]\n\t"
895                                 "cmp %0, %2\n\t"
896                                 "swpne %1, %2, [%3]\n\t"
897                                 "bne 0b"
898                                 : "=&r" (a), "=&r" (b), "=&r" (c)
899                                 : "r" (dest), "r" (-1)
900                                 : "cc", "memory");
901
902         return b;
903 #endif
904 }
905
906 static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
907 {
908 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__)
909         gint32 ret, flag;
910         __asm__ __volatile__ (
911                                   "dmb\n"
912                               "1:\n"
913                               "ldrex %0, [%3]\n"
914                               "strex %1, %2, [%3]\n"
915                               "teq %1, #0\n"
916                               "bne 1b\n"
917                                   "dmb\n"
918                               : "=&r" (ret), "=&r" (flag)
919                               : "r" (exch), "r" (dest)
920                               : "memory", "cc");
921         return ret;
922 #else
923         gint32 a;
924
925         __asm__ __volatile__ (  "swp %0, %2, [%1]"
926                                 : "=&r" (a)
927                                 : "r" (dest), "r" (exch));
928
929         return a;
930 #endif
931 }
932
933 static inline gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch)
934 {
935 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__)
936         gpointer ret, flag;
937         __asm__ __volatile__ (
938                                   "dmb\n"
939                               "1:\n"
940                               "ldrex %0, [%3]\n"
941                               "strex %1, %2, [%3]\n"
942                               "teq %1, #0\n"
943                               "bne 1b\n"
944                                   "dmb\n"
945                               : "=&r" (ret), "=&r" (flag)
946                               : "r" (exch), "r" (dest)
947                               : "memory", "cc");
948         return ret;
949 #else
950         gpointer a;
951
952         __asm__ __volatile__ (  "swp %0, %2, [%1]"
953                                 : "=&r" (a)
954                                 : "r" (dest), "r" (exch));
955
956         return a;
957 #endif
958 }
959
960 static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
961 {
962 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__)
963         gint32 ret, tmp, flag;
964         __asm__ __volatile__ (
965                                 "dmb\n"
966                                 "1:\n"
967                                 "ldrex %0, [%3]\n"
968                                 "add %1, %0, %4\n"
969                                 "strex %2, %1, [%3]\n"
970                                 "teq %2, #0\n"
971                                 "bne 1b\n"
972                                 "dmb\n"
973                                 : "=&r" (ret), "=&r" (tmp), "=&r" (flag)
974                                 : "r" (dest), "r" (add)
975                                 : "memory", "cc");
976
977         return ret;
978 #else
979         int a, b, c;
980
981         __asm__ __volatile__ (  "0:\n\t"
982                                 "ldr %0, [%3]\n\t"
983                                 "add %1, %0, %4\n\t"
984                                 "swp %2, %1, [%3]\n\t"
985                                 "cmp %0, %2\n\t"
986                                 "swpne %1, %2, [%3]\n\t"
987                                 "bne 0b"
988                                 : "=&r" (a), "=&r" (b), "=&r" (c)
989                                 : "r" (dest), "r" (add)
990                                 : "cc", "memory");
991
992         return a;
993 #endif
994 }
995
996 #elif defined(__ia64__)
997 #define WAPI_ATOMIC_ASM
998
999 #ifdef __INTEL_COMPILER
1000 #include <ia64intrin.h>
1001 #endif
1002
1003 static inline gint32 InterlockedCompareExchange(gint32 volatile *dest,
1004                                                 gint32 exch, gint32 comp)
1005 {
1006         gint32 old;
1007         guint64 real_comp;
1008
1009 #ifdef __INTEL_COMPILER
1010         old = _InterlockedCompareExchange (dest, exch, comp);
1011 #else
1012         /* cmpxchg4 zero extends the value read from memory */
1013         real_comp = (guint64)(guint32)comp;
1014         asm volatile ("mov ar.ccv = %2 ;;\n\t"
1015                                   "cmpxchg4.acq %0 = [%1], %3, ar.ccv\n\t"
1016                                   : "=r" (old) : "r" (dest), "r" (real_comp), "r" (exch));
1017 #endif
1018
1019         return(old);
1020 }
1021
1022 static inline gpointer InterlockedCompareExchangePointer(gpointer volatile *dest,
1023                                                 gpointer exch, gpointer comp)
1024 {
1025         gpointer old;
1026
1027 #ifdef __INTEL_COMPILER
1028         old = _InterlockedCompareExchangePointer (dest, exch, comp);
1029 #else
1030         asm volatile ("mov ar.ccv = %2 ;;\n\t"
1031                                   "cmpxchg8.acq %0 = [%1], %3, ar.ccv\n\t"
1032                                   : "=r" (old) : "r" (dest), "r" (comp), "r" (exch));
1033 #endif
1034
1035         return(old);
1036 }
1037
1038 static inline gint32 InterlockedIncrement(gint32 volatile *val)
1039 {
1040 #ifdef __INTEL_COMPILER
1041         return _InterlockedIncrement (val);
1042 #else
1043         gint32 old;
1044
1045         do {
1046                 old = *val;
1047         } while (InterlockedCompareExchange (val, old + 1, old) != old);
1048
1049         return old + 1;
1050 #endif
1051 }
1052
1053 static inline gint32 InterlockedDecrement(gint32 volatile *val)
1054 {
1055 #ifdef __INTEL_COMPILER
1056         return _InterlockedDecrement (val);
1057 #else
1058         gint32 old;
1059
1060         do {
1061                 old = *val;
1062         } while (InterlockedCompareExchange (val, old - 1, old) != old);
1063
1064         return old - 1;
1065 #endif
1066 }
1067
1068 static inline gint32 InterlockedExchange(gint32 volatile *dest, gint32 new_val)
1069 {
1070 #ifdef __INTEL_COMPILER
1071         return _InterlockedExchange (dest, new_val);
1072 #else
1073         gint32 res;
1074
1075         do {
1076                 res = *dest;
1077         } while (InterlockedCompareExchange (dest, new_val, res) != res);
1078
1079         return res;
1080 #endif
1081 }
1082
1083 static inline gpointer InterlockedExchangePointer(gpointer volatile *dest, gpointer new_val)
1084 {
1085 #ifdef __INTEL_COMPILER
1086         return (gpointer)_InterlockedExchange64 ((gint64*)dest, (gint64)new_val);
1087 #else
1088         gpointer res;
1089
1090         do {
1091                 res = *dest;
1092         } while (InterlockedCompareExchangePointer (dest, new_val, res) != res);
1093
1094         return res;
1095 #endif
1096 }
1097
1098 static inline gint32 InterlockedExchangeAdd(gint32 volatile *val, gint32 add)
1099 {
1100         gint32 old;
1101
1102 #ifdef __INTEL_COMPILER
1103         old = _InterlockedExchangeAdd (val, add);
1104 #else
1105         do {
1106                 old = *val;
1107         } while (InterlockedCompareExchange (val, old + add, old) != old);
1108
1109         return old;
1110 #endif
1111 }
1112
1113 #elif defined(__alpha__)
1114 #define WAPI_ATOMIC_ASM
1115
1116 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
1117                                                 gint32 exch, gint32 comp)
1118 {
1119         gint32 old, temp, temp2;
1120         long compq = comp, exchq = exch;
1121
1122         __asm__ __volatile__ (
1123                 "1:     ldl_l %2, %0\n"
1124                 "       mov %2, %1\n"
1125                 "       cmpeq %2, %5, %3\n"
1126                 "       cmovne %3, %4, %2\n"
1127                 "       stl_c %2, %0\n"
1128                 "       beq %2, 1b\n"
1129                 : "=m" (*dest), "=&r" (old), "=&r" (temp), "=&r" (temp2)
1130                 : "r" (exchq), "r" (compq), "m" (*dest));
1131         return(old);
1132 }
1133
1134 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
1135 {
1136         gpointer old, temp, temp2;
1137
1138         __asm__ __volatile__ (
1139                 "1:     ldq_l %2, %0\n"
1140                 "       mov %2, %1\n"
1141                 "       cmpeq %2, %5, %3\n"
1142                 "       cmovne %3, %4, %2\n"
1143                 "       stq_c %2, %0\n"
1144                 "       beq %2, 1b\n"
1145                 : "=m" (*dest), "=&r" (old), "=&r" (temp), "=&r" (temp2)
1146                 : "r" (exch), "r" (comp), "m" (*dest));
1147         return(old);
1148 }
1149
1150 static inline gint32 InterlockedIncrement(volatile gint32 *val)
1151 {
1152         gint32 temp, cur;
1153         
1154         __asm__ __volatile__ (
1155                 "1:     ldl_l %0, %1\n"
1156                 "       addl %0, %3, %0\n"
1157                 "       mov %0, %2\n"
1158                 "       stl_c %0, %1\n"
1159                 "       beq %0, 1b\n"
1160                 : "=&r" (temp), "=m" (*val), "=r" (cur)
1161                 : "Ir" (1), "m" (*val));
1162         return(cur);
1163 }
1164
1165 static inline gint32 InterlockedDecrement(volatile gint32 *val)
1166 {
1167         gint32 temp, cur;
1168         
1169         __asm__ __volatile__ (
1170                 "1:     ldl_l %0, %1\n"
1171                 "       subl %0, %3, %0\n"
1172                 "       mov %0, %2\n"
1173                 "       stl_c %0, %1\n"
1174                 "       beq %0, 1b\n"
1175                 : "=&r" (temp), "=m" (*val), "=r" (cur)
1176                 : "Ir" (1), "m" (*val));
1177         return(cur);
1178 }
1179
1180 static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new_val)
1181 {
1182         gint32 ret, temp;
1183
1184         __asm__ __volatile__ (
1185                 "1:     ldl_l %1, %0\n"
1186                 "       mov %3, %2\n"
1187                 "       stl_c %2, %0\n"
1188                 "       beq %2, 1b\n"
1189                 : "=m" (*val), "=&r" (ret), "=&r" (temp)
1190                 : "r" (new_val), "m" (*val));
1191         return(ret);
1192 }
1193
1194 static inline gpointer InterlockedExchangePointer(volatile gpointer *val, gpointer new_val)
1195 {
1196         gpointer ret, temp;
1197
1198         __asm__ __volatile__ (
1199                 "1:     ldq_l %1, %0\n"
1200                 "       mov %3, %2\n"
1201                 "       stq_c %2, %0\n"
1202                 "       beq %2, 1b\n"
1203                 : "=m" (*val), "=&r" (ret), "=&r" (temp)
1204                 : "r" (new_val), "m" (*val));
1205         return(ret);
1206 }
1207
1208 static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
1209 {
1210         gint32 ret, temp;
1211         
1212         __asm__ __volatile__ (
1213                 "1:     ldl_l   %2, %0\n"
1214                 "       mov     %2, %1\n"
1215                 "       addl    %2, %3, %2\n"
1216                 "       stl_c   %2, %0\n"
1217                 "       beq     %2, 1b\n"
1218                 : "=m" (*val), "=&r" (ret), "=&r" (temp)
1219                 : "r" (add), "m" (*val));
1220         
1221         return(ret);
1222 }
1223
1224 #elif defined(__mips__)
1225 #define WAPI_ATOMIC_ASM
1226
1227 #if SIZEOF_REGISTER == 8
1228 #error "Not implemented."
1229 #endif
1230
1231 static inline gint32 InterlockedIncrement(volatile gint32 *val)
1232 {
1233         gint32 tmp, result = 0;
1234
1235         __asm__ __volatile__ ("    .set    mips32\n"
1236                               "1:  ll      %0, %2\n"
1237                               "    addu    %1, %0, 1\n"
1238                               "    sc      %1, %2\n"
1239                               "    beqz    %1, 1b\n"
1240                               "    .set    mips0\n"
1241                               : "=&r" (result), "=&r" (tmp), "=m" (*val)
1242                               : "m" (*val));
1243         return result + 1;
1244 }
1245
1246 static inline gint32 InterlockedDecrement(volatile gint32 *val)
1247 {
1248         gint32 tmp, result = 0;
1249
1250         __asm__ __volatile__ ("    .set    mips32\n"
1251                               "1:  ll      %0, %2\n"
1252                               "    subu    %1, %0, 1\n"
1253                               "    sc      %1, %2\n"
1254                               "    beqz    %1, 1b\n"
1255                               "    .set    mips0\n"
1256                               : "=&r" (result), "=&r" (tmp), "=m" (*val)
1257                               : "m" (*val));
1258         return result - 1;
1259 }
1260
1261 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
1262                                                 gint32 exch, gint32 comp) {
1263         gint32 old, tmp;
1264
1265         __asm__ __volatile__ ("    .set    mips32\n"
1266                               "1:  ll      %0, %2\n"
1267                               "    bne     %0, %5, 2f\n"
1268                               "    move    %1, %4\n"
1269                               "    sc      %1, %2\n"
1270                               "    beqz    %1, 1b\n"
1271                               "2:  .set    mips0\n"
1272                               : "=&r" (old), "=&r" (tmp), "=m" (*dest)
1273                               : "m" (*dest), "r" (exch), "r" (comp));
1274         return(old);
1275 }
1276
1277 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
1278 {
1279         return (gpointer)(InterlockedCompareExchange((volatile gint32 *)(dest), (gint32)(exch), (gint32)(comp)));
1280 }
1281
1282 static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
1283 {
1284         gint32 result, tmp;
1285
1286         __asm__ __volatile__ ("    .set    mips32\n"
1287                               "1:  ll      %0, %2\n"
1288                               "    move    %1, %4\n"
1289                               "    sc      %1, %2\n"
1290                               "    beqz    %1, 1b\n"
1291                               "    .set    mips0\n"
1292                               : "=&r" (result), "=&r" (tmp), "=m" (*dest)
1293                               : "m" (*dest), "r" (exch));
1294         return(result);
1295 }
1296
1297 static inline gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch)
1298 {
1299         return (gpointer)InterlockedExchange((volatile gint32 *)(dest), (gint32)(exch));
1300 }
1301
1302 static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
1303 {
1304         gint32 result, tmp;
1305
1306         __asm__ __volatile__ ("    .set    mips32\n"
1307                               "1:  ll      %0, %2\n"
1308                               "    addu    %1, %0, %4\n"
1309                               "    sc      %1, %2\n"
1310                               "    beqz    %1, 1b\n"
1311                               "    .set    mips0\n"
1312                               : "=&r" (result), "=&r" (tmp), "=m" (*dest)
1313                               : "m" (*dest), "r" (add));
1314         return result;
1315 }
1316
1317 #else
1318
1319 extern gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp);
1320 extern gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp);
1321 extern gint32 InterlockedIncrement(volatile gint32 *dest);
1322 extern gint32 InterlockedDecrement(volatile gint32 *dest);
1323 extern gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch);
1324 extern gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch);
1325 extern gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add);
1326
1327 #if defined(__hppa__)
1328 #define WAPI_ATOMIC_ASM
1329 #endif
1330
1331 #endif
1332
1333 #endif /* _WAPI_ATOMIC_H_ */