|
From: <sv...@va...> - 2014-06-04 11:28:26
|
Author: dejanj
Date: Wed Jun 4 11:28:07 2014
New Revision: 2865
Log:
mips64: Support for Cavium MIPS Octeon Atomic and Count Instructions.
Implement Cavium MIPS specific instructions:
baddu, pop, dpop, saa, saad, laa, laad, lai, laid, lad, ladd, law, lawd,
las, lasd, lac, lacd
Fixes BZ #327223.
Modified:
trunk/priv/guest_mips_toIR.c
trunk/priv/host_mips_defs.c
trunk/priv/host_mips_defs.h
trunk/priv/host_mips_isel.c
Modified: trunk/priv/guest_mips_toIR.c
==============================================================================
--- trunk/priv/guest_mips_toIR.c (original)
+++ trunk/priv/guest_mips_toIR.c Wed Jun 4 11:28:07 2014
@@ -2170,6 +2170,62 @@
/*********************************************************/
/*--- Cavium Specific Instructions ---*/
/*********************************************************/
+
+/* Convenience function to yield to thread scheduler */
+static void jump_back(IRExpr *condition)
+{
+ stmt( IRStmt_Exit(condition,
+ Ijk_Yield,
+ IRConst_U64( guest_PC_curr_instr ),
+ OFFB_PC) );
+}
+
+/* Based on s390_irgen_load_and_add32. */
+static void mips_irgen_load_and_add32(IRTemp op1addr, IRTemp new_val,
+ UChar rd, Bool putIntoRd)
+{
+ IRCAS *cas;
+ IRTemp old_mem = newTemp(Ity_I32);
+ IRTemp expd = newTemp(Ity_I32);
+
+ assign(expd, load(Ity_I32, mkexpr(op1addr)));
+
+ cas = mkIRCAS(IRTemp_INVALID, old_mem,
+ Iend_LE, mkexpr(op1addr),
+ NULL, mkexpr(expd), /* expected value */
+ NULL, mkexpr(new_val) /* new value */);
+ stmt(IRStmt_CAS(cas));
+
+ /* If old_mem contains the expected value, then the CAS succeeded.
+ Otherwise, it did not */
+ jump_back(binop(Iop_CmpNE32, mkexpr(old_mem), mkexpr(expd)));
+ if (putIntoRd)
+ putIReg(rd, mkWidenFrom32(Ity_I64, mkexpr(old_mem), True));
+}
+
+/* Based on s390_irgen_load_and_add64. */
+static void mips_irgen_load_and_add64(IRTemp op1addr, IRTemp new_val,
+ UChar rd, Bool putIntoRd)
+{
+ IRCAS *cas;
+ IRTemp old_mem = newTemp(Ity_I64);
+ IRTemp expd = newTemp(Ity_I64);
+
+ assign(expd, load(Ity_I64, mkexpr(op1addr)));
+
+ cas = mkIRCAS(IRTemp_INVALID, old_mem,
+ Iend_LE, mkexpr(op1addr),
+ NULL, mkexpr(expd), /* expected value */
+ NULL, mkexpr(new_val) /* new value */);
+ stmt(IRStmt_CAS(cas));
+
+ /* If old_mem contains the expected value, then the CAS succeeded.
+ Otherwise, it did not */
+ jump_back(binop(Iop_CmpNE64, mkexpr(old_mem), mkexpr(expd)));
+ if (putIntoRd)
+ putIReg(rd, mkexpr(old_mem));
+}
+
static Bool dis_instr_CVM ( UInt theInstr )
{
UChar opc2 = get_function(theInstr);
@@ -2177,7 +2233,7 @@
UChar regRs = get_rs(theInstr);
UChar regRt = get_rt(theInstr);
UChar regRd = get_rd(theInstr);
- UInt imm = get_imm(theInstr);
+ UInt imm = get_imm(theInstr);
UChar lenM1 = get_msb(theInstr);
UChar p = get_lsb(theInstr);
IRType ty = mode64? Ity_I64 : Ity_I32;
@@ -2188,8 +2244,8 @@
UInt size;
assign(tmpRs, getIReg(regRs));
- switch(opc1){
- case 0x1C: {
+ switch(opc1) {
+ case 0x1C: {
switch(opc2) {
case 0x03: { /* DMUL rd, rs, rt */
DIP("dmul r%d, r%d, r%d", regRd, regRs, regRt);
@@ -2199,6 +2255,277 @@
break;
}
+ case 0x18: { /* Store Atomic Add Word - SAA; Cavium OCTEON */
+ DIP("saa r%u, (r%u)", regRt, regRs);
+ IRTemp addr = newTemp(Ity_I64);
+ IRTemp new = newTemp(Ity_I32);
+ assign (addr, getIReg(regRs));
+ assign(new, binop(Iop_Add32,
+ load(Ity_I32, mkexpr(addr)),
+ mkNarrowTo32(ty, getIReg(regRt))));
+ mips_irgen_load_and_add32(addr, new, 0, False);
+ break;
+ }
+
+ /* Store Atomic Add Doubleword - SAAD; Cavium OCTEON */
+ case 0x19: {
+ DIP( "saad r%u, (r%u)", regRt, regRs);
+ IRTemp addr = newTemp(Ity_I64);
+ IRTemp new = newTemp(Ity_I64);
+ assign (addr, getIReg(regRs));
+ assign(new, binop(Iop_Add64,
+ load(Ity_I64, mkexpr(addr)),
+ getIReg(regRt)));
+ mips_irgen_load_and_add64(addr, new, 0, False);
+ break;
+ }
+
+ /* LAI, LAID, LAD, LADD, LAS, LASD,
+ LAC, LACD, LAA, LAAD, LAW, LAWD */
+ case 0x1f: {
+ UInt opc3 = get_sa(theInstr);
+ IRTemp addr = newTemp(Ity_I64);
+ switch (opc3) {
+ /* Load Atomic Increment Word - LAI; Cavium OCTEON2 */
+ case 0x02: {
+ DIP("lai r%u,(r%u)\n", regRd, regRs);
+ IRTemp new = newTemp(Ity_I32);
+ assign(addr, getIReg(regRs));
+ assign(new, binop(Iop_Add32,
+ load(Ity_I32, mkexpr(addr)),
+ mkU32(1)));
+ mips_irgen_load_and_add32(addr, new, regRd, True);
+ break;
+ }
+ /* Load Atomic Increment Doubleword - LAID; Cavium OCTEON2 */
+ case 0x03: {
+ DIP("laid r%u,(r%u)\n", regRd, regRs);
+ IRTemp new = newTemp(Ity_I64);
+ assign(addr, getIReg(regRs));
+ assign(new, binop(Iop_Add64,
+ load(Ity_I64, mkexpr(addr)),
+ mkU64(1)));
+ mips_irgen_load_and_add64(addr, new, regRd, True);
+ break;
+ }
+ /* Load Atomic Decrement Word - LAD; Cavium OCTEON2 */
+ case 0x06: {
+ DIP("lad r%u,(r%u)\n", regRd, regRs);
+ IRTemp new = newTemp(Ity_I32);
+ assign(addr, getIReg(regRs));
+ assign(new, binop(Iop_Sub32,
+ load(Ity_I32, mkexpr(addr)),
+ mkU32(1)));
+ mips_irgen_load_and_add32(addr, new, regRd, True);
+ break;
+ }
+ /* Load Atomic Decrement Doubleword - LADD; Cavium OCTEON2 */
+ case 0x07: {
+ DIP("ladd r%u,(r%u)\n", regRd, regRs);
+ IRTemp new = newTemp(Ity_I64);
+ assign (addr, getIReg(regRs));
+ assign(new, binop(Iop_Sub64,
+ load(Ity_I64, mkexpr(addr)),
+ mkU64(1)));
+ mips_irgen_load_and_add64(addr, new, regRd, True);
+ break;
+ }
+ /* Load Atomic Set Word - LAS; Cavium OCTEON2 */
+ case 0x0a: {
+ DIP("las r%u,(r%u)\n", regRd, regRs);
+ IRTemp new = newTemp(Ity_I32);
+ assign(addr, getIReg(regRs));
+ assign(new, mkU32(0xffffffff));
+ mips_irgen_load_and_add32(addr, new, regRd, True);
+ break;
+ }
+ /* Load Atomic Set Doubleword - LASD; Cavium OCTEON2 */
+ case 0x0b: {
+ DIP("lasd r%u,(r%u)\n", regRd, regRs);
+ IRTemp new = newTemp(Ity_I64);
+ assign (addr, getIReg(regRs));
+ assign(new, mkU64(0xffffffffffffffff));
+ mips_irgen_load_and_add64(addr, new, regRd, True);
+ break;
+ }
+ /* Load Atomic Clear Word - LAC; Cavium OCTEON2 */
+ case 0x0e: {
+ DIP("lac r%u,(r%u)\n", regRd, regRs);
+ IRTemp new = newTemp(Ity_I32);
+ assign (addr, getIReg(regRs));
+ assign(new, mkU32(0));
+ mips_irgen_load_and_add32(addr, new, regRd, True);
+ break;
+ }
+ /* Load Atomic Clear Doubleword - LACD; Cavium OCTEON2 */
+ case 0x0f: {
+ DIP("lacd r%u,(r%u)\n", regRd, regRs);
+ IRTemp new = newTemp(Ity_I64);
+ assign(addr, getIReg(regRs));
+ assign(new, mkU64(0));
+ mips_irgen_load_and_add64(addr, new, regRd, True);
+ break;
+ }
+ /* Load Atomic Add Word - LAA; Cavium OCTEON2 */
+ case 0x12: {
+ DIP("laa r%u,(r%u),r%u\n", regRd, regRs, regRt);
+ IRTemp new = newTemp(Ity_I32);
+ assign(addr, getIReg(regRs));
+ assign(new, binop(Iop_Add32,
+ load(Ity_I32, mkexpr(addr)),
+ mkNarrowTo32(ty, getIReg(regRt))));
+ mips_irgen_load_and_add32(addr, new, regRd, True);
+ break;
+ }
+ /* Load Atomic Add Doubleword - LAAD; Cavium OCTEON2 */
+ case 0x13: {
+ DIP("laad r%u,(r%u),r%u\n", regRd, regRs, regRt);
+ IRTemp new = newTemp(Ity_I64);
+ assign (addr, getIReg(regRs));
+ assign(new, binop(Iop_Add64,
+ load(Ity_I64, mkexpr(addr)),
+ getIReg(regRt)));
+ mips_irgen_load_and_add64(addr, new, regRd, True);
+ break;
+ }
+ /* Load Atomic Swap Word - LAW; Cavium OCTEON2 */
+ case 0x16: {
+ DIP("law r%u,(r%u)\n", regRd, regRs);
+ IRTemp new = newTemp(Ity_I32);
+ assign(addr, getIReg(regRs));
+ assign(new, mkNarrowTo32(ty, getIReg(regRt)));
+ mips_irgen_load_and_add32(addr, new, regRd, True);
+ break;
+ }
+ /* Load Atomic Swap Doubleword - LAWD; Cavium OCTEON2 */
+ case 0x17: {
+ DIP("lawd r%u,(r%u)\n", regRd, regRs);
+ IRTemp new = newTemp(Ity_I64);
+ assign(addr, getIReg(regRs));
+ assign(new, getIReg(regRt));
+ mips_irgen_load_and_add64(addr, new, regRd, True);
+ break;
+ }
+ default:
+ vex_printf("Unknown laxx instruction, opc3=0x%x\n", opc3);
+ vex_printf("Instruction=0x%08x\n", theInstr);
+ return False;
+ }
+ break;
+ }
+
+ /* Unsigned Byte Add - BADDU rd, rs, rt; Cavium OCTEON */
+ case 0x28: {
+ DIP("BADDU r%d, r%d, r%d", regRs, regRt, regRd);
+ IRTemp t0 = newTemp(Ity_I8);
+
+ assign(t0, binop(Iop_Add8,
+ mkNarrowTo8(ty, getIReg(regRs)),
+ mkNarrowTo8(ty, getIReg(regRt))));
+
+ if (mode64)
+ putIReg(regRd, binop(mkSzOp(ty, Iop_And8),
+ unop(Iop_8Uto64, mkexpr(t0)),
+ mkSzImm(ty, 0xFF)));
+ else
+ putIReg(regRd, binop(mkSzOp(ty, Iop_And8),
+ unop(Iop_8Uto32, mkexpr(t0)),
+ mkSzImm(ty, 0xFF)));
+ break;
+ }
+
+ case 0x2c: { /* Count Ones in a Word - POP; Cavium OCTEON */
+ int i, shift[5];
+ IRTemp mask[5];
+ IRTemp old = newTemp(ty);
+ IRTemp nyu = IRTemp_INVALID;
+ assign(old, getIReg(regRs));
+ DIP("pop r%d, r%d", regRd, regRs);
+
+ for (i = 0; i < 5; i++) {
+ mask[i] = newTemp(ty);
+ shift[i] = 1 << i;
+ }
+ if(mode64) {
+ assign(mask[0], mkU64(0x0000000055555555));
+ assign(mask[1], mkU64(0x0000000033333333));
+ assign(mask[2], mkU64(0x000000000F0F0F0F));
+ assign(mask[3], mkU64(0x0000000000FF00FF));
+ assign(mask[4], mkU64(0x000000000000FFFF));
+
+ for (i = 0; i < 5; i++) {
+ nyu = newTemp(ty);
+ assign(nyu,
+ binop(Iop_Add64,
+ binop(Iop_And64,
+ mkexpr(old), mkexpr(mask[i])),
+ binop(Iop_And64,
+ binop(Iop_Shr64,
+ mkexpr(old), mkU8(shift[i])),
+ mkexpr(mask[i]))));
+ old = nyu;
+ }
+ } else {
+ assign(mask[0], mkU32(0x55555555));
+ assign(mask[1], mkU32(0x33333333));
+ assign(mask[2], mkU32(0x0F0F0F0F));
+ assign(mask[3], mkU32(0x00FF00FF));
+ assign(mask[4], mkU32(0x0000FFFF));
+ assign(old, getIReg(regRs));
+
+ for (i = 0; i < 5; i++) {
+ nyu = newTemp(ty);
+ assign(nyu,
+ binop(Iop_Add32,
+ binop(Iop_And32,
+ mkexpr(old), mkexpr(mask[i])),
+ binop(Iop_And32,
+ binop(Iop_Shr32,
+ mkexpr(old), mkU8(shift[i])),
+ mkexpr(mask[i]))));
+ old = nyu;
+ }
+ }
+ putIReg(regRd, mkexpr(nyu));
+ break;
+ }
+
+ /* Count Ones in a Doubleword - DPOP; Cavium OCTEON */
+ case 0x2d: {
+ int i, shift[6];
+ IRTemp mask[6];
+ IRTemp old = newTemp(ty);
+ IRTemp nyu = IRTemp_INVALID;
+ DIP("dpop r%d, r%d", regRd, regRs);
+
+ for (i = 0; i < 6; i++) {
+ mask[i] = newTemp(ty);
+ shift[i] = 1 << i;
+ }
+ vassert(mode64); /*Caution! Only for Mode 64*/
+ assign(mask[0], mkU64(0x5555555555555555ULL));
+ assign(mask[1], mkU64(0x3333333333333333ULL));
+ assign(mask[2], mkU64(0x0F0F0F0F0F0F0F0FULL));
+ assign(mask[3], mkU64(0x00FF00FF00FF00FFULL));
+ assign(mask[4], mkU64(0x0000FFFF0000FFFFULL));
+ assign(mask[5], mkU64(0x00000000FFFFFFFFULL));
+ assign(old, getIReg(regRs));
+ for (i = 0; i < 6; i++) {
+ nyu = newTemp(Ity_I64);
+ assign(nyu,
+ binop(Iop_Add64,
+ binop(Iop_And64,
+ mkexpr(old), mkexpr(mask[i])),
+ binop(Iop_And64,
+ binop(Iop_Shr64,
+ mkexpr(old), mkU8(shift[i])),
+ mkexpr(mask[i]))));
+ old = nyu;
+ }
+ putIReg(regRd, mkexpr(nyu));
+ break;
+ }
+
case 0x32: /* 5. CINS rd, rs, p, lenm1 */
DIP("cins r%u, r%u, %d, %d\n", regRt, regRs, p, lenM1);
assign ( tmp , binop(Iop_Shl64, mkexpr(tmpRs),
@@ -2291,7 +2618,7 @@
}
break;
} /* opc1 0x1C ends here*/
- case 0x1F:{
+ case 0x1F: {
switch(opc2) {
case 0x0A: { // lx - Load indexed instructions
switch (get_sa(theInstr)) {
@@ -14120,34 +14447,40 @@
case 0x1C: /* Special2 */
switch (function) {
- /* Cavium Specific instructions */
- case 0x03: case 0x32: case 0x33: /* DMUL, CINS , CINS32 */
- case 0x3A: case 0x3B: case 0x2B: /* EXT, EXT32, SNE */
- /* CVM Compare Instructions */
- case 0x2A: case 0x2E: case 0x2F: /* SEQ, SEQI, SNEI */
- if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) {
- if (dis_instr_CVM(cins))
- break;
- goto decode_failure;
- } else {
- goto decode_failure;
- }
+ /* Cavium Specific instructions */
+ case 0x03: case 0x32: case 0x33: /* DMUL, CINS , CINS32 */
+ case 0x3A: case 0x3B: case 0x2B: /* EXT, EXT32, SNE */
+ /* CVM Compare Instructions */
+ case 0x2A: case 0x2E: case 0x2F: /* SEQ, SEQI, SNEI */
+ /* CPU Load, Store, Memory, and Control Instructions */
+ case 0x18: case 0x19: /* SAA, SAAD */
+ case 0x1F: /* LAA, LAAD, LAI, LAID */
+ case 0x28: case 0x2C: case 0x2D: /* BADDU, POP, DPOP */
+ if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) {
+ if (dis_instr_CVM(cins))
+ break;
+ goto decode_failure;
+ } else {
+ goto decode_failure;
+ }
break;
- case 0x02: { /* MUL */
- DIP("mul r%d, r%d, r%d", rd, rs, rt);
- if (mode64) {
- IRTemp tmpRs32 = newTemp(Ity_I32);
- IRTemp tmpRt32 = newTemp(Ity_I32);
- IRTemp tmpRes = newTemp(Ity_I32);
- assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs)));
- assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
- assign(tmpRes, binop(Iop_Mul32, mkexpr(tmpRs32), mkexpr(tmpRt32)));
- putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpRes), True));
- } else
- putIReg(rd, binop(Iop_Mul32, getIReg(rs), getIReg(rt)));
- break;
- }
+ case 0x02: { /* MUL */
+ DIP("mul r%d, r%d, r%d", rd, rs, rt);
+ if (mode64) {
+ IRTemp tmpRs32 = newTemp(Ity_I32);
+ IRTemp tmpRt32 = newTemp(Ity_I32);
+ IRTemp tmpRes = newTemp(Ity_I32);
+
+ assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs)));
+ assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
+ assign(tmpRes, binop(Iop_Mul32,
+ mkexpr(tmpRs32), mkexpr(tmpRt32)));
+ putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpRes), True));
+ } else
+ putIReg(rd, binop(Iop_Mul32, getIReg(rs), getIReg(rt)));
+ break;
+ }
case 0x00: { /* MADD */
if (mode64) {
Modified: trunk/priv/host_mips_defs.c
==============================================================================
--- trunk/priv/host_mips_defs.c (original)
+++ trunk/priv/host_mips_defs.c Wed Jun 4 11:28:07 2014
@@ -1399,6 +1399,23 @@
return i;
}
+MIPSInstr *MIPSInstr_Cas(UChar sz, HReg old, HReg addr,
+ HReg expd, HReg data, Bool mode64)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Cas;
+ i->Min.Cas.sz = sz;
+ i->Min.Cas.old = old;
+ i->Min.Cas.addr = addr;
+ i->Min.Cas.expd = expd;
+ i->Min.Cas.data = data;
+ vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
+
+ if (sz == 8)
+ vassert(mode64);
+ return i;
+}
+
MIPSInstr *MIPSInstr_StoreC(UChar sz, MIPSAMode * dst, HReg src, Bool mode64)
{
MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
@@ -1777,6 +1794,55 @@
ppMIPSAMode(i->Min.LoadL.src, mode64);
return;
}
+ case Min_Cas: {
+ Bool sz8 = toBool(i->Min.Cas.sz == 8);
+ /*
+ * ll(d) old, 0(addr)
+ * bne old, expd, end
+ * nop
+ * (d)addiu old, old, 1
+ * sc(d) data, 0(addr)
+ * movn old, expd, data
+ * end:
+ */
+ // ll(d) old, 0(addr)
+ vex_printf("cas: ");
+
+ vex_printf("%s ", sz8 ? "lld" : "ll");
+ ppHRegMIPS(i->Min.Cas.old , mode64);
+ vex_printf(", 0(");
+ ppHRegMIPS(i->Min.Cas.addr , mode64);
+ vex_printf(")\n");
+
+ vex_printf("bne ");
+ ppHRegMIPS(i->Min.Cas.old , mode64);
+ vex_printf(", ");
+ ppHRegMIPS(i->Min.Cas.expd , mode64);
+ vex_printf(", end\n");
+
+ vex_printf("nop\n");
+
+ vex_printf("%s ", sz8 ? "daddiu" : "addiu");
+ ppHRegMIPS(i->Min.Cas.old , mode64);
+ vex_printf(", ");
+ ppHRegMIPS(i->Min.Cas.old , mode64);
+ vex_printf(", 1\n");
+
+ vex_printf("%s ", sz8 ? "scd" : "sc");
+ ppHRegMIPS(i->Min.Cas.data , mode64);
+ vex_printf(", 0(");
+ ppHRegMIPS(i->Min.Cas.addr , mode64);
+ vex_printf(")\n");
+
+ vex_printf("movn ");
+ ppHRegMIPS(i->Min.Cas.old , mode64);
+ vex_printf(", ");
+ ppHRegMIPS(i->Min.Cas.expd , mode64);
+ vex_printf(", ");
+ ppHRegMIPS(i->Min.Cas.data , mode64);
+ vex_printf("\nend:");
+ return;
+ }
case Min_StoreC: {
vex_printf("sc ");
ppHRegMIPS(i->Min.StoreC.src, mode64);
@@ -2062,6 +2128,12 @@
addRegUsage_MIPSAMode(u, i->Min.LoadL.src);
addHRegUse(u, HRmWrite, i->Min.LoadL.dst);
return;
+ case Min_Cas:
+ addHRegUse(u, HRmWrite, i->Min.Cas.old);
+ addHRegUse(u, HRmRead, i->Min.Cas.addr);
+ addHRegUse(u, HRmRead, i->Min.Cas.expd);
+ addHRegUse(u, HRmModify, i->Min.Cas.data);
+ return;
case Min_StoreC:
addHRegUse(u, HRmWrite, i->Min.StoreC.src);
addHRegUse(u, HRmRead, i->Min.StoreC.src);
@@ -2214,6 +2286,12 @@
mapRegs_MIPSAMode(m, i->Min.LoadL.src);
mapReg(m, &i->Min.LoadL.dst);
return;
+ case Min_Cas:
+ mapReg(m, &i->Min.Cas.old);
+ mapReg(m, &i->Min.Cas.addr);
+ mapReg(m, &i->Min.Cas.expd);
+ mapReg(m, &i->Min.Cas.data);
+ return;
case Min_StoreC:
mapReg(m, &i->Min.StoreC.src);
mapRegs_MIPSAMode(m, i->Min.StoreC.dst);
@@ -3459,8 +3537,8 @@
switch (i->Min.XAssisted.jk) {
case Ijk_ClientReq: trcval = VEX_TRC_JMP_CLIENTREQ; break;
case Ijk_Sys_syscall: trcval = VEX_TRC_JMP_SYS_SYSCALL; break;
- /* case Ijk_Sys_int128: trcval = VEX_TRC_JMP_SYS_INT128; break;
- case Ijk_Yield: trcval = VEX_TRC_JMP_YIELD; break; */
+ /* case Ijk_Sys_int128: trcval = VEX_TRC_JMP_SYS_INT128; break; */
+ case Ijk_Yield: trcval = VEX_TRC_JMP_YIELD; break;
case Ijk_EmWarn: trcval = VEX_TRC_JMP_EMWARN; break;
case Ijk_EmFail: trcval = VEX_TRC_JMP_EMFAIL; break;
/* case Ijk_MapFail: trcval = VEX_TRC_JMP_MAPFAIL; break; */
@@ -3646,6 +3724,39 @@
p = mkFormI(p, 0x3C, r_dst, r_src, idx);
goto done;
}
+ case Min_Cas: {
+ if (i->Min.Cas.sz != 8 && i->Min.Cas.sz != 4)
+ goto bad;
+ UInt old = iregNo(i->Min.Cas.old, mode64);
+ UInt addr = iregNo(i->Min.Cas.addr, mode64);
+ UInt expd = iregNo(i->Min.Cas.expd, mode64);
+ UInt data = iregNo(i->Min.Cas.data, mode64);
+ Bool sz8 = toBool(i->Min.Cas.sz == 8);
+
+ /*
+ * ll(d) old, 0(addr)
+ * bne old, expd, end
+ * nop
+ * (d)addiu old, old, 1
+ * sc(d) data, 0(addr)
+ * movn old, expd, data
+ * end:
+ */
+ // ll(d) old, 0(addr)
+ p = mkFormI(p, sz8 ? 0x34 : 0x30, addr, old, 0);
+ // bne old, expd, end
+ p = mkFormI(p, 5, old, expd, 4);
+ // nop
+ p = mkFormR(p, 0, 0, 0, 0, 0, 0);
+ // (d)addiu old, old, 1
+ p = mkFormI(p, sz8 ? 25 : 9, old, old, 1);
+ // sc(d) data, 0(addr)
+ p = mkFormI(p, sz8 ? 0x3C : 0x38, addr, data, 0);
+ // movn old, expd, data
+ p = mkFormR(p, 0, expd, data, old, 0, 0xb);
+
+ goto done;
+ }
case Min_RdWrLR: {
UInt reg = iregNo(i->Min.RdWrLR.gpr, mode64);
Bool wrLR = i->Min.RdWrLR.wrLR;
Modified: trunk/priv/host_mips_defs.h
==============================================================================
--- trunk/priv/host_mips_defs.h (original)
+++ trunk/priv/host_mips_defs.h Wed Jun 4 11:28:07 2014
@@ -325,6 +325,7 @@
Min_Load, /* zero-extending load a 8|16|32 bit value from mem */
Min_Store, /* store a 8|16|32 bit value to mem */
+ Min_Cas, /* compare and swap */
Min_LoadL, /* mips Load Linked Word - LL */
Min_StoreC, /* mips Store Conditional Word - SC */
@@ -521,6 +522,13 @@
} LoadL;
struct {
UChar sz; /* 4|8 */
+ HReg old;
+ HReg addr;
+ HReg expd;
+ HReg data;
+ } Cas;
+ struct {
+ UChar sz; /* 4|8 */
MIPSAMode *dst;
HReg src;
} StoreC;
@@ -649,6 +657,8 @@
Bool mode64);
extern MIPSInstr *MIPSInstr_StoreC(UChar sz, MIPSAMode * dst, HReg src,
Bool mode64);
+extern MIPSInstr *MIPSInstr_Cas(UChar sz, HReg old, HReg addr,
+ HReg expd, HReg data, Bool mode64);
extern MIPSInstr *MIPSInstr_Call ( MIPSCondCode, Addr64, UInt, HReg, RetLoc );
extern MIPSInstr *MIPSInstr_CallAlways ( MIPSCondCode, Addr64, UInt, RetLoc );
Modified: trunk/priv/host_mips_isel.c
==============================================================================
--- trunk/priv/host_mips_isel.c (original)
+++ trunk/priv/host_mips_isel.c Wed Jun 4 11:28:07 2014
@@ -971,7 +971,9 @@
|| e->Iex.Binop.op == Iop_CmpLE32S
|| e->Iex.Binop.op == Iop_CmpLE64S
|| e->Iex.Binop.op == Iop_CmpLT64S
- || e->Iex.Binop.op == Iop_CmpEQ64) {
+ || e->Iex.Binop.op == Iop_CmpEQ64
+ || e->Iex.Binop.op == Iop_CasCmpEQ32
+ || e->Iex.Binop.op == Iop_CasCmpEQ64) {
Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
|| e->Iex.Binop.op == Iop_CmpLE32S
@@ -986,6 +988,7 @@
switch (e->Iex.Binop.op) {
case Iop_CmpEQ32:
+ case Iop_CasCmpEQ32:
cc = MIPScc_EQ;
size32 = True;
break;
@@ -1030,6 +1033,7 @@
size32 = False;
break;
case Iop_CmpEQ64:
+ case Iop_CasCmpEQ64:
cc = MIPScc_EQ;
size32 = False;
break;
@@ -2051,7 +2055,9 @@
|| e->Iex.Binop.op == Iop_CmpLE32S
|| e->Iex.Binop.op == Iop_CmpLE64S
|| e->Iex.Binop.op == Iop_CmpLT64S
- || e->Iex.Binop.op == Iop_CmpEQ64) {
+ || e->Iex.Binop.op == Iop_CmpEQ64
+ || e->Iex.Binop.op == Iop_CasCmpEQ32
+ || e->Iex.Binop.op == Iop_CasCmpEQ64) {
Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
|| e->Iex.Binop.op == Iop_CmpLE32S
@@ -2066,6 +2072,7 @@
switch (e->Iex.Binop.op) {
case Iop_CmpEQ32:
+ case Iop_CasCmpEQ32:
cc = MIPScc_EQ;
size32 = True;
break;
@@ -2102,6 +2109,7 @@
size32 = False;
break;
case Iop_CmpEQ64:
+ case Iop_CasCmpEQ64:
cc = MIPScc_EQ;
size32 = False;
break;
@@ -3933,6 +3941,20 @@
goto stmt_fail;
/* NOTREACHED */}
+ case Ist_CAS:
+ if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
+ IRCAS *cas = stmt->Ist.CAS.details;
+ HReg old = lookupIRTemp(env, cas->oldLo);
+ HReg addr = iselWordExpr_R(env, cas->addr);
+ HReg expd = iselWordExpr_R(env, cas->expdLo);
+ HReg data = iselWordExpr_R(env, cas->dataLo);
+ if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I64) {
+ addInstr(env, MIPSInstr_Cas(8, old, addr, expd, data, mode64));
+ } else if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
+ addInstr(env, MIPSInstr_Cas(4, old, addr, expd, data, mode64));
+ }
+ }
+
/* --------- INSTR MARK --------- */
/* Doesn't generate any executable code ... */
case Ist_IMark:
@@ -3997,6 +4019,7 @@
case Ijk_NoDecode:
case Ijk_NoRedir:
case Ijk_SigBUS:
+ case Ijk_Yield:
case Ijk_SigTRAP:
case Ijk_SigFPE_IntDiv:
case Ijk_SigFPE_IntOvf:
|