From: Petar Jovanovic Date: Thu, 1 Feb 2018 17:19:24 +0000 (+0100) Subject: mips: add support for mips32/mips64 R6 to VEX X-Git-Tag: VALGRIND_3_14_0~169 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6e7f9c9ef405e8d5289fbb6d960e220311ebe110;p=thirdparty%2Fvalgrind.git mips: add support for mips32/mips64 R6 to VEX Full support of MIPS R6 instruction set. Special implementation for MIPS R6 has been added for following IOPs: Iop_Max32U, Iop_Mul32, Iop_Mul64, Iop_MullS32, Iop_MullU32, Iop_MullU8, Iop_MullS8, Iop_MullU16, Iop_MullS16, Iop_CmpF64, Iop_DivModU32to32, Iop_DivModS32to32, Iop_DivS32, Iop_DivU32, Iop_DivS64, Iop_DivU64, Iop_MullU64, Iop_MullS64, Iop_DivModU64to64, Iop_DivModS64to64, Iop_Shr64, Iop_Shl64, Iop_Sar64, Iop_RoundF32toInt, Iop_RoundF64toInt, Iop_MAddF32, Iop_MAddF64, Iop_MSubF32, Iop_MSubF64 Following IOPs have been implemented using MIPS R6 instructions: Iop_MaxNumF32, Iop_MaxNumF64 Iop_MinNumF32, Iop_MinNumF64, Iop_CmpF32, Iop_Rotx32, Iop_Rotx64 Following IOPs have been implemented without using MIPS R6 instructions: Iop_F64toI64S, Iop_F32toI32S, Iop_I64StoF64. Part of MIPS32/64 Revision 6 changes. Contributed by: Tamara Vlahovic, Aleksandar Rikalo and Aleksandra Karadzic. Related BZ issue - #387410. --- diff --git a/VEX/priv/guest_mips_defs.h b/VEX/priv/guest_mips_defs.h index 6ee6728d4c..bbdbc4d7c3 100644 --- a/VEX/priv/guest_mips_defs.h +++ b/VEX/priv/guest_mips_defs.h @@ -91,7 +91,11 @@ typedef enum { CVTDS, CVTDW, CVTSD, CVTSW, CVTWS, CVTWD, CVTDL, CVTLS, CVTLD, CVTSL, ADDS, ADDD, - SUBS, SUBD, DIVS + SUBS, SUBD, DIVS, + RINTS, RINTD, + MAXS, MAXD, MINS, MIND, + MAXAS, MAXAD, MINAS, MINAD, + CMPAFS, CMPAFD, CMPSAFS, CMPSAFD, } flt_op; typedef enum { diff --git a/VEX/priv/guest_mips_helpers.c b/VEX/priv/guest_mips_helpers.c index 3f21512a82..4f74593789 100644 --- a/VEX/priv/guest_mips_helpers.c +++ b/VEX/priv/guest_mips_helpers.c @@ -172,6 +172,7 @@ void LibVEX_GuestMIPS32_initialise( /*OUT*/ VexGuestMIPS32State * vex_state) vex_state->guest_COND = 0; vex_state->guest_CP0_status = 0; + vex_state->guest_CP0_Config5 = 0; vex_state->guest_LLaddr = 0xFFFFFFFF; vex_state->guest_LLdata = 0; @@ -812,6 +813,50 @@ extern UInt mips_dirtyhelper_calculate_FCSR_fp64 ( void* gs, UInt fs, UInt ft, case DIVS: ASM_VOLATILE_BINARY64(div.s) break; +#if defined(__mips_isa_rev) && (__mips_isa_rev >= 6) + case RINTS: + ASM_VOLATILE_UNARY64(rint.s) + break; + case RINTD: + ASM_VOLATILE_UNARY64(rint.d) + break; + case MAXS: + ASM_VOLATILE_BINARY64(max.s) + break; + case MAXD: + ASM_VOLATILE_BINARY64(max.d) + break; + case MINS: + ASM_VOLATILE_BINARY64(min.s) + break; + case MIND: + ASM_VOLATILE_BINARY64(min.d) + break; + case MAXAS: + ASM_VOLATILE_BINARY64(maxa.s) + break; + case MAXAD: + ASM_VOLATILE_BINARY64(maxa.d) + break; + case MINAS: + ASM_VOLATILE_BINARY64(mina.s) + break; + case MINAD: + ASM_VOLATILE_BINARY64(mina.d) + break; + case CMPAFS: + ASM_VOLATILE_BINARY64(cmp.af.s) + break; + case CMPAFD: + ASM_VOLATILE_BINARY64(cmp.af.d) + break; + case CMPSAFS: + ASM_VOLATILE_BINARY64(cmp.saf.s) + break; + case CMPSAFD: + ASM_VOLATILE_BINARY64(cmp.saf.d) + break; +#endif default: vassert(0); break; diff --git a/VEX/priv/guest_mips_toIR.c b/VEX/priv/guest_mips_toIR.c index 0063ae3026..8421126473 100644 --- a/VEX/priv/guest_mips_toIR.c +++ b/VEX/priv/guest_mips_toIR.c @@ -75,6 +75,9 @@ static Bool mode64 = False; /* CPU has FPU and 32 dbl. prec. FP registers. */ static Bool fp_mode64 = False; +/* FPU works in FRE mode */ +static Bool fp_mode64_fre = False; + /* CPU has MSA unit */ static Bool has_msa = False; @@ -1076,6 +1079,17 @@ static Bool branch_or_jump(const UChar * addr) if (fmt == 0x0b) { return True; } + + /* R6 branches */ + /* bc1eqz */ + if (fmt == 0x09) { + return True; + } + + /* bc1nez */ + if (fmt == 0x0D) { + return True; + } } /* bposge32 */ @@ -1105,7 +1119,7 @@ static Bool is_Branch_or_Jump_and_Link(const UChar * addr) return True; } - /* bgezal */ + /* bgezal or bal(r6) */ if (opcode == 0x01 && rt == 0x11) { return True; } @@ -1265,6 +1279,12 @@ static IRExpr *genRORV32(IRExpr * src, IRExpr * rs) binop(Iop_Shr32, src, mkexpr(t0))); } + +static UShort extend_s_9to16(UInt x) +{ + return (UShort) ((((Int) x) << 23) >> 23); +} + static UShort extend_s_10to16(UInt x) { return (UShort) ((((Int) x) << 22) >> 22); @@ -1290,6 +1310,21 @@ static UInt extend_s_18to32(UInt x) return (UInt) ((((Int) x) << 14) >> 14); } +static UInt extend_s_19to32(UInt x) +{ + return (UInt) ((((Int) x) << 13) >> 13); +} + +static UInt extend_s_23to32(UInt x) +{ + return (UInt) ((((Int) x) << 9) >> 9); +} + +static UInt extend_s_26to32(UInt x) +{ + return (UInt) ((((Int) x) << 6) >> 6); +} + static ULong extend_s_16to64 ( UInt x ) { return (ULong) ((((Long) x) << 48) >> 48); @@ -1300,6 +1335,21 @@ static ULong extend_s_18to64 ( UInt x ) return (ULong) ((((Long) x) << 46) >> 46); } +static ULong extend_s_19to64(UInt x) +{ + return (ULong) ((((Long) x) << 45) >> 45); +} + +static ULong extend_s_23to64(UInt x) +{ + return (ULong) ((((Long) x) << 41) >> 41); +} + +static ULong extend_s_26to64(UInt x) +{ + return (ULong) ((((Long) x) << 38) >> 38); +} + static ULong extend_s_32to64 ( UInt x ) { return (ULong) ((((Long) x) << 32) >> 32); @@ -1757,6 +1807,13 @@ static IRExpr *getLoFromF64(IRType ty, IRExpr * src) return src; } +static inline IRExpr *getHiFromF64(IRExpr * src) +{ + vassert(typeOfIRExpr(irsb->tyenv, src) == Ity_F64); + return unop(Iop_ReinterpI32asF32, unop(Iop_64HIto32, + unop(Iop_ReinterpF64asI64, src))); +} + static IRExpr *mkWidenFromF32(IRType ty, IRExpr * src) { vassert(ty == Ity_F32 || ty == Ity_F64); @@ -1848,6 +1905,51 @@ static void dis_branch(Bool link, IRExpr * guard, UInt imm, IRStmt ** set) (UInt) branch_offset), OFFB_PC); } +static void dis_branch_compact(Bool link, IRExpr * guard, UInt imm, + DisResult *dres) +{ + ULong branch_offset; + IRTemp t0; + + if (link) { /* LR (GPR31) = addr of the instr after branch instr */ + if (mode64) + putIReg(31, mkU64(guest_PC_curr_instr + 4)); + else + putIReg(31, mkU32(guest_PC_curr_instr + 4)); + dres->jk_StopHere = Ijk_Call; + } else { + dres->jk_StopHere = Ijk_Boring; + } + + dres->whatNext = Dis_StopHere; + + /* PC = PC + (SignExtend(signed_immed_24) << 2) + An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) + is added to the address of the instruction following + the branch (not the branch itself), in the branch delay slot, to form + a PC-relative effective target address. */ + + if (mode64) + branch_offset = extend_s_18to64(imm << 2); + else + branch_offset = extend_s_18to32(imm << 2); + + t0 = newTemp(Ity_I1); + assign(t0, guard); + + if (mode64) { + stmt(IRStmt_Exit(mkexpr(t0), link ? Ijk_Call : Ijk_Boring, + IRConst_U64(guest_PC_curr_instr + 4 + branch_offset), + OFFB_PC)); + putPC(mkU64(guest_PC_curr_instr + 4)); + } else { + stmt(IRStmt_Exit(mkexpr(t0), link ? Ijk_Call : Ijk_Boring, + IRConst_U32(guest_PC_curr_instr + 4 + + (UInt) branch_offset), OFFB_PC)); + putPC(mkU32(guest_PC_curr_instr + 4)); + } +} + static IRExpr *getFReg(UInt fregNo) { vassert(fregNo < 32); @@ -1887,11 +1989,28 @@ static void putFReg(UInt dregNo, IRExpr * e) vassert(dregNo < 32); IRType ty = fp_mode64 ? Ity_F64 : Ity_F32; vassert(typeOfIRExpr(irsb->tyenv, e) == ty); - stmt(IRStmt_Put(floatGuestRegOffset(dregNo), e)); + + if (fp_mode64_fre) { + IRTemp t0 = newTemp(Ity_F32); + assign(t0, getLoFromF64(ty, e)); +#if defined (_MIPSEL) + stmt(IRStmt_Put(floatGuestRegOffset(dregNo), mkexpr(t0))); + if (dregNo & 1) + stmt(IRStmt_Put(floatGuestRegOffset(dregNo) - 4, mkexpr(t0))); +#else + stmt(IRStmt_Put(floatGuestRegOffset(dregNo) + 4, mkexpr(t0))); + if (dregNo & 1) + stmt(IRStmt_Put(floatGuestRegOffset(dregNo & (~1)), mkexpr(t0))); +#endif + } else { + stmt(IRStmt_Put(floatGuestRegOffset(dregNo), e)); + } + if (has_msa && fp_mode64) { stmt(IRStmt_Put(msaGuestRegOffset(dregNo), binop(Iop_64HLtoV128, - mkU64(0), unop(Iop_ReinterpF64asI64, e)))); + unop(Iop_ReinterpF64asI64, e), + unop(Iop_ReinterpF64asI64, e)))); } } @@ -1902,10 +2021,29 @@ static void putDReg(UInt dregNo, IRExpr * e) IRType ty = Ity_F64; vassert(typeOfIRExpr(irsb->tyenv, e) == ty); stmt(IRStmt_Put(floatGuestRegOffset(dregNo), e)); + if (fp_mode64_fre) { + IRTemp t0 = newTemp(Ity_F32); + if (dregNo & 1) { + assign(t0, getLoFromF64(ty, e)); +#if defined (_MIPSEL) + stmt(IRStmt_Put(floatGuestRegOffset(dregNo) - 4, mkexpr(t0))); +#else + stmt(IRStmt_Put(floatGuestRegOffset(dregNo & (~1)), mkexpr(t0))); +#endif + } else { + assign(t0, getHiFromF64(e)); +#if defined (_MIPSEL) + stmt(IRStmt_Put(floatGuestRegOffset(dregNo | 1), mkexpr(t0))); +#else + stmt(IRStmt_Put(floatGuestRegOffset(dregNo | 1) + 4, mkexpr(t0))); +#endif + } + } if (has_msa) stmt(IRStmt_Put(msaGuestRegOffset(dregNo), binop(Iop_64HLtoV128, - mkU64(0), unop(Iop_ReinterpF64asI64, e)))); + unop(Iop_ReinterpF64asI64, e), + unop(Iop_ReinterpF64asI64, e)))); } else { vassert(dregNo < 32); vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F64); @@ -24645,19 +24783,13 @@ static Int msa_2RF(UInt cins, UChar wd, UChar ws) { /* 2RF */ mkU64(0xC3E0000000000000), mkU64(0xC3E0000000000000))))); assign(t1, - unop(Iop_ReinterpF64asI64, - binop(Iop_RoundF64toInt, - mkU32(0x3), - unop(Iop_ReinterpI64asF64, - unop(Iop_V128to64, - mkexpr(t3)))))); + binop(Iop_F64toI64S, mkU32(0x3), + unop(Iop_ReinterpI64asF64, + unop(Iop_V128to64, mkexpr(t3))))); assign(t2, - unop(Iop_ReinterpF64asI64, - binop(Iop_RoundF64toInt, - mkU32(0x3), - unop(Iop_ReinterpI64asF64, - unop(Iop_V128HIto64, - mkexpr(t3)))))); + binop(Iop_F64toI64S, mkU32(0x3), + unop(Iop_ReinterpI64asF64, + unop(Iop_V128HIto64, mkexpr(t3))))); putWReg(wd, binop(Iop_64HLtoV128, mkexpr(t2), mkexpr(t1))); @@ -24825,13 +24957,10 @@ static Int msa_2RF(UInt cins, UChar wd, UChar ws) { /* 2RF */ tmp[i] = newTemp(Ity_I32); assign(tmp[i], unop(Iop_ReinterpF32asI32, - binop(Iop_I32StoF32, rm, - unop(Iop_ReinterpF32asI32, - binop(Iop_RoundF32toInt, rm, - unop(Iop_ReinterpI32asF32, - binop(Iop_GetElem32x4, - mkexpr(t1), - mkU8(i)))))))); + binop(Iop_RoundF32toInt, rm, + unop(Iop_ReinterpI32asF32, + binop(Iop_GetElem32x4, + mkexpr(t1), mkU8(i)))))); } putWReg(wd, @@ -24909,13 +25038,10 @@ static Int msa_2RF(UInt cins, UChar wd, UChar ws) { /* 2RF */ tmp[i] = newTemp(Ity_I64); assign(tmp[i], unop(Iop_ReinterpF64asI64, - binop(Iop_I64StoF64, rm, - unop(Iop_ReinterpF64asI64, - binop(Iop_RoundF64toInt, rm, - unop(Iop_ReinterpI64asF64, - binop(Iop_GetElem64x2, - mkexpr(t1), - mkU8(i)))))))); + binop(Iop_RoundF64toInt, rm, + unop(Iop_ReinterpI64asF64, + binop(Iop_GetElem64x2, + mkexpr(t1), mkU8(i)))))); } putWReg(wd, @@ -25274,32 +25400,24 @@ static Int msa_2RF(UInt cins, UChar wd, UChar ws) { /* 2RF */ IRExpr *rm = get_IR_roundingmode_MSA(); assign(t1, binop(Iop_32HLto64, - unop(Iop_ReinterpF32asI32, - binop(Iop_RoundF32toInt, rm, - unop(Iop_ReinterpI32asF32, - binop(Iop_GetElem32x4, - mkexpr(t3), - mkU8(1))))), - unop(Iop_ReinterpF32asI32, - binop(Iop_RoundF32toInt, rm, - unop(Iop_ReinterpI32asF32, - binop(Iop_GetElem32x4, - mkexpr(t3), - mkU8(0))))))); + binop(Iop_F32toI32S, rm, + unop(Iop_ReinterpI32asF32, + binop(Iop_GetElem32x4, + mkexpr(t3), mkU8(1)))), + binop(Iop_F32toI32S, rm, + unop(Iop_ReinterpI32asF32, + binop(Iop_GetElem32x4, + mkexpr(t3), mkU8(0)))))); assign(t2, binop(Iop_32HLto64, - unop(Iop_ReinterpF32asI32, - binop(Iop_RoundF32toInt, rm, - unop(Iop_ReinterpI32asF32, - binop(Iop_GetElem32x4, - mkexpr(t3), - mkU8(3))))), - unop(Iop_ReinterpF32asI32, - binop(Iop_RoundF32toInt, rm, - unop(Iop_ReinterpI32asF32, - binop(Iop_GetElem32x4, - mkexpr(t3), - mkU8(2))))))); + binop(Iop_F32toI32S, rm, + unop(Iop_ReinterpI32asF32, + binop(Iop_GetElem32x4, + mkexpr(t3), mkU8(3)))), + binop(Iop_F32toI32S, rm, + unop(Iop_ReinterpI32asF32, + binop(Iop_GetElem32x4, + mkexpr(t3), mkU8(2)))))); putWReg(wd, binop(Iop_64HLtoV128, mkexpr(t2), mkexpr(t1))); @@ -25325,17 +25443,13 @@ static Int msa_2RF(UInt cins, UChar wd, UChar ws) { /* 2RF */ mkU64(0xC3E0000000000000))))); IRExpr *rm = get_IR_roundingmode_MSA(); assign(t1, - unop(Iop_ReinterpF64asI64, - binop(Iop_RoundF64toInt, rm, - unop(Iop_ReinterpI64asF64, - unop(Iop_V128to64, - mkexpr(t3)))))); + binop(Iop_F64toI64S, rm, + unop(Iop_ReinterpI64asF64, + unop(Iop_V128to64, mkexpr(t3))))); assign(t2, - unop(Iop_ReinterpF64asI64, - binop(Iop_RoundF64toInt, rm, - unop(Iop_ReinterpI64asF64, - unop(Iop_V128HIto64, - mkexpr(t3)))))); + binop(Iop_F64toI64S, rm, + unop(Iop_ReinterpI64asF64, + unop(Iop_V128HIto64, mkexpr(t3))))); putWReg(wd, binop(Iop_64HLtoV128, mkexpr(t2), mkexpr(t1))); @@ -25361,32 +25475,24 @@ static Int msa_2RF(UInt cins, UChar wd, UChar ws) { /* 2RF */ IRExpr *rm = get_IR_roundingmode_MSA(); assign(t1, binop(Iop_32HLto64, - unop(Iop_ReinterpF32asI32, - binop(Iop_RoundF32toInt, rm, - unop(Iop_ReinterpI32asF32, - binop(Iop_GetElem32x4, - getWReg(ws), - mkU8(1))))), - unop(Iop_ReinterpF32asI32, - binop(Iop_RoundF32toInt, rm, - unop(Iop_ReinterpI32asF32, - binop(Iop_GetElem32x4, - getWReg(ws), - mkU8(0))))))); + binop(Iop_F32toI32U, rm, + unop(Iop_ReinterpI32asF32, + binop(Iop_GetElem32x4, + getWReg(ws), mkU8(1)))), + binop(Iop_F32toI32U, rm, + unop(Iop_ReinterpI32asF32, + binop(Iop_GetElem32x4, + getWReg(ws), mkU8(0)))))); assign(t2, binop(Iop_32HLto64, - unop(Iop_ReinterpF32asI32, - binop(Iop_RoundF32toInt, rm, - unop(Iop_ReinterpI32asF32, - binop(Iop_GetElem32x4, - getWReg(ws), - mkU8(3))))), - unop(Iop_ReinterpF32asI32, - binop(Iop_RoundF32toInt, rm, - unop(Iop_ReinterpI32asF32, - binop(Iop_GetElem32x4, - getWReg(ws), - mkU8(2))))))); + binop(Iop_F32toI32U, rm, + unop(Iop_ReinterpI32asF32, + binop(Iop_GetElem32x4, + getWReg(ws), mkU8(3)))), + binop(Iop_F32toI32U, rm, + unop(Iop_ReinterpI32asF32, + binop(Iop_GetElem32x4, + getWReg(ws), mkU8(2)))))); assign(t3, unop(Iop_NotV128, binop(Iop_SarN32x4, @@ -25991,39 +26097,39 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, case 0x11: { /* COP1 */ if (fmt == 0x3 && fd == 0 && function == 0) { /* MFHC1 */ DIP("mfhc1 r%u, f%u", rt, fs); - if (VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + if (VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps) || + VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { if (fp_mode64) { t0 = newTemp(Ity_I64); t1 = newTemp(Ity_I32); assign(t0, unop(Iop_ReinterpF64asI64, getDReg(fs))); assign(t1, unop(Iop_64HIto32, mkexpr(t0))); putIReg(rt, mkWidenFrom32(ty, mkexpr(t1), True)); - break; } else { putIReg(rt, mkWidenFrom32(ty, unop(Iop_ReinterpF32asI32, getFReg(fs | 1)), True)); - break; } + } else { + ILLEGAL_INSTRUCTON; } - ILLEGAL_INSTRUCTON; break; } else if (fmt == 0x7 && fd == 0 && function == 0) { /* MTHC1 */ DIP("mthc1 r%u, f%u", rt, fs); - if (VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + if (VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps) || + VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { if (fp_mode64) { t0 = newTemp(Ity_I64); assign(t0, binop(Iop_32HLto64, mkNarrowTo32(ty, getIReg(rt)), unop(Iop_ReinterpF32asI32, getLoFromF64(Ity_F64, getDReg(fs))))); putDReg(fs, unop(Iop_ReinterpI64asF64, mkexpr(t0))); - break; } else { putFReg(fs | 1, unop(Iop_ReinterpI32asF32, mkNarrowTo32(ty, getIReg(rt)))); - break; } + } else { + ILLEGAL_INSTRUCTON; } - ILLEGAL_INSTRUCTON; break; } else if (fmt == 0x8) { /* BC */ /* FcConditionalCode(bc1_cc) */ @@ -26189,7 +26295,437 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, unop(Iop_V128HIto64, mkexpr(t1)))))); dis_branch(False, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0)), imm, &bstmt); + } else if (fmt == 0x09) { /* BC1EQZ */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("bc1eqz f%u, %u", ft, imm); + t1 = newTemp(Ity_I1); + if (mode64) { + assign(t1, binop(Iop_CmpEQ64, + binop(Iop_And64, + unop(Iop_ReinterpF64asI64, getDReg(ft)), + mkU64(1)), + mkU64(0))); + } else { + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64to32, + unop(Iop_ReinterpF64asI64, getDReg(ft))), + mkU32(1)), + mkU32(0))); + } + dis_branch(False, mkexpr(t1), imm, &bstmt); + } else { + ILLEGAL_INSTRUCTON; + } + } else if (fmt == 0x0D) { /* BC1NEZ */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("bc1nez f%u, %u", ft, imm); + t1 = newTemp(Ity_I1); + if (mode64) { + assign(t1, binop(Iop_CmpNE64, + binop(Iop_And64, + unop(Iop_ReinterpF64asI64, getDReg(ft)), + mkU64(1)), + mkU64(0))); + } else { + assign(t1, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + unop(Iop_ReinterpF64asI64, getDReg(ft))), + mkU32(1)), + mkU32(0))); + } + dis_branch(False, mkexpr(t1), imm, &bstmt); + } else { + ILLEGAL_INSTRUCTON; + } } else { + if (fmt == 0x15) { /* CMP.cond.d */ + Bool comparison = True; + UInt signaling = CMPAFD; + DIP("cmp.cond.d f%u, f%u, f%u, cond %u", fd, fs, ft, function); + t0 = newTemp(Ity_I32); + /* Conditions starting with S should signal exception on QNaN inputs. */ + switch (function) { + case 8: /* SAF */ + signaling = CMPSAFD; + case 0: /* AF */ + assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft))); + calculateFCSR(fs, ft, signaling, False, 2); + putDReg(fd, + binop(Iop_I64StoF64, + get_IR_roundingmode(), mkU64(0))); + break; + case 9: /* SUN */ + signaling = CMPSAFD; + case 1: /* UN */ + assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft))); + calculateFCSR(fs, ft, signaling, False, 2); + putDReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x45)), + unop(Iop_ReinterpI64asF64, + mkU64(0xFFFFFFFFFFFFFFFFULL)), + binop(Iop_I64StoF64, + get_IR_roundingmode(), mkU64(0)))); + break; + case 0x19: /* SOR */ + signaling = CMPSAFD; + case 0x11: /* OR */ + assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft))); + calculateFCSR(fs, ft, signaling, False, 2); + putDReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x45)), + binop(Iop_I64StoF64, + get_IR_roundingmode(), mkU64(0)), + unop(Iop_ReinterpI64asF64, + mkU64(0xFFFFFFFFFFFFFFFFULL)))); + break; + case 0xa: /* SEQ */ + signaling = CMPSAFD; + case 2: /* EQ */ + assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft))); + calculateFCSR(fs, ft, signaling, False, 2); + putDReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x40)), + unop(Iop_ReinterpI64asF64, + mkU64(0xFFFFFFFFFFFFFFFFULL)), + binop(Iop_I64StoF64, + get_IR_roundingmode(), mkU64(0)))); + break; + case 0x1A: /* SNEQ */ + signaling = CMPSAFD; + case 0x12: /* NEQ */ + assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft))); + calculateFCSR(fs, ft, signaling, False, 2); + putDReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x40)), + binop(Iop_I64StoF64, + get_IR_roundingmode(), mkU64(0)), + unop(Iop_ReinterpI64asF64, + mkU64(0xFFFFFFFFFFFFFFFFULL)))); + break; + case 0xB: /* SUEQ */ + signaling = CMPSAFD; + case 0x3: /* UEQ */ + assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft))); + calculateFCSR(fs, ft, signaling, False, 2); + putDReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x40)), + unop(Iop_ReinterpI64asF64, + mkU64(0xFFFFFFFFFFFFFFFFULL)), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t0), mkU32(0x45)), + unop(Iop_ReinterpI64asF64, + mkU64(0xFFFFFFFFFFFFFFFFULL)), + binop(Iop_I64StoF64, + get_IR_roundingmode(), + mkU64(0))))); + break; + case 0x1B: /* SNEQ */ + signaling = CMPSAFD; + case 0x13: /* NEQ */ + assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft))); + calculateFCSR(fs, ft, signaling, False, 2); + putDReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0),mkU32(0x01)), + unop(Iop_ReinterpI64asF64, + mkU64(0xFFFFFFFFFFFFFFFFULL)), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t0),mkU32(0x00)), + unop(Iop_ReinterpI64asF64, + mkU64(0xFFFFFFFFFFFFFFFFULL)), + binop(Iop_I64StoF64, + get_IR_roundingmode(), + mkU64(0))))); + break; + case 0xC: /* SLT */ + signaling = CMPSAFD; + case 0x4: /* LT */ + assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft))); + calculateFCSR(fs, ft, signaling, False, 2); + putDReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x01)), + unop(Iop_ReinterpI64asF64, + mkU64(0xFFFFFFFFFFFFFFFFULL)), + binop(Iop_I64StoF64, + get_IR_roundingmode(), mkU64(0)))); + break; + case 0xD: /* SULT */ + signaling = CMPSAFD; + case 0x5: /* ULT */ + assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft))); + calculateFCSR(fs, ft, signaling, False, 2); + putDReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x01)), + unop(Iop_ReinterpI64asF64, + mkU64(0xFFFFFFFFFFFFFFFFULL)), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t0), mkU32(0x45)), + unop(Iop_ReinterpI64asF64, + mkU64(0xFFFFFFFFFFFFFFFFULL)), + binop(Iop_I64StoF64, + get_IR_roundingmode(), + mkU64(0))))); + break; + case 0xE: /* SLE */ + signaling = CMPSAFD; + case 0x6: /* LE */ + assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft))); + calculateFCSR(fs, ft, signaling, False, 2); + putDReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0),mkU32(0x01)), + unop(Iop_ReinterpI64asF64, + mkU64(0xFFFFFFFFFFFFFFFFULL)), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t0),mkU32(0x40)), + unop(Iop_ReinterpI64asF64, + mkU64(0xFFFFFFFFFFFFFFFFULL)), + binop(Iop_I64StoF64, + get_IR_roundingmode(), + mkU64(0))))); + break; + case 0xF: /* SULE */ + signaling = CMPSAFD; + case 0x7: /* ULE */ + assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft))); + calculateFCSR(fs, ft, signaling, False, 2); + putDReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0)), + binop(Iop_I64StoF64, + get_IR_roundingmode(), mkU64(0)), + unop(Iop_ReinterpI64asF64, + mkU64(0xFFFFFFFFFFFFFFFFULL)))); + break; + default: + comparison = False; + } + if (comparison) { + if (!VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON; + } + break; + } + + } else if (fmt == 0x14) { + Bool comparison = True; + UInt signaling = CMPAFS; + DIP("cmp.cond.s f%u, f%u, f%u, cond %u", fd, fs, ft, function); + t0 = newTemp(Ity_I32); + /* Conditions starting with S should signal exception on QNaN inputs. */ + switch (function) { + case 8: /* SAF */ + signaling = CMPSAFS; + case 0: /* AF */ + assign(t0, binop(Iop_CmpF32, + getLoFromF64(Ity_F64, getFReg(fs)), + getLoFromF64(Ity_F64, getFReg(ft)))); + calculateFCSR(fs, ft, signaling, True, 2); + putFReg(fd, + mkWidenFromF32(tyF, + binop(Iop_I32StoF32, + get_IR_roundingmode(), mkU32(0)))); + break; + case 9: /* SUN */ + signaling = CMPSAFS; + case 1: /* UN */ + assign(t0, binop(Iop_CmpF32, + getLoFromF64(Ity_F64, getFReg(fs)), + getLoFromF64(Ity_F64, getFReg(ft)))); + calculateFCSR(fs, ft, signaling, True, 2); + putFReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x45)), + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + mkU32(0xFFFFFFFFU))), + mkWidenFromF32(tyF, + binop(Iop_I32StoF32, + get_IR_roundingmode(), + mkU32(0))))); + break; + case 0x19: /* SOR */ + signaling = CMPSAFS; + case 0x11: /* OR */ + assign(t0, binop(Iop_CmpF32, + getLoFromF64(Ity_F64, getFReg(fs)), + getLoFromF64(Ity_F64, getFReg(ft)))); + calculateFCSR(fs, ft, signaling, True, 2); + putFReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x45)), + mkWidenFromF32(tyF, + binop(Iop_I32StoF32, + get_IR_roundingmode(), + mkU32(0))), + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + mkU32(0xFFFFFFFFU))))); + break; + case 0xa: /* SEQ */ + signaling = CMPSAFS; + case 2: /* EQ */ + assign(t0, binop(Iop_CmpF32, + getLoFromF64(Ity_F64, getFReg(fs)), + getLoFromF64(Ity_F64, getFReg(ft)))); + calculateFCSR(fs, ft, signaling, True, 2); + putFReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x40)), + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + mkU32(0xFFFFFFFFU))), + mkWidenFromF32(tyF, + binop(Iop_I32StoF32, + get_IR_roundingmode(), + mkU32(0))))); + break; + case 0x1A: /* SNEQ */ + signaling = CMPSAFS; + case 0x12: /* NEQ */ + assign(t0, binop(Iop_CmpF32, + getLoFromF64(Ity_F64, getFReg(fs)), + getLoFromF64(Ity_F64, getFReg(ft)))); + calculateFCSR(fs, ft, signaling, True, 2); + putFReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x40)), + mkWidenFromF32(tyF, + binop(Iop_I32StoF32, + get_IR_roundingmode(), + mkU32(0))), + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + mkU32(0xFFFFFFFFU))))); + break; + case 0xB: /* SUEQ */ + signaling = CMPSAFS; + case 0x3: /* UEQ */ + assign(t0, binop(Iop_CmpF32, + getLoFromF64(Ity_F64, getFReg(fs)), + getLoFromF64(Ity_F64, getFReg(ft)))); + calculateFCSR(fs, ft, signaling, True, 2); + putFReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x40)), + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + mkU32(0xFFFFFFFFU))), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t0), mkU32(0x45)), + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + mkU32(0xFFFFFFFFU))), + mkWidenFromF32(tyF, + binop(Iop_I32StoF32, + get_IR_roundingmode(), + mkU32(0)))))); + break; + case 0x1B: /* SNEQ */ + signaling = CMPSAFS; + case 0x13: /* NEQ */ + assign(t0, binop(Iop_CmpF32, + getLoFromF64(Ity_F64, getFReg(fs)), + getLoFromF64(Ity_F64, getFReg(ft)))); + calculateFCSR(fs, ft, signaling, True, 2); + putFReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0),mkU32(0x01)), + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + mkU32(0xFFFFFFFFU))), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t0),mkU32(0x00)), + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + mkU32(0xFFFFFFFFU))), + mkWidenFromF32(tyF, + binop(Iop_I32StoF32, + get_IR_roundingmode(), + mkU32(0)))))); + break; + case 0xC: /* SLT */ + signaling = CMPSAFS; + case 0x4: /* LT */ + assign(t0, binop(Iop_CmpF32, + getLoFromF64(Ity_F64, getFReg(fs)), + getLoFromF64(Ity_F64, getFReg(ft)))); + calculateFCSR(fs, ft, signaling, True, 2); + putFReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x01)), + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + mkU32(0xFFFFFFFFU))), + mkWidenFromF32(tyF, + binop(Iop_I32StoF32, + get_IR_roundingmode(), + mkU32(0))))); + break; + case 0xD: /* SULT */ + signaling = CMPSAFS; + case 0x5: /* ULT */ + assign(t0, binop(Iop_CmpF32, + getLoFromF64(Ity_F64, getFReg(fs)), + getLoFromF64(Ity_F64, getFReg(ft)))); + calculateFCSR(fs, ft, signaling, True, 2); + putFReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x01)), + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + mkU32(0xFFFFFFFFU))), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t0), mkU32(0x45)), + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + mkU32(0xFFFFFFFFU))), + mkWidenFromF32(tyF, + binop(Iop_I32StoF32, + get_IR_roundingmode(), + mkU32(0)))))); + break; + case 0xE: /* SLE */ + signaling = CMPSAFS; + case 0x6: /* LE */ + assign(t0, binop(Iop_CmpF32, + getLoFromF64(Ity_F64, getFReg(fs)), + getLoFromF64(Ity_F64, getFReg(ft)))); + calculateFCSR(fs, ft, signaling, True, 2); + putFReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0),mkU32(0x01)), + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + mkU32(0xFFFFFFFFU))), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t0),mkU32(0x40)), + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + mkU32(0xFFFFFFFFU))), + mkWidenFromF32(tyF, + binop(Iop_I32StoF32, + get_IR_roundingmode(), + mkU32(0)))))); + break; + case 0xF: /* SULE */ + signaling = CMPSAFS; + case 0x7: /* ULE */ + assign(t0, binop(Iop_CmpF32, + getLoFromF64(Ity_F64, getFReg(fs)), + getLoFromF64(Ity_F64, getFReg(ft)))); + calculateFCSR(fs, ft, signaling, True, 2); + putFReg(fd, + IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0)), + mkWidenFromF32(tyF, + binop(Iop_I32StoF32, + get_IR_roundingmode(), + mkU32(0))), + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + mkU32(0xFFFFFFFFU))))); + break; + default: + comparison = False; + } + if (comparison) { + if (!VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON; + } + break; + } + } + switch (function) { case 0x4: { /* SQRT.fmt */ switch (fmt) { @@ -26350,8 +26886,10 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, DIP("round.l.d f%u, f%u", fd, fs); if (fp_mode64) { calculateFCSR(fs, 0, ROUNDLD, False, 1); - putDReg(fd, binop(Iop_RoundF64toInt, mkU32(0x0), - getDReg(fs))); + putDReg(fd, unop(Iop_ReinterpI64asF64, + binop(Iop_F64toI64S, + mkU32(0x0), + getDReg(fs)))); } else { ILLEGAL_INSTRUCTON; } @@ -26381,8 +26919,10 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, DIP("trunc.l.d f%u, f%u", fd, fs); if (fp_mode64) { calculateFCSR(fs, 0, TRUNCLD, False, 1); - putDReg(fd, binop(Iop_RoundF64toInt, mkU32(0x3), - getDReg(fs))); + putDReg(fd, unop(Iop_ReinterpI64asF64, + binop(Iop_F64toI64S, + mkU32(0x3), + getDReg(fs)))); } else { ILLEGAL_INSTRUCTON; } @@ -26923,10 +27463,11 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, calculateFCSR(fs, 0, CVTWS, True, 1); putFReg(fd, mkWidenFromF32(tyF, - binop(Iop_RoundF32toInt, - get_IR_roundingmode(), - getLoFromF64(tyF, getFReg(fs)))) - ); + unop(Iop_ReinterpI32asF32, + binop(Iop_F32toI32S, + get_IR_roundingmode(), + getLoFromF64(tyF, + getFReg(fs)))))); break; case 0x11: @@ -26967,8 +27508,10 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, DIP("cvt.l.d %u, %u", fd, fs); if (fp_mode64) { calculateFCSR(fs, 0, CVTLD, False, 1); - putDReg(fd, binop(Iop_RoundF64toInt, - get_IR_roundingmode(), getDReg(fs))); + putDReg(fd, unop(Iop_ReinterpI64asF64, + binop(Iop_F64toI64S, + get_IR_roundingmode(), + getDReg(fs)))); } else { ILLEGAL_INSTRUCTON; } @@ -27001,8 +27544,10 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, DIP("floor.l.d %u, %u", fd, fs); if (fp_mode64) { calculateFCSR(fs, 0, FLOORLD, False, 1); - putDReg(fd, binop(Iop_RoundF64toInt, mkU32(0x1), - getDReg(fs))); + putDReg(fd, unop(Iop_ReinterpI64asF64, + binop(Iop_F64toI64S, + mkU32(0x01), + getDReg(fs)))); } else { ILLEGAL_INSTRUCTON; } @@ -27017,25 +27562,13 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, case 0x10: /* S */ DIP("round.w.s f%u, f%u", fd, fs); calculateFCSR(fs, 0, ROUNDWS, True, 1); - if (fp_mode64) { - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I32); - t3 = newTemp(Ity_F32); - t4 = newTemp(Ity_F32); - /* get lo half of FPR */ - assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs))); - - assign(t1, unop(Iop_64to32, mkexpr(t0))); - - assign(t3, unop(Iop_ReinterpI32asF32, mkexpr(t1))); - - assign(t4, binop(Iop_RoundF32toInt, mkU32(0x0), - mkexpr(t3))); - - putFReg(fd, mkWidenFromF32(tyF, mkexpr(t4))); - } else - putFReg(fd, binop(Iop_RoundF32toInt, mkU32(0x0), - getFReg(fs))); + putFReg(fd, + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + binop(Iop_F32toI32S, + mkU32(0x0), + getLoFromF64(tyF, + getFReg(fs)))))); break; case 0x11: /* D */ @@ -27067,25 +27600,13 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, case 0x10: /* S */ DIP("floor.w.s f%u, f%u", fd, fs); calculateFCSR(fs, 0, FLOORWS, True, 1); - if (fp_mode64) { - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I32); - t3 = newTemp(Ity_F32); - t4 = newTemp(Ity_F32); - /* get lo half of FPR */ - assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs))); - - assign(t1, unop(Iop_64to32, mkexpr(t0))); - - assign(t3, unop(Iop_ReinterpI32asF32, mkexpr(t1))); - - assign(t4, binop(Iop_RoundF32toInt, mkU32(0x1), - mkexpr(t3))); - - putFReg(fd, mkWidenFromF32(tyF, mkexpr(t4))); - } else - putFReg(fd, binop(Iop_RoundF32toInt, mkU32(0x1), - getFReg(fs))); + putFReg(fd, + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + binop(Iop_F32toI32S, + mkU32(0x1), + getLoFromF64(tyF, + getFReg(fs)))))); break; case 0x11: /* D */ @@ -27118,25 +27639,13 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, case 0x10: /* S */ DIP("trunc.w.s %u, %u", fd, fs); calculateFCSR(fs, 0, TRUNCWS, True, 1); - if (fp_mode64) { - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I32); - t3 = newTemp(Ity_F32); - t4 = newTemp(Ity_F32); - /* get lo half of FPR */ - assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs))); - - assign(t1, unop(Iop_64to32, mkexpr(t0))); - - assign(t3, unop(Iop_ReinterpI32asF32, mkexpr(t1))); - - assign(t4, binop(Iop_RoundF32toInt, mkU32(0x3), - mkexpr(t3))); - - putFReg(fd, mkWidenFromF32(tyF, mkexpr(t4))); - } else - putFReg(fd, binop(Iop_RoundF32toInt, mkU32(0x3), - getFReg(fs))); + putFReg(fd, + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + binop(Iop_F32toI32S, + mkU32(0x3), + getLoFromF64(tyF, + getFReg(fs)))))); break; case 0x11: /* D */ DIP("trunc.w.d %u, %u", fd, fs); @@ -27169,26 +27678,14 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, case 0x10: /* S */ DIP("ceil.w.s %u, %u", fd, fs); calculateFCSR(fs, 0, CEILWS, True, 1); - if (fp_mode64) { - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I32); - t3 = newTemp(Ity_F32); - t4 = newTemp(Ity_F32); - /* get lo half of FPR */ - assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs))); - - assign(t1, unop(Iop_64to32, mkexpr(t0))); - - assign(t3, unop(Iop_ReinterpI32asF32, mkexpr(t1))); - - assign(t4, binop(Iop_RoundF32toInt, mkU32(0x2), - mkexpr(t3))); - - putFReg(fd, mkWidenFromF32(tyF, mkexpr(t4))); - } else - putFReg(fd, binop(Iop_RoundF32toInt, mkU32(0x2), - getFReg(fs))); - break; + putFReg(fd, + mkWidenFromF32(tyF, + unop(Iop_ReinterpI32asF32, + binop(Iop_F32toI32S, + mkU32(0x2), + getLoFromF64(tyF, + getFReg(fs)))))); + break; case 0x11: /* D */ DIP("ceil.w.d %u, %u", fd, fs); @@ -27206,6 +27703,7 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, unop(Iop_ReinterpI32asF32, mkexpr(t0)))); } break; + default: goto decode_failure; @@ -27233,8 +27731,10 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, DIP("ceil.l.d %u, %u", fd, fs); if (fp_mode64) { calculateFCSR(fs, 0, CEILLD, False, 1); - putDReg(fd, binop(Iop_RoundF64toInt, mkU32(0x2), - getDReg(fs))); + putDReg(fd, unop(Iop_ReinterpI64asF64, + binop(Iop_F64toI64S, + mkU32(0x2), + getDReg(fs)))); } else { ILLEGAL_INSTRUCTON; } @@ -27272,6 +27772,554 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, } break; + case 0x18: /* MADDF.fmt */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + switch (fmt) { + case 0x11: { /* D */ + DIP("maddf.d f%u, f%u, f%u", fd, fs, ft); + IRExpr *rm = get_IR_roundingmode(); + putDReg(fd, qop(Iop_MAddF64, rm, getDReg(fs), getDReg(ft), + getDReg(fd))); + break; + } + + case 0x10: { /* S */ + DIP("maddf.s f%u, f%u, f%u", fd, fs, ft); + IRExpr *rm = get_IR_roundingmode(); + t1 = newTemp(Ity_F32); + assign(t1, qop(Iop_MAddF32, rm, + getLoFromF64(tyF, getFReg(fs)), + getLoFromF64(tyF, getFReg(ft)), + getLoFromF64(tyF, getFReg(fd)))); + putFReg(fd, mkWidenFromF32(tyF, mkexpr(t1))); + break; + } + + default: + goto decode_failure; + } + } else { + ILLEGAL_INSTRUCTON; + } + + break; + + case 0x19: /* MSUBF.fmt */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + switch (fmt) { + case 0x11: { /* D */ + DIP("msubf.d f%u, f%u, f%u", fd, fs, ft); + IRExpr *rm = get_IR_roundingmode(); + putDReg(fd, qop(Iop_MSubF64, rm, getDReg(fs), + getDReg(ft), getDReg(fd))); + break; + } + + case 0x10: { /* S */ + DIP("msubf.s f%u, f%u, f%u", fd, fs, ft); + IRExpr *rm = get_IR_roundingmode(); + t1 = newTemp(Ity_F32); + assign(t1, qop(Iop_MSubF32, rm, + getLoFromF64(tyF, getFReg(fs)), + getLoFromF64(tyF, getFReg(ft)), + getLoFromF64(tyF, getFReg(fd)))); + putFReg(fd, mkWidenFromF32(tyF, mkexpr(t1))); + break; + } + + default: + goto decode_failure; + } + } else { + ILLEGAL_INSTRUCTON; + } + + break; + + case 0x1E: /* MAX.fmt */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + switch (fmt) { + case 0x11: { /* D */ + DIP("max.d f%u, f%u, f%u", fd, fs, ft); + calculateFCSR(fs, ft, MAXD, False, 2); + putDReg(fd, binop(Iop_MaxNumF64, getDReg(fs), getDReg(ft))); + break; + } + + case 0x10: { /* S */ + DIP("max.s f%u, f%u, f%u", fd, fs, ft); + calculateFCSR(fs, ft, MAXS, True, 2); + putFReg(fd, mkWidenFromF32(tyF, binop(Iop_MaxNumF32, + getLoFromF64(Ity_F64, + getFReg(fs)), + getLoFromF64(Ity_F64, + getFReg(ft))))); + break; + } + + default: + goto decode_failure; + } + } else { + ILLEGAL_INSTRUCTON; + } + + break; + + case 0x1C: /* MIN.fmt */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + switch (fmt) { + case 0x11: { /* D */ + DIP("min.d f%u, f%u, f%u", fd, fs, ft); + calculateFCSR(fs, ft, MIND, False, 2); + putDReg(fd, binop(Iop_MinNumF64, getDReg(fs), getDReg(ft))); + break; + } + + case 0x10: { /* S */ + DIP("min.s f%u, f%u, f%u", fd, fs, ft); + calculateFCSR(fs, ft, MINS, True, 2); + putFReg(fd, mkWidenFromF32(tyF, binop(Iop_MinNumF32, + getLoFromF64(Ity_F64, + getFReg(fs)), + getLoFromF64(Ity_F64, + getFReg(ft))))); + break; + } + default: + goto decode_failure; + } + } else { + ILLEGAL_INSTRUCTON; + } + + break; + + case 0x1F: /* MAXA.fmt */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + switch (fmt) { + case 0x11: { /* D */ + DIP("maxa.d f%u, f%u, f%u", fd, fs, ft); + calculateFCSR(fs, ft, MAXAD, False, 2); + t1 = newTemp(Ity_F64); + t2 = newTemp(Ity_F64); + t3 = newTemp(Ity_F64); + t4 = newTemp(Ity_I1); + assign(t1, unop(Iop_AbsF64, getFReg(fs))); + assign(t2, unop(Iop_AbsF64, getFReg(ft))); + assign(t3, binop(Iop_MaxNumF64, mkexpr(t1), mkexpr(t2))); + assign(t4, binop(Iop_CmpEQ32, + binop(Iop_CmpF64, mkexpr(t3), mkexpr(t1)), + mkU32(0x40))); + putFReg(fd, IRExpr_ITE(mkexpr(t4), + getFReg(fs), getFReg(ft))); + break; + } + + case 0x10: { /* S */ + DIP("maxa.s f%u, f%u, f%u", fd, fs, ft); + calculateFCSR(fs, ft, MAXAS, True, 2); + t1 = newTemp(Ity_F32); + t2 = newTemp(Ity_F32); + t3 = newTemp(Ity_F32); + t4 = newTemp(Ity_I1); + assign(t1, unop(Iop_AbsF32, getLoFromF64(Ity_F64, + getFReg(fs)))); + assign(t2, unop(Iop_AbsF32, getLoFromF64(Ity_F64, + getFReg(ft)))); + assign(t3, binop(Iop_MaxNumF32, mkexpr(t1), mkexpr(t2))); + assign(t4, binop(Iop_CmpEQ32, + binop(Iop_CmpF32, mkexpr(t3), mkexpr(t1)), + mkU32(0x40))); + putFReg(fd, IRExpr_ITE(mkexpr(t4), + getFReg(fs), getFReg(ft))); + break; + } + + default: + goto decode_failure; + } + /* missing in documentation */ + } else { + ILLEGAL_INSTRUCTON; + } + break; + + case 0x1D: /* MINA.fmt */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + switch (fmt) { + case 0x11: { /* D */ + DIP("mina.d f%u, f%u, f%u", fd, fs, ft); + calculateFCSR(fs, ft, MINAD, False, 2); + t1 = newTemp(Ity_F64); + t2 = newTemp(Ity_F64); + t3 = newTemp(Ity_F64); + t4 = newTemp(Ity_I1); + assign(t1, unop(Iop_AbsF64, getFReg(fs))); + assign(t2, unop(Iop_AbsF64, getFReg(ft))); + assign(t3, binop(Iop_MinNumF64, mkexpr(t1), mkexpr(t2))); + assign(t4, binop(Iop_CmpEQ32, + binop(Iop_CmpF64, mkexpr(t3), mkexpr(t1)), + mkU32(0x40))); + putFReg(fd, IRExpr_ITE(mkexpr(t4), + getFReg(fs), getFReg(ft))); + break; + } + + case 0x10: { /* S */ + DIP("mina.s f%u, f%u, f%u", fd, fs, ft); + calculateFCSR(fs, ft, MINAS, True, 2); + t1 = newTemp(Ity_F32); + t2 = newTemp(Ity_F32); + t3 = newTemp(Ity_F32); + t4 = newTemp(Ity_I1); + assign(t1, unop(Iop_AbsF32, getLoFromF64(Ity_F64, + getFReg(fs)))); + assign(t2, unop(Iop_AbsF32, getLoFromF64(Ity_F64, + getFReg(ft)))); + assign(t3, binop(Iop_MinNumF32, mkexpr(t1), mkexpr(t2))); + assign(t4, binop(Iop_CmpEQ32, + binop(Iop_CmpF32, mkexpr(t3), mkexpr(t1)), + mkU32(0x40))); + putFReg(fd, IRExpr_ITE(mkexpr(t4), + getFReg(fs), getFReg(ft))); + break; + } + + default: + goto decode_failure; + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + + case 0x1A: /* RINT.fmt */ + if (ft == 0) { + switch (fmt) { + case 0x11: { /* D */ + DIP("rint.d f%u, f%u", fd, fs); + calculateFCSR(fs, 0, RINTS, True, 1); + IRExpr *rm = get_IR_roundingmode(); + putDReg(fd, binop(Iop_RoundF64toInt, rm, getDReg(fs))); + break; + } + + case 0x10: { /* S */ + DIP("rint.s f%u, f%u", fd, fs); + calculateFCSR(fs, 0, RINTD, True, 1); + IRExpr *rm = get_IR_roundingmode(); + putFReg(fd, + mkWidenFromF32(tyF, + binop(Iop_RoundF32toInt, rm, + getLoFromF64(tyF, + getFReg(fs))))); + break; + } + + default: + goto decode_failure; + } + + } + break; + + case 0x10: /* SEL.fmt */ + switch (fmt) { + case 0x11: { /* D */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("sel.d f%u, f%u, f%u", fd, fs, ft); + t1 = newTemp(Ity_I1); + if (mode64) { + assign(t1,binop(Iop_CmpNE64, + binop(Iop_And64, + unop(Iop_ReinterpF64asI64, + getDReg(fd)), + mkU64(1)), + mkU64(0))); + } else { + assign(t1,binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + unop(Iop_ReinterpF64asI64, + getDReg(fd))), + mkU32(1)), + mkU32(0))); + } + putDReg(fd, IRExpr_ITE(mkexpr(t1), + getDReg(ft), getDReg(fs))); + break; + } else { + ILLEGAL_INSTRUCTON; + } + + } + + case 0x10: { /* S */ + DIP("sel.s f%u, f%u, f%u", fd, fs, ft); + t1 = newTemp(Ity_I1); + assign(t1,binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_ReinterpF32asI32, + getLoFromF64(tyF, getFReg(fd))), + mkU32(1)), + mkU32(0))); + putFReg(fd, IRExpr_ITE( mkexpr(t1), + getFReg(ft), getFReg(fs))); + break; + } + default: + goto decode_failure; + } + break; + + case 0x14: /* SELEQZ.fmt */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + switch (fmt) { /* SELEQZ.df */ + case 0x11: { /* D */ + DIP("seleqz.d f%u, f%u, f%u", fd, fs, ft); + t1 = newTemp(Ity_I1); + if (mode64) { + assign(t1, binop(Iop_CmpNE64, + binop(Iop_And64, + unop(Iop_ReinterpF64asI64, + getDReg(ft)), + mkU64(1)), + mkU64(0))); + } else { + assign(t1, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + unop(Iop_ReinterpF64asI64, + getDReg(ft))), + mkU32(1)), + mkU32(0))); + } + putDReg(fd, IRExpr_ITE( mkexpr(t1), + binop(Iop_I64StoF64, + get_IR_roundingmode(),mkU64(0)), + getDReg(fs))); + break; + } + + case 0x10: { /* S */ + DIP("seleqz.s f%u, f%u, f%u", fd, fs, ft); + t1 = newTemp(Ity_I1); + assign(t1, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_ReinterpF32asI32, + getLoFromF64(tyF, getFReg(ft))), + mkU32(1)), + mkU32(0))); + putFReg(fd, IRExpr_ITE(mkexpr(t1), + mkWidenFromF32(tyF, + binop(Iop_I32StoF32, + get_IR_roundingmode(), + mkU32(0))), + getFReg(fs))); + break; + } + + default: + goto decode_failure; + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + + case 0x17: /* SELNEZ.fmt */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + switch (fmt) { + case 0x11: { /* D */ + DIP("selnez.d f%u, f%u, f%u", fd, fs, ft); + t1 = newTemp(Ity_I1); + if (mode64) { + assign(t1, binop(Iop_CmpNE64, + binop(Iop_And64, + unop(Iop_ReinterpF64asI64, + getDReg(ft)), + mkU64(1)), + mkU64(0))); + } else { + assign(t1, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + unop(Iop_ReinterpF64asI64, + getDReg(ft))), + mkU32(1)), + mkU32(0))); + } + putDReg(fd, IRExpr_ITE( mkexpr(t1), + getDReg(fs), + binop(Iop_I64StoF64, + get_IR_roundingmode(), + mkU64(0)))); + break; + } + + case 0x10: { /* S */ + DIP("selnez.s f%u, f%u, f%u", fd, fs, ft); + t1 = newTemp(Ity_I1); + assign(t1,binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_ReinterpF32asI32, + getLoFromF64(tyF, getFReg(ft))), + mkU32(1)), + mkU32(0))); + putFReg(fd, IRExpr_ITE(mkexpr(t1), + getFReg(fs), + mkWidenFromF32(tyF, + binop(Iop_I32StoF32, + get_IR_roundingmode(), + mkU32(0))))); + break; + } + + default: + goto decode_failure; + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + + case 0x1B: /* CLASS.fmt */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + t0 = newTemp(Ity_I1); // exp zero + t1 = newTemp(Ity_I1); // exp max + t2 = newTemp(Ity_I1); // sign + t3 = newTemp(Ity_I1); // first + t4 = newTemp(Ity_I1); // val not zero + t5 = newTemp(Ity_I32); + switch (fmt) { + case 0x11: { /* D */ + DIP("class.d f%u, f%u", fd, fs); + assign(t0, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + unop(Iop_ReinterpF64asI64, + getDReg(fs))), + mkU32(0x7ff00000)), + mkU32(0))); + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + unop(Iop_ReinterpF64asI64, + getDReg(fs))), + mkU32(0x7ff00000)), + mkU32(0x7ff00000))); + assign(t2, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + unop(Iop_ReinterpF64asI64, + getDReg(fs))), + mkU32(0x80000000)), + mkU32(0x80000000))); + assign(t3, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + unop(Iop_ReinterpF64asI64, + getDReg(fs))), + mkU32(0x00080000)), + mkU32(0x00080000))); + if (mode64) assign(t4, binop(Iop_CmpNE64, + binop(Iop_And64, + unop(Iop_ReinterpF64asI64, + getDReg(fs)), + mkU64(0x000fffffffffffffULL)), + mkU64(0))); + else assign(t4, binop(Iop_CmpNE32, + binop(Iop_Or32, + binop(Iop_And32, + unop(Iop_64HIto32, + unop(Iop_ReinterpF64asI64, + getDReg(fs))), + mkU32(0x000fffff)), + unop(Iop_64to32, + unop(Iop_ReinterpF64asI64, + getDReg(fs)))), + mkU32(0))); + assign(t5, binop(Iop_Shl32, + IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t4), + mkU32(0), mkU32(1)), + IRExpr_ITE(mkexpr(t0), + IRExpr_ITE(mkexpr(t4), + mkU32(0x4), + mkU32(0x8)), + mkU32(2))), + IRExpr_ITE(mkexpr(t2), mkU8(2), mkU8(6)))); + putDReg(fd, unop(Iop_ReinterpI64asF64, + unop(Iop_32Uto64, + IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t5), mkU32(0)), + mkexpr(t5), + IRExpr_ITE(mkexpr(t3), + mkU32(2), + mkU32(1)))))); + break; + } + case 0x10: { /* S */ + DIP("class.s f%u, f%u", fd, fs); + assign(t0, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_ReinterpF32asI32, + getLoFromF64(tyF, getFReg(fs))), + mkU32(0x7f800000)), + mkU32(0))); + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_ReinterpF32asI32, + getLoFromF64(tyF, getFReg(fs))), + mkU32(0x7f800000)), + mkU32(0x7f800000))); + assign(t2, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_ReinterpF32asI32, + getLoFromF64(tyF, getFReg(fs))), + mkU32(0x80000000)), + mkU32(0x80000000))); + assign(t3, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_ReinterpF32asI32, + getLoFromF64(tyF, getFReg(fs))), + mkU32(0x00400000)), + mkU32(0x00400000))); + assign(t4, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_ReinterpF32asI32, + getLoFromF64(tyF, getFReg(fs))), + mkU32(0x007fffff)), + mkU32(0))); + assign(t5, binop(Iop_Shl32, + IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t4), + mkU32(0), mkU32(1)), + IRExpr_ITE(mkexpr(t0), + IRExpr_ITE(mkexpr(t4), + mkU32(0x4), + mkU32(0x8)), //zero or subnorm + mkU32(2))), + IRExpr_ITE(mkexpr(t2), mkU8(2), mkU8(6)))); + putDReg(fd, unop(Iop_ReinterpI64asF64, + unop(Iop_32Uto64, + IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t5), mkU32(0)), + mkexpr(t5), + IRExpr_ITE(mkexpr(t3), + mkU32(2), + mkU32(1)))))); + break; + } + default: + goto decode_failure; + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + default: if (dis_instr_CCondFmt(cins)) break; @@ -27375,12 +28423,28 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, break; case 0x0F: /* LUI */ - p = (imm << 16); - DIP("lui r%u, imm: 0x%x", rt, imm); - if (mode64) - putIReg(rt, mkU64(extend_s_32to64(p))); - else - putIReg(rt, mkU32(p)); + if (rs == 0) { + p = (imm << 16); + DIP("lui r%u, imm: 0x%x", rt, imm); + if (mode64) + putIReg(rt, mkU64(extend_s_32to64(p))); + else + putIReg(rt, mkU32(p)); + break; + } else if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { /* AUI */ + DIP("aui r%u, imm: 0x%x", rt, imm); + if (mode64) { + putIReg(rt, unop(Iop_32Sto64, + unop(Iop_64to32, + binop(Iop_Add64, + getIReg(rs), + mkU64(extend_s_32to64(imm << 16)))))); + } else { + putIReg(rt, binop(Iop_Add32, getIReg(rs), mkU32(imm << 16))); + } + } else { + ILLEGAL_INSTRUCTON; + } break; case 0x13: /* COP1X */ @@ -28893,6 +29957,31 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, putIReg(rd, mkexpr(tmpRd)); break; } + case 0x08 ... 0x0f: { /* DALIGN */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("daling r%u, r%u, r%u, %d", rd, rs, rt, lsb & 0x7); + UInt bp = (lsb & 0x7) << 3; + if (bp) { + putIReg(rd, binop(Iop_Or64, + binop(Iop_Shl64, getIReg(rt), mkU8(bp)), + binop(Iop_Shr64, + getIReg(rs), mkU8(64 - bp)))); + } else + putIReg(rd, getIReg(rt)); + } else { + ILLEGAL_INSTRUCTON; + } + break; + } + + case 0: /* DBITSWAP */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("dbitswap r%u, r%u", rd, rt); + putIReg(rd, qop(Iop_Rotx64, getIReg(rt), mkU8(7), mkU8(8), mkU8(1))); + } else { + ILLEGAL_INSTRUCTON; + } + break; default: vex_printf("\nop6o10 = %u", lsb); goto decode_failure;; @@ -28901,6 +29990,7 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, case 0x3B: /* RDHWR */ DIP("rdhwr r%u, r%u", rt, rd); if (VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps) || + VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) || (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_BROADCOM)) { if (rd == 29) { putIReg(rt, getULR()); @@ -29018,6 +30108,21 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, case 0x20: /* BSHFL */ switch (sa) { + case 0x0: /* BITSWAP */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("bitswap r%u, r%u", rd, rt); + if (mode64) { + putIReg(rd, unop(Iop_32Uto64, qop(Iop_Rotx32, unop(Iop_64to32, getIReg(rt)), + mkU8(7), mkU8(8), mkU8(1)))); + } else { + putIReg(rd, qop(Iop_Rotx32, getIReg(rt), mkU8(7), + mkU8(8), mkU8(1))); + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + case 0x02: /* WSBH */ DIP("wsbh r%u, r%u", rd, rt); t0 = newTemp(Ity_I32); @@ -29055,6 +30160,39 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, putIReg(rd, unop(Iop_16Sto32, unop(Iop_32to16, getIReg(rt)))); break; + case 0x08 ... 0x0b: /* ALIGN */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + if (mode64) { + UInt bp = (sa & 0x3) << 3; + if (bp) { + putIReg(rd, unop(Iop_32Sto64, + binop(Iop_Or32, + binop(Iop_Shl32, + unop(Iop_64to32, + getIReg(rt)), + mkU8(bp)), + binop(Iop_Shr32, + unop(Iop_64to32, + getIReg(rs)), + mkU8(32 - bp))))); + } else + putIReg(rd, getIReg(rt)); + } else { + UInt bp = (sa & 0x3) << 3; + if (bp) { + putIReg(rd, binop(Iop_Or32, + binop(Iop_Shl32, + getIReg(rt), mkU8(bp)), + binop(Iop_Shr32, + getIReg(rs), mkU8(32 - bp)))); + } else + putIReg(rd, getIReg(rt)); + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + default: goto decode_failure; @@ -29258,20 +30396,195 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, goto decode_failure_dsp; } } - default: - goto decode_failure; + case 0x35: { /* PREF r6*/ + DIP("pref"); + break; + } + case 0x36: { /* LL */ + imm = extend_s_9to16((instr_index >> 7) & 0x1ff); + DIP("ll r%u, %u(r%u)", rt, imm, rs); + LOAD_STORE_PATTERN; + t2 = newTemp(ty); + assign(t2, mkWidenFrom32(ty, load(Ity_I32, mkexpr(t1)), True)); + putLLaddr(mkexpr(t1)); + putLLdata(mkexpr(t2)); + putIReg(rt, mkexpr(t2)); + break; + } + case 0x26: { /* SC */ + imm = extend_s_9to16((instr_index >> 7) & 0x1ff); + DIP("sc r%u, %u(r%u)", rt, imm, rs); + LOAD_STORE_PATTERN; - } - break; /* Special3 */ + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I32); + assign(t2, binop(mode64 ? Iop_CmpNE64 : Iop_CmpNE32, + mkexpr(t1), getLLaddr())); + assign(t3, mkNarrowTo32(ty, getIReg(rt))); + putLLaddr(LLADDR_INVALID); + putIReg(rt, getIReg(0)); - case 0x3B: - if (0x3B == function && - (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_BROADCOM)) { - /*RDHWR*/ - DIP("rdhwr r%u, r%u", rt, rd); - if (rd == 29) { - putIReg(rt, getULR()); - } else + mips_next_insn_if(mkexpr(t2)); + + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + + assign(t5, mkNarrowTo32(ty, getLLdata())); + + stmt(IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t4, /* old_mem */ + MIPS_IEND, mkexpr(t1), /* addr */ + NULL, mkexpr(t5), /* expected value */ + NULL, mkexpr(t3) /* new value */))); + + putIReg(rt, unop(mode64 ? Iop_1Uto64 : Iop_1Uto32, + binop(Iop_CmpEQ32, mkexpr(t4), mkexpr(t5)))); + break; + } + case 0x37: { /* LLD */ + imm = extend_s_9to16((instr_index >> 7) & 0x1ff); + DIP("lld r%u, %u(r%u)", rt, imm, rs); + LOAD_STORE_PATTERN; + + t2 = newTemp(Ity_I64); + assign(t2, load(Ity_I64, mkexpr(t1))); + putLLaddr(mkexpr(t1)); + putLLdata(mkexpr(t2)); + putIReg(rt, mkexpr(t2)); + break; + } + case 0x27: { /* SCD */ + imm = extend_s_9to16((instr_index >> 7) & 0x1ff); + DIP("sdc r%u, %u(r%u)", rt, imm, rs); + LOAD_STORE_PATTERN; + + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I64); + assign(t2, binop(Iop_CmpNE64, mkexpr(t1), getLLaddr())); + assign(t3, getIReg(rt)); + putLLaddr(LLADDR_INVALID); + putIReg(rt, getIReg(0)); + + mips_next_insn_if(mkexpr(t2)); + + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + + assign(t5, getLLdata()); + + stmt(IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t4, /* old_mem */ + MIPS_IEND, mkexpr(t1), /* addr */ + NULL, mkexpr(t5), /* expected value */ + NULL, mkexpr(t3) /* new value */))); + + putIReg(rt, unop(Iop_1Uto64, + binop(Iop_CmpEQ64, mkexpr(t4), mkexpr(t5)))); + break; + } + default: + goto decode_failure; + + } + break; /* Special3 */ + + case 0x3B: /* PCREL */ + if (rt == 0x1E) { /* AUIPC */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("auipc r%u, %u", rs, imm); + if (mode64) { + putIReg(rs, mkU64(guest_PC_curr_instr + (imm << 16))); + } else { + putIReg(rs, mkU32(guest_PC_curr_instr + (imm << 16))); + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + } else if (rt == 0x1F) { /* ALUIPC */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("aluipc r%u, %u", rs, imm); + if (mode64) { + putIReg(rs, mkU64((~0x0FFFFULL) & + (guest_PC_curr_instr + extend_s_32to64(imm << 16)))); + } else { + putIReg(rs, mkU32((~0x0FFFFULL) & + (guest_PC_curr_instr + (imm << 16)))); + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + } else if ((rt & 0x18) == 0) { /* ADDIUPC */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("addiupc r%u, %u", rs, instr_index & 0x7FFFF); + if (mode64) { + putIReg(rs, mkU64(guest_PC_curr_instr + + (extend_s_19to64(instr_index & 0x7FFFF) << 2))); + } else { + putIReg(rs, mkU32(guest_PC_curr_instr + + (extend_s_19to32(instr_index & 0x7FFFF) << 2))); + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + } else if ((rt & 0x18) == 8) { /* LWPC */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("lwpc r%u, %x", rs, instr_index & 0x7FFFF); + if (mode64) { + t1 = newTemp(Ity_I64); + assign(t1, mkU64(guest_PC_curr_instr + + (extend_s_19to64(instr_index & 0x7FFFF) << 2))); + putIReg(rs, unop(Iop_32Sto64, load(Ity_I32, mkexpr(t1)))); + } else { + t1 = newTemp(Ity_I32); + assign(t1, mkU32(guest_PC_curr_instr + + (extend_s_19to32(instr_index & 0x7FFFF) << 2))); + putIReg(rs, load(Ity_I32, mkexpr(t1))); + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + } else if ((rt & 0x18) == 16) { /* LWUPC */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("lwupc r%u, %x", rs, instr_index & 0x7FFFF); + if (mode64) { + t1 = newTemp(Ity_I64); + assign(t1, mkU64(guest_PC_curr_instr + + (extend_s_19to64(instr_index & 0x7FFFF) << 2))); + putIReg(rs, unop(Iop_32Uto64, load(Ity_I32, mkexpr(t1)))); + } else { + t1 = newTemp(Ity_I32); + assign(t1, mkU32(guest_PC_curr_instr + + (extend_s_19to32(instr_index & 0x7FFFF) << 2))); + putIReg(rs, load(Ity_I32, mkexpr(t1))); + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + } else if ((rt & 0x1C) == 0x18) { /* LDPC */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("ldpc r%u, %x", rs, instr_index & 0x3FFFF); + t1 = newTemp(Ity_I64); + assign(t1, mkU64(guest_PC_curr_instr + + (extend_s_18to64(instr_index & 0x3FFFF) << 3))); + putIReg(rs, load(Ity_I64, mkexpr(t1))); + } else { + ILLEGAL_INSTRUCTON; + } + break; + } else { + goto decode_failure; + } + + if (0x3B == function && + (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_BROADCOM)) { + /*RDHWR*/ + DIP("rdhwr r%u, r%u", rt, rd); + if (rd == 29) { + putIReg(rt, getULR()); + } else goto decode_failure; break; } else { @@ -29372,53 +30685,150 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, } case 0x18: { /* MULT */ - if ( (1 <= ac) && ( 3 >= ac) ) { - if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { - /* If DSP is present -> DSP ASE MULT */ - UInt retVal = disDSPInstr_MIPS_WRK ( cins ); - if (0 != retVal ) { - goto decode_failure_dsp; + switch (sa & 0x3) { + case 0: { + if ((1 <= ac) && ( 3 >= ac)) { + if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { + /* If DSP is present -> DSP ASE MULT */ + UInt retVal = disDSPInstr_MIPS_WRK(cins); + if (0 != retVal) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + } else { + DIP("mult r%u, r%u", rs, rt); + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON; + } + t2 = newTemp(Ity_I64); + + assign(t2, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)), + mkNarrowTo32(ty, getIReg(rt)))); + + putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True)); + putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True)); + break; + } + } + case 2: { /* MUL R6 */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("mul r%u, r%u, r%u", rs, rt, rd); + if (mode64) { + putIReg(rd, unop(Iop_32Sto64, + unop(Iop_64to32, + binop(Iop_MullS32, + unop(Iop_64to32, getIReg(rs)), + unop(Iop_64to32, getIReg(rt)))))); + } else { + putIReg(rd, unop(Iop_64to32, + binop(Iop_MullS32, + getIReg(rs), getIReg(rt)))); + } + } else { + ILLEGAL_INSTRUCTON; } break; - } else { - goto decode_failure_dsp; } - } else { - DIP("mult r%u, r%u", rs, rt); - t2 = newTemp(Ity_I64); - assign(t2, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)), - mkNarrowTo32(ty, getIReg(rt)))); - - putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True)); - putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True)); - break; + case 3: { /* MUH R6 */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("muh r%u, r%u, r%u", rs, rt, rd); + if (mode64) { + putIReg(rd, unop(Iop_32Sto64, + unop(Iop_64HIto32, + binop(Iop_MullS32, + unop(Iop_64to32, getIReg(rs)), + unop(Iop_64to32, getIReg(rt)))))); + } else { + putIReg(rd, unop(Iop_64HIto32, + binop(Iop_MullS32, + getIReg(rs), getIReg(rt)))); + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + } } + break; } + case 0x19: { /* MULTU */ - if ( (1 <= ac) && ( 3 >= ac) ) { - if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { - /* If DSP is present -> DSP ASE MULTU */ - UInt retVal = disDSPInstr_MIPS_WRK ( cins ); - if (0 != retVal ) { - goto decode_failure_dsp; + switch (sa & 0x3) { + case 0: { + if ((1 <= ac) && ( 3 >= ac)) { + if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { + /* If DSP is present -> DSP ASE MULTU */ + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + } else { + DIP("multu r%u, r%u", rs, rt); + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON; + } + t2 = newTemp(Ity_I64); + + assign(t2, binop(Iop_MullU32, mkNarrowTo32(ty, getIReg(rs)), + mkNarrowTo32(ty, getIReg(rt)))); + + putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True)); + putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True)); + break; + } + } + case 2: { /* MULU R6 */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("mulu r%u, r%u, r%u", rs, rt, rd); + if (mode64) { + putIReg(rd, unop(Iop_32Uto64, + unop(Iop_64to32, + binop(Iop_MullU32, + unop(Iop_64to32, getIReg(rs)), + unop(Iop_64to32, getIReg(rt)))))); + } else { + putIReg(rd, unop(Iop_64to32, + binop(Iop_MullU32, + getIReg(rs), getIReg(rt)))); + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + } + case 3: { /* MUHU R6 */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("muhu r%u, r%u, r%u", rs, rt, rd); + if (mode64) { + putIReg(rd, unop(Iop_32Uto64, + unop(Iop_64HIto32, + binop(Iop_MullU32, + unop(Iop_64to32, getIReg(rs)), + unop(Iop_64to32, getIReg(rt)))))); + } else { + putIReg(rd, unop(Iop_64HIto32, + binop(Iop_MullU32, + getIReg(rs), getIReg(rt)))); + } + } else { + ILLEGAL_INSTRUCTON; } break; - } else { - goto decode_failure_dsp; } - } else { - DIP("multu r%u, r%u", rs, rt); - t2 = newTemp(Ity_I64); - - assign(t2, binop(Iop_MullU32, mkNarrowTo32(ty, getIReg(rs)), - mkNarrowTo32(ty, getIReg(rt)))); - - putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True)); - putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True)); - break; } } + break; + case 0x20: { /* ADD */ DIP("add r%u, r%u, r%u", rd, rs, rt); IRTemp tmpRs32 = newTemp(Ity_I32); @@ -29463,89 +30873,302 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, putIReg(rd, mkWidenFrom32(ty, mkexpr(t0), True)); break; } + case 0x1A: /* DIV */ - DIP("div r%u, r%u", rs, rt); - if (mode64) { - t2 = newTemp(Ity_I64); + switch (sa & 0x3) { + case 0: + DIP("div r%u, r%u", rs, rt); + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON; + } + if (mode64) { + t2 = newTemp(Ity_I64); - assign(t2, binop(Iop_DivModS32to32, - mkNarrowTo32(ty, getIReg(rs)), - mkNarrowTo32(ty, getIReg(rt)))); + assign(t2, binop(Iop_DivModS32to32, + mkNarrowTo32(ty, getIReg(rs)), + mkNarrowTo32(ty, getIReg(rt)))); - putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True)); - putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True)); - } else { - t1 = newTemp(Ity_I64); + putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True)); + putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True)); + } else { + t1 = newTemp(Ity_I64); - assign(t1, binop(Iop_DivModS32to32, getIReg(rs), getIReg(rt))); + assign(t1, binop(Iop_DivModS32to32, getIReg(rs), getIReg(rt))); - putHI(unop(Iop_64HIto32, mkexpr(t1))); - putLO(unop(Iop_64to32, mkexpr(t1))); + putHI(unop(Iop_64HIto32, mkexpr(t1))); + putLO(unop(Iop_64to32, mkexpr(t1))); + } + break; + case 2: + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("div r%u, r%u, r%u", rs, rt, rd); + if (mode64) { + putIReg(rd, unop(Iop_32Sto64, + binop(Iop_DivS32, + unop(Iop_64to32, getIReg(rs)), + unop(Iop_64to32, getIReg(rt))))); + } else + putIReg(rd, binop(Iop_DivS32, getIReg(rs), getIReg(rt))); + } else { + ILLEGAL_INSTRUCTON; + } + break; + case 3: + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("mod r%u, r%u, r%u", rs, rt, rd); + if (mode64) { + putIReg(rd, unop(Iop_32Sto64, + unop(Iop_64HIto32, + binop(Iop_DivModS32to32, + unop(Iop_64to32, getIReg(rs)), + unop(Iop_64to32, getIReg(rt)))))); + } else { + t1 = newTemp(Ity_I64); + + assign(t1, binop(Iop_DivModS32to32, getIReg(rs), getIReg(rt))); + putIReg(rd, unop(Iop_64HIto32, mkexpr(t1))); + } + } else { + ILLEGAL_INSTRUCTON; + } + break; } break; case 0x1B: /* DIVU */ - DIP("divu r%u, r%u", rs, rt); - if (mode64) { - t2 = newTemp(Ity_I64); + switch (sa & 0x3) { + case 0: + DIP("divu r%u, r%u", rs, rt); + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON; + } + if (mode64) { + t1 = newTemp(Ity_I64); - assign(t2, binop(Iop_DivModU32to32, - mkNarrowTo32(ty, getIReg(rs)), - mkNarrowTo32(ty, getIReg(rt)))); + assign(t1, binop(Iop_DivModU32to32, + mkNarrowTo32(ty, getIReg(rs)), + mkNarrowTo32(ty, getIReg(rt)))); - putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True)); - putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True)); - } else { - t1 = newTemp(Ity_I64); + putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t1)), True)); + putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t1)), True)); + } else { + t1 = newTemp(Ity_I64); - assign(t1, binop(Iop_DivModU32to32, getIReg(rs), getIReg(rt))); - putHI(unop(Iop_64HIto32, mkexpr(t1))); - putLO(unop(Iop_64to32, mkexpr(t1))); - } - break; + assign(t1, binop(Iop_DivModU32to32, getIReg(rs), getIReg(rt))); + putHI(unop(Iop_64HIto32, mkexpr(t1))); + putLO(unop(Iop_64to32, mkexpr(t1))); + } + break; + case 2: + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("divu r%u, r%u, r%u", rs, rt, rd); + if (mode64) { + putIReg(rd, unop(Iop_32Sto64, + binop(Iop_DivU32, + unop(Iop_64to32, getIReg(rs)), + unop(Iop_64to32, getIReg(rt))))); + } else { + putIReg(rd, binop(Iop_DivU32, getIReg(rs), getIReg(rt))); + } + break; + } else { + ILLEGAL_INSTRUCTON; + } + break; + case 3: + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("modu r%u, r%u, r%u", rs, rt, rd); + if (mode64) { + putIReg(rd, unop(Iop_32Uto64, + unop(Iop_64HIto32, + binop(Iop_DivModU32to32, + unop(Iop_64to32, getIReg(rs)), + unop(Iop_64to32, getIReg(rt)))))); + } else { + t1 = newTemp(Ity_I64); + + assign(t1, binop(Iop_DivModU32to32, getIReg(rs), getIReg(rt))); + putIReg(rd, unop(Iop_64HIto32, mkexpr(t1))); + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + } + break; case 0x1C: /* Doubleword Multiply - DMULT; MIPS64 */ - DIP("dmult r%u, r%u", rs, rt); - t0 = newTemp(Ity_I128); + switch (sa) { + case 0: + DIP("dmult r%u, r%u", rs, rt); + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON; + } + t0 = newTemp(Ity_I128); - assign(t0, binop(Iop_MullS64, getIReg(rs), getIReg(rt))); + assign(t0, binop(Iop_MullS64, getIReg(rs), getIReg(rt))); - putHI(unop(Iop_128HIto64, mkexpr(t0))); - putLO(unop(Iop_128to64, mkexpr(t0))); + putHI(unop(Iop_128HIto64, mkexpr(t0))); + putLO(unop(Iop_128to64, mkexpr(t0))); + break; + case 2: /* DMUL */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("dmul r%u, r%u, r%u", rd, rs, rt); + putIReg(rd, unop(Iop_128to64, + binop(Iop_MullS64, getIReg(rs), getIReg(rt)))); + } else { + ILLEGAL_INSTRUCTON; + } + /* Value for function in documentation is 111000 */ + break; + case 3: /* DMUH */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("dmuh r%u, r%u, r%u", rd, rs, rt); + putIReg(rd, unop(Iop_128HIto64, + binop(Iop_MullS64, getIReg(rs), getIReg(rt)))); + } else { + ILLEGAL_INSTRUCTON; + } + break; + } break; case 0x1D: /* Doubleword Multiply Unsigned - DMULTU; MIPS64 */ - DIP("dmultu r%u, r%u", rs, rt); - t0 = newTemp(Ity_I128); + switch (sa) { + case 0: + DIP("dmultu r%u, r%u", rs, rt); + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON; + } + t0 = newTemp(Ity_I128); - assign(t0, binop(Iop_MullU64, getIReg(rs), getIReg(rt))); + assign(t0, binop(Iop_MullU64, getIReg(rs), getIReg(rt))); - putHI(unop(Iop_128HIto64, mkexpr(t0))); - putLO(unop(Iop_128to64, mkexpr(t0))); + putHI(unop(Iop_128HIto64, mkexpr(t0))); + putLO(unop(Iop_128to64, mkexpr(t0))); + break; + case 2: /* DMULU */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("dmulu r%u, r%u, r%u", rd, rs, rt); + putIReg(rd, unop(Iop_128to64, + binop(Iop_MullU64, getIReg(rs), getIReg(rt)))); + } else { + ILLEGAL_INSTRUCTON; + } + break; + case 3: /* DMUHU */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("dmuhu r%u, r%u, r%u", rd, rs, rt); + putIReg(rd, unop(Iop_128HIto64, + binop(Iop_MullU64, getIReg(rs), getIReg(rt)))); + } else { + ILLEGAL_INSTRUCTON; + } + break; + } break; case 0x1E: /* Doubleword Divide DDIV; MIPS64 */ - DIP("ddiv r%u, r%u", rs, rt); - t1 = newTemp(Ity_I128); + switch (sa) { + case 0: + DIP("ddiv r%u, r%u", rs, rt); + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON; + } + t1 = newTemp(Ity_I128); - assign(t1, binop(Iop_DivModS64to64, getIReg(rs), getIReg(rt))); + assign(t1, binop(Iop_DivModS64to64, getIReg(rs), getIReg(rt))); - putHI(unop(Iop_128HIto64, mkexpr(t1))); - putLO(unop(Iop_128to64, mkexpr(t1))); + putHI(unop(Iop_128HIto64, mkexpr(t1))); + putLO(unop(Iop_128to64, mkexpr(t1))); + break; + case 2: /* DDIV r6 */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("ddiv r%u, r%u, r%u", rs, rt, rd); + putIReg(rd, unop(Iop_128to64, + binop(Iop_DivModS64to64, + getIReg(rs), getIReg(rt)))); + } else { + ILLEGAL_INSTRUCTON; + } + break; + case 3: /* DMOD r6 */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("dmod r%u, r%u, r%u", rs, rt, rd); + t2 = newTemp(Ity_I128); + assign(t2, binop(Iop_DivModS64to64, getIReg(rs), getIReg(rt))); + putIReg(rd, unop(Iop_128HIto64, mkexpr(t2))); + } else { + ILLEGAL_INSTRUCTON; + } + break; + } break; case 0x1F: /* Doubleword Divide Unsigned DDIVU; MIPS64 check this */ - DIP("ddivu r%u, r%u", rs, rt); - t1 = newTemp(Ity_I128); + switch (sa) { + case 0: + DIP("ddivu r%u, r%u", rs, rt); + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON; + } + t1 = newTemp(Ity_I128); - assign(t1, binop(Iop_DivModU64to64, getIReg(rs), getIReg(rt))); + assign(t1, binop(Iop_DivModU64to64, getIReg(rs), getIReg(rt))); - putHI(unop(Iop_128HIto64, mkexpr(t1))); - putLO(unop(Iop_128to64, mkexpr(t1))); + putHI(unop(Iop_128HIto64, mkexpr(t1))); + putLO(unop(Iop_128to64, mkexpr(t1))); + break; + case 2: + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("ddivu r%u, r%u, r%u", rs, rt, rd); + putIReg(rd, unop(Iop_128to64, binop(Iop_DivModU64to64, + getIReg(rs), getIReg(rt)))); + } else { + ILLEGAL_INSTRUCTON; + } + break; + case 3: + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("dmodu r%u, r%u, r%u", rs, rt, rd); + putIReg(rd, unop(Iop_128HIto64, binop(Iop_DivModU64to64, + getIReg(rs), getIReg(rt)))); + } else { + ILLEGAL_INSTRUCTON; + } + break; + } break; - case 0x10: { /* MFHI */ - if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { + case 0x10: { /* MFHI, CLZ R6 */ + if (((instr_index >> 6) & 0x1f) == 1) { /* CLZ */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("clz r%u, r%u", rd, rs); + if (mode64) { + IRTemp tmpClz32 = newTemp(Ity_I32); + IRTemp tmpRs32 = newTemp(Ity_I32); + + assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs))); + assign(tmpClz32, unop(Iop_Clz32, mkexpr(tmpRs32))); + putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpClz32), True)); + } else { + t1 = newTemp(Ity_I1); + assign(t1, binop(Iop_CmpEQ32, getIReg(rs), mkU32(0))); + putIReg(rd, IRExpr_ITE(mkexpr(t1), + mkU32(0x00000020), + unop(Iop_Clz32, getIReg(rs)))); + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + } else if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { /* If DSP is present -> DSP ASE MFHI */ UInt retVal = disDSPInstr_MIPS_WRK ( cins ); if (0 != retVal ) { @@ -29559,8 +31182,36 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, } } - case 0x11: { /* MTHI */ - if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { + case 0x11: { /* MTHI, CLO R6 */ + if (((instr_index >> 6) & 0x1f) == 1) { /* CLO */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("clo r%u, r%u", rd, rs); + if (mode64) { + IRTemp tmpClo32 = newTemp(Ity_I32); + IRTemp tmpRs32 = newTemp(Ity_I32); + assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs))); + + t1 = newTemp(Ity_I1); + assign(t1, binop(Iop_CmpEQ32, mkexpr(tmpRs32), mkU32(0xffffffff))); + assign(tmpClo32, IRExpr_ITE(mkexpr(t1), + mkU32(0x00000020), + unop(Iop_Clz32, unop(Iop_Not32, mkexpr(tmpRs32))))); + + putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpClo32), True)); + break; + } else { + t1 = newTemp(Ity_I1); + assign(t1, binop(Iop_CmpEQ32, getIReg(rs), mkU32(0xffffffff))); + putIReg(rd, IRExpr_ITE(mkexpr(t1), + mkU32(0x00000020), + unop(Iop_Clz32, + unop(Iop_Not32, getIReg(rs))))); + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + } else if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { /* If DSP is present -> DSP ASE MTHI */ UInt retVal = disDSPInstr_MIPS_WRK ( cins ); if (0 != retVal ) { @@ -29583,8 +31234,24 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, } break; } else { - DIP("mflo r%u", rd); - putIReg(rd, getLO()); + switch (sa) { + case 0: + DIP("mflo r%u", rd); + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON; + } + putIReg(rd, getLO()); + break; + case 1: + DIP("dclz r%u, r%u", rd, rs); + t1 = newTemp(Ity_I1); + assign(t1, binop(Iop_CmpEQ64, getIReg(rs), mkU64(0))); + putIReg(rd, IRExpr_ITE(mkexpr(t1), + mkU64(0x00000040), + unop(Iop_Clz64, getIReg(rs)))); + break; + } break; } } @@ -29598,8 +31265,26 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, } break; } else { - DIP("mtlo r%u", rs); - putLO(getIReg(rs)); + switch (sa) { + case 0: + DIP("mtlo r%u", rs); + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON; + } + putLO(getIReg(rs)); + break; + case 1: + DIP("dclo r%u, r%u", rd, rs); + t1 = newTemp(Ity_I1); + assign(t1, binop(Iop_CmpEQ64, getIReg(rs), + mkU64(0xffffffffffffffffULL))); + putIReg(rd, IRExpr_ITE(mkexpr(t1), + mkU64(0x40), + unop(Iop_Clz64, unop(Iop_Not64, + getIReg(rs))))); + break; + } break; } } @@ -29875,36 +31560,41 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, break; } } - - case 0x05: /* LSA */ - if (has_msa) { - UInt imm2 = (imm & 0xC0) >> 6; + case 0x05: { /* LSA */ + UInt imm2 = (imm & 0xC0) >> 6; + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) || has_msa) { DIP("lsa r%u, r%u, r%u, imm: 0x%x", rd, rs, rt, imm2); if (mode64) { - putIReg(rd, - unop(Iop_32Sto64, - binop(Iop_Add32, - binop(Iop_Shl32, - unop(Iop_64to32, getIReg(rs)), - mkU8(imm2 + 1)), - unop(Iop_64to32, getIReg(rt))))); + DIP("lsa r%u, r%u, r%u, imm: 0x%x", rd, rs, rt, imm2); + putIReg(rd, unop(Iop_32Sto64, + binop(Iop_Add32, + binop(Iop_Shl32, + unop(Iop_64to32, getIReg(rs)), + mkU8(imm2 + 1)), + unop(Iop_64to32, getIReg(rt))))); + break; } else { - putIReg(rd, - binop(Iop_Add32, - binop(Iop_Shl32, getIReg(rs), mkU8(imm2 + 1)), - getIReg(rt))); + DIP("lsa r%u, r%u, r%u, imm: 0x%x", rd, rs, rt, imm2); + putIReg(rd, binop(Iop_Add32, + binop(Iop_Shl32, + getIReg(rs), mkU8(imm2 + 1)), getIReg(rt))); + break; } } else { ILLEGAL_INSTRUCTON; } - break; + + } case 0x15:{ /* DLSA */ UInt imm2 = (imm & 0xC0) >> 6; - DIP("dlsa r%u, r%u, r%u, imm: 0x%x", rd, rs, rt, imm2); - putIReg(rd, - binop(Iop_Add64, - binop(Iop_Shl64, getIReg(rs), mkU8(imm2 + 1)), - getIReg(rt))); + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) || has_msa) { + DIP("dlsa r%u, r%u, r%u, imm: 0x%x", rd, rs, rt, imm2); + putIReg(rd, binop(Iop_Add64, + binop(Iop_Shl64, getIReg(rs), mkU8(imm2 + 1)), + getIReg(rt))); + } else { + ILLEGAL_INSTRUCTON; + } break; } @@ -30138,6 +31828,26 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, } break; } + case 0x35: { /* SELEQZ */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("seleqz r%u, r%u, r%u", rd, rs, rt); + if (mode64) { + putIReg(rd, binop(Iop_And64, + unop(Iop_Not64, + unop(Iop_CmpwNEZ64, getIReg(rt))), + getIReg(rs))); + } else { + putIReg(rd, binop(Iop_And32, + unop(Iop_Not32, + unop(Iop_CmpwNEZ32, getIReg(rt))), + getIReg(rs))); + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + } + case 0x36: { /* TNE */ DIP("tne r%u, r%u %u", rs, rt, trap_code); if (mode64) { @@ -30175,6 +31885,21 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, } break; } + case 0x37: { /* SELNEZ */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("selnez r%u, r%u, r%u", rd, rs, rt); + if (mode64) { + putIReg(rd, binop(Iop_And64, + unop(Iop_CmpwNEZ64, getIReg(rt)), getIReg(rs))); + } else { + putIReg(rd, binop(Iop_And32, + unop(Iop_CmpwNEZ32, getIReg(rt)), getIReg(rs))); + } + } else { + ILLEGAL_INSTRUCTON; + } + break; + } case 0x14: case 0x16: case 0x17: /* DSLLV, DROTRV:DSRLV, DSRAV */ @@ -30399,18 +32124,18 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, case 0x08: /* TGEI */ DIP("tgei r%u, %u %u", rs, imm, trap_code); if (mode64) { - stmt (IRStmt_Exit (unop (Iop_Not1, - binop (Iop_CmpLT64S, - getIReg (rs), - mkU64 (extend_s_16to64 (imm)))), + stmt (IRStmt_Exit(unop(Iop_Not1, + binop(Iop_CmpLT64S, + getIReg(rs), + mkU64(extend_s_16to64 (imm)))), Ijk_SigTRAP, IRConst_U64(guest_PC_curr_instr + 4), OFFB_PC)); } else { - stmt (IRStmt_Exit (unop (Iop_Not1, - binop (Iop_CmpLT32S, - getIReg (rs), - mkU32 (extend_s_16to32 (imm)))), + stmt (IRStmt_Exit(unop(Iop_Not1, + binop(Iop_CmpLT32S, + getIReg(rs), + mkU32(extend_s_16to32 (imm)))), Ijk_SigTRAP, IRConst_U32(guest_PC_curr_instr + 4), OFFB_PC)); @@ -30520,6 +32245,28 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, /* Just ignore it */ break; + case 0x06: { /* DAHI */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("dahi r%u, %x", rs, imm); + putIReg(rs, binop(Iop_Add64, + getIReg(rs), mkU64(extend_s_16to64 (imm) << 32))); + } else { + ILLEGAL_INSTRUCTON; + } + break; + } + + case 0x1E: { /* DATI */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("dati r%u, %x", rs, imm); + putIReg(rs, binop(Iop_Add64, + getIReg(rs), mkU64((long long)imm << 48))); + } else { + ILLEGAL_INSTRUCTON; + } + break; + } + default: goto decode_failure; } @@ -30557,43 +32304,221 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, getIReg(rs), getIReg(rt)), imm); break; - case 0x07: /* BGTZ */ - DIP("bgtz r%u, %u", rs, imm); - if (mode64) - dis_branch(False, unop(Iop_Not1, binop(Iop_CmpLE64S, getIReg(rs), - mkU64(0x00))), imm, &bstmt); - else - dis_branch(False, unop(Iop_Not1, binop(Iop_CmpLE32S, getIReg(rs), - mkU32(0x00))), imm, &bstmt); + case 0x07: /* BGTZ, BGTZALC, BLTZALC, BLTUC */ + if (rt == 0) { /* BGTZ */ + DIP("bgtz r%u, %u", rs, imm); + if (mode64) + dis_branch(False, unop(Iop_Not1, binop(Iop_CmpLE64S, getIReg(rs), + mkU64(0x00))), imm, &bstmt); + else + dis_branch(False, unop(Iop_Not1, binop(Iop_CmpLE32S, getIReg(rs), + mkU32(0x00))), imm, &bstmt); + } else if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + if (rs == 0) { /* BGTZALC */ + DIP("bgtzalc r%u, %u", rt, imm); + if (mode64) { + dis_branch_compact(True, + unop(Iop_Not1, + binop(Iop_CmpLE64S, + getIReg(rt), mkU64(0x0))), + imm, &dres); + } else { + dis_branch_compact(True, + unop(Iop_Not1, + binop(Iop_CmpLE32S, + getIReg(rt), mkU32(0x0))), + imm, &dres); + } + } else if (rs == rt) { /* BLTZALC */ + DIP("bltzalc r%u, %u", rt, imm); + if (mode64) { + dis_branch_compact(True, + unop(Iop_Not1, + binop(Iop_CmpLE64S, + mkU64(0x0), getIReg(rt))), + imm, &dres); + } else { + dis_branch_compact(True, + unop(Iop_Not1, + binop(Iop_CmpLE32S, + mkU32(0x0), getIReg(rt))), + imm, &dres); + } + } else { /* BLTUC */ + DIP("bltuc r%u, r%u, %u", rt, rs, imm); + if (mode64) { + dis_branch_compact(False, + binop(Iop_CmpLT64U, getIReg(rs), getIReg(rt)), + imm, &dres); + } else { + dis_branch_compact(False, + binop(Iop_CmpLT32U, getIReg(rs), getIReg(rt)), + imm, &dres); + } + } + } else { + ILLEGAL_INSTRUCTON; + } break; - case 0x17: /* BGTZL */ - DIP("bgtzl r%u, %u", rs, imm); - if (mode64) - lastn = dis_branch_likely(binop(Iop_CmpLE64S, getIReg(rs), - mkU64(0x00)), imm); - else - lastn = dis_branch_likely(binop(Iop_CmpLE32S, getIReg(rs), - mkU32(0x00)), imm); + case 0x17: /* BGTZL, BGTZC, BLTZC, BLTC */ + if (rt == 0) { /* BGTZL */ + DIP("bgtzl r%u, %u", rs, imm); + if (mode64) + lastn = dis_branch_likely(binop(Iop_CmpLE64S, getIReg(rs), + mkU64(0x00)), imm); + else + lastn = dis_branch_likely(binop(Iop_CmpLE32S, getIReg(rs), + mkU32(0x00)), imm); + } else if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + if (rs == 0) { /* BGTZC */ + DIP("bgtzc r%u, %u", rt, imm); + if (mode64) { + dis_branch_compact(False, + unop(Iop_Not1, + binop(Iop_CmpLE64S, + getIReg(rt), mkU64(0x0))), + imm, &dres); + } else { + dis_branch_compact(False, + unop(Iop_Not1, + binop(Iop_CmpLE32S, + getIReg(rt), mkU32(0x0))), + imm, &dres); + } + } else if (rs == rt) { /* BLTZC */ + DIP("bltzc r%u, %u", rt, imm); + if (mode64) { + dis_branch_compact(False, + unop(Iop_Not1, + binop(Iop_CmpLE64S, + mkU64(0x0), getIReg(rt))), + imm, &dres); + } else { + dis_branch_compact(False, + unop(Iop_Not1, + binop(Iop_CmpLE32S, + mkU32(0x0), getIReg(rt))), + imm, &dres); + } + } else { /* BLTC */ + DIP("bltc r%u, r%u, %u", rs, rt, imm); + if (mode64) { + dis_branch_compact(False, + unop(Iop_Not1, + binop(Iop_CmpLE64S, + getIReg(rt), getIReg(rs))), + imm, &dres); + } else { + dis_branch_compact(False, + unop(Iop_Not1, + binop(Iop_CmpLE32S, + getIReg(rt), getIReg(rs))), + imm, &dres); + } + } + } else { + ILLEGAL_INSTRUCTON; + } break; - case 0x06: /* BLEZ */ - DIP("blez r%u, %u", rs, imm); - if (mode64) - dis_branch(False, binop(Iop_CmpLE64S, getIReg(rs), mkU64(0x0)), - imm, &bstmt); - else - dis_branch(False,binop(Iop_CmpLE32S, getIReg(rs), mkU32(0x0)), imm, - &bstmt); + case 0x06: /* BLEZ, BLEZALC, BGEZALC, BGEUC */ + if (rt == 0) { /* BLEZ */ + DIP("blez r%u, %u", rs, imm); + if (mode64) + dis_branch(False, binop(Iop_CmpLE64S, getIReg(rs), mkU64(0x0)), + imm, &bstmt); + else + dis_branch(False, binop(Iop_CmpLE32S, getIReg(rs), mkU32(0x0)), imm, + &bstmt); + } else if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + if (rs == 0) { /* BLEZALC */ + DIP("blezalc r%u, %u", rt, imm); + if (mode64) + dis_branch_compact(True, + binop(Iop_CmpLE64S, getIReg(rt), mkU64(0x0)), + imm, &dres); + else + dis_branch_compact(True, + binop(Iop_CmpLE32S, getIReg(rt), mkU32(0x0)), + imm, &dres); + } else if (rt == rs) {/* BGEZALC */ + DIP("bgezalc r%u, %u", rt, imm); + if (mode64) + dis_branch_compact(True, + binop(Iop_CmpLE64S, mkU64(0x0), getIReg(rt)), + imm, &dres); + else + dis_branch_compact(True, + binop(Iop_CmpLE32S, mkU32(0x0), getIReg(rt)), + imm, &dres); + } else { /* BGEUC */ + DIP("bgeuc r%u, r%u, %u", rt, rs, imm); + if (mode64) + dis_branch_compact(False, + unop(Iop_Not1, + binop(Iop_CmpLT64U, + getIReg(rs), getIReg(rt))), + imm, &dres); + else + dis_branch_compact(False, + unop(Iop_Not1, + binop(Iop_CmpLT32U, + getIReg(rs), getIReg(rt))), + imm, &dres); + } + } else { + ILLEGAL_INSTRUCTON; + } break; - case 0x16: /* BLEZL */ - DIP("blezl r%u, %u", rs, imm); - lastn = dis_branch_likely(unop(Iop_Not1, (binop(mode64 ? Iop_CmpLE64S : - Iop_CmpLE32S, getIReg(rs), mode64 ? - mkU64(0x0) : mkU32(0x0)))), imm); + case 0x16: /* BLEZL, BLEZC, BGEZC, BGEC */ + if (rt == 0) { /* BLEZL */ + DIP("blezl r%u, %u", rs, imm); + lastn = dis_branch_likely(unop(Iop_Not1, (binop(mode64 ? Iop_CmpLE64S : + Iop_CmpLE32S, getIReg(rs), mode64 ? + mkU64(0x0) : mkU32(0x0)))), imm); + } else if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + if (rs == 0) { /* BLEZC */ + DIP("blezc r%u, %u", rt, imm); + if (mode64) { + dis_branch_compact(False, + binop(Iop_CmpLE64S, getIReg(rt), mkU64(0x0)), + imm, &dres); + } else { + dis_branch_compact(False, + binop(Iop_CmpLE32S, getIReg(rt), mkU32(0x0)), + imm, &dres); + } + } else if (rt == rs) { /* BGEZC */ + DIP("bgezc r%u, %u", rt, imm); + if (mode64) { + dis_branch_compact(False, + binop(Iop_CmpLE64S, mkU64(0x0), getIReg(rt)), + imm, &dres); + } else { + dis_branch_compact(False, + binop(Iop_CmpLE32S, mkU32(0x0), getIReg(rt)), + imm, &dres); + } + } else { /* BGEC */ + DIP("bgec r%u, r%u, %u", rs, rt, imm); + if (mode64) { + dis_branch_compact(False, + binop(Iop_CmpLE64S, getIReg(rt), getIReg(rs)), + imm, &dres); + } else { + dis_branch_compact(False, + binop(Iop_CmpLE32S, getIReg(rt), getIReg(rs)), + imm, &dres); + } + } + } else { + ILLEGAL_INSTRUCTON; + } break; +#if defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev < 6)) case 0x08: { /* ADDI */ DIP("addi r%u, r%u, %u", rt, rs, imm); IRTemp tmpRs32 = newTemp(Ity_I32); @@ -30631,6 +32556,111 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, putIReg(rt, mkWidenFrom32(ty, mkexpr(t0), True)); break; } +#elif defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev >= 6)) + case 0x08: { /* BEQZALC, BEQC, BOVC */ + if (rs == 0) { /* BEQZALC */ + DIP("beqzalc r%u, %u", rt, imm); + if (mode64) { + dis_branch_compact(True, + binop(Iop_CmpEQ64, getIReg(rt), mkU64(0x0)), + imm, &dres); + } else { + dis_branch_compact(True, + binop(Iop_CmpEQ32, getIReg(rt), mkU32(0x0)), + imm, &dres); + } + } else if (rs < rt) { /* BEQC */ + DIP("beqc r%u, r%u, %u",rs, rt, imm); + if (mode64) { + dis_branch_compact(False, + binop(Iop_CmpEQ64, getIReg(rt), getIReg(rs)), + imm, &dres); + } else { + dis_branch_compact(False, + binop(Iop_CmpEQ32, getIReg(rt), getIReg(rs)), + imm, &dres); + } + } else { /* BOVC */ + DIP("bovc r%u, r%u, %u",rs, rt, imm); + if (mode64) { + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + assign(t0, IRExpr_ITE(binop(Iop_CmpLT64S, + getIReg(rt), + mkU64(0xffffffff80000000ULL)), + mkU32(1), + IRExpr_ITE(binop(Iop_CmpLT64S, + getIReg(rt), + mkU64(0x7FFFFFFFULL)), + mkU32(0),mkU32(1)))); + assign(t1, IRExpr_ITE(binop(Iop_CmpLT64S, + getIReg(rs), + mkU64(0xffffffff80000000ULL)), + mkU32(1), + IRExpr_ITE(binop(Iop_CmpLT64S, + getIReg(rs), + mkU64(0x7FFFFFFFULL)), + mkU32(0), mkU32(1)))); + assign(t2, IRExpr_ITE(binop(Iop_CmpLT64S, + binop(Iop_Add64, + getIReg(rt), getIReg(rs)), + mkU64(0xffffffff80000000ULL)), + mkU32(1), + IRExpr_ITE(binop(Iop_CmpLT64S, + binop(Iop_Add64, + getIReg(rt), + getIReg(rs)), + mkU64(0x7FFFFFFFULL)), + mkU32(0), mkU32(1)))); + assign(t3, binop(Iop_Add32, + mkexpr(t0), + binop(Iop_Add32, mkexpr(t1), mkexpr(t2)))); + dis_branch_compact(False, + binop(Iop_CmpNE32, mkexpr(t3), mkU32(0)), + imm, &dres); + } else { + IRTemp tmpRs32 = newTemp(Ity_I32); + IRTemp tmpRt32 = newTemp(Ity_I32); + assign(tmpRs32, getIReg(rs)); + assign(tmpRt32, getIReg(rt)); + + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + /* dst = src0 + src1 + if (sign(src0 ) != sign(src1 )) + goto no overflow; + if (sign(dst) == sign(src0 )) + goto no overflow; + we have overflow! */ + + assign(t0, binop(Iop_Add32, mkexpr(tmpRs32), mkexpr(tmpRt32))); + assign(t1, binop(Iop_Xor32, mkexpr(tmpRs32), mkexpr(tmpRt32))); + assign(t2, unop(Iop_1Uto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, mkexpr(t1), mkU32(0x80000000)), + mkU32(0x80000000)))); + + assign(t3, binop(Iop_Xor32, mkexpr(t0), mkexpr(tmpRs32))); + assign(t4, unop(Iop_1Uto32, + binop(Iop_CmpNE32, + binop(Iop_And32, mkexpr(t3), mkU32(0x80000000)), + mkU32(0x80000000)))); + + dis_branch_compact(False, binop(Iop_CmpEQ32, + binop(Iop_Or32, mkexpr(t2), mkexpr(t4)), + mkU32(0)), imm, &dres); + } + } + break; + /* In documentation for BEQC stands rs > rt and for BOVC stands rs >= rt! */ + } +#endif + case 0x09: /* ADDIU */ DIP("addiu r%u, r%u, %u", rt, rs, imm); if (mode64) { @@ -30640,7 +32670,6 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, } else putIReg(rt, binop(Iop_Add32, getIReg(rs),mkU32(extend_s_16to32(imm)))); break; - case 0x0C: /* ANDI */ DIP("andi r%u, r%u, %u", rt, rs, imm); if (mode64) { @@ -30688,7 +32717,8 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, mkU32(extend_s_16to32(imm))))); break; - case 0x18: { /* Doubleword Add Immidiate - DADD; MIPS64 */ +#if defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev < 6)) + case 0x18: { /* Doubleword Add Immidiate - DADDI; MIPS64 */ DIP("daddi r%u, r%u, %u", rt, rs, imm); IRTemp tmpRs64 = newTemp(Ity_I64); assign(tmpRs64, getIReg(rs)); @@ -30726,6 +32756,115 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, putIReg(rt, mkexpr(t0)); break; } +#elif defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev >= 6)) + case 0x18: { /* BNEZALC, BNEC, BNVC */ + if (rs == 0) { /* BNEZALC */ + DIP("bnezalc r%u, %u", rt, imm); + if (mode64) { + dis_branch_compact(True, + unop(Iop_Not1, + binop(Iop_CmpEQ64, getIReg(rt), mkU64(0x0))), + imm, &dres); + } else { + dis_branch_compact(True, + unop(Iop_Not1, + binop(Iop_CmpEQ32, getIReg(rt), mkU32(0x0))), + imm, &dres); + } + } else if (rs < rt) { /* BNEC */ + DIP("bnec r%u, %u", rt, imm); + if (mode64) { + dis_branch_compact(False, + unop(Iop_Not1, + binop(Iop_CmpEQ64, + getIReg(rt), getIReg(rs))), + imm, &dres); + } else { + dis_branch_compact(False, + unop(Iop_Not1, + binop(Iop_CmpEQ32, + getIReg(rt), getIReg(rs))), + imm, &dres); + } + } else { /* BNVC */ + DIP("bnvc r%u, r%u, %u", rs, rt, imm); + if (mode64) { + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + assign(t0, IRExpr_ITE(binop(Iop_CmpLT64S, + getIReg(rt), + mkU64(0xffffffff80000000ULL)), + mkU32(1), + IRExpr_ITE(binop(Iop_CmpLT64S, + getIReg(rt), + mkU64(0x7FFFFFFFULL)), + mkU32(0),mkU32(1)))); + assign(t1, IRExpr_ITE(binop(Iop_CmpLT64S, + getIReg(rs), + mkU64(0xffffffff80000000ULL)), + mkU32(1), + IRExpr_ITE(binop(Iop_CmpLT64S, + getIReg(rs), + mkU64(0x7FFFFFFFULL)), + mkU32(0),mkU32(1)))); + assign(t2, IRExpr_ITE(binop(Iop_CmpLT64S, + binop(Iop_Add64, + getIReg(rt), getIReg(rs)), + mkU64(0xffffffff80000000ULL)), + mkU32(1), + IRExpr_ITE(binop(Iop_CmpLT64S, + binop(Iop_Add64, + getIReg(rt), + getIReg(rs)), + mkU64(0x7FFFFFFFULL)), + mkU32(0),mkU32(1)))); + assign(t3, binop(Iop_Add32, + mkexpr(t0), + binop(Iop_Add32, mkexpr(t1), mkexpr(t2)))); + dis_branch_compact(False, + binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0)), + imm, &dres); + } else { + IRTemp tmpRs32 = newTemp(Ity_I32); + IRTemp tmpRt32 = newTemp(Ity_I32); + + assign(tmpRs32, getIReg(rs)); + assign(tmpRt32, getIReg(rt)); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + /* dst = src0 + src1 + if (sign(src0 ) != sign(src1 )) + goto no overflow; + if (sign(dst) == sign(src0 )) + goto no overflow; + we have overflow! */ + + assign(t0, binop(Iop_Add32, mkexpr(tmpRs32), mkexpr(tmpRt32))); + assign(t1, binop(Iop_Xor32, mkexpr(tmpRs32), mkexpr(tmpRt32))); + assign(t2, unop(Iop_1Uto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, mkexpr(t1), mkU32(0x80000000)), + mkU32(0x80000000)))); + + assign(t3, binop(Iop_Xor32, mkexpr(t0), mkexpr(tmpRs32))); + assign(t4, unop(Iop_1Uto32, + binop(Iop_CmpNE32, + binop(Iop_And32, mkexpr(t3), mkU32(0x80000000)), + mkU32(0x80000000)))); + + dis_branch_compact(False, binop(Iop_CmpNE32 , + binop(Iop_Or32, mkexpr(t2), mkexpr(t4)), + mkU32(0)), imm, &dres); + } + } + break; + } +#endif case 0x19: /* Doubleword Add Immidiate Unsigned - DADDIU; MIPS64 */ DIP("daddiu r%u, r%u, %u", rt, rs, imm); @@ -30938,11 +33077,28 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, mkNarrowTo32(ty, getIReg(rs))), mkU32(0x0)), imm, &bstmt); - break; + } else if (archinfo->hwcaps & VEX_MIPS_CPU_ISA_M32R6) { /* BC */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("bc %x", instr_index & 0x3FFFFFF); + if (mode64) { + t0 = newTemp(Ity_I64); + assign(t0, mkU64(guest_PC_curr_instr + + ((extend_s_26to64(instr_index & 0x3FFFFFF) + 1 ) << 2))); + } else { + t0 = newTemp(Ity_I32); + assign(t0, mkU32(guest_PC_curr_instr + + ((extend_s_26to32(instr_index & 0x3FFFFFF) + 1) << 2))); + } + putPC(mkexpr(t0)); + dres.whatNext = Dis_StopHere; + dres.jk_StopHere = Ijk_Boring; + } else { + ILLEGAL_INSTRUCTON; + } } else { goto decode_failure; } - + break; case 0x36: /* Branch on Bit Clear Plus 32 - BBIT032; Cavium OCTEON */ /* Cavium Specific instructions. */ if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) { @@ -30959,11 +33115,47 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, getIReg(rs)), mkU64(0x0)), imm, &bstmt); - break; + } else if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + if (rs == 0) { /* JIC */ + DIP("jic r%u, %u", rt, instr_index & 0xFFFF); + if (mode64) { + t0 = newTemp(Ity_I64); + assign(t0, binop(Iop_Add64, getIReg(rt), + mkU64(extend_s_16to64((instr_index & 0xFFFF))))); + } else { + t0 = newTemp(Ity_I32); + assign(t0, binop(Iop_Add32, getIReg(rt), + mkU32(extend_s_16to32((instr_index & 0xFFFF))))); + } + putPC(mkexpr(t0)); + dres.whatNext = Dis_StopHere; + dres.jk_StopHere = Ijk_Boring; + } else { /* BEQZC */ + DIP("beqzc r%u, %u", rs, imm); + dres.jk_StopHere = Ijk_Boring; + dres.whatNext = Dis_StopHere; + ULong branch_offset; + t0 = newTemp(Ity_I1); + if (mode64) { + branch_offset = extend_s_23to64((instr_index& 0x1fffff) << 2); + assign(t0, binop(Iop_CmpEQ64, getIReg(rs), mkU64(0x0))); + stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring, + IRConst_U64(guest_PC_curr_instr + 4 + branch_offset), + OFFB_PC)); + putPC(mkU64(guest_PC_curr_instr + 4)); + } else { + branch_offset = extend_s_23to32((instr_index& 0x1fffff) << 2); + assign(t0, binop(Iop_CmpEQ32, getIReg(rs), mkU32(0x0))); + stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring, + IRConst_U32(guest_PC_curr_instr + 4 + + (UInt) branch_offset), OFFB_PC)); + putPC(mkU32(guest_PC_curr_instr + 4)); + } + } } else { - goto decode_failure; + ILLEGAL_INSTRUCTON; } - + break; case 0x3A: /* Branch on Bit Set - BBIT1; Cavium OCTEON */ /* Cavium Specific instructions. */ if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) { @@ -30978,11 +33170,28 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, mkNarrowTo32(ty, getIReg(rs))), mkU32(0x0)), imm, &bstmt); - break; + } else if (archinfo->hwcaps & VEX_MIPS_CPU_ISA_M32R6) {/* BALC */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("balc %x", instr_index & 0x3FFFFFF); + if (mode64) { + t0 = newTemp(Ity_I64); + assign(t0, mkU64(guest_PC_curr_instr + ((extend_s_26to64(instr_index & 0x3FFFFFF)+1)<<2))); + putIReg(31, mkU64(guest_PC_curr_instr + 4)); + } else { + t0 = newTemp(Ity_I32); + assign(t0, mkU32(guest_PC_curr_instr+((extend_s_26to32(instr_index & 0x3FFFFFF)+1)<<2))); + putIReg(31, mkU32(guest_PC_curr_instr + 4)); + } + putPC(mkexpr(t0)); + dres.whatNext = Dis_StopHere; + dres.jk_StopHere = Ijk_Call; + } else { + ILLEGAL_INSTRUCTON; + } } else { goto decode_failure; } - + break; case 0x3E: /* Branch on Bit Set Plus 32 - BBIT132; Cavium OCTEON */ /* Cavium Specific instructions. */ if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) { @@ -30999,10 +33208,59 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, getIReg(rs)), mkU64(0x0)), imm, &bstmt); - break; + } else if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + if (rs == 0) {/* JIALC */ + DIP("jialc r%u, %u", rt, instr_index & 0xFFFF); + if (rs) goto decode_failure; + if (mode64) { + t0 = newTemp(Ity_I64); + assign(t0, binop(Iop_Add64, getIReg(rt), + mkU64(extend_s_16to64((instr_index & 0xFFFF))))); + putIReg(31, mkU64(guest_PC_curr_instr + 4)); + } else { + t0 = newTemp(Ity_I32); + assign(t0, binop(Iop_Add32, getIReg(rt), + mkU32(extend_s_16to32((instr_index & 0xFFFF))))); + putIReg(31, mkU32(guest_PC_curr_instr + 4)); + } + putPC(mkexpr(t0)); + dres.whatNext = Dis_StopHere; + dres.jk_StopHere = Ijk_Call; + } else { /* BNEZC */ + DIP("bnezc r%u, %u", rs, imm); + dres.jk_StopHere = Ijk_Boring; + dres.whatNext = Dis_StopHere; + ULong branch_offset; + t0 = newTemp(Ity_I1); + if (mode64) { + branch_offset = extend_s_23to64((instr_index& 0x1fffff) << 2); + assign(t0, unop(Iop_Not1, binop(Iop_CmpEQ64, getIReg(rs), mkU64(0x0)))); + stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring, + IRConst_U64(guest_PC_curr_instr + 4 + branch_offset), + OFFB_PC)); + putPC(mkU64(guest_PC_curr_instr + 4)); + } else { + branch_offset = extend_s_23to32((instr_index& 0x1fffff) << 2); + assign(t0, unop(Iop_Not1, binop(Iop_CmpEQ32, getIReg(rs), mkU32(0x0)))); + stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring, + IRConst_U32(guest_PC_curr_instr + 4 + + (UInt) branch_offset), OFFB_PC)); + putPC(mkU32(guest_PC_curr_instr + 4)); + } + } } else { goto decode_failure; } + break; + + case 0x1D: /* DAUI */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("daui r%u, r%u, %x", rt, rs, imm); + putIReg(rt, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_32to64(imm << 16)))); + } else { + ILLEGAL_INSTRUCTON; + } + break; case 0x1E: /* MIPS MSA (SIMD) */ if (has_msa) { @@ -31148,7 +33406,8 @@ DisResult disInstr_MIPS( IRSB* irsb_IN, vassert(guest_arch == VexArchMIPS32 || guest_arch == VexArchMIPS64); mode64 = guest_arch != VexArchMIPS32; - fp_mode64 = abiinfo->guest_mips_fp_mode64; + fp_mode64 = abiinfo->guest_mips_fp_mode & 1; + fp_mode64_fre = abiinfo->guest_mips_fp_mode & 2; has_msa = VEX_MIPS_PROC_MSA(archinfo->hwcaps); vassert(VEX_MIPS_HOST_FP_MODE(archinfo->hwcaps) >= fp_mode64); diff --git a/VEX/priv/host_mips_defs.c b/VEX/priv/host_mips_defs.c index f62a410d11..a88ad1a84e 100644 --- a/VEX/priv/host_mips_defs.c +++ b/VEX/priv/host_mips_defs.c @@ -380,6 +380,12 @@ const HChar *showMIPSFpOp(MIPSFpOp op) case Mfp_CVTWS: ret = "cvt.w.s"; break; + case Mfp_RINTS: + ret = "rint.s"; + break; + case Mfp_RINTD: + ret = "rint.d"; + break; case Mfp_CVTWD: ret = "cvt.w.d"; break; @@ -413,6 +419,44 @@ const HChar *showMIPSFpOp(MIPSFpOp op) case Mfp_CEILLD: ret = "ceil.l.d"; break; +#if (__mips_isa_rev >= 6) + case Mfp_CMP_UN: + ret = "cmp.un.d"; + break; + case Mfp_CMP_EQ: + ret = "cmp.eq.d"; + break; + case Mfp_CMP_LT: + ret = "cmp.lt.d"; + break; + case Mfp_CMP_NGT: + ret = "cmp.ngt.d"; + break; + case Mfp_CMP_UN_S: + ret = "cmp.un.s"; + break; + case Mfp_CMP_EQ_S: + ret = "cmp.eq.s"; + break; + case Mfp_CMP_LT_S: + ret = "cmp.lt.s"; + break; + case Mfp_CMP_NGT_S: + ret = "cmp.ngt.s"; + break; + case Mfp_MAXS: + ret = "max.s"; + break; + case Mfp_MAXD: + ret = "max.d"; + break; + case Mfp_MINS: + ret = "min.s"; + break; + case Mfp_MIND: + ret = "min.d"; + break; +#else case Mfp_CMP_UN: ret = "c.un.d"; break; @@ -425,6 +469,7 @@ const HChar *showMIPSFpOp(MIPSFpOp op) case Mfp_CMP_NGT: ret = "c.ngt.d"; break; +#endif default: vex_printf("Unknown op: %d", (Int)op); vpanic("showMIPSFpOp"); @@ -471,6 +516,18 @@ const HChar* showMIPSMoveCondOp ( MIPSMoveCondOp op ) case MMoveCond_movn: ret = "movn"; break; + case MSeleqz: + ret = "seleqz"; + break; + case MSelnez: + ret = "selnez"; + break; + case MFpSels: + ret = "sel.s"; + break; + case MFpSeld: + ret = "sel.d"; + break; default: vpanic("showMIPSFpMoveCondOp"); break; @@ -733,7 +790,7 @@ const HChar *showMIPSAluOp(MIPSAluOp op, Bool immR) ret = immR ? "xori" : "xor"; break; case Malu_DADD: - ret = immR ? "daddi" : "dadd"; + ret = immR ? "daddiu" : "dadd"; break; case Malu_DSUB: ret = immR ? "dsubi" : "dsub"; @@ -909,6 +966,20 @@ const HChar *showMsa2ROp(MSA2ROp op) { return ret; } +const HChar *showRotxOp(MIPSRotxOp op) { + const HChar *ret; + switch(op) { + case Rotx32: + ret = "rotx32"; + break; + case Rotx64: + ret = "rotx64"; + break; + } + + return ret; +} + const HChar *showMsa2RFOp(MSA2RFOp op) { const HChar *ret; @@ -1336,6 +1407,20 @@ MIPSInstr *MIPSInstr_Ext(HReg dst, HReg src, UInt pos, UInt size) return i; } +MIPSInstr *MIPSInstr_Mulr6(Bool syned, Bool sz32, Bool low, HReg dst, + HReg srcL, HReg srcR) +{ + MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr)); + i->tag = Min_Mulr6; + i->Min.Mulr6.syned = syned; + i->Min.Mulr6.sz32 = sz32; /* True = 32 bits */ + i->Min.Mulr6.low = low; + i->Min.Mulr6.dst = dst; + i->Min.Mulr6.srcL = srcL; + i->Min.Mulr6.srcR = srcR; + return i; +} + /* msub */ MIPSInstr *MIPSInstr_Msub(Bool syned, HReg srcL, HReg srcR) { @@ -1374,6 +1459,20 @@ MIPSInstr *MIPSInstr_Div(Bool syned, Bool sz32, HReg srcL, HReg srcR) return i; } +MIPSInstr *MIPSInstr_Divr6(Bool syned, Bool sz32, Bool mod, HReg dst, + HReg srcL, HReg srcR) +{ + MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr)); + i->tag = Min_Divr6; + i->Min.Divr6.syned = syned; + i->Min.Divr6.sz32 = sz32; /* True = 32 bits */ + i->Min.Divr6.mod = mod; + i->Min.Divr6.dst = dst; + i->Min.Divr6.srcL = srcL; + i->Min.Divr6.srcR = srcR; + return i; +} + MIPSInstr *MIPSInstr_Call ( MIPSCondCode cond, Addr64 target, UInt argiregs, HReg src, RetLoc rloc ) { @@ -1626,6 +1725,18 @@ MIPSInstr *MIPSInstr_FpCompare(MIPSFpOp op, HReg dst, HReg srcL, HReg srcR) return i; } +MIPSInstr *MIPSInstr_FpMinMax(MIPSFpOp op, HReg dst, HReg srcL, HReg srcR) +{ + MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr)); + i->tag = Min_FpMinMax; + i->Min.FpMinMax.op = op; + i->Min.FpMinMax.dst = dst; + i->Min.FpMinMax.srcL = srcL; + i->Min.FpMinMax.srcR = srcR; + return i; +} + + MIPSInstr *MIPSInstr_MtFCSR(HReg src) { MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr)); @@ -1766,6 +1877,18 @@ MIPSInstr* MIPSInstr_Msa2RF(MSA2RFOp op, MSADFFlx df, HReg wd, HReg ws) { return i; } +MIPSInstr* MIPSInstr_Bitswap(MIPSRotxOp op, HReg rd, HReg rt, HReg shift, HReg shiftx, HReg stripe) { + MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr)); + i->tag = Min_Rotx; + i->Min.Rotx.op = op; + i->Min.Rotx.rd = rd; + i->Min.Rotx.rt = rt; + i->Min.Rotx.shift = shift; + i->Min.Rotx.shiftx = shiftx; + i->Min.Rotx.stripe = stripe; + return i; +} + /* -------- Pretty Print instructions ------------- */ static void ppLoadImm(HReg dst, ULong imm, Bool mode64) { @@ -1829,6 +1952,14 @@ void ppMIPSInstr(const MIPSInstr * i, Bool mode64) ppMIPSRH(rh_srcR, mode64); return; } + case Min_Rotx: { + HReg r_src = i->Min.Rotx.rt; + vex_printf("rotx "); + ppHRegMIPS(i->Min.Rotx.rd, mode64); + vex_printf(","); + ppHRegMIPS(r_src, mode64); + return; + } case Min_Unary: { vex_printf("%s ", showMIPSUnaryOp(i->Min.Unary.op)); ppHRegMIPS(i->Min.Unary.dst, mode64); @@ -1878,6 +2009,27 @@ void ppMIPSInstr(const MIPSInstr * i, Bool mode64) vex_printf(", %u, %u", i->Min.Ext.pos, i->Min.Ext.size); return; } + case Min_Mulr6: { + if(i->Min.Mulr6.sz32) { + if(i->Min.Mulr6.low)vex_printf("mul"); + else vex_printf("muh"); + if(i->Min.Mulr6.syned)vex_printf("u "); + else vex_printf(" "); + } else { + if(i->Min.Mulr6.low) + vex_printf("%s%s ", "dmul", + i->Min.Mulr6.syned ? "" : "u"); + else + vex_printf("%s%s ","dmuh", + i->Min.Mulr6.syned ? "" : "u"); + } + ppHRegMIPS(i->Min.Mulr6.dst, mode64); + vex_printf(", "); + ppHRegMIPS(i->Min.Mulr6.srcL, mode64); + vex_printf(", "); + ppHRegMIPS(i->Min.Mulr6.srcR, mode64); + break; + } case Min_Mthi: { vex_printf("mthi "); ppHRegMIPS(i->Min.MtHL.src, mode64); @@ -1915,6 +2067,27 @@ void ppMIPSInstr(const MIPSInstr * i, Bool mode64) ppHRegMIPS(i->Min.Div.srcR, mode64); return; } + case Min_Divr6: { + if(i->Min.Divr6.sz32) { + if(i->Min.Divr6.mod)vex_printf("mod"); + else vex_printf("div"); + if(i->Min.Divr6.syned)vex_printf("u "); + else vex_printf(" "); + } else { + if(i->Min.Divr6.mod) + vex_printf("%s%s ", "dmod", + i->Min.Divr6.syned ? "" : "u"); + else + vex_printf("%s%s ","ddiv", + i->Min.Divr6.syned ? "" : "u"); + } + ppHRegMIPS(i->Min.Divr6.dst, mode64); + vex_printf(", "); + ppHRegMIPS(i->Min.Divr6.srcL, mode64); + vex_printf(", "); + ppHRegMIPS(i->Min.Divr6.srcR, mode64); + break; + } case Min_Call: { Int n; vex_printf("call: "); @@ -2096,6 +2269,12 @@ void ppMIPSInstr(const MIPSInstr * i, Bool mode64) vex_printf(","); ppHRegMIPS(i->Min.FpCompare.srcR, mode64); return; + case Min_FpMinMax: + vex_printf("%s ", showMIPSFpOp(i->Min.FpMinMax.op)); + ppHRegMIPS(i->Min.FpCompare.srcL, mode64); + vex_printf(","); + ppHRegMIPS(i->Min.FpCompare.srcR, mode64); + return; case Min_FpMulAcc: vex_printf("%s ", showMIPSFpOp(i->Min.FpMulAcc.op)); ppHRegMIPS(i->Min.FpMulAcc.dst, mode64); @@ -2378,6 +2557,10 @@ void getRegUsage_MIPSInstr(HRegUsage * u, const MIPSInstr * i, Bool mode64) addRegUsage_MIPSRH(u, i->Min.Shft.srcR); addHRegUse(u, HRmWrite, i->Min.Shft.dst); return; + case Min_Rotx: + addHRegUse(u, HRmRead, i->Min.Rotx.rt); + addHRegUse(u, HRmWrite, i->Min.Rotx.rd); + return; case Min_Cmp: addHRegUse(u, HRmRead, i->Min.Cmp.srcL); addHRegUse(u, HRmRead, i->Min.Cmp.srcR); @@ -2404,6 +2587,11 @@ void getRegUsage_MIPSInstr(HRegUsage * u, const MIPSInstr * i, Bool mode64) addHRegUse(u, HRmWrite, i->Min.Ext.dst); addHRegUse(u, HRmRead, i->Min.Ext.src); return; + case Min_Mulr6: + addHRegUse(u, HRmWrite, i->Min.Mulr6.dst); + addHRegUse(u, HRmRead, i->Min.Mulr6.srcL); + addHRegUse(u, HRmRead, i->Min.Mulr6.srcR); + return; case Min_Mthi: case Min_Mtlo: addHRegUse(u, HRmWrite, hregMIPS_HI(mode64)); @@ -2512,6 +2700,11 @@ void getRegUsage_MIPSInstr(HRegUsage * u, const MIPSInstr * i, Bool mode64) addHRegUse(u, HRmRead, i->Min.Div.srcL); addHRegUse(u, HRmRead, i->Min.Div.srcR); return; + case Min_Divr6: + addHRegUse(u, HRmWrite, i->Min.Divr6.dst); + addHRegUse(u, HRmRead, i->Min.Divr6.srcL); + addHRegUse(u, HRmRead, i->Min.Divr6.srcR); + return; case Min_Call: { /* Logic and comments copied/modified from x86, ppc and arm back end. First off, claim it trashes all the caller-saved regs @@ -2640,12 +2833,17 @@ void getRegUsage_MIPSInstr(HRegUsage * u, const MIPSInstr * i, Bool mode64) addHRegUse(u, HRmRead, i->Min.FpCompare.srcL); addHRegUse(u, HRmRead, i->Min.FpCompare.srcR); return; + case Min_FpMinMax: + addHRegUse(u, HRmWrite, i->Min.FpMinMax.dst); + addHRegUse(u, HRmRead, i->Min.FpMinMax.srcL); + addHRegUse(u, HRmRead, i->Min.FpMinMax.srcR); + return; case Min_FpGpMove: addHRegUse(u, HRmWrite, i->Min.FpGpMove.dst); addHRegUse(u, HRmRead, i->Min.FpGpMove.src); return; case Min_MoveCond: - addHRegUse(u, HRmModify, i->Min.MoveCond.dst); + addHRegUse(u, HRmWrite, i->Min.MoveCond.dst); addHRegUse(u, HRmRead, i->Min.MoveCond.src); addHRegUse(u, HRmRead, i->Min.MoveCond.cond); return; @@ -2687,6 +2885,10 @@ void mapRegs_MIPSInstr(HRegRemap * m, MIPSInstr * i, Bool mode64) mapRegs_MIPSRH(m, i->Min.Shft.srcR); mapReg(m, &i->Min.Shft.dst); return; + case Min_Rotx: + mapReg(m, &i->Min.Rotx.rt); + mapReg(m, &i->Min.Rotx.rd); + return; case Min_Cmp: mapReg(m, &i->Min.Cmp.srcL); mapReg(m, &i->Min.Cmp.srcR); @@ -2709,6 +2911,11 @@ void mapRegs_MIPSInstr(HRegRemap * m, MIPSInstr * i, Bool mode64) mapReg(m, &i->Min.Ext.src); mapReg(m, &i->Min.Ext.dst); return; + case Min_Mulr6: + mapReg(m, &i->Min.Mulr6.dst); + mapReg(m, &i->Min.Mulr6.srcL); + mapReg(m, &i->Min.Mulr6.srcR); + return; case Min_Mthi: case Min_Mtlo: mapReg(m, &i->Min.MtHL.src); @@ -2725,6 +2932,18 @@ void mapRegs_MIPSInstr(HRegRemap * m, MIPSInstr * i, Bool mode64) mapReg(m, &i->Min.Div.srcL); mapReg(m, &i->Min.Div.srcR); return; + + case Min_Divr6: + mapReg(m, &i->Min.Divr6.dst); + mapReg(m, &i->Min.Divr6.srcL); + mapReg(m, &i->Min.Divr6.srcR); + return; + + case Min_Call: + if (i->Min.Call.cond != MIPScc_AL) + mapReg(m, &i->Min.Call.src); + return; + case Msa_MI10: mapReg(m, &i->Min.MsaMi10.rs); mapReg(m, &i->Min.MsaMi10.wd); @@ -2740,12 +2959,6 @@ void mapRegs_MIPSInstr(HRegRemap * m, MIPSInstr * i, Bool mode64) mapReg(m, &i->Min.Msa2R.ws); return; - case Min_Call: - { - if (i->Min.Call.cond != MIPScc_AL) - mapReg(m, &i->Min.Call.src); - return; - } case Msa_3R: mapReg(m, &i->Min.Msa3R.wt); mapReg(m, &i->Min.Msa3R.ws); @@ -2845,6 +3058,11 @@ void mapRegs_MIPSInstr(HRegRemap * m, MIPSInstr * i, Bool mode64) mapReg(m, &i->Min.FpCompare.srcL); mapReg(m, &i->Min.FpCompare.srcR); return; + case Min_FpMinMax: + mapReg(m, &i->Min.FpMinMax.dst); + mapReg(m, &i->Min.FpMinMax.srcL); + mapReg(m, &i->Min.FpMinMax.srcR); + return; case Min_MtFCSR: mapReg(m, &i->Min.MtFCSR.src); return; @@ -3896,27 +4114,55 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, goto done; } + case Min_Rotx: { + UInt r_dst = iregNo(i->Min.Rotx.rd, mode64); + UInt r_src = iregNo(i->Min.Rotx.rt, mode64); + switch(i->Min.Rotx.op) { + case Rotx32: + p = mkFormR(p, 31, 0, r_src, r_dst, 0, 32); + break; + case Rotx64: + p = mkFormR(p, 31, 0, r_src, r_dst, 0, 36); + break; + } + goto done; + } case Min_Unary: { UInt r_dst = iregNo(i->Min.Unary.dst, mode64); UInt r_src = iregNo(i->Min.Unary.src, mode64); switch (i->Min.Unary.op) { /* Mun_CLO, Mun_CLZ, Mun_NOP, Mun_DCLO, Mun_DCLZ */ +#if (__mips_isa_rev >= 6) + case Mun_CLO: /* clo */ + p = mkFormR(p, 0, r_src, 0, r_dst, 1, 17); + break; + case Mun_CLZ: /* clz */ + p = mkFormR(p, 0, r_src, 0, r_dst, 1, 16); + break; + case Mun_DCLO: /* clo */ + p = mkFormR(p, 0, r_src, 0, r_dst, 1, 19); + break; + case Mun_DCLZ: /* clz */ + p = mkFormR(p, 0, r_src, 0, r_dst, 1, 18); + break; +#else case Mun_CLO: /* clo */ p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 33); break; case Mun_CLZ: /* clz */ p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 32); break; - case Mun_NOP: /* nop (sll r0,r0,0) */ - p = mkFormR(p, 0, 0, 0, 0, 0, 0); - break; case Mun_DCLO: /* clo */ p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 37); break; case Mun_DCLZ: /* clz */ p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 36); break; +#endif + case Mun_NOP: /* nop (sll r0,r0,0) */ + p = mkFormR(p, 0, 0, 0, 0, 0, 0); + break; } goto done; } @@ -4012,6 +4258,29 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, goto done; } + case Min_Mulr6: { + Bool syned = i->Min.Mulr6.syned; + Bool sz32 = i->Min.Mulr6.sz32; + UInt r_srcL = iregNo(i->Min.Mulr6.srcL, mode64); + UInt r_srcR = iregNo(i->Min.Mulr6.srcR, mode64); + UInt r_dst = iregNo(i->Min.Mulr6.dst, mode64); + int low = i->Min.Mulr6.low?2:3; + if (sz32) { + if (syned) + /* mul/muh */ + p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, low, 24); + else + /* mulu/muhu */ + p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, low, 25); + } else { + if (syned) /* DMUL/DMUH r_dst,r_srcL,r_srcR */ + p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, low, 28); + else /* DMULU/DMUHU r_dst,r_srcL,r_srcR */ + p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, low, 29); + } + goto done; + } + case Min_Macc: { Bool syned = i->Min.Macc.syned; UInt r_srcL = iregNo(i->Min.Macc.srcL, mode64); @@ -4074,7 +4343,28 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, goto done; } } - + case Min_Divr6: { + Bool syned = i->Min.Divr6.syned; + Bool sz32 = i->Min.Divr6.sz32; + UInt r_srcL = iregNo(i->Min.Divr6.srcL, mode64); + UInt r_srcR = iregNo(i->Min.Divr6.srcR, mode64); + UInt r_dst = iregNo(i->Min.Divr6.dst, mode64); + int mod = i->Min.Divr6.mod?3:2; + if (sz32) { + if (syned) + /* mul/muh */ + p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, mod, 26); + else + /* mulu/muhu */ + p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, mod, 27); + } else { + if (syned) /* DMUL/DMUH r_dst,r_srcL,r_srcR */ + p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, mod, 30); + else /* DMULU/DMUHU r_dst,r_srcL,r_srcR */ + p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, mod, 31); + } + goto done; + } case Min_Mthi: { UInt r_src = iregNo(i->Min.MtHL.src, mode64); p = mkFormR(p, 0, r_src, 0, 0, 0, 17); @@ -4472,11 +4762,17 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, UInt r_src = iregNo(am_addr->Mam.IR.base, mode64); UInt idx = am_addr->Mam.IR.index; UInt r_dst = iregNo(i->Min.LoadL.dst, mode64); - +#if (__mips_isa_rev >= 6) + if (i->Min.LoadL.sz == 4) + p = mkFormI(p, 0x1F, r_src, r_dst, ((idx << 7) & 0xff80) | 0x36); + else + p = mkFormI(p, 0x1F, r_src, r_dst, ((idx << 7) & 0xff80) | 0x37); +#else if (i->Min.LoadL.sz == 4) p = mkFormI(p, 0x30, r_src, r_dst, idx); else p = mkFormI(p, 0x34, r_src, r_dst, idx); +#endif goto done; } case Min_StoreC: { @@ -4484,11 +4780,17 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, UInt r_src = iregNo(i->Min.StoreC.src, mode64); UInt idx = am_addr->Mam.IR.index; UInt r_dst = iregNo(am_addr->Mam.IR.base, mode64); - +#if (__mips_isa_rev >= 6) + if (i->Min.LoadL.sz == 4) + p = mkFormI(p, 0x1F, r_src, r_dst, ((idx << 7) & 0xff80) | 0x26); + else + p = mkFormI(p, 0x1F, r_src, r_dst, ((idx << 7) & 0xff80) | 0x27); +#else if (i->Min.StoreC.sz == 4) p = mkFormI(p, 0x38, r_dst, r_src, idx); else p = mkFormI(p, 0x3C, r_dst, r_src, idx); +#endif goto done; } case Min_Cas: { @@ -4509,18 +4811,35 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, * movn old, expd, data * end: */ +#if (__mips_isa_rev >= 6) + // ll(d) old, 0(addr) + p = mkFormI(p, 0x1F, addr, old, sz8? 0x37: 0x36); + // bne old, expd, end + p = mkFormI(p, 5, old, expd, 5); +#else // 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); +#endif // nop p = mkFormR(p, 0, 0, 0, 0, 0, 0); // (d)addiu old, old, 1 - p = mkFormI(p, sz8 ? 25 : 9, old, old, 1); + p = mkFormI(p, sz8 ? 25 : 9, old, old, 4); + +#if (__mips_isa_rev >= 6) + // sc(d) data, 0(addr) + p = mkFormI(p, 0x1F, addr, data, sz8? 0x27: 0x26); + //beqzc + p = mkFormI(p, 0x36, data, 0, 1); + //or + p = mkFormR(p, 0, 0, expd, old, 0, 0x25 ); +#else // 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); +#endif goto done; } @@ -4698,7 +5017,12 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, UInt fr_src1 = fregNo(i->Min.FpTernary.src1, mode64); UInt fr_src2 = fregNo(i->Min.FpTernary.src2, mode64); UInt fr_src3 = fregNo(i->Min.FpTernary.src3, mode64); +#if (__mips_isa_rev >= 6) + p = mkFormR(p, 0x11, 0x10 , 0x0, fr_src1, fr_dst, 0x6); + p = mkFormR(p, 0x11, 0x10, fr_src3, fr_src2, fr_dst, 0x18); +#else p = mkFormR(p, 0x13, fr_src1, fr_src2, fr_src3, fr_dst, 0x20); +#endif break; } case Mfp_MADDD: { @@ -4706,7 +5030,12 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, UInt fr_src1 = dregNo(i->Min.FpTernary.src1); UInt fr_src2 = dregNo(i->Min.FpTernary.src2); UInt fr_src3 = dregNo(i->Min.FpTernary.src3); +#if (__mips_isa_rev >= 6) + p = mkFormR(p, 0x11, 0x11 , 0x0, fr_src1, fr_dst, 0x6); + p = mkFormR(p, 0x11, 0x11, fr_src3, fr_src2, fr_dst, 0x18); +#else p = mkFormR(p, 0x13, fr_src1, fr_src2, fr_src3, fr_dst, 0x21); +#endif break; } case Mfp_MSUBS: { @@ -4714,7 +5043,12 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, UInt fr_src1 = fregNo(i->Min.FpTernary.src1, mode64); UInt fr_src2 = fregNo(i->Min.FpTernary.src2, mode64); UInt fr_src3 = fregNo(i->Min.FpTernary.src3, mode64); +#if (__mips_isa_rev >= 6) + p = mkFormR(p, 0x11, 0x10 , 0x0, fr_src1, fr_dst, 0x6); + p = mkFormR(p, 0x11, 0x10, fr_src3, fr_src2, fr_dst, 0x19); +#else p = mkFormR(p, 0x13, fr_src1, fr_src2, fr_src3, fr_dst, 0x28); +#endif break; } case Mfp_MSUBD: { @@ -4722,7 +5056,12 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, UInt fr_src1 = dregNo(i->Min.FpTernary.src1); UInt fr_src2 = dregNo(i->Min.FpTernary.src2); UInt fr_src3 = dregNo(i->Min.FpTernary.src3); +#if (__mips_isa_rev >= 6) + p = mkFormR(p, 0x11, 0x11 , 0x0, fr_src1, fr_dst, 0x6); + p = mkFormR(p, 0x11, 0x11, fr_src3, fr_src2, fr_dst, 0x19); +#else p = mkFormR(p, 0x13, fr_src1, fr_src2, fr_src3, fr_dst, 0x29); +#endif break; } default: @@ -4859,6 +5198,16 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, fr_src = dregNo(i->Min.FpConvert.src); p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0B); break; + case Mfp_RINTS: + fr_dst = fregNo(i->Min.FpConvert.dst, mode64); + fr_src = fregNo(i->Min.FpConvert.src, mode64); + p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x1A); + break; + case Mfp_RINTD: + fr_dst = dregNo(i->Min.FpConvert.dst); + fr_src = dregNo(i->Min.FpConvert.src); + p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x1A); + break; default: goto bad; @@ -4867,6 +5216,76 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, } case Min_FpCompare: { +#if (__mips_isa_rev >= 6) + UInt fr_dst; + UInt fr_srcL; + UInt fr_srcR; + + UInt op; + UInt format; + switch (i->Min.FpConvert.op) { + case Mfp_CMP_UN: + fr_dst = dregNo(i->Min.FpCompare.dst); + fr_srcL = dregNo(i->Min.FpCompare.srcL); + fr_srcR = dregNo(i->Min.FpCompare.srcR); + format=0x15; + op = 1; + break; + case Mfp_CMP_EQ: + fr_dst = dregNo(i->Min.FpCompare.dst); + fr_srcL = dregNo(i->Min.FpCompare.srcL); + fr_srcR = dregNo(i->Min.FpCompare.srcR); + format=0x15; + op = 2; + break; + case Mfp_CMP_LT: + fr_dst = dregNo(i->Min.FpCompare.dst); + fr_srcL = dregNo(i->Min.FpCompare.srcL); + fr_srcR = dregNo(i->Min.FpCompare.srcR); + format=0x15; + op = 4; + break; + case Mfp_CMP_NGT: + fr_dst = dregNo(i->Min.FpCompare.dst); + fr_srcL = dregNo(i->Min.FpCompare.srcL); + fr_srcR = dregNo(i->Min.FpCompare.srcR); + format=0x15; + op = 5; + break; + case Mfp_CMP_UN_S: + fr_dst = fregNo(i->Min.FpCompare.dst, mode64); + fr_srcL = fregNo(i->Min.FpCompare.srcL, mode64); + fr_srcR = fregNo(i->Min.FpCompare.srcR, mode64); + format=0x14; + op = 1; + break; + case Mfp_CMP_EQ_S: + fr_dst = fregNo(i->Min.FpCompare.dst, mode64); + fr_srcL = fregNo(i->Min.FpCompare.srcL, mode64); + fr_srcR = fregNo(i->Min.FpCompare.srcR, mode64); + format=0x14; + op = 2; + break; + case Mfp_CMP_LT_S: + fr_dst = fregNo(i->Min.FpCompare.dst, mode64); + fr_srcL = fregNo(i->Min.FpCompare.srcL, mode64); + fr_srcR = fregNo(i->Min.FpCompare.srcR, mode64); + format=0x14; + op = 4; + break; + case Mfp_CMP_NGT_S: + fr_dst = fregNo(i->Min.FpCompare.dst, mode64); + fr_srcL = fregNo(i->Min.FpCompare.srcL, mode64); + fr_srcR = fregNo(i->Min.FpCompare.srcR, mode64); + format=0x14; + op = 5; + break; + default: + goto bad; + } + /* cmp.cond.d fr_srcL, fr_srcR */ + p = mkFormR(p, 0x11, format, fr_srcR, fr_srcL, fr_dst, op); +#else UInt r_dst = iregNo(i->Min.FpCompare.dst, mode64); UInt fr_srcL = dregNo(i->Min.FpCompare.srcL); UInt fr_srcR = dregNo(i->Min.FpCompare.srcR); @@ -4896,8 +5315,42 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, p = mkFormR(p, 0x11, 0x2, r_dst, 31, 0, 0); p = mkFormS(p, 0, r_dst, 0, r_dst, 23, 2); p = mkFormI(p, 12, r_dst, r_dst, 1); +#endif + goto done; + } + +#if (__mips_isa_rev >= 6) + case Min_FpMinMax: { + UInt r_dst = dregNo(i->Min.FpCompare.dst); + UInt fr_srcL = dregNo(i->Min.FpCompare.srcL); + UInt fr_srcR = dregNo(i->Min.FpCompare.srcR); + UInt format; + UInt instr; + switch (i->Min.FpMinMax.op) { + case Mfp_MAXS: + format = 0x10; + instr = 0x1E; + break; + case Mfp_MAXD: + format = 0x11; + instr = 0x1E; + break; + case Mfp_MINS: + format = 0x10; + instr = 0x1C; + break; + case Mfp_MIND: + format = 0x11; + instr = 0x1C; + break; + default: + goto bad; + } + p = mkFormR(p, 0x11, format, fr_srcR, fr_srcL, r_dst, instr); goto done; } +#endif + case Min_FpGpMove: { switch (i->Min.FpGpMove.op) { @@ -4956,6 +5409,35 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, s = iregNo(i->Min.MoveCond.src, mode64); t = iregNo(i->Min.MoveCond.cond, mode64); p = mkFormR(p, 0, s, t, d, 0, 0xb); + + break; + } + case MSeleqz: { + d = iregNo(i->Min.MoveCond.dst, mode64); + s = iregNo(i->Min.MoveCond.src, mode64); + t = iregNo(i->Min.MoveCond.cond, mode64); + p = mkFormR(p, 0, s, t, d, 0, 0x35); + break; + } + case MSelnez: { + d = iregNo(i->Min.MoveCond.dst, mode64); + s = iregNo(i->Min.MoveCond.src, mode64); + t = iregNo(i->Min.MoveCond.cond, mode64); + p = mkFormR(p, 0, s, t, d, 0, 0x37); + break; + } + case MFpSels: { + d = fregNo(i->Min.MoveCond.dst, mode64); + s = fregNo(i->Min.MoveCond.src, mode64); + t = fregNo(i->Min.MoveCond.cond, mode64); + p = mkFormR(p, 0x11, 0x10, t, s, d, 0x10); + break; + } + case MFpSeld: { + d = fregNo(i->Min.MoveCond.dst, mode64); + s = fregNo(i->Min.MoveCond.src, mode64); + t = fregNo(i->Min.MoveCond.cond, mode64); + p = mkFormR(p, 0x11, 0x11, t, s, d, 0x10); break; } default: diff --git a/VEX/priv/host_mips_defs.h b/VEX/priv/host_mips_defs.h index c49def072c..8834ae9693 100644 --- a/VEX/priv/host_mips_defs.h +++ b/VEX/priv/host_mips_defs.h @@ -451,12 +451,15 @@ typedef enum { Min_Shft, /* word sll/srl/sra */ Min_Unary, /* clo, clz, nop, neg */ Min_Ext, /* ext / dext, dextm, dextu */ + Min_Rotx, Min_Cmp, /* word compare (fake insn) */ Min_Mul, /* non-widening, 32-bit, signed multiply */ Min_Mult, /* widening multiply */ + Min_Mulr6, Min_Div, /* div */ + Min_Divr6, Min_Call, /* call to address in register */ @@ -493,6 +496,7 @@ typedef enum { Min_MtFCSR, /* set FCSR register */ Min_MfFCSR, /* get FCSR register */ Min_FpCompare, /* FP compare, generating value into int reg */ + Min_FpMinMax, /* FP r6 min and max*/ Min_FpGpMove, /* Move from/to fpr to/from gpr */ Min_MoveCond, /* Move Conditional */ @@ -528,13 +532,25 @@ typedef enum { Mfp_CVTWS, Mfp_CVTDL, Mfp_CVTSL, Mfp_CVTLS, Mfp_CVTLD, Mfp_TRULS, Mfp_TRULD, Mfp_TRUWS, Mfp_TRUWD, Mfp_FLOORWS, Mfp_FLOORWD, Mfp_ROUNDWS, Mfp_ROUNDWD, Mfp_CVTDW, Mfp_CEILWS, Mfp_CEILWD, Mfp_CEILLS, Mfp_CEILLD, Mfp_CVTDS, - Mfp_ROUNDLD, Mfp_FLOORLD, + Mfp_ROUNDLD, Mfp_FLOORLD, Mfp_RINTS, Mfp_RINTD, /* FP compare */ - Mfp_CMP_UN, Mfp_CMP_EQ, Mfp_CMP_LT, Mfp_CMP_NGT + Mfp_CMP_UN, Mfp_CMP_EQ, Mfp_CMP_LT, Mfp_CMP_NGT, + + Mfp_CMP_UN_S, Mfp_CMP_EQ_S, Mfp_CMP_LT_S, Mfp_CMP_NGT_S, + + /*MAX and MIN*/ + Mfp_MAXS, Mfp_MAXD, Mfp_MINS, Mfp_MIND } MIPSFpOp; +extern const HChar *showRotxOp(MIPSRotxOp); + +typedef enum { + Rotx32, + Rotx64 +} MIPSRotxOp; + extern const HChar *showMIPSFpOp(MIPSFpOp); /* Move from/to fpr to/from gpr */ @@ -551,7 +567,11 @@ extern const HChar *showMIPSFpGpMoveOp ( MIPSFpGpMoveOp ); typedef enum { MFpMoveCond_movns, /* FP Move Conditional on Not Zero - MIPS32 */ MFpMoveCond_movnd, - MMoveCond_movn /* Move Conditional on Not Zero */ + MMoveCond_movn, /* Move Conditional on Not Zero */ + MSeleqz, /* r6 instructions */ + MSelnez, + MFpSels, + MFpSeld } MIPSMoveCondOp; extern const HChar *showMIPSMoveCondOp ( MIPSMoveCondOp ); @@ -594,6 +614,14 @@ typedef struct { HReg srcL; MIPSRH *srcR; } Shft; + struct { + MIPSRotxOp op; + HReg rd; + HReg rt; + HReg shift; + HReg shiftx; + HReg stripe; + } Rotx; /* Clz, Clo, nop */ struct { MIPSUnaryOp op; @@ -630,12 +658,28 @@ typedef struct { HReg srcL; HReg srcR; } Mult; + struct { + Bool syned; /* signed/unsigned - meaningless if widenind = False */ + Bool sz32; + Bool low; + HReg dst; + HReg srcL; + HReg srcR; + } Mulr6; struct { Bool syned; /* signed/unsigned - meaningless if widenind = False */ Bool sz32; HReg srcL; HReg srcR; } Div; + struct { + Bool syned; /* signed/unsigned - meaningless if widenind = False */ + Bool sz32; + Bool mod; + HReg dst; + HReg srcL; + HReg srcR; + } Divr6; /* Pseudo-insn. Call target (an absolute address), on given condition (which could be Mcc_ALWAYS). argiregs indicates which of $4 .. $7 (mips32) or $4 .. $11 (mips64) @@ -778,6 +822,12 @@ typedef struct { HReg srcR; UChar cond1; } FpCompare; + struct { + MIPSFpOp op; + HReg dst; + HReg srcL; + HReg srcR; + } FpMinMax; /* Move from GP register to FCSR register. */ struct { HReg src; @@ -870,10 +920,13 @@ extern MIPSInstr *MIPSInstr_Shft(MIPSShftOp, Bool sz32, HReg, HReg, MIPSRH *); extern MIPSInstr *MIPSInstr_Unary(MIPSUnaryOp op, HReg dst, HReg src); extern MIPSInstr *MIPSInstr_Ext(HReg, HReg, UInt, UInt); extern MIPSInstr *MIPSInstr_Cmp(Bool, Bool, HReg, HReg, HReg, MIPSCondCode); - extern MIPSInstr *MIPSInstr_Mul(HReg, HReg, HReg); extern MIPSInstr *MIPSInstr_Mult(Bool, HReg, HReg); +extern MIPSInstr *MIPSInstr_Mulr6(Bool syned, Bool sz32, Bool low, + HReg, HReg, HReg); extern MIPSInstr *MIPSInstr_Div(Bool syned, Bool sz32, HReg, HReg); +extern MIPSInstr *MIPSInstr_Divr6(Bool syned, Bool sz32, Bool mod, + HReg, HReg, HReg); extern MIPSInstr *MIPSInstr_Madd(Bool, HReg, HReg); extern MIPSInstr *MIPSInstr_Msub(Bool, HReg, HReg); @@ -907,6 +960,8 @@ extern MIPSInstr *MIPSInstr_FpTernary ( MIPSFpOp op, HReg dst, HReg src1, extern MIPSInstr *MIPSInstr_FpConvert(MIPSFpOp op, HReg dst, HReg src); extern MIPSInstr *MIPSInstr_FpCompare(MIPSFpOp op, HReg dst, HReg srcL, HReg srcR); +extern MIPSInstr *MIPSInstr_FpMinMax(MIPSFpOp op, HReg dst, HReg srcL, + HReg srcR); extern MIPSInstr *MIPSInstr_FpMulAcc(MIPSFpOp op, HReg dst, HReg srcML, HReg srcMR, HReg srcAcc); extern MIPSInstr *MIPSInstr_FpLdSt(Bool isLoad, UChar sz, HReg, MIPSAMode *); @@ -943,6 +998,8 @@ extern MIPSInstr* MIPSInstr_MsaBit(MSABITOp op, MSADF df, UChar ms, HReg ws, HRe extern MIPSInstr* MIPSInstr_Msa3RF(MSA3RFOp op, MSADFFlx df, HReg wd, HReg ws, HReg wt); extern MIPSInstr* MIPSInstr_Msa2RF(MSA2RFOp op, MSADFFlx df, HReg wd, HReg ws); +extern MIPSInstr* MIPSInstr_Bitswap(MIPSRotxOp, HReg, HReg, HReg, HReg, HReg); + extern void ppMIPSInstr(const MIPSInstr *, Bool mode64); /* Some functions that insulate the register allocator from details diff --git a/VEX/priv/host_mips_isel.c b/VEX/priv/host_mips_isel.c index ebc25a4ae1..e3ada211ae 100644 --- a/VEX/priv/host_mips_isel.c +++ b/VEX/priv/host_mips_isel.c @@ -296,7 +296,7 @@ static void set_MIPS_rounding_mode(ISelEnv * env, IRExpr * mode) to +infinity | 10 | 10 to -infinity | 11 | 01 */ - /* rm_MIPS32 = XOR(rm_IR , (rm_IR << 1)) & 2 */ + /* rm_MIPS32 = XOR(rm_IR , (rm_IR << 1)) & 3 */ HReg irrm = iselWordExpr_R(env, mode); HReg tmp = newVRegI(env); HReg fcsr_old = newVRegI(env); @@ -618,9 +618,9 @@ static void doHelperCall(/*OUT*/UInt* stackAdjustAfterCall, HReg rHi, rLo; iselInt64Expr(&rHi, &rLo, env, arg); argiregs |= (1 << (argreg + 4)); - addInstr(env, mk_iMOVds_RR( argregs[argreg++], rHi )); + addInstr(env, mk_iMOVds_RR( argregs[argreg++], rLo )); argiregs |= (1 << (argreg + 4)); - addInstr(env, mk_iMOVds_RR( argregs[argreg], rLo)); + addInstr(env, mk_iMOVds_RR( argregs[argreg], rHi)); argreg++; } else if (arg->tag == Iex_GSPTR) { vassert(0); // ATC @@ -1180,8 +1180,19 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) movn v0, s0, v1 */ addInstr(env, MIPSInstr_Alu(Malu_SLT, tmp, argL, argRH)); +#if (__mips_isa_rev >= 6) + { + HReg r_temp = newVRegI(env); + addInstr(env, MIPSInstr_MoveCond(MSeleqz, r_dst, argL, tmp)); + addInstr(env, MIPSInstr_MoveCond(MSelnez, r_temp, argR, tmp)); + addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst, + MIPSRH_Reg(r_temp))); + } + +#else addInstr(env, mk_iMOVds_RR(r_dst, argL)); addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dst, argR, tmp)); +#endif return r_dst; } @@ -1189,7 +1200,12 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) HReg r_dst = newVRegI(env); HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_Mulr6(False, True, True, + r_dst, r_srcL, r_srcR)); +#else addInstr(env, MIPSInstr_Mul(r_dst, r_srcL, r_srcR)); +#endif return r_dst; } @@ -1199,8 +1215,13 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) HReg r_dst = newVRegI(env); HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_Mulr6(False, False, True, + r_dst, r_srcL, r_srcR)); +#else addInstr(env, MIPSInstr_Mult(True, r_srcL, r_srcR)); addInstr(env, MIPSInstr_Mflo(r_dst)); +#endif return r_dst; } @@ -1210,6 +1231,12 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) HReg r_tmpR = newVRegI(env); HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_Ext(r_tmpL, r_srcL, 0, 32)); + addInstr(env, MIPSInstr_Ext(r_tmpR, r_srcR, 0, 32)); + addInstr(env, MIPSInstr_Mulr6(True, False, True, + r_tmpR, r_tmpL, r_tmpR)); +#else if (VEX_MIPS_CPU_HAS_MIPS64R2(hwcaps_host)) { addInstr(env, MIPSInstr_Ext(r_tmpL, r_srcL, 0, 32)); addInstr(env, MIPSInstr_Ext(r_tmpR, r_srcR, 0, 32)); @@ -1222,6 +1249,7 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) } addInstr(env, MIPSInstr_Mult(False, r_tmpL, r_tmpR)); addInstr(env, MIPSInstr_Mflo(r_tmpR)); +#endif return r_tmpR; } @@ -1234,6 +1262,25 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) HReg r_dst = newVRegI(env); HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); +#if (__mips_isa_rev >= 6) + if (syned) { + Int no_bits = (e->Iex.Binop.op == Iop_MullS16) ? 16 : 24; + addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, + r_srcL, r_srcL, + MIPSRH_Imm(False, no_bits))); + addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, + r_srcL, r_srcL, + MIPSRH_Imm(False, no_bits))); + addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, + r_srcR, r_srcR, + MIPSRH_Imm(False, no_bits))); + addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, + r_srcR, r_srcR, + MIPSRH_Imm(False, no_bits))); + } + addInstr(env, MIPSInstr_Mulr6(syned, True, True, + r_dst, r_srcL, r_srcR)); +#else if (syned) { Int no_bits = (e->Iex.Binop.op == Iop_MullS16) ? 16 : 24; addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, @@ -1254,6 +1301,7 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) addInstr(env, MIPSInstr_Mult(syned, r_srcL, r_srcR)); addInstr(env, MIPSInstr_Mflo(r_dst)); } +#endif return r_dst; } @@ -1266,6 +1314,33 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) r_srcL = iselDblExpr(env, e->Iex.Binop.arg1); r_srcR = iselDblExpr(env, e->Iex.Binop.arg2); } +#if (__mips_isa_rev >= 6) + HReg tmp = newVRegI(env); + HReg tmpf; + HReg result = newVRegI(env); + if (mode64) tmpf = newVRegF(env); + else tmpf = newVRegD(env); + addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_UN, tmpf, r_srcL, r_srcR)); + addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, tmp, tmpf)); + addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp, + MIPSRH_Imm(False, 0x45))); + addInstr(env, MIPSInstr_Alu(Malu_OR, result, + hregMIPS_GPR0(env->mode64), + MIPSRH_Reg(tmp))); + addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_LT, tmpf, r_srcL, r_srcR)); + addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, tmp, tmpf)); + addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp, + MIPSRH_Imm(False, 0x1))); + addInstr(env, MIPSInstr_Alu(Malu_OR, result, result, + MIPSRH_Reg(tmp))); + addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_EQ, tmpf, r_srcL, r_srcR)); + addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, tmp, tmpf)); + addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp, + MIPSRH_Imm(False, 0x40))); + addInstr(env, MIPSInstr_Alu(Malu_OR, result, result, + MIPSRH_Reg(tmp))); + return result; +#else HReg tmp = newVRegI(env); HReg r_ccMIPS = newVRegI(env); HReg r_ccIR = newVRegI(env); @@ -1339,6 +1414,39 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR, MIPSRH_Reg(r_ccIR_b6))); return r_ccIR; +#endif + } + + if (e->Iex.Binop.op == Iop_CmpF32) { +#if (__mips_isa_rev >= 6) + HReg r_srcL = iselFltExpr(env, e->Iex.Binop.arg1); + HReg r_srcR = iselFltExpr(env, e->Iex.Binop.arg2); + HReg tmp = newVRegI(env); + HReg tmpf; + HReg result = newVRegI(env); + if (mode64) tmpf = newVRegF(env); + else tmpf = newVRegD(env); + addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_UN_S, tmpf, r_srcL, r_srcR)); + addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, tmp, tmpf)); + addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp, + MIPSRH_Imm(False, 0x45))); + addInstr(env, MIPSInstr_Alu(Malu_OR, result, + hregMIPS_GPR0(env->mode64), + MIPSRH_Reg(tmp))); + addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_LT_S, tmpf, r_srcL, r_srcR)); + addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, tmp, tmpf)); + addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp, + MIPSRH_Imm(False, 0x1))); + addInstr(env, MIPSInstr_Alu(Malu_OR, result, result, + MIPSRH_Reg(tmp))); + addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_EQ_S, tmpf, r_srcL, r_srcR)); + addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, tmp, tmpf)); + addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp, + MIPSRH_Imm(False, 0x40))); + addInstr(env, MIPSInstr_Alu(Malu_OR, result, result, + MIPSRH_Reg(tmp))); + return result; +#endif } if (e->Iex.Binop.op == Iop_DivModU32to32 || @@ -1353,11 +1461,20 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); - +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_Divr6(syned /* Unsigned or Signed */ , + True /* 32bit or 64bit div */ , + False /* mod */, + tLo, r_srcL, r_srcR)); + addInstr(env, MIPSInstr_Divr6(syned /* Unsigned or Signed */ , + True /*3 2bit or 64bit div */ , + True /* mod */, + tHi, r_srcL, r_srcR)); +#else addInstr(env, MIPSInstr_Div(syned, True, r_srcL, r_srcR)); addInstr(env, MIPSInstr_Mfhi(tHi)); addInstr(env, MIPSInstr_Mflo(tLo)); - +#endif addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi, MIPSRH_Imm(False, 32))); @@ -1382,8 +1499,13 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) e->Iex.Binop.op == Iop_DivU32); HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_Divr6(syned, div32, False, + r_dst, r_srcL, r_srcR)); +#else addInstr(env, MIPSInstr_Div(syned, div32, r_srcL, r_srcR)); addInstr(env, MIPSInstr_Mflo(r_dst)); +#endif return r_dst; } @@ -1460,6 +1582,24 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) return valS; } + if (e->Iex.Binop.op == Iop_F64toI64S) { + vassert(mode64); + HReg valS = newVRegI(env); + HReg tmpF = newVRegF(env); + HReg valF = iselFltExpr(env, e->Iex.Binop.arg2); + + /* CVTLS tmpF, valF */ + set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); + addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, tmpF, valF)); + set_MIPS_rounding_default(env); + + /* Doubleword Move from Floating Point + dmfc1 valS, tmpF */ + addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmfc1, valS, tmpF)); + + return valS; + } + if (e->Iex.Binop.op == Iop_F64toI32S) { HReg valD; if (mode64) @@ -1638,6 +1778,20 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) return r_dst; } + if (e->Iex.Binop.op == Iop_F32toI32S) { + HReg valS = newVRegF(env); + HReg valF = iselFltExpr(env, e->Iex.Binop.arg2); + HReg r_dst = newVRegI(env); + + set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); + addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWS, valS, valF)); + set_MIPS_rounding_default(env); + + addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, valS)); + + return r_dst; + } + /* -------- DSP ASE -------- */ /* All used cases involving host-side helper calls. */ void* fn = NULL; @@ -2171,8 +2325,17 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) * r_dst = r0 * movn r_dst, r1, r_cond */ +#if (__mips_isa_rev >= 6) + HReg r_temp = newVRegI(env); + addInstr(env, MIPSInstr_MoveCond(MSeleqz, r_dst, r0, r_cond)); + addInstr(env, MIPSInstr_MoveCond(MSelnez, r_temp, r1, r_cond)); + addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst, + MIPSRH_Reg(r_temp))); + +#else addInstr(env, mk_iMOVds_RR(r_dst, r0)); addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dst, r1, r_cond)); +#endif return r_dst; } break; @@ -2230,6 +2393,27 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) return r_dst; } + case Iex_Qop: { + HReg dst = newVRegI(env); + HReg src1 = iselWordExpr_R(env, e->Iex.Qop.details->arg1); + HReg src2 = iselWordExpr_R(env, e->Iex.Qop.details->arg2); + HReg src3 = iselWordExpr_R(env, e->Iex.Qop.details->arg3); + HReg src4 = iselWordExpr_R(env, e->Iex.Qop.details->arg4); + switch (e->Iex.Qop.details->op) { +#if (__mips_isa_rev >= 6) + case Iop_Rotx32: + addInstr(env, MIPSInstr_Bitswap(Rotx32, dst, src1, src2, src3, src4)); + break; + case Iop_Rotx64: + addInstr(env, MIPSInstr_Bitswap(Rotx64, dst, src1, src2, src3, src4)); + break; +#endif + default: + break; + } + return dst; + } + default: break; } /* end switch(e->tag) */ @@ -4662,9 +4846,16 @@ static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64); HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_Mulr6(syned, False, True, + tLo, r_srcL, r_srcR)); + addInstr(env, MIPSInstr_Mulr6(syned, False, False, + tHi, r_srcL, r_srcR)); +#else addInstr(env, MIPSInstr_Mult(syned, r_srcL, r_srcR)); addInstr(env, MIPSInstr_Mfhi(tHi)); addInstr(env, MIPSInstr_Mflo(tLo)); +#endif *rHi = tHi; *rLo = tLo; return; @@ -4683,10 +4874,20 @@ static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, HReg tLo = newVRegI(env); HReg tHi = newVRegI(env); Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to64); - +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_Divr6(syned/*Unsigned or Signed */ , + False /*32bit or 64bit div */ , + False /*mod*/, + tLo, r_srcL, r_srcR)); + addInstr(env, MIPSInstr_Divr6(syned/*Unsigned or Signed */ , + False /*32bit or 64bit div */ , + True /*mod*/, + tHi, r_srcL, r_srcR)); +#else addInstr(env, MIPSInstr_Div(syned, False, r_srcL, r_srcR)); addInstr(env, MIPSInstr_Mfhi(tHi)); addInstr(env, MIPSInstr_Mflo(tLo)); +#endif *rHi = tHi; *rLo = tLo; return; @@ -4798,10 +4999,23 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) * move desHi, expr0Hi * movn desLo, expr1Lo, cond * movn desHi, expr1Hi, cond */ +#if (__mips_isa_rev >= 6) + { + HReg r_temp = newVRegI(env); + addInstr(env, MIPSInstr_MoveCond(MSeleqz, desLo, expr0Lo, cond)); + addInstr(env, MIPSInstr_MoveCond(MSelnez, r_temp, expr1Lo, cond)); + addInstr(env, MIPSInstr_Alu(Malu_OR, desLo, desLo, MIPSRH_Reg(r_temp))); + + addInstr(env, MIPSInstr_MoveCond(MSeleqz, desHi, expr0Hi, cond)); + addInstr(env, MIPSInstr_MoveCond(MSelnez, r_temp, expr1Hi, cond)); + addInstr(env, MIPSInstr_Alu(Malu_OR, desHi, desHi, MIPSRH_Reg(r_temp))); + } +#else addInstr(env, mk_iMOVds_RR(desLo, expr0Lo)); addInstr(env, mk_iMOVds_RR(desHi, expr0Hi)); addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, desLo, expr1Lo, cond)); addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, desHi, expr1Hi, cond)); +#endif *rHi = desHi; *rLo = desLo; @@ -4895,9 +5109,16 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) Bool syned = toBool(op_binop == Iop_MullS32); HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_Mulr6(syned, True, True, + tLo, r_srcL, r_srcR)); + addInstr(env, MIPSInstr_Mulr6(syned, True, False, + tHi, r_srcL, r_srcR)); +#else addInstr(env, MIPSInstr_Mult(syned, r_srcL, r_srcR)); addInstr(env, MIPSInstr_Mfhi(tHi)); addInstr(env, MIPSInstr_Mflo(tLo)); +#endif *rHi = tHi; *rLo = tLo; @@ -4912,9 +5133,20 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) HReg tHi = newVRegI(env); Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS32to32); +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_Divr6(syned /*Unsigned or Signed */ , + True /*32bit or 64bit div */ , + False /*mod*/, + tLo, r_srcL, r_srcR)); + addInstr(env, MIPSInstr_Divr6(syned /*Unsigned or Signed */ , + True /*32bit or 64bit div */ , + True /*mod*/, + tHi, r_srcL, r_srcR)); +#else addInstr(env, MIPSInstr_Div(syned, True, r_srcL, r_srcR)); addInstr(env, MIPSInstr_Mfhi(tHi)); addInstr(env, MIPSInstr_Mflo(tLo)); +#endif *rHi = tHi; *rLo = tLo; return; @@ -4945,7 +5177,6 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) } case Iop_Shr64: { -#if defined (_MIPSEL) /* 64-bit logical shift right based on what gcc generates: : nor v0, zero, a2 @@ -4959,122 +5190,59 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) jr ra movn v1, zero, a0 */ - HReg a0, a1; - HReg a0tmp = newVRegI(env); - HReg a2 = newVRegI(env); + HReg r_srcLo, r_srcHi; + HReg r_srcLotmp = newVRegI(env); + HReg shift = newVRegI(env); HReg a3 = newVRegI(env); - HReg v0 = newVRegI(env); - HReg v1 = newVRegI(env); - HReg zero = newVRegI(env); + HReg r_dstLo = newVRegI(env); + HReg r_dstHi = newVRegI(env); + HReg zero = hregMIPS_GPR0(env->mode64); MIPSRH *sa = NULL; - iselInt64Expr(&a1, &a0, env, e->Iex.Binop.arg1); + iselInt64Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg1); sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2); if (sa->tag == Mrh_Imm) { - addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16)); + addInstr(env, MIPSInstr_LI(shift, sa->Mrh.Imm.imm16)); } else { - addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg, + addInstr(env, MIPSInstr_Alu(Malu_AND, shift, sa->Mrh.Reg.reg, MIPSRH_Imm(False, 0x3f))); } - - addInstr(env, MIPSInstr_LI(zero, 0x00000000)); - /* nor v0, zero, a2 */ - addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2))); - /* sll a3, a1, 0x1 */ + /* nor r_dstLo, zero, shift */ + addInstr(env, MIPSInstr_Alu(Malu_NOR, r_dstLo, zero, MIPSRH_Reg(shift))); + /* sll a3, r_srcHi, 0x1 */ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */, - a3, a1, MIPSRH_Imm(False, 0x1))); - /* sllv a3, a3, v0 */ + a3, r_srcHi, MIPSRH_Imm(False, 0x1))); + /* sllv a3, a3, r_dstLo */ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */, - a3, a3, MIPSRH_Reg(v0))); - /* srlv v0, a0, a2 */ - addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, - v0, a0, MIPSRH_Reg(a2))); - /* srlv v1, a1, a2 */ + a3, a3, MIPSRH_Reg(r_dstLo))); + /* srlv r_dstLo, r_srcLo, shift */ addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, - v1, a1, MIPSRH_Reg(a2))); - /* andi a0, a2, 0x20 */ - addInstr(env, MIPSInstr_Alu(Malu_AND, a0tmp, a2, - MIPSRH_Imm(False, 0x20))); - /* or v0, a3, v0 */ - addInstr(env, MIPSInstr_Alu(Malu_OR, v0, a3, MIPSRH_Reg(v0))); - - /* movn v0, v1, a0 */ - addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v0, v1, a0tmp)); - /* movn v1, zero, a0 */ - addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, zero, a0tmp)); - - *rHi = v1; - *rLo = v0; - return; -#elif defined (_MIPSEB) - /* 64-bit logical shift right based on what gcc generates: - : - nor v0, zero, a2 - sll a3, a0, 0x1 - sllv a3, a3, v0 - srlv v1, a1, a2 - andi v0, a2, 0x20 - or v1, a3, v1 - srlv a2, a0, a2 - movn v1, a2, v0 - movn a2, zero, v0 - jr ra - move v0, a2 - */ - HReg a0, a1; - HReg a2 = newVRegI(env); - HReg a2tmp = newVRegI(env); - HReg a3 = newVRegI(env); - HReg v0 = newVRegI(env); - HReg v1 = newVRegI(env); - HReg zero = newVRegI(env); - MIPSRH *sa = NULL; - - iselInt64Expr(&a0, &a1, env, e->Iex.Binop.arg1); - sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2); - - if (sa->tag == Mrh_Imm) { - addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16)); - } - else { - addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg, - MIPSRH_Imm(False, 0x3f))); - } - - addInstr(env, MIPSInstr_LI(zero, 0x00000000)); - /* nor v0, zero, a2 */ - addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2))); - /* sll a3, a0, 0x1 */ - addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */, - a3, a0, MIPSRH_Imm(False, 0x1))); - /* sllv a3, a3, v0 */ - addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */, - a3, a3, MIPSRH_Reg(v0))); - /* srlv v1, a1, a2 */ + r_dstLo, r_srcLo, MIPSRH_Reg(shift))); + /* srlv r_dstHi, r_srcHi, shift */ addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, - v1, a1, MIPSRH_Reg(a2))); - /* andi v0, a2, 0x20 */ - addInstr(env, MIPSInstr_Alu(Malu_AND, v0, a2, + r_dstHi, r_srcHi, MIPSRH_Reg(shift))); + /* andi r_srcLo, shift, 0x20 */ + addInstr(env, MIPSInstr_Alu(Malu_AND, r_srcLotmp, shift, MIPSRH_Imm(False, 0x20))); - /* or v1, a3, v1 */ - addInstr(env, MIPSInstr_Alu(Malu_OR, v1, a3, MIPSRH_Reg(v1))); - /* srlv a2, a0, a2 */ - addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, - a2tmp, a0, MIPSRH_Reg(a2))); - - /* movn v1, a2, v0 */ - addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, a2tmp, v0)); - /* movn a2, zero, v0 */ - addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, a2tmp, zero, v0)); - /* move v0, a2 */ - addInstr(env, mk_iMOVds_RR(v0, a2tmp)); - - *rHi = v0; - *rLo = v1; - return; + /* or r_dstLo, a3, r_dstLo */ + addInstr(env, MIPSInstr_Alu(Malu_OR, r_dstLo, a3, MIPSRH_Reg(r_dstLo))); +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_MoveCond(MSeleqz, r_dstLo, r_dstLo, r_srcLotmp)); + addInstr(env, MIPSInstr_MoveCond(MSelnez, a3, r_dstHi, r_srcLotmp)); + addInstr(env, MIPSInstr_Alu(Malu_OR, r_dstLo, r_dstLo, MIPSRH_Reg(a3))); + + addInstr(env, MIPSInstr_MoveCond(MSeleqz, r_dstHi, r_dstHi, r_srcLotmp)); +#else + /* movn r_dstLo, r_dstHi, r_srcLo */ + addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dstLo, r_dstHi, r_srcLotmp)); + /* movn r_dstHi, zero, r_srcLo */ + addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dstHi, zero, r_srcLotmp)); #endif + *rHi = r_dstHi; + *rLo = r_dstLo; + return; } case Iop_Shl64: { @@ -5092,54 +5260,57 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) jr ra move v0,a2 */ - HReg a0, a1; - HReg a2 = newVRegI(env); + HReg r_srcLo, r_srcHi; + HReg r_shift = newVRegI(env); HReg a3 = newVRegI(env); - HReg v0 = newVRegI(env); - HReg v1 = newVRegI(env); - HReg zero = newVRegI(env); + HReg r_dstLo = newVRegI(env); + HReg r_dstHi = newVRegI(env); + HReg zero = hregMIPS_GPR0(env->mode64); MIPSRH *sa = NULL; - iselInt64Expr(&a1, &a0, env, e->Iex.Binop.arg1); + iselInt64Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg1); sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2); if (sa->tag == Mrh_Imm) { - addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16)); + addInstr(env, MIPSInstr_LI(r_shift, sa->Mrh.Imm.imm16)); } else { - addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg, + addInstr(env, MIPSInstr_Alu(Malu_AND, r_shift, sa->Mrh.Reg.reg, MIPSRH_Imm(False, 0x3f))); } - - addInstr(env, MIPSInstr_LI(zero, 0x00000000)); - /* nor v0, zero, a2 */ - addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2))); - /* srl a3, a0, 0x1 */ + /* nor r_dstLo, zero, r_shift */ + addInstr(env, MIPSInstr_Alu(Malu_NOR, r_dstLo, zero, MIPSRH_Reg(r_shift))); + /* srl a3, r_srcLo, 0x1 */ addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, - a3, a0, MIPSRH_Imm(False, 0x1))); - /* srlv a3, a3, v0 */ + a3, r_srcLo, MIPSRH_Imm(False, 0x1))); + /* srlv a3, a3, r_dstLo */ addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, - a3, a3, MIPSRH_Reg(v0))); - /* sllv v1, a1, a2 */ + a3, a3, MIPSRH_Reg(r_dstLo))); + /* sllv r_dstHi, r_srcHi, r_shift */ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */, - v1, a1, MIPSRH_Reg(a2))); - /* andi v0, a2, 0x20 */ - addInstr(env, MIPSInstr_Alu(Malu_AND, v0, a2, + r_dstHi, r_srcHi, MIPSRH_Reg(r_shift))); + /* or r_dstHi, a3, r_dstHi */ + addInstr(env, MIPSInstr_Alu(Malu_OR, r_dstHi, a3, MIPSRH_Reg(r_dstHi))); + /* andi a3, r_shift, 0x20 */ + addInstr(env, MIPSInstr_Alu(Malu_AND, a3, r_shift, MIPSRH_Imm(False, 0x20))); - /* or v1, a3, v1 */ - addInstr(env, MIPSInstr_Alu(Malu_OR, v1, a3, MIPSRH_Reg(v1))); - /* sllv a2, a0, a2 */ + /* sllv r_dstLo, r_srcLo, r_shift */ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */, - a2, a0, MIPSRH_Reg(a2))); - - /* movn v1, a2, v0 */ - addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, a2, v0)); - /* movn a2, zero, v0 */ - addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, a2, zero, v0)); - addInstr(env, mk_iMOVds_RR(v0, a2)); + r_dstLo, r_srcLo, MIPSRH_Reg(r_shift))); +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_MoveCond(MSeleqz, r_dstHi, r_dstHi, a3)); + addInstr(env, MIPSInstr_MoveCond(MSelnez, r_shift, r_dstLo, a3)); + addInstr(env, MIPSInstr_Alu(Malu_OR, r_dstHi, r_dstHi, MIPSRH_Reg(r_shift))); - *rHi = v1; - *rLo = v0; + addInstr(env, MIPSInstr_MoveCond(MSeleqz, r_dstLo, r_dstLo, a3)); +#else + /* movn r_dstHi, r_dstLo, a3 */ + addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dstHi, r_dstLo, a3)); + /* movn r_dstLo, zero, a3 */ + addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dstLo, zero, a3)); +#endif + *rHi = r_dstHi; + *rLo = r_dstLo; return; } @@ -5158,58 +5329,64 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) jr ra movn v1, a1, a0 */ - HReg a0, a1; - HReg a0tmp = newVRegI(env); - HReg a1tmp = newVRegI(env); - HReg a2 = newVRegI(env); + HReg r_srcHi, r_srcLo; + HReg r_srcHitmp = newVRegI(env); + HReg r_srcLotmp = newVRegI(env); + HReg r_shift = newVRegI(env); HReg a3 = newVRegI(env); - HReg v0 = newVRegI(env); - HReg v1 = newVRegI(env); - HReg zero = newVRegI(env); + HReg r_dstLo = newVRegI(env); + HReg r_dstHi = newVRegI(env); + HReg zero = hregMIPS_GPR0(env->mode64); MIPSRH *sa = NULL; - iselInt64Expr(&a1, &a0, env, e->Iex.Binop.arg1); + iselInt64Expr(&r_srcLo, &r_srcHi, env, e->Iex.Binop.arg1); sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2); if (sa->tag == Mrh_Imm) { - addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16)); + addInstr(env, MIPSInstr_LI(r_shift, sa->Mrh.Imm.imm16)); } else { - addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg, + addInstr(env, MIPSInstr_Alu(Malu_AND, r_shift, sa->Mrh.Reg.reg, MIPSRH_Imm(False, 0x3f))); } - - addInstr(env, MIPSInstr_LI(zero, 0x00000000)); - /* nor v0, zero, a2 */ - addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2))); - /* sll a3, a1, 0x1 */ + /* nor r_dstLo, zero, r_shift */ + addInstr(env, MIPSInstr_Alu(Malu_NOR, r_dstLo, zero, MIPSRH_Reg(r_shift))); + /* sll a3, r_srcLo, 0x1 */ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */, - a3, a1, MIPSRH_Imm(False, 0x1))); - /* sllv a3, a3, v0 */ + a3, r_srcLo, MIPSRH_Imm(False, 0x1))); + /* sllv a3, a3, r_dstLo */ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */, - a3, a3, MIPSRH_Reg(v0))); - /* srlv v0, a0, a2 */ + a3, a3, MIPSRH_Reg(r_dstLo))); + /* srlv r_dstLo, r_srcHi, r_shift */ addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, - v0, a0, MIPSRH_Reg(a2))); - /* srav v1, a1, a2 */ + r_dstLo, r_srcHi, MIPSRH_Reg(r_shift))); + /* srav r_dstHi, r_srcLo, r_shift */ addInstr(env, MIPSInstr_Shft(Mshft_SRA, True /* 32bit shift */, - v1, a1, MIPSRH_Reg(a2))); - /* andi a0, a2, 0x20 */ - addInstr(env, MIPSInstr_Alu(Malu_AND, a0tmp, a2, + r_dstHi, r_srcLo, MIPSRH_Reg(r_shift))); + /* andi r_srcHi, r_shift, 0x20 */ + addInstr(env, MIPSInstr_Alu(Malu_AND, r_srcHitmp, r_shift, MIPSRH_Imm(False, 0x20))); - /* sra a1, a1, 0x1f */ + /* sra r_srcLo, r_srcLo, 0x1f */ addInstr(env, MIPSInstr_Shft(Mshft_SRA, True /* 32bit shift */, - a1tmp, a1, MIPSRH_Imm(False, 0x1f))); - /* or v0, a3, v0 */ - addInstr(env, MIPSInstr_Alu(Malu_OR, v0, a3, MIPSRH_Reg(v0))); - - /* movn v0, v1, a0 */ - addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v0, v1, a0tmp)); - /* movn v1, a1, a0 */ - addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, a1tmp, a0tmp)); - - *rHi = v1; - *rLo = v0; + r_srcLotmp, r_srcLo, MIPSRH_Imm(False, 0x1f))); + /* or r_dstLo, a3, r_dstLo */ + addInstr(env, MIPSInstr_Alu(Malu_OR, r_dstLo, a3, MIPSRH_Reg(r_dstLo))); +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_MoveCond(MSeleqz, r_dstLo, r_dstLo, r_srcHitmp)); + addInstr(env, MIPSInstr_MoveCond(MSelnez, a3, r_dstHi, r_srcHitmp)); + addInstr(env, MIPSInstr_Alu(Malu_OR, r_dstLo, r_dstLo, MIPSRH_Reg(a3))); + + addInstr(env, MIPSInstr_MoveCond(MSeleqz, r_dstHi, r_dstHi, r_srcHitmp)); + addInstr(env, MIPSInstr_MoveCond(MSelnez, a3, r_srcLotmp, r_srcHitmp)); + addInstr(env, MIPSInstr_Alu(Malu_OR, r_dstHi, r_dstHi, MIPSRH_Reg(a3))); +#else + /* movn r_dstLo, r_dstHi, r_srcHi */ + addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dstLo, r_dstHi, r_srcHitmp)); + /* movn r_dstHi, r_srcLo, r_srcHi */ + addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dstHi, r_srcLotmp, r_srcHitmp)); +#endif + *rHi = r_dstHi; + *rLo = r_dstLo; return; } @@ -5316,6 +5493,21 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) iselInt64Expr(&a_H, &a_L, env, e->Iex.Binop.arg1); iselInt64Expr(&b_H, &b_L, env, e->Iex.Binop.arg2); +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_Mulr6(True, True, True, + dst_H, a_H, b_L)); + addInstr(env, MIPSInstr_Mulr6(True, True, True, + dst_L, b_H, a_L)); + addInstr(env, MIPSInstr_Alu(Malu_ADD, dst_H, dst_H, + MIPSRH_Reg(dst_L))); + addInstr(env, MIPSInstr_Mulr6(False, True, False, + dst_L, a_L, b_L)); + + addInstr(env, MIPSInstr_Alu(Malu_ADD, dst_H, dst_H, + MIPSRH_Reg(dst_L))); + addInstr(env, MIPSInstr_Mulr6(False, True, True, + dst_L, a_L, b_L)); +#else addInstr(env, MIPSInstr_Mul(dst_H, a_H, b_L)); addInstr(env, MIPSInstr_Mult(True, b_H, a_L)); addInstr(env, MIPSInstr_Mflo(dst_L)); @@ -5327,6 +5519,7 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) addInstr(env, MIPSInstr_Alu(Malu_ADD, dst_H, dst_H, MIPSRH_Reg(dst_L))); addInstr(env, MIPSInstr_Mflo(dst_L)); +#endif *rHi = dst_H; *rLo = dst_L; return; @@ -5374,6 +5567,50 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) return; } + case Iop_F64toI64S: { + HReg tmpD = newVRegD(env); + HReg valF; + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + MIPSAMode *am_addr; + + if(mode64){ + valF = iselFltExpr(env, e->Iex.Binop.arg2); + } else { + valF = iselDblExpr(env, e->Iex.Binop.arg2); + } + + /* CVTLS tmpD, valF */ + set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); + addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, tmpD, valF)); + set_MIPS_rounding_default(env); + + sub_from_sp(env, 16); /* Move SP down 16 bytes */ + am_addr = MIPSAMode_IR(0, StackPointer(mode64)); + + /* store as F64 */ + addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, tmpD, + am_addr)); + /* load as 2xI32 */ +#if defined (_MIPSEL) + addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64)); + addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeFloat(am_addr), + mode64)); +#elif defined (_MIPSEB) + addInstr(env, MIPSInstr_Load(4, tHi, am_addr, mode64)); + addInstr(env, MIPSInstr_Load(4, tLo, nextMIPSAModeFloat(am_addr), + mode64)); +#endif + + /* Reset SP */ + add_to_sp(env, 16); + + *rHi = tHi; + *rLo = tLo; + + return; + } + default: break; } @@ -5619,9 +5856,15 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) 64-bit stuff. */ static HReg iselFltExpr(ISelEnv * env, IRExpr * e) { - HReg r = iselFltExpr_wrk(env, e); - vassert(hregIsVirtual(r)); - return r; + HReg r; + IRType ty = typeOfIRExpr(env->type_env, e); + if (ty == Ity_F32 || (ty == Ity_F64 && fp_mode64)) { + r = iselFltExpr_wrk(env, e); + } else { + r = iselDblExpr_wrk(env, e); + vassert(hregClass(r) == HRcFlt64); + } + return r; } /* DO NOT CALL THIS DIRECTLY */ @@ -5854,7 +6097,12 @@ static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e) HReg valF = iselFltExpr(env, e->Iex.Binop.arg2); set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_FpConvert(Mfp_RINTS, valS, valF)); +#else addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWS, valS, valF)); + addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSW, valS, valS)); +#endif set_MIPS_rounding_default(env); return valS; } @@ -5864,7 +6112,13 @@ static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e) HReg valF = iselFltExpr(env, e->Iex.Binop.arg2); set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_FpConvert(Mfp_RINTD, valS, valF)); +#else addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, valS, valF)); + addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDL, valS, valS)); + +#endif set_MIPS_rounding_default(env); return valS; } @@ -5990,7 +6244,43 @@ static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e) return r_dst; } +#if (__mips_isa_rev >= 6) + case Iop_MaxNumF32: { + HReg src1 = iselFltExpr(env, e->Iex.Binop.arg1); + HReg src2 = iselFltExpr(env, e->Iex.Binop.arg2); + HReg dst = newVRegF(env); + addInstr(env, MIPSInstr_FpMinMax(Mfp_MAXS, dst, + src1, src2)); + return dst; + } + + case Iop_MaxNumF64: { + HReg src1 = iselFltExpr(env, e->Iex.Binop.arg1); + HReg src2 = iselFltExpr(env, e->Iex.Binop.arg2); + HReg dst = newVRegF(env); + addInstr(env, MIPSInstr_FpMinMax(Mfp_MAXD, dst, + src1, src2)); + return dst; + } + + case Iop_MinNumF32: { + HReg src1 = iselFltExpr(env, e->Iex.Binop.arg1); + HReg src2 = iselFltExpr(env, e->Iex.Binop.arg2); + HReg dst = newVRegF(env); + addInstr(env, MIPSInstr_FpMinMax(Mfp_MINS, dst, + src1, src2)); + return dst; + } + case Iop_MinNumF64: { + HReg src1 = iselFltExpr(env, e->Iex.Binop.arg1); + HReg src2 = iselFltExpr(env, e->Iex.Binop.arg2); + HReg dst = newVRegF(env); + addInstr(env, MIPSInstr_FpMinMax(Mfp_MIND, dst, + src1, src2)); + return dst; + } +#endif default: break; } @@ -6003,8 +6293,24 @@ static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e) case Iop_MSubF32: case Iop_MSubF64: { Int op = 0; +#if (__mips_isa_rev < 6) MSADFFlx type = 0; +#endif switch (e->Iex.Qop.details->op) { +#if (__mips_isa_rev >= 6) + case Iop_MAddF32: + op = Mfp_MADDS; + break; + case Iop_MAddF64: + op = Mfp_MADDD; + break; + case Iop_MSubF32: + op = Mfp_MSUBS; + break; + case Iop_MSubF64: + op = Mfp_MSUBD; + break; +#else case Iop_MAddF32: op = has_msa ? MSA_FMADD : Mfp_MADDS; type = MSA_F_WH; @@ -6021,6 +6327,7 @@ static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e) op = has_msa ? MSA_FMSUB : Mfp_MSUBD; type = MSA_F_DW; break; +#endif default: vassert(0); } @@ -6029,7 +6336,12 @@ static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e) HReg src1 = iselFltExpr(env, e->Iex.Qop.details->arg2); HReg src2 = iselFltExpr(env, e->Iex.Qop.details->arg3); HReg src3 = iselFltExpr(env, e->Iex.Qop.details->arg4); - +#if (__mips_isa_rev >= 6) + set_MIPS_rounding_mode(env, e->Iex.Qop.details->arg1); + addInstr(env, MIPSInstr_FpTernary(op, dst, + src3, src1, src2)); + set_MIPS_rounding_default(env); +#else if (has_msa) { addInstr(env, MIPSInstr_MsaElm(MSA_MOVE, src3, dst, 0)); set_MIPS_rounding_mode_MSA(env, e->Iex.Qop.details->arg1); @@ -6041,6 +6353,7 @@ static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e) src1, src2, src3)); set_MIPS_rounding_default(env); } +#endif return dst; } @@ -6098,11 +6411,16 @@ static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e) HReg r1 = iselFltExpr(env, e->Iex.ITE.iftrue); HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond); HReg r_dst = newVRegF(env); +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, r_dst, r_cond)); + addInstr(env, MIPSInstr_MoveCond(MFpSeld, r_dst, r0, r1)); +#else addInstr(env, MIPSInstr_FpUnary((ty == Ity_F64) ? Mfp_MOVD : Mfp_MOVS, r_dst, r0)); addInstr(env, MIPSInstr_MoveCond((ty == Ity_F64) ? MFpMoveCond_movnd : MFpMoveCond_movns, r_dst, r1, r_cond)); +#endif return r_dst; } @@ -6210,7 +6528,13 @@ static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e) HReg dst = newVRegD(env); set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_FpConvert(Mfp_RINTD, dst, src)); +#else addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, dst, src)); + addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDL, dst, dst)); + +#endif set_MIPS_rounding_default(env); return dst; @@ -6278,6 +6602,25 @@ static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e) set_MIPS_rounding_default_MSA(env); return r_dst; } +#if (__mips_isa_rev >= 6) + case Iop_MaxNumF64: { + HReg src1 = iselDblExpr(env, e->Iex.Binop.arg1); + HReg src2 = iselDblExpr(env, e->Iex.Binop.arg2); + HReg dst = newVRegD(env); + addInstr(env, MIPSInstr_FpMinMax(Mfp_MAXD, dst, + src1, src2)); + return dst; + } + + case Iop_MinNumF64: { + HReg src1 = iselDblExpr(env, e->Iex.Binop.arg1); + HReg src2 = iselDblExpr(env, e->Iex.Binop.arg2); + HReg dst = newVRegD(env); + addInstr(env, MIPSInstr_FpMinMax(Mfp_MIND, dst, + src1, src2)); + return dst; + } +#endif default: break; @@ -6339,18 +6682,26 @@ static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e) } if (e->tag == Iex_Qop) { - vassert(has_msa); switch (e->Iex.Qop.details->op) { case Iop_MAddF64: case Iop_MSubF64: { MSA3RFOp op = 0; switch (e->Iex.Qop.details->op) { +#if (__mips_isa_rev >= 6) + case Iop_MAddF64: + op = Mfp_MADDD; + break; + case Iop_MSubF64: + op = Mfp_MSUBD; + break; +#else case Iop_MAddF64: op = MSA_FMADD; break; case Iop_MSubF64: op = MSA_FMSUB; break; +#endif default: vassert(0); } @@ -6358,12 +6709,52 @@ static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e) HReg src1 = iselDblExpr(env, e->Iex.Qop.details->arg2); HReg src2 = iselDblExpr(env, e->Iex.Qop.details->arg3); HReg src3 = iselDblExpr(env, e->Iex.Qop.details->arg4); +#if (__mips_isa_rev >= 6) + set_MIPS_rounding_mode(env, e->Iex.Qop.details->arg1); + addInstr(env, MIPSInstr_FpTernary(op, dst, + src3, src1, src2)); + set_MIPS_rounding_default(env); +#else + vassert(has_msa); addInstr(env, MIPSInstr_MsaElm(MSA_MOVE, src3, dst, 0)); set_MIPS_rounding_mode_MSA(env, e->Iex.Qop.details->arg1); addInstr(env, MIPSInstr_Msa3RF(op, MSA_F_DW, dst, src1, src2)); set_MIPS_rounding_default_MSA(env); +#endif return dst; } + case Iop_I64StoF64: { + HReg r_dst = newVRegD(env); + MIPSAMode *am_addr; + HReg tmp, fr_src; + if (mode64) { + tmp = newVRegF(env); + fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2); + /* Move SP down 8 bytes */ + sub_from_sp(env, 8); + am_addr = MIPSAMode_IR(0, StackPointer(mode64)); + + /* store as I64 */ + addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64)); + + /* load as Ity_F64 */ + addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr)); + + /* Reset SP */ + add_to_sp(env, 8); + } else { + HReg Hi, Lo; + tmp = newVRegD(env); + iselInt64Expr(&Hi, &Lo, env, e->Iex.Binop.arg2); + tmp = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */ + } + + set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); + addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDL, r_dst, tmp)); + set_MIPS_rounding_default(env); + + return r_dst; + } default: break; @@ -6378,10 +6769,14 @@ static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e) HReg r1 = iselDblExpr(env, e->Iex.ITE.iftrue); HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond); HReg r_dst = newVRegD(env); - +#if (__mips_isa_rev >= 6) + addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, r_dst, r_cond)); + addInstr(env, MIPSInstr_MoveCond(MFpSeld, r_dst, r0, r1)); +#else addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, r_dst, r0)); addInstr(env, MIPSInstr_MoveCond(MFpMoveCond_movnd, r_dst, r1, r_cond)); +#endif return r_dst; } } @@ -6501,11 +6896,19 @@ static void iselStmt(ISelEnv * env, IRStmt * stmt) } if (ty == Ity_F64) { - HReg fr_src = iselFltExpr(env, stmt->Ist.Put.data); - MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset, - GuestStatePointer(mode64)); - addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src, - am_addr)); + if (mode64) { + HReg fr_src = iselFltExpr(env, stmt->Ist.Put.data); + MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset, + GuestStatePointer(mode64)); + addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src, + am_addr)); + } else { + HReg fr_src = iselDblExpr(env, stmt->Ist.Put.data); + MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset, + GuestStatePointer(mode64)); + addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src, + am_addr)); + } return; } if (ty == Ity_V128) { diff --git a/VEX/pub/libvex.h b/VEX/pub/libvex.h index 24e5c98a6c..93aaf43e24 100644 --- a/VEX/pub/libvex.h +++ b/VEX/pub/libvex.h @@ -252,6 +252,10 @@ typedef /* Check if the processor supports MIPS64R2. */ #define VEX_MIPS_CPU_HAS_MIPS64R2(x) (VEX_MIPS_EX_INFO(x) & \ VEX_MIPS_CPU_ISA_M64R2) +/* Check if the processor supports MIPSR6. */ +#define VEX_MIPS_CPU_HAS_MIPSR6(x) (VEX_MIPS_EX_INFO(x) & \ + (VEX_MIPS_CPU_ISA_M32R6 | \ + VEX_MIPS_CPU_ISA_M64R6)) /* Check if the processor supports DSP ASE Rev 2. */ #define VEX_MIPS_PROC_DSP2(x) ((VEX_MIPS_COMP_ID(x) == VEX_PRID_COMP_MIPS) && \ (VEX_MIPS_PROC_ID(x) == VEX_PRID_IMP_74K)) @@ -426,8 +430,8 @@ typedef itself? True => descriptor, False => code. */ Bool host_ppc_calls_use_fndescrs; - /* ??? Description ??? */ - Bool guest_mips_fp_mode64; + /* MIPS32/MIPS64 GUESTS only: emulated FPU mode. */ + UInt guest_mips_fp_mode; } VexAbiInfo; diff --git a/VEX/pub/libvex_guest_mips32.h b/VEX/pub/libvex_guest_mips32.h index c9291e9ede..5a9d43279a 100644 --- a/VEX/pub/libvex_guest_mips32.h +++ b/VEX/pub/libvex_guest_mips32.h @@ -150,11 +150,10 @@ typedef /* 480 */ ULong guest_ac3; /* 488 */ UInt guest_CP0_status; + /* 492 */ UInt guest_CP0_Config5; - /* 492 */ UInt guest_LLaddr; - /* 496 */ UInt guest_LLdata; - - /* 500 */ UInt _padding2; + /* 496 */ UInt guest_LLaddr; + /* 500 */ UInt guest_LLdata; /* MIPS32 MSA 128-bit vector registers */ /* 504 */ V128 guest_w0; @@ -208,6 +207,9 @@ void LibVEX_GuestMIPS32_initialise ( /*OUT*/VexGuestMIPS32State* vex_state ); /* FR bit of CP0_STATUS_FR register */ #define MIPS_CP0_STATUS_FR (1ul << 26) +/* FRE bit of CP0_Config5 register */ +#define MIPS_CONF5_FRE (1ul << 8) + #endif /* ndef __LIBVEX_PUB_GUEST_MIPS32_H */