From: Dejan Jevtic Date: Wed, 4 Jun 2014 11:28:07 +0000 (+0000) Subject: mips64: Support for Cavium MIPS Octeon Atomic and Count Instructions. X-Git-Tag: svn/VALGRIND_3_10_1^2~105 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=82c58799eb2a0425569fd55abb93c97a71c68458;p=thirdparty%2Fvalgrind.git 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. git-svn-id: svn://svn.valgrind.org/vex/trunk@2865 --- diff --git a/VEX/priv/guest_mips_toIR.c b/VEX/priv/guest_mips_toIR.c index 92059ede0c..d8bdfeb360 100644 --- a/VEX/priv/guest_mips_toIR.c +++ b/VEX/priv/guest_mips_toIR.c @@ -2170,6 +2170,62 @@ static Bool dis_instr_branch ( UInt theInstr, DisResult * dres, /*********************************************************/ /*--- 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 @@ static Bool dis_instr_CVM ( UInt theInstr ) 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 @@ static Bool dis_instr_CVM ( UInt theInstr ) 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 @@ static Bool dis_instr_CVM ( UInt theInstr ) 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 @@ static Bool dis_instr_CVM ( UInt theInstr ) } 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 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, 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) { diff --git a/VEX/priv/host_mips_defs.c b/VEX/priv/host_mips_defs.c index ca92f89f90..1bf81b2f59 100644 --- a/VEX/priv/host_mips_defs.c +++ b/VEX/priv/host_mips_defs.c @@ -1399,6 +1399,23 @@ MIPSInstr *MIPSInstr_LoadL(UChar sz, HReg dst, MIPSAMode * src, Bool mode64) 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 @@ void ppMIPSInstr(MIPSInstr * i, Bool mode64) 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 @@ void getRegUsage_MIPSInstr(HRegUsage * u, MIPSInstr * i, Bool mode64) 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 @@ void mapRegs_MIPSInstr(HRegRemap * m, MIPSInstr * i, Bool mode64) 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 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, 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 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, 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; diff --git a/VEX/priv/host_mips_defs.h b/VEX/priv/host_mips_defs.h index cc2b48fc64..22881eea82 100644 --- a/VEX/priv/host_mips_defs.h +++ b/VEX/priv/host_mips_defs.h @@ -325,6 +325,7 @@ typedef enum { 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 */ @@ -519,6 +520,13 @@ typedef struct { HReg dst; MIPSAMode *src; } LoadL; + struct { + UChar sz; /* 4|8 */ + HReg old; + HReg addr; + HReg expd; + HReg data; + } Cas; struct { UChar sz; /* 4|8 */ MIPSAMode *dst; @@ -649,6 +657,8 @@ extern MIPSInstr *MIPSInstr_LoadL(UChar sz, HReg dst, MIPSAMode * src, 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 ); diff --git a/VEX/priv/host_mips_isel.c b/VEX/priv/host_mips_isel.c index 572edf4462..233367d925 100644 --- a/VEX/priv/host_mips_isel.c +++ b/VEX/priv/host_mips_isel.c @@ -971,7 +971,9 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) || 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 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) switch (e->Iex.Binop.op) { case Iop_CmpEQ32: + case Iop_CasCmpEQ32: cc = MIPScc_EQ; size32 = True; break; @@ -1030,6 +1033,7 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) size32 = False; break; case Iop_CmpEQ64: + case Iop_CasCmpEQ64: cc = MIPScc_EQ; size32 = False; break; @@ -2051,7 +2055,9 @@ static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e) || 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 @@ static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e) switch (e->Iex.Binop.op) { case Iop_CmpEQ32: + case Iop_CasCmpEQ32: cc = MIPScc_EQ; size32 = True; break; @@ -2102,6 +2109,7 @@ static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e) size32 = False; break; case Iop_CmpEQ64: + case Iop_CasCmpEQ64: cc = MIPScc_EQ; size32 = False; break; @@ -3933,6 +3941,20 @@ static void iselStmt(ISelEnv * env, IRStmt * stmt) 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 @@ static void iselStmt(ISelEnv * env, IRStmt * stmt) case Ijk_NoDecode: case Ijk_NoRedir: case Ijk_SigBUS: + case Ijk_Yield: case Ijk_SigTRAP: case Ijk_SigFPE_IntDiv: case Ijk_SigFPE_IntOvf: