From: Dejan Jevtic Date: Thu, 25 Jul 2013 09:08:03 +0000 (+0000) Subject: mips32: Add support for mips32 DSP instruction set. X-Git-Tag: svn/VALGRIND_3_9_0^2~63 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=06b6b3f37acee89d192c5db2b0dc4e755313a97c;p=thirdparty%2Fvalgrind.git mips32: Add support for mips32 DSP instruction set. Add support for mips32 DSP and DSP revision 2 ASE. More details about the mips32 DSP(r2) ASE: http://www.mips.com/media/files/MD00566-2B-MIPSDSP-QRC-01.00.pdf Applied patch provided by Maja Gagic git-svn-id: svn://svn.valgrind.org/vex/trunk@2732 --- diff --git a/VEX/priv/guest_mips_helpers.c b/VEX/priv/guest_mips_helpers.c index f390389819..80ee906e94 100644 --- a/VEX/priv/guest_mips_helpers.c +++ b/VEX/priv/guest_mips_helpers.c @@ -164,6 +164,13 @@ void LibVEX_GuestMIPS32_initialise( /*OUT*/ VexGuestMIPS32State * vex_state) vex_state->guest_NRADDR = 0; vex_state->guest_COND = 0; + + /* MIPS32 DSP ASE(r2) specific registers */ + vex_state->guest_DSPControl = 0; /* DSPControl register */ + vex_state->guest_ac0 = 0; /* Accumulator 0 */ + vex_state->guest_ac1 = 0; /* Accumulator 1 */ + vex_state->guest_ac2 = 0; /* Accumulator 2 */ + vex_state->guest_ac3 = 0; /* Accumulator 3 */ } void LibVEX_GuestMIPS64_initialise ( /*OUT*/ VexGuestMIPS64State * vex_state ) @@ -274,11 +281,11 @@ void LibVEX_GuestMIPS64_initialise ( /*OUT*/ VexGuestMIPS64State * vex_state ) /* Figure out if any part of the guest state contained in minoff .. maxoff requires precise memory exceptions. If in doubt return - True (but this generates significantly slower code). + True (but this generates significantly slower code). We enforce precise exns for guest SP, PC. - Only SP is needed in mode VexRegUpdSpAtMemAccess. + Only SP is needed in mode VexRegUpdSpAtMemAccess. */ Bool guest_mips32_state_requires_precise_mem_exns(Int minoff, Int maxoff) { @@ -1057,7 +1064,7 @@ ULong mips64_dirtyhelper_dmfc0 ( UInt rd, UInt sel ) break; } break; - + default: break; } diff --git a/VEX/priv/guest_mips_toIR.c b/VEX/priv/guest_mips_toIR.c index 551faee06b..6db5b85fac 100644 --- a/VEX/priv/guest_mips_toIR.c +++ b/VEX/priv/guest_mips_toIR.c @@ -395,8 +395,31 @@ static UInt floatGuestRegOffset(UInt fregNo) return ret; } -/* Do a endian load of a 32-bit word, regardless of the - endianness of the underlying host. */ +/* ---------------- MIPS32 DSP ASE(r2) accumulators ---------------- */ + +static UInt accumulatorGuestRegOffset(UInt acNo) +{ + vassert(!mode64); + vassert(acNo <= 3); + UInt ret; + switch (acNo) { + case 0: + ret = offsetof(VexGuestMIPS32State, guest_ac0); break; + case 1: + ret = offsetof(VexGuestMIPS32State, guest_ac1); break; + case 2: + ret = offsetof(VexGuestMIPS32State, guest_ac2); break; + case 3: + ret = offsetof(VexGuestMIPS32State, guest_ac3); break; + default: + vassert(0); + break; + } + return ret; +} + +/* Do a endian load of a 32-bit word, regardless of the endianness of the + underlying host. */ static inline UInt getUInt(UChar * p) { UInt w = 0; @@ -449,7 +472,7 @@ static inline UInt getUInt(UChar * p) t4 = newTemp(Ity_I32); \ assign(t4, mkNarrowTo32( ty, binop(Iop_And64, \ mkexpr(t1), mkU64(0x3)))); - + #define LWX_SWX_PATTERN64_1 \ t2 = newTemp(Ity_I64); \ assign(t2, binop(Iop_And64, mkexpr(t1), mkU64(0xFFFFFFFFFFFFFFF8ULL))); \ @@ -641,6 +664,43 @@ static UInt get_sel(UInt mipsins) return (0x00000007 & mipsins); } +/* Get acc number for all MIPS32 DSP ASE(r2) instructions that use them, + except for MFHI and MFLO. */ +static UInt get_acNo(UInt mipsins) +{ + return (0x00001800 & mipsins) >> 11; +} + +/* Get accumulator number for MIPS32 DSP ASEr2 MFHI and MFLO instructions. */ +static UInt get_acNo_mfhilo(UInt mipsins) +{ + return (0x00600000 & mipsins) >> 21; +} + +/* Get mask field (helper function for wrdsp instruction). */ +static UInt get_wrdspMask(UInt mipsins) +{ + return (0x001ff800 & mipsins) >> 11; +} + +/* Get mask field (helper function for rddsp instruction). */ +static UInt get_rddspMask(UInt mipsins) +{ + return (0x03ff0000 & mipsins) >> 16; +} + +/* Get shift field (helper function for DSP ASE instructions). */ +static UInt get_shift(UInt mipsins) +{ + return (0x03f00000 & mipsins) >> 20; +} + +/* Get immediate field for DSP ASE instructions. */ +static UInt get_dspImm(UInt mipsins) +{ + return (0x03ff0000 & mipsins) >> 16; +} + static Bool branch_or_jump(UChar * addr) { UInt fmt; @@ -651,7 +711,7 @@ static Bool branch_or_jump(UChar * addr) UInt function = get_function(cins); /* bgtz, blez, bne, beq, jal */ - if (opcode == 0x07 || opcode == 0x06 || opcode == 0x05 || opcode == 0x04 + if (opcode == 0x07 || opcode == 0x06 || opcode == 0x05 || opcode == 0x04 || opcode == 0x03 || opcode == 0x02) { return True; } @@ -694,6 +754,11 @@ static Bool branch_or_jump(UChar * addr) } } + /* bposge32 */ + if (opcode == 0x01 && rt == 0x1c) { + return True; + } + return False; } @@ -767,13 +832,19 @@ static IRExpr *mkU8(UInt i) return IRExpr_Const(IRConst_U8((UChar) i)); } -/* Create an expression node for a 32-bit integer constant */ +/* Create an expression node for a 16-bit integer constant. */ +static IRExpr *mkU16(UInt i) +{ + return IRExpr_Const(IRConst_U16(i)); +} + +/* Create an expression node for a 32-bit integer constant. */ static IRExpr *mkU32(UInt i) { return IRExpr_Const(IRConst_U32(i)); } -/* Create an expression node for a 64-bit integer constant */ +/* Create an expression node for a 64-bit integer constant. */ static IRExpr *mkU64(ULong i) { return IRExpr_Const(IRConst_U64(i)); @@ -864,6 +935,11 @@ static IRExpr *genRORV32(IRExpr * src, IRExpr * rs) binop(Iop_Shr32, src, mkexpr(t0))); } +static UShort extend_s_10to16(UInt x) +{ + return (UShort) ((((Int) x) << 22) >> 22); +} + static UInt extend_s_16to32(UInt x) { return (UInt) ((((Int) x) << 16) >> 16); @@ -911,6 +987,34 @@ static void jmp_lit64 ( /*MOD*/ DisResult* dres, IRJumpKind kind, Addr64 d64 ) stmt(IRStmt_Put(OFFB_PC, mkU64(d64))); } +/* Get value from accumulator (helper function for MIPS32 DSP ASE instructions). + This function should be called before any other operation if widening + multiplications are used. */ +static IRExpr *getAcc(UInt acNo) +{ + vassert(!mode64); + vassert(acNo <= 3); + return IRExpr_Get(accumulatorGuestRegOffset(acNo), Ity_I64); +} + +/* Get value from DSPControl register (helper function for MIPS32 DSP ASE + instructions). */ +static IRExpr *getDSPControl(void) +{ + vassert(!mode64); + return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_DSPControl), Ity_I32); +} + +/* Put value to DSPControl register. Expression e is written to DSPControl as + is. If only certain bits of DSPControl need to be changed, it should be done + before calling putDSPControl(). It could be done by reading DSPControl and + ORing it with appropriate mask. */ +static void putDSPControl(IRExpr * e) +{ + vassert(!mode64); + stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_DSPControl), e)); +} + /* Fetch a byte from the guest insn stream. */ static UChar getIByte(Int delta) { @@ -993,18 +1097,53 @@ static void putIReg(UInt archreg, IRExpr * e) static void putLO(IRExpr * e) { - if (mode64) + if (mode64) { stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_LO), e)); - else + } else { stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_LO), e)); + /* Add value to lower 32 bits of ac0 to maintain compatibility between + regular MIPS32 instruction set and MIPS DSP ASE. Keep higher 32bits + unchanged. */ + IRTemp t_lo = newTemp(Ity_I32); + IRTemp t_hi = newTemp(Ity_I32); + assign(t_lo, e); + assign(t_hi, unop(Iop_64HIto32, getAcc(0))); + stmt(IRStmt_Put(accumulatorGuestRegOffset(0), + binop(Iop_32HLto64, mkexpr(t_hi), mkexpr(t_lo)))); + } } static void putHI(IRExpr * e) { - if (mode64) + if (mode64) { stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_HI), e)); - else + } else { stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_HI), e)); + /* Add value to higher 32 bits of ac0 to maintain compatibility between + regular MIPS32 instruction set and MIPS DSP ASE. Keep lower 32bits + unchanged. */ + IRTemp t_lo = newTemp(Ity_I32); + IRTemp t_hi = newTemp(Ity_I32); + assign(t_hi, e); + assign(t_lo, unop(Iop_64to32, getAcc(0))); + stmt(IRStmt_Put(accumulatorGuestRegOffset(0), + binop(Iop_32HLto64, mkexpr(t_hi), mkexpr(t_lo)))); + } +} + +/* Put value to accumulator(helper function for MIPS32 DSP ASE instructions). */ +static void putAcc(UInt acNo, IRExpr * e) +{ + vassert(!mode64); + vassert(acNo <= 3); + vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64); + stmt(IRStmt_Put(accumulatorGuestRegOffset(acNo), e)); +/* If acNo = 0, split value to HI and LO regs in order to maintain compatibility + between MIPS32 and MIPS DSP ASE insn sets. */ + if (0 == acNo) { + putLO(unop(Iop_64to32, e)); + putHI(unop(Iop_64HIto32, e)); + } } static IRExpr *mkNarrowTo8 ( IRType ty, IRExpr * src ) @@ -1088,9 +1227,9 @@ static IRExpr *dis_branch_likely(IRExpr * guard, UInt imm) IRTemp t0; /* PC = PC + (SignExtend(signed_immed_24) << 2) - An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) + 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 + 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); @@ -1104,7 +1243,7 @@ static IRExpr *dis_branch_likely(IRExpr * guard, UInt imm) stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring, IRConst_U64(guest_PC_curr_instr + 8), OFFB_PC)); else - stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring, + stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring, IRConst_U32(guest_PC_curr_instr + 8), OFFB_PC)); irsb->jumpkind = Ijk_Boring; @@ -1128,9 +1267,9 @@ static void dis_branch(Bool link, IRExpr * guard, UInt imm, IRStmt ** set) } /* PC = PC + (SignExtend(signed_immed_24) << 2) - An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) + 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 + the branch (not the branch itself), in the branch delay slot, to form a PC-relative effective target address. */ if (mode64) @@ -1221,7 +1360,7 @@ static void setFPUCondCode(IRExpr * e, UInt cc) putFCSR(binop(Iop_And32, getFCSR(), mkU32(0xFF7FFFFF))); putFCSR(binop(Iop_Or32, getFCSR(), binop(Iop_Shl32, e, mkU8(23)))); } else { - putFCSR(binop(Iop_And32, getFCSR(), unop(Iop_Not32, + putFCSR(binop(Iop_And32, getFCSR(), unop(Iop_Not32, binop(Iop_Shl32, mkU32(0x01000000), mkU8(cc))))); putFCSR(binop(Iop_Or32, getFCSR(), binop(Iop_Shl32, e, mkU8(24 + cc)))); } @@ -1229,7 +1368,7 @@ static void setFPUCondCode(IRExpr * e, UInt cc) static IRExpr* get_IR_roundingmode ( void ) { -/* +/* rounding mode | MIPS | IR ------------------------ to nearest | 00 | 00 @@ -1270,7 +1409,7 @@ static IRConst *mkSzConst ( IRType ty, ULong imm64 ) static Addr64 mkSzAddr ( IRType ty, Addr64 addr ) { vassert(ty == Ity_I32 || ty == Ity_I64); - return (ty == Ity_I64 ? (Addr64) addr : + return (ty == Ity_I64 ? (Addr64) addr : (Addr64) extend_s_32to64(toUInt(addr))); } @@ -1515,11 +1654,11 @@ static Bool dis_instr_CCondFmt ( UInt cins ) */ /* ccMIPS = Shl(1, (~(ccIR>>5) & 2) | ((ccIR ^ (ccIR>>6)) & 1) */ - assign(ccMIPS, binop(Iop_Shl32, mkU32(1), unop(Iop_32to8, + assign(ccMIPS, binop(Iop_Shl32, mkU32(1), unop(Iop_32to8, binop(Iop_Or32, binop(Iop_And32, unop(Iop_Not32, binop(Iop_Shr32, mkexpr(ccIR),mkU8(5))),mkU32(2)), binop(Iop_And32, binop(Iop_Xor32, mkexpr(ccIR), - binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))), + binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))), mkU32(1)))))); putLO(mkWidenFrom32(Ity_I64, mkexpr(ccMIPS), True)); @@ -1589,7 +1728,7 @@ static Bool dis_instr_CCondFmt ( UInt cins ) case 0xF: setFPUCondCode(mkexpr(t2), fpc_cc); break; - + default: return False; } @@ -1612,12 +1751,12 @@ static Bool dis_instr_CCondFmt ( UInt cins ) */ /* ccMIPS = Shl(1, (~(ccIR>>5) & 2) | ((ccIR ^ (ccIR>>6)) & 1) */ - assign(ccMIPS, binop(Iop_Shl32, mkU32(1), unop(Iop_32to8, + assign(ccMIPS, binop(Iop_Shl32, mkU32(1), unop(Iop_32to8, binop(Iop_Or32, binop(Iop_And32, unop(Iop_Not32, binop(Iop_Shr32, mkexpr(ccIR), mkU8(5))), mkU32(2)), binop(Iop_And32, binop(Iop_Xor32, mkexpr(ccIR), - binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))), + binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))), mkU32(1)))))); /* UN */ assign(t0, binop(Iop_And32, mkexpr(ccMIPS), mkU32(0x1))); @@ -1686,7 +1825,7 @@ static Bool dis_instr_CCondFmt ( UInt cins ) case 0xF: setFPUCondCode(mkexpr(t2), fpc_cc); break; - + default: return False; } @@ -1717,7 +1856,7 @@ static Bool dis_instr_CCondFmt ( UInt cins ) binop(Iop_And32, binop(Iop_Xor32, mkexpr(ccIR), binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))), mkU32(1)))))); - + /* UN */ assign(t0, binop(Iop_And32, mkexpr(ccMIPS), mkU32(0x1))); /* EQ */ @@ -1904,14 +2043,9079 @@ static Bool dis_instr_branch ( UInt theInstr, DisResult * dres, jmpKind = Ijk_Call; break; } - + + } + break; + default: + return False; + } + *set = IRStmt_Exit(eCond, jmpKind, mkSzConst(ty, addrTgt), OFFB_PC); + return True; +} + +/*------------------------------------------------------------*/ +/*--- Disassemble a single DSP ASE instruction ---*/ +/*------------------------------------------------------------*/ + +static UInt disDSPInstr_MIPS_WRK ( UInt cins ) +{ + IRTemp t0, t1 = 0, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, + t15, t16, t17, t18; + UInt opcode, rs, rt, rd, sa, function, ac, ac_mfhilo, rddsp_mask, + wrdsp_mask, dsp_imm, shift; + + opcode = get_opcode(cins); + rs = get_rs(cins); + rt = get_rt(cins); + rd = get_rd(cins); + sa = get_sa(cins); + function = get_function(cins); + ac = get_acNo(cins); + ac_mfhilo = get_acNo_mfhilo(cins); + rddsp_mask = get_rddspMask(cins); + wrdsp_mask = get_wrdspMask(cins); + dsp_imm = get_dspImm(cins); + shift = get_shift(cins); + + switch (opcode) { + case 0x00: { /* Special */ + switch (function) { + case 0x10: { /* MFHI */ + DIP("mfhi ac%d r%d", ac_mfhilo, rd); + putIReg(rd, unop(Iop_64HIto32, getAcc(ac_mfhilo))); + break; + } + + case 0x11: { /* MTHI */ + DIP("mthi ac%d r%d", ac, rs); + t1 = newTemp(Ity_I32); + assign(t1, unop(Iop_64to32, getAcc(ac))); + putAcc(ac, binop(Iop_32HLto64, getIReg(rs), mkexpr(t1))); + break; + } + + case 0x12: { /* MFLO */ + DIP("mflo ac%d r%d", ac_mfhilo, rd); + putIReg(rd, unop(Iop_64to32, getAcc(ac_mfhilo))); + break; + } + + case 0x13: { /* MTLO */ + DIP("mtlo ac%d r%d", ac, rs); + t1 = newTemp(Ity_I32); + assign(t1, unop(Iop_64HIto32, getAcc(ac))); + putAcc(ac, binop(Iop_32HLto64, mkexpr(t1), getIReg(rs))); + break; + } + + case 0x18: { /* MULT */ + DIP("mult ac%d r%d, r%d", ac, rs, rt); + t1 = newTemp(Ity_I64); + assign(t1, binop(Iop_MullS32, mkNarrowTo32(Ity_I32, getIReg(rs)), + mkNarrowTo32(Ity_I32, getIReg(rt)))); + putAcc(ac, mkexpr(t1)); + break; + } + + case 0x19: { /* MULTU */ + DIP("multu ac%d r%d, r%d", ac, rs, rt); + t1 = newTemp(Ity_I64); + assign(t1, binop(Iop_MullU32, mkNarrowTo32(Ity_I32, getIReg(rs)), + mkNarrowTo32(Ity_I32, + getIReg(rt)))); + putAcc(ac, mkexpr(t1)); + break; + } + } + break; + } + case 0x1C: { /* Special2 */ + switch (function) { + case 0x00: { /* MADD */ + DIP("madd ac%d, r%d, r%d", ac, rs, rt); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + + assign(t1, getAcc(ac)); + assign(t2, binop(Iop_MullS32, getIReg(rs), getIReg(rt))); + assign(t3, binop(Iop_Add64, mkexpr(t1), mkexpr(t2))); + + putAcc(ac, mkexpr(t3)); + break; + } + case 0x01: { /* MADDU */ + DIP("maddu ac%d r%d, r%d", ac, rs, rt); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + + assign(t1, getAcc(ac)); + assign(t2, binop(Iop_MullU32, getIReg(rs), getIReg(rt))); + assign(t3, binop(Iop_Add64, mkexpr(t2), mkexpr(t1))); + + putAcc(ac, mkexpr(t3)); + break; + } + case 0x04: { /* MSUB */ + DIP("msub ac%d r%d, r%d", ac, rs, rt); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + + assign(t1, getAcc(ac)); + assign(t2, binop(Iop_MullS32, getIReg(rs), getIReg(rt))); + assign(t3, binop(Iop_Sub64, mkexpr(t1), mkexpr(t2))); + + putAcc(ac, mkexpr(t3)); + break; + } + case 0x05: { /* MSUBU */ + DIP("msubu ac%d r%d, r%d", ac, rs, rt); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + + assign(t1, getAcc(ac)); + assign(t2, binop(Iop_MullU32, getIReg(rs), getIReg(rt))); + assign(t3, binop(Iop_Sub64, mkexpr(t1), mkexpr(t2))); + + putAcc(ac, mkexpr(t3)); + break; + } + } + break; + } + case 0x1F: { /* Special3 */ + switch (function) { + case 0x12: { /* ABSQ_S.PH */ + switch (sa) { + case 0x1: { /* ABSQ_S.QB */ + DIP("absq_s.qb r%d, r%d", rd, rt); + vassert(!mode64); + t0 = newTemp(Ity_I8); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I8); + t4 = newTemp(Ity_I8); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I8); + t8 = newTemp(Ity_I8); + t9 = newTemp(Ity_I1); + t10 = newTemp(Ity_I1); + t11 = newTemp(Ity_I8); + t12 = newTemp(Ity_I8); + t13 = newTemp(Ity_I1); + t14 = newTemp(Ity_I1); + t15 = newTemp(Ity_I8); + t16 = newTemp(Ity_I32); + t17 = newTemp(Ity_I32); + + /* Absolute value of the rightmost byte (bits 7-0). */ + /* t0 - rightmost byte. */ + assign(t0, unop(Iop_16to8, unop(Iop_32to16, getIReg(rt)))); + /* t1 holds 1 if t0 is equal to 0x80, or 0 otherwise. */ + assign(t1, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, mkexpr(t0)), + mkU32(0x00000080))); + /* t2 holds 1 if value in t0 is negative, 0 otherwise. */ + assign(t2, unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00000080)), + mkU8(0x7)))); + /* t3 holds abs(t0). */ + assign(t3, IRExpr_ITE(mkexpr(t1), + mkU8(0x7F), + IRExpr_ITE(mkexpr(t2), + binop(Iop_Add8, + unop(Iop_Not8, + mkexpr(t0)), + mkU8(0x1)), + mkexpr(t0)))); + + /* Absolute value of bits 15-8. */ + /* t4 - input byte. */ + assign(t4, + unop(Iop_16HIto8, unop(Iop_32to16, getIReg(rt)))); + /* t5 holds 1 if t4 is equal to 0x80, or 0 otherwise. */ + assign(t5, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, mkexpr(t4)), + mkU32(0x00000080))); + /* t6 holds 1 if value in t4 is negative, 0 otherwise. */ + assign(t6, unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00008000)), + mkU8(15)))); + /* t3 holds abs(t4). */ + assign(t7, IRExpr_ITE(mkexpr(t5), + mkU8(0x7F), + IRExpr_ITE(mkexpr(t6), + binop(Iop_Add8, + unop(Iop_Not8, + mkexpr(t4)), + mkU8(0x1)), + mkexpr(t4)))); + + /* Absolute value of bits 23-15. */ + /* t8 - input byte. */ + assign(t8, + unop(Iop_16to8, unop(Iop_32HIto16, getIReg(rt)))); + /* t9 holds 1 if t8 is equal to 0x80, or 0 otherwise. */ + assign(t9, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, mkexpr(t8)), + mkU32(0x00000080))); + /* t6 holds 1 if value in t8 is negative, 0 otherwise. */ + assign(t10, unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00800000)), + mkU8(23)))); + /* t3 holds abs(t8). */ + assign(t11, IRExpr_ITE(mkexpr(t9), + mkU8(0x7F), + IRExpr_ITE(mkexpr(t10), + binop(Iop_Add8, + unop(Iop_Not8, + mkexpr(t8)), + mkU8(0x1)), + mkexpr(t8)))); + + /* Absolute value of bits 31-24. */ + /* t12 - input byte. */ + assign(t12, + unop(Iop_16HIto8, unop(Iop_32HIto16, getIReg(rt)))); + /* t13 holds 1 if t12 is equal to 0x80, or 0 otherwise. */ + assign(t13, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, mkexpr(t12)), + mkU32(0x00000080))); + /* t14 holds 1 if value in t12 is negative, 0 otherwise. */ + assign(t14, unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31)))); + /* t15 holds abs(t12). */ + assign(t15, IRExpr_ITE(mkexpr(t13), + mkU8(0x7F), + IRExpr_ITE(mkexpr(t14), + binop(Iop_Add8, + unop(Iop_Not8, + mkexpr(t12)), + mkU8(0x1)), + mkexpr(t12)))); + + /* t16 holds !0 if any of input bytes is 0x80 or 0 + otherwise. */ + assign(t16, + binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t13)), + unop(Iop_1Sto32, mkexpr(t9))), + unop(Iop_1Sto32, mkexpr(t5))), + unop(Iop_1Sto32, mkexpr(t1)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t16), + mkU32(0x0)), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)))); + + /* t17 = t15|t11|t7|t3 */ + assign(t17, + binop(Iop_16HLto32, + binop(Iop_8HLto16, mkexpr(t15), mkexpr(t11)), + binop(Iop_8HLto16, mkexpr(t7), mkexpr(t3)))); + + putIReg(rd, mkexpr(t17)); + break; + } + case 0x2: { /* REPL.QB */ + DIP("repl.qb r%d, %d", rd, dsp_imm); + vassert(!mode64); + + putIReg(rd, mkU32((dsp_imm << 24) | (dsp_imm << 16) | + (dsp_imm << 8) | (dsp_imm))); + break; + } + case 0x3: { /* REPLV.QB */ + DIP("replv.qb r%d, r%d", rd, rt); + vassert(!mode64); + t0 = newTemp(Ity_I8); + + assign(t0, unop(Iop_32to8, + binop(Iop_And32, getIReg(rt), mkU32(0xff)))); + putIReg(rd, + binop(Iop_16HLto32, + binop(Iop_8HLto16, mkexpr(t0), mkexpr(t0)), + binop(Iop_8HLto16, mkexpr(t0), mkexpr(t0)))); + break; + } + case 0x4: { /* PRECEQU.PH.QBL */ + DIP("precequ.ph.qbl r%d, r%d", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xff000000)), + mkU8(1)), + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00ff0000)), + mkU8(9)))); + break; + } + case 0x5: { /* PRECEQU.PH.QBR */ + DIP("precequ.ph.qbr r%d, r%d", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x0000ff00)), + mkU8(15)), + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x000000ff)), + mkU8(7)))); + break; + } + case 0x6: { /* PRECEQU.PH.QBLA */ + DIP("precequ.ph.qbla r%d, r%d", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xff000000)), + mkU8(1)), + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x0000ff00)), + mkU8(1)))); + break; + } + case 0x7: { /* PRECEQU.PH.QBRA */ + DIP("precequ.ph.qbra r%d, r%d", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00ff0000)), + mkU8(7)), + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x000000ff)), + mkU8(7)))); + break; + } + case 0x9: { /* ABSQ_S.PH */ + DIP("absq_s.ph r%d, r%d", rd, rt); + vassert(!mode64); + t0 = newTemp(Ity_I16); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I16); + t4 = newTemp(Ity_I16); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I16); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + + /* t0 holds lower 16 bits of value in rt. */ + assign(t0, unop(Iop_32to16, getIReg(rt))); + /* t1 holds 1 if t0 is equal to 0x8000. */ + assign(t1, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, mkexpr(t0)), + mkU32(0x00008000))); + /* t2 holds 1 if value in t0 is negative, 0 otherwise. */ + assign(t2, unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00008000)), + mkU8(15)))); + /* t3 holds abs(t0). */ + assign(t3, IRExpr_ITE(mkexpr(t1), + mkU16(0x7FFF), + IRExpr_ITE(mkexpr(t2), + binop(Iop_Add16, + unop(Iop_Not16, + mkexpr(t0)), + mkU16(0x1)), + mkexpr(t0)))); + + /* t4 holds lower 16 bits of value in rt. */ + assign(t4, unop(Iop_32HIto16, getIReg(rt))); + /* t5 holds 1 if t4 is equal to 0x8000. */ + assign(t5, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, mkexpr(t4)), + mkU32(0x00008000))); + /* t6 holds 1 if value in t4 is negative, 0 otherwise. */ + assign(t6, unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31)))); + /* t7 holds abs(t4). */ + assign(t7, IRExpr_ITE(mkexpr(t5), + mkU16(0x7FFF), + IRExpr_ITE(mkexpr(t6), + binop(Iop_Add16, + unop(Iop_Not16, + mkexpr(t4)), + mkU16(0x1)), + mkexpr(t4)))); + /* If any of the two input halfwords is equal 0x8000, + set bit 20 in DSPControl register. */ + assign(t8, binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t5)), + unop(Iop_1Sto32, mkexpr(t1)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t8), + mkU32(0x0)), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)))); + + /* t9 = t7|t3 */ + assign(t9, binop(Iop_16HLto32, mkexpr(t7), mkexpr(t3))); + + putIReg(rd, mkexpr(t9)); + break; + } + case 0xA: { /* REPL.PH */ + DIP("repl.ph r%d, %d", rd, dsp_imm); + vassert(!mode64); + UShort immediate = extend_s_10to16(dsp_imm); + + putIReg(rd, mkU32(immediate << 16 | immediate)); + break; + } + case 0xB: { /* REPLV.PH */ + DIP("replv.ph r%d, r%d", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, getIReg(rt)), + unop(Iop_32to16, getIReg(rt)))); + break; + } + case 0xC: { /* PRECEQ.W.PHL */ + DIP("preceq.w.phl r%d, r%d", rd, rt); + vassert(!mode64); + putIReg(rd, binop(Iop_And32, + getIReg(rt), + mkU32(0xffff0000))); + break; + } + case 0xD: { /* PRECEQ.W.PHR */ + DIP("preceq.w.phr r%d, r%d", rd, rt); + vassert(!mode64); + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, getIReg(rt)), + mkU16(0x0))); + break; + } + case 0x11: { /* ABSQ_S.W */ + DIP("absq_s.w r%d, r%d", rd, rt); + vassert(!mode64); + t0 = newTemp(Ity_I1); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + + assign(t0, + binop(Iop_CmpEQ32, getIReg(rt), mkU32(0x80000000))); + + putDSPControl(IRExpr_ITE(mkexpr(t0), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + assign(t1, binop(Iop_CmpLT32S, getIReg(rt), mkU32(0x0))); + + assign(t2, IRExpr_ITE(mkexpr(t0), + mkU32(0x7FFFFFFF), + IRExpr_ITE(mkexpr(t1), + binop(Iop_Add32, + unop(Iop_Not32, + getIReg(rt)), + mkU32(0x1)), + getIReg(rt)))); + putIReg(rd, mkexpr(t2)); + break; + } + case 0x1B: { /* BITREV */ + DIP("bitrev r%d, r%d", rd, rt); + vassert(!mode64); + /* 32bit reversal as seen on Bit Twiddling Hacks site + http://graphics.stanford.edu/~seander/bithacks.html + section ReverseParallel */ + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + + assign(t1, binop(Iop_Or32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xaaaaaaaa)), + mkU8(0x1)), + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x55555555)), + mkU8(0x1)))); + assign(t2, binop(Iop_Or32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t1), + mkU32(0xcccccccc)), + mkU8(0x2)), + binop(Iop_Shl32, + binop(Iop_And32, + mkexpr(t1), + mkU32(0x33333333)), + mkU8(0x2)))); + assign(t3, binop(Iop_Or32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0xf0f0f0f0)), + mkU8(0x4)), + binop(Iop_Shl32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x0f0f0f0f)), + mkU8(0x4)))); + assign(t4, binop(Iop_Or32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t3), + mkU32(0xff00ff00)), + mkU8(0x8)), + binop(Iop_Shl32, + binop(Iop_And32, + mkexpr(t3), + mkU32(0x00ff00ff)), + mkU8(0x8)))); + assign(t5, binop(Iop_Or32, + binop(Iop_Shr32, + mkexpr(t4), + mkU8(0x10)), + binop(Iop_Shl32, + mkexpr(t4), + mkU8(0x10)))); + putIReg(rd, binop(Iop_Shr32, + mkexpr(t5), + mkU8(16))); + break; + } + case 0x1C: { /* PRECEU.PH.QBL */ + DIP("preceu.ph.qbl r%d, r%d", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xff000000)), + mkU8(8)), + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00ff0000)), + mkU8(16)))); + break; + } + case 0x1E: { /* PRECEU.PH.QBLA */ + DIP("preceu.ph.qbla r%d, r%d", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xff000000)), + mkU8(8)), + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x0000ff00)), + mkU8(8)))); + break; + } + case 0x1D: { /* PRECEU.PH.QBR */ + DIP("preceu.ph.qbr r%d, r%d", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x0000ff00)), + mkU8(8)), + binop(Iop_And32, + getIReg(rt), + mkU32(0x000000ff)))); + break; + } + case 0x1F: { /* PRECEU.PH.QBRA */ + DIP("preceu.ph.qbra r%d, r%d", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00ff0000)), + binop(Iop_And32, + getIReg(rt), + mkU32(0x000000ff)))); + break; + } + default: + return -1; + } + break; /* end of ABSQ_S.PH */ + } + case 0x38: { /* EXTR.W */ + switch(sa) { + case 0x0: { /* EXTR.W */ + DIP("extr.w r%d, ac%d, %d", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + + assign(t0, getAcc(ac)); + assign(t1, binop(Iop_Sar64, mkexpr(t0), mkU8(rs))); + putIReg(rt, unop(Iop_64to32, mkexpr(t1))); + + assign(t2, binop(Iop_Or32, + getDSPControl(), mkU32(0x00800000))); + + /* Check if signOut == signIn */ + assign(t3, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t0)), + mkU32(0x80000000)), + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000))), + getDSPControl(), + mkexpr(t2))); + + assign(t4, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0x0)), + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0xffffffff)), + mkexpr(t2), + mkexpr(t3)), + mkexpr(t3))); + putDSPControl(mkexpr(t4)); + break; + } + case 0x1: { /* EXTRV.W */ + DIP("extrv.w r%d, ac%d, r%d", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I1); + + assign(t0, getAcc(ac)); + assign(t1, binop(Iop_Sar64, + mkexpr(t0), + unop(Iop_32to8, + binop(Iop_And32, + getIReg(rs), + mkU32(0x1f))))); + putIReg(rt, unop(Iop_64to32, mkexpr(t1))); + + assign(t2, binop(Iop_Or32, + getDSPControl(), mkU32(0x00800000))); + + /* Check if signOut == signIn */ + assign(t3, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t0)), + mkU32(0x80000000)), + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000))), + getDSPControl(), + mkexpr(t2))); + assign(t4, binop(Iop_CmpNE32, + unop(Iop_64HIto32, mkexpr(t1)), + mkU32(0xffffffff))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0x0)), + IRExpr_ITE(mkexpr(t4), + mkexpr(t2), + mkexpr(t3)), + mkexpr(t3))); + break; + } + case 0x2: { /* EXTP */ + DIP("extp r%d, ac%d, %d", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I8); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I32); + + assign(t0, getAcc(ac)); + /* Extract pos field of DSPControl register. */ + assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); + + /* Check if (pos - size) >= 0 [size <= pos] + if (pos < size) + put 1 to EFI field of DSPControl register + else + extract bits from acc and put 0 to EFI field of + DSPCtrl */ + assign(t2, binop(Iop_CmpLT32U, mkexpr(t1), mkU32(rs))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffbfff)), + mkU32(0x4000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffbfff)))); + + /* If pos <= 31, shift right the value from the acc + (pos-size) times and take (size+1) bits from the least + significant positions. Otherwise, shift left the value + (63-pos) times, take (size+1) bits from the most + significant positions and shift right (31-size) times.*/ + assign(t3, binop(Iop_CmpLE32U, mkexpr(t1), mkU32(31))); + + assign(t4, + IRExpr_ITE(mkexpr(t3), + unop(Iop_32to8, + binop(Iop_Sub32, + mkexpr(t1), mkU32(rs))), + unop(Iop_32to8, + binop(Iop_Sub32, + mkU32(63), mkexpr(t1))))); + + assign(t5, IRExpr_ITE(mkexpr(t3), + binop(Iop_Shr64, + mkexpr(t0), mkexpr(t4)), + binop(Iop_Shl64, + mkexpr(t0), mkexpr(t4)))); + + /* t6 holds a mask for bit extraction */ + assign(t6, + IRExpr_ITE(mkexpr(t3), + unop(Iop_Not64, + binop(Iop_Shl64, + mkU64(0xffffffffffffffffULL), + mkU8(rs+1))), + unop(Iop_Not64, + binop(Iop_Shr64, + mkU64(0xffffffffffffffffULL), + mkU8(rs+1))))); + + assign(t7, IRExpr_ITE(mkexpr(t3), + unop(Iop_64to32, + binop(Iop_And64, + mkexpr(t5), + mkexpr(t6))), + binop(Iop_Shr32, + unop(Iop_64HIto32, + binop(Iop_And64, + mkexpr(t5), + mkexpr(t6))), + mkU8(31-rs)))); + + putIReg(rt, mkexpr(t7)); + break; + } + case 0x3: { /* EXTPV */ + DIP("extpv r%d, ac%d, r%d", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I8); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t8, binop(Iop_And32, getIReg(rs), mkU32(0x1f))); + assign(t0, getAcc(ac)); + /* Extract pos field of DSPControl register. */ + assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); + + /* Check if (pos - size) >= 0 [size <= pos] + if (pos < size) + put 1 to EFI field of DSPControl register + else + extract bits from acc and put 0 to EFI field of + DSPCtrl */ + assign(t2, binop(Iop_CmpLT32U, mkexpr(t1), mkexpr(t8))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffbfff)), + mkU32(0x4000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffbfff)))); + + /* If pos <= 31, shift right the value from the acc + (pos-size) times and take (size+1) bits from the least + significant positions. Otherwise, shift left the value + (63-pos) times, take (size+1) bits from the most + significant positions and shift right (31-size) + times. */ + assign(t3, binop(Iop_CmpLE32U, mkexpr(t1), mkU32(31))); + + assign(t4, + IRExpr_ITE(mkexpr(t3), + unop(Iop_32to8, + binop(Iop_Sub32, + mkexpr(t1), mkexpr(t8))), + unop(Iop_32to8, + binop(Iop_Sub32, + mkU32(63), mkexpr(t1))))); + + assign(t5, IRExpr_ITE(mkexpr(t3), + binop(Iop_Shr64, + mkexpr(t0), mkexpr(t4)), + binop(Iop_Shl64, + mkexpr(t0), mkexpr(t4)))); + + /* t6 holds a mask for bit extraction. */ + assign(t6, + IRExpr_ITE(mkexpr(t3), + unop(Iop_Not64, + binop(Iop_Shl64, + mkU64(0xffffffffffffffffULL), + unop(Iop_32to8, + binop(Iop_Add32, + mkexpr(t8), + mkU32(1))))), + unop(Iop_Not64, + binop(Iop_Shr64, + mkU64(0xffffffffffffffffULL), + unop(Iop_32to8, + binop(Iop_Add32, + mkexpr(t8), + mkU32(1))))))); + + assign(t7, IRExpr_ITE(mkexpr(t3), + unop(Iop_64to32, + binop(Iop_And64, + mkexpr(t5), + mkexpr(t6))), + binop(Iop_Shr32, + unop(Iop_64HIto32, + binop(Iop_And64, + mkexpr(t5), + mkexpr(t6))), + unop(Iop_32to8, + binop(Iop_Sub32, + mkU32(31), + mkexpr(t8)))))); + + putIReg(rt, mkexpr(t7)); + break; + } + case 0x4: { /* EXTR_R.W */ + DIP("extr_r.w r%d, ac%d, %d", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + if (0 == rs) { + putIReg(rt, unop(Iop_64to32, mkexpr(t0))); + } else { + assign(t1, binop(Iop_Sar64, mkexpr(t0), mkU8(rs))); + + assign(t2, binop(Iop_Or32, + getDSPControl(), mkU32(0x800000))); + + putDSPControl(IRExpr_ITE( + binop(Iop_CmpNE32, + unop(Iop_64HIto32, mkexpr(t1)), + mkU32(0x0)), + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0xffffffff)), + mkexpr(t2), + getDSPControl()), + getDSPControl())); + + assign(t4, binop(Iop_Or32, + getDSPControl(), mkU32(0x800000))); + /* If the last discarded bit is 1, there would be carry + when rounding, otherwise there wouldn't. We use that + fact and just add the value of the last discarded bit + to the least sifgnificant bit of the shifted value + from acc. */ + assign(t5, binop(Iop_Shr64, + binop(Iop_And64, + mkexpr(t0), + binop(Iop_Shl64, + mkU64(0x1ULL), + mkU8(rs-1))), + mkU8(rs-1))); + + assign(t6, binop(Iop_Add64, mkexpr(t1), mkexpr(t5))); + + putDSPControl(IRExpr_ITE( + binop(Iop_CmpNE32, + unop(Iop_64HIto32, mkexpr(t6)), + mkU32(0x0)), + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0xffffffff)), + mkexpr(t4), + getDSPControl()), + getDSPControl())); + putIReg(rt, unop(Iop_64to32, mkexpr(t6))); + } + break; + } + case 0x5: { /* EXTRV_R.W */ + DIP("extrv_r.w r%d, ac%d, r%d", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Sar64, + mkexpr(t0), + unop(Iop_32to8, + binop(Iop_And32, + getIReg(rs), + mkU32(0x1f))))); + + assign(t2, binop(Iop_Or32, + getDSPControl(), mkU32(0x00800000))); + + putDSPControl(IRExpr_ITE( + binop(Iop_CmpNE32, + unop(Iop_64HIto32, mkexpr(t1)), + mkU32(0x0)), + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0xffffffff)), + mkexpr(t2), + getDSPControl()), + getDSPControl())); + + assign(t4, binop(Iop_Or32, + getDSPControl(), mkU32(0x00800000))); + /* If the last discarded bit is 1, there would be carry + when rounding, otherwise there wouldn't. We use that + fact and just add the value of the last discarded bit to + the least sifgnificant bit of the shifted value from + acc. */ + assign(t5, binop(Iop_Shr64, + binop(Iop_And64, + mkexpr(t0), + binop(Iop_Shl64, + mkU64(0x1ULL), + unop(Iop_32to8, + binop(Iop_Sub32, + binop(Iop_And32, + getIReg(rs), + mkU32(0x1f)), + mkU32(0x1))))), + unop(Iop_32to8, + binop(Iop_Sub32, + binop(Iop_And32, + getIReg(rs), + mkU32(0x1f)), + mkU32(0x1))))); + + assign(t6, binop(Iop_Add64, mkexpr(t1), mkexpr(t5))); + + putDSPControl(IRExpr_ITE( + binop(Iop_CmpNE32, + unop(Iop_64HIto32, mkexpr(t6)), + mkU32(0x0)), + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0xffffffff)), + mkexpr(t4), + getDSPControl()), + getDSPControl())); + putIReg(rt, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rs), + mkU32(0x1f)), + mkU32(0x0)), + unop(Iop_64to32, mkexpr(t0)), + unop(Iop_64to32, mkexpr(t6)))); + break; + } + case 0x6: { /* EXTR_RS.W */ + DIP("extr_rs.w r%d, ac%d, %d", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + + if (0 != rs) { + assign(t0, getAcc(ac)); + assign(t1, binop(Iop_Sar64, mkexpr(t0), mkU8(rs))); + putDSPControl(IRExpr_ITE( + binop(Iop_CmpNE32, + unop(Iop_64HIto32, mkexpr(t1)), + mkU32(0x0)), + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0xffffffff)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl()), + getDSPControl())); + /* If the last discarded bit is 1, there would be carry + when rounding, otherwise there wouldn't. We use that + fact and just add the value of the last discarded bit + to the least sifgnificant bit of the shifted value + from acc. */ + assign(t2, binop(Iop_Add64, + mkexpr(t1), + binop(Iop_Shr64, + binop(Iop_And64, + mkexpr(t0), + binop(Iop_Shl64, + mkU64(0x1ULL), + unop(Iop_32to8, + mkU32(rs-1)))), + unop(Iop_32to8, mkU32(rs-1))))); + assign(t6, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t2)), + mkU32(0xffffffff)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t2)), + mkU32(0x0)), + mkexpr(t6), + getDSPControl())); + assign(t3, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t2)), + mkU32(0x80000000)), + mkU32(0x0)), + mkU32(0x7fffffff), + mkU32(0x80000000))); + assign(t4, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t2)), + mkU32(0xffffffff)), + mkexpr(t3), + unop(Iop_64to32, mkexpr(t2)))); + assign(t5, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t2)), + mkU32(0x0)), + mkexpr(t4), + unop(Iop_64to32, mkexpr(t2)))); + putIReg(rt, mkexpr(t5)); + } else { + putIReg(rt, unop(Iop_64to32, getAcc(ac))); + } + break; + } + case 0x7: { /* EXTRV_RS.W */ + DIP("extrv_rs.w r%d, ac%d, r%d", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I32); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Sar64, + mkexpr(t0), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x1f))))); + + assign(t2, binop(Iop_Or32, + getDSPControl(), mkU32(0x00800000))); + + assign(t10, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0x0)), + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0xffffffff)), + mkexpr(t2), + getDSPControl()), + getDSPControl())); + + putDSPControl(mkexpr(t10)); + + assign(t4, binop(Iop_Or32, + getDSPControl(), mkU32(0x00800000))); + /* If the last discarded bit is 1, there would be carry + when rounding, otherwise there wouldn't. We use that + fact and just add the value of the last discarded bit to + the least sifgnificant bit of the shifted value from + acc. */ + assign(t5, binop(Iop_Shr64, + binop(Iop_And64, + mkexpr(t0), + binop(Iop_Shl64, + mkU64(0x1ULL), + unop(Iop_32to8, + binop(Iop_Sub32, + binop(Iop_And32, + getIReg(rs), + mkU32(0x1f)), + mkU32(0x1))))), + unop(Iop_32to8, + binop(Iop_Sub32, + binop(Iop_And32, + getIReg(rs), + mkU32(0x1f)), + mkU32(0x1))))); + + assign(t6, binop(Iop_Add64, mkexpr(t1), mkexpr(t5))); + + assign(t8, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0xffffffff)), + mkexpr(t4), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0x0)), + mkexpr(t8), + getDSPControl())); + assign(t9, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0x80000000)), + mkU32(0x0)), + mkU32(0x7fffffff), + mkU32(0x80000000))); + assign(t7, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, mkexpr(t6)), + mkU32(0x0)), + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0xffffffff)), + mkexpr(t9), + unop(Iop_64to32, + mkexpr(t6))), + unop(Iop_64to32, mkexpr(t6)))); + putIReg(rt, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rs), + mkU32(0x1f)), + mkU32(0x0)), + unop(Iop_64to32, mkexpr(t0)), + mkexpr(t7))); + break; + } + case 0xA: { /* EXTPDP */ + DIP("extpdp r%d, ac%d, %d", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I8); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t0, getAcc(ac)); + /* Extract pos field of DSPControl register. */ + assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); + + /* Check if (pos - size) >= 0 [size <= pos] + if (pos < size) + put 1 to EFI field of DSPControl register + else + extract bits from acc and put 0 to EFI field of + DSPCtrl */ + assign(t2, binop(Iop_CmpLT32U, mkexpr(t1), mkU32(rs))); + + assign(t8, binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffbfc0)), + binop(Iop_And32, + binop(Iop_Sub32, + binop(Iop_And32, + getDSPControl(), + mkU32(0x3f)), + mkU32(rs+1)), + mkU32(0x3f)))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffbfff)), + mkU32(0x4000)), + mkexpr(t8))); + + /* If pos <= 31, shift right the value from the acc + (pos-size) times and take (size+1) bits from the least + significant positions. Otherwise, shift left the value + (63-pos) times, take (size+1) bits from the most + significant positions and shift right (31-size) times. + */ + assign(t3, binop(Iop_CmpLE32U, mkexpr(t1), mkU32(31))); + + assign(t4, + IRExpr_ITE(mkexpr(t3), + unop(Iop_32to8, + binop(Iop_Sub32, + mkexpr(t1), mkU32(rs))), + unop(Iop_32to8, + binop(Iop_Sub32, + mkU32(63), mkexpr(t1))))); + + assign(t5, IRExpr_ITE(mkexpr(t3), + binop(Iop_Shr64, + mkexpr(t0), mkexpr(t4)), + binop(Iop_Shl64, + mkexpr(t0), mkexpr(t4)))); + + /* t6 holds a mask for bit extraction. */ + assign(t6, + IRExpr_ITE(mkexpr(t3), + unop(Iop_Not64, + binop(Iop_Shl64, + mkU64(0xffffffffffffffffULL), + mkU8(rs+1))), + unop(Iop_Not64, + binop(Iop_Shr64, + mkU64(0xffffffffffffffffULL), + mkU8(rs+1))))); + + assign(t7, IRExpr_ITE(mkexpr(t3), + unop(Iop_64to32, + binop(Iop_And64, + mkexpr(t5), + mkexpr(t6))), + binop(Iop_Shr32, + unop(Iop_64HIto32, + binop(Iop_And64, + mkexpr(t5), + mkexpr(t6))), + mkU8(31-rs)))); + + putIReg(rt, mkexpr(t7)); + break; + } + case 0xB: { /* EXTPDPV */ + DIP("extpdpv r%d, ac%d, r%d", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I8); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + + assign(t8, binop(Iop_And32, getIReg(rs), mkU32(0x1f))); + assign(t0, getAcc(ac)); + /* Extract pos field of DSPControl register. */ + assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); + + /* Check if (pos - size) >= 0 [size <= pos] + if (pos < size) + put 1 to EFI field of DSPControl register + else + extract bits from acc and put 0 to EFI field of + DSPCtrl */ + assign(t2, binop(Iop_CmpLT32U, mkexpr(t1), mkexpr(t8))); + + assign(t9, binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffbfc0)), + binop(Iop_And32, + binop(Iop_Sub32, + binop(Iop_And32, + getDSPControl(), + mkU32(0x3f)), + binop(Iop_Add32, + mkexpr(t8), + mkU32(0x1))), + mkU32(0x3f)))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffbfff)), + mkU32(0x4000)), + mkexpr(t9))); + + /* If pos <= 31, shift right the value from the acc + (pos-size) times and take (size+1) bits from the least + significant positions. Otherwise, shift left the value + (63-pos) times, take (size+1) bits from the most + significant positions and shift right (31-size) times. + */ + assign(t3, binop(Iop_CmpLE32U, mkexpr(t1), mkU32(31))); + + assign(t4, + IRExpr_ITE(mkexpr(t3), + unop(Iop_32to8, + binop(Iop_Sub32, + mkexpr(t1), mkexpr(t8))), + unop(Iop_32to8, + binop(Iop_Sub32, + mkU32(63), mkexpr(t1))))); + + assign(t5, IRExpr_ITE(mkexpr(t3), + binop(Iop_Shr64, + mkexpr(t0), mkexpr(t4)), + binop(Iop_Shl64, + mkexpr(t0), mkexpr(t4)))); + + /* t6 holds a mask for bit extraction. */ + assign(t6, + IRExpr_ITE(mkexpr(t3), + unop(Iop_Not64, + binop(Iop_Shl64, + mkU64(0xffffffffffffffffULL), + unop(Iop_32to8, + binop(Iop_Add32, + mkexpr(t8), + mkU32(1))))), + unop(Iop_Not64, + binop(Iop_Shr64, + mkU64(0xffffffffffffffffULL), + unop(Iop_32to8, + binop(Iop_Add32, + mkexpr(t8), + mkU32(1))))))); + + assign(t7, IRExpr_ITE(mkexpr(t3), + unop(Iop_64to32, + binop(Iop_And64, + mkexpr(t5), + mkexpr(t6))), + binop(Iop_Shr32, + unop(Iop_64HIto32, + binop(Iop_And64, + mkexpr(t5), + mkexpr(t6))), + unop(Iop_32to8, + binop(Iop_Sub32, + mkU32(31), + mkexpr(t8)))))); + + putIReg(rt, mkexpr(t7)); + break; + } + case 0xE: { /* EXTR_S.H */ + DIP("extr_s.h r%d, ac%d, %d", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I64); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I1); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Sar64, mkexpr(t0), mkU8(rs))); + + assign(t2, binop(Iop_Or32, + getDSPControl(), mkU32(0x00800000))); + + assign(t9, binop(Iop_Shl32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t1)), + mkU32(0x00008000)), + mkU8(16))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t9), + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t0)), + mkU32(0x80000000))), + mkexpr(t2), + getDSPControl())); + + /* Check if t1 > 0x7fff ((t1 - 0x7fff) > 0) + 1. subtract 0x7fff from t1 + 2. if the resulting number is positive (sign bit = 0) + and any of the other bits is 1, the value is > 0. */ + assign(t3, binop(Iop_Sub64, + mkexpr(t1), + mkU64(0x0000000000007fffULL))); + assign(t4, binop(Iop_Or32, + unop(Iop_1Uto32, + binop(Iop_CmpNE32, + mkU32(0), + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t3)), + mkU32(0x7fffffff)))), + unop(Iop_1Uto32, + binop(Iop_CmpNE32, + mkU32(0), + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t3)), + mkU32(0xffffffff)))))); + + assign(t5, IRExpr_ITE(unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t3)), + mkU32(0x80000000)), + mkU8(31))), + unop(Iop_64to32, mkexpr(t1)), + IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t4), + mkU32(0x0)), + mkU32(0x7fff), + unop(Iop_64to32, + mkexpr(t1))))); + + assign(t10, unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t3)), + mkU32(0x80000000)), + mkU8(31)))); + putDSPControl(IRExpr_ITE(mkexpr(t10), + getDSPControl(), + IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t4), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl()))); + + /* Check if t1<0xffffffffffff8000 (0xffffffffffff8000-t1)>0 + 1. subtract t1 from 0x7fff + 2. if the resulting number is positive (sign bit = 0) + and any of the other bits is 1, the value is > 0 */ + assign(t6, binop(Iop_Sub64, + mkU64(0xffffffffffff8000ULL), + mkexpr(t1))); + + assign(t7, binop(Iop_Or32, + unop(Iop_1Uto32, + binop(Iop_CmpNE32, + mkU32(0), + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0x7fffffff)))), + unop(Iop_1Uto32, + binop(Iop_CmpNE32, + mkU32(0), + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t6)), + mkU32(0xffffffff)))))); + + assign(t8, IRExpr_ITE(unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0x80000000)), + mkU8(31))), + unop(Iop_64to32, mkexpr(t1)), + IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t7), + mkU32(0x0)), + mkU32(0xffff8000), + unop(Iop_64to32, + mkexpr(t1))))); + putDSPControl(IRExpr_ITE(unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0x80000000)), + mkU8(31))), + getDSPControl(), + IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t7), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl()))); + + /* If the shifted value is positive, it can only be >0x7fff + and the final result is the value stored in t5, + otherwise, the final result is in t8. */ + putIReg(rt, IRExpr_ITE(unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0x80000000)), + mkU8(31))), + mkexpr(t8), + mkexpr(t5))); + break; + } + case 0xF: { /* EXTRV_S.H */ + DIP("extrv_s.h r%d, ac%d, %d", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I64); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I32); + t11 = newTemp(Ity_I32); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Sar64, + mkexpr(t0), + unop(Iop_32to8, + binop(Iop_And32, + getIReg(rs), + mkU32(0x1f))))); + + assign(t2, binop(Iop_Or32, + getDSPControl(), mkU32(0x00800000))); + + assign(t9, binop(Iop_Shl32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t1)), + mkU32(0x00008000)), + mkU8(16))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t9), + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t0)), + mkU32(0x80000000))), + mkexpr(t2), + getDSPControl())); + + /* Check if t1 > 0x7fff ((t1 - 0x7fff) > 0) + 1. subtract 0x7fff from t1 + 2. if the resulting number is positive (sign bit = 0) + and any of the other bits is 1, the value is > 0 */ + assign(t3, binop(Iop_Sub64, + mkexpr(t1), + mkU64(0x0000000000007fffULL))); + assign(t4, binop(Iop_Or32, + unop(Iop_1Uto32, + binop(Iop_CmpNE32, + mkU32(0), + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t3)), + mkU32(0x7fffffff)))), + unop(Iop_1Uto32, + binop(Iop_CmpNE32, + mkU32(0), + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t3)), + mkU32(0xffffffff)))))); + + assign(t5, IRExpr_ITE(unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t3)), + mkU32(0x80000000)), + mkU8(31))), + unop(Iop_64to32, mkexpr(t1)), + IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t4), + mkU32(0x0)), + mkU32(0x7fff), + unop(Iop_64to32, + mkexpr(t1))))); + + assign(t10, binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t3)), + mkU32(0x80000000)), + mkU8(31))); + assign(t11, IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t4), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(unop(Iop_32to1, + mkexpr(t10)), + getDSPControl(), + mkexpr(t11))); + + /* Check if t1<0xffffffffffff8000 + 1. subtract t1 from 0x7fff + 2. if the resulting number is positive (sign bit == 0) + and any of the other bits is 1, the value is > 0 */ + assign(t6, binop(Iop_Sub64, + mkU64(0xffffffffffff8000ULL), + mkexpr(t1))); + + assign(t7, binop(Iop_Or32, + unop(Iop_1Uto32, + binop(Iop_CmpNE32, + mkU32(0), + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0x7fffffff)))), + unop(Iop_1Uto32, + binop(Iop_CmpNE32, + mkU32(0), + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t6)), + mkU32(0xffffffff)))))); + + assign(t8, IRExpr_ITE(unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0x80000000)), + mkU8(31))), + unop(Iop_64to32, mkexpr(t1)), + IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t7), + mkU32(0x0)), + mkU32(0xffff8000), + unop(Iop_64to32, + mkexpr(t1))))); + putDSPControl(IRExpr_ITE(unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0x80000000) + ), + mkU8(31))), + getDSPControl(), + IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t7), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000) + ), + getDSPControl()))); + + /* If the shifted value is positive, it can only be >0x7fff + and the final result is the value stored in t5, + otherwise, the final result is in t8. */ + putIReg(rt, IRExpr_ITE(unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0x80000000)), + mkU8(31))), + mkexpr(t8), + mkexpr(t5))); + break; + } + case 0x12: { /* RDDSP*/ + DIP("rddsp r%d, mask 0x%x", rd, rddsp_mask); + vassert(!mode64); + + putIReg(rd, mkU32(0x0)); + + if ((rddsp_mask & 0b000001) == 0b000001) { + /* Read pos field (bits 5-0) of DSPControl register. */ + putIReg(rd, binop(Iop_Or32, + getIReg(rd), + binop(Iop_And32, + getDSPControl(), + mkU32(0x0000003F)))); + } + + if ((rddsp_mask & 0b000010) == 0b000010) { + /* Read scount field (bits 12-7) of DSPControl + register. */ + putIReg(rd, binop(Iop_Or32, + getIReg(rd), + binop(Iop_And32, + getDSPControl(), + mkU32(0x00001F80)))); + } + + if ((rddsp_mask & 0b000100) == 0b000100) { + /* Read C field (bit 13) of DSPControl register. */ + putIReg(rd, binop(Iop_Or32, + getIReg(rd), + binop(Iop_And32, + getDSPControl(), + mkU32(0x00002000)))); + } + + if ((rddsp_mask & 0b001000) == 0b001000) { + /* Read outflag field (bit s 23-16) of DSPControl + register. */ + putIReg(rd, binop(Iop_Or32, + getIReg(rd), + binop(Iop_And32, + getDSPControl(), + mkU32(0x00FF0000)))); + } + + if ((rddsp_mask & 0b010000) == 0b010000) { + /* Read ccond field (bits 31-24) of DSPControl + register. */ + putIReg(rd, binop(Iop_Or32, + getIReg(rd), + binop(Iop_And32, + getDSPControl(), + mkU32(0xFF000000)))); + } + + if ((rddsp_mask & 0b100000) == 0b100000) { + /* Read EFI field (bit 14) of DSPControl register. */ + putIReg(rd, binop(Iop_Or32, + getIReg(rd), + binop(Iop_And32, + getDSPControl(), + mkU32(0x00004000)))); + } + + if ((rddsp_mask & 0b111111) == 0b111111) { + /* Read all fields of DSPControl register. */ + putIReg(rd, getDSPControl()); + } + break; + } + case 0x13: { /* WRDSP */ + DIP("wrdsp r%d, mask 0x%x", rs, wrdsp_mask); + vassert(!mode64); + + if ((wrdsp_mask & 0b111111) == 0b111111) { + /* If mips64 put all fields of rs, except bit 15 and bit + 6, to DSPControl register, otherwise put all except + bits 15, 6 and bits 31..28. */ + putDSPControl(mode64 ? + binop(Iop_And32, + getIReg(rs), + mkU32(0xffff7fbf)) : + binop(Iop_And32, + getIReg(rs), + mkU32(0x0fff7fbf))); + } else { + if ((wrdsp_mask & 0b000001) == 0b000001) { + /* Put bits 5-0 of rs to DSPControl register pos + field. */ + putDSPControl(binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xFFFF7F40)), + binop(Iop_And32, + getIReg(rs), + mkU32(0x0000003F)))); + } + + if ((wrdsp_mask & 0b000010) == 0b000010) { + /* Put bits 12-7 of rs to DSPControl scount field. */ + putDSPControl(binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xFFFFE03F)), + binop(Iop_And32, + getIReg(rs), + mkU32(0x00001F80)))); + } + + if ((wrdsp_mask & 0b000100) == 0b000100) { + /* Put bit 13 of rs to DSPControl register C + field. */ + putDSPControl(binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xFFFF5FBF)), + binop(Iop_And32, + getIReg(rs), + mkU32(0x00002000)))); + } + + if ((wrdsp_mask & 0b001000) == 0b001000) { + /* Put bits 23-16 of rs to DSPControl reg outflag + field. */ + putDSPControl(binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xFF007FBF)), + binop(Iop_And32, + getIReg(rs), + mkU32(0x00FF0000)))); + } + + if ((wrdsp_mask & 0b010000) == 0b010000) { + /* Put bits 31-24 of rs to DSPControl reg ccond + field. */ + putDSPControl(binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0x00FF7FBF)), + binop(Iop_And32, + getIReg(rs), + mode64 ? mkU32(0xFF000000) + : mkU32(0x0F000000)) + ) + ); + } + + if ((wrdsp_mask & 0b100000) == 0b100000) { + /* Put bit 14 of rs to DSPControl register EFI + field. */ + putDSPControl(binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xFFFF3FBF)), + binop(Iop_And32, + getIReg(rs), + mkU32(0x00004000)))); + } + } + break; + } + case 0x1A: { /* SHILO */ + DIP("shilo ac%d, %d", ac, shift); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + + putAcc(ac, mkexpr(t0)); + + if (0b100000 == (shift & 0x3f)) { + putAcc(ac, binop(Iop_32HLto64, + unop(Iop_64to32, mkexpr(t0)), + mkU32(0x0))); + } else if (0b100000 == (shift & 0x20)) { + assign(t1, binop(Iop_Shl64, + mkexpr(t0), + unop(Iop_32to8, + binop(Iop_Add32, + unop(Iop_Not32, + mkU32(shift)), + mkU32(0x1))))); + + putAcc(ac, mkexpr(t1)); + } else { + assign(t1, binop(Iop_Shr64, mkexpr(t0), mkU8(shift))); + + putAcc(ac, mkexpr(t1)); + } + break; + } + case 0x1B: { /* SHILOV */ + DIP("shilov ac%d, r%d", ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + assign(t2, binop(Iop_And32, getIReg(rs), mkU32(0x3f))); + assign(t3, binop(Iop_CmpEQ32, mkexpr(t2), mkU32(0x20))); + + assign(t4, binop(Iop_Shl64, + mkexpr(t0), + unop(Iop_32to8, + binop(Iop_Add32, + unop(Iop_Not32, + mkexpr(t2)), + mkU32(0x1))))); + assign(t5, binop(Iop_Shr64, + mkexpr(t0), + unop(Iop_32to8, + mkexpr(t2)))); + putAcc(ac, IRExpr_ITE(mkexpr(t3), + binop(Iop_32HLto64, + unop(Iop_64to32, mkexpr(t0)), + mkU32(0x0)), + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x20)), + mkU32(0x20)), + mkexpr(t4), + mkexpr(t5)))); + break; + } + case 0x1F: { /* MTHLIP */ + DIP("mthlip r%d, ac%d", rs, ac); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + + assign(t0, getAcc(ac)); + putAcc(ac, binop(Iop_32HLto64, + unop(Iop_64to32, mkexpr(t0)), + getIReg(rs))); + assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpLE32U, + mkU32(32), + mkexpr(t1)), + binop(Iop_Or32, + binop(Iop_Sub32, + mkexpr(t1), + mkU32(32)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffffc0))), + binop(Iop_Or32, + binop(Iop_Add32, + mkexpr(t1), + mkU32(32)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffffc0))))); + break; + } + default: + return -1; + } + break; /* end of EXTR.W */ + } + case 0xA: { /* LX */ + switch(sa) { + case 0x0: { /* LWX */ + DIP("lwx r%d, r%d(r%d)", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + + assign(t0, binop(Iop_Add32, getIReg(rt), getIReg(rs))); + + putIReg(rd, load(Ity_I32, mkexpr(t0))); + break; + } + case 0x4: { /* LHX */ + DIP("lhx r%d, r%d(r%d)", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + + assign(t0, binop(Iop_Add32, getIReg(rt), getIReg(rs))); + + putIReg(rd, unop(Iop_16Sto32, load(Ity_I16, mkexpr(t0)))); + break; + } + case 0x6: { /* LBUX */ + DIP("lbux r%d, r%d(r%d)", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + + assign(t0, binop(Iop_Add32, getIReg(rt), getIReg(rs))); + + putIReg(rd, unop(Iop_8Uto32, load(Ity_I8, mkexpr(t0)))); + break; + } + default: + return -1; + } + break; /* end of LX */ + } + case 0xC: { /* INSV */ + switch(sa) { + case 0x0: { /* INSV */ + DIP("insv r%d, r%d", rt, rs); + vassert(!mode64); + + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I8); + t3 = newTemp(Ity_I8); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + + /* t0 <- pos field of DSPControl register. */ + assign(t0, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); + /* t1 <- scount field of DSPControl register. */ + assign(t1, binop(Iop_Shr32, + binop(Iop_And32, + getDSPControl(), + mkU32(0x1f80)), + mkU8(7))); + + assign(t2, unop(Iop_32to8, + binop(Iop_Add32, + mkexpr(t1), + mkexpr(t0)))); + + /* 32-(pos+size) most significant bits of rt. */ + assign(t6, binop(Iop_Shl32, + binop(Iop_Shr32, + getIReg(rt), + mkexpr(t2)), + mkexpr(t2))); + + assign(t3, unop(Iop_32to8, + binop(Iop_Sub32, + mkU32(32), + mkexpr(t0)))); + /* Pos least significant bits of rt. */ + assign(t7, binop(Iop_Shr32, + binop(Iop_Shl32, + getIReg(rt), + mkexpr(t3)), + mkexpr(t3))); + + /* Size least significant bits of rs, + shifted to appropriate position. */ + assign(t8, binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rs), + unop(Iop_Not32, + binop(Iop_Shl32, + mkU32(0xffffffff), + unop(Iop_32to8, + mkexpr(t1))))), + unop(Iop_32to8, + mkexpr(t0)))); + + putIReg(rt, IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t0), + mkU32(0)), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t1), + mkU32(32)), + getIReg(rs), + binop(Iop_Or32, + mkexpr(t6), + mkexpr(t8))), + IRExpr_ITE(binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + mkexpr(t2)), + mkU32(32)), + binop(Iop_Or32, + mkexpr(t7), + mkexpr(t8)), + binop(Iop_Or32, + binop(Iop_Or32, + mkexpr(t6), + mkexpr(t7)), + mkexpr(t8))))); + break; + } + default: + return -1; + } + break; /* enf of INSV */ + } + case 0x10: { /* ADDU.QB */ + switch(sa) { + case 0x00: { /* ADDU.QB */ + DIP("addu.qb r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I32); + + /* Add rightmost bytes of rs and rt. */ + assign(t0, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt)))))); + /* t1 will be 1 if there is overflow, 0 otherwise. */ + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x00000100)), + mkU32(0x00000100))); + + /* Add bits 15-8 of rs and rt. */ + assign(t2, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))))); + /* t3 will be 1 if there is overflow, 0 otherwise. */ + assign(t3, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00000100)), + mkU32(0x00000100))); + + /* Add bits 15-8 of rs and rt. */ + assign(t4, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt)))))); + /* t5 will be 1 if there is overflow, 0 otherwise. */ + assign(t5, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t4), + mkU32(0x00000100)), + mkU32(0x00000100))); + + /* Add bits 15-8 of rs and rt. */ + assign(t6, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt)))))); + /* t7 will be 1 if there is overflow, 0 otherwise. */ + assign(t7, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t6), + mkU32(0x00000100)), + mkU32(0x00000100))); + + assign(t8, + binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t7)), + unop(Iop_1Sto32, mkexpr(t5))), + unop(Iop_1Sto32, mkexpr(t3))), + unop(Iop_1Sto32, mkexpr(t1)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t8), + mkU32(0x0)), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)))); + + putIReg(rd, binop(Iop_16HLto32, + binop(Iop_8HLto16, + unop(Iop_32to8, mkexpr(t6)), + unop(Iop_32to8, mkexpr(t4))), + binop(Iop_8HLto16, + unop(Iop_32to8, mkexpr(t2)), + unop(Iop_32to8, mkexpr(t0))))); + break; + } + case 0x1: { /* SUBU.QB */ + DIP("subu.qb r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I32); + + /* Subtract rightmost bytes of rs and rt. */ + assign(t0, + binop(Iop_Sub32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt)))))); + /* t1 will be 1 if there is overflow, 0 otherwise. */ + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x00000100)), + mkU32(0x00000100))); + + /* Subtract bits 15-8 of rs and rt. */ + assign(t2, + binop(Iop_Sub32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))))); + /* t3 will be 1 if there is overflow, 0 otherwise. */ + assign(t3, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00000100)), + mkU32(0x00000100))); + + /* Subtract bits 15-8 of rs and rt. */ + assign(t4, + binop(Iop_Sub32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt)))))); + /* t5 will be 1 if there is overflow, 0 otherwise. */ + assign(t5, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t4), + mkU32(0x00000100)), + mkU32(0x00000100))); + + /* Subtract bits 15-8 of rs and rt. */ + assign(t6, + binop(Iop_Sub32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt)))))); + /* t7 will be 1 if there is overflow, 0 otherwise. */ + assign(t7, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t6), + mkU32(0x00000100)), + mkU32(0x00000100))); + + assign(t8, binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t7)), + unop(Iop_1Sto32, mkexpr(t5))), + unop(Iop_1Sto32, mkexpr(t3))), + unop(Iop_1Sto32, mkexpr(t1)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t8), + mkU32(0x0)), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)))); + + putIReg(rd, binop(Iop_16HLto32, + binop(Iop_8HLto16, + unop(Iop_32to8, mkexpr(t6)), + unop(Iop_32to8, mkexpr(t4))), + binop(Iop_8HLto16, + unop(Iop_32to8, mkexpr(t2)), + unop(Iop_32to8, mkexpr(t0))))); + break; + } + case 0x04: { /* ADDU_S.QB */ + DIP("addu_s.qb r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I8); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I8); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I8); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I1); + t11 = newTemp(Ity_I8); + t12 = newTemp(Ity_I32); + + /* Add rightmost bytes of rs and rt. */ + assign(t0, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt)))))); + /* t1 will be 1 if there is overflow, 0 otherwise. */ + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x00000100)), + mkU32(0x00000100))); + /* Saturate if necessary. */ + assign(t2, IRExpr_ITE(mkexpr(t1), + mkU8(0xff), + unop(Iop_32to8, mkexpr(t0)))); + + /* Add bits 15-8 of rs and rt. */ + assign(t3, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))))); + /* t4 will be 1 if there is overflow, 0 otherwise. */ + assign(t4, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t3), + mkU32(0x00000100)), + mkU32(0x00000100))); + /* Saturate if necessary. */ + assign(t5, IRExpr_ITE(mkexpr(t4), + mkU8(0xff), + unop(Iop_32to8, mkexpr(t3)))); + + /* Add bits 15-8 of rs and rt. */ + assign(t6, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt)))))); + /* t7 will be 1 if there is overflow, 0 otherwise. */ + assign(t7, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t6), + mkU32(0x00000100)), + mkU32(0x00000100))); + /* Saturate if necessary. */ + assign(t8, IRExpr_ITE(mkexpr(t7), + mkU8(0xff), + unop(Iop_32to8, mkexpr(t6)))); + + /* Add bits 15-8 of rs and rt. */ + assign(t9, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt)))))); + /* t10 will be 1 if there is overflow, 0 otherwise. */ + assign(t10, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t9), + mkU32(0x00000100)), + mkU32(0x00000100))); + /* Saturate if necessary. */ + assign(t11, IRExpr_ITE(mkexpr(t10), + mkU8(0xff), + unop(Iop_32to8, mkexpr(t9)))); + + assign(t12, + binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t10)), + unop(Iop_1Sto32, mkexpr(t7))), + unop(Iop_1Sto32, mkexpr(t4))), + unop(Iop_1Sto32, mkexpr(t1)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t12), + mkU32(0x0)), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)))); + + putIReg(rd, + binop(Iop_16HLto32, + binop(Iop_8HLto16, mkexpr(t11), mkexpr(t8)), + binop(Iop_8HLto16, mkexpr(t5), mkexpr(t2)))); + break; + } + case 0x05: { /* SUBU_S.QB */ + DIP("subu_s.qb r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + + /* Use C function to easily calculate the result + and write it in the register more conveniently + Underflow is checked using step by step subtraction. */ + assign(t1, binop(Iop_QSub8Ux4, getIReg(rs), getIReg(rt))); + + /* Subtract each byte of rs and rt. */ + assign(t6, + binop(Iop_Sub32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt)))))); + assign(t7, + binop(Iop_Sub32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))))); + assign(t8, + binop(Iop_Sub32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t9, + binop(Iop_Sub32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt)))))); + + /* Put 1 to bit 20 in DSPControl if there is underflow + in either byte. */ + assign(t2, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t6), + mkU32(0x00000100)), + mkU32(0x00000100))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + assign(t3, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t7), + mkU32(0x00000100)), + mkU32(0x00000100))); + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + assign(t4, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t8), + mkU32(0x00000100)), + mkU32(0x00000100))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + assign(t5, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t9), + mkU32(0x00000100)), + mkU32(0x00000100))); + putDSPControl(IRExpr_ITE(mkexpr(t5), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + putIReg(rd, mkexpr(t1)); + break; + } + case 0x6: { /* MULEU_S.PH.QBL */ + DIP("muleu_s.ph.qbl r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + + assign(t0, + unop(Iop_64to32, + binop(Iop_MullU32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t1, + unop(Iop_64to32, + binop(Iop_MullU32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt)))))); + + assign(t2, binop(Iop_CmpNE32, + mkU32(0x0), + binop(Iop_And32, + mkexpr(t0), + mkU32(0x03ff0000)))); + assign(t3, binop(Iop_CmpNE32, + mkU32(0x0), + binop(Iop_And32, + mkexpr(t1), + mkU32(0x03ff0000)))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x200000)), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x200000)), + getDSPControl()))); + putIReg(rd, + binop(Iop_16HLto32, + IRExpr_ITE(mkexpr(t2), + mkU16(0xffff), + unop(Iop_32to16, mkexpr(t0))), + IRExpr_ITE(mkexpr(t3), + mkU16(0xffff), + unop(Iop_32to16, mkexpr(t1))))); + break; + } + case 0x7: { /* MULEU_S.PH.QBR */ + DIP("muleu_s.ph.qbr r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + + assign(t0, unop(Iop_64to32, + binop(Iop_MullU32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rs)))), + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t1, unop(Iop_64to32, + binop(Iop_MullU32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rs)))), + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rt)))))); + + assign(t2, binop(Iop_CmpNE32, + mkU32(0x0), + binop(Iop_And32, + mkexpr(t0), + mkU32(0x03ff0000)))); + assign(t3, binop(Iop_CmpNE32, + mkU32(0x0), + binop(Iop_And32, + mkexpr(t1), + mkU32(0x03ff0000)))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x200000)), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x200000)), + getDSPControl()))); + putIReg(rd, binop(Iop_16HLto32, + IRExpr_ITE(mkexpr(t2), + mkU16(0xffff), + unop(Iop_32to16, + mkexpr(t0))), + IRExpr_ITE(mkexpr(t3), + mkU16(0xffff), + unop(Iop_32to16, + mkexpr(t1))))); + break; + } + case 0x08: { /* ADDU.PH */ + DIP("addu.ph r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + + /* Add lower halves. */ + assign(t0, binop(Iop_Add32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))))); + + /* Detect overflow. */ + assign(t1, binop(Iop_CmpLT32U, + unop(Iop_16Uto32, + unop(Iop_32to16, mkexpr(t0))), + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + /* Add higher halves. */ + assign(t2, binop(Iop_Add32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Detect overflow. */ + assign(t3, binop(Iop_CmpLT32U, + unop(Iop_16Uto32, + unop(Iop_32to16, mkexpr(t2))), + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rs))))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t2)), + unop(Iop_32to16, mkexpr(t0)))); + break; + } + case 0x9: { /* SUBU.PH */ + DIP("subu.ph r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + + /* Substract lower halves. */ + assign(t0, binop(Iop_Sub32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))))); + + /* Detect underflow. */ + assign(t1, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x00010000)), + mkU32(0x0))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + /* Subtract higher halves. */ + assign(t2, binop(Iop_Sub32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Detect underflow. */ + assign(t3, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00010000)), + mkU32(0x0))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t2)), + unop(Iop_32to16, mkexpr(t0)))); + break; + } + case 0xA: { /* ADDQ.PH */ + DIP("addq.ph r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + + /* Add lower halves. */ + assign(t0, binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + + /* Bit 16 of the result. */ + assign(t6, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, mkexpr(t0))), + mkU32(0x1))); + /* Detect overflow. */ + assign(t1, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x8000)), + mkU8(15)), + mkexpr(t6))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + /* Add higher halves. */ + assign(t2, binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Bit 16 of the result. */ + assign(t7, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, mkexpr(t2))), + mkU32(0x1))); + /* Detect overflow. */ + assign(t3, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00008000)), + mkU8(15)), + mkexpr(t7))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t2)), + unop(Iop_32to16, mkexpr(t0)))); + break; + } + case 0xB: { /* SUBQ.PH */ + DIP("subq.ph r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + + /* Subtract lower halves. */ + assign(t0, binop(Iop_Sub32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + + /* Bit 16 of the result. */ + assign(t6, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, mkexpr(t0))), + mkU32(0x1))); + /* Compare the signs of input value and the result. */ + assign(t1, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x8000)), + mkU8(15)), + mkexpr(t6))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + /* Subtract higher halves. */ + assign(t2, binop(Iop_Sub32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Bit 16 of the result. */ + assign(t7, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, mkexpr(t2))), + mkU32(0x1))); + /* Compare the signs of input value and the result. */ + assign(t3, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00008000)), + mkU8(15)), + mkexpr(t7))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t2)), + unop(Iop_32to16, mkexpr(t0)))); + break; + } + case 0xC: { /* ADDU_S.PH */ + DIP("addu_s.ph r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + + /* Add lower halves. */ + assign(t0, binop(Iop_Add32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))))); + + /* Detect overflow. */ + assign(t1, binop(Iop_CmpLT32U, + unop(Iop_16Uto32, + unop(Iop_32to16, mkexpr(t0))), + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + /* Add higher halves. */ + assign(t2, binop(Iop_Add32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Detect overflow. */ + assign(t3, binop(Iop_CmpLT32U, + unop(Iop_16Uto32, + unop(Iop_32to16, mkexpr(t2))), + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + putIReg(rd, binop(Iop_16HLto32, + IRExpr_ITE(mkexpr(t3), + mkU16(0xffff), + unop(Iop_32to16, + mkexpr(t2))), + IRExpr_ITE(mkexpr(t1), + mkU16(0xffff), + unop(Iop_32to16, + mkexpr(t0))))); + break; + } + case 0xD: { /* SUBU_S.PH */ + DIP("subu_s.ph r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + + /* Subtract lower halves. */ + assign(t0, binop(Iop_Sub32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))))); + + /* Detect underflow. */ + assign(t1, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), mkU32(0x00010000)), + mkU32(0x0))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + /* Subtract higher halves. */ + assign(t2, binop(Iop_Sub32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Detect underflow. */ + assign(t3, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t2), mkU32(0x00010000)), + mkU32(0x0))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + putIReg(rd, + binop(Iop_16HLto32, + IRExpr_ITE(mkexpr(t3), + mkU16(0x0000), + unop(Iop_32to16, mkexpr(t2))), + IRExpr_ITE(mkexpr(t1), + mkU16(0x0000), + unop(Iop_32to16, mkexpr(t0))))); + break; + } + case 0xE: { /* ADDQ_S.PH */ + DIP("addq_s.ph r%d r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I16); + t5 = newTemp(Ity_I16); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + + /* Add lower halves. */ + assign(t0, binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + + /* Bit 16 of the result. */ + assign(t6, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, mkexpr(t0))), + mkU32(0x1))); + /* Detect overflow. */ + assign(t1, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x8000)), + mkU8(15)), + mkexpr(t6))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + /* Saturate if needed. */ + assign(t4, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t6), + mkU32(0x0)), + mkU16(0x7fff), + mkU16(0x8000)), + unop(Iop_32to16, mkexpr(t0)))); + + /* Add higher halves. */ + assign(t2, binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Bit 16 of the result. */ + assign(t7, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, mkexpr(t2))), + mkU32(0x1))); + /* Detect overflow. */ + assign(t3, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00008000)), + mkU8(15)), + mkexpr(t7))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + /* Saturate if needed. */ + assign(t5, IRExpr_ITE(mkexpr(t3), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t7), + mkU32(0x0)), + mkU16(0x7fff), + mkU16(0x8000)), + unop(Iop_32to16, mkexpr(t2)))); + + putIReg(rd, binop(Iop_16HLto32, mkexpr(t5), mkexpr(t4))); + break; + } + case 0xF: { /* SUBQ_S.PH */ + DIP("subq_s.ph r%d r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I16); + t5 = newTemp(Ity_I16); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + + /* Subtract lower halves. */ + assign(t0, binop(Iop_Sub32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + + /* Bit 16 of the result. */ + assign(t6, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, mkexpr(t0))), + mkU32(0x1))); + /* Detect overflow or underflow. */ + assign(t1, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x8000)), + mkU8(15)), + mkexpr(t6))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + /* Saturate if needed. */ + assign(t4, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t6), + mkU32(0x0)), + mkU16(0x7fff), + mkU16(0x8000)), + unop(Iop_32to16, mkexpr(t0)))); + + /* Subtract higher halves. */ + assign(t2, binop(Iop_Sub32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Bit 16 of the result. */ + assign(t7, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, mkexpr(t2))), + mkU32(0x1))); + /* Detect overflow or underflow. */ + assign(t3, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00008000)), + mkU8(15)), + mkexpr(t7))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + /* Saturate if needed. */ + assign(t5, IRExpr_ITE(mkexpr(t3), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t7), + mkU32(0x0)), + mkU16(0x7fff), + mkU16(0x8000)), + unop(Iop_32to16, mkexpr(t2)))); + + putIReg(rd, binop(Iop_16HLto32, mkexpr(t5), mkexpr(t4))); + break; + } + case 0x10: { /* ADDSC */ + DIP("addsc r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I1); + + /* The carry bit result out of the addition operation is + written to bit 13(the c field) of the DSPControl reg. */ + assign(t0, binop(Iop_Add64, + unop(Iop_32Uto64, getIReg(rs)), + unop(Iop_32Uto64, getIReg(rt)))); + + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t0)), + mkU32(0x1)), + mkU32(0x1))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x2000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffdfff)))); + + putIReg(rd, unop(Iop_64to32, mkexpr(t0))); + break; + } + case 0x11: { /* ADDWC */ + DIP("addwc r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I1); + + /* Get carry bit from DSPControl register. */ + assign(t0, binop(Iop_Shr32, + binop(Iop_And32, + getDSPControl(), + mkU32(0x2000)), + mkU8(0xd))); + assign(t1, binop(Iop_Add64, + unop(Iop_32Sto64, getIReg(rs)), + unop(Iop_32Sto64, + binop(Iop_Add32, + getIReg(rt), + mkexpr(t0))))); + + /* Extract bits 32 and 31. */ + assign(t2, binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t1)), + mkU32(0x1))); + assign(t3, binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64to32, mkexpr(t1)), + mkU32(0x80000000)), + mkU8(31))); + assign(t4, binop(Iop_CmpNE32, mkexpr(t2), mkexpr(t3))); + + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + putIReg(rd, unop(Iop_64to32, mkexpr(t1))); + break; + } + case 0x12: { /* MODSUB */ + DIP("modsub r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + + /* decr_7..0 */ + assign(t0, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt))))); + + /* lastindex_15..0 */ + assign(t1, + unop(Iop_16Uto32, + binop(Iop_8HLto16, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))))); + /* temp_15..0 */ + assign(t2, + IRExpr_ITE(binop(Iop_CmpEQ32, + getIReg(rs), + mkU32(0x00000000)), + mkexpr(t1), + binop(Iop_Sub32, + getIReg(rs), mkexpr(t0)))); + putIReg(rd, mkexpr(t2)); + break; + } + case 0x14: { /* RADDU.W.QB */ + DIP("raddu.w.qb r%d, r%d", rd, rs); + vassert(!mode64); + putIReg(rd, binop(Iop_Add32, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rs))))), + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs))))))); + break; + } + case 0x16: { /* ADDQ_S.W */ + DIP("addq_s.w r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + + assign(t0, binop(Iop_Add64, + unop(Iop_32Sto64, getIReg(rs)), + unop(Iop_32Sto64, getIReg(rt)))); + + assign(t3, binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t0)), + mkU32(0x1))); + assign(t1, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64to32, mkexpr(t0)), + mkU32(0x80000000)), + mkU8(31)), + mkexpr(t3))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + putIReg(rd, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t3), + mkU32(0x0)), + mkU32(0x7fffffff), + mkU32(0x80000000)), + unop(Iop_64to32, mkexpr(t0)))); + break; + } + case 0x17: { /* SUBQ_S.W */ + DIP("subq_s.w r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + + assign(t0, binop(Iop_Sub64, + unop(Iop_32Sto64, getIReg(rs)), + unop(Iop_32Sto64, getIReg(rt)))); + + assign(t3, binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t0)), + mkU32(0x1))); + assign(t1, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64to32, mkexpr(t0)), + mkU32(0x80000000)), + mkU8(31)), + mkexpr(t3))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + putIReg(rd, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t3), + mkU32(0x0)), + mkU32(0x7fffffff), + mkU32(0x80000000)), + unop(Iop_64to32, mkexpr(t0)))); + break; + } + case 0x1C: { /* MULEQ_S.W.PHL */ + DIP("muleq_s.w.phl r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I32); + + assign(t0, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs)))), + mkU8(0x1))); + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xffff0000)), + mkU32(0x80000000))); + assign(t2, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rs), + mkU32(0xffff0000)), + mkU32(0x80000000))); + assign(t3, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000)), + getDSPControl()), + getDSPControl())); + putDSPControl(mkexpr(t3)); + + putIReg(rd, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + mkU32(0x7fffffff), + mkexpr(t0)), + mkexpr(t0))); + break; + } + case 0x1D: { /* MULEQ_S.W.PHR */ + DIP("muleq_s.w.phr r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + + assign(t0, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs)))), + mkU8(0x1))); + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xffff)), + mkU32(0x8000))); + assign(t2, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rs), + mkU32(0xffff)), + mkU32(0x8000))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000) + ), + getDSPControl()), + getDSPControl())); + putIReg(rd, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + mkU32(0x7fffffff), + mkexpr(t0)), + mkexpr(t0))); + break; + } + case 0x1E: { /* MULQ_S.PH */ + DIP("mulq_s.ph r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I16); + t3 = newTemp(Ity_I16); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t5, + unop(Iop_16Sto32, unop(Iop_32to16, getIReg(rs)))); + assign(t6, + unop(Iop_16Sto32, unop(Iop_32to16, getIReg(rt)))); + + assign(t7, + unop(Iop_16Sto32, unop(Iop_32HIto16, getIReg(rs)))); + assign(t8, + unop(Iop_16Sto32, unop(Iop_32HIto16, getIReg(rt)))); + + assign(t0, binop(Iop_And32, + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t5), + mkU32(0xffff)), + mkU32(0x8000))), + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t6), + mkU32(0xffff)), + mkU32(0x8000))))); + assign(t1, binop(Iop_And32, + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t7), + mkU32(0xffff)), + mkU32(0x8000))), + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t8), + mkU32(0xffff)), + mkU32(0x8000))))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_Or32, + mkexpr(t0), + mkexpr(t1)), + mkU32(0x0)), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x200000)))); + + assign(t2, unop(Iop_32HIto16, + binop(Iop_Shl32, + unop(Iop_64to32, + binop(Iop_MullS32, + mkexpr(t7), + mkexpr(t8))), + mkU8(0x1)))); + assign(t3, unop(Iop_32HIto16, + binop(Iop_Shl32, + unop(Iop_64to32, + binop(Iop_MullS32, + mkexpr(t5), + mkexpr(t6))), + mkU8(0x1)))); + putIReg(rd, binop(Iop_16HLto32, + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t1), + mkU32(0x0)), + mkexpr(t2), + mkU16(0x7fff)), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t0), + mkU32(0x0)), + mkexpr(t3), + mkU16(0x7fff)))); + break; + } + case 0x1F: { /* MULQ_RS.PH */ + DIP("mulq_rs.ph r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I16); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I16); + + /* Multiply and round lower halfwords. */ + assign(t0, binop(Iop_Add32, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rt))), + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rs)))), + mkU8(0x1)), + mkU32(0x00008000))); + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), mkU32(0xffff)), + mkU32(0x8000))); + assign(t2, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rs), mkU32(0xffff)), + mkU32(0x8000))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000) + ), + getDSPControl()), + getDSPControl())); + assign(t3, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + mkU16(0x7fff), + unop(Iop_32HIto16, + mkexpr(t0))), + unop(Iop_32HIto16, mkexpr(t0)))); + + /* Multiply and round higher halfwords. */ + assign(t4, binop(Iop_Add32, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rs)))), + mkU8(0x1)), + mkU32(0x00008000))); + assign(t5, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xffff0000)), + mkU32(0x80000000))); + assign(t6, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rs), + mkU32(0xffff0000)), + mkU32(0x80000000))); + putDSPControl(IRExpr_ITE(mkexpr(t5), + IRExpr_ITE(mkexpr(t6), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000)), + getDSPControl()), + getDSPControl())); + assign(t7, IRExpr_ITE(mkexpr(t5), + IRExpr_ITE(mkexpr(t6), + mkU16(0x7fff), + unop(Iop_32HIto16, + mkexpr(t4))), + unop(Iop_32HIto16, mkexpr(t4)))); + + putIReg(rd, binop(Iop_16HLto32, mkexpr(t7), mkexpr(t3))); + break; + } + default: + return -1; + } + break; /* end of ADDU.QB */ + } + case 0x11: { /* CMPU.EQ.QB */ + switch(sa) { + case 0x0: { /* CMPU.EQ.QB */ + DIP("cmpu.eq.qb r%d, r%d", rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + + assign(t1, + binop(Iop_CmpEQ32, + binop(Iop_And32, getIReg(rs), mkU32(0xff)), + binop(Iop_And32, getIReg(rt), mkU32(0xff)))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x04000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfbffffff)))); + + assign(t4, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x08000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xf7ffffff)))); + break; + } + case 0x1: { /* CMPU.LT.QB */ + DIP("cmpu.lt.qb r%d, r%d", rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + + assign(t1, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + + assign(t2, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + + assign(t3, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x04000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfbffffff)))); + + assign(t4, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x08000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xf7ffffff)))); + break; + } + case 0x2: { /* CMPU.LE.QB */ + DIP("cmpu.le.qb r%d, r%d", rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + + assign(t1, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + + assign(t2, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + + assign(t3, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x04000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfbffffff)))); + + assign(t4, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x08000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xf7ffffff)))); + break; + } + case 0x3: { /* PICK.QB */ + DIP("pick.qb r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I8); + t2 = newTemp(Ity_I8); + t3 = newTemp(Ity_I8); + t4 = newTemp(Ity_I8); + + assign(t0, getDSPControl()); + assign(t1, IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x01000000)), + mkU32(0x0)), + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rs))), + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rt))))); + assign(t2, IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x02000000)), + mkU32(0x0)), + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt))))); + assign(t3, IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x04000000)), + mkU32(0x0)), + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt))))); + assign(t4, IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x08000000)), + mkU32(0x0)), + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt))))); + putIReg(rd, + binop(Iop_16HLto32, + binop(Iop_8HLto16, mkexpr(t4), mkexpr(t3)), + binop(Iop_8HLto16, mkexpr(t2), mkexpr(t1)))); + break; + } + case 0x4: { /* CMPGU.EQ.QB */ + DIP("cmpgu.eq.qb r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t1, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t5, IRExpr_ITE(mkexpr(t1), + mkU32(0x00000001), mkU32(0))); + + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t6, IRExpr_ITE(mkexpr(t2), + mkU32(0x00000002), mkU32(0))); + + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t7, IRExpr_ITE(mkexpr(t3), + mkU32(0x00000004), mkU32(0))); + + assign(t4, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t8, IRExpr_ITE(mkexpr(t4), + mkU32(0x00000008), mkU32(0))); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + mkexpr(t5), mkexpr(t6)), + mkexpr(t7)), + mkexpr(t8))); + break; + } + case 0x5: { /* CMPGU.LT.QB */ + DIP("cmpgu.lt.qb r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t1, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t5, IRExpr_ITE(mkexpr(t1), + mkU32(0x00000001), mkU32(0))); + + assign(t2, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t6, IRExpr_ITE(mkexpr(t2), + mkU32(0x00000002), mkU32(0))); + + assign(t3, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t7, IRExpr_ITE(mkexpr(t3), + mkU32(0x00000004), mkU32(0))); + + assign(t4, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t8, IRExpr_ITE(mkexpr(t4), + mkU32(0x00000008), mkU32(0))); + putIReg(rd, binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + mkexpr(t5), mkexpr(t6)), + mkexpr(t7)), + mkexpr(t8))); + break; + } + case 0x6: { /* CMPGU.LE.QB */ + DIP("cmpgu.le.qb r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t1, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t5, IRExpr_ITE(mkexpr(t1), + mkU32(0x00000001), mkU32(0))); + + assign(t2, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t6, IRExpr_ITE(mkexpr(t2), + mkU32(0x00000002), mkU32(0))); + + assign(t3, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t7, IRExpr_ITE(mkexpr(t3), + mkU32(0x00000004), mkU32(0))); + + assign(t4, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t8, IRExpr_ITE(mkexpr(t4), + mkU32(0x00000008), mkU32(0))); + putIReg(rd, binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + mkexpr(t5), mkexpr(t6)), + mkexpr(t7)), + mkexpr(t8))); + break; + } + case 0x8: { /* CMP.EQ.PH */ + DIP("cmp.eq.ph r%d, r%d", rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + + assign(t1, binop(Iop_CmpEQ16, + unop(Iop_32to16, getIReg(rs)), + unop(Iop_32to16, getIReg(rt)))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + assign(t2, binop(Iop_CmpEQ16, + unop(Iop_32HIto16, getIReg(rs)), + unop(Iop_32HIto16, getIReg(rt)))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + break; + } + case 0x9: { /* CMP.LT.PH */ + DIP("cmp.lt.ph r%d, r%d", rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + + assign(t1, binop(Iop_CmpLT32S, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + + assign(t2, binop(Iop_CmpLT32S, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + break; + } + case 0xA: { /* CMP.LE.PH */ + DIP("cmp.le.ph r%d, r%d", rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + + assign(t1, binop(Iop_CmpLE32S, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + + assign(t2, binop(Iop_CmpLE32S, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + break; + } + case 0xB: { /* PICK.PH */ + DIP("pick.qb r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I16); + t2 = newTemp(Ity_I16); + + assign(t0, getDSPControl()); + + assign(t1, IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x01000000)), + mkU32(0x0)), + unop(Iop_32to16, getIReg(rs)), + unop(Iop_32to16, getIReg(rt)))); + + assign(t2, IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x02000000)), + mkU32(0x0)), + unop(Iop_32HIto16, getIReg(rs)), + unop(Iop_32HIto16, getIReg(rt)))); + + putIReg(rd, binop(Iop_16HLto32, mkexpr(t2), mkexpr(t1))); + break; + } + case 0xC: { /* PRECRQ.QB.PH */ + DIP("precrq.qb.ph r%d, r%d, %d", rd, rs, rt); + vassert(!mode64); + putIReg(rd, + binop(Iop_16HLto32, + binop(Iop_8HLto16, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + binop(Iop_8HLto16, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))))); + break; + } + case 0xD: { /* PRECR.QB.PH */ + DIP("precr.qb.ph r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + + putIReg(rd, + binop(Iop_16HLto32, + binop(Iop_8HLto16, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + binop(Iop_8HLto16, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt)))))); + break; + } + case 0xF: { /* PRECRQU_S.QB.PH */ + DIP("precrqu_s.qb.ph r%d, r%d, %d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I8); + t1 = newTemp(Ity_I8); + t2 = newTemp(Ity_I8); + t3 = newTemp(Ity_I8); + t4 = newTemp(Ity_I8); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I8); + t8 = newTemp(Ity_I1); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I8); + t11 = newTemp(Ity_I1); + t12 = newTemp(Ity_I32); + t13 = newTemp(Ity_I8); + t14 = newTemp(Ity_I1); + t15 = newTemp(Ity_I32); + + assign(t4, IRExpr_ITE(binop(Iop_CmpLT32U, + mkU32(0x7f80), + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rs))), + mkU32(0x7fff))), + mkU8(0xff), + unop(Iop_16HIto8, + unop(Iop_32to16, + binop(Iop_Shl32, + getIReg(rs), + mkU8(1)))))); + assign(t0, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rs))), + mkU32(0x00008000)), + mkU32(0x0)), + mkexpr(t4), + mkU8(0x0))); + assign(t5, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rs))), + mkU32(0x00008000))); + assign(t6, binop(Iop_CmpLT32U, + mkU32(0x7f80), + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rs))), + mkU32(0x7fff)))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t5), + mkU32(0x0)), + IRExpr_ITE(mkexpr(t6), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00400000) + ), + getDSPControl()), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00400000)))); + + assign(t7, IRExpr_ITE(binop(Iop_CmpLT32U, + mkU32(0x7f80), + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rs))), + mkU32(0x7fff))), + mkU8(0xff), + unop(Iop_16HIto8, + unop(Iop_32HIto16, + binop(Iop_Shl32, + getIReg(rs), + mkU8(1)))))); + assign(t1, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rs))), + mkU32(0x00008000)), + mkU32(0x0)), + mkexpr(t7), + mkU8(0x0))); + assign(t8, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rs))), + mkU32(0x00008000)), + mkU32(0x0))); + assign(t9, IRExpr_ITE(binop(Iop_CmpLT32U, + mkU32(0x7f80), + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rs))), + mkU32(0x7fff))), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(mkexpr(t8), + mkexpr(t9), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00400000)))); + + assign(t10, IRExpr_ITE(binop(Iop_CmpLT32U, + mkU32(0x7f80), + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rt))), + mkU32(0x7fff))), + mkU8(0xff), + unop(Iop_16HIto8, + unop(Iop_32to16, + binop(Iop_Shl32, + getIReg(rt), + mkU8(1)))))); + assign(t2, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rt))), + mkU32(0x00008000)), + mkU32(0x0)), + mkexpr(t10), + mkU8(0x0))); + assign(t11, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rt))), + mkU32(0x00008000)), + mkU32(0x0))); + assign(t12, IRExpr_ITE(binop(Iop_CmpLT32U, + mkU32(0x7f80), + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rt))), + mkU32(0x7fff))), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(mkexpr(t11), + mkexpr(t12), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00400000)))); + + assign(t13, IRExpr_ITE(binop(Iop_CmpLT32U, + mkU32(0x7f80), + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rt))), + mkU32(0x7fff))), + mkU8(0xff), + unop(Iop_16HIto8, + unop(Iop_32HIto16, + binop(Iop_Shl32, + getIReg(rt), + mkU8(1)))))); + assign(t3, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rt))), + mkU32(0x00008000)), + mkU32(0x0)), + mkexpr(t13), + mkU8(0x0))); + assign(t14, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rt))), + mkU32(0x00008000)), + mkU32(0x0))); + assign(t15, IRExpr_ITE(binop(Iop_CmpLT32U, + mkU32(0x7f80), + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rt))), + mkU32(0x7fff))), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(mkexpr(t14), + mkexpr(t15), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00400000)))); + + putIReg(rd, binop(Iop_16HLto32, + binop(Iop_8HLto16, + mkexpr(t1), mkexpr(t0)), + binop(Iop_8HLto16, + mkexpr(t3), mkexpr(t2)))); + break; + } + case 0x14: { /* PRECRQ.PH.W */ + DIP("precrq.ph.w r%d, r%d, %d", rd, rs, rt); + vassert(!mode64); + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32HIto16, getIReg(rs)), + unop(Iop_32HIto16, getIReg(rt)))); + break; + } + case 0x15: { /* PRECRQ_RS.PH.W */ + DIP("precrq_rs.ph.w r%d, r%d, %d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I64); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + + assign(t0, binop(Iop_Add64, + binop(Iop_32HLto64, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rs), + mkU32(0x80000000)), + mkU8(31)), + getIReg(rs)), + mkU64(0x0000000000008000ULL))); + assign(t1, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t0)), + mkU32(0x1)), + binop(Iop_And32, + binop(Iop_Shr32, + unop(Iop_64to32, mkexpr(t0)), + mkU8(31)), + mkU32(0x1)))); + assign(t2, IRExpr_ITE(mkexpr(t1), + mkU32(0x7fffffff), + unop(Iop_64to32, mkexpr(t0)))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + assign(t3, binop(Iop_Add64, + binop(Iop_32HLto64, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31)), + getIReg(rt)), + mkU64(0x0000000000008000ULL))); + assign(t4, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t3)), + mkU32(0x1)), + binop(Iop_And32, + binop(Iop_Shr32, + unop(Iop_64to32, mkexpr(t3)), + mkU8(31)), + mkU32(0x1)))); + assign(t5, IRExpr_ITE(mkexpr(t4), + mkU32(0x7fffffff), + unop(Iop_64to32, mkexpr(t3)))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32HIto16, mkexpr(t2)), + unop(Iop_32HIto16, mkexpr(t5)))); + break; + } + case 0x1E: { /* PRECR_SRA.PH.W */ + DIP("precr_sra.ph.w r%d, r%d, %d", rt, rs, rd); + vassert(!mode64); + + if (0 == rd) { + putIReg(rt, binop(Iop_16HLto32, + unop(Iop_32to16, getIReg(rt)), + unop(Iop_32to16, getIReg(rs)))); + } else { + putIReg(rt, binop(Iop_16HLto32, + unop(Iop_32to16, binop(Iop_Sar32, + getIReg(rt), + mkU8(rd))), + unop(Iop_32to16, binop(Iop_Sar32, + getIReg(rs), + mkU8(rd))))); + } + break; + } + case 0x1F: { /* PRECR_SRA_R.PH.W */ + DIP("precr_sra_r.ph.w r%d, r%d, %d", rt, rs, rd); + vassert(!mode64); + + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + + if (0 == rd) { + putIReg(rt, binop(Iop_16HLto32, + unop(Iop_32to16, getIReg(rt)), + unop(Iop_32to16, getIReg(rs)))); + } else { + assign(t0, binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Sar32, + getIReg(rt), + mkU8(rd-1)), + mkU32(0x1)), + mkU8(0x1))); + assign(t1, binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Sar32, + getIReg(rs), + mkU8(rd-1)), + mkU32(0x1)), + mkU8(0x1))); + putIReg(rt, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t0)), + unop(Iop_32to16, mkexpr(t1)))); + }; + break; + } + case 0xE: { /* PACKRL.PH */ + DIP("packrl.ph r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, getIReg(rs)), + unop(Iop_32HIto16, getIReg(rt)))); + break; + } + case 0x18: { /* CMPGDU.EQ.QB */ + DIP("cmpgdu.eq.qb r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t1, + binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt)))))); + assign(t5, IRExpr_ITE(mkexpr(t1), + mkU32(0x00000001), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t6, IRExpr_ITE(mkexpr(t2), + mkU32(0x00000002), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t7, IRExpr_ITE(mkexpr(t3), + mkU32(0x00000004), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x04000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfbffffff)))); + + assign(t4, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t8, IRExpr_ITE(mkexpr(t4), + mkU32(0x00000008), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x08000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xf7ffffff)))); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + mkexpr(t5), mkexpr(t6)), + mkexpr(t7)), + mkexpr(t8))); + break; + } + case 0x19: { /* CMPGDU.LT.QB */ + DIP("cmpgdu.lt.qb r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t1, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t5, IRExpr_ITE(mkexpr(t1), + mkU32(0x00000001), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + + assign(t2, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t6, IRExpr_ITE(mkexpr(t2), + mkU32(0x00000002), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + + assign(t3, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t7, IRExpr_ITE(mkexpr(t3), + mkU32(0x00000004), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x04000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfbffffff)))); + + assign(t4, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t8, IRExpr_ITE(mkexpr(t4), + mkU32(0x00000008), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x08000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xf7ffffff)))); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + mkexpr(t5), mkexpr(t6)), + mkexpr(t7)), + mkexpr(t8))); + break; + } + case 0x1A: { /* CMPGDU.LE.QB */ + DIP("cmpgdu.le.qb r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t1, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t5, IRExpr_ITE(mkexpr(t1), + mkU32(0x00000001), + mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + + assign(t2, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t6, IRExpr_ITE(mkexpr(t2), + mkU32(0x00000002), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + + assign(t3, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t7, IRExpr_ITE(mkexpr(t3), + mkU32(0x00000004), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x04000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfbffffff)))); + + assign(t4, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t8, IRExpr_ITE(mkexpr(t4), + mkU32(0x00000008), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x08000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xf7ffffff)))); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + mkexpr(t5), mkexpr(t6)), + mkexpr(t7)), + mkexpr(t8))); + break; + } + default: + return -1; + } + break; /* end of CMPU.EQ.QB */ + } + case 0x13: { /* SHLL.QB */ + switch(sa) { + case 0x0: { /* SHLL.QB */ + DIP("shll.qb r%d, r%d, %d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I1); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I32); + t11 = newTemp(Ity_I1); + t12 = newTemp(Ity_I1); + t13 = newTemp(Ity_I1); + t14 = newTemp(Ity_I32); + t15 = newTemp(Ity_I32); + t16 = newTemp(Ity_I1); + t17 = newTemp(Ity_I1); + t18 = newTemp(Ity_I32); + + if (0 == rs) { + putIReg(rd, getIReg(rt)); + } else { + /* Shift bits 7..0. */ + assign(t0, binop(Iop_Shl32, + unop(Iop_8Uto32, + unop(Iop_32to8, getIReg(rt))), + unop(Iop_32to8, + binop(Iop_And32, + mkU32(rs), + mkU32(0x7))))); + /* Check if discard isn't 0x0 and 0xffffffff. */ + assign(t1, binop(Iop_CmpNE32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + mkexpr(t0)))), + mkU32(0x00000000))); + assign(t2, binop(Iop_CmpNE32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + mkexpr(t0)))), + mkU32(0x000000ff))); + assign(t4, binop(Iop_Or32, + getDSPControl(), mkU32(0x400000))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + mkexpr(t4), + getDSPControl()), + getDSPControl())); + + /* Shift bits 15..8. */ + assign(t5, binop(Iop_Shl32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))), + unop(Iop_32to8, + binop(Iop_And32, + mkU32(rs), + mkU32(0x7))))); + /* Check if discard isn't 0x0 and 0xffffffff. */ + assign(t6, binop(Iop_CmpNE32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + mkexpr(t5)))), + mkU32(0x00000000))); + assign(t7, binop(Iop_CmpNE32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + mkexpr(t5)))), + mkU32(0x000000ff))); + assign(t9, binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))); + putDSPControl(IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + mkexpr(t9), + getDSPControl()), + getDSPControl())); + + /* Shift bits 23..16. */ + assign(t10, binop(Iop_Shl32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))), + unop(Iop_32to8, + binop(Iop_And32, + mkU32(rs), + mkU32(0x7))))); + /* Check if discard isn't 0x0 and 0xffffffff. */ + assign(t11, binop(Iop_CmpNE32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + mkexpr(t10)))), + mkU32(0x00000000))); + assign(t12, binop(Iop_CmpNE32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + mkexpr(t10)))), + mkU32(0x000000ff))); + + assign(t14, binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))); + putDSPControl(IRExpr_ITE(mkexpr(t11), + IRExpr_ITE(mkexpr(t12), + mkexpr(t14), + getDSPControl()), + getDSPControl())); + + /* Shift bits 31..24. */ + assign(t15, binop(Iop_Shl32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))), + unop(Iop_32to8, + binop(Iop_And32, + mkU32(rs), + mkU32(0x7))))); + /* Check if discard isn't 0x0 and 0xffffffff. */ + assign(t16, binop(Iop_CmpNE32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + mkexpr(t15)))), + mkU32(0x00000000))); + assign(t17, binop(Iop_CmpNE32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + mkexpr(t15)))), + mkU32(0x000000ff))); + + assign(t18, binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))); + putDSPControl(IRExpr_ITE(mkexpr(t16), + IRExpr_ITE(mkexpr(t17), + mkexpr(t18), + getDSPControl()), + getDSPControl())); + + putIReg(rd, binop(Iop_16HLto32, + binop(Iop_8HLto16, + unop(Iop_32to8, mkexpr(t15)), + unop(Iop_32to8, mkexpr(t10))), + binop(Iop_8HLto16, + unop(Iop_32to8, mkexpr(t5)), + unop(Iop_32to8, mkexpr(t0))))); + } + break; + } + case 0x3: { /* SHRL.QB */ + DIP("shrl.qb r%d, r%d, %d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I8); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I8); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I8); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I8); + t9 = newTemp(Ity_I32); + + assign(t9, binop(Iop_And32, getIReg(rs), mkU32(0x7))); + assign(t0, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt))))); + assign(t1, unop(Iop_32to8, + binop(Iop_Shr32, + mkexpr(t0), + unop(Iop_32to8, mkexpr(t9))))); + + assign(t2, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt))))); + assign(t3, unop(Iop_32to8, + binop(Iop_Shr32, + mkexpr(t2), + unop(Iop_32to8, mkexpr(t9))))); + + assign(t4, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t5, unop(Iop_32to8, + binop(Iop_Shr32, + mkexpr(t4), + unop(Iop_32to8, mkexpr(t9))))); + + assign(t6, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t7, unop(Iop_32to8, + binop(Iop_Shr32, + mkexpr(t6), + unop(Iop_32to8, mkexpr(t9))))); + putIReg(rd, IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t9), + mkU32(0x0)), + getIReg(rt), + binop(Iop_16HLto32, + binop(Iop_8HLto16, + mkexpr(t7), + mkexpr(t5)), + binop(Iop_8HLto16, + mkexpr(t3), + mkexpr(t1))))); + break; + } + case 0x2: { /* SHLLV.QB */ + DIP("shllv.qb r%d, r%d, r%d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I1); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I32); + t11 = newTemp(Ity_I1); + t12 = newTemp(Ity_I1); + t13 = newTemp(Ity_I1); + t14 = newTemp(Ity_I32); + t15 = newTemp(Ity_I32); + t16 = newTemp(Ity_I1); + t17 = newTemp(Ity_I1); + t18 = newTemp(Ity_I32); + + /* Shift bits 7..0. */ + assign(t0, binop(Iop_Shl32, + unop(Iop_8Uto32, + unop(Iop_32to8, getIReg(rt))), + unop(Iop_32to8, + binop(Iop_And32, + getIReg(rs), + mkU32(0x7))))); + /* Check if discard isn't 0x0 and 0xffffffff. */ + assign(t1, binop(Iop_CmpNE32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, mkexpr(t0)))), + mkU32(0x00000000))); + assign(t2, binop(Iop_CmpNE32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, mkexpr(t0)))), + mkU32(0x000000ff))); + + assign(t4, binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + mkexpr(t4), + getDSPControl()), + getDSPControl())); + + /* Shift bits 15..8. */ + assign(t5, binop(Iop_Shl32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))), + unop(Iop_32to8, + binop(Iop_And32, + getIReg(rs), + mkU32(0x7))))); + /* Check if discard isn't 0x0 and 0xffffffff. */ + assign(t6, binop(Iop_CmpNE32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, mkexpr(t5)))), + mkU32(0x00000000))); + assign(t7, binop(Iop_CmpNE32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, mkexpr(t5)))), + mkU32(0x000000ff))); + + assign(t9, binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))); + putDSPControl(IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + mkexpr(t9), + getDSPControl()), + getDSPControl())); + + /* Shift bits 23..16. */ + assign(t10, binop(Iop_Shl32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))), + unop(Iop_32to8, + binop(Iop_And32, + getIReg(rs), + mkU32(0x7))))); + /* Check if discard isn't 0x0 and 0xffffffff. */ + assign(t11, binop(Iop_CmpNE32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + mkexpr(t10)))), + mkU32(0x00000000))); + assign(t12, binop(Iop_CmpNE32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + mkexpr(t10)))), + mkU32(0x000000ff))); + + assign(t14, binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))); + putDSPControl(IRExpr_ITE(mkexpr(t11), + IRExpr_ITE(mkexpr(t12), + mkexpr(t14), + getDSPControl()), + getDSPControl())); + + /* Shift bits 31..24. */ + assign(t15, binop(Iop_Shl32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))), + unop(Iop_32to8, + binop(Iop_And32, + getIReg(rs), + mkU32(0x7))))); + /* Check if discard isn't 0x0 and 0xffffffff. */ + assign(t16, binop(Iop_CmpNE32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + mkexpr(t15)))), + mkU32(0x00000000))); + assign(t17, binop(Iop_CmpNE32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + mkexpr(t15)))), + mkU32(0x000000ff))); + + assign(t18, binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))); + putDSPControl(IRExpr_ITE(mkexpr(t16), + IRExpr_ITE(mkexpr(t17), + mkexpr(t18), + getDSPControl()), + getDSPControl())); + + putIReg(rd, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rs), + mkU32(0x7)), + mkU32(0x0)), + getIReg(rt), + binop(Iop_16HLto32, + binop(Iop_8HLto16, + unop(Iop_32to8, + mkexpr(t15)), + unop(Iop_32to8, + mkexpr(t10))), + binop(Iop_8HLto16, + unop(Iop_32to8, + mkexpr(t5)), + unop(Iop_32to8, + mkexpr(t0)))))); + break; + } + case 0x1: { /* SHRLV.QB */ + DIP("shrlv.qb r%d, r%d, r%d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I8); + t1 = newTemp(Ity_I8); + t2 = newTemp(Ity_I8); + t3 = newTemp(Ity_I8); + + assign(t0, unop(Iop_32to8, + binop(Iop_Shr32, + unop(Iop_8Uto32, + unop(Iop_32to8, getIReg(rt))), + mkU8(rs)))); + assign(t1, unop(Iop_32to8, + binop(Iop_Shr32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))), + mkU8(rs)))); + assign(t2, unop(Iop_32to8, + binop(Iop_Shr32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(rs)))); + assign(t3, unop(Iop_32to8, + binop(Iop_Shr32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(rs)))); + putIReg(rd, + binop(Iop_16HLto32, + binop(Iop_8HLto16, mkexpr(t3), mkexpr(t2)), + binop(Iop_8HLto16, mkexpr(t1), mkexpr(t0)))); + break; + } + case 0x4: { /* SHRA.QB */ + DIP("shra.qb r%d, r%d, %d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I32); + t11 = newTemp(Ity_I32); + + /* ========== GPR[rt]_31..24 ========== */ + assign(t1, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t2, + binop(Iop_Shr32, mkexpr(t1), mkU8(rs))); + /* tempD_7..0 */ + assign(t0, + binop(Iop_Or32, + mkexpr(t2), + binop(Iop_Shl32, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t1), + mkU32(0x00000080) + ), + mkU32(0x00000080)), + mkU32(0xFFFFFFFF), + mkU32(0x00000000)), + binop(Iop_Sub8, mkU8(0x8), mkU8(rs))))); + + /* ========== GPR[rt]_23..16 ========== */ + assign(t4, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t5, binop(Iop_Shr32, mkexpr(t4), mkU8(rs))); + /* tempC_7..0 */ + assign(t3, + binop(Iop_Or32, + mkexpr(t5), + binop(Iop_Shl32, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t4), + mkU32(0x00000080) + ), + mkU32(0x00000080)), + mkU32(0xFFFFFFFF), + mkU32(0x00000000)), + binop(Iop_Sub8, mkU8(0x8), mkU8(rs))))); + + /* ========== GPR[rt]_15..8 ========== */ + assign(t7, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt))))); + assign(t8, binop(Iop_Shr32, mkexpr(t7), mkU8(rs))); + /* tempB_7..0 */ + assign(t6, + binop(Iop_Or32, + mkexpr(t8), + binop(Iop_Shl32, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t7), + mkU32(0x00000080) + ), + mkU32(0x00000080)), + mkU32(0xFFFFFFFF), + mkU32(0x00000000)), + binop(Iop_Sub8, mkU8(0x8), mkU8(rs))))); + + /* ========== GPR[rt]_7..0 ========== */ + assign(t10, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt))))); + assign(t11, binop(Iop_Shr32, mkexpr(t10), mkU8(rs))); + /* tempB_7..0 */ + assign(t9, + binop(Iop_Or32, + mkexpr(t11), + binop(Iop_Shl32, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t10), + mkU32(0x00000080) + ), + mkU32(0x00000080)), + mkU32(0xFFFFFFFF), + mkU32(0x00000000)), + binop(Iop_Sub8, mkU8(0x8), mkU8(rs))))); + + putIReg(rd, + binop(Iop_16HLto32, + binop(Iop_8HLto16, + unop(Iop_32to8, mkexpr(t0)), + unop(Iop_32to8, mkexpr(t3))), + binop(Iop_8HLto16, + unop(Iop_32to8, mkexpr(t6)), + unop(Iop_32to8, mkexpr(t9))))); + break; + } + case 0x5: { /* SHRA_R.QB */ + DIP("shra_r.qb r%d, r%d, %d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I8); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I8); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I8); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I8); + + if (0 == rs) { + putIReg(rd, getIReg(rt)); + } else { + assign(t0, unop(Iop_8Sto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt))))); + assign(t1, unop(Iop_32to8, + binop(Iop_Sar32, + binop(Iop_Add32, + mkexpr(t0), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(rs-1))), + mkU8(rs)))); + + assign(t2, unop(Iop_8Sto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt))))); + assign(t3, unop(Iop_32to8, + binop(Iop_Sar32, + binop(Iop_Add32, + mkexpr(t2), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(rs-1))), + mkU8(rs)))); + + assign(t4, unop(Iop_8Sto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t5, unop(Iop_32to8, + binop(Iop_Sar32, + binop(Iop_Add32, + mkexpr(t4), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(rs-1))), + mkU8(rs)))); + + assign(t6, unop(Iop_8Sto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t7, unop(Iop_32to8, + binop(Iop_Sar32, + binop(Iop_Add32, + mkexpr(t6), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(rs-1))), + mkU8(rs)))); + putIReg(rd, binop(Iop_16HLto32, + binop(Iop_8HLto16, + mkexpr(t7), mkexpr(t5)), + binop(Iop_8HLto16, + mkexpr(t3), mkexpr(t1)))); + } + break; + } + case 0x6: { /* SHRAV.QB */ + DIP("shrav.qb r%d, r%d, %d", rd, rt, rs); + vassert(!mode64); + + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I32); + t11 = newTemp(Ity_I32); + + /* ========== GPR[rt]_31..24 ========== */ + assign(t1, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t2, + binop(Iop_Shr32, + mkexpr(t1), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x7))))); + /* tempD_7..0 */ + assign(t0, + binop(Iop_Or32, + mkexpr(t2), + binop(Iop_Shl32, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t1), + mkU32(0x00000080) + ), + mkU32(0x00000080)), + mkU32(0xFFFFFFFF), + mkU32(0x00000000)), + binop(Iop_Sub8, + mkU8(0x8), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x7))) + )))); + + /* ========== GPR[rt]_23..16 ========== */ + assign(t4, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t5, + binop(Iop_Shr32, + mkexpr(t4), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x7))))); + /* tempC_7..0 */ + assign(t3, + binop(Iop_Or32, + mkexpr(t5), + binop(Iop_Shl32, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t4), + mkU32(0x00000080) + ), + mkU32(0x00000080)), + mkU32(0xFFFFFFFF), + mkU32(0x00000000)), + binop(Iop_Sub8, + mkU8(0x8), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x7))) + )))); + + /* ========== GPR[rt]_15..8 ========== */ + assign(t7, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt))))); + assign(t8, + binop(Iop_Shr32, + mkexpr(t7), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x7))))); + /* tempB_7..0 */ + assign(t6, + binop(Iop_Or32, + mkexpr(t8), + binop(Iop_Shl32, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t7), + mkU32(0x00000080) + ), + mkU32(0x00000080)), + mkU32(0xFFFFFFFF), + mkU32(0x00000000)), + binop(Iop_Sub8, + mkU8(0x8), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x7))) + )))); + + /* ========== GPR[rt]_7..0 ========== */ + assign(t10, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt))))); + assign(t11, + binop(Iop_Shr32, + mkexpr(t10), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x7))))); + /* tempB_7..0 */ + assign(t9, + binop(Iop_Or32, + mkexpr(t11), + binop(Iop_Shl32, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t10), + mkU32(0x00000080) + ), + mkU32(0x00000080)), + mkU32(0xFFFFFFFF), + mkU32(0x00000000)), + binop(Iop_Sub8, + mkU8(0x8), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x7))) + )))); + + putIReg(rd, + binop(Iop_16HLto32, + binop(Iop_8HLto16, + unop(Iop_32to8, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkU32(rs), + mkU32(0x7) + ), + mkU32(0x0)), + mkexpr(t1), + mkexpr(t0))), + unop(Iop_32to8, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkU32(rs), + mkU32(0x7) + ), + mkU32(0x0)), + mkexpr(t2), + mkexpr(t3)))), + binop(Iop_8HLto16, + unop(Iop_32to8, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkU32(rs), + mkU32(0x7) + ), + mkU32(0x0)), + mkexpr(t5), + mkexpr(t6))), + unop(Iop_32to8, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkU32(rs), + mkU32(0x7) + ), + mkU32(0x0)), + mkexpr(t8), + mkexpr(t9)))))); + break; + } + case 0x7: { /* SHRAV_R.QB */ + DIP("shrav_r.qb r%d, r%d, r%d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I8); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I8); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I8); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I8); + t8 = newTemp(Ity_I8); + t9 = newTemp(Ity_I32); + + assign(t9, binop(Iop_And32, getIReg(rs), mkU32(0x7))); + assign(t8, unop(Iop_32to8, + binop(Iop_Sub32, mkexpr(t9), mkU32(0x1)))); + assign(t0, unop(Iop_8Sto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt))))); + assign(t1, unop(Iop_32to8, + binop(Iop_Sar32, + binop(Iop_Add32, + mkexpr(t0), + binop(Iop_Shl32, + mkU32(0x1), + mkexpr(t8))), + unop(Iop_32to8, + mkexpr(t9))))); + + assign(t2, unop(Iop_8Sto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt))))); + assign(t3, unop(Iop_32to8, + binop(Iop_Sar32, + binop(Iop_Add32, + mkexpr(t2), + binop(Iop_Shl32, + mkU32(0x1), + mkexpr(t8))), + unop(Iop_32to8, mkexpr(t9))))); + + assign(t4, unop(Iop_8Sto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t5, unop(Iop_32to8, + binop(Iop_Sar32, + binop(Iop_Add32, + mkexpr(t4), + binop(Iop_Shl32, + mkU32(0x1), + mkexpr(t8))), + unop(Iop_32to8, mkexpr(t9))))); + + assign(t6, unop(Iop_8Sto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t7, unop(Iop_32to8, + binop(Iop_Sar32, + binop(Iop_Add32, + mkexpr(t6), + binop(Iop_Shl32, + mkU32(0x1), + mkexpr(t8))), + unop(Iop_32to8, mkexpr(t9))))); + putIReg(rd, IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t9), + mkU32(0x0)), + getIReg(rt), + binop(Iop_16HLto32, + binop(Iop_8HLto16, + mkexpr(t7), + mkexpr(t5)), + binop(Iop_8HLto16, + mkexpr(t3), + mkexpr(t1))))); + break; + } + case 0x8: { /* SHLL.PH */ + DIP("shll.ph r%d, r%d, %d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I1); + + if (0 == rs) { + putIReg(rd, getIReg(rt)); + } else { + /* Shift lower 16 bits. */ + assign(t0, binop(Iop_Shl32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + mkU8(rs))); + + assign(t2, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + mkexpr(t0))), + mkU32(0xffffffff)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + mkexpr(t0))), + mkU32(0x00000000)), + mkexpr(t2), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00008000)), + binop(Iop_And32, + mkexpr(t0), + mkU32(0x00008000)) + ), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)))); + /* Shift higher 16 bits. */ + assign(t1, binop(Iop_Shl32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU8(rs))); + + assign(t3, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + mkexpr(t1))), + mkU32(0xffffffff)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + mkexpr(t1))), + mkU32(0x00000000)), + mkexpr(t3), + getDSPControl())); + assign(t4, binop(Iop_CmpEQ32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31)), + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t1), + mkU32(0x00008000)), + mkU8(15)))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)))); + + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t1)), + unop(Iop_32to16, mkexpr(t0)))); + } + break; + } + case 0x9: { /* SHRA.PH */ + DIP("shra.ph r%d, r%d, %d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + if (0 == rs) { + putIReg(rd, getIReg(rt)); + } else { + assign(t0, binop(Iop_Sar32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + mkU8(rs))); + assign(t1, binop(Iop_Sar32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU8(rs))); + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t1)), + unop(Iop_32to16, mkexpr(t0)))); + } + break; + } + case 0xA: { /* SHLLV.PH */ + DIP("shllv.ph r%d, r%d, r%d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I1); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I32); + t11 = newTemp(Ity_I32); + t12 = newTemp(Ity_I1); + t13 = newTemp(Ity_I1); + + assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f))); + + /* Shift lower 16 bits. */ + assign(t2, binop(Iop_Shl32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + unop(Iop_32to8, mkexpr(t0)))); + + assign(t3, binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, mkexpr(t2))), + mkU32(0x00000000))); + assign(t4, binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, mkexpr(t2))), + mkU32(0xffffffff))); + assign(t10, binop(Iop_And32, + unop(Iop_1Sto32, mkexpr(t3)), + unop(Iop_1Sto32, mkexpr(t4)))); + assign(t5, binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00008000)), + mkU8(15))); + assign(t12, binop(Iop_CmpEQ32, + mkexpr(t5), + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00008000)), + mkU8(15)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t10), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + IRExpr_ITE(mkexpr(t12), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))) + )); + /* Shift higher 16 bits. */ + assign(t6, binop(Iop_Shl32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_32to8, mkexpr(t0)))); + + assign(t7, binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, mkexpr(t6))), + mkU32(0x00000000))); + assign(t8, binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, mkexpr(t6))), + mkU32(0xffffffff))); + assign(t11, binop(Iop_And32, + unop(Iop_1Sto32, mkexpr(t7)), + unop(Iop_1Sto32, mkexpr(t8)))); + + assign(t9, binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31))); + assign(t13, binop(Iop_CmpEQ32, + mkexpr(t9), + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t6), + mkU32(0x00008000)), + mkU8(15)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t11), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + IRExpr_ITE(mkexpr(t13), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))) + )); + + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t6)), + unop(Iop_32to16, mkexpr(t2)))); + break; + } + case 0xB: { /* SHRAV.PH */ + DIP("shrav.ph r%d, r%d, r%d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + + assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f))); + assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0))); + assign(t2, binop(Iop_Sar32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + unop(Iop_32to8, mkexpr(t0)))); + assign(t3, binop(Iop_Sar32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_32to8, mkexpr(t0)))); + putIReg(rd, + binop(Iop_16HLto32, + IRExpr_ITE(mkexpr(t1), + unop(Iop_32HIto16, getIReg(rt)), + unop(Iop_32to16, mkexpr(t3))), + IRExpr_ITE(mkexpr(t1), + unop(Iop_32to16, getIReg(rt)), + unop(Iop_32to16, mkexpr(t2))))); + break; + } + case 0xC: { /* SHLL_S.PH */ + DIP("shll_s.ph r%d, r%d, %d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I16); + t2 = newTemp(Ity_I16); + t3 = newTemp(Ity_I16); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I16); + t6 = newTemp(Ity_I16); + t7 = newTemp(Ity_I16); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I1); + t11 = newTemp(Ity_I32); + t12 = newTemp(Ity_I32); + + if (0 == rs) { + putIReg(rd, getIReg(rt)); + } else { + /* Shift lower 16 bits. */ + assign(t0, binop(Iop_Shl32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + mkU8(rs))); + + assign(t1, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00008000)), + mkU32(0x0)), + mkU16(0x7fff), + mkU16(0x8000))); + assign(t2, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00008000)), + mkU8(15)), + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x00008000)), + mkU8(15))), + unop(Iop_32to16, mkexpr(t0)), + mkexpr(t1))); + assign(t11, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + mkexpr(t0))), + mkU32(0xffffffff)), + mkexpr(t1), + mkexpr(t2))); + assign(t3, + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + mkexpr(t0))), + mkU32(0x00000000)), + mkexpr(t11), + mkexpr(t2))); + assign(t8, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + mkexpr(t0))), + mkU32(0xffffffff)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + mkexpr(t0))), + mkU32(0x00000000)), + mkexpr(t8), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00008000)), + binop(Iop_And32, + mkexpr(t0), + mkU32(0x00008000))), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)))); + /* Shift higher 16 bits. */ + assign(t4, binop(Iop_Shl32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU8(rs))); + + assign(t5, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU32(0x0)), + mkU16(0x7fff), + mkU16(0x8000))); + assign(t6, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31)), + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t4), + mkU32(0x00008000)), + mkU8(15))), + unop(Iop_32to16, mkexpr(t4)), + mkexpr(t5))); + assign(t12, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + mkexpr(t4))), + mkU32(0xffffffff)), + mkexpr(t5), + mkexpr(t6))); + assign(t7, + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + mkexpr(t4))), + mkU32(0x00000000)), + mkexpr(t12), + mkexpr(t6))); + assign(t9, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + mkexpr(t4))), + mkU32(0xffffffff)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + mkexpr(t4))), + mkU32(0x00000000)), + mkexpr(t9), + getDSPControl())); + assign(t10, binop(Iop_CmpEQ32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31)), + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t4), + mkU32(0x00008000)), + mkU8(15)))); + putDSPControl(IRExpr_ITE(mkexpr(t10), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)))); + + putIReg(rd, binop(Iop_16HLto32, + mkexpr(t7), mkexpr(t3))); + } + break; + } + case 0xD: { /* SHRA_R.PH */ + DIP("shra.ph r%d, r%d, %d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + if (0 == rs) { + putIReg(rd, getIReg(rt)); + } else { + assign(t0, binop(Iop_Sar32, + binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rt))), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(rs-1))), + mkU8(rs))); + assign(t1, binop(Iop_Sar32, + binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt))), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(rs-1))), + mkU8(rs))); + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t1)), + unop(Iop_32to16, mkexpr(t0)))); + } + break; + } + case 0xE: { /* SHLLV_S.PH */ + DIP("shllv_s.ph r%d, r%d, r%d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I1); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I32); + t11 = newTemp(Ity_I32); + t12 = newTemp(Ity_I1); + t13 = newTemp(Ity_I1); + t14 = newTemp(Ity_I16); + t15 = newTemp(Ity_I16); + t16 = newTemp(Ity_I16); + t17 = newTemp(Ity_I16); + + assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f))); + + /* Shift lower 16 bits. */ + assign(t2, binop(Iop_Shl32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + unop(Iop_32to8, mkexpr(t0)))); + + assign(t3, binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, mkexpr(t2))), + mkU32(0x00000000))); + assign(t4, binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, mkexpr(t2))), + mkU32(0xffffffff))); + assign(t10, binop(Iop_And32, + unop(Iop_1Sto32, mkexpr(t3)), + unop(Iop_1Sto32, mkexpr(t4)))); + assign(t5, binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00008000)), + mkU8(15))); + assign(t12, binop(Iop_CmpEQ32, + mkexpr(t5), + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00008000)), + mkU8(15)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t10), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + IRExpr_ITE(mkexpr(t12), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))) + )); + assign(t14, IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t5), + mkU32(0x0)), + mkU16(0x8000), + mkU16(0x7fff))); + assign(t15, IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t10), + mkU32(0x0)), + mkexpr(t14), + IRExpr_ITE(mkexpr(t12), + unop(Iop_32to16, + mkexpr(t2)), + mkexpr(t14)))); + /* Shift higher 16 bits. */ + assign(t6, binop(Iop_Shl32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_32to8, mkexpr(t0)))); + + assign(t7, binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, mkexpr(t6))), + mkU32(0x00000000))); + assign(t8, binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, mkexpr(t6))), + mkU32(0xffffffff))); + assign(t11, binop(Iop_And32, + unop(Iop_1Sto32, mkexpr(t7)), + unop(Iop_1Sto32, mkexpr(t8)))); + + assign(t9, binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31))); + assign(t13, binop(Iop_CmpEQ32, + mkexpr(t9), + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t6), + mkU32(0x00008000)), + mkU8(15)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t11), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + IRExpr_ITE(mkexpr(t13), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))) + )); + + assign(t16, IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t9), + mkU32(0x0)), + mkU16(0x8000), + mkU16(0x7fff))); + assign(t17, IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t11), + mkU32(0x0)), + mkexpr(t16), + IRExpr_ITE(mkexpr(t13), + unop(Iop_32to16, + mkexpr(t6)), + mkexpr(t16)))); + + putIReg(rd, binop(Iop_16HLto32, mkexpr(t17), mkexpr(t15))); + break; + } + case 0xF: { /* SHRAV_R.PH */ + DIP("shrav_r.ph r%d, r%d, r%d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I8); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + + assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f))); + assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0))); + assign(t2, unop(Iop_32to8, + binop(Iop_Sub32, mkexpr(t0), mkU32(1)))); + + assign(t3, binop(Iop_Sar32, + binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + binop(Iop_Shl32, + mkU32(0x1), + mkexpr(t2))), + unop(Iop_32to8, mkexpr(t0)))); + assign(t4, binop(Iop_Sar32, + binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt))), + binop(Iop_Shl32, + mkU32(0x1), + mkexpr(t2))), + unop(Iop_32to8, mkexpr(t0)))); + + putIReg(rd, binop(Iop_16HLto32, + IRExpr_ITE(mkexpr(t1), + unop(Iop_32HIto16, + getIReg(rt)), + unop(Iop_32to16, + mkexpr(t4))), + IRExpr_ITE(mkexpr(t1), + unop(Iop_32to16, getIReg(rt)), + unop(Iop_32to16, + mkexpr(t3))))); + break; + } + case 0x14: { /* SHLL_S.W */ + DIP("shll_s.w r%d, r%d, %d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + + if (0 == rs) { + putIReg(rd, getIReg(rt)); + } else { + /* t0-bits that will be discarded, sign extended to + 32bits. */ + assign(t0, binop(Iop_Sar32, + binop(Iop_And32, + getIReg(rt), + binop(Iop_Sar32, + mkU32(0x80000000), + mkU8(rs-1))), + mkU8(32-rs))); + + assign(t1, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU32(0x0)), + mkU32(0x7fffffff), + mkU32(0x80000000))); + + assign(t2, binop(Iop_Shl32, getIReg(rt), mkU8(rs))); + assign(t3, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + binop(Iop_And32, + mkexpr(t2), + mkU32(0x80000000))), + mkexpr(t2), + mkexpr(t1))); + + assign(t4, IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t0), + mkU32(0x0)), + IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t0), + mkU32(0xffffffff) + ), + mkexpr(t1), + mkexpr(t3)), + mkexpr(t3))); + assign(t5, IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t0), + mkU32(0xffffffff)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t0), + mkU32(0x0)), + mkexpr(t5), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + binop(Iop_And32, + mkexpr(t2), + mkU32(0x80000000)) + ), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)))); + putIReg(rd, mkexpr(t4)); + } + break; + } + case 0x15: { /* SHRA_R.W */ + DIP("shra_r.w r%d, r%d, %d", rd, rt, rs); + vassert(!mode64); + if (0 == rs) { + putIReg(rd, getIReg(rt)); + } else { + putIReg(rd, binop(Iop_Add32, + binop(Iop_Sar32, + getIReg(rt), mkU8(rs)), + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(rs-1))), + mkU8(rs-1)))); + } + break; + } + case 0x16: { /* SHLLV_S.W */ + DIP("shllv_s.w r%d, r%d, r%d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I64); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I32); + + /* Check if shift amount is zero. */ + assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x1f))); + assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0))); + + /* t2 = sign of the input value. */ + assign(t2, binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31))); + /* Shift left input value and check for overflow. */ + assign(t3, binop(Iop_Shl64, + unop(Iop_32Sto64, getIReg(rt)), + unop(Iop_32to8, mkexpr(t0)))); + assign(t4, binop(Iop_CmpNE32, + unop(Iop_64HIto32, mkexpr(t3)), + mkU32(0x00000000))); + assign(t5, binop(Iop_CmpNE32, + unop(Iop_64HIto32, mkexpr(t3)), + mkU32(0xffffffff))); + assign(t6, binop(Iop_And32, + unop(Iop_1Uto32, mkexpr(t4)), + unop(Iop_1Uto32, mkexpr(t5)))); + assign(t7, binop(Iop_CmpEQ32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31)), + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64to32, mkexpr(t3)), + mkU32(0x80000000)), + mkU8(31)))); + + putDSPControl(IRExpr_ITE(unop(Iop_32to1, mkexpr(t6)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + IRExpr_ITE(mkexpr(t7), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))) + )); + + assign(t8, IRExpr_ITE(unop(Iop_32to1, + mkexpr(t2)), + mkU32(0x80000000), + mkU32(0x7fffffff))); + putIReg(rd, IRExpr_ITE(unop(Iop_32to1, mkexpr(t6)), + IRExpr_ITE(unop(Iop_32to1, + mkexpr(t2)), + mkU32(0x80000000), + mkU32(0x7fffffff)), + IRExpr_ITE(mkexpr(t7), + unop(Iop_64to32, + mkexpr(t3)), + mkexpr(t8)))); + break; + } + case 0x17: { /* SHRAV_R.W */ + DIP("shrav_r.w r%d, r%d, r%d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I8); + t3 = newTemp(Ity_I32); + + assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x1f))); + assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0))); + assign(t2, unop(Iop_32to8, + binop(Iop_Sub32, mkexpr(t0), mkU32(1)))); + + putIReg(rd, IRExpr_ITE(mkexpr(t1), + getIReg(rt), + binop(Iop_Sar32, + binop(Iop_Add32, + binop(Iop_Sar32, + getIReg(rt), + mkexpr(t2)), + mkU32(0x1)), + mkU8(1)))); + break; + } + case 0x19: { /* SHRL.PH */ + DIP("shrl.ph r%d, r%d, %d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + assign(t0, binop(Iop_Shr32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + mkU8(rs))); + assign(t1, binop(Iop_Shr32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU8(rs))); + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t1)), + unop(Iop_32to16, mkexpr(t0)))); + break; + } + case 0x1B: { /* SHRLV.PH */ + DIP("shrlv.ph r%d, r%d, r%d", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I16); + t5 = newTemp(Ity_I16); + + /* Get shift amount from lower 5 bits of rs + and check if it is zero. */ + assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f))); + assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0))); + + assign(t2, binop(Iop_Shr32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + unop(Iop_32to8, mkexpr(t0)))); + assign(t3, binop(Iop_Shr32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_32to8, mkexpr(t0)))); + + assign(t4, IRExpr_ITE(mkexpr(t1), + unop(Iop_32HIto16, getIReg(rt)), + unop(Iop_32to16, mkexpr(t3)))); + assign(t5, IRExpr_ITE(mkexpr(t1), + unop(Iop_32to16, getIReg(rt)), + unop(Iop_32to16, mkexpr(t2)))); + putIReg(rd, binop(Iop_16HLto32, mkexpr(t4), mkexpr(t5))); + break; + } + default: + return -1; + } + break; /* end of SHLL.QB */ + } + case 0x18: { /* ADDUH.QB/MUL.PH */ + switch(sa) { + case 0x00: { /* ADDUH.QB */ + DIP("adduh.qb r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + + assign(t0, binop(Iop_HAdd8Ux4, getIReg(rs), getIReg(rt))); + + putIReg(rd, mkexpr(t0)); + break; + } + case 0x1: { /* SUBUH.QB */ + DIP("subuh.qb r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + + assign(t0, binop(Iop_HSub8Ux4, getIReg(rs), getIReg(rt))); + + putIReg(rd, mkexpr(t0)); + break; + } + case 0x02: { /* ADDUH_R.QB */ + DIP("adduh_r.qb r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I8); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I8); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I8); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I32); + t11 = newTemp(Ity_I8); + + /* Extract input bytes, add values, add 1 and half the + result. */ + assign(t0, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs))))); + assign(t1, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt))))); + assign(t2, unop(Iop_16to8, + unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Add32, + mkexpr(t0), + mkexpr(t1)), + mkU32(0x00000001)), + mkU8(0x01))))); + + assign(t3, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs))))); + assign(t4, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt))))); + assign(t5, unop(Iop_16to8, + unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Add32, + mkexpr(t3), + mkexpr(t4)), + mkU32(0x00000001)), + mkU8(0x01))))); + + assign(t6, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs))))); + assign(t7, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t8, unop(Iop_16to8, + unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Add32, + mkexpr(t7), + mkexpr(t6)), + mkU32(0x00000001)), + mkU8(0x01))))); + + assign(t9, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs))))); + assign(t10, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t11, unop(Iop_16to8, + unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Add32, + mkexpr(t9), + mkexpr(t10)), + mkU32(0x00000001)), + mkU8(0x01))))); + + putIReg(rd, binop(Iop_16HLto32, + binop(Iop_8HLto16, + mkexpr(t11), mkexpr(t8)), + binop(Iop_8HLto16, + mkexpr(t5), mkexpr(t2)))); + break; + } + case 0x3: { /* SUBUH_R.QB */ + DIP("subuh_r.qb r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I8); + t10 = newTemp(Ity_I8); + t11 = newTemp(Ity_I8); + t12 = newTemp(Ity_I8); + + /* Extract each byte of rs and rt. */ + assign(t1, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs))))); + assign(t2, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs))))); + assign(t3, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs))))); + assign(t4, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs))))); + + assign(t5, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt))))); + assign(t6, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt))))); + assign(t7, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t8, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Add 1 to each resulting byte and half the results. */ + assign(t9, unop(Iop_16to8, + unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Sub32, + mkexpr(t1), + mkexpr(t5)), + mkU32(0x00000001)), + mkU8(0x01))))); + assign(t10, unop(Iop_16to8, + unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Sub32, + mkexpr(t2), + mkexpr(t6)), + mkU32(0x00000001)), + mkU8(0x01))))); + assign(t11, unop(Iop_16to8, + unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Sub32, + mkexpr(t3), + mkexpr(t7)), + mkU32(0x00000001)), + mkU8(0x01))))); + assign(t12, unop(Iop_16to8, + unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Sub32, + mkexpr(t4), + mkexpr(t8)), + mkU32(0x00000001)), + mkU8(0x01))))); + + putIReg(rd, binop(Iop_16HLto32, + binop(Iop_8HLto16, + mkexpr(t12), mkexpr(t11)), + binop(Iop_8HLto16, + mkexpr(t10), mkexpr(t9)))); + break; + } + case 0x8: { /* ADDQH.PH */ + DIP("addqh.ph r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I16); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I16); + + /* Add lower halfs of rs and rt + and right shift the result by 1. */ + assign(t0, binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + assign(t1, unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x0001fffe)), + mkU8(0x1)))); + /* Add higher halfs of rs and rt + and right shift the result by 1. */ + assign(t2, binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t3, unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x0001fffe)), + mkU8(0x1)))); + putIReg(rd, binop(Iop_16HLto32, mkexpr(t3), mkexpr(t1))); + break; + } + case 0x9: { /* SUBQH.PH */ + DIP("subqh.ph r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_HSub16Sx2, + getIReg(rs), getIReg(rt))); + break; + } + case 0xA: {/* ADDQH_R.PH */ + DIP("addqh_r.ph r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I16); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I16); + + /* Add lower halfs of rs and rt, add 1 + and right shift the result by 1. */ + assign(t0, binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + assign(t1, unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_And32, + binop(Iop_Add32, + mkexpr(t0), + mkU32(0x1)), + mkU32(0x0001fffe)), + mkU8(0x1)))); + /* Add higher halfs of rs and rt, add 1 + and right shift the result by 1. */ + assign(t2, binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t3, unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_And32, + binop(Iop_Add32, + mkexpr(t2), + mkU32(0x1)), + mkU32(0x0001fffe)), + mkU8(0x1)))); + + putIReg(rd, binop(Iop_16HLto32, mkexpr(t3), mkexpr(t1))); + break; + } + case 0xB: { /* SUBQH_R.PH */ + DIP("subqh_r.ph r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I16); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I16); + + /* Sub lower halfs of rs and rt, add 1 + and right shift the result by 1. */ + assign(t0, binop(Iop_Sub32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + assign(t1, unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_And32, + binop(Iop_Add32, + mkexpr(t0), + mkU32(0x1)), + mkU32(0x0001fffe)), + mkU8(0x1)))); + /* Sub higher halfs of rs and rt, add 1 + and right shift the result by 1. */ + assign(t2, binop(Iop_Sub32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t3, unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_And32, + binop(Iop_Add32, + mkexpr(t2), + mkU32(0x1)), + mkU32(0x0001fffe)), + mkU8(0x1)))); + + putIReg(rd, binop(Iop_16HLto32, mkexpr(t3), mkexpr(t1))); + break; + } + case 0xC: { /* MUL.PH */ + DIP("mul.ph r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + + assign(t0, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + /* DSP Control flag. */ + putDSPControl(IRExpr_ITE(unop(Iop_Not1, + binop(Iop_CmpLE32S, + mkexpr(t0), + mkU32(0x7FFF))), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000)), + IRExpr_ITE(binop(Iop_CmpLT32S, + mkexpr(t0), + mkU32(0xFFFF8000) + ), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000) + ), + getDSPControl()))); + + assign(t1, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + /* DSP Control flag. */ + putDSPControl(IRExpr_ITE(unop(Iop_Not1, + binop(Iop_CmpLE32S, + mkexpr(t1), + mkU32(0x7FFF))), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000)), + IRExpr_ITE(binop(Iop_CmpLT32S, + mkexpr(t1), + mkU32(0xFFFF8000) + ), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000) + ), + getDSPControl()))); + + assign(t2, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t0)), + unop(Iop_32to16, mkexpr(t1)))); + putIReg(rd, mkexpr(t2)); + break; + } + case 0xE: { /* MUL_S.PH */ + DIP("mul_s.ph r%d r%d, r%d", rd, rs, rt); + vassert(!mode64); + + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + + /* t0 - signed intermediate result. */ + assign(t0, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + + assign(t1, + IRExpr_ITE(unop(Iop_Not1, + binop(Iop_CmpLE32S, + mkexpr(t0), + mkU32(0x7FFF))), + mkU32(0x00007FFF), + IRExpr_ITE(binop(Iop_CmpLT32S, + mkexpr(t0), + mkU32(0xFFFF8000)), + mkU32(0xFFFF8000), + mkexpr(t0)))); + + /* DSP Control flag. */ + putDSPControl(IRExpr_ITE(unop(Iop_Not1, + binop(Iop_CmpLE32S, + mkexpr(t0), + mkU32(0x7FFF))), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000)), + IRExpr_ITE(binop(Iop_CmpLT32S, + mkexpr(t0), + mkU32(0xFFFF8000) + ), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000) + ), + getDSPControl()))); + + /* t2 - signed intermediate result. */ + assign(t2, binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + + assign(t3, IRExpr_ITE(unop(Iop_Not1, + binop(Iop_CmpLE32S, + mkexpr(t2), + mkU32(0x7FFF))), + mkU32(0x00007FFF), + IRExpr_ITE(binop(Iop_CmpLT32S, + mkexpr(t2), + mkU32(0xFFFF8000)), + mkU32(0xFFFF8000), + mkexpr(t2)))); + + /* DSP Control flag. */ + putDSPControl(IRExpr_ITE(unop(Iop_Not1, + binop(Iop_CmpLE32S, + mkexpr(t2), + mkU32(0x7FFF))), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000)), + IRExpr_ITE(binop(Iop_CmpLT32S, + mkexpr(t2), + mkU32(0xFFFF8000) + ), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000) + ), + getDSPControl()))); + + assign(t4, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t1)), + unop(Iop_32to16, mkexpr(t3)))); + putIReg(rd, mkexpr(t4)); + break; + } + case 0x10: { /* ADDQH.W */ + DIP("addqh.w r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + + assign(t0, binop(Iop_Add64, + unop(Iop_32Sto64, getIReg(rs)), + unop(Iop_32Sto64, getIReg(rt)))); + assign(t1, binop(Iop_And64, + mkexpr(t0), + mkU64(0x00000001fffffffeULL))); + putIReg(rd, unop(Iop_64to32, + binop(Iop_Shr64, mkexpr(t1), mkU8(0x1)))); + break; + } + case 0x11: { /* SUBQH.W */ + DIP("subqh.w r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + + assign(t0, binop(Iop_Sub64, + unop(Iop_32Sto64, getIReg(rs)), + unop(Iop_32Sto64, getIReg(rt)))); + assign(t1, binop(Iop_And64, + mkexpr(t0), + mkU64(0x00000001fffffffeULL))); + putIReg(rd, unop(Iop_64to32, + binop(Iop_Shr64, mkexpr(t1), mkU8(0x1)))); + break; + } + case 0x12: { /* ADDQH_R.W */ + DIP("addqh_r.w r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + + assign(t0, binop(Iop_Add64, + unop(Iop_32Sto64, getIReg(rs)), + unop(Iop_32Sto64, getIReg(rt)))); + assign(t1, binop(Iop_Add64, + mkexpr(t0), + mkU64(0x0000000000000001ULL))); + assign(t2, binop(Iop_And64, + mkexpr(t1), + mkU64(0x00000001fffffffeULL))); + putIReg(rd, unop(Iop_64to32, + binop(Iop_Shr64, mkexpr(t2), mkU8(0x1)))); + break; + } + case 0x13: { /* SUBQH_R.W */ + DIP("subqh_r.w r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + + assign(t0, binop(Iop_Sub64, + unop(Iop_32Sto64, getIReg(rs)), + unop(Iop_32Sto64, getIReg(rt)))); + assign(t1, binop(Iop_Add64, + mkexpr(t0), + mkU64(0x0000000000000001ULL))); + assign(t2, binop(Iop_And64, + mkexpr(t1), + mkU64(0x00000001fffffffeULL))); + putIReg(rd, unop(Iop_64to32, + binop(Iop_Shr64, mkexpr(t2), mkU8(0x1)))); + break; + } + case 0x16: { /* MULQ_S.W */ + DIP("mulq_s.w r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + + assign(t0, binop(Iop_Shl64, + binop(Iop_MullS32, + getIReg(rt), getIReg(rs)), + mkU8(0x1))); + assign(t1, binop(Iop_CmpEQ32, + getIReg(rt), mkU32(0x80000000))); + assign(t2, binop(Iop_CmpEQ32, + getIReg(rs), mkU32(0x80000000))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000) + ), + getDSPControl()), + getDSPControl())); + putIReg(rd, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + mkU32(0x7fffffff), + unop(Iop_64HIto32, + mkexpr(t0))), + unop(Iop_64HIto32, mkexpr(t0)))); + break; + } + case 0x17: { /* MULQ_RS.W */ + DIP("mulq_rs.w r%d, r%d, r%d", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + + assign(t0, binop(Iop_Add64, + binop(Iop_Shl64, + binop(Iop_MullS32, + getIReg(rt), + getIReg(rs)), + mkU8(0x1)), + mkU64(0x0000000080000000ULL))); + assign(t1, + binop(Iop_CmpEQ32, getIReg(rt), mkU32(0x80000000))); + assign(t2, + binop(Iop_CmpEQ32, getIReg(rs), mkU32(0x80000000))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000) + ), + getDSPControl()), + getDSPControl())); + putIReg(rd, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + mkU32(0x7fffffff), + unop(Iop_64HIto32, + mkexpr(t0))), + unop(Iop_64HIto32, mkexpr(t0)))); + break; + } + default: + return -1; + } + break; /* end of ADDUH.QB/MUL.PH */ + } + case 0x30: { /* DPAQ.W.PH */ + switch(sa) { + case 0x0: { /* DPA.W.PH */ + DIP("dpa.w.ph ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + + assign(t0, + unop(Iop_32Sto64, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t1, + unop(Iop_32Sto64, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt)))))); + assign(t2, + binop(Iop_Add64, + getAcc(ac), + binop(Iop_Add64, mkexpr(t0), mkexpr(t1)))); + putAcc(ac, mkexpr(t2)); + break; + } + case 0x1: { /* DPS.W.PH */ + DIP("dps.w.ph ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + + assign(t0, + unop(Iop_32Sto64, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t1, + unop(Iop_32Sto64, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt)))))); + assign(t2, + binop(Iop_Sub64, + getAcc(ac), + binop(Iop_Add64, mkexpr(t0), mkexpr(t1)))); + putAcc(ac, mkexpr(t2)); + break; + } + case 0x2: { /* MULSA.W.PH */ + DIP("mulsa.w.ph ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + + assign(t4, getAcc(ac)); + assign(t0, binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))))); + assign(t1, binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))))); + assign(t2, binop(Iop_Sub32, mkexpr(t1), mkexpr(t0))); + putAcc(ac, binop(Iop_Add64, + mkexpr(t4), + unop(Iop_32Sto64, mkexpr(t2)))); + break; + } + case 0x3: { /* DPAU.H.QBL */ + DIP("dpau.h.qbl ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + + assign(t0, + binop(Iop_Mul32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t1, + binop(Iop_Mul32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t2, + unop(Iop_32Uto64, + binop(Iop_Add32, + mkexpr(t0), + mkexpr(t1)))); + assign(t3, + binop(Iop_Add64, getAcc(ac), mkexpr(t2))); + putAcc(ac, mkexpr(t3)); + break; + } + case 0x4: { /* DPAQ_S.W.PH */ + DIP("dpaq_s.w.ph ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Shl64, + binop(Iop_MullS32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(0x1))); + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + mkU32(0x00008000))); + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU32(0x00008000))); + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x000000007fffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t5, binop(Iop_Shl64, + binop(Iop_MullS32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))) + ), + mkU8(0x1))); + assign(t6, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + mkU32(0x00008000))); + assign(t7, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + mkU32(0x00008000))); + assign(t8, + IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + mkU64(0x000000007fffffffULL), + mkexpr(t5)), + mkexpr(t5))); + + putDSPControl(IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t9, binop(Iop_Add64, + binop(Iop_Add64, mkexpr(t4), mkexpr(t8)), + mkexpr(t0))); + putAcc(ac, mkexpr(t9)); + break; + } + case 0x5: { /* DPSQ_S.W.PH */ + DIP("dpsq_s.w.ph ac%d r%d, r%d", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Shl64, + binop(Iop_MullS32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(0x1))); + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + mkU32(0x00008000))); + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU32(0x00008000))); + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x000000007fffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t5, + binop(Iop_Shl64, + binop(Iop_MullS32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt)))), + mkU8(0x1))); + assign(t6, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + mkU32(0x00008000))); + assign(t7, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + mkU32(0x00008000))); + assign(t8, + IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + mkU64(0x000000007fffffffULL), + mkexpr(t5)), + mkexpr(t5))); + + putDSPControl(IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t9, + binop(Iop_Sub64, + mkexpr(t0), + binop(Iop_Add64, mkexpr(t4), mkexpr(t8)))); + putAcc(ac, mkexpr(t9)); + break; + } + case 0x6: { /* MULSAQ_S.W.PH */ + DIP("mulsaq_s.w.ph ac%d r%d, r%d", ac, rs, rt); + vassert(!mode64); + + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I64); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + + assign(t0, unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs)))); + assign(t1, unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt)))); + + assign(t8, binop(Iop_And32, + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rs))), + mkU32(0x8000))), + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rt))), + mkU32(0x8000))))); + /* DSPControl_outflag:16+acc <- 1 */ + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t8), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x00010000), + mkU8(ac))), + getDSPControl())); + + /* tempB_31..0 */ + assign(t2, + IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t8), mkU32(0x0)), + mkU32(0x7FFFFFFF), + binop(Iop_Shl32, + binop(Iop_Mul32, + mkexpr(t0), mkexpr(t1)), + mkU8(1)))); + + assign(t3, unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs)))); + assign(t4, unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt)))); + + assign(t9, binop(Iop_And32, + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rs))), + mkU32(0x8000))), + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rt))), + mkU32(0x8000))))); + /* DSPControl_outflag:16+acc <- 1 */ + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t9), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x00010000), + mkU8(ac))), + getDSPControl())); + /* tempA_31..0 */ + assign(t5, + IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t9), + mkU32(0x0)), + mkU32(0x7FFFFFFF), + binop(Iop_Shl32, + binop(Iop_Mul32, + mkexpr(t3), + mkexpr(t4)), + mkU8(1)))); + /* dotp_63..0 */ + assign(t6, + binop(Iop_Sub64, + unop(Iop_32Sto64, mkexpr(t2)), + unop(Iop_32Sto64, mkexpr(t5)))); + /* tempC_63..0 */ + assign(t7, binop(Iop_Add64, getAcc(ac), mkexpr(t6))); + + putAcc(ac, mkexpr(t7)); + break; + } + case 0x7: { /* DPAU.H.QBR */ + DIP("dpau.h.qbr ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + + assign(t0, + binop(Iop_Mul32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))))); + assign(t1, + binop(Iop_Mul32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt)))))); + assign(t2, unop(Iop_32Uto64, + binop(Iop_Add32, mkexpr(t0), mkexpr(t1)))); + assign(t3, binop(Iop_Add64, getAcc(ac), mkexpr(t2))); + putAcc(ac, mkexpr(t3)); + break; + } + case 0x8: { /* DPAX.W.PH */ + DIP("dpax.w.ph ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + + assign(t0, + unop(Iop_32Sto64, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt)))))); + assign(t1, + unop(Iop_32Sto64, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t2, + binop(Iop_Add64, + getAcc(ac), + binop(Iop_Add64, mkexpr(t0), mkexpr(t1)))); + putAcc(ac, mkexpr(t2)); + break; + } + case 0x9: { /* DPSX.W.PH */ + DIP("dpsx.w.ph ac%d r%d, r%d", ac, rs, rt); + vassert(!mode64); + + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + + assign(t0, + unop(Iop_32Sto64, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt)))))); + assign(t1, + unop(Iop_32Sto64, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t2, + binop(Iop_Sub64, + getAcc(ac), + binop(Iop_Add64, mkexpr(t0), mkexpr(t1)))); + putAcc(ac, mkexpr(t2)); + break; + } + case 0xB: { /* DPSU.H.QBL */ + DIP("dpsu.h.qbl ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + + assign(t0, + binop(Iop_Mul32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t1, + binop(Iop_Mul32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t2, + unop(Iop_32Uto64, + binop(Iop_Add32, mkexpr(t0), mkexpr(t1)))); + assign(t3, + binop(Iop_Sub64, getAcc(ac), mkexpr(t2))); + putAcc(ac, mkexpr(t3)); + break; + } + case 0xC: { /* DPAQ_SA.L.W */ + DIP("dpaq_sa.l.w ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I64); + t8 = newTemp(Ity_I1); + t9 = newTemp(Ity_I1); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Shl64, + binop(Iop_MullS32, + getIReg(rs), getIReg(rt)), + mkU8(0x1))); + + assign(t2, binop(Iop_CmpEQ32, + getIReg(rs), + mkU32(0x80000000))); + assign(t3, binop(Iop_CmpEQ32, + getIReg(rt), + mkU32(0x80000000))); + + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x7fffffffffffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t5, binop(Iop_Add64, + unop(Iop_32Uto64, + unop(Iop_64to32, mkexpr(t0))), + unop(Iop_32Uto64, + unop(Iop_64to32, mkexpr(t4))))); + assign(t6, + binop(Iop_Add64, + binop(Iop_Add64, + unop(Iop_32Sto64, + unop(Iop_64HIto32, mkexpr(t0))), + unop(Iop_32Sto64, + unop(Iop_64HIto32, mkexpr(t4)))), + unop(Iop_32Uto64, + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t5)), + mkU32(0x1))))); + assign(t7, binop(Iop_32HLto64, + unop(Iop_64to32, mkexpr(t6)), + unop(Iop_64to32, mkexpr(t5)))); + assign(t8, binop(Iop_CmpEQ32, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64to32, mkexpr(t6)), + mkU32(0x80000000)), + mkU8(31)), + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t6)), + mkU32(0x00000001)))); + assign(t9, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0x00000001)), + mkU32(0x1))); + putDSPControl(IRExpr_ITE(mkexpr(t8), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16))))); + putAcc(ac, + IRExpr_ITE(mkexpr(t8), + mkexpr(t7), + IRExpr_ITE(mkexpr(t9), + mkU64(0x8000000000000000ULL), + mkU64(0x7fffffffffffffffULL))) + ); + break; + } + case 0xD: { /* DPSQ_SA.L.W */ + DIP("dpsq_sa.l.w ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I64); + t8 = newTemp(Ity_I1); + t9 = newTemp(Ity_I1); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Shl64, + binop(Iop_MullS32, + getIReg(rs), getIReg(rt)), + mkU8(0x1))); + + assign(t2, binop(Iop_CmpEQ32, + getIReg(rs), + mkU32(0x80000000))); + assign(t3, binop(Iop_CmpEQ32, + getIReg(rt), + mkU32(0x80000000))); + + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x7fffffffffffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t5, binop(Iop_Sub64, + unop(Iop_32Uto64, + unop(Iop_64to32, mkexpr(t0))), + unop(Iop_32Uto64, + unop(Iop_64to32, mkexpr(t4))))); + assign(t6, binop(Iop_Sub64, + binop(Iop_Add64, + unop(Iop_32Sto64, + unop(Iop_64HIto32, mkexpr(t0)) + ), + unop(Iop_32Sto64, + unop(Iop_1Sto32, + binop(Iop_CmpLT32U, + unop(Iop_64to32, + mkexpr(t0)), + unop(Iop_64to32, + mkexpr(t4)))))), + unop(Iop_32Sto64, + unop(Iop_64HIto32, mkexpr(t4))))); + assign(t7, binop(Iop_32HLto64, + unop(Iop_64to32, mkexpr(t6)), + unop(Iop_64to32, mkexpr(t5)))); + assign(t8, binop(Iop_CmpEQ32, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64to32, mkexpr(t6)), + mkU32(0x80000000)), + mkU8(31)), + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t6)), + mkU32(0x00000001)))); + assign(t9, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t6)), + mkU32(0x00000001)), + mkU32(0x1))); + putDSPControl(IRExpr_ITE(mkexpr(t8), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16))))); + putAcc(ac, + IRExpr_ITE(mkexpr(t8), + mkexpr(t7), + IRExpr_ITE(mkexpr(t9), + mkU64(0x8000000000000000ULL), + mkU64(0x7fffffffffffffffULL))) + ); + break; + } + case 0xF: { /* DPSU.H.QBR */ + DIP("dpsu.h.qbr ac%d r%d, r%d", ac, rs, rt); + vassert(!mode64); + + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + + assign(t0, + binop(Iop_Mul32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))))); + assign(t1, + binop(Iop_Mul32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt)))))); + assign(t2, unop(Iop_32Uto64, + binop(Iop_Add32, mkexpr(t0), mkexpr(t1)))); + assign(t3, binop(Iop_Sub64, getAcc(ac), mkexpr(t2))); + putAcc(ac, mkexpr(t3)); + + break; + } + case 0x10: { /* MAQ_SA.W.PHL */ + DIP("maq_sa.w.phl ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + assign(t1, unop(Iop_32Sto64, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(0x1)))); + + /* If both input arguments are equal 0x8000, saturate + intermediate product and write to DSPControl register. + */ + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + mkU32(0x00008000))); + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU32(0x00008000))); + + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x000000007fffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16) + ) + ), + getDSPControl()), + getDSPControl())); + /* Add intermediate product and value in the + accumulator. */ + assign(t5, binop(Iop_Add64, mkexpr(t0), mkexpr(t4))); + + /* Compare bits 31 and 32 of the value in t5. */ + assign(t6, binop(Iop_CmpEQ32, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64to32, mkexpr(t5)), + mkU32(0x80000000)), + mkU8(31)), + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t5)), + mkU32(1)))); + putDSPControl(IRExpr_ITE(mkexpr(t6), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16))))); + assign(t7, + IRExpr_ITE(mkexpr(t6), + mkexpr(t5), + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t5)), + mkU32(1)), + mkU32(0x0)), + mkU64(0x000000007fffffffULL), + mkU64(0xffffffff80000000ULL))) + ); + putAcc(ac, mkexpr(t7)); + break; + } + case 0x12: { /* MAQ_SA.W.PHR */ + DIP("maq_sa.w.phr ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + assign(t1, unop(Iop_32Sto64, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rt)))), + mkU8(0x1)))); + + /* If both input arguments are equal 0x8000, saturate + intermediate product and write to DSPControl + register. */ + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + mkU32(0x00008000))); + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + mkU32(0x00008000))); + + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x000000007fffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16) + ) + ), + getDSPControl()), + getDSPControl())); + /* Add intermediate product and value in the + accumulator. */ + assign(t5, binop(Iop_Add64, mkexpr(t0), mkexpr(t4))); + + /* Compare bits 31 and 32 of the value in t5. */ + assign(t6, binop(Iop_CmpEQ32, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64to32, mkexpr(t5)), + mkU32(0x80000000)), + mkU8(31)), + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t5)), + mkU32(1)))); + putDSPControl(IRExpr_ITE(mkexpr(t6), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16))))); + assign(t7, + IRExpr_ITE(mkexpr(t6), + mkexpr(t5), + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t5)), + mkU32(1)), + mkU32(0x0)), + mkU64(0x000000007fffffffULL), + mkU64(0xffffffff80000000ULL))) + ); + putAcc(ac, mkexpr(t7)); + break; + } + case 0x14: { /* MAQ_S.W.PHL */ + DIP("maq_s.w.phl ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I64); + + assign(t5, getAcc(ac)); + + assign(t0, unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs)))); + assign(t1, unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt)))); + + assign(t2, binop(Iop_And32, + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0xffff)), + mkU32(0x8000))), + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t1), + mkU32(0xffff)), + mkU32(0x8000))))); + + assign(t3, binop(Iop_CmpEQ32, mkexpr(t2), mkU32(0x0))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16))))); + + assign(t4, unop(Iop_64to32, + binop(Iop_MullS32, + mkexpr(t0), mkexpr(t1)))); + putAcc(ac, IRExpr_ITE(mkexpr(t3), + binop(Iop_Add64, + unop(Iop_32Sto64, + binop(Iop_Shl32, + mkexpr(t4), + mkU8(0x1))), + mkexpr(t5)), + binop(Iop_Add64, + mkexpr(t5), + unop(Iop_32Sto64, + mkU32(0x7fffffff))))); + break; + } + case 0x16: { /* MAQ_S.W.PHR */ + DIP("maq_s.w.phr ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I64); + + assign(t5, getAcc(ac)); + + assign(t0, unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs)))); + assign(t1, unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt)))); + + assign(t2, binop(Iop_And32, + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0xffff)), + mkU32(0x8000))), + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t1), + mkU32(0xffff)), + mkU32(0x8000))))); + + assign(t3, binop(Iop_CmpEQ32, mkexpr(t2), mkU32(0x0))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16))))); + + assign(t4, unop(Iop_64to32, + binop(Iop_MullS32, + mkexpr(t0), mkexpr(t1)))); + putAcc(ac, IRExpr_ITE(mkexpr(t3), + binop(Iop_Add64, + unop(Iop_32Sto64, + binop(Iop_Shl32, + mkexpr(t4), + mkU8(0x1))), + mkexpr(t5)), + binop(Iop_Add64, + mkexpr(t5), + unop(Iop_32Sto64, + mkU32(0x7fffffff))))); + break; + } + case 0x18: { /* DPAQX_S.W.PH */ + DIP("dpaqx_s.w.ph ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Shl64, + binop(Iop_MullS32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rt)))), + mkU8(0x1))); + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + mkU32(0x00008000))); + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + mkU32(0x00008000))); + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x000000007fffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16))), + getDSPControl()), + getDSPControl())); + + assign(t5, binop(Iop_Shl64, + binop(Iop_MullS32, + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(0x1))); + assign(t6, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + mkU32(0x00008000))); + assign(t7, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU32(0x00008000))); + assign(t8, + IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + mkU64(0x000000007fffffffULL), + mkexpr(t5)), + mkexpr(t5))); + + putDSPControl(IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t9, binop(Iop_Add64, + binop(Iop_Add64, mkexpr(t4), mkexpr(t8)), + mkexpr(t0))); + putAcc(ac, mkexpr(t9)); + break; + } + case 0x19: { /* DPSQX_S.W.PH */ + DIP("dpsqx_s.w.ph ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Shl64, + binop(Iop_MullS32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rt)))), + mkU8(0x1))); + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + mkU32(0x00008000))); + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + mkU32(0x00008000))); + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x000000007fffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t5, binop(Iop_Shl64, + binop(Iop_MullS32, + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(0x1))); + assign(t6, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + mkU32(0x00008000))); + assign(t7, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU32(0x00008000))); + assign(t8, + IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + mkU64(0x000000007fffffffULL), + mkexpr(t5)), + mkexpr(t5))); + + putDSPControl(IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t9, binop(Iop_Sub64, + mkexpr(t0), + binop(Iop_Add64, mkexpr(t4), mkexpr(t8)))); + putAcc(ac, mkexpr(t9)); + break; + } + case 0x1A: { /* DPAQX_SA.W.PH */ + DIP("dpaqx_sa.w.ph ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + t10 = newTemp(Ity_I32); + t11 = newTemp(Ity_I32); + + assign(t0, getAcc(ac)); + /* Calculate first cross dot product and saturate if + needed. */ + assign(t1, unop(Iop_32Sto64, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rt)))), + mkU8(0x1)))); + + /* If both input arguments are equal 0x8000, saturate + intermediate product and write to DSPControl + register. */ + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + mkU32(0x00008000))); + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + mkU32(0x00008000))); + + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x000000007fffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16) + ) + ), + getDSPControl()), + getDSPControl())); + /* Calculate second cross dot product and saturate if + needed. */ + assign(t5, unop(Iop_32Sto64, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(0x1)))); + + /* If both input arguments are equal 0x8000, saturate + intermediate product and write to DSPControl + register. */ + assign(t6, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + mkU32(0x00008000))); + assign(t7, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU32(0x00008000))); + + assign(t8, + IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + mkU64(0x000000007fffffffULL), + mkexpr(t5)), + mkexpr(t5))); + + putDSPControl(IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16) + ) + ), + getDSPControl()), + getDSPControl())); + /* Add intermediate products with value in the + accumulator. */ + assign(t9, binop(Iop_Add64, + mkexpr(t0), + binop(Iop_Add64, mkexpr(t8), mkexpr(t4)))); + + putAcc(ac, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0x0)), + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + binop(Iop_Shl64, + mkexpr(t9), + mkU8(1))), + mkU32(0x0)), + mkU64(0x000000007fffffffULL), + mkexpr(t9)), + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + binop(Iop_Shl64, + mkexpr(t9), + mkU8(1))), + mkU32(0xffffffff)), + mkU64(0xffffffff80000000ULL), + mkexpr(t9)))); + assign(t10, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + binop(Iop_Shl64, + mkexpr(t9), + mkU8(1))), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16))), + getDSPControl())); + assign(t11, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + binop(Iop_Shl64, + mkexpr(t9), + mkU8(1))), + mkU32(0xffffffff)), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16))), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0x0)), + mkexpr(t10), + mkexpr(t11))); + break; + } + case 0x1B: { /* DPSQX_SA.W.PH */ + DIP("dpsqx_sa.w.ph ac%d, r%d, r%d", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + t10 = newTemp(Ity_I32); + t11 = newTemp(Ity_I32); + + assign(t0, getAcc(ac)); + /* Calculate first cross dot product and saturate if + needed. */ + assign(t1, unop(Iop_32Sto64, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rt)))), + mkU8(0x1)))); + + /* If both input arguments are equal 0x8000, saturate + intermediate product and write to DSPControl + register. */ + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + mkU32(0x00008000))); + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + mkU32(0x00008000))); + + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x000000007fffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16) + ) + ), + getDSPControl()), + getDSPControl())); + /* Calculate second cross dot product and saturate if + needed. */ + assign(t5, unop(Iop_32Sto64, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(0x1)))); + + /* If both input arguments are equal 0x8000, saturate + intermediate product and write to DSPControl + register. */ + assign(t6, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rs), + mkU32(0x0000ffff)), + mkU32(0x00008000))); + assign(t7, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xffff0000)), + mkU32(0x80000000))); + + assign(t8, + IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + mkU64(0x000000007fffffffULL), + mkexpr(t5)), + mkexpr(t5))); + + putDSPControl(IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16))), + getDSPControl()), + getDSPControl())); + /* Subtract intermediate products from value in the + accumulator. */ + assign(t9, + binop(Iop_Sub64, + mkexpr(t0), + binop(Iop_Add64, mkexpr(t8), mkexpr(t4)))); + + putAcc(ac, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0x0)), + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + binop(Iop_Shl64, + mkexpr(t9), + mkU8(1))), + mkU32(0x0)), + mkU64(0x000000007fffffffULL), + mkexpr(t9)), + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + binop(Iop_Shl64, + mkexpr(t9), + mkU8(1))), + mkU32(0xffffffff)), + mkU64(0xffffffff80000000ULL), + mkexpr(t9)))); + assign(t10, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + binop(Iop_Shl64, + mkexpr(t9), + mkU8(1))), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16))), + getDSPControl())); + assign(t11, IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + binop(Iop_Shl64, + mkexpr(t9), + mkU8(1))), + mkU32(0xffffffff)), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac+16))), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0x0)), + mkexpr(t10), + mkexpr(t11))); + break; + } + default: + return -1; + } + break; /* end of DPAQ.W.PH */ + } + case 0x31: { /* APPEND */ + switch(sa) { + case 0x0: { /* APPEND */ + DIP("append r%d, r%d, %d", rt, rs, rd); + vassert(!mode64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + + assign(t1, binop(Iop_Shl32, getIReg(rt), mkU8(rd))); + + if (31 == rd) { + putIReg(rt, binop(Iop_Or32, + mkexpr(t1), + binop(Iop_And32, + getIReg(rs), + mkU32(0x7fffffff)))); + } else if (1 == rd) { + putIReg(rt, + binop(Iop_Or32, + mkexpr(t1), + binop(Iop_And32, + getIReg(rs), mkU32(0x1)))); + } else { + assign(t2, + unop(Iop_Not32, + binop(Iop_Shl32, + mkU32(0xffffffff), mkU8(rd)))); + + putIReg(rt, binop(Iop_Or32, + mkexpr(t1), + binop(Iop_And32, + getIReg(rs), mkexpr(t2)))); + } + break; + } + case 0x1: { /* PREPEND */ + DIP("prepend r%d, r%d, %d", rt, rs, rd); + vassert(!mode64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + + if (0 != rd) { + assign(t1, binop(Iop_Shr32, getIReg(rt), mkU8(rd))); + + if (31 == rd) { + putIReg(rt, binop(Iop_Or32, + mkexpr(t1), + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rs), + mkU32(0x7fffffff)), + mkU8(1)))); + } else if (1 == rd) { + putIReg(rt, binop(Iop_Or32, + mkexpr(t1), + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rs), + mkU32(0x1)), + mkU8(31)))); + } else { + assign(t2, binop(Iop_Add32, mkU32(rd), mkU32(0x1))); + + assign(t3, unop(Iop_Not32, + binop(Iop_Shl32, + mkU32(0xffffffff), + unop(Iop_32to8, mkexpr(t2))))); + + putIReg(rt, binop(Iop_Or32, + mkexpr(t1), + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rs), + mkexpr(t3)), + mkU8(32-rd)))); + } + } + break; + } + case 0x10: { /* BALIGN */ + DIP("balign r%d, r%d, %d", rt, rs, rd); + vassert(!mode64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + + if ((2 != rd) && (0 != rd)) { + assign(t1, binop(Iop_Shl32, + binop(Iop_And32, + mkU32(rd), mkU32(0x3)), + mkU8(0x3))); + assign(t2, binop(Iop_Shl32, + getIReg(rt), + unop(Iop_32to8, mkexpr(t1)))); + assign(t3, binop(Iop_Shr32, + getIReg(rs), + unop(Iop_32to8, + binop(Iop_Shl32, + binop(Iop_Sub32, + mkU32(0x4), + binop(Iop_And32, + mkU32(rd), + mkU32(0x3))), + mkU8(0x3))))); + putIReg(rt, binop(Iop_Or32, mkexpr(t2), mkexpr(t3))); + } + break; + } + default: + return -1; + } + break; /* end of APPEND */ + } + default: + return -1; } break; - default: - return False; } - *set = IRStmt_Exit(eCond, jmpKind, mkSzConst(ty, addrTgt), OFFB_PC); - return True; + default: + return -1; + } + return 0; } /*------------------------------------------------------------*/ @@ -1933,8 +11137,11 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, Bool sigill_diag ) { IRTemp t0, t1 = 0, t2, t3, t4, t5, t6, t7; + UInt opcode, cins, rs, rt, rd, sa, ft, fs, fd, fmt, tf, nd, function, trap_code, imm, instr_index, p, msb, lsb, size, rot, sel; + /* Additional variables for instruction fields in DSP ASE insructions */ + UInt ac; DisResult dres; @@ -1984,7 +11191,7 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, /* Spot "Special" instructions (see comment at top of file). */ { - /* Spot the 16-byte preamble: + /* Spot the 16-byte preamble: ****mips32**** "srl $0, $0, 13 "srl $0, $0, 29 @@ -2094,6 +11301,8 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, IRType ty = mode64 ? Ity_I64 : Ity_I32; IRType tyF = mode64 ? Ity_F64 : Ity_F32; + ac = get_acNo(cins); + switch (opcode) { case 0x03: /* JAL */ @@ -3444,7 +12653,7 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, } case 0x1: { /* LDXC1 */ - /* Load Doubleword Indexed to Floating Point + /* Load Doubleword Indexed to Floating Point LDXC1 (MIPS32r2 and MIPS64) */ if (mode64) { DIP("ldxc1 f%d, r%d(r%d)", fd, rt, rs); @@ -3520,7 +12729,7 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, } break; } - case 0xD: /* Store Doubleword Indexed Unaligned from Floating Point - + case 0xD: /* Store Doubleword Indexed Unaligned from Floating Point - SUXC1; MIPS64 MIPS32r2 */ DIP("suxc1 f%d, r%d(r%d)", fd, rt, rs); t0 = newTemp(Ity_I64); @@ -3879,7 +13088,7 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, assign(E_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x4)), mkU64(0x4), mkU64(0x0))); - + assign(F_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x3)), mkU64(0x5), mkU64(0x0))); @@ -4309,56 +13518,72 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, break; } - case 0x00: { /* MADD */ - DIP("madd r%d, r%d", rs, rt); - if (mode64) { - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I64); - t4 = newTemp(Ity_I64); - t5 = newTemp(Ity_I64); - t6 = newTemp(Ity_I32); + case 0x00: { /* MADD */ + if (mode64) { + DIP("madd r%d, r%d", rs, rt); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I64); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I32); - assign(t1, mkNarrowTo32(ty, getHI())); - assign(t2, mkNarrowTo32(ty, getLO())); + assign(t1, mkNarrowTo32(ty, getHI())); + assign(t2, mkNarrowTo32(ty, getLO())); - assign(t3, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)), - mkNarrowTo32(ty, getIReg(rt)))); + assign(t3, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)), + mkNarrowTo32(ty, getIReg(rt)))); - assign(t4, binop(Iop_32HLto64, mkexpr(t1), mkexpr(t2))); - assign(t5, binop(Iop_Add64, mkexpr(t3), mkexpr(t4))); + assign(t4, binop(Iop_32HLto64, mkexpr(t1), mkexpr(t2))); + assign(t5, binop(Iop_Add64, mkexpr(t3), mkexpr(t4))); - putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t5)), True)); - putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t5)), True)); - } else { - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I64); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I32); - t6 = newTemp(Ity_I32); + putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t5)), True)); + putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t5)), True)); + } else { + if ( (1 <= ac) && ( 3 >= ac) ) { + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) { + /* If DSP is present -> DSP ASE MADD */ + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + } else { + DIP("madd r%d, r%d", rs, rt); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I64); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); - assign(t1, getHI()); - assign(t2, getLO()); + assign(t1, getHI()); + assign(t2, getLO()); - assign(t3, binop(Iop_MullS32, getIReg(rs), getIReg(rt))); + assign(t3, binop(Iop_MullS32, getIReg(rs), getIReg(rt))); - assign(t4, binop(Iop_Add32, mkexpr(t2), unop(Iop_64to32, - mkexpr(t3)))); + assign(t4, binop(Iop_Add32, mkexpr(t2), unop(Iop_64to32, + mkexpr(t3)))); - assign(t5, unop(Iop_1Uto32, binop(Iop_CmpLT32U, mkexpr(t4), - unop(Iop_64to32, mkexpr(t3))))); - assign(t6, binop(Iop_Add32, mkexpr(t5), mkexpr(t1))); + assign(t5, unop(Iop_1Uto32, binop(Iop_CmpLT32U, mkexpr(t4), + unop(Iop_64to32, mkexpr(t3))))); + assign(t6, binop(Iop_Add32, mkexpr(t5), mkexpr(t1))); - putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32, mkexpr(t3)))); - putLO(mkexpr(t4)); + putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32, + mkexpr(t3)))); + putLO(mkexpr(t4)); + break; + } + } + break; } - break; - } case 0x01: { /* MADDU */ - DIP("maddu r%d, r%d", rs, rt); if (mode64) { + DIP("maddu r%d, r%d", rs, rt); t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32); t3 = newTemp(Ity_I64); @@ -4378,33 +13603,49 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t5)), True)); putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t5)), True)); } else { - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I64); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I32); - t6 = newTemp(Ity_I32); + if ( (1 <= ac) && ( 3 >= ac) ) { + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) { + /* If DSP is present -> DSP ASE MADDU */ + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + } else { + DIP("maddu r%d, r%d", rs, rt); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I64); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); - assign(t1, getHI()); - assign(t2, getLO()); + assign(t1, getHI()); + assign(t2, getLO()); - assign(t3, binop(Iop_MullU32, getIReg(rs), getIReg(rt))); + assign(t3, binop(Iop_MullU32, getIReg(rs), getIReg(rt))); - assign(t4, binop(Iop_Add32, mkexpr(t2), unop(Iop_64to32, - mkexpr(t3)))); - assign(t5, unop(Iop_1Uto32, binop(Iop_CmpLT32U, mkexpr(t4), - unop(Iop_64to32, mkexpr(t3))))); - assign(t6, binop(Iop_Add32, mkexpr(t5), mkexpr(t1))); + assign(t4, binop(Iop_Add32, mkexpr(t2), unop(Iop_64to32, + mkexpr(t3)))); + assign(t5, unop(Iop_1Uto32, binop(Iop_CmpLT32U, mkexpr(t4), + unop(Iop_64to32, mkexpr(t3))))); + assign(t6, binop(Iop_Add32, mkexpr(t5), mkexpr(t1))); - putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32, mkexpr(t3)))); - putLO(mkexpr(t4)); + putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32, + mkexpr(t3)))); + putLO(mkexpr(t4)); + break; + } } break; } case 0x04: { /* MSUB */ - DIP("msub r%d, r%d", rs, rt); if (mode64) { + DIP("msub r%d, r%d", rs, rt); t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32); t3 = newTemp(Ity_I64); @@ -4424,35 +13665,53 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t5)), True)); putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t5)), True)); } else { - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I64); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I32); + if ( (1 <= ac) && ( 3 >= ac) ) { + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) { + /* If DSP is present -> DSP ASE MSUB */ + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + } else { + DIP("msub r%d, r%d", rs, rt); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I64); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); - assign(t1, getHI()); - assign(t2, getLO()); + assign(t1, getHI()); + assign(t2, getLO()); - assign(t3, binop(Iop_MullS32, getIReg(rs), getIReg(rt))); - assign(t4, unop(Iop_64to32, mkexpr(t3))); /* new lo */ + assign(t3, binop(Iop_MullS32, getIReg(rs), getIReg(rt))); + assign(t4, unop(Iop_64to32, mkexpr(t3))); /* new lo */ - /* if lo= ac) ) { + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) { + /* If DSP is present -> DSP ASE MSUBU */ + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + } else { + DIP("msubu r%d, r%d", rs, rt); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I64); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); - assign(t1, getHI()); - assign(t2, getLO()); + assign(t1, getHI()); + assign(t2, getLO()); - assign(t3, binop(Iop_MullU32, getIReg(rs), getIReg(rt))); - assign(t4, unop(Iop_64to32, mkexpr(t3))); /* new lo */ + assign(t3, binop(Iop_MullU32, getIReg(rs), getIReg(rt))); + assign(t4, unop(Iop_64to32, mkexpr(t3))); /* new lo */ - /* if lohwcaps & VEX_MIPS_ASE_DSP)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + break; + } + case 0x10: { /* ADDU.QB */ + switch(sa) { + case 0xC: /* SUBU_S.PH */ + case 0xD: /* ADDU_S.PH */ + case 0x1E: { /* MULQ_S.PH */ + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP2P)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + break; + } + default: { + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + break; + } + } + break; } + case 0x11: { /* CMPU.EQ.QB */ + switch(sa) { + case 0x18: /* CMPGDU.EQ.QB */ + case 0x19: /* CMPGDU.LT.QB */ + case 0x1A: /* CMPGDU.LE.QB */ + case 0x0D: /* PRECR.QB.PH */ + case 0x1E: /* PRECR_SRA.PH.W */ + case 0x1F: { /* PRECR_SRA_R.PH.W */ + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP2P)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + break; + } + default: { + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + break; + } + } + break; + } + case 0x12: { /* ABSQ_S.PH */ + switch(sa){ + case 0x1: { /* ABSQ_S.QB */ + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP2P)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + break; + } + default: { + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + break; + } + } + break; + } + case 0x13: { /* SHLL.QB */ + switch(sa) { + case 0x04: /* SHRA.QB */ + case 0x05: /* SHRA_R.QB */ + case 0x06: /* SHRAV.QB */ + case 0x07: /* SHRAV_R.QB */ + case 0x19: /* SHLR.PH */ + case 0x1B: { /* SHLRV.PH */ + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP2P)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + break; + } + default: { + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + break; + } + } + break; + } + case 0x30: { /* DPAQ.W.PH */ + switch(sa) { + case 0x0: /* DPA.W.PH */ + case 0x18: /* DPAQX_S.W.PH */ + case 0x1A: /* DPAQX_SA.W.PH */ + case 0x8: /* DPAX.W.PH */ + case 0x1: /* DPS.W.PH */ + case 0x19: /* DPSQX_S.W.PH */ + case 0x1B: /* DPSQX_SA.W.PH */ + case 0x9: /* DPSX.W.PH */ + case 0x2: { /* MULSA.W.PH */ + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP2P)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + break; + } + default: { + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + break; + } + } + break; + } + case 0x18: /* ADDUH.QB/MUL.PH */ + case 0x31: { /* APPEND */ + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP2P)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure_dsp; + } + break; + } else { + goto decode_failure_dsp; + } + } + default: + goto decode_failure; + + } break; /* Special3 */ case 0x3B: @@ -5149,28 +14621,54 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, break; } - case 0x18: /* MULT */ - DIP("mult r%d, r%d", 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 0x18: { /* MULT */ + if ( (1 <= ac) && ( 3 >= ac) ) { + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) { + /* 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%d, r%d", rs, rt); + t2 = newTemp(Ity_I64); - case 0x19: /* MULTU */ - DIP("multu r%d, r%d", rs, rt); - t2 = newTemp(Ity_I64); + assign(t2, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)), + mkNarrowTo32(ty, getIReg(rt)))); - 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 0x19: { /* MULTU */ + if ( (1 <= ac) && ( 3 >= ac) ) { + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) { + /* 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%d, r%d", rs, rt); + t2 = newTemp(Ity_I64); - putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True)); - putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True)); - break; + 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 0x20: { /* ADD */ DIP("add r%d, r%d, r%d", rd, rs, rt); IRTemp tmpRs32 = newTemp(Ity_I32); @@ -5185,9 +14683,9 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, t3 = newTemp(Ity_I32); t4 = newTemp(Ity_I32); /* dst = src0 + src1 - if(sign(src0 ) != sign(src1 )) + if (sign(src0 ) != sign(src1 )) goto no overflow; - if(sign(dst) == sign(src0 )) + if (sign(dst) == sign(src0 )) goto no overflow; we have overflow! */ @@ -5300,25 +14798,65 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, putLO(unop(Iop_128to64, mkexpr(t2))); break; - case 0x10: /* MFHI */ - DIP("mfhi r%d", rd); - putIReg(rd, getHI()); - break; + case 0x10: { /* MFHI */ + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) { + /* If DSP is present -> DSP ASE MFHI */ + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure; + } + break; + } else { + DIP("mfhi r%d", rd); + putIReg(rd, getHI()); + break; + } + } - case 0x11: /* MTHI */ - DIP("mthi r%d", rs); - putHI(getIReg(rs)); - break; + case 0x11: { /* MTHI */ + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) { + /* If DSP is present -> DSP ASE MTHI */ + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure; + } + break; + } else { + DIP("mthi r%d", rs); + putHI(getIReg(rs)); + break; + } + } - case 0x12: /* MFLO */ - DIP("mflo r%d", rd); - putIReg(rd, getLO()); - break; + case 0x12: { /* MFLO */ + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) { + /* If DSP is present -> DSP ASE MFLO */ + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure; + } + break; + } else { + DIP("mflo r%d", rd); + putIReg(rd, getLO()); + break; + } + } - case 0x13: /* MTLO */ - DIP("mtlo r%d", rs); - putLO(getIReg(rs)); - break; + case 0x13: { /* MTLO */ + if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) { + /* If DSP is present -> DSP ASE MTLO */ + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + if (0 != retVal ) { + goto decode_failure; + } + break; + } else { + DIP("mtlo r%d", rs); + putLO(getIReg(rs)); + break; + } + } case 0x21: /* ADDU */ DIP("addu r%d, r%d, r%d", rd, rs, rt); @@ -5590,7 +15128,7 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, } break; } - } + } case 0x0D: /* BREAK */ DIP("break 0x%x", trap_code); @@ -6133,7 +15671,7 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, } break; } - case 0x0A: { /* TLTI */ + case 0x0A: { /* TLTI */ DIP("tlti r%d, %d %d", rs, imm, trap_code); if (mode64) { stmt (IRStmt_Exit (binop (Iop_CmpLT64S, getIReg (rs), @@ -6201,6 +15739,15 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, } break; } + case 0x1C: { /* BPOSGE32 */ + DIP("bposge32 %d", imm); + vassert(!mode64); + t0 = newTemp(Ity_I32); + /* Get pos field from DSPControl register. */ + assign(t0, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); + dis_branch(False, unop(Iop_Not1, binop(Iop_CmpLT32U, mkexpr(t0), + mkU32(32))), imm, &bstmt); + } case 0x1F: /* SYNCI */ /* Just ignore it */ @@ -6568,6 +16115,10 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, store(mkexpr(t1), getIReg(rt)); break; + decode_failure_dsp: + vex_printf("Error occured while trying to decode MIPS32 DSP " + "instruction.\nYour platform probably doesn't support " + "MIPS32 DSP ASE.\n"); decode_failure: /* All decode failures end up here. */ if (sigill_diag) @@ -6644,8 +16195,8 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, break; } - /* On MIPS we need to check if the last instruction - in block is branch or jump. */ + /* On MIPS we need to check if the last instruction in block is branch or + jump. */ if (((vex_control.guest_max_insns - 1) == (delta + 4) / 4) && (dres.whatNext != Dis_StopHere)) if (branch_or_jump(guest_code + delta + 4)) { diff --git a/VEX/priv/host_mips_defs.c b/VEX/priv/host_mips_defs.c index cba7f1885a..b6ea1751f2 100644 --- a/VEX/priv/host_mips_defs.c +++ b/VEX/priv/host_mips_defs.c @@ -678,124 +678,121 @@ const HChar *showMIPSFpOp(MIPSFpOp op) const HChar *ret; switch (op) { case Mfp_ADDD: - ret = "ADD.D"; + ret = "add.d"; break; case Mfp_SUBD: - ret = "SUB.D"; + ret = "sub.d"; break; case Mfp_MULD: - ret = "MUL.D"; + ret = "mul.d"; break; case Mfp_DIVD: - ret = "DIV.D"; + ret = "div.d"; break; case Mfp_MADDD: - ret = "MADD.D"; + ret = "madd.d"; break; case Mfp_MSUBD: - ret = "MSUB.D"; + ret = "msub.d"; break; case Mfp_MADDS: - ret = "MADD.S"; + ret = "madd.s"; break; case Mfp_MSUBS: - ret = "MSUB.S"; + ret = "msub.s"; break; case Mfp_ADDS: - ret = "ADD.S"; + ret = "add.s"; break; case Mfp_SUBS: - ret = "SUB.S"; + ret = "sub.s"; break; case Mfp_MULS: - ret = "MUL.S"; + ret = "mul.s"; break; case Mfp_DIVS: - ret = "DIV.S"; + ret = "div.s"; break; case Mfp_SQRTS: - ret = "SQRT.S"; + ret = "sqrt.s"; break; case Mfp_SQRTD: - ret = "SQRT.D"; - break; - case Mfp_RSQRTS: - ret = "RSQRT.S"; - break; - case Mfp_RSQRTD: - ret = "RSQRT.D"; - break; - case Mfp_RECIPS: - ret = "RECIP.S"; - break; - case Mfp_RECIPD: - ret = "RECIP.D"; + ret = "sqrt.d"; break; case Mfp_ABSS: - ret = "ABS.S"; + ret = "abs.s"; break; case Mfp_ABSD: - ret = "ABS.D"; + ret = "abs.d"; break; case Mfp_NEGS: - ret = "NEG.S"; + ret = "neg.s"; break; case Mfp_NEGD: - ret = "NEG.D"; + ret = "neg.d"; break; case Mfp_MOVS: - ret = "MOV.S"; + ret = "mov.s"; break; case Mfp_MOVD: - ret = "MOV.D"; + ret = "mov.d"; break; case Mfp_ROUNDWS: - ret = "ROUND.W.S"; + ret = "round.w.s"; break; case Mfp_ROUNDWD: - ret = "ROUND.W.D"; + ret = "round.w.d"; break; case Mfp_FLOORWS: - ret = "FLOOR.W.S"; + ret = "floor.w.s"; break; case Mfp_FLOORWD: - ret = "FLOOR.W.D"; - break; - case Mfp_RSQRTE: - ret = "frsqrte"; + ret = "floor.w.d"; break; case Mfp_CVTDW: - ret = "CVT.D.W"; + ret = "cvt.d.w"; break; case Mfp_CVTDL: - ret = "CVT.D.L"; + ret = "cvt.d.l"; break; case Mfp_CVTDS: - ret = "CVT.D.S"; + ret = "cvt.d.s"; break; case Mfp_CVTSD: + ret = "cvt.s.d"; + break; case Mfp_CVTSW: - ret = "CVT.S"; + ret = "cvt.s.w"; break; case Mfp_CVTWS: + ret = "cvt.w.s"; + break; case Mfp_CVTWD: - ret = "CVT.W"; + ret = "cvt.w.d"; break; case Mfp_TRUWD: + ret = "trunc.w.d"; + break; case Mfp_TRUWS: - ret = "TRUNC.W"; + ret = "trunc.w.s"; break; case Mfp_TRULD: + ret = "trunc.l.d"; + break; case Mfp_TRULS: - ret = "TRUNC.L"; + ret = "trunc.l.s"; break; case Mfp_CEILWS: + ret = "ceil.w.s"; + break; case Mfp_CEILWD: - ret = "CEIL.W"; + ret = "ceil.w.d"; break; case Mfp_CEILLS: + ret = "ceil.l.s"; + break; case Mfp_CEILLD: - ret = "CEIL.L"; + ret = "ceil.l.d"; break; case Mfp_CMP: ret = "C.cond.d"; @@ -1131,7 +1128,7 @@ const HChar *showMIPSShftOp(MIPSShftOp op, Bool immR, Bool sz32) const HChar *ret; switch (op) { case Mshft_SRA: - ret = immR ? (sz32 ? "sar" : "dsar") : (sz32 ? "sarv" : "dsrav"); + ret = immR ? (sz32 ? "sra" : "dsra") : (sz32 ? "srav" : "dsrav"); break; case Mshft_SLL: ret = immR ? (sz32 ? "sll" : "dsll") : (sz32 ? "sllv" : "dsllv"); @@ -1719,7 +1716,7 @@ void ppMIPSInstr(MIPSInstr * i, Bool mode64) case Min_XIndir: vex_printf("(xIndir) "); vex_printf("if (guest_COND.%s) { sw ", - showMIPSCondCode(i->Min.XIndir.cond)); + showMIPSCondCode(i->Min.XIndir.cond)); ppHRegMIPS(i->Min.XIndir.dstGA, mode64); vex_printf(", "); ppMIPSAMode(i->Min.XIndir.amPC, mode64); @@ -1852,13 +1849,13 @@ void ppMIPSInstr(MIPSInstr * i, Bool mode64) return; } case Min_MtFCSR: { - vex_printf("ctc1 "); + vex_printf("ctc1 "); ppHRegMIPS(i->Min.MtFCSR.src, mode64); vex_printf(", $31"); return; } case Min_MfFCSR: { - vex_printf("ctc1 "); + vex_printf("ctc1 "); ppHRegMIPS(i->Min.MfFCSR.dst, mode64); vex_printf(", $31"); return; @@ -2278,7 +2275,7 @@ void mapRegs_MIPSInstr(HRegRemap * m, MIPSInstr * i, Bool mode64) /* Figure out if i represents a reg-reg move, and if so assign the source and destination to *src and *dst. If in doubt say No. Used - by the register allocator to do move coalescing. + by the register allocator to do move coalescing. */ Bool isMove_MIPSInstr(MIPSInstr * i, HReg * src, HReg * dst) { @@ -2289,7 +2286,7 @@ Bool isMove_MIPSInstr(MIPSInstr * i, HReg * src, HReg * dst) return False; if (i->Min.Alu.srcR->tag != Mrh_Reg) return False; - if (hregNumber(i->Min.Alu.srcR->Mrh.Reg.reg) + if (hregNumber(i->Min.Alu.srcR->Mrh.Reg.reg) != hregNumber(i->Min.Alu.srcL)) return False; *src = i->Min.Alu.srcL; @@ -2432,7 +2429,7 @@ static UInt fetch32 ( UChar* p ) } /* physical structure of mips instructions */ -/* type I : opcode - 6 bits +/* type I : opcode - 6 bits rs - 5 bits rt - 5 bits immediate - 16 bits @@ -2557,9 +2554,9 @@ static UChar *doAMode_RR(UChar * p, UInt opc1, UInt rSD, MIPSAMode * am, if (mode64) { /* addiu sp, sp, -8 sd rA, 0(sp) - daddu rA, rA, rB + daddu rA, rA, rB sd/ld r_dst, 0(rA) - ld rA, 0(sp) + ld rA, 0(sp) daddiu sp, sp, 8 */ p = mkFormI(p, 25, 29, 29, 0xFFF8); p = mkFormI(p, 63, 29, rA, 0); @@ -2570,9 +2567,9 @@ static UChar *doAMode_RR(UChar * p, UInt opc1, UInt rSD, MIPSAMode * am, } else { /* addiu sp, sp, -4 sw rA, 0(sp) - addu rA, rA, rB + addu rA, rA, rB sw/lw r_dst, 0(rA) - lw rA, 0(sp) + lw rA, 0(sp) addiu sp, sp, 4 */ p = mkFormI(p, 9, 29, 29, 0xFFFC); p = mkFormI(p, 43, 29, rA, 0); @@ -2842,7 +2839,7 @@ static UChar *mkMoveReg(UChar * p, UInt r_dst, UInt r_src) instruction was a profiler inc, set *is_profInc to True, else leave it unchanged. */ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, - UChar* buf, Int nbuf, MIPSInstr* i, + UChar* buf, Int nbuf, MIPSInstr* i, Bool mode64, void* disp_cp_chain_me_to_slowEP, void* disp_cp_chain_me_to_fastEP, @@ -3059,7 +3056,7 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, } } break; - + default: goto bad; } @@ -3074,19 +3071,19 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, switch (i->Min.Unary.op) { /* Mun_CLO, Mun_CLZ, Mun_NOP, Mun_DCLO, Mun_DCLZ */ case Mun_CLO: /* clo */ - p = mkFormR(p, 28, r_src, 0 /*whatever */ , r_dst, 0, 33); + p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 33); break; case Mun_CLZ: /* clz */ - p = mkFormR(p, 28, r_src, 0 /*whatever */ , r_dst, 0, 32); + 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, 0 /*whatever */ , r_dst, 0, 37); + p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 37); break; case Mun_DCLZ: /* clz */ - p = mkFormR(p, 28, r_src, 0 /*whatever */ , r_dst, 0, 36); + p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 36); break; } goto done; @@ -3300,7 +3297,7 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, goto bad; } MIPSCondCode cond = i->Min.Call.cond; - UInt r_dst = 25; /* using %r25 as address temporary - + UInt r_dst = 25; /* using %r25 as address temporary - see getRegUsage_MIPSInstr */ /* jump over the following insns if condition does not hold */ @@ -3380,7 +3377,7 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, /* move r9, VG_(disp_cp_chain_me_to_{slowEP,fastEP}) */ /* jr r9 */ void* disp_cp_chain_me - = i->Min.XDirect.toFastEP ? disp_cp_chain_me_to_fastEP + = i->Min.XDirect.toFastEP ? disp_cp_chain_me_to_fastEP : disp_cp_chain_me_to_slowEP; p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9, Ptr_to_ULong(disp_cp_chain_me), mode64); @@ -3496,7 +3493,7 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, case Ijk_Ret: case Ijk_Call: fallthrough */ - default: + default: ppIRJumpKind(i->Min.XAssisted.jk); vpanic("emit_MIPSInstr.Min_XAssisted: unexpected jump kind"); } @@ -3725,25 +3722,25 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x6); break; } - case Mfp_ABSS: { /* ABSS */ + case Mfp_ABSS: { /* ABS.S */ UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64); UInt fr_src = fregNo(i->Min.FpUnary.src, mode64); p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x5); break; } - case Mfp_ABSD: { /* ABSD */ + case Mfp_ABSD: { /* ABS.D */ UInt fr_dst = dregNo(i->Min.FpUnary.dst); UInt fr_src = dregNo(i->Min.FpUnary.src); p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x5); break; } - case Mfp_NEGS: { /* ABSS */ + case Mfp_NEGS: { /* NEG.S */ UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64); UInt fr_src = fregNo(i->Min.FpUnary.src, mode64); p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x7); break; } - case Mfp_NEGD: { /* ABSD */ + case Mfp_NEGD: { /* NEG.D */ UInt fr_dst = dregNo(i->Min.FpUnary.dst); UInt fr_src = dregNo(i->Min.FpUnary.src); p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x7); @@ -3761,30 +3758,6 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x04); break; } - case Mfp_RSQRTS: { /* RSQRT.S */ - UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64); - UInt fr_src = fregNo(i->Min.FpUnary.src, mode64); - p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x16); - break; - } - case Mfp_RSQRTD: { /* RSQRT.D */ - UInt fr_dst = dregNo(i->Min.FpUnary.dst); - UInt fr_src = dregNo(i->Min.FpUnary.src); - p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x16); - break; - } - case Mfp_RECIPS: { /* RECIP.S */ - UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64); - UInt fr_src = fregNo(i->Min.FpUnary.src, mode64); - p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x15); - break; - } - case Mfp_RECIPD: { /* RECIP.D */ - UInt fr_dst = dregNo(i->Min.FpUnary.dst); - UInt fr_src = dregNo(i->Min.FpUnary.src); - p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x15); - break; - } default: goto bad; } diff --git a/VEX/priv/host_mips_defs.h b/VEX/priv/host_mips_defs.h index a7f6d77032..d4c0c8c221 100644 --- a/VEX/priv/host_mips_defs.h +++ b/VEX/priv/host_mips_defs.h @@ -359,9 +359,8 @@ typedef enum { Mfp_ADDS, Mfp_SUBS, Mfp_MULS, Mfp_DIVS, /* Unary */ - Mfp_SQRTS, Mfp_SQRTD, Mfp_RSQRTS, Mfp_RSQRTD, Mfp_RECIPS, Mfp_RECIPD, + Mfp_SQRTS, Mfp_SQRTD, Mfp_ABSS, Mfp_ABSD, Mfp_NEGS, Mfp_NEGD, Mfp_MOVS, Mfp_MOVD, - Mfp_RSQRTE, /* FP convert */ Mfp_CVTSD, Mfp_CVTSW, Mfp_CVTWD, diff --git a/VEX/priv/host_mips_isel.c b/VEX/priv/host_mips_isel.c index 7be6c93f9a..0c573afd07 100644 --- a/VEX/priv/host_mips_isel.c +++ b/VEX/priv/host_mips_isel.c @@ -35,6 +35,7 @@ #include "main_util.h" #include "main_globals.h" #include "host_generic_regs.h" +#include "host_generic_simd64.h" /* for 64-bit SIMD helpers */ #include "host_mips_defs.h" /*---------------------------------------------------------*/ @@ -87,7 +88,7 @@ static Bool mode64 = False; - A counter, for generating new virtual registers. - - The host subarchitecture we are selecting insns for. + - The host subarchitecture we are selecting insns for. This is set at the start and does not change. - A Bool for indicating whether we may generate chain-me @@ -164,7 +165,7 @@ static void addInstr(ISelEnv * env, MIPSInstr * instr) static HReg newVRegI(ISelEnv * env) { - HReg reg = mkHReg(env->vreg_ctr, HRcGPR(env->mode64), + HReg reg = mkHReg(env->vreg_ctr, HRcGPR(env->mode64), True /*virtual reg */ ); env->vreg_ctr++; return reg; @@ -179,7 +180,7 @@ static HReg newVRegD(ISelEnv * env) static HReg newVRegF(ISelEnv * env) { - HReg reg = mkHReg(env->vreg_ctr, HRcFPR(env->mode64), + HReg reg = mkHReg(env->vreg_ctr, HRcFPR(env->mode64), True /*virtual reg */ ); env->vreg_ctr++; return reg; @@ -224,7 +225,7 @@ static void sub_from_sp(ISelEnv * env, UInt n) It's important to specify whether the immediate is to be regarded as signed or not. If yes, this will never return -32768 as an immediate; this guaranteed that all signed immediates that are - return can have their sign inverted if need be. + return can have their sign inverted if need be. */ static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e); static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e); @@ -396,14 +397,14 @@ static void doHelperCall(ISelEnv * env, Bool passBBP, IRExpr * guard, /* MIPS O32 calling convention: up to four registers ($a0 ... $a3) are allowed to be used for passing integer arguments. They correspond - to regs GPR4 ... GPR7. Note that the cee->regparms field is meaningless - on MIPS host (since we only implement one calling convention) and so we + to regs GPR4 ... GPR7. Note that the cee->regparms field is meaningless + on MIPS host (since we only implement one calling convention) and so we always ignore it. */ /* MIPS 64 calling convention: up to four registers ($a0 ... $a7) are allowed to be used for passing integer arguments. They correspond - to regs GPR4 ... GPR11. Note that the cee->regparms field is meaningless - on MIPS host (since we only implement one calling convention) and so we + to regs GPR4 ... GPR11. Note that the cee->regparms field is meaningless + on MIPS host (since we only implement one calling convention) and so we always ignore it. */ n_args = 0; for (i = 0; args[i]; i++) @@ -518,7 +519,7 @@ static void doHelperCall(ISelEnv * env, Bool passBBP, IRExpr * guard, iselInt64Expr(&raHi, &raLo, env, args[i]); tmpregs[argreg] = raLo; argreg++; - tmpregs[argreg] = raHi; + tmpregs[argreg] = raHi; } argreg++; } @@ -698,6 +699,7 @@ static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e) /* DO NOT CALL THIS DIRECTLY ! */ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) { + UInt argiregs = 0; IRType ty = typeOfIRExpr(env->type_env, e); vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1 || ty == Ity_F32 || (ty == Ity_I64 && mode64) @@ -729,39 +731,43 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) /* Is it an addition or logical style op? */ switch (e->Iex.Binop.op) { + case Iop_Add8: + case Iop_Add16: case Iop_Add32: aluOp = Malu_ADD; break; - + case Iop_Sub8: case Iop_Sub16: case Iop_Sub32: aluOp = Malu_SUB; break; - + case Iop_Sub64: aluOp = Malu_DSUB; break; - + case Iop_And32: case Iop_And64: aluOp = Malu_AND; break; - + + case Iop_Or8: + case Iop_Or16: case Iop_Or32: case Iop_Or64: aluOp = Malu_OR; break; - + case Iop_Xor32: case Iop_Xor64: aluOp = Malu_XOR; break; - + case Iop_Add64: aluOp = Malu_DADD; break; - + default: aluOp = Malu_INVALID; break; @@ -818,27 +824,39 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) if (shftOp != Mshft_INVALID) { HReg r_dst = newVRegI(env); HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); - MIPSRH *ri_srcR = NULL; - /* get right arg into an RH, in the appropriate way */ - switch (shftOp) { - case Mshft_SLL: - case Mshft_SRL: - case Mshft_SRA: - if (mode64) - ri_srcR = iselWordExpr_RH6u(env, e->Iex.Binop.arg2); - else - ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop.arg2); - break; - default: - vpanic("iselIntExpr_R_wrk-shftOp-arg2"); - } - if (ty == Ity_I64) { + MIPSRH *ri_srcR; + if (mode64) + ri_srcR = iselWordExpr_RH6u(env, e->Iex.Binop.arg2); + else + ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop.arg2); + + if (ty == Ity_I8) { + vassert(0); + } else if (ty == Ity_I32) { + if (mode64 && (shftOp == Mshft_SRA || shftOp == Mshft_SRL)) { + HReg tmp = newVRegI(env); + HReg r_srcL_se = newVRegI(env); + /* SRA, SRAV, SRL, SRLV: On 64-bit processors, if GPR rt does + not contain a sign-extended 32-bit value (bits 63..31 + equal), then the result of the operation is UNPREDICTABLE. + So we need to sign-extend r_srcL: + DSLLV tmp, r_srcL, 32 + DSRAV r_srcL_se, tmp, 32 + */ + addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tmp, + r_srcL, MIPSRH_Imm(False, 32))); + addInstr(env, MIPSInstr_Shft(Mshft_SRA, False, r_srcL_se, + tmp, MIPSRH_Imm(False, 32))); + /* And finally do the shift. */ + addInstr(env, MIPSInstr_Shft(shftOp, True /*32bit shift */, + r_dst, r_srcL_se, ri_srcR)); + } else + addInstr(env, MIPSInstr_Shft(shftOp, True /*32bit shift */, + r_dst, r_srcL, ri_srcR)); + } else if (ty == Ity_I64) { vassert(mode64); addInstr(env, MIPSInstr_Shft(shftOp, False/*64bit shift */, r_dst, r_srcL, ri_srcR)); - } else if (ty == Ity_I32) { - addInstr(env, MIPSInstr_Shft(shftOp, True /*32bit shift */, - r_dst, r_srcL, ri_srcR)); } else goto irreducible; return r_dst; @@ -846,11 +864,13 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) /* Cmp*32*(x,y) ? */ if (e->Iex.Binop.op == Iop_CmpEQ32 + || e->Iex.Binop.op == Iop_CmpEQ16 || e->Iex.Binop.op == Iop_CmpNE32 || e->Iex.Binop.op == Iop_CmpNE64 || e->Iex.Binop.op == Iop_CmpLT32S || e->Iex.Binop.op == Iop_CmpLT32U || e->Iex.Binop.op == Iop_CmpLT64U + || e->Iex.Binop.op == Iop_CmpLE32U || e->Iex.Binop.op == Iop_CmpLE32S || e->Iex.Binop.op == Iop_CmpLE64S || e->Iex.Binop.op == Iop_CmpLT64S @@ -872,6 +892,10 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) cc = MIPScc_EQ; size32 = True; break; + case Iop_CmpEQ16: + cc = MIPScc_EQ; + size32 = True; + break; case Iop_CmpNE32: cc = MIPScc_NE; size32 = True; @@ -892,6 +916,10 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) cc = MIPScc_LO; size32 = False; break; + case Iop_CmpLE32U: + cc = MIPScc_LE; + size32 = True; + break; case Iop_CmpLE32S: cc = MIPScc_LE; size32 = True; @@ -1099,6 +1127,46 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) return r_dst; } + if (e->Iex.Binop.op == Iop_8HLto16) { + HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1); + HReg tLo = iselWordExpr_R(env, e->Iex.Binop.arg2); + HReg tLo_1 = newVRegI(env); + HReg tHi_1 = newVRegI(env); + HReg r_dst = newVRegI(env); + HReg mask = newVRegI(env); + + addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tHi_1, tHi, + MIPSRH_Imm(False, 8))); + + addInstr(env, MIPSInstr_LI(mask, 0xff)); + addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo, + MIPSRH_Reg(mask))); + addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1, + MIPSRH_Reg(tLo_1))); + + return r_dst; + } + + if (e->Iex.Binop.op == Iop_16HLto32) { + HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1); + HReg tLo = iselWordExpr_R(env, e->Iex.Binop.arg2); + HReg tLo_1 = newVRegI(env); + HReg tHi_1 = newVRegI(env); + HReg r_dst = newVRegI(env); + HReg mask = newVRegI(env); + + addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tHi_1, tHi, + MIPSRH_Imm(False, 16))); + + addInstr(env, MIPSInstr_LI(mask, 0xffff)); + addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo, + MIPSRH_Reg(mask))); + addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1, + MIPSRH_Reg(tLo_1))); + + return r_dst; + } + if (e->Iex.Binop.op == Iop_32HLto64) { vassert(mode64); HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1); @@ -1159,6 +1227,48 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) return r_dst; } + /* -------- DSP ASE -------- */ + /* All used cases involving host-side helper calls. */ + void* fn = NULL; + switch (e->Iex.Binop.op) { + case Iop_HAdd8Ux4: + fn = &h_generic_calc_HAdd8Ux4; break; + case Iop_HSub8Ux4: + fn = &h_generic_calc_HSub8Ux4; break; + case Iop_HSub16Sx2: + fn = &h_generic_calc_HSub16Sx2; break; + case Iop_QSub8Ux4: + fn = &h_generic_calc_QSub8Ux4; break; + default: + break; + } + + /* What's the retloc? */ + RetLoc rloc = RetLocINVALID; + if (ty == Ity_I32) { + rloc = RetLocInt; + } + else if (ty == Ity_I64) { + rloc = mode64 ? RetLocInt : RetLoc2Int; + } + else { + goto irreducible; + } + + if (fn) { + HReg regL = iselWordExpr_R(env, e->Iex.Binop.arg1); + HReg regR = iselWordExpr_R(env, e->Iex.Binop.arg2); + HReg res = newVRegI(env); + addInstr(env, mk_iMOVds_RR(hregMIPS_GPR4(env->mode64), regL)); + addInstr(env, mk_iMOVds_RR(hregMIPS_GPR5(env->mode64), regR)); + argiregs |= (1 << 4); + argiregs |= (1 << 5); + addInstr(env, MIPSInstr_CallAlways( MIPScc_AL, + (HWord)Ptr_to_ULong(fn), + argiregs, rloc)); + addInstr(env, mk_iMOVds_RR(res, hregMIPS_GPR2(env->mode64))); + return res; + } break; } @@ -1167,6 +1277,8 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) IROp op_unop = e->Iex.Unop.op; switch (op_unop) { + case Iop_1Sto8: + case Iop_1Sto16: case Iop_1Sto32: case Iop_8Sto32: case Iop_16Sto32: @@ -1178,6 +1290,14 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) Bool sz32; UShort amt; switch (op_unop) { + case Iop_1Sto8: + amt = 31; + sz32 = True; + break; + case Iop_1Sto16: + amt = 31; + sz32 = True; + break; case Iop_1Sto32: amt = 31; sz32 = True; @@ -1224,6 +1344,8 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) return r_dst; } + case Iop_Not8: + case Iop_Not16: case Iop_Not32: case Iop_Not64: { HReg r_dst = newVRegI(env); @@ -1277,9 +1399,20 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) return r_dst; } + case Iop_16to8: case Iop_32to8: case Iop_32to16: return iselWordExpr_R(env, e->Iex.Unop.arg); + case Iop_32to1: + return iselWordExpr_R(env, e->Iex.Unop.arg); + + case Iop_32HIto16: { + HReg r_dst = newVRegI(env); + HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); + addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, + r_dst, r_src, MIPSRH_Imm(False, 16))); + return r_dst; + } case Iop_64to8: { vassert(mode64); @@ -1291,6 +1424,14 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) return r_dst; } + case Iop_16HIto8: { + HReg r_dst = newVRegI(env); + HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); + addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, + r_dst, r_src, MIPSRH_Imm(False, 8))); + return r_dst; + } + case Iop_1Uto32: case Iop_8Uto32: case Iop_16Uto32: { @@ -1403,6 +1544,21 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) return r_dst; } + case Iop_CmpNEZ16: { + HReg r_dst = newVRegI(env); + HReg tmp = newVRegI(env); + HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); + + MIPSCondCode cc; + + cc = MIPScc_NE; + addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, r_src, + MIPSRH_Imm(False, 0xFFFF))); + addInstr(env, MIPSInstr_Cmp(False, True, r_dst, tmp, + hregMIPS_GPR0(mode64), cc)); + return r_dst; + } + case Iop_CmpNEZ32: { HReg r_dst = newVRegI(env); HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); @@ -1431,6 +1587,7 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) } case Iop_Left8: + case Iop_Left16: case Iop_Left32: case Iop_Left64: { if (op_unop == Iop_Left64 && !mode64) @@ -1511,6 +1668,42 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) default: break; } + + /* -------- DSP ASE -------- */ + /* All Unop cases involving host-side helper calls. */ + void* fn = NULL; + switch (e->Iex.Unop.op) { + case Iop_CmpNEZ16x2: + fn = &h_generic_calc_CmpNEZ16x2; break; + case Iop_CmpNEZ8x4: + fn = &h_generic_calc_CmpNEZ8x4; break; + default: + break; + } + + RetLoc rloc = RetLocINVALID; + if (ty == Ity_I32) { + rloc = RetLocInt; + } + else if (ty == Ity_I64) { + rloc = mode64 ? RetLocInt : RetLoc2Int; + } + else { + goto irreducible; + } + + if (fn) { + HReg regL = iselWordExpr_R(env, e->Iex.Unop.arg); + HReg res = newVRegI(env); + addInstr(env, mk_iMOVds_RR(hregMIPS_GPR4(env->mode64), regL)); + argiregs |= (1 << 4); + addInstr(env, MIPSInstr_CallAlways( MIPScc_AL, + (HWord)Ptr_to_ULong(fn), + argiregs, rloc)); + addInstr(env, mk_iMOVds_RR(res, hregMIPS_GPR2(env->mode64))); + return res; + } + break; } @@ -1610,7 +1803,7 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) RetLoc rloc = RetLocINVALID; if (ty == Ity_I32) { rloc = RetLocInt; - } + } else if (ty == Ity_I64) { rloc = mode64 ? RetLocInt : RetLoc2Int; } @@ -1984,13 +2177,13 @@ static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, *rLo = tLo; return; } - + /* 64HLto128(e1,e2) */ case Iop_64HLto128: *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1); *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2); return; - + case Iop_DivModS64to64: { HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); @@ -2005,7 +2198,7 @@ static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, *rLo = tLo; return; } - + case Iop_DivModU128to64: { vassert(mode64); HReg rHi1, rLo1; @@ -2023,7 +2216,7 @@ static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, *rLo = tLo; return; } - + default: break; } @@ -2037,7 +2230,7 @@ static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, /*--- ISEL: Integer expressions (64 bit) ---*/ /*---------------------------------------------------------*/ -/* 32-bit mode ONLY. Compute a 64-bit value into the register +/* 32-bit mode ONLY. Compute a 64-bit value into the register * pair HI, LO. HI and LO must not be changed by subsequent * code emitted by the caller. */ @@ -2115,9 +2308,9 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) /* 64-bit ITE */ if (e->tag == Iex_ITE) { vassert(typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1); - vassert(!mode64); HReg expr0Lo, expr0Hi; HReg expr1Lo, expr1Hi; + HReg carryBit; HReg tmpHi = newVRegI(env); HReg tmpLo = newVRegI(env); HReg tmp1Hi = newVRegI(env); @@ -2128,6 +2321,8 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) HReg mask = newVRegI(env); HReg desLo = newVRegI(env); HReg desHi = newVRegI(env); + carryBit = newVRegI(env); + /* r_cond = 0 - r_cond_1 */ addInstr(env, MIPSInstr_LI(mask, 0x0)); addInstr(env, MIPSInstr_Alu(Malu_SUB, r_cond, @@ -2145,11 +2340,16 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) addInstr(env, MIPSInstr_Alu(Malu_NOR, r_cond_neg, r_cond, MIPSRH_Reg(r_cond))); addInstr(env, MIPSInstr_Alu(Malu_AND, tmp1Lo, r_cond_neg, - MIPSRH_Reg(expr1Lo))); + MIPSRH_Reg(expr0Lo))); addInstr(env, MIPSInstr_Alu(Malu_AND, tmp1Hi, r_cond_neg, - MIPSRH_Reg(expr1Hi))); + MIPSRH_Reg(expr0Hi))); + addInstr(env, MIPSInstr_Alu(Malu_ADD, desLo, tmpLo, MIPSRH_Reg(tmp1Lo))); + addInstr(env, MIPSInstr_Cmp(False, True, carryBit, desLo, + tmpLo, MIPScc_LO)); + addInstr(env, MIPSInstr_Alu(Malu_ADD, tmpHi, tmpHi, + MIPSRH_Reg(carryBit))); addInstr(env, MIPSInstr_Alu(Malu_ADD, desHi, tmpHi, MIPSRH_Reg(tmp1Hi))); *rHi = desHi; @@ -2164,13 +2364,53 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) /* 32 x 32 -> 64 multiply */ /* Add64 */ case Iop_Add64: { - HReg xLo, xHi, yLo, yHi; + HReg xLo, xHi, yLo, yHi, carryBit; + HReg tHi = newVRegI(env); + HReg tHi1 = newVRegI(env); HReg tLo = newVRegI(env); + + carryBit = newVRegI(env); + + Bool size32 = True; + MIPSCondCode cc = MIPScc_LO; + iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2); - addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, xHi, MIPSRH_Reg(yHi))); addInstr(env, MIPSInstr_Alu(Malu_ADD, tLo, xLo, MIPSRH_Reg(yLo))); + + /* Check carry. */ + addInstr(env, MIPSInstr_Cmp(False, size32, carryBit, tLo, xLo, cc)); + + addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi1, xHi, MIPSRH_Reg(yHi))); + addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, tHi1, + MIPSRH_Reg(carryBit))); + + *rHi = tHi; + *rLo = tLo; + return; + } + case Iop_Sub64: { + HReg xLo, xHi, yLo, yHi, borrow; + Bool size32 = True; + MIPSCondCode cc = MIPScc_LO; + + HReg tHi = newVRegI(env); + HReg tLo = newVRegI(env); + + borrow = newVRegI(env); + + iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); + iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2); + + addInstr(env, MIPSInstr_Alu(Malu_SUB, tLo, xLo, MIPSRH_Reg(yLo))); + + /* Check if borrow is nedded. */ + addInstr(env, MIPSInstr_Cmp(False, size32, borrow, xLo, yLo, cc)); + + addInstr(env, MIPSInstr_Alu(Malu_ADD, yHi, yHi, MIPSRH_Reg(borrow))); + addInstr(env, MIPSInstr_Alu(Malu_SUB, tHi, xHi, MIPSRH_Reg(yHi))); + *rHi = tHi; *rLo = tLo; return; @@ -2236,6 +2476,181 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) return; } + case Iop_Shr64: { + HReg xLo, xHi; + HReg tLo = newVRegI(env); + HReg tLo1 = newVRegI(env); + HReg tHi = newVRegI(env); + HReg tmp = newVRegI(env); + HReg tmp2 = newVRegI(env); + HReg tmp3 = newVRegI(env); + HReg mask = newVRegI(env); + HReg tMask = newVRegI(env); + HReg discard = newVRegI(env); + HReg discard1 = newVRegI(env); + + /* We assume any literal values are on the second operand. */ + iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); + MIPSRH *ri_srcR = NULL; + MIPSRH *ri_srcR_sub = NULL; + + ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop.arg2); + ri_srcR_sub = iselWordExpr_RH(env, True /*signed */ , + e->Iex.Binop.arg2); + + /* Steps: + 1. Take shift-amount (arg2) least significant bits from upper + half of 64bit input value (arg1) + 2. Shift upper half + 3. Shift lower half + 4. Put discarded bits (those from step 1) to most significant + bit positions of lower half */ + + /* Mask for extraction of bits that will be discarded. */ + addInstr(env, MIPSInstr_LI(tmp, 0xffffffff)); + addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /*32bit shift */, + tMask, tmp, ri_srcR)); + addInstr(env, MIPSInstr_Alu(Malu_NOR, mask, + tMask, MIPSRH_Reg(tMask))); + + /* Extraction of bits that will be discarded. */ + addInstr(env, MIPSInstr_Alu(Malu_AND, discard, xHi, + MIPSRH_Reg(mask))); + /* Position discarded bits to most significant bit positions. */ + addInstr(env, MIPSInstr_LI(tmp3, 32)); + addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, + tmp3, ri_srcR_sub)); + addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /*32bit shift */, + discard1, discard, MIPSRH_Reg(tmp2))); + + addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /*32bit shift */, + tHi, xHi, ri_srcR)); + addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /*32bit shift */, + tLo1, xLo, ri_srcR)); + + addInstr(env, MIPSInstr_Alu(Malu_OR, tLo, + tLo1, MIPSRH_Reg(discard1))); + *rHi = tHi; + *rLo = tLo; + return; + } + case Iop_Shl64: { + HReg xLo, xHi; + HReg tLo = newVRegI(env); + HReg tHi1 = newVRegI(env); + HReg tHi = newVRegI(env); + HReg tmp = newVRegI(env); + HReg tmp2 = newVRegI(env); + HReg tmp3 = newVRegI(env); + HReg mask = newVRegI(env); + HReg tMask = newVRegI(env); + HReg discard = newVRegI(env); + HReg discard1 = newVRegI(env); + + /* We assume any literal values are on the second operand. */ + iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); + MIPSRH *ri_srcR = NULL; + MIPSRH *ri_srcR_sub = NULL; + + ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop.arg2); + ri_srcR_sub = iselWordExpr_RH(env, True /*signed */ , + e->Iex.Binop.arg2); + + /* Steps: + 1. Take shift-amount (arg2) most significant bits from lower + half of 64bit input value (arg1) + 2. Shift lower half + 3. Shift upper half + 4. Put discarded bits (those from step 1) to least significant + bit positions of upper half */ + + /* Mask for extraction of bits that will be discarded. */ + addInstr(env, MIPSInstr_LI(tmp, 0xffffffff)); + addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /*32bit shift */, + tMask, tmp, ri_srcR)); + addInstr(env, MIPSInstr_Alu(Malu_NOR, mask, + tMask, MIPSRH_Reg(tMask))); + + /* Extraction of bits that will be discarded. */ + addInstr(env, MIPSInstr_Alu(Malu_AND, discard, xLo, + MIPSRH_Reg(mask))); + /* Position discarded bits to least significant bit positions. */ + addInstr(env, MIPSInstr_LI(tmp3, 32)); + addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, + tmp3, ri_srcR_sub)); + addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /*32bit shift */, + discard1, discard, MIPSRH_Reg(tmp2))); + + addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /*32bit shift */, + tHi1, xHi, ri_srcR)); + addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /*32bit shift */, + tLo, xLo, ri_srcR)); + + addInstr(env, MIPSInstr_Alu(Malu_OR, tHi, + tHi1, MIPSRH_Reg(discard1))); + *rHi = tHi; + *rLo = tLo; + return; + } + case Iop_Sar64: { + HReg xLo, xHi; + HReg tLo = newVRegI(env); + HReg tLo1 = newVRegI(env); + HReg tHi = newVRegI(env); + HReg tmp = newVRegI(env); + HReg tmp2 = newVRegI(env); + HReg tmp3 = newVRegI(env); + HReg mask = newVRegI(env); + HReg tMask = newVRegI(env); + HReg discard = newVRegI(env); + HReg discard1 = newVRegI(env); + + /* We assume any literal values are on the second operand. */ + iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); + MIPSRH *ri_srcR = NULL; + MIPSRH *ri_srcR_sub = NULL; + + ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop.arg2); + ri_srcR_sub = iselWordExpr_RH(env, True /*signed */ , + e->Iex.Binop.arg2); + + /* Steps: + 1. Take shift-amount (arg2) least significant bits from upper + half of 64bit input value (arg1) + 2. Shift upper half + 3. Shift lower half + 4. Put discarded bits (those from step 1) to most significant + bit positions of lower half */ + + /* Mask for extraction of bits that will be discarded. */ + addInstr(env, MIPSInstr_LI(tmp, 0xffffffff)); + addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /*32bit shift */, + tMask, tmp, ri_srcR)); + addInstr(env, MIPSInstr_Alu(Malu_NOR, mask, + tMask, MIPSRH_Reg(tMask))); + + /* Extraction of bits that will be discarded. */ + addInstr(env, MIPSInstr_Alu(Malu_AND, discard, xHi, + MIPSRH_Reg(mask))); + /* Position discarded bits to most significant bit positions. */ + addInstr(env, MIPSInstr_LI(tmp3, 32)); + addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, + tmp3, ri_srcR_sub)); + addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /*32bit shift */, + discard1, discard, MIPSRH_Reg(tmp2))); + + addInstr(env, MIPSInstr_Shft(Mshft_SRA, True /*32bit shift */, + tHi, xHi, ri_srcR)); + addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /*32bit shift */, + tLo1, xLo, ri_srcR)); + + addInstr(env, MIPSInstr_Alu(Malu_OR, tLo, + tLo1, MIPSRH_Reg(discard1))); + *rHi = tHi; + *rLo = tLo; + return; + } + default: break; } @@ -2304,7 +2719,42 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) *rLo = tLo; return; } - + + case Iop_Left64: { + HReg yLo, yHi, borrow; + HReg tHi = newVRegI(env); + HReg tLo = newVRegI(env); + HReg zero = newVRegI(env); + Bool size32 = True; + MIPSCondCode cc = MIPScc_LO; + + borrow = newVRegI(env); + + /* yHi:yLo = arg */ + iselInt64Expr(&yHi, &yLo, env, e->Iex.Unop.arg); + /* zero = 0 */ + addInstr(env, MIPSInstr_LI(zero, 0x00000000)); + + /* tLo = 0 - yLo */ + addInstr(env, MIPSInstr_Alu(Malu_SUB, tLo, zero, MIPSRH_Reg(yLo))); + + /* Check if borrow is needed. */ + addInstr(env, MIPSInstr_Cmp(False, size32, borrow, zero, yLo, cc)); + + /* tHi = 0 - (yHi + borrow) */ + addInstr(env, MIPSInstr_Alu(Malu_ADD, + yHi, yHi, MIPSRH_Reg(borrow))); + addInstr(env, MIPSInstr_Alu(Malu_SUB, tHi, zero, MIPSRH_Reg(yHi))); + /* So now we have tHi:tLo = -arg. To finish off, or 'arg' + back in, so as to give the final result + tHi:tLo = arg | -arg. */ + addInstr(env, MIPSInstr_Alu(Malu_OR, tHi, tHi, MIPSRH_Reg(yHi))); + addInstr(env, MIPSInstr_Alu(Malu_OR, tLo, tLo, MIPSRH_Reg(yLo))); + *rHi = tHi; + *rLo = tLo; + return; + } + case Iop_CmpwNEZ64: { HReg srcLo, srcHi; HReg tmp1 = newVRegI(env); @@ -2441,21 +2891,21 @@ static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e) MIPSAMode *am_addr; HReg src = iselFltExpr(env, e->Iex.Unop.arg); HReg dst = newVRegF(env); - + sub_from_sp(env, 16); /* Move SP down 16 bytes */ am_addr = MIPSAMode_IR(0, StackPointer(mode64)); - + addInstr(env, MIPSInstr_Store(4, MIPSAMode_IR(am_addr->Mam.IR.index +4, am_addr->Mam.IR.base), hregMIPS_GPR0(mode64), mode64)); addInstr(env, MIPSInstr_FpLdSt(False /* store */, 4, src, am_addr)); - + /* load as Ity_F64 */ addInstr(env, MIPSInstr_FpLdSt(True /* load */, 8, dst, am_addr)); /* Reset SP */ add_to_sp(env, 16); - + return dst; } } @@ -3140,7 +3590,7 @@ static void iselStmt(ISelEnv * env, IRStmt * stmt) /* --------- PUT --------- */ case Ist_Put: { IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data); - + if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || (ty == Ity_I64 && mode64)) { HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data); @@ -3150,7 +3600,7 @@ static void iselStmt(ISelEnv * env, IRStmt * stmt) am_addr, r_src, mode64)); return; } - + if (ty == Ity_I64 && !mode64) { HReg vHi, vLo; MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset, @@ -3163,9 +3613,9 @@ static void iselStmt(ISelEnv * env, IRStmt * stmt) addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)), am_addr4, vHi, mode64)); return; - + } - + if (ty == Ity_F32) { HReg fr_src = iselFltExpr(env, stmt->Ist.Put.data); MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset, @@ -3174,7 +3624,7 @@ static void iselStmt(ISelEnv * env, IRStmt * stmt) am_addr)); return; } - + if (ty == Ity_F64) { HReg fr_src; if (mode64) { @@ -3350,7 +3800,7 @@ static void iselStmt(ISelEnv * env, IRStmt * stmt) r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr); HReg r_src = iselWordExpr_R(env, stmt->Ist.LLSC.storedata); HReg r_dst = lookupIRTemp(env, res); - IRType tyData = typeOfIRExpr(env->type_env, + IRType tyData = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.storedata); if (tyData == Ity_I32) { diff --git a/VEX/priv/main_main.c b/VEX/priv/main_main.c index a2920fefe1..05ca8fa706 100644 --- a/VEX/priv/main_main.c +++ b/VEX/priv/main_main.c @@ -1418,8 +1418,45 @@ static const HChar* show_hwcaps_s390x ( UInt hwcaps ) static const HChar* show_hwcaps_mips32 ( UInt hwcaps ) { - if (hwcaps == 0x00010000) return "MIPS-baseline"; - if (hwcaps == 0x00020000) return "Broadcom-baseline"; + /* MIPS baseline. */ + if (hwcaps && VEX_PRID_COMP_MIPS == VEX_PRID_COMP_MIPS) { + /* MIPS baseline with dspr2. */ + if (hwcaps && VEX_MIPS_ASE_DSP2P == VEX_MIPS_ASE_DSP2P) { + return "MIPS-baseline-dspr2"; + } + /* MIPS baseline with dsp. */ + if (hwcaps && VEX_MIPS_ASE_DSP == VEX_MIPS_ASE_DSP) { + return "MIPS-baseline-dsp"; + } + return "MIPS-baseline"; + } + + /* Broadcom baseline. */ + if (hwcaps && VEX_PRID_COMP_BROADCOM == VEX_PRID_COMP_BROADCOM) { + /* Broadcom baseline with dspr2. */ + if (hwcaps && VEX_MIPS_ASE_DSP2P == VEX_MIPS_ASE_DSP2P) { + return "Broadcom-baseline-dspr2"; + } + /* Broadcom baseline with dsp. */ + if (hwcaps && VEX_MIPS_ASE_DSP == VEX_MIPS_ASE_DSP) { + return "Broadcom-baseline-dsp"; + } + return "Broadcom-baseline"; + } + + /* Netlogic baseline. */ + if (hwcaps && VEX_PRID_COMP_NETLOGIC == VEX_PRID_COMP_NETLOGIC) { + /* Netlogic baseline with dspr2. */ + if (hwcaps && VEX_MIPS_ASE_DSP2P == VEX_MIPS_ASE_DSP2P) { + return "Netlogic-baseline-dspr2"; + } + /* Netlogic baseline with dsp. */ + if (hwcaps && VEX_MIPS_ASE_DSP == VEX_MIPS_ASE_DSP) { + return "Netlogic-baseline-dsp"; + } + return "Netlogic-baseline"; + } + return NULL; } diff --git a/VEX/pub/libvex.h b/VEX/pub/libvex.h index fafb8144e7..8b26c3e882 100644 --- a/VEX/pub/libvex.h +++ b/VEX/pub/libvex.h @@ -185,6 +185,10 @@ typedef #define VEX_PRID_COMP_BROADCOM 0x00020000 #define VEX_PRID_COMP_NETLOGIC 0x000c0000 +/* MIPS additional capabilities */ +#define VEX_MIPS_ASE_DSP 0x00000010 /* Signal Processing ASE */ +#define VEX_MIPS_ASE_DSP2P 0x00000040 /* Signal Processing ASE Rev 2 */ + /* These return statically allocated strings. */ extern const HChar* LibVEX_ppVexArch ( VexArch ); diff --git a/VEX/pub/libvex_guest_mips32.h b/VEX/pub/libvex_guest_mips32.h index cdcadfc8e0..a49c646d52 100644 --- a/VEX/pub/libvex_guest_mips32.h +++ b/VEX/pub/libvex_guest_mips32.h @@ -139,6 +139,16 @@ typedef UInt host_EvC_FAILADDR; /* 308 */ UInt host_EvC_COUNTER; /* 312 */ UInt guest_COND; /* 316 */ + + UInt padding1; + /* MIPS32 DSP ASE(r2) specific registers. */ + UInt guest_DSPControl; /* 324 */ + ULong guest_ac0; /* 328 */ + ULong guest_ac1; /* 336 */ + ULong guest_ac2; /* 344 */ + ULong guest_ac3; /* 352 */ + + UInt padding[6]; } VexGuestMIPS32State; /*---------------------------------------------------------------*/ /*--- Utility functions for MIPS32 guest stuff. ---*/