|
From: <sv...@va...> - 2009-05-21 21:40:29
|
Author: sewardj
Date: 2009-05-21 22:40:21 +0100 (Thu, 21 May 2009)
New Revision: 1893
Log:
Handle IRStmt_IRCAS in the amd64 back end.
Modified:
branches/DCAS/priv/host-amd64/hdefs.c
branches/DCAS/priv/host-amd64/hdefs.h
branches/DCAS/priv/host-amd64/isel.c
Modified: branches/DCAS/priv/host-amd64/hdefs.c
===================================================================
--- branches/DCAS/priv/host-amd64/hdefs.c 2009-05-21 21:37:23 UTC (rev 1892)
+++ branches/DCAS/priv/host-amd64/hdefs.c 2009-05-21 21:40:21 UTC (rev 1893)
@@ -790,12 +790,28 @@
i->Ain.Bsfr64.dst = dst;
return i;
}
-AMD64Instr* AMD64Instr_MFence ( void )
-{
+AMD64Instr* AMD64Instr_MFence ( void ) {
AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr));
i->tag = Ain_MFence;
return i;
}
+AMD64Instr* AMD64Instr_ACAS ( AMD64AMode* addr, UChar sz ) {
+ AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr));
+ i->tag = Ain_ACAS;
+ i->Ain.ACAS.addr = addr;
+ i->Ain.ACAS.sz = sz;
+ vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
+ return i;
+}
+AMD64Instr* AMD64Instr_DACAS ( AMD64AMode* addr, UChar sz ) {
+ AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr));
+ i->tag = Ain_DACAS;
+ i->Ain.DACAS.addr = addr;
+ i->Ain.DACAS.sz = sz;
+ vassert(sz == 8 || sz == 4);
+ return i;
+}
+
AMD64Instr* AMD64Instr_A87Free ( Int nregs )
{
AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr));
@@ -1174,6 +1190,18 @@
case Ain_MFence:
vex_printf("mfence" );
return;
+ case Ain_ACAS:
+ vex_printf("lock cmpxchg%c ",
+ i->Ain.ACAS.sz==1 ? 'b' : i->Ain.ACAS.sz==2 ? 'w'
+ : i->Ain.ACAS.sz==4 ? 'l' : 'q' );
+ vex_printf("{%%rax->%%rbx},");
+ ppAMD64AMode(i->Ain.ACAS.addr);
+ return;
+ case Ain_DACAS:
+ vex_printf("lock cmpxchg%db {%%rdx:%%rax->%%rcx:%%rbx},",
+ (Int)(2 * i->Ain.DACAS.sz));
+ ppAMD64AMode(i->Ain.DACAS.addr);
+ return;
case Ain_A87Free:
vex_printf("ffree %%st(7..%d)", 8 - i->Ain.A87Free.nregs );
break;
@@ -1511,6 +1539,18 @@
return;
case Ain_MFence:
return;
+ case Ain_ACAS:
+ addRegUsage_AMD64AMode(u, i->Ain.ACAS.addr);
+ addHRegUse(u, HRmRead, hregAMD64_RBX());
+ addHRegUse(u, HRmModify, hregAMD64_RAX());
+ return;
+ case Ain_DACAS:
+ addRegUsage_AMD64AMode(u, i->Ain.DACAS.addr);
+ addHRegUse(u, HRmRead, hregAMD64_RCX());
+ addHRegUse(u, HRmRead, hregAMD64_RBX());
+ addHRegUse(u, HRmModify, hregAMD64_RDX());
+ addHRegUse(u, HRmModify, hregAMD64_RAX());
+ return;
case Ain_A87Free:
return;
case Ain_A87PushPop:
@@ -1729,6 +1769,12 @@
return;
case Ain_MFence:
return;
+ case Ain_ACAS:
+ mapRegs_AMD64AMode(m, i->Ain.ACAS.addr);
+ return;
+ case Ain_DACAS:
+ mapRegs_AMD64AMode(m, i->Ain.DACAS.addr);
+ return;
case Ain_A87Free:
return;
case Ain_A87PushPop:
@@ -2848,6 +2894,40 @@
*p++ = 0x0F; *p++ = 0xAE; *p++ = 0xF0;
goto done;
+ case Ain_ACAS:
+ /* lock */
+ *p++ = 0xF0;
+ if (i->Ain.ACAS.sz == 2) *p++ = 0x66;
+ /* cmpxchg{b,w,l,q} %rbx,mem. Expected-value in %rax, new value
+ in %rbx. The new-value register is hardwired to be %rbx
+ since dealing with byte integer registers is too much hassle,
+ so we force the register operand to %rbx (could equally be
+ %rcx or %rdx). */
+ rex = rexAMode_M( hregAMD64_RBX(), i->Ain.ACAS.addr );
+ if (i->Ain.ACAS.sz != 8)
+ rex = clearWBit(rex);
+
+ *p++ = rex; /* this can emit 0x40, which is pointless. oh well. */
+ *p++ = 0x0F;
+ if (i->Ain.ACAS.sz == 1) *p++ = 0xB0; else *p++ = 0xB1;
+ p = doAMode_M(p, hregAMD64_RBX(), i->Ain.ACAS.addr);
+ goto done;
+
+ case Ain_DACAS:
+ /* lock */
+ *p++ = 0xF0;
+ /* cmpxchg{8,16}b m{64,128}. Expected-value in %rdx:%rax, new
+ value in %rcx:%rbx. All 4 regs are hardwired in the ISA, so
+ aren't encoded in the insn. */
+ rex = rexAMode_M( fake(1), i->Ain.ACAS.addr );
+ if (i->Ain.ACAS.sz != 8)
+ rex = clearWBit(rex);
+ *p++ = rex;
+ *p++ = 0x0F;
+ *p++ = 0xC7;
+ p = doAMode_M(p, fake(1), i->Ain.DACAS.addr);
+ goto done;
+
case Ain_A87Free:
vassert(i->Ain.A87Free.nregs > 0 && i->Ain.A87Free.nregs <= 7);
for (j = 0; j < i->Ain.A87Free.nregs; j++) {
Modified: branches/DCAS/priv/host-amd64/hdefs.h
===================================================================
--- branches/DCAS/priv/host-amd64/hdefs.h 2009-05-21 21:37:23 UTC (rev 1892)
+++ branches/DCAS/priv/host-amd64/hdefs.h 2009-05-21 21:40:21 UTC (rev 1893)
@@ -383,6 +383,10 @@
Ain_Set64, /* convert condition code to 64-bit value */
Ain_Bsfr64, /* 64-bit bsf/bsr */
Ain_MFence, /* mem fence */
+ Ain_ACAS, /* 8/16/32/64-bit lock;cmpxchg */
+ Ain_DACAS, /* lock;cmpxchg8b/16b (doubleword ACAS, 2 x
+ 32-bit or 2 x 64-bit only) */
+
Ain_A87Free, /* free up x87 registers */
Ain_A87PushPop, /* x87 loads/stores */
Ain_A87FpOp, /* x87 operations */
@@ -534,6 +538,14 @@
On AMD64 we emit a real "mfence". */
struct {
} MFence;
+ struct {
+ AMD64AMode* addr;
+ UChar sz; /* 1, 2, 4 or 8 */
+ } ACAS;
+ struct {
+ AMD64AMode* addr;
+ UChar sz; /* 4 or 8 only */
+ } DACAS;
/* --- X87 --- */
@@ -689,6 +701,9 @@
extern AMD64Instr* AMD64Instr_Set64 ( AMD64CondCode cond, HReg dst );
extern AMD64Instr* AMD64Instr_Bsfr64 ( Bool isFwds, HReg src, HReg dst );
extern AMD64Instr* AMD64Instr_MFence ( void );
+extern AMD64Instr* AMD64Instr_ACAS ( AMD64AMode* addr, UChar sz );
+extern AMD64Instr* AMD64Instr_DACAS ( AMD64AMode* addr, UChar sz );
+
extern AMD64Instr* AMD64Instr_A87Free ( Int nregs );
extern AMD64Instr* AMD64Instr_A87PushPop ( AMD64AMode* addr, Bool isPush );
extern AMD64Instr* AMD64Instr_A87FpOp ( A87FpOp op );
Modified: branches/DCAS/priv/host-amd64/isel.c
===================================================================
--- branches/DCAS/priv/host-amd64/isel.c 2009-05-21 21:37:23 UTC (rev 1892)
+++ branches/DCAS/priv/host-amd64/isel.c 2009-05-21 21:40:21 UTC (rev 1893)
@@ -145,7 +145,6 @@
Int vreg_ctr;
- /* Currently (27 Jan 06) unused */
UInt hwcaps;
}
ISelEnv;
@@ -3822,6 +3821,81 @@
}
break;
+ /* --------- ACAS --------- */
+ case Ist_CAS:
+ if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
+ /* "normal" singleton CAS */
+ UChar sz;
+ IRCAS* cas = stmt->Ist.CAS.details;
+ IRType ty = typeOfIRExpr(env->type_env, cas->dataLo);
+ /* get: cas->expd into %rax, and cas->data into %rbx */
+ AMD64AMode* am = iselIntExpr_AMode(env, cas->addr);
+ HReg rData = iselIntExpr_R(env, cas->dataLo);
+ HReg rExpd = iselIntExpr_R(env, cas->expdLo);
+ HReg rOld = lookupIRTemp(env, cas->oldLo);
+ vassert(cas->expdHi == NULL);
+ vassert(cas->dataHi == NULL);
+ addInstr(env, mk_iMOVsd_RR(rExpd, rOld));
+ addInstr(env, mk_iMOVsd_RR(rExpd, hregAMD64_RAX()));
+ addInstr(env, mk_iMOVsd_RR(rData, hregAMD64_RBX()));
+ switch (ty) {
+ case Ity_I64: sz = 8; break;
+ case Ity_I32: sz = 4; break;
+ case Ity_I16: sz = 2; break;
+ case Ity_I8: sz = 1; break;
+ default: goto unhandled_cas;
+ }
+ addInstr(env, AMD64Instr_ACAS(am, sz));
+ addInstr(env, AMD64Instr_CMov64(
+ Acc_NZ, AMD64RM_Reg(hregAMD64_RAX()), rOld));
+ return;
+ } else {
+ /* double CAS */
+ UChar sz;
+ IRCAS* cas = stmt->Ist.CAS.details;
+ IRType ty = typeOfIRExpr(env->type_env, cas->dataLo);
+ /* only 32-bit and 64-bit allowed in this case */
+ /* get: cas->expdLo into %rax, and cas->dataLo into %rbx */
+ /* get: cas->expdHi into %rdx, and cas->dataHi into %rcx */
+ AMD64AMode* am = iselIntExpr_AMode(env, cas->addr);
+ HReg rDataHi = iselIntExpr_R(env, cas->dataHi);
+ HReg rDataLo = iselIntExpr_R(env, cas->dataLo);
+ HReg rExpdHi = iselIntExpr_R(env, cas->expdHi);
+ HReg rExpdLo = iselIntExpr_R(env, cas->expdLo);
+ HReg rOldHi = lookupIRTemp(env, cas->oldHi);
+ HReg rOldLo = lookupIRTemp(env, cas->oldLo);
+ switch (ty) {
+ case Ity_I64:
+ if (!(env->hwcaps & VEX_HWCAPS_AMD64_CX16))
+ goto unhandled_cas; /* we'd have to generate
+ cmpxchg16b, but the host
+ doesn't support that */
+ sz = 8;
+ break;
+ case Ity_I32:
+ sz = 4;
+ break;
+ default:
+ goto unhandled_cas;
+ }
+ addInstr(env, mk_iMOVsd_RR(rExpdHi, rOldHi));
+ addInstr(env, mk_iMOVsd_RR(rExpdLo, rOldLo));
+ addInstr(env, mk_iMOVsd_RR(rExpdHi, hregAMD64_RDX()));
+ addInstr(env, mk_iMOVsd_RR(rExpdLo, hregAMD64_RAX()));
+ addInstr(env, mk_iMOVsd_RR(rDataHi, hregAMD64_RCX()));
+ addInstr(env, mk_iMOVsd_RR(rDataLo, hregAMD64_RBX()));
+ addInstr(env, AMD64Instr_DACAS(am, sz));
+ addInstr(env,
+ AMD64Instr_CMov64(
+ Acc_NZ, AMD64RM_Reg(hregAMD64_RDX()), rOldHi));
+ addInstr(env,
+ AMD64Instr_CMov64(
+ Acc_NZ, AMD64RM_Reg(hregAMD64_RAX()), rOldLo));
+ return;
+ }
+ unhandled_cas:
+ break;
+
/* --------- INSTR MARK --------- */
/* Doesn't generate any executable code ... */
case Ist_IMark:
@@ -3893,7 +3967,8 @@
/* sanity ... */
vassert(arch_host == VexArchAMD64);
- vassert(0 == (hwcaps_host & ~(VEX_HWCAPS_AMD64_SSE3)));
+ vassert(0 == (hwcaps_host & ~(VEX_HWCAPS_AMD64_SSE3
+ |VEX_HWCAPS_AMD64_CX16)));
/* Make up an initial environment to use. */
env = LibVEX_Alloc(sizeof(ISelEnv));
|