|
From: <sv...@va...> - 2009-05-21 21:37:35
|
Author: sewardj
Date: 2009-05-21 22:37:23 +0100 (Thu, 21 May 2009)
New Revision: 1892
Log:
Handle IRStmt_IRCAS in the x86 back end.
Modified:
branches/DCAS/priv/host-x86/hdefs.c
branches/DCAS/priv/host-x86/hdefs.h
branches/DCAS/priv/host-x86/isel.c
Modified: branches/DCAS/priv/host-x86/hdefs.c
===================================================================
--- branches/DCAS/priv/host-x86/hdefs.c 2009-05-21 21:31:49 UTC (rev 1891)
+++ branches/DCAS/priv/host-x86/hdefs.c 2009-05-21 21:37:23 UTC (rev 1892)
@@ -710,8 +710,7 @@
i->Xin.Bsfr32.dst = dst;
return i;
}
-X86Instr* X86Instr_MFence ( UInt hwcaps )
-{
+X86Instr* X86Instr_MFence ( UInt hwcaps ) {
X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
i->tag = Xin_MFence;
i->Xin.MFence.hwcaps = hwcaps;
@@ -719,6 +718,20 @@
|VEX_HWCAPS_X86_SSE3)));
return i;
}
+X86Instr* X86Instr_ACAS ( X86AMode* addr, UChar sz ) {
+ X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
+ i->tag = Xin_ACAS;
+ i->Xin.ACAS.addr = addr;
+ i->Xin.ACAS.sz = sz;
+ vassert(sz == 4 || sz == 2 || sz == 1);
+ return i;
+}
+X86Instr* X86Instr_DACAS ( X86AMode* addr ) {
+ X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
+ i->tag = Xin_DACAS;
+ i->Xin.DACAS.addr = addr;
+ return i;
+}
X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst ) {
X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
@@ -1002,6 +1015,17 @@
vex_printf("mfence(%s)",
LibVEX_ppVexHwCaps(VexArchX86,i->Xin.MFence.hwcaps));
return;
+ case Xin_ACAS:
+ vex_printf("lock cmpxchg%c ",
+ i->Xin.ACAS.sz==1 ? 'b'
+ : i->Xin.ACAS.sz==2 ? 'w' : 'l');
+ vex_printf("{%%eax->%%ebx},");
+ ppX86AMode(i->Xin.ACAS.addr);
+ return;
+ case Xin_DACAS:
+ vex_printf("lock cmpxchg8b {%%edx:%%eax->%%ecx:%%ebx},");
+ ppX86AMode(i->Xin.DACAS.addr);
+ return;
case Xin_FpUnary:
vex_printf("g%sD ", showX86FpOp(i->Xin.FpUnary.op));
ppHRegX86(i->Xin.FpUnary.src);
@@ -1266,6 +1290,18 @@
return;
case Xin_MFence:
return;
+ case Xin_ACAS:
+ addRegUsage_X86AMode(u, i->Xin.ACAS.addr);
+ addHRegUse(u, HRmRead, hregX86_EBX());
+ addHRegUse(u, HRmModify, hregX86_EAX());
+ return;
+ case Xin_DACAS:
+ addRegUsage_X86AMode(u, i->Xin.DACAS.addr);
+ addHRegUse(u, HRmRead, hregX86_ECX());
+ addHRegUse(u, HRmRead, hregX86_EBX());
+ addHRegUse(u, HRmModify, hregX86_EDX());
+ addHRegUse(u, HRmModify, hregX86_EAX());
+ return;
case Xin_FpUnary:
addHRegUse(u, HRmRead, i->Xin.FpUnary.src);
addHRegUse(u, HRmWrite, i->Xin.FpUnary.dst);
@@ -1450,6 +1486,12 @@
return;
case Xin_MFence:
return;
+ case Xin_ACAS:
+ mapRegs_X86AMode(m, i->Xin.ACAS.addr);
+ return;
+ case Xin_DACAS:
+ mapRegs_X86AMode(m, i->Xin.DACAS.addr);
+ return;
case Xin_FpUnary:
mapReg(m, &i->Xin.FpUnary.src);
mapReg(m, &i->Xin.FpUnary.dst);
@@ -2495,6 +2537,35 @@
/*NOTREACHED*/
break;
+ case Xin_ACAS:
+ /* lock */
+ *p++ = 0xF0;
+ /* cmpxchg{b,w,l} %ebx,mem. Expected-value in %eax, new value
+ in %ebx. The new-value register is hardwired to be %ebx
+ since letting it be any integer register gives the problem
+ that %sil and %dil are unaddressible on x86 and hence we
+ would have to resort to the same kind of trickery as with
+ byte-sized Xin.Store, just below. Given that this isn't
+ performance critical, it is simpler just to force the
+ register operand to %ebx (could equally be %ecx or %edx).
+ (Although %ebx is more consistent with cmpxchg8b.) */
+ if (i->Xin.ACAS.sz == 2) *p++ = 0x66;
+ *p++ = 0x0F;
+ if (i->Xin.ACAS.sz == 1) *p++ = 0xB0; else *p++ = 0xB1;
+ p = doAMode_M(p, hregX86_EBX(), i->Xin.ACAS.addr);
+ goto done;
+
+ case Xin_DACAS:
+ /* lock */
+ *p++ = 0xF0;
+ /* cmpxchg8b m64. Expected-value in %edx:%eax, new value
+ in %ecx:%ebx. All 4 regs are hardwired in the ISA, so
+ aren't encoded in the insn. */
+ *p++ = 0x0F;
+ *p++ = 0xC7;
+ p = doAMode_M(p, fake(1), i->Xin.DACAS.addr);
+ goto done;
+
case Xin_Store:
if (i->Xin.Store.sz == 2) {
/* This case, at least, is simple, given that we can
Modified: branches/DCAS/priv/host-x86/hdefs.h
===================================================================
--- branches/DCAS/priv/host-x86/hdefs.h 2009-05-21 21:31:49 UTC (rev 1891)
+++ branches/DCAS/priv/host-x86/hdefs.h 2009-05-21 21:37:23 UTC (rev 1892)
@@ -367,6 +367,8 @@
Xin_Set32, /* convert condition code to 32-bit value */
Xin_Bsfr32, /* 32-bit bsf/bsr */
Xin_MFence, /* mem fence (not just sse2, but sse0 and 1 too) */
+ Xin_ACAS, /* 8/16/32-bit lock;cmpxchg */
+ Xin_DACAS, /* lock;cmpxchg8b (doubleword ACAS, 2 x 32-bit only) */
Xin_FpUnary, /* FP fake unary op */
Xin_FpBinary, /* FP fake binary op */
@@ -502,6 +504,17 @@
struct {
UInt hwcaps;
} MFence;
+ /* "lock;cmpxchg": mem address in .addr,
+ expected value in %eax, new value in %ebx */
+ struct {
+ X86AMode* addr;
+ UChar sz; /* 1, 2 or 4 */
+ } ACAS;
+ /* "lock;cmpxchg8b": mem address in .addr, expected value in
+ %edx:%eax, new value in %ecx:%ebx */
+ struct {
+ X86AMode* addr;
+ } DACAS;
/* X86 Floating point (fake 3-operand, "flat reg file" insns) */
struct {
@@ -638,6 +651,8 @@
extern X86Instr* X86Instr_Set32 ( X86CondCode cond, HReg dst );
extern X86Instr* X86Instr_Bsfr32 ( Bool isFwds, HReg src, HReg dst );
extern X86Instr* X86Instr_MFence ( UInt hwcaps );
+extern X86Instr* X86Instr_ACAS ( X86AMode* addr, UChar sz );
+extern X86Instr* X86Instr_DACAS ( X86AMode* addr );
extern X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst );
extern X86Instr* X86Instr_FpBinary ( X86FpOp op, HReg srcL, HReg srcR, HReg dst );
Modified: branches/DCAS/priv/host-x86/isel.c
===================================================================
--- branches/DCAS/priv/host-x86/isel.c 2009-05-21 21:31:49 UTC (rev 1891)
+++ branches/DCAS/priv/host-x86/isel.c 2009-05-21 21:37:23 UTC (rev 1892)
@@ -3858,6 +3858,68 @@
}
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->expdLo into %eax, and cas->dataLo into %ebx */
+ X86AMode* am = iselIntExpr_AMode(env, cas->addr);
+ HReg rDataLo = iselIntExpr_R(env, cas->dataLo);
+ HReg rExpdLo = iselIntExpr_R(env, cas->expdLo);
+ HReg rOldLo = lookupIRTemp(env, cas->oldLo);
+ vassert(cas->expdHi == NULL);
+ vassert(cas->dataHi == NULL);
+ addInstr(env, mk_iMOVsd_RR(rExpdLo, rOldLo));
+ addInstr(env, mk_iMOVsd_RR(rExpdLo, hregX86_EAX()));
+ addInstr(env, mk_iMOVsd_RR(rDataLo, hregX86_EBX()));
+ switch (ty) {
+ case Ity_I32: sz = 4; break;
+ case Ity_I16: sz = 2; break;
+ case Ity_I8: sz = 1; break;
+ default: goto unhandled_cas;
+ }
+ addInstr(env, X86Instr_ACAS(am, sz));
+ addInstr(env,
+ X86Instr_CMov32(Xcc_NZ,
+ X86RM_Reg(hregX86_EAX()), rOldLo));
+ return;
+ } else {
+ /* double CAS */
+ IRCAS* cas = stmt->Ist.CAS.details;
+ IRType ty = typeOfIRExpr(env->type_env, cas->dataLo);
+ /* only 32-bit allowed in this case */
+ /* get: cas->expdLo into %eax, and cas->dataLo into %ebx */
+ /* get: cas->expdHi into %edx, and cas->dataHi into %ecx */
+ X86AMode* 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);
+ if (ty != Ity_I32)
+ goto unhandled_cas;
+ addInstr(env, mk_iMOVsd_RR(rExpdHi, rOldHi));
+ addInstr(env, mk_iMOVsd_RR(rExpdLo, rOldLo));
+ addInstr(env, mk_iMOVsd_RR(rExpdHi, hregX86_EDX()));
+ addInstr(env, mk_iMOVsd_RR(rExpdLo, hregX86_EAX()));
+ addInstr(env, mk_iMOVsd_RR(rDataHi, hregX86_ECX()));
+ addInstr(env, mk_iMOVsd_RR(rDataLo, hregX86_EBX()));
+ addInstr(env, X86Instr_DACAS(am));
+ addInstr(env,
+ X86Instr_CMov32(Xcc_NZ,
+ X86RM_Reg(hregX86_EDX()), rOldHi));
+ addInstr(env,
+ X86Instr_CMov32(Xcc_NZ,
+ X86RM_Reg(hregX86_EAX()), rOldLo));
+ return;
+ }
+ unhandled_cas:
+ break;
+
/* --------- INSTR MARK --------- */
/* Doesn't generate any executable code ... */
case Ist_IMark:
|