ATOMIC_CAS with 3 sregs.
authorMark Probst <mark.probst@gmail.com>
Tue, 24 Mar 2009 20:33:21 +0000 (20:33 -0000)
committerMark Probst <mark.probst@gmail.com>
Tue, 24 Mar 2009 20:33:21 +0000 (20:33 -0000)
2009-03-24  Mark Probst  <mark.probst@gmail.com>

        * mini-ops.h: New ternary ATOMIC_CAS ops replace the old
        ATOMIC_CAS_IMM ops.

        * method-to-ir.c: Handle more cases for
        Interlocked.CompareExchange.

        * cpu-x86.md, mini-x86.c, mini-x86.h, cpu-amd64.md,
        * mini-amd64.c,
        mini-amd64.h, cpu-ppc.md, cpu-ppc64.md, mini-ppc.c, mini-ppc.h:
        ATOMIC_CAS implementations for x86, AMD64, PPC and PPC64.

2009-03-24  Mark Probst  <mark.probst@gmail.com>

        * interlocked-3.cs: New CompareExchange test.

        * Makefile.am: Test added.

svn path=/trunk/mono/; revision=130153

15 files changed:
mono/mini/ChangeLog
mono/mini/cpu-amd64.md
mono/mini/cpu-ppc.md
mono/mini/cpu-ppc64.md
mono/mini/cpu-x86.md
mono/mini/method-to-ir.c
mono/mini/mini-amd64.c
mono/mini/mini-amd64.h
mono/mini/mini-ops.h
mono/mini/mini-ppc.c
mono/mini/mini-ppc.h
mono/mini/mini-x86.c
mono/mini/mini-x86.h
mono/tests/ChangeLog
mono/tests/Makefile.am

index 00373f82062b27f4f25e3add0084cad5ea1ca4a0..ee695628288c8926e396d166bca717bc0fd4bb82 100644 (file)
@@ -1,3 +1,15 @@
+2009-03-24  Mark Probst  <mark.probst@gmail.com>
+
+       * mini-ops.h: New ternary ATOMIC_CAS ops replace the old
+       ATOMIC_CAS_IMM ops.
+
+       * method-to-ir.c: Handle more cases for
+       Interlocked.CompareExchange.
+
+       * cpu-x86.md, mini-x86.c, mini-x86.h, cpu-amd64.md, mini-amd64.c,
+       mini-amd64.h, cpu-ppc.md, cpu-ppc64.md, mini-ppc.c, mini-ppc.h:
+       ATOMIC_CAS implementations for x86, AMD64, PPC and PPC64.
+
 2009-03-23  Zoltan Varga  <vargaz@gmail.com>
 
        * aot-runtime.c (decode_method_ref): Fix a warning.
index db0be21bb2aa016d0fae8f80a42af28b2c8db406..5a53bfd3188a67540e2d6f99c36607f407e33e93 100644 (file)
@@ -298,8 +298,8 @@ atomic_exchange_i4: src1:b src2:i dest:a len:32
 atomic_add_i8: src1:b src2:i dest:i len:32
 atomic_add_new_i8: src1:b src2:i dest:i len:32
 atomic_exchange_i8: src1:b src2:i dest:a len:32
-atomic_cas_imm_i4: src1:b src2:i dest:a len:32
-atomic_cas_imm_i8: src1:b src2:i dest:a len:32
+atomic_cas_i4: src1:b src2:i src3:a dest:i len:24
+atomic_cas_i8: src1:b src2:i src3:a dest:i len:24
 memory_barrier: len:16
 adc: dest:i src1:i src2:i len:3 clob:1
 addcc: dest:i src1:i src2:i len:3 clob:1
index e5d75c23f4742048d321bdba482c89d5c18b07ca..7c7571e314086e2f1757499fb6014b129a5349df 100644 (file)
@@ -309,3 +309,4 @@ vcall2_membase: src1:b len:12 clob:c
 
 jump_table: dest:i len:8
 
+atomic_cas_i4: src1:b src2:i src3:i dest:i len:30
index 5b76b6db9c033a79c5e466ac28f25332ae411eee..3f0210f251a0419ce87e63318df0f3220e411b8b 100644 (file)
@@ -377,3 +377,6 @@ jump_table: dest:i len:20
 
 atomic_add_new_i4: src1:b src2:i dest:i len:20
 atomic_add_new_i8: src1:b src2:i dest:i len:20
+
+atomic_cas_i4: src1:b src2:i src3:i dest:i len:30
+atomic_cas_i8: src1:b src2:i src3:i dest:i len:30
index 235a1f25cefff0dd28cffab3aa259a2da5db31e7..fef209753a65d27c972e4ef11ce036d214306cd1 100644 (file)
@@ -304,7 +304,7 @@ tls_get: dest:i len:20
 atomic_add_i4: src1:b src2:i dest:i len:16
 atomic_add_new_i4: src1:b src2:i dest:i len:16
 atomic_exchange_i4: src1:b src2:i dest:a len:24
-atomic_cas_imm_i4: src1:b src2:i dest:a len:24
+atomic_cas_i4: src1:b src2:i src3:a dest:i len:24
 memory_barrier: len:16
 
 relaxed_nop: len:2
index f23341194ef69584c99c677938cb44b22c8e4d2c..0913ad6cb0408f699a339bcc866016ff890b0e00 100644 (file)
@@ -3891,27 +3891,36 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                }
 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
  
-#ifdef MONO_ARCH_HAVE_ATOMIC_CAS_IMM
-               /* 
-                * Can't implement CompareExchange methods this way since they have
-                * three arguments. We can implement one of the common cases, where the new
-                * value is a constant.
-                */
+#ifdef MONO_ARCH_HAVE_ATOMIC_CAS
                if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
-                       if ((fsig->params [1]->type == MONO_TYPE_I4 ||
-                                               (sizeof (gpointer) == 4 && fsig->params [1]->type == MONO_TYPE_I))
-                                       && args [2]->opcode == OP_ICONST) {
-                               MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_IMM_I4);
+                       int size = 0;
+                       if (fsig->params [1]->type == MONO_TYPE_I4)
+                               size = 4;
+                       else if (fsig->params [1]->type == MONO_TYPE_I || MONO_TYPE_IS_REFERENCE (fsig->params [1]))
+                               size = sizeof (gpointer);
+                       else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I4)
+                               size = 8;
+                       if (size == 4) {
+                               MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
                                ins->dreg = alloc_ireg (cfg);
                                ins->sreg1 = args [0]->dreg;
                                ins->sreg2 = args [1]->dreg;
-                               ins->backend.data = GINT_TO_POINTER (args [2]->inst_c0);
+                               ins->sreg3 = args [2]->dreg;
                                ins->type = STACK_I4;
                                MONO_ADD_INS (cfg->cbb, ins);
+                       } else if (size == 8) {
+                               MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8);
+                               ins->dreg = alloc_ireg (cfg);
+                               ins->sreg1 = args [0]->dreg;
+                               ins->sreg2 = args [1]->dreg;
+                               ins->sreg3 = args [2]->dreg;
+                               ins->type = STACK_I8;
+                               MONO_ADD_INS (cfg->cbb, ins);
+                       } else {
+                               /* g_assert_not_reached (); */
                        }
-                       /* The I8 case is hard to detect, since the arg might be a conv.i8 (iconst) tree */
                }
-#endif /* MONO_ARCH_HAVE_ATOMIC_CAS_IMM */
+#endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
 
                if (ins)
                        return ins;
index fdab64cb7e7f8084e711078b935c8fd772832684..875a6505ced9bcc835623993296675bdc7aec578 100644 (file)
@@ -4181,8 +4181,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                }
                case OP_ATOMIC_EXCHANGE_I4:
-               case OP_ATOMIC_EXCHANGE_I8:
-               case OP_ATOMIC_CAS_IMM_I4: {
+               case OP_ATOMIC_EXCHANGE_I8: {
                        guchar *br[2];
                        int sreg2 = ins->sreg2;
                        int breg = ins->inst_basereg;
@@ -4229,28 +4228,42 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                }
                        }
 
-                       if (ins->opcode == OP_ATOMIC_CAS_IMM_I4) {
-                               if (ins->backend.data == NULL)
-                                       amd64_alu_reg_reg (code, X86_XOR, AMD64_RAX, AMD64_RAX);
-                               else
-                                       amd64_mov_reg_imm (code, AMD64_RAX, ins->backend.data);
+                       amd64_mov_reg_membase (code, AMD64_RAX, breg, ins->inst_offset, size);
 
-                               amd64_prefix (code, X86_LOCK_PREFIX);
-                               amd64_cmpxchg_membase_reg_size (code, breg, ins->inst_offset, sreg2, size);
-                       } else {
-                               amd64_mov_reg_membase (code, AMD64_RAX, breg, ins->inst_offset, size);
-
-                               br [0] = code; amd64_prefix (code, X86_LOCK_PREFIX);
-                               amd64_cmpxchg_membase_reg_size (code, breg, ins->inst_offset, sreg2, size);
-                               br [1] = code; amd64_branch8 (code, X86_CC_NE, -1, FALSE);
-                               amd64_patch (br [1], br [0]);
-                       }
+                       br [0] = code; amd64_prefix (code, X86_LOCK_PREFIX);
+                       amd64_cmpxchg_membase_reg_size (code, breg, ins->inst_offset, sreg2, size);
+                       br [1] = code; amd64_branch8 (code, X86_CC_NE, -1, FALSE);
+                       amd64_patch (br [1], br [0]);
 
                        if (rdx_pushed)
                                amd64_pop_reg (code, AMD64_RDX);
 
                        break;
                }
+               case OP_ATOMIC_CAS_I4:
+               case OP_ATOMIC_CAS_I8: {
+                       guint32 size;
+
+                       if (ins->opcode == OP_ATOMIC_CAS_I8)
+                               size = 8;
+                       else
+                               size = 4;
+
+                       /* 
+                        * See http://msdn.microsoft.com/en-us/magazine/cc302329.aspx for
+                        * an explanation of how this works.
+                        */
+                       g_assert (ins->sreg3 == AMD64_RAX);
+                       g_assert (ins->sreg1 != AMD64_RAX);
+                       g_assert (ins->sreg1 != ins->sreg2);
+
+                       amd64_prefix (code, X86_LOCK_PREFIX);
+                       amd64_cmpxchg_membase_reg_size (code, ins->sreg1, ins->inst_offset, ins->sreg2, size);
+
+                       if (ins->dreg != AMD64_RAX)
+                               amd64_mov_reg_reg (code, ins->dreg, AMD64_RAX, size);
+                       break;
+               }
                case OP_LIVERANGE_START: {
                        if (cfg->verbose_level > 1)
                                printf ("R%d START=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
index b408f776b28a777919115959f5e6df7068b70c31..e5d089cf5df569497e93000d2640eee589749959 100644 (file)
@@ -301,7 +301,7 @@ typedef struct {
 #define MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE 1
 #define MONO_ARCH_HAVE_ATOMIC_ADD 1
 #define MONO_ARCH_HAVE_ATOMIC_EXCHANGE 1
-#define MONO_ARCH_HAVE_ATOMIC_CAS_IMM 1
+#define MONO_ARCH_HAVE_ATOMIC_CAS 1
 #define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES 1
 #define MONO_ARCH_HAVE_IMT 1
 #define MONO_ARCH_HAVE_TLS_GET 1
index fd86530c3a863f31aa5c6cccf8f7e4afdf6780ed..d4c1a14adafc7c9c3017dcb1fde7c0a085cff19c 100644 (file)
@@ -799,10 +799,8 @@ MINI_OP(OP_ATOMIC_ADD_IMM_NEW_I8, "atomic_add_imm_new_i8", IREG, IREG, NONE)
 MINI_OP(OP_ATOMIC_EXCHANGE_I8, "atomic_exchange_i8", IREG, IREG, IREG)
 MINI_OP(OP_MEMORY_BARRIER, "memory_barrier", NONE, NONE, NONE)
 
-/* CompareExchange where the value to store is a constant */
-/* backend->data holds the constant value */
-MINI_OP(OP_ATOMIC_CAS_IMM_I4, "atomic_cas_imm_i4", IREG, IREG, IREG)
-MINI_OP(OP_ATOMIC_CAS_IMM_I8, "atomic_cas_imm_i8", IREG, IREG, IREG)
+MINI_OP3(OP_ATOMIC_CAS_I4, "atomic_cas_i4", IREG, IREG, IREG, IREG)
+MINI_OP3(OP_ATOMIC_CAS_I8, "atomic_cas_i8", IREG, IREG, IREG, IREG)
 
 /* Conditional move opcodes.
  * Must be in the same order as the matching CEE_B... opcodes
index cac13cc5e0bf9b0a352f6ee00ec309f767c878b9..f1149abd8b7e0a2ae1070b27bce3ac1002814f17 100644 (file)
@@ -4218,6 +4218,39 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                }
 #endif
+               case OP_ATOMIC_CAS_I4:
+               CASE_PPC64 (OP_ATOMIC_CAS_I8) {
+                       int location = ins->sreg1;
+                       int value = ins->sreg2;
+                       int comparand = ins->sreg3;
+                       guint8 *start, *not_equal, *lost_reservation;
+
+                       start = code;
+                       if (ins->opcode == OP_ATOMIC_CAS_I4)
+                               ppc_lwarx (code, ppc_r0, 0, location);
+#ifdef __mono_ppc64__
+                       else
+                               ppc_ldarx (code, ppc_r0, 0, location);
+#endif
+                       ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
+
+                       not_equal = code;
+                       ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
+                       if (ins->opcode == OP_ATOMIC_CAS_I4)
+                               ppc_stwcxd (code, value, 0, location);
+#ifdef __mono_ppc64__
+                       else
+                               ppc_stdcxd (code, value, 0, location);
+#endif
+
+                       lost_reservation = code;
+                       ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
+                       ppc_patch (lost_reservation, start);
+
+                       ppc_patch (not_equal, code);
+                       ppc_mr (code, ins->dreg, ppc_r0);
+                       break;
+               }
 
                default:
                        g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
index 23c4d24a1c11e4d0be45197ad4770bd1ce4c0a44..628625fc0e07fb485e4946f4c5ae3391452f1828 100644 (file)
@@ -77,6 +77,7 @@ typedef struct MonoCompileArch {
 #define MONO_ARCH_EMULATE_LCONV_TO_R8_UN 1
 #define MONO_ARCH_EMULATE_FREM 1
 #define MONO_ARCH_BIGMUL_INTRINS 1
+#define MONO_ARCH_HAVE_ATOMIC_CAS 1
 //#define MONO_ARCH_ENABLE_EMIT_STATE_OPT 1
 
 /* Parameters used by the register allocator */
index 61e514738a7ca6247105cc2c27b7c9e7a276b85d..b9ea6fda0319126bb2aa9a1890f6d054a3924092 100644 (file)
@@ -3640,8 +3640,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        break;
                }
-               case OP_ATOMIC_EXCHANGE_I4:
-               case OP_ATOMIC_CAS_IMM_I4: {
+               case OP_ATOMIC_EXCHANGE_I4: {
                        guchar *br[2];
                        int sreg2 = ins->sreg2;
                        int breg = ins->inst_basereg;
@@ -3665,19 +3664,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                x86_mov_reg_reg (code, breg, X86_EAX, 4);
                        }
 
-                       if (ins->opcode == OP_ATOMIC_CAS_IMM_I4) {
-                               x86_mov_reg_imm (code, X86_EAX, ins->backend.data);
+                       x86_mov_reg_membase (code, X86_EAX, breg, ins->inst_offset, 4);
 
-                               x86_prefix (code, X86_LOCK_PREFIX);
-                               x86_cmpxchg_membase_reg (code, breg, ins->inst_offset, sreg2);
-                       } else {
-                               x86_mov_reg_membase (code, X86_EAX, breg, ins->inst_offset, 4);
-
-                               br [0] = code; x86_prefix (code, X86_LOCK_PREFIX);
-                               x86_cmpxchg_membase_reg (code, breg, ins->inst_offset, sreg2);
-                               br [1] = code; x86_branch8 (code, X86_CC_NE, -1, FALSE);
-                               x86_patch (br [1], br [0]);
-                       }
+                       br [0] = code; x86_prefix (code, X86_LOCK_PREFIX);
+                       x86_cmpxchg_membase_reg (code, breg, ins->inst_offset, sreg2);
+                       br [1] = code; x86_branch8 (code, X86_CC_NE, -1, FALSE);
+                       x86_patch (br [1], br [0]);
 
                        if (breg != ins->inst_basereg)
                                x86_pop_reg (code, breg);
@@ -3687,6 +3679,18 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        break;
                }
+               case OP_ATOMIC_CAS_I4: {
+                       g_assert (ins->sreg3 == X86_EAX);
+                       g_assert (ins->sreg1 != X86_EAX);
+                       g_assert (ins->sreg1 != ins->sreg2);
+
+                       x86_prefix (code, X86_LOCK_PREFIX);
+                       x86_cmpxchg_membase_reg (code, ins->sreg1, ins->inst_offset, ins->sreg2);
+
+                       if (ins->dreg != X86_EAX)
+                               x86_mov_reg_reg (code, ins->dreg, X86_EAX, 4);
+                       break;
+               }
 #ifdef MONO_ARCH_SIMD_INTRINSICS
                case OP_ADDPS:
                        x86_sse_alu_ps_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2);
index 26716415bc8a750105115fe7bb790e1da4fcead0..a546a3272a9b60a5952c282d1644e2e8d13a43e5 100644 (file)
@@ -278,7 +278,7 @@ typedef struct {
 #define MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE 1
 #define MONO_ARCH_HAVE_ATOMIC_ADD 1
 #define MONO_ARCH_HAVE_ATOMIC_EXCHANGE 1
-#define MONO_ARCH_HAVE_ATOMIC_CAS_IMM 1
+#define MONO_ARCH_HAVE_ATOMIC_CAS 1
 #define MONO_ARCH_HAVE_IMT 1
 #define MONO_ARCH_HAVE_TLS_GET 1
 #define MONO_ARCH_IMT_REG X86_EDX
index d7be41429debf11187edfcd08ed20a1c892f9ff4..7a723bb76fe59335f81061c1527550ff54368036 100644 (file)
@@ -1,3 +1,9 @@
+2009-03-24  Mark Probst  <mark.probst@gmail.com>
+
+       * interlocked-3.cs: New CompareExchange test.
+
+       * Makefile.am: Test added.
+
 2009-03-24  Zoltan Varga  <vargaz@gmail.com>
 
        * thread6.cs: Add back a sleep to avoid a race.
index 022ebd0e20155a823d74fdb130d1a8edd737df62..b4217ccb0c41053f6c0ffb6a52407dacd11b09ea 100644 (file)
@@ -347,7 +347,8 @@ BASE_TEST_CS_SRC=           \
        bug-467456.cs   \
        appdomain-unload-callback.cs    \
        bug-472692.2.cs         \
-       gchandles.cs
+       gchandles.cs    \
+       interlocked-3.cs
 
 if AMD64
 TEST_CS_SRC = $(BASE_TEST_CS_SRC) async-exc-compilation.cs