2 * atomic.h: Atomic operations
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
10 #ifndef _WAPI_ATOMIC_H_
11 #define _WAPI_ATOMIC_H_
15 #include "mono/io-layer/wapi.h"
17 #if defined(__i386__) || defined(__x86_64__)
18 #define WAPI_ATOMIC_ASM
21 * NB: The *Pointer() functions here assume that
22 * sizeof(pointer)==sizeof(gint32)
24 * NB2: These asm functions assume 486+ (some of the opcodes dont
25 * exist on 386). If this becomes an issue, we can get configure to
26 * fall back to the non-atomic C versions of these calls.
29 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
30 gint32 exch, gint32 comp)
34 __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
35 : "=m" (*dest), "=a" (old)
36 : "r" (exch), "m" (*dest), "a" (comp));
40 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
44 __asm__ __volatile__ ("lock; "
51 : "=m" (*dest), "=a" (old)
52 : "r" (exch), "m" (*dest), "a" (comp));
57 static inline gint32 InterlockedIncrement(volatile gint32 *val)
61 __asm__ __volatile__ ("lock; xaddl %0, %1"
62 : "=r" (tmp), "=m" (*val)
63 : "0" (1), "m" (*val));
68 static inline gint32 InterlockedDecrement(volatile gint32 *val)
72 __asm__ __volatile__ ("lock; xaddl %0, %1"
73 : "=r" (tmp), "=m" (*val)
74 : "0" (-1), "m" (*val));
81 * http://msdn.microsoft.com/library/en-us/dnmag00/html/win320700.asp?frame=true
82 * for the reasons for using cmpxchg and a loop here.
84 * That url is no longer valid, but it's still in the google cache at the
85 * moment: http://www.google.com/search?q=cache:http://msdn.microsoft.com/library/en-us/dnmag00/html/win320700.asp?frame=true
87 * For the time being, http://msdn.microsoft.com/msdnmag/issues/0700/Win32/
88 * might work. Bet it will change soon enough though.
90 static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new_val)
94 __asm__ __volatile__ ("1:; lock; cmpxchgl %2, %0; jne 1b"
95 : "=m" (*val), "=a" (ret)
96 : "r" (new_val), "m" (*val), "a" (*val));
101 static inline gpointer InterlockedExchangePointer(volatile gpointer *val,
106 __asm__ __volatile__ ("1:; lock; "
113 : "=m" (*val), "=a" (ret)
114 : "r" (new_val), "m" (*val), "a" (*val));
119 static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
123 __asm__ __volatile__ ("lock; xaddl %0, %1"
124 : "=r" (ret), "=m" (*val)
125 : "0" (add), "m" (*val));
130 #elif (defined(sparc) || defined (__sparc__)) && defined(__GNUC__)
131 #define WAPI_ATOMIC_ASM
134 static inline gint32 InterlockedCompareExchange(volatile gint32 *_dest, gint32 _exch, gint32 _comp)
136 register volatile gint32 *dest asm("g1") = _dest;
137 register gint32 comp asm("o4") = _comp;
138 register gint32 exch asm("o5") = _exch;
140 __asm__ __volatile__(
141 /* cas [%%g1], %%o4, %%o5 */
144 : "0" (exch), "r" (dest), "r" (comp)
151 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *_dest, gpointer _exch, gpointer _comp)
153 register volatile gpointer *dest asm("g1") = _dest;
154 register gpointer comp asm("o4") = _comp;
155 register gpointer exch asm("o5") = _exch;
157 __asm__ __volatile__(
159 /* casx [%%g1], %%o4, %%o5 */
162 /* cas [%%g1], %%o4, %%o5 */
166 : "0" (exch), "r" (dest), "r" (comp)
173 static inline gint32 InterlockedIncrement(volatile gint32 *_dest)
175 register volatile gint32 *dest asm("g1") = _dest;
176 register gint32 tmp asm("o4");
177 register gint32 ret asm("o5");
179 __asm__ __volatile__(
180 "1: ld [%%g1], %%o4\n\t"
181 " add %%o4, 1, %%o5\n\t"
182 /* cas [%%g1], %%o4, %%o5 */
183 " .word 0xdbe0500c\n\t"
184 " cmp %%o4, %%o5\n\t"
187 : "=&r" (tmp), "=&r" (ret)
195 static inline gint32 InterlockedDecrement(volatile gint32 *_dest)
197 register volatile gint32 *dest asm("g1") = _dest;
198 register gint32 tmp asm("o4");
199 register gint32 ret asm("o5");
201 __asm__ __volatile__(
202 "1: ld [%%g1], %%o4\n\t"
203 " sub %%o4, 1, %%o5\n\t"
204 /* cas [%%g1], %%o4, %%o5 */
205 " .word 0xdbe0500c\n\t"
206 " cmp %%o4, %%o5\n\t"
209 : "=&r" (tmp), "=&r" (ret)
217 static inline gint32 InterlockedExchange(volatile gint32 *_dest, gint32 exch)
219 register volatile gint32 *dest asm("g1") = _dest;
220 register gint32 tmp asm("o4");
221 register gint32 ret asm("o5");
223 __asm__ __volatile__(
224 "1: ld [%%g1], %%o4\n\t"
226 /* cas [%%g1], %%o4, %%o5 */
227 " .word 0xdbe0500c\n\t"
228 " cmp %%o4, %%o5\n\t"
231 : "=&r" (tmp), "=&r" (ret)
232 : "r" (dest), "r" (exch)
239 static inline gpointer InterlockedExchangePointer(volatile gpointer *_dest, gpointer exch)
241 register volatile gpointer *dest asm("g1") = _dest;
242 register gpointer tmp asm("o4");
243 register gpointer ret asm("o5");
245 __asm__ __volatile__(
247 "1: ldx [%%g1], %%o4\n\t"
249 "1: ld [%%g1], %%o4\n\t"
253 /* casx [%%g1], %%o4, %%o5 */
254 " .word 0xdbf0500c\n\t"
256 /* cas [%%g1], %%o4, %%o5 */
257 " .word 0xdbe0500c\n\t"
259 " cmp %%o4, %%o5\n\t"
262 : "=&r" (tmp), "=&r" (ret)
263 : "r" (dest), "r" (exch)
270 static inline gint32 InterlockedExchangeAdd(volatile gint32 *_dest, gint32 add)
272 register volatile gint32 *dest asm("g1") = _dest;
273 register gint32 tmp asm("o4");
274 register gint32 ret asm("o5");
276 __asm__ __volatile__(
277 "1: ld [%%g1], %%o4\n\t"
278 " add %%o4, %3, %%o5\n\t"
279 /* cas [%%g1], %%o4, %%o5 */
280 " .word 0xdbe0500c\n\t"
281 " cmp %%o4, %%o5\n\t"
283 " add %%o5, %3, %%o5"
284 : "=&r" (tmp), "=&r" (ret)
285 : "r" (dest), "r" (add)
293 #define WAPI_ATOMIC_ASM
296 InterlockedCompareExchange(volatile gint32 *dest,
297 gint32 exch, gint32 comp)
301 __asm__ __volatile__ ("\tLA\t1,%0\n"
304 : "+m" (*dest), "=&r" (old)
305 : "r" (exch), "r" (comp)
311 static inline gpointer
312 InterlockedCompareExchangePointer(volatile gpointer *dest,
313 gpointer exch, gpointer comp)
317 __asm__ __volatile__ ("\tLA\t1,%0\n"
320 : "+m" (*dest), "=&r" (old)
321 : "r" (exch), "r" (comp)
326 static inline gpointer
327 InterlockedCompareExchangePointer(volatile gpointer *dest,
333 __asm__ __volatile__ ("\tLA\t1,%0\n"
335 "\tCSG\t%1,%2,0(1)\n"
336 : "+m" (*dest), "=&r" (old)
337 : "r" (exch), "r" (comp)
346 InterlockedIncrement(volatile gint32 *val)
350 __asm__ __volatile__ ("\tLA\t2,%1\n"
357 : "=r" (tmp), "+m" (*val)
364 InterlockedIncrement(volatile gint32 *val)
368 __asm__ __volatile__ ("\tLA\t2,%1\n"
375 : "=r" (tmp), "+m" (*val)
384 InterlockedDecrement(volatile gint32 *val)
388 __asm__ __volatile__ ("\tLA\t2,%1\n"
395 : "=r" (tmp), "+m" (*val)
402 InterlockedDecrement(volatile gint32 *val)
406 __asm__ __volatile__ ("\tLA\t2,%1\n"
413 : "=r" (tmp), "+m" (*val)
421 InterlockedExchange(volatile gint32 *val, gint32 new_val)
425 __asm__ __volatile__ ("\tLA\t1,%0\n"
429 : "+m" (*val), "=&r" (ret)
437 static inline gpointer
438 InterlockedExchangePointer(volatile gpointer *val, gpointer new_val)
442 __asm__ __volatile__ ("\tLA\t1,%0\n"
446 : "+m" (*val), "=&r" (ret)
453 static inline gpointer
454 InterlockedExchangePointer(volatile gpointer *val, gpointer new_val)
458 __asm__ __volatile__ ("\tLA\t1,%0\n"
460 "\tCSG\t%1,%2,0(1)\n"
462 : "+m" (*val), "=&r" (ret)
472 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
476 __asm__ __volatile__ ("\tLA\t2,%1\n"
482 : "=&r" (ret), "+m" (*val)
490 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
494 __asm__ __volatile__ ("\tLA\t2,%1\n"
500 : "=&r" (ret), "+m" (*val)
508 #elif defined(__ppc__) || defined (__powerpc__)
509 #define WAPI_ATOMIC_ASM
511 static inline gint32 InterlockedIncrement(volatile gint32 *val)
513 gint32 result = 0, tmp;
515 __asm__ __volatile__ ("\n1:\n\t"
516 "lwarx %0, 0, %2\n\t"
518 "stwcx. %1, 0, %2\n\t"
520 : "=&b" (result), "=&b" (tmp): "r" (val): "cc", "memory");
524 static inline gint32 InterlockedDecrement(volatile gint32 *val)
526 gint32 result = 0, tmp;
528 __asm__ __volatile__ ("\n1:\n\t"
529 "lwarx %0, 0, %2\n\t"
530 "addi %1, %0, -1\n\t"
531 "stwcx. %1, 0, %2\n\t"
533 : "=&b" (result), "=&b" (tmp): "r" (val): "cc", "memory");
537 #define InterlockedCompareExchangePointer(dest,exch,comp) (gpointer)InterlockedCompareExchange((volatile gint32 *)(dest), (gint32)(exch), (gint32)(comp))
539 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
540 gint32 exch, gint32 comp) {
543 __asm__ __volatile__ ("\n1:\n\t"
544 "lwarx %0, 0, %1\n\t"
547 "stwcx. %3, 0, %1\n\t"
551 : "b" (dest), "r" (comp), "r" (exch): "cc", "memory");
555 static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
559 __asm__ __volatile__ ("\n1:\n\t"
560 "lwarx %0, 0, %2\n\t"
561 "stwcx. %3, 0, %2\n\t"
563 : "=r" (tmp) : "0" (tmp), "b" (dest), "r" (exch): "cc", "memory");
566 #define InterlockedExchangePointer(dest,exch) (gpointer)InterlockedExchange((volatile gint32 *)(dest), (gint32)(exch))
568 static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
571 __asm__ __volatile__ ("\n1:\n\t"
572 "lwarx %0, 0, %2\n\t"
574 "stwcx. %1, 0, %2\n\t"
576 : "=&r" (result), "=&r" (tmp)
577 : "r" (dest), "r" (add) : "cc", "memory");
581 #elif defined(__arm__)
582 #define WAPI_ATOMIC_ASM
584 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp)
588 __asm__ __volatile__ ( "0:\n\t"
593 "swp %0, %3, [%2]\n\t"
595 "swpne %3, %0, [%2]\n\t"
598 : "=&r" (a), "=&r" (b)
599 : "r" (dest), "r" (exch), "r" (comp)
605 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
609 __asm__ __volatile__ ( "0:\n\t"
614 "swpeq %0, %3, [%2]\n\t"
616 "swpne %3, %0, [%2]\n\t"
619 : "=&r" (a), "=&r" (b)
620 : "r" (dest), "r" (exch), "r" (comp)
626 static inline gint32 InterlockedIncrement(volatile gint32 *dest)
630 __asm__ __volatile__ ( "0:\n\t"
633 "swp %2, %1, [%3]\n\t"
635 "swpne %1, %2, [%3]\n\t"
637 : "=&r" (a), "=&r" (b), "=&r" (c)
638 : "r" (dest), "r" (1)
644 static inline gint32 InterlockedDecrement(volatile gint32 *dest)
648 __asm__ __volatile__ ( "0:\n\t"
651 "swp %2, %1, [%3]\n\t"
653 "swpne %1, %2, [%3]\n\t"
655 : "=&r" (a), "=&r" (b), "=&r" (c)
656 : "r" (dest), "r" (-1)
662 static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
666 __asm__ __volatile__ ( "swp %0, %2, [%1]"
668 : "r" (dest), "r" (exch));
673 static inline gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch)
677 __asm__ __volatile__ ( "swp %0, %2, [%1]"
679 : "r" (dest), "r" (exch));
684 static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
688 __asm__ __volatile__ ( "0:\n\t"
691 "swp %2, %1, [%3]\n\t"
693 "swpne %1, %2, [%3]\n\t"
695 : "=&r" (a), "=&r" (b), "=&r" (c)
696 : "r" (dest), "r" (add)
702 #elif defined(__ia64__)
703 #define WAPI_ATOMIC_ASM
705 #ifdef __INTEL_COMPILER
706 #include <ia64intrin.h>
709 static inline gint32 InterlockedCompareExchange(gint32 volatile *dest,
710 gint32 exch, gint32 comp)
715 #ifdef __INTEL_COMPILER
716 old = _InterlockedCompareExchange (dest, exch, comp);
718 /* cmpxchg4 zero extends the value read from memory */
719 real_comp = (guint64)(guint32)comp;
720 asm volatile ("mov ar.ccv = %2 ;;\n\t"
721 "cmpxchg4.acq %0 = [%1], %3, ar.ccv\n\t"
722 : "=r" (old) : "r" (dest), "r" (real_comp), "r" (exch));
728 static inline gpointer InterlockedCompareExchangePointer(gpointer volatile *dest,
729 gpointer exch, gpointer comp)
733 #ifdef __INTEL_COMPILER
734 old = _InterlockedCompareExchangePointer (dest, exch, comp);
736 asm volatile ("mov ar.ccv = %2 ;;\n\t"
737 "cmpxchg8.acq %0 = [%1], %3, ar.ccv\n\t"
738 : "=r" (old) : "r" (dest), "r" (comp), "r" (exch));
744 static inline gint32 InterlockedIncrement(gint32 volatile *val)
746 #ifdef __INTEL_COMPILER
747 return _InterlockedIncrement (val);
753 } while (InterlockedCompareExchange (val, old + 1, old) != old);
759 static inline gint32 InterlockedDecrement(gint32 volatile *val)
761 #ifdef __INTEL_COMPILER
762 return _InterlockedDecrement (val);
768 } while (InterlockedCompareExchange (val, old - 1, old) != old);
774 static inline gint32 InterlockedExchange(gint32 volatile *dest, gint32 new_val)
776 #ifdef __INTEL_COMPILER
777 return _InterlockedExchange (dest, new_val);
783 } while (InterlockedCompareExchange (dest, new_val, res) != res);
789 static inline gpointer InterlockedExchangePointer(gpointer volatile *dest, gpointer new_val)
791 #ifdef __INTEL_COMPILER
792 return (gpointer)_InterlockedExchange64 ((gint64*)dest, (gint64)new_val);
798 } while (InterlockedCompareExchangePointer (dest, new_val, res) != res);
804 static inline gint32 InterlockedExchangeAdd(gint32 volatile *val, gint32 add)
808 #ifdef __INTEL_COMPILER
809 old = _InterlockedExchangeAdd (val, add);
813 } while (InterlockedCompareExchange (val, old + add, old) != old);
819 #elif defined(__alpha__)
820 #define WAPI_ATOMIC_ASM
822 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
823 gint32 exch, gint32 comp)
825 gint32 old, temp, temp2;
826 long compq = comp, exchq = exch;
828 __asm__ __volatile__ (
831 " cmpeq %2, %5, %3\n"
832 " cmovne %3, %4, %2\n"
835 : "=m" (*dest), "=&r" (old), "=&r" (temp), "=&r" (temp2)
836 : "r" (exchq), "r" (compq), "m" (*dest));
840 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
842 gpointer old, temp, temp2;
844 __asm__ __volatile__ (
847 " cmpeq %2, %5, %3\n"
848 " cmovne %3, %4, %2\n"
851 : "=m" (*dest), "=&r" (old), "=&r" (temp), "=&r" (temp2)
852 : "r" (exch), "r" (comp), "m" (*dest));
856 static inline gint32 InterlockedIncrement(volatile gint32 *val)
860 __asm__ __volatile__ (
866 : "=&r" (temp), "=m" (*val), "=r" (cur)
867 : "Ir" (1), "m" (*val));
871 static inline gint32 InterlockedDecrement(volatile gint32 *val)
875 __asm__ __volatile__ (
881 : "=&r" (temp), "=m" (*val), "=r" (cur)
882 : "Ir" (1), "m" (*val));
886 static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new_val)
890 __asm__ __volatile__ (
895 : "=m" (*val), "=&r" (ret), "=&r" (temp)
896 : "r" (new_val), "m" (*val));
900 static inline gpointer InterlockedExchangePointer(volatile gpointer *val, gpointer new_val)
904 __asm__ __volatile__ (
909 : "=m" (*val), "=&r" (ret), "=&r" (temp)
910 : "r" (new_val), "m" (*val));
914 static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
918 __asm__ __volatile__ (
924 : "=m" (*val), "=&r" (ret), "=&r" (temp)
925 : "r" (add), "m" (*val));
930 #elif defined(__mips__)
931 #define WAPI_ATOMIC_ASM
933 static inline gint32 InterlockedIncrement(volatile gint32 *val)
935 gint32 tmp, result = 0;
937 __asm__ __volatile__ (" .set mips32\n"
943 : "=&r" (result), "=&r" (tmp), "=m" (*val)
948 static inline gint32 InterlockedDecrement(volatile gint32 *val)
950 gint32 tmp, result = 0;
952 __asm__ __volatile__ (" .set mips32\n"
958 : "=&r" (result), "=&r" (tmp), "=m" (*val)
963 #define InterlockedCompareExchangePointer(dest,exch,comp) InterlockedCompareExchange((volatile gint32 *)(dest), (gint32)(exch), (gint32)(comp))
965 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
966 gint32 exch, gint32 comp) {
969 __asm__ __volatile__ (" .set mips32\n"
976 : "=&r" (old), "=&r" (tmp), "=m" (*dest)
977 : "m" (*dest), "r" (exch), "r" (comp));
981 static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
985 __asm__ __volatile__ (" .set mips32\n"
991 : "=&r" (result), "=&r" (tmp), "=m" (*dest)
992 : "m" (*dest), "r" (exch));
995 #define InterlockedExchangePointer(dest,exch) InterlockedExchange((volatile gint32 *)(dest), (gint32)(exch))
997 static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
1001 __asm__ __volatile__ (" .set mips32\n"
1003 " addu %1, %0, %4\n"
1007 : "=&r" (result), "=&r" (tmp), "=m" (*dest)
1008 : "m" (*dest), "r" (add));
1014 extern gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp);
1015 extern gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp);
1016 extern gint32 InterlockedIncrement(volatile gint32 *dest);
1017 extern gint32 InterlockedDecrement(volatile gint32 *dest);
1018 extern gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch);
1019 extern gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch);
1020 extern gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add);
1022 #if defined(__hppa__)
1023 #define WAPI_ATOMIC_ASM
1028 #endif /* _WAPI_ATOMIC_H_ */