From: Mark Probst Date: Tue, 24 Mar 2009 20:33:21 +0000 (-0000) Subject: ATOMIC_CAS with 3 sregs. X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=d4e5947ea88f7b78bcba036f4e785dea5e43266f;p=mono.git ATOMIC_CAS with 3 sregs. 2009-03-24 Mark Probst * 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 * interlocked-3.cs: New CompareExchange test. * Makefile.am: Test added. svn path=/trunk/mono/; revision=130153 --- diff --git a/mono/mini/ChangeLog b/mono/mini/ChangeLog index 00373f82062..ee695628288 100644 --- a/mono/mini/ChangeLog +++ b/mono/mini/ChangeLog @@ -1,3 +1,15 @@ +2009-03-24 Mark Probst + + * 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 * aot-runtime.c (decode_method_ref): Fix a warning. diff --git a/mono/mini/cpu-amd64.md b/mono/mini/cpu-amd64.md index db0be21bb2a..5a53bfd3188 100644 --- a/mono/mini/cpu-amd64.md +++ b/mono/mini/cpu-amd64.md @@ -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 diff --git a/mono/mini/cpu-ppc.md b/mono/mini/cpu-ppc.md index e5d75c23f47..7c7571e3140 100644 --- a/mono/mini/cpu-ppc.md +++ b/mono/mini/cpu-ppc.md @@ -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 diff --git a/mono/mini/cpu-ppc64.md b/mono/mini/cpu-ppc64.md index 5b76b6db9c0..3f0210f251a 100644 --- a/mono/mini/cpu-ppc64.md +++ b/mono/mini/cpu-ppc64.md @@ -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 diff --git a/mono/mini/cpu-x86.md b/mono/mini/cpu-x86.md index 235a1f25cef..fef209753a6 100644 --- a/mono/mini/cpu-x86.md +++ b/mono/mini/cpu-x86.md @@ -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 diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index f23341194ef..0913ad6cb04 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -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; diff --git a/mono/mini/mini-amd64.c b/mono/mini/mini-amd64.c index fdab64cb7e7..875a6505ced 100644 --- a/mono/mini/mini-amd64.c +++ b/mono/mini/mini-amd64.c @@ -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)); diff --git a/mono/mini/mini-amd64.h b/mono/mini/mini-amd64.h index b408f776b28..e5d089cf5df 100644 --- a/mono/mini/mini-amd64.h +++ b/mono/mini/mini-amd64.h @@ -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 diff --git a/mono/mini/mini-ops.h b/mono/mini/mini-ops.h index fd86530c3a8..d4c1a14adaf 100644 --- a/mono/mini/mini-ops.h +++ b/mono/mini/mini-ops.h @@ -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 diff --git a/mono/mini/mini-ppc.c b/mono/mini/mini-ppc.c index cac13cc5e0b..f1149abd8b7 100644 --- a/mono/mini/mini-ppc.c +++ b/mono/mini/mini-ppc.c @@ -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__); diff --git a/mono/mini/mini-ppc.h b/mono/mini/mini-ppc.h index 23c4d24a1c1..628625fc0e0 100644 --- a/mono/mini/mini-ppc.h +++ b/mono/mini/mini-ppc.h @@ -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 */ diff --git a/mono/mini/mini-x86.c b/mono/mini/mini-x86.c index 61e514738a7..b9ea6fda031 100644 --- a/mono/mini/mini-x86.c +++ b/mono/mini/mini-x86.c @@ -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); diff --git a/mono/mini/mini-x86.h b/mono/mini/mini-x86.h index 26716415bc8..a546a3272a9 100644 --- a/mono/mini/mini-x86.h +++ b/mono/mini/mini-x86.h @@ -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 diff --git a/mono/tests/ChangeLog b/mono/tests/ChangeLog index d7be41429de..7a723bb76fe 100644 --- a/mono/tests/ChangeLog +++ b/mono/tests/ChangeLog @@ -1,3 +1,9 @@ +2009-03-24 Mark Probst + + * interlocked-3.cs: New CompareExchange test. + + * Makefile.am: Test added. + 2009-03-24 Zoltan Varga * thread6.cs: Add back a sleep to avoid a race. diff --git a/mono/tests/Makefile.am b/mono/tests/Makefile.am index 022ebd0e201..b4217ccb0c4 100644 --- a/mono/tests/Makefile.am +++ b/mono/tests/Makefile.am @@ -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