Flush (work in progress)
[mono.git] / mono / io-layer / atomic.h
index 85e86b1577e1c2d6f0237129f811bb0abd24a838..2fd0e5e131e40e2a9e62df6e106bc55064382a20 100644 (file)
 #ifndef _WAPI_ATOMIC_H_
 #define _WAPI_ATOMIC_H_
 
+#if defined(__NetBSD__)
+#include <sys/param.h>
+
+#if __NetBSD_Version__ > 499004000
+#include <sys/atomic.h>
+#define HAVE_ATOMIC_OPS
+#endif
+
+#endif
+
 #include <glib.h>
 
 #include "mono/io-layer/wapi.h"
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__NetBSD__) && defined(HAVE_ATOMIC_OPS)
+
+#define WAPI_ATOMIC_ASM
+static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
+       gint32 exch, gint32 comp)
+{
+       return atomic_cas_32((uint32_t*)dest, comp, exch);
+}
+
+static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
+{
+       return atomic_cas_ptr(dest, comp, exch);
+}
+
+static inline gint32 InterlockedIncrement(volatile gint32 *val)
+{
+       return atomic_inc_32_nv((uint32_t*)val);
+}
+
+static inline gint32 InterlockedDecrement(volatile gint32 *val)
+{
+       return atomic_dec_32_nv((uint32_t*)val);
+}
+
+static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new_val)
+{
+       return atomic_swap_32((uint32_t*)val, new_val);
+}
+
+static inline gpointer InterlockedExchangePointer(volatile gpointer *val,
+               gpointer new_val)
+{
+       return atomic_swap_ptr(val, new_val);
+}
+
+static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
+{
+       return atomic_add_32_nv((uint32_t*)val, add) - add;
+}
+
+#elif defined(__i386__) || defined(__x86_64__)
 #define WAPI_ATOMIC_ASM
 
 /*
@@ -301,7 +351,7 @@ InterlockedCompareExchange(volatile gint32 *dest,
        __asm__ __volatile__ ("\tLA\t1,%0\n"
                              "\tLR\t%1,%3\n"
                              "\tCS\t%1,%2,0(1)\n"
-                             : "+m" (*dest), "=r" (old)
+                             : "+m" (*dest), "=&r" (old)
                              : "r" (exch), "r" (comp)
                              : "1", "cc");     
        return(old);
@@ -317,7 +367,7 @@ InterlockedCompareExchangePointer(volatile gpointer *dest,
        __asm__ __volatile__ ("\tLA\t1,%0\n"
                              "\tLR\t%1,%3\n"
                              "\tCS\t%1,%2,0(1)\n"
-                             : "+m" (*dest), "=r" (old)
+                             : "+m" (*dest), "=&r" (old)
                              : "r" (exch), "r" (comp)
                              : "1", "cc");     
        return(old);
@@ -333,7 +383,7 @@ InterlockedCompareExchangePointer(volatile gpointer *dest,
        __asm__ __volatile__ ("\tLA\t1,%0\n"
                              "\tLGR\t%1,%3\n"
                              "\tCSG\t%1,%2,0(1)\n"
-                             : "+m" (*dest), "=r" (old)
+                             : "+m" (*dest), "=&r" (old)
                              : "r" (exch), "r" (comp)
                              : "1", "cc");
 
@@ -426,7 +476,7 @@ InterlockedExchange(volatile gint32 *val, gint32 new_val)
                              "0:\tL\t%1,%0\n"
                              "\tCS\t%1,%2,0(1)\n"
                              "\tJNZ\t0b"
-                             : "+m" (*val), "=r" (ret)
+                             : "+m" (*val), "=&r" (ret)
                              : "r" (new_val)
                              : "1", "cc");
 
@@ -443,7 +493,7 @@ InterlockedExchangePointer(volatile gpointer *val, gpointer new_val)
                              "0:\tL\t%1,%0\n"
                              "\tCS\t%1,%2,0(1)\n"
                              "\tJNZ\t0b"
-                             : "+m" (*val), "=r" (ret)
+                             : "+m" (*val), "=&r" (ret)
                              : "r" (new_val)
                              : "1", "cc");
 
@@ -459,7 +509,7 @@ InterlockedExchangePointer(volatile gpointer *val, gpointer new_val)
                              "0:\tLG\t%1,%0\n"
                              "\tCSG\t%1,%2,0(1)\n"
                              "\tJNZ\t0b"
-                             : "+m" (*val), "=r" (ret)
+                             : "+m" (*val), "=&r" (ret)
                              : "r" (new_val)
                              : "1", "cc");
 
@@ -479,7 +529,7 @@ InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
                              "\tAR\t1,%2\n"
                              "\tCS\t%0,1,0(2)\n"
                              "\tJNZ\t0b"
-                             : "=r" (ret), "+m" (*val)
+                             : "=&r" (ret), "+m" (*val)
                              : "r" (add) 
                              : "1", "2", "cc");
        
@@ -497,7 +547,7 @@ InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
                              "\tAGR\t1,%2\n"
                              "\tCS\t%0,1,0(2)\n"
                              "\tJNZ\t0b"
-                             : "=r" (ret), "+m" (*val)
+                             : "=&r" (ret), "+m" (*val)
                              : "r" (add) 
                              : "1", "2", "cc");
        
@@ -505,9 +555,90 @@ InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
 }
 # endif
 
-#elif defined(__ppc__) || defined (__powerpc__)
+#elif defined(__mono_ppc__)
 #define WAPI_ATOMIC_ASM
 
+#ifdef G_COMPILER_CODEWARRIOR
+static inline gint32 InterlockedIncrement(volatile register gint32 *val)
+{
+       gint32 result = 0, tmp;
+       register gint32 result = 0;
+       register gint32 tmp;
+
+       asm
+       {
+               @1:
+                       lwarx   tmp, 0, val
+                       addi    result, tmp, 1
+                       stwcx.  result, 0, val
+                       bne-    @1
+       }
+       return result;
+}
+
+static inline gint32 InterlockedDecrement(register volatile gint32 *val)
+{
+       register gint32 result = 0;
+       register gint32 tmp;
+
+       asm
+       {
+               @1:
+                       lwarx   tmp, 0, val
+                       addi    result, tmp, -1
+                       stwcx.  result, 0, val
+                       bne-    @1
+       }
+
+       return result;
+}
+#define InterlockedCompareExchangePointer(dest,exch,comp) (void*)InterlockedCompareExchange((volatile gint32 *)(dest), (gint32)(exch), (gint32)(comp))
+
+static inline gint32 InterlockedCompareExchange(volatile register gint32 *dest, register gint32 exch, register gint32 comp)
+{
+       register gint32 tmp = 0;
+
+       asm
+       {
+               @1:
+                       lwarx   tmp, 0, dest
+                       cmpw    tmp, comp
+                       bne-    @2
+                       stwcx.  exch, 0, dest
+                       bne-    @1
+               @2:
+       }
+
+       return tmp;
+}
+static inline gint32 InterlockedExchange(register volatile gint32 *dest, register gint32 exch)
+{
+       register gint32 tmp = 0;
+
+       asm
+       {
+               @1:
+                       lwarx   tmp, 0, dest
+                       stwcx.  exch, 0, dest
+                       bne-    @1
+       }
+
+       return tmp;
+}
+#define InterlockedExchangePointer(dest,exch) (void*)InterlockedExchange((volatile gint32 *)(dest), (gint32)(exch))
+#else
+
+#if defined(__mono_ppc64__) && !defined(__mono_ilp32__)
+#define LDREGX "ldarx"
+#define STREGCXD "stdcx."
+#define CMPREG "cmpd"
+#else
+#define LDREGX "lwarx"
+#define STREGCXD "stwcx."
+#define CMPREG "cmpw"
+#endif
+
 static inline gint32 InterlockedIncrement(volatile gint32 *val)
 {
        gint32 result = 0, tmp;
@@ -534,7 +665,22 @@ static inline gint32 InterlockedDecrement(volatile gint32 *val)
        return result - 1;
 }
 
-#define InterlockedCompareExchangePointer(dest,exch,comp) InterlockedCompareExchange((volatile gint32 *)(dest), (gint32)(exch), (gint32)(comp))
+static inline gpointer InterlockedCompareExchangePointer (volatile gpointer *dest,
+                                               gpointer exch, gpointer comp)
+{
+       gpointer tmp = NULL;
+
+       __asm__ __volatile__ ("\n1:\n\t"
+                            LDREGX " %0, 0, %1\n\t"
+                            CMPREG " %0, %2\n\t" 
+                            "bne-    2f\n\t"
+                            STREGCXD " %3, 0, %1\n\t"
+                            "bne-    1b\n"
+                            "2:"
+                            : "=&r" (tmp)
+                            : "b" (dest), "r" (comp), "r" (exch): "cc", "memory");
+       return(tmp);
+}
 
 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
                                                gint32 exch, gint32 comp) {
@@ -563,7 +709,18 @@ static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
                              : "=r" (tmp) : "0" (tmp), "b" (dest), "r" (exch): "cc", "memory");
        return(tmp);
 }
-#define InterlockedExchangePointer(dest,exch) InterlockedExchange((volatile gint32 *)(dest), (gint32)(exch))
+
+static inline gpointer InterlockedExchangePointer (volatile gpointer *dest, gpointer exch)
+{
+       gpointer tmp = NULL;
+
+       __asm__ __volatile__ ("\n1:\n\t"
+                             LDREGX " %0, 0, %2\n\t"
+                             STREGCXD " %3, 0, %2\n\t"
+                             "bne    1b"
+                             : "=r" (tmp) : "0" (tmp), "b" (dest), "r" (exch): "cc", "memory");
+       return(tmp);
+}
 
 static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
 {
@@ -578,6 +735,12 @@ static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
         return(result);
 }
 
+#undef LDREGX
+#undef STREGCXD
+#undef CMPREG
+
+#endif /* !G_COMPILER_CODEWARRIOR */
+
 #elif defined(__arm__)
 #define WAPI_ATOMIC_ASM
 
@@ -588,6 +751,7 @@ static inline gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 ex
        __asm__ __volatile__ (    "0:\n\t"
                                  "ldr %1, [%2]\n\t"
                                  "cmp %1, %4\n\t"
+                                 "mov %0, %1\n\t"
                                  "bne 1f\n\t"
                                  "swp %0, %3, [%2]\n\t"
                                  "cmp %0, %1\n\t"
@@ -608,6 +772,7 @@ static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest
        __asm__ __volatile__ (    "0:\n\t"
                                  "ldr %1, [%2]\n\t"
                                  "cmp %1, %4\n\t"
+                                 "mov %0, %1\n\t"
                                  "bne 1f\n\t"
                                  "swpeq %0, %3, [%2]\n\t"
                                  "cmp %0, %1\n\t"
@@ -708,13 +873,16 @@ static inline gint32 InterlockedCompareExchange(gint32 volatile *dest,
                                                gint32 exch, gint32 comp)
 {
        gint32 old;
+       guint64 real_comp;
 
 #ifdef __INTEL_COMPILER
        old = _InterlockedCompareExchange (dest, exch, comp);
 #else
+       /* cmpxchg4 zero extends the value read from memory */
+       real_comp = (guint64)(guint32)comp;
        asm volatile ("mov ar.ccv = %2 ;;\n\t"
                                  "cmpxchg4.acq %0 = [%1], %3, ar.ccv\n\t"
-                                 : "=r" (old) : "r" (dest), "r" (comp), "r" (exch));
+                                 : "=r" (old) : "r" (dest), "r" (real_comp), "r" (exch));
 #endif
 
        return(old);
@@ -869,12 +1037,12 @@ static inline gint32 InterlockedDecrement(volatile gint32 *val)
        
        __asm__ __volatile__ (
                "1:     ldl_l %0, %1\n"
-               "       addl %0, %3, %0\n"
+               "       subl %0, %3, %0\n"
                "       mov %0, %2\n"
                "       stl_c %0, %1\n"
                "       beq %0, 1b\n"
                : "=&r" (temp), "=m" (*val), "=r" (cur)
-               : "Ir" (-1), "m" (*val));
+               : "Ir" (1), "m" (*val));
        return(cur);
 }
 
@@ -922,6 +1090,88 @@ static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
        return(ret);
 }
 
+#elif defined(__mips__)
+#define WAPI_ATOMIC_ASM
+
+static inline gint32 InterlockedIncrement(volatile gint32 *val)
+{
+       gint32 tmp, result = 0;
+
+       __asm__ __volatile__ ("    .set    mips32\n"
+                             "1:  ll      %0, %2\n"
+                             "    addu    %1, %0, 1\n"
+                              "    sc      %1, %2\n"
+                             "    beqz    %1, 1b\n"
+                             "    .set    mips0\n"
+                             : "=&r" (result), "=&r" (tmp), "=m" (*val)
+                             : "m" (*val));
+       return result + 1;
+}
+
+static inline gint32 InterlockedDecrement(volatile gint32 *val)
+{
+       gint32 tmp, result = 0;
+
+       __asm__ __volatile__ ("    .set    mips32\n"
+                             "1:  ll      %0, %2\n"
+                             "    subu    %1, %0, 1\n"
+                              "    sc      %1, %2\n"
+                             "    beqz    %1, 1b\n"
+                             "    .set    mips0\n"
+                             : "=&r" (result), "=&r" (tmp), "=m" (*val)
+                             : "m" (*val));
+       return result - 1;
+}
+
+#define InterlockedCompareExchangePointer(dest,exch,comp) InterlockedCompareExchange((volatile gint32 *)(dest), (gint32)(exch), (gint32)(comp))
+
+static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
+                                               gint32 exch, gint32 comp) {
+       gint32 old, tmp;
+
+       __asm__ __volatile__ ("    .set    mips32\n"
+                             "1:  ll      %0, %2\n"
+                             "    bne     %0, %5, 2f\n"
+                             "    move    %1, %4\n"
+                              "    sc      %1, %2\n"
+                             "    beqz    %1, 1b\n"
+                             "2:  .set    mips0\n"
+                             : "=&r" (old), "=&r" (tmp), "=m" (*dest)
+                             : "m" (*dest), "r" (exch), "r" (comp));
+       return(old);
+}
+
+static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
+{
+       gint32 result, tmp;
+
+       __asm__ __volatile__ ("    .set    mips32\n"
+                             "1:  ll      %0, %2\n"
+                             "    move    %1, %4\n"
+                              "    sc      %1, %2\n"
+                             "    beqz    %1, 1b\n"
+                             "    .set    mips0\n"
+                             : "=&r" (result), "=&r" (tmp), "=m" (*dest)
+                             : "m" (*dest), "r" (exch));
+       return(result);
+}
+#define InterlockedExchangePointer(dest,exch) InterlockedExchange((volatile gint32 *)(dest), (gint32)(exch))
+
+static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
+{
+        gint32 result, tmp;
+
+       __asm__ __volatile__ ("    .set    mips32\n"
+                             "1:  ll      %0, %2\n"
+                             "    addu    %1, %0, %4\n"
+                              "    sc      %1, %2\n"
+                             "    beqz    %1, 1b\n"
+                             "    .set    mips0\n"
+                             : "=&r" (result), "=&r" (tmp), "=m" (*dest)
+                             : "m" (*dest), "r" (add));
+        return result;
+}
+
 #else
 
 extern gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp);
@@ -932,7 +1182,7 @@ extern gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch);
 extern gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch);
 extern gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add);
 
-#if defined(__hpux) && !defined(__GNUC__)
+#if defined(__hppa__)
 #define WAPI_ATOMIC_ASM
 #endif