+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.
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
jump_table: dest:i len:8
+atomic_cas_i4: src1:b src2:i src3:i dest:i len:30
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
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
}
#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;
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;
}
}
- 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));
#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
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
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__);
#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 */
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;
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);
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);
#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
+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.
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