/* CPU has FPU and 32 dbl. prec. FP registers. */
static Bool fp_mode64 = False;
+/* CPU has MSA unit */
+static Bool has_msa = False;
+
/* Define 1.0 in single and double precision. */
#define ONE_SINGLE 0x3F800000
#define ONE_DOUBLE 0x3FF0000000000000ULL
return ret;
}
+/* ---------------- MIPS32 MSA registers ---------------- */
+
+static UInt msaGuestRegOffset(UInt msaRegNo) {
+ vassert(msaRegNo <= 31);
+ UInt ret;
+
+ if (mode64) {
+ switch (msaRegNo) {
+ case 0:
+ ret = offsetof(VexGuestMIPS64State, guest_w0);
+ break;
+
+ case 1:
+ ret = offsetof(VexGuestMIPS64State, guest_w1);
+ break;
+
+ case 2:
+ ret = offsetof(VexGuestMIPS64State, guest_w2);
+ break;
+
+ case 3:
+ ret = offsetof(VexGuestMIPS64State, guest_w3);
+ break;
+
+ case 4:
+ ret = offsetof(VexGuestMIPS64State, guest_w4);
+ break;
+
+ case 5:
+ ret = offsetof(VexGuestMIPS64State, guest_w5);
+ break;
+
+ case 6:
+ ret = offsetof(VexGuestMIPS64State, guest_w6);
+ break;
+
+ case 7:
+ ret = offsetof(VexGuestMIPS64State, guest_w7);
+ break;
+
+ case 8:
+ ret = offsetof(VexGuestMIPS64State, guest_w8);
+ break;
+
+ case 9:
+ ret = offsetof(VexGuestMIPS64State, guest_w9);
+ break;
+
+ case 10:
+ ret = offsetof(VexGuestMIPS64State, guest_w10);
+ break;
+
+ case 11:
+ ret = offsetof(VexGuestMIPS64State, guest_w11);
+ break;
+
+ case 12:
+ ret = offsetof(VexGuestMIPS64State, guest_w12);
+ break;
+
+ case 13:
+ ret = offsetof(VexGuestMIPS64State, guest_w13);
+ break;
+
+ case 14:
+ ret = offsetof(VexGuestMIPS64State, guest_w14);
+ break;
+
+ case 15:
+ ret = offsetof(VexGuestMIPS64State, guest_w15);
+ break;
+
+ case 16:
+ ret = offsetof(VexGuestMIPS64State, guest_w16);
+ break;
+
+ case 17:
+ ret = offsetof(VexGuestMIPS64State, guest_w17);
+ break;
+
+ case 18:
+ ret = offsetof(VexGuestMIPS64State, guest_w18);
+ break;
+
+ case 19:
+ ret = offsetof(VexGuestMIPS64State, guest_w19);
+ break;
+
+ case 20:
+ ret = offsetof(VexGuestMIPS64State, guest_w20);
+ break;
+
+ case 21:
+ ret = offsetof(VexGuestMIPS64State, guest_w21);
+ break;
+
+ case 22:
+ ret = offsetof(VexGuestMIPS64State, guest_w22);
+ break;
+
+ case 23:
+ ret = offsetof(VexGuestMIPS64State, guest_w23);
+ break;
+
+ case 24:
+ ret = offsetof(VexGuestMIPS64State, guest_w24);
+ break;
+
+ case 25:
+ ret = offsetof(VexGuestMIPS64State, guest_w25);
+ break;
+
+ case 26:
+ ret = offsetof(VexGuestMIPS64State, guest_w26);
+ break;
+
+ case 27:
+ ret = offsetof(VexGuestMIPS64State, guest_w27);
+ break;
+
+ case 28:
+ ret = offsetof(VexGuestMIPS64State, guest_w28);
+ break;
+
+ case 29:
+ ret = offsetof(VexGuestMIPS64State, guest_w29);
+ break;
+
+ case 30:
+ ret = offsetof(VexGuestMIPS64State, guest_w30);
+ break;
+
+ case 31:
+ ret = offsetof(VexGuestMIPS64State, guest_w31);
+ break;
+
+ default:
+ vassert(0);
+ break;
+ }
+ } else {
+ switch (msaRegNo) {
+ case 0:
+ ret = offsetof(VexGuestMIPS32State, guest_w0);
+ break;
+
+ case 1:
+ ret = offsetof(VexGuestMIPS32State, guest_w1);
+ break;
+
+ case 2:
+ ret = offsetof(VexGuestMIPS32State, guest_w2);
+ break;
+
+ case 3:
+ ret = offsetof(VexGuestMIPS32State, guest_w3);
+ break;
+
+ case 4:
+ ret = offsetof(VexGuestMIPS32State, guest_w4);
+ break;
+
+ case 5:
+ ret = offsetof(VexGuestMIPS32State, guest_w5);
+ break;
+
+ case 6:
+ ret = offsetof(VexGuestMIPS32State, guest_w6);
+ break;
+
+ case 7:
+ ret = offsetof(VexGuestMIPS32State, guest_w7);
+ break;
+
+ case 8:
+ ret = offsetof(VexGuestMIPS32State, guest_w8);
+ break;
+
+ case 9:
+ ret = offsetof(VexGuestMIPS32State, guest_w9);
+ break;
+
+ case 10:
+ ret = offsetof(VexGuestMIPS32State, guest_w10);
+ break;
+
+ case 11:
+ ret = offsetof(VexGuestMIPS32State, guest_w11);
+ break;
+
+ case 12:
+ ret = offsetof(VexGuestMIPS32State, guest_w12);
+ break;
+
+ case 13:
+ ret = offsetof(VexGuestMIPS32State, guest_w13);
+ break;
+
+ case 14:
+ ret = offsetof(VexGuestMIPS32State, guest_w14);
+ break;
+
+ case 15:
+ ret = offsetof(VexGuestMIPS32State, guest_w15);
+ break;
+
+ case 16:
+ ret = offsetof(VexGuestMIPS32State, guest_w16);
+ break;
+
+ case 17:
+ ret = offsetof(VexGuestMIPS32State, guest_w17);
+ break;
+
+ case 18:
+ ret = offsetof(VexGuestMIPS32State, guest_w18);
+ break;
+
+ case 19:
+ ret = offsetof(VexGuestMIPS32State, guest_w19);
+ break;
+
+ case 20:
+ ret = offsetof(VexGuestMIPS32State, guest_w20);
+ break;
+
+ case 21:
+ ret = offsetof(VexGuestMIPS32State, guest_w21);
+ break;
+
+ case 22:
+ ret = offsetof(VexGuestMIPS32State, guest_w22);
+ break;
+
+ case 23:
+ ret = offsetof(VexGuestMIPS32State, guest_w23);
+ break;
+
+ case 24:
+ ret = offsetof(VexGuestMIPS32State, guest_w24);
+ break;
+
+ case 25:
+ ret = offsetof(VexGuestMIPS32State, guest_w25);
+ break;
+
+ case 26:
+ ret = offsetof(VexGuestMIPS32State, guest_w26);
+ break;
+
+ case 27:
+ ret = offsetof(VexGuestMIPS32State, guest_w27);
+ break;
+
+ case 28:
+ ret = offsetof(VexGuestMIPS32State, guest_w28);
+ break;
+
+ case 29:
+ ret = offsetof(VexGuestMIPS32State, guest_w29);
+ break;
+
+ case 30:
+ ret = offsetof(VexGuestMIPS32State, guest_w30);
+ break;
+
+ case 31:
+ ret = offsetof(VexGuestMIPS32State, guest_w31);
+ 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(const UChar * p)
assign(t1, binop(Iop_Add64, getIReg(rs), \
mkU64(extend_s_16to64(imm)))); \
+#define LOAD_STORE_PATTERN_MSA(imm) \
+ t1 = newTemp(mode64 ? Ity_I64 : Ity_I32); \
+ if (!mode64) \
+ assign(t1, binop(Iop_Add32, getIReg(ws), \
+ mkU32(extend_s_10to32(imm)))); \
+ else \
+ assign(t1, binop(Iop_Add64, getIReg(ws), \
+ mkU64(extend_s_10to64(imm)))); \
+
#define LOADX_STORE_PATTERN \
t1 = newTemp(mode64 ? Ity_I64 : Ity_I32); \
if(!mode64) \
}
if (opcode == 0x11) {
- /*bc1f & bc1t */
+ /* bc1f & bc1t */
fmt = get_fmt(cins);
if (fmt == 0x08) {
return True;
}
+
+ /* MSA branches */
+ /* bnz.df, bz.df */
+ if (fmt >= 0x18) {
+ return True;
+ }
+ /* bnz.v */
+ if (fmt == 0x0f) {
+ return True;
+ }
+ /* bz.v */
+ if (fmt == 0x0b) {
+ return True;
+ }
}
/* bposge32 */
return (UShort) ((((Int) x) << 22) >> 22);
}
-static ULong extend_s_10to32(UInt x)
+static UInt extend_s_10to32(UInt x)
{
- return (ULong)((((Long) x) << 22) >> 22);
+ return (UInt)((((Int) x) << 22) >> 22);
}
static ULong extend_s_10to64(UInt x)
}
}
+
+static IRExpr *getWReg(UInt wregNo) {
+ vassert(wregNo <= 31);
+ return IRExpr_Get(msaGuestRegOffset(wregNo), Ity_V128);
+}
+
static IRExpr *getHI(void)
{
if (mode64)
return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_LLdata), Ity_I32);
}
+static IRExpr *getMSACSR(void) {
+ if (mode64)
+ return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_MSACSR), Ity_I32);
+ else
+ return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_MSACSR), Ity_I32);
+}
+
/* Get byte from register reg, byte pos from 0 to 3 (or 7 for MIPS64) . */
static IRExpr *getByteFromReg(UInt reg, UInt byte_pos)
{
stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_LLdata), e));
}
+static void putMSACSR(IRExpr * e) {
+ if (mode64)
+ stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_MSACSR), e));
+ else
+ stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_MSACSR), e));
+}
+
/* fs - fpu source register number.
inst - fpu instruction that needs to be executed.
sz32 - size of source register.
putFCSR(mkexpr(fcsr));
}
-static IRExpr *getULR(void)
-{
- if (mode64)
- return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_ULR), Ity_I64);
- else
- return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_ULR), Ity_I32);
-}
+/* ws, wt - source MSA register numbers.
+ inst - MSA fp instruction that needs to be executed.
+ opN - number of operads:
+ 1 - unary operation.
+ 2 - binary operation. */
+static void calculateMSACSR(UInt ws, UInt wt, UInt inst, UInt opN) {
+ IRDirty *d;
+ IRTemp msacsr = newTemp(Ity_I32);
+ /* IRExpr_BBPTR() => Need to pass pointer to guest state to helper. */
+ d = unsafeIRDirty_1_N(msacsr, 0,
+ "mips_dirtyhelper_calculate_MSACSR",
+ &mips_dirtyhelper_calculate_MSACSR,
+ mkIRExprVec_4(IRExpr_GSPTR(),
+ mkU32(ws),
+ mkU32(wt),
+ mkU32(inst)));
-static void putIReg(UInt archreg, IRExpr * e)
-{
- IRType ty = mode64 ? Ity_I64 : Ity_I32;
- vassert(archreg < 32);
- vassert(typeOfIRExpr(irsb->tyenv, e) == ty);
- if (archreg != 0)
- stmt(IRStmt_Put(integerGuestRegOffset(archreg), e));
-}
+ if (opN == 1) { /* Unary operation. */
+ /* Declare we're reading guest state. */
+ d->nFxState = 2;
+ vex_bzero(&d->fxState, sizeof(d->fxState));
+ d->fxState[0].fx = Ifx_Read; /* read */
-static IRExpr *mkNarrowTo32(IRType ty, IRExpr * src)
-{
- vassert(ty == Ity_I32 || ty == Ity_I64);
+ if (mode64)
+ d->fxState[0].offset = offsetof(VexGuestMIPS64State, guest_MSACSR);
+ else
+ d->fxState[0].offset = offsetof(VexGuestMIPS32State, guest_MSACSR);
+
+ d->fxState[0].size = sizeof(UInt);
+ d->fxState[1].fx = Ifx_Read; /* read */
+ d->fxState[1].offset = msaGuestRegOffset(ws);
+ d->fxState[1].size = sizeof(ULong);
+ } else if (opN == 2) { /* Binary operation. */
+ /* Declare we're reading guest state. */
+ d->nFxState = 3;
+ vex_bzero(&d->fxState, sizeof(d->fxState));
+ d->fxState[0].fx = Ifx_Read; /* read */
+
+ if (mode64)
+ d->fxState[0].offset = offsetof(VexGuestMIPS64State, guest_MSACSR);
+ else
+ d->fxState[0].offset = offsetof(VexGuestMIPS32State, guest_MSACSR);
+
+ d->fxState[0].size = sizeof(UInt);
+ d->fxState[1].fx = Ifx_Read; /* read */
+ d->fxState[1].offset = msaGuestRegOffset(ws);
+ d->fxState[1].size = sizeof(ULong);
+ d->fxState[2].fx = Ifx_Read; /* read */
+ d->fxState[2].offset = msaGuestRegOffset(wt);
+ d->fxState[2].size = sizeof(ULong);
+ }
+
+ stmt(IRStmt_Dirty(d));
+ putMSACSR(mkexpr(msacsr));
+}
+
+static IRExpr *getULR(void)
+{
+ if (mode64)
+ return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_ULR), Ity_I64);
+ else
+ return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_ULR), Ity_I32);
+}
+
+static void putIReg(UInt archreg, IRExpr * e)
+{
+ IRType ty = mode64 ? Ity_I64 : Ity_I32;
+ vassert(archreg < 32);
+ vassert(typeOfIRExpr(irsb->tyenv, e) == ty);
+ if (archreg != 0)
+ stmt(IRStmt_Put(integerGuestRegOffset(archreg), e));
+}
+
+static void putWReg(UInt wregNo, IRExpr * e) {
+ vassert(wregNo <= 31);
+ vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_V128);
+ stmt(IRStmt_Put(msaGuestRegOffset(wregNo), e));
+ stmt(IRStmt_Put(floatGuestRegOffset(wregNo),
+ unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, e))));
+}
+
+static IRExpr *mkNarrowTo32(IRType ty, IRExpr * src)
+{
+ vassert(ty == Ity_I32 || ty == Ity_I64);
return ty == Ity_I64 ? unop(Iop_64to32, src) : src;
}
return ty == Ity_I64 ? unop(Iop_64to8, src) : unop(Iop_32to8, src);
}
+static IRExpr *mkNarrowTo16 ( IRType ty, IRExpr * src )
+{
+ vassert(ty == Ity_I32 || ty == Ity_I64);
+ return ty == Ity_I64 ? unop(Iop_64to16, src) : unop(Iop_32to16, src);
+}
+
static void putPC(IRExpr * e)
{
stmt(IRStmt_Put(OFFB_PC, e));
IRType ty = fp_mode64 ? Ity_F64 : Ity_F32;
vassert(typeOfIRExpr(irsb->tyenv, e) == ty);
stmt(IRStmt_Put(floatGuestRegOffset(dregNo), e));
+ if (has_msa && fp_mode64) {
+ stmt(IRStmt_Put(msaGuestRegOffset(dregNo),
+ binop(Iop_64HLtoV128,
+ mkU64(0), unop(Iop_ReinterpF64asI64, e))));
+ }
}
static void putDReg(UInt dregNo, IRExpr * e)
IRType ty = Ity_F64;
vassert(typeOfIRExpr(irsb->tyenv, e) == ty);
stmt(IRStmt_Put(floatGuestRegOffset(dregNo), e));
+ if (has_msa)
+ stmt(IRStmt_Put(msaGuestRegOffset(dregNo),
+ binop(Iop_64HLtoV128,
+ mkU64(0), unop(Iop_ReinterpF64asI64, e))));
} else {
vassert(dregNo < 32);
vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F64);
binop(Iop_Shl32, mkexpr(rm_MIPS), mkU8(1)), mkU32(2)));
}
+static IRExpr* get_IR_roundingmode_MSA ( void ) {
+ /*
+ rounding mode | MIPS | IR
+ ------------------------
+ to nearest | 00 | 00
+ to zero | 01 | 11
+ to +infinity | 10 | 10
+ to -infinity | 11 | 01
+ */
+ IRTemp rm_MIPS = newTemp(Ity_I32);
+ /* Last two bits in MSACSR are rounding mode. */
+
+ if (mode64)
+ assign(rm_MIPS, binop(Iop_And32, IRExpr_Get(offsetof(VexGuestMIPS64State,
+ guest_MSACSR), Ity_I32), mkU32(3)));
+ else
+ assign(rm_MIPS, binop(Iop_And32, IRExpr_Get(offsetof(VexGuestMIPS32State,
+ guest_MSACSR), Ity_I32), mkU32(3)));
+
+ /* rm_IR = XOR( rm_MIPS32, (rm_MIPS32 << 1) & 2) */
+ return binop(Iop_Xor32, mkexpr(rm_MIPS), binop(Iop_And32,
+ binop(Iop_Shl32, mkexpr(rm_MIPS), mkU8(1)), mkU32(2)));
+}
+
/* sz, ULong -> IRExpr */
static IRExpr *mkSzImm ( IRType ty, ULong imm64 )
{
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))));
+ 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%u, r%u, %u", 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%u, r%u, %u", 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 -1;
+ }
+ return 0;
+}
+
+static Int msa_I8_logical(UInt cins, UChar wd, UChar ws) {
+ IRTemp t1, t2;
+ UShort operation;
+ UChar i8;
+
+ operation = (cins >> 24) & 3;
+ i8 = (cins & 0x00FF0000) >> 16;
+ switch (operation) {
+ case 0x00: { /* ANDI.B */
+ DIP("ANDI.B w%d, w%d, %d", wd, ws, i8);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ ULong tmp = i8;
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ putWReg(wd, binop(Iop_AndV128, mkexpr(t1), mkexpr(t2)));
+ break;
+ }
+
+ case 0x01: { /* ORI.B */
+ DIP("ORI.B w%d, w%d, %d", wd, ws, i8);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ ULong tmp = i8;
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ putWReg(wd, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
+ break;
+ }
+
+ case 0x02: { /* NORI.B */
+ DIP("NORI.B w%d, w%d, %d", wd, ws, i8);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ ULong tmp = i8;
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ putWReg(wd, unop(Iop_NotV128, binop(Iop_OrV128,
+ mkexpr(t1), mkexpr(t2))));
+ break;
+ }
+
+ case 0x03: { /* XORI.B */
+ DIP("XORI.B w%d, w%d, %d", wd, ws, i8);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ ULong tmp = i8;
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ putWReg(wd, binop(Iop_XorV128, mkexpr(t1), mkexpr(t2)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_I8_branch(UInt cins, UChar wd, UChar ws) {
+ IRTemp t1, t2, t3, t4;
+ UShort operation;
+ UChar i8;
+
+ operation = (cins >> 24) & 3;
+ i8 = (cins & 0x00FF0000) >> 16;
+ switch (operation) {
+ case 0x00: { /* BMNZI.B */
+ DIP("BMNZI.B w%d, w%d, %d", wd, ws, i8);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ ULong tmp = i8;
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t4, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t1, binop(Iop_AndV128, getWReg(ws), mkexpr(t4)));
+ assign(t2, binop(Iop_AndV128, getWReg(wd),
+ unop(Iop_NotV128, mkexpr(t4))));
+ assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* BMZI.B */
+ DIP("BMZI.B w%d, w%d, %d", wd, ws, i8);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ ULong tmp = i8;
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t4, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t1, binop(Iop_AndV128, getWReg(wd), mkexpr(t4)));
+ assign(t2, binop(Iop_AndV128, getWReg(ws),
+ unop(Iop_NotV128, mkexpr(t4))));
+ assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* BSELI.B */
+ DIP("BSELI.B w%d, w%d, %d", wd, ws, i8);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ ULong tmp = i8;
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t4, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t1, binop(Iop_AndV128, getWReg(wd), mkexpr(t4)));
+ assign(t2, binop(Iop_AndV128, getWReg(ws),
+ unop(Iop_NotV128, getWReg(wd))));
+ assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_I8_shift(UInt cins, UChar wd, UChar ws) {
+ IRTemp t1, t2;
+ UShort operation;
+ UChar i8;
+
+ operation = (cins >> 24) & 3;
+ i8 = (cins & 0x00FF0000) >> 16;
+ switch (operation) {
+ case 0x00: { /* SHF.B */
+ DIP("SHF.B w%d, w%d, %d", wd, ws, i8);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(wd));
+ assign(t2, getWReg(ws));
+ Int i;
+ IRTemp tmp[16];
+
+ for (i = 0; i < 16; i++) {
+ tmp[i] = newTemp(Ity_I8);
+ assign(tmp[i],
+ binop(Iop_GetElem8x16, mkexpr(t2),
+ mkU8(i - (i % 4) +
+ ((i8 >> (i % 4) * 2) & 0x03))));
+ }
+
+ putWReg(wd, binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(tmp[15]),
+ mkexpr(tmp[14])),
+ binop(Iop_8HLto16,
+ mkexpr(tmp[13]),
+ mkexpr(tmp[12]))),
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(tmp[11]),
+ mkexpr(tmp[10])),
+ binop(Iop_8HLto16,
+ mkexpr(tmp[9]),
+ mkexpr(tmp[8])))),
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_8HLto16,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_8HLto16,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))))));
+ break;
+ }
+
+ case 0x01: { /* SHF.H */
+ DIP("SHF.H w%d, w%d, %d", wd, ws, i8);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(wd));
+ assign(t2, getWReg(ws));
+ Int i;
+ IRTemp tmp[8];
+
+ for (i = 0; i < 8; i++) {
+ tmp[i] = newTemp(Ity_I16);
+ assign(tmp[i],
+ binop(Iop_GetElem16x8, mkexpr(t2),
+ mkU8(i - (i % 4) +
+ ((i8 >> (i % 4) * 2) & 0x03))));
+ }
+
+ putWReg(wd, binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[7]), mkexpr(tmp[6])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[5]), mkexpr(tmp[4]))),
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[3]), mkexpr(tmp[2])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[1]), mkexpr(tmp[0])))));
+ break;
+ }
+
+ case 0x02: { /* SHF.W */
+ DIP("SHF.W w%d, w%d, %d", wd, ws, i8);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(wd));
+ assign(t2, getWReg(ws));
+ Int i;
+ IRTemp tmp[4];
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_GetElem32x4, mkexpr(t2),
+ mkU8(i - (i % 4) +
+ ((i8 >> (i % 4) * 2) & 0x03))));
+ }
+
+ putWReg(wd, binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ mkexpr(tmp[3]), mkexpr(tmp[2])),
+ binop(Iop_32HLto64,
+ mkexpr(tmp[1]), mkexpr(tmp[0]))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_I5_06(UInt cins, UChar wd, UChar ws) { /* I5 (0x06) */
+ IRTemp t1, t2, t3;
+ UShort operation;
+ UChar df, wt;
+
+ operation = (cins & 0x03800000) >> 23;
+ df = (cins & 0x00600000) >> 21;
+ wt = (cins & 0x001F0000) >> 16;
+
+ switch (operation) {
+ case 0x00: { /* ADDVI */
+ ULong tmp = wt;
+
+ switch (df) {
+ case 0x00: { /* ADDVI.B */
+ DIP("ADDVI.B w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Add8x16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* ADDVI.H */
+ DIP("ADDVI.H w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Add16x8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* ADDVI.W */
+ DIP("ADDVI.W w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 32);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Add32x4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* ADDVI.D */
+ DIP("ADDVI.D w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Add64x2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x01: { /* SUBVI */
+ ULong tmp = wt;
+
+ switch (df) {
+ case 0x00: { /* SUBVI.B */
+ DIP("SUBVI.B w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Sub8x16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* SUBVI.H */
+ DIP("SUBVI.H w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Sub16x8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* SUBVI.W */
+ DIP("SUBVI.W w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 32);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Sub32x4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* SUBVI.D */
+ DIP("SUBVI.D w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Sub64x2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x02: { /* MAXI_S */
+ ULong tmp = wt;
+
+ switch (df) {
+ case 0x00: { /* MAXI_S.B */
+ DIP("MAXI_S.B w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ char stemp = ((int)tmp << 27) >> 27;
+ tmp = (UChar)stemp;
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t1, getWReg(ws));
+ assign(t2,binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Max8Sx16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* MAXI_S.H */
+ DIP("MAXI_S.H w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ short stemp = ((int)tmp << 27) >> 27;
+ tmp = (UShort)stemp;
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Max16Sx8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* MAXI_S.W */
+ DIP("MAXI_S.W w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ int stemp = ((int)tmp << 27) >> 27;
+ tmp = (UInt)stemp;
+ tmp |= (tmp << 32);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Max32Sx4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* MAXI_S.D */
+ DIP("MAXI_S.D w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ Long stemp = ((Long)tmp << 59) >> 59;
+ tmp = stemp;
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Max64Sx2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x03: { /* MAXI_U */
+ ULong tmp = wt;
+
+ switch (df) {
+ case 0x00: { /* MAXI_U.B */
+ DIP("MAXI_U.B w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Max8Ux16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* MAXI_U.H */
+ DIP("MAXI_U.H w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Max16Ux8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* MAXI_U.W */
+ DIP("MAXI_U.W w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 32);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Max32Ux4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* MAXI_U.D */
+ DIP("MAXI_U.D w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Max64Ux2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x04: { /* MINI_S */
+ ULong tmp = wt;
+
+ switch (df) {
+ case 0x00: { /* MINI_S.B */
+ DIP("MINI_S.B w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ char stemp = ((int)tmp << 27) >> 27;
+ tmp = (UChar)stemp;
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Min8Sx16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* MINI_S.H */
+ DIP("MINI_S.H w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ short stemp = ((int)tmp << 27) >> 27;
+ tmp = (UShort)stemp;
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Min16Sx8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* MINI_S.W */
+ DIP("MINI_S.W w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ int stemp = ((int)tmp << 27) >> 27;
+ tmp = (UInt)stemp;
+ tmp |= (tmp << 32);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Min32Sx4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* MINI_S.D */
+ DIP("MINI_S.D w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ Long stemp = ((Long)tmp << 59) >> 59;
+ tmp = stemp;
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Min64Sx2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x05: { /* MINI_U */
+ ULong tmp = wt;
+
+ switch (df) {
+ case 0x00: { /* MINI_U.B */
+ DIP("MINI_U.B w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Min8Ux16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* MINI_U.H */
+ DIP("MINI_U.H w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Min16Ux8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* MINI_U.W */
+ DIP("MINI_U.W w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 32);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Min32Ux4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* MINI_U.D */
+ DIP("MINI_U.D w%d, w%d, %d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_Min64Ux2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+ }
+
+ break;
+ }
+
+ default: {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static Int msa_I5_07(UInt cins, UChar wd, UChar ws) { /* I5 (0x07) / I10 */
+ IRTemp t1, t2, t3;
+ UShort operation;
+ UChar df, i5;
+
+ operation = (cins & 0x03800000) >> 23;
+ df = (cins & 0x00600000) >> 21;
+ i5 = (cins & 0x001F0000) >> 16;
+
+ switch (operation) {
+ case 0x00: {
+ ULong tmp = i5;
+
+ switch (df) {
+ case 0x00: { /* CEQI.B */
+ DIP("CEQI.B w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ char stemp = ((int)tmp << 27) >> 27;
+ tmp = (UChar)stemp;
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_CmpEQ8x16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* CEQI.H */
+ DIP("CEQI.H w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ short stemp = ((int)tmp << 27) >> 27;
+ tmp = (UShort)stemp;
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_CmpEQ16x8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* CEQI.W */
+ DIP("CEQI.W w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ int stemp = ((int)tmp << 27) >> 27;
+ tmp = (UInt)stemp;
+ tmp |= (tmp << 32);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_CmpEQ32x4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* CEQI.D */
+ DIP("CEQI.D w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ Long stemp = ((Long)tmp << 59) >> 59;
+ tmp = stemp;
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_CmpEQ64x2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x02: { /* CLTI_S.df */
+ ULong tmp = i5;
+
+ switch (df) {
+ case 0x00: { /* CLTI_S.B */
+ DIP("CLTI_S.B w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ char stemp = ((int)tmp << 27) >> 27;
+ tmp = (UChar)stemp;
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_CmpGT8Sx16, mkexpr(t2), mkexpr(t1)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* CLTI_S.H */
+ DIP("CLTI_S.H w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ short stemp = ((int)tmp << 27) >> 27;
+ tmp = (UShort)stemp;
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_CmpGT16Sx8, mkexpr(t2), mkexpr(t1)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* CLTI_S.W */
+ DIP("CLTI_S.W w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ int stemp = ((int)tmp << 27) >> 27;
+ tmp = (UInt)stemp;
+ tmp |= (tmp << 32);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_CmpGT32Sx4, mkexpr(t2), mkexpr(t1)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* CLTI_S.D */
+ DIP("CLTI_S.D w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ Long stemp = ((Long)tmp << 59) >> 59;
+ tmp = stemp;
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_CmpGT64Sx2, mkexpr(t2), mkexpr(t1)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x03: { /* CLTI_U.df */
+ ULong tmp = i5;
+
+ switch (df) {
+ case 0x00: { /* CLTI_U.B */
+ DIP("CLTI_U.B w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_CmpGT8Ux16, mkexpr(t2), mkexpr(t1)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* CLTI_U.H */
+ DIP("CLTI_U.H w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_CmpGT16Ux8, mkexpr(t2), mkexpr(t1)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* CLTI_U.W */
+ DIP("CLTI_U.W w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 32);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_CmpGT32Ux4, mkexpr(t2), mkexpr(t1)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* CLTI_U.D */
+ DIP("CLTI_U.D w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_CmpGT64Ux2, mkexpr(t2), mkexpr(t1)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x04: { /* CLEI_S.df */
+ ULong tmp = i5;
+
+ switch (df) {
+ case 0x00: { /* CLEI_S.B */
+ DIP("CLEI_S.B w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ char stemp = ((int)tmp << 27) >> 27;
+ tmp = (UChar)stemp;
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_OrV128, binop(Iop_CmpGT8Sx16,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_CmpEQ8x16,
+ mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* CLEI_S.H */
+ DIP("CLEI_S.H w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ short stemp = ((int)tmp << 27) >> 27;
+ tmp = (UShort)stemp;
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_OrV128, binop(Iop_CmpGT16Sx8,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_CmpEQ16x8,
+ mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* CLEI_S.W */
+ DIP("CLEI_S.W w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ int stemp = ((int)tmp << 27) >> 27;
+ tmp = (UInt)stemp;
+ tmp |= (tmp << 32);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_CmpGT32Sx4,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_CmpEQ32x4,
+ mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* CLEI_S.D */
+ DIP("CLEI_S.D w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ Long stemp = ((Long)tmp << 59) >> 59;
+ tmp = stemp;
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_CmpGT64Sx2,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_CmpEQ64x2,
+ mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x05: { /* CLEI_U.df */
+ ULong tmp = i5;
+
+ switch (df) {
+ case 0x00: { /* CLEI_U.B */
+ DIP("CLEI_U.B w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_CmpGT8Ux16,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_CmpEQ8x16,
+ mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* CLEI_U.H */
+ DIP("CLEI_U.H w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_CmpGT16Ux8,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_CmpEQ16x8,
+ mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* CLEI_U.W */
+ DIP("CLEI_U.W w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ tmp |= (tmp << 32);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_CmpGT32Ux4,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_CmpEQ32x4,
+ mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* CLEI_U.D */
+ DIP("CLEI_U.D w%d, w%d, %d", wd, ws, i5);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_CmpGT64Ux2,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_CmpEQ64x2,
+ mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x06: { /* LDI.df */
+ ULong tmp;
+ UShort s10;
+ s10 = (cins & 0x001FF800) >> 11;
+ switch (df) {
+ case 0x00: /* LDI.B */
+ DIP("LDI.B w%d, %d", wd, s10);
+ tmp = s10 & 0xFFl;
+ tmp = tmp | (tmp << 8) | (tmp << 16) | (tmp << 24)
+ | (tmp << 32) | (tmp << 40) | (tmp << 48) |
+ (tmp << 56);
+ break;
+
+ case 0x01: /* LDI.H */
+ DIP("LDI.H w%d, %d", wd, s10);
+ tmp = extend_s_10to16(s10);
+ tmp = tmp | (tmp << 16) | (tmp << 32) | (tmp << 48);
+ break;
+
+ case 0x02: /* LDI.W */
+ DIP("LDI.W w%d, %d", wd, s10);
+ tmp = extend_s_10to32(s10);
+ tmp = tmp | (tmp << 32);
+ break;
+
+ case 0x03: /* LDI.D */
+ DIP("LDI.D w%d, %d", wd, s10);
+ tmp = extend_s_10to64(s10);
+ break;
+
+ default:
+ return -1;
+ }
+
+ putWReg(wd, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_BIT_09(UInt cins, UChar wd, UChar ws) { /* BIT (0x09) */
+ IRTemp t1, t2, t3;
+ UShort operation;
+ UChar df, m;
+
+ operation = (cins & 0x03800000) >> 23;
+ df = (cins & 0x007F0000) >> 16;
+
+ if ((df & 0x70) == 0x70) { // 111mmmm; b
+ m = df & 0x07;
+ df = 0;
+ } else if ((df & 0x60) == 0x60) { // 110mmmm; h
+ m = df & 0x0F;
+ df = 1;
+ } else if ((df & 0x40) == 0x40) { // 10mmmmm; w
+ m = df & 0x1F;
+ df = 2;
+ } else if ((df & 0x00) == 0x00) { // 0mmmmmm; d
+ m = df & 0x3F;
+ df = 3;
+ }
+
+ switch (operation) {
+ case 0x00: { /* SLLI.df */
+ switch (df) {
+ case 0x00: { /* SLLI.B */
+ DIP("SLLI.B w%d, w%d, %d", wd, ws, m);
+ putWReg(wd, binop(Iop_ShlN8x16, getWReg(ws), mkU8(m)));
+ break;
+ }
+
+ case 0x01: { /* SLLI.H */
+ DIP("SLLI.H w%d, w%d, %d", wd, ws, m);
+ putWReg(wd, binop(Iop_ShlN16x8, getWReg(ws), mkU8(m)));
+ break;
+ }
+
+ case 0x02: { /* SLLI.W */
+ DIP("SLLI.W w%d, w%d, %d", wd, ws, m);
+ putWReg(wd, binop(Iop_ShlN32x4, getWReg(ws), mkU8(m)));
+ break;
+ }
+
+ case 0x03: { /* SLLI.D */
+ DIP("SLLI.D w%d, w%d, %d", wd, ws, m);
+ putWReg(wd, binop(Iop_ShlN64x2, getWReg(ws), mkU8(m)));
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x01: { /* SRAI.df */
+ switch (df) {
+ case 0x00: { /* SRAI.B */
+ DIP("SRAI.B w%d, w%d, %d", wd, ws, m);
+ putWReg(wd, binop(Iop_SarN8x16, getWReg(ws), mkU8(m)));
+ break;
+ }
+
+ case 0x01: { /* SRAI.H */
+ DIP("SRAI.H w%d, w%d, %d", wd, ws, m);
+ putWReg(wd, binop(Iop_SarN16x8, getWReg(ws), mkU8(m)));
+ break;
+ }
+
+ case 0x02: { /* SRAI.W */
+ DIP("SRAI.W w%d, w%d, %d", wd, ws, m);
+ putWReg(wd, binop(Iop_SarN32x4, getWReg(ws), mkU8(m)));
+ break;
+ }
+
+ case 0x03: { /* SRAI.D */
+ DIP("SRAI.D w%d, w%d, %d", wd, ws, m);
+ putWReg(wd, binop(Iop_SarN64x2, getWReg(ws), mkU8(m)));
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x02: { /* SRLI.df */
+ switch (df) {
+ case 0x00: { /* SRLI.B */
+ DIP("SRLI.B w%d, w%d, %d", wd, ws, m);
+ putWReg(wd, binop(Iop_ShrN8x16, getWReg(ws), mkU8(m)));
+ break;
+ }
+
+ case 0x01: { /* SRLI.H */
+ DIP("SRLI.H w%d, w%d, %d", wd, ws, m);
+ putWReg(wd, binop(Iop_ShrN16x8, getWReg(ws), mkU8(m)));
+ break;
+ }
+
+ case 0x02: { /* SRLI.W */
+ DIP("SRLI.W w%d, w%d, %d", wd, ws, m);
+ putWReg(wd, binop(Iop_ShrN32x4, getWReg(ws), mkU8(m)));
+ break;
+ }
+
+ case 0x03: { /* SRLI.D */
+ DIP("SRLI.D w%d, w%d, %d", wd, ws, m);
+ putWReg(wd, binop(Iop_ShrN64x2, getWReg(ws), mkU8(m)));
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x03: { /* BCLRI.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 1;
+ assign(t1, getWReg(ws));
+
+ switch (df) {
+ case 0x00: { /* BCLRI.B */
+ DIP("BCLRI.B w%d, w%d, %d", wd, ws, m);
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t2, binop(Iop_ShlN8x16,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),mkU8(m)));
+ break;
+ }
+
+ case 0x01: { /* BCLRI.H */
+ DIP("BCLRI.H w%d, w%d, %d", wd, ws, m);
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t2, binop(Iop_ShlN16x8,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)), mkU8(m)));
+ break;
+ }
+
+ case 0x02: { /* BCLRI.W */
+ DIP("BCLRI.W w%d, w%d, %d", wd, ws, m);
+ tmp |= (tmp << 32);
+ assign(t2, binop(Iop_ShlN32x4,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)), mkU8(m)));
+ break;
+ }
+
+ case 0x03: { /* BCLRI.D */
+ DIP("BCLRI.D w%d, w%d, %d", wd, ws, m);
+ assign(t2, binop(Iop_ShlN64x2,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)), mkU8(m)));
+ break;
+ }
+ }
+
+ assign(t3, binop(Iop_AndV128,
+ mkexpr(t1), unop(Iop_NotV128, mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x04: { /* BSETI */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 1;
+ assign(t1, getWReg(ws));
+
+ switch (df) {
+ case 0x00: { /* BSETI.B */
+ DIP("BSETI.B w%d, w%d, %d", wd, ws, m);
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t2, binop(Iop_ShlN8x16,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)), mkU8(m)));
+ break;
+ }
+
+ case 0x01: { /* BSETI.H */
+ DIP("BSETI.H w%d, w%d, %d", wd, ws, m);
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t2, binop(Iop_ShlN16x8,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)), mkU8(m)));
+ break;
+ }
+
+ case 0x02: { /* BSETI.W */
+ DIP("BSETI.W w%d, w%d, %d", wd, ws, m);
+ tmp |= (tmp << 32);
+ assign(t2, binop(Iop_ShlN32x4,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)), mkU8(m)));
+ break;
+ }
+
+ case 0x03: { /* BSETI.D */
+ DIP("BSETI.D w%d, w%d, %d", wd, ws, m);
+ assign(t2, binop(Iop_ShlN64x2,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)), mkU8(m)));
+ break;
+ }
+ }
+
+ assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x05: { /* BNEGI.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 1;
+ assign(t1, getWReg(ws));
+
+ switch (df) {
+ case 0x00: { /* BNEGI.B */
+ DIP("BNEGI.B w%d, w%d, %d", wd, ws, m);
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t2, binop(Iop_ShlN8x16,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)), mkU8(m)));
+ break;
+ }
+
+ case 0x01: { /* BNEGI.H */
+ DIP("BNEGI.H w%d, w%d, %d", wd, ws, m);
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t2, binop(Iop_ShlN16x8,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)), mkU8(m)));
+ break;
+ }
+
+ case 0x02: { /* BNEGI.W */
+ DIP("BNEGI.W w%d, w%d, %d", wd, ws, m);
+ tmp |= (tmp << 32);
+ assign(t2, binop(Iop_ShlN32x4,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)), mkU8(m)));
+ break;
+ }
+
+ case 0x03: { /* BNEGI.D */
+ DIP("BNEGI.D w%d, w%d, %d", wd, ws, m);
+ assign(t2, binop(Iop_ShlN64x2,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)), mkU8(m)));
+ break;
+ }
+ }
+
+ assign(t3, binop(Iop_XorV128, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x06: { /* BINSLI.df */
+ switch (df) {
+ case 0x00: { /* BINSLI.B */
+ DIP("BINSLI.B w%d, w%d, w%d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 0x8080808080808080ULL;
+ assign(t1, binop(Iop_SarN8x16,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)), mkU8(m)));
+ assign(t2,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t1)), getWReg(wd)));
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), getWReg(ws)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ case 0x01: { /* BINSLI.H */
+ DIP("BINSLI.H w%d, w%d, w%d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 0x8000800080008000ULL;
+ assign(t1,
+ binop(Iop_SarN16x8,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)), mkU8(m)));
+ assign(t2,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t1)), getWReg(wd)));
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), getWReg(ws)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ case 0x02: { /* BINSLI.W */
+ DIP("BINSLI.W w%d, w%d, w%d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 0x8000000080000000ULL;
+ assign(t1,
+ binop(Iop_SarN32x4,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)), mkU8(m)));
+ assign(t2,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t1)), getWReg(wd)));
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), getWReg(ws)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ case 0x03: { /* BINSLI.D */
+ DIP("BINSLI.D w%d, w%d, w%d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 0x8000000000000000ULL;
+ assign(t1,
+ binop(Iop_SarN64x2,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)), mkU8(m)));
+ assign(t2,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t1)), getWReg(wd)));
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), getWReg(ws)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x07: {
+ switch (df) {
+ case 0x00: { /* BINSRI.B */
+ DIP("BINSRI.B w%d, w%d, w%d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 0xFEFEFEFEFEFEFEFEULL;
+ assign(t1,
+ binop(Iop_ShlN8x16,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)), mkU8(m)));
+ assign(t2,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t1)), getWReg(ws)));
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), getWReg(wd)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ case 0x01: { /* BINSRI.H */
+ DIP("BINSRI.H w%d, w%d, w%d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 0xFFFEFFFEFFFEFFFEULL;
+ assign(t1,
+ binop(Iop_ShlN16x8,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ mkU8(m)));
+ assign(t2,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t1)),
+ getWReg(ws)));
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), getWReg(wd)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ case 0x02: { /* BINSRI.W */
+ DIP("BINSRI.W w%d, w%d, w%d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 0xFFFFFFFEFFFFFFFEULL;
+ assign(t1,
+ binop(Iop_ShlN32x4,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ mkU8(m)));
+ assign(t2,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t1)),
+ getWReg(ws)));
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), getWReg(wd)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ case 0x03: { /* BINSRI.D */
+ DIP("BINSRI.D w%d, w%d, w%d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = -2;
+ assign(t1,
+ binop(Iop_ShlN64x2,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ mkU8(m)));
+ assign(t2,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t1)),
+ getWReg(ws)));
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), getWReg(wd)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_BIT_0A(UInt cins, UChar wd, UChar ws) { /* BIT (0x0A) */
+ IRTemp t1, t2;
+ UShort operation;
+ UChar df, m;
+
+ operation = (cins & 0x03800000) >> 23;
+ df = (cins & 0x007F0000) >> 16;
+
+ if ((df & 0x70) == 0x70) { // 111mmmm; b
+ m = df & 0x07;
+ df = 0;
+ } else if ((df & 0x60) == 0x60) { // 110mmmm; h
+ m = df & 0x0F;
+ df = 1;
+ } else if ((df & 0x40) == 0x40) { // 10mmmmm; w
+ m = df & 0x1F;
+ df = 2;
+ } else if ((df & 0x00) == 0x00) { // 0mmmmmm; d
+ m = df & 0x3F;
+ df = 3;
+ }
+
+ switch (operation) {
+ case 0x00: { /* SAT_S.df */
+ switch (df) {
+ case 0x00: { /* SAT_S.B */
+ DIP("SAT_S.B w%d, w%d, %d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ assign(t1, binop(Iop_SarN8x16, getWReg(ws), mkU8(7)));
+
+ if (m == 0) {
+ putWReg(wd, mkexpr(t1));
+ } else {
+ t2 = newTemp(Ity_V128);
+ assign(t2,
+ binop(Iop_SarN8x16, getWReg(ws), mkU8(m)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_CmpEQ8x16,
+ mkexpr(t1),
+ mkexpr(t2)),
+ getWReg(ws)),
+ binop(Iop_ShlN8x16,
+ binop(Iop_CmpGT8Sx16,
+ mkexpr(t1),
+ mkexpr(t2)),
+ mkU8(m))),
+ binop(Iop_ShrN8x16,
+ binop(Iop_CmpGT8Sx16,
+ mkexpr(t2),
+ mkexpr(t1)),
+ mkU8(8 - m))));
+ }
+
+ break;
+ }
+
+ case 0x01: { /* SAT_S.H */
+ DIP("SAT_S.H w%d, w%d, %d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ assign(t1, binop(Iop_SarN16x8, getWReg(ws), mkU8(15)));
+
+ if (m == 0) {
+ putWReg(wd, mkexpr(t1));
+ } else {
+ t2 = newTemp(Ity_V128);
+ assign(t2,
+ binop(Iop_SarN16x8,
+ getWReg(ws),
+ mkU8(m)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_CmpEQ16x8,
+ mkexpr(t1),
+ mkexpr(t2)),
+ getWReg(ws)),
+ binop(Iop_ShlN16x8,
+ binop(Iop_CmpGT16Sx8,
+ mkexpr(t1),
+ mkexpr(t2)),
+ mkU8(m))),
+ binop(Iop_ShrN16x8,
+ binop(Iop_CmpGT16Sx8,
+ mkexpr(t2),
+ mkexpr(t1)),
+ mkU8(16 - m))));
+ }
+
+ break;
+ }
+
+ case 0x02: { /* SAT_S.W */
+ DIP("SAT_S.W w%d, w%d, %d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ assign(t1, binop(Iop_SarN32x4, getWReg(ws), mkU8(31)));
+
+ if (m == 0) {
+ putWReg(wd, mkexpr(t1));
+ } else {
+ t2 = newTemp(Ity_V128);
+ assign(t2,
+ binop(Iop_SarN32x4,
+ getWReg(ws),
+ mkU8(m)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_CmpEQ32x4,
+ mkexpr(t1),
+ mkexpr(t2)),
+ getWReg(ws)),
+ binop(Iop_ShlN32x4,
+ binop(Iop_CmpGT32Sx4,
+ mkexpr(t1),
+ mkexpr(t2)),
+ mkU8(m))),
+ binop(Iop_ShrN32x4,
+ binop(Iop_CmpGT32Sx4,
+ mkexpr(t2),
+ mkexpr(t1)),
+ mkU8(32 - m))));
+ }
+
+ break;
+ }
+
+ case 0x03: { /* SAT_S.D */
+ DIP("SAT_S.D w%d, w%d, %d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ assign(t1, binop(Iop_SarN64x2, getWReg(ws), mkU8(63)));
+
+ if (m == 0) {
+ putWReg(wd, mkexpr(t1));
+ } else {
+ t2 = newTemp(Ity_V128);
+ assign(t2,
+ binop(Iop_SarN64x2,
+ getWReg(ws),
+ mkU8(m)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_CmpEQ64x2,
+ mkexpr(t1),
+ mkexpr(t2)),
+ getWReg(ws)),
+ binop(Iop_ShlN64x2,
+ binop(Iop_CmpGT64Sx2,
+ mkexpr(t1),
+ mkexpr(t2)),
+ mkU8(m))),
+ binop(Iop_ShrN64x2,
+ binop(Iop_CmpGT64Sx2,
+ mkexpr(t2),
+ mkexpr(t1)),
+ mkU8(64 - m))));
+ }
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x01: { /* SAT_U.df */
+ switch (df) {
+ case 0x00: { /* SAT_U.B */
+ DIP("SAT_U.B w%d, w%d, %d", wd, ws, m);
+
+ if (m == 7) {
+ putWReg(wd, getWReg(ws));
+ } else {
+ t1 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_CmpEQ8x16,
+ binop(Iop_ShrN8x16,
+ getWReg(ws),
+ mkU8(m + 1)),
+ binop(Iop_64HLtoV128,
+ mkU64(0), mkU64(0))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ getWReg(ws)),
+ binop(Iop_ShrN8x16,
+ unop(Iop_NotV128,
+ mkexpr(t1)),
+ mkU8(7 - m))));
+ }
+
+ break;
+ }
+
+ case 0x01: { /* SAT_U.H */
+ DIP("SAT_U.H w%d, w%d, %d", wd, ws, m);
+
+ if (m == 15) {
+ putWReg(wd, getWReg(ws));
+ } else {
+ t1 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_CmpEQ16x8,
+ binop(Iop_ShrN16x8,
+ getWReg(ws),
+ mkU8(m + 1)),
+ binop(Iop_64HLtoV128,
+ mkU64(0), mkU64(0))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ getWReg(ws)),
+ binop(Iop_ShrN16x8,
+ unop(Iop_NotV128,
+ mkexpr(t1)),
+ mkU8(15 - m))));
+ }
+
+ break;
+ }
+
+ case 0x02: { /* SAT_U.W */
+ DIP("SAT_U.W w%d, w%d, %d", wd, ws, m);
+
+ if (m == 31) {
+ putWReg(wd, getWReg(ws));
+ } else {
+ t1 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_CmpEQ32x4,
+ binop(Iop_ShrN32x4,
+ getWReg(ws),
+ mkU8(m + 1)),
+ binop(Iop_64HLtoV128,
+ mkU64(0), mkU64(0))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t1), \
+ getWReg(ws)),
+ binop(Iop_ShrN32x4,
+ unop(Iop_NotV128,
+ mkexpr(t1)),
+ mkU8(31 - m))));
+ }
+
+ break;
+ }
+
+ case 0x03: { /* SAT_U.D */
+ DIP("SAT_U.D w%d, w%d, %d", wd, ws, m);
+
+ if (m == 63) {
+ putWReg(wd, getWReg(ws));
+ } else {
+ t1 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_CmpEQ64x2,
+ binop(Iop_ShrN64x2,
+ getWReg(ws),
+ mkU8(m + 1)),
+ binop(Iop_64HLtoV128,
+ mkU64(0), mkU64(0))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ getWReg(ws)),
+ binop(Iop_ShrN64x2,
+ unop(Iop_NotV128,
+ mkexpr(t1)),
+ mkU8(63 - m))));
+ }
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x02: { /* SRARI.df */
+ switch (df) {
+ case 0x00: { /* SRARI.B */
+ DIP("SRARI.B w%d, w%d, %d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_SarN8x16,
+ getWReg(ws),
+ mkU8(m)));
+ assign(t2,
+ binop(Iop_ShrN8x16,
+ binop(Iop_ShlN8x16,
+ getWReg(ws),
+ mkU8(8 - m)),
+ mkU8(7)));
+
+ if (m) putWReg(wd, binop(Iop_Add8x16,
+ mkexpr(t1),
+ mkexpr(t2)));
+ else putWReg(wd, mkexpr(t1));
+
+ break;
+ }
+
+ case 0x01: { /* SRARI.H */
+ DIP("SRARI.H w%d, w%d, %d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_SarN16x8,
+ getWReg(ws),
+ mkU8(m)));
+ assign(t2,
+ binop(Iop_ShrN16x8,
+ binop(Iop_ShlN16x8,
+ getWReg(ws),
+ mkU8(16 - m)),
+ mkU8(15)));
+
+ if (m)
+ putWReg(wd,
+ binop(Iop_Add16x8,
+ mkexpr(t1), mkexpr(t2)));
+ else putWReg(wd, mkexpr(t1));
+
+ break;
+ }
+
+ case 0x02: { /* SRARI.W */
+ DIP("SRARI.W w%d, w%d, %d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_SarN32x4,
+ getWReg(ws),
+ mkU8(m)));
+ assign(t2,
+ binop(Iop_ShrN32x4,
+ binop(Iop_ShlN32x4,
+ getWReg(ws),
+ mkU8(32 - m)),
+ mkU8(31)));
+
+ if (m)
+ putWReg(wd,
+ binop(Iop_Add32x4,
+ mkexpr(t1), mkexpr(t2)));
+ else putWReg(wd, mkexpr(t1));
+
+ break;
+ }
+
+ case 0x03: { /* SRARI.D */
+ DIP("SRARI.D w%d, w%d, %d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_SarN64x2,
+ getWReg(ws),
+ mkU8(m)));
+ assign(t2,
+ binop(Iop_ShrN64x2,
+ binop(Iop_ShlN64x2,
+ getWReg(ws),
+ mkU8(64 - m)),
+ mkU8(63)));
+
+ if (m)
+ putWReg(wd,
+ binop(Iop_Add64x2,
+ mkexpr(t1), mkexpr(t2)));
+ else putWReg(wd, mkexpr(t1));
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x03: { /* SRLRI.df */
+ switch (df) {
+ case 0x00: { /* SRLRI.B */
+ DIP("SRLRI.B w%d, w%d, %d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_ShrN8x16,
+ getWReg(ws),
+ mkU8(m)));
+ assign(t2,
+ binop(Iop_ShrN8x16,
+ binop(Iop_ShlN8x16,
+ getWReg(ws),
+ mkU8(8 - m)),
+ mkU8(7)));
+
+ if (m)
+ putWReg(wd,
+ binop(Iop_Add8x16,
+ mkexpr(t1), mkexpr(t2)));
+ else putWReg(wd, mkexpr(t1));
+
+ break;
+ }
+
+ case 0x01: { /* SRLRI.H */
+ DIP("SRLRI.H w%d, w%d, %d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_ShrN16x8,
+ getWReg(ws),
+ mkU8(m)));
+ assign(t2,
+ binop(Iop_ShrN16x8,
+ binop(Iop_ShlN16x8,
+ getWReg(ws),
+ mkU8(16 - m)),
+ mkU8(15)));
+
+ if (m)
+ putWReg(wd,
+ binop(Iop_Add16x8,
+ mkexpr(t1), mkexpr(t2)));
+ else putWReg(wd, mkexpr(t1));
+
+ break;
+ }
+
+ case 0x02: { /* SRLRI.W */
+ DIP("SRLRI.W w%d, w%d, %d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_ShrN32x4,
+ getWReg(ws),
+ mkU8(m)));
+ assign(t2,
+ binop(Iop_ShrN32x4,
+ binop(Iop_ShlN32x4,
+ getWReg(ws),
+ mkU8(32 - m)),
+ mkU8(31)));
+
+ if (m)
+ putWReg(wd,
+ binop(Iop_Add32x4,
+ mkexpr(t1), mkexpr(t2)));
+ else putWReg(wd, mkexpr(t1));
+
+ break;
+ }
+
+ case 0x03: { /* SRLRI.D */
+ DIP("SRLRI.D w%d, w%d, %d", wd, ws, m);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_ShrN64x2,
+ getWReg(ws),
+ mkU8(m)));
+ assign(t2,
+ binop(Iop_ShrN64x2,
+ binop(Iop_ShlN64x2,
+ getWReg(ws),
+ mkU8(64 - m)),
+ mkU8(63)));
+
+ if (m)
+ putWReg(wd,
+ binop(Iop_Add64x2,
+ mkexpr(t1), mkexpr(t2)));
+ else putWReg(wd, mkexpr(t1));
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_3R_0D(UInt cins, UChar wd, UChar ws) { /* 3R (0x0D) */
+ IRTemp t1, t2, t3;
+ UShort operation;
+ UChar df, wt;
+
+ operation = (cins & 0x03800000) >> 23;
+ df = (cins & 0x00600000) >> 21;
+ wt = (cins & 0x001F0000) >> 16;
+
+ switch (operation) {
+ case 0x00: { /* SLL.df */
+ switch (df) {
+ case 0x00: { /* SLL.B */
+ DIP("SLL.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Shl8x16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* SLL.H */
+ DIP("SLL.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Shl16x8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* SLL.W */
+ DIP("SLL.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Shl32x4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* SLL.D */
+ DIP("SLL.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Shl64x2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x01: { /* SRA.df */
+ switch (df) {
+ case 0x00: { /* SRA.B */
+ DIP("SRA.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Sar8x16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* SRA.H */
+ DIP("SRA.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Sar16x8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* SRA.W */
+ DIP("SRA.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Sar32x4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* SRA.D */
+ DIP("SRA.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Sar64x2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x02: { /* SRL.df */
+ switch (df) {
+ case 0x00: { /* SRL.B */
+ DIP("SRL.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Shr8x16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* SRL.H */
+ DIP("SRL.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Shr16x8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* SRL.W */
+ DIP("SRL.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Shr32x4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* SRL.D */
+ DIP("SRL.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Shr64x2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x03: { /* BCLR.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 1;
+ assign(t1, getWReg(ws));
+
+ switch (df) {
+ case 0x00: { /* BCLR.B */
+ DIP("BCLR.B w%d, w%d, w%d", wd, ws, wt);
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t2, binop(Iop_Shl8x16,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* BCLR.H */
+ DIP("BCLR.H w%d, w%d, w%d", wd, ws, wt);
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t2,
+ binop(Iop_Shl16x8,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x02: { /* BCLR.W */
+ DIP("BCLR.W w%d, w%d, w%d", wd, ws, wt);
+ tmp |= (tmp << 32);
+ assign(t2,
+ binop(Iop_Shl32x4,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x03: { /* BCLR.D */
+ DIP("BCLR.D w%d, w%d, w%d", wd, ws, wt);
+ assign(t2,
+ binop(Iop_Shl64x2,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ break;
+ }
+ }
+
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), unop(Iop_NotV128, mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x04: { /* BSET.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 1;
+ assign(t1, getWReg(ws));
+
+ switch (df) {
+ case 0x00: { /* BSET.B */
+ DIP("BSET.B w%d, w%d, w%d", wd, ws, wt);
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t2,
+ binop(Iop_Shl8x16,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* BSET.H */
+ DIP("BSET.H w%d, w%d, w%d", wd, ws, wt);
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t2,
+ binop(Iop_Shl16x8,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x02: { /* BSET.W */
+ DIP("BSET.W w%d, w%d, w%d", wd, ws, wt);
+ tmp |= (tmp << 32);
+ assign(t2,
+ binop(Iop_Shl32x4,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x03: { /* BSET.D */
+ DIP("BSET.D w%d, w%d, w%d", wd, ws, wt);
+ assign(t2,
+ binop(Iop_Shl64x2,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ break;
+ }
+ }
+
+ assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x05: { /* BNEG.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 1;
+ assign(t1, getWReg(ws));
+
+ switch (df) {
+ case 0x00: { /* BNEG.B */
+ DIP("BNEG.B w%d, w%d, w%d", wd, ws, wt);
+ tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
+ (tmp << 32) | (tmp << 24) | (tmp << 16) |
+ (tmp << 8);
+ assign(t2,
+ binop(Iop_Shl8x16,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* BNEG.H */
+ DIP("BNEG.H w%d, w%d, w%d", wd, ws, wt);
+ tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
+ assign(t2,
+ binop(Iop_Shl16x8,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x02: { /* BNEG.W */
+ DIP("BNEG.W w%d, w%d, w%d", wd, ws, wt);
+ tmp |= (tmp << 32);
+ assign(t2,
+ binop(Iop_Shl32x4,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x03: { /* BNEG.D */
+ DIP("BNEG.D w%d, w%d, w%d", wd, ws, wt);
+ assign(t2,
+ binop(Iop_Shl64x2,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ break;
+ }
+ }
+
+ assign(t3, binop(Iop_XorV128, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x06: { /* BINSL.df */
+ switch (df) {
+ case 0x00: { /* BINSL.B */
+ DIP("BINSL.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 0x8080808080808080ULL;
+ assign(t1,
+ binop(Iop_Sar8x16,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ assign(t2,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t1)),
+ getWReg(wd)));
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), getWReg(ws)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ case 0x01: { /* BINSL.H */
+ DIP("BINSL.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 0x8000800080008000ULL;
+ assign(t1,
+ binop(Iop_Sar16x8,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ assign(t2,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t1)),
+ getWReg(wd)));
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), getWReg(ws)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ case 0x02: { /* BINSL.W */
+ DIP("BINSL.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 0x8000000080000000ULL;
+ assign(t1,
+ binop(Iop_Sar32x4,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ assign(t2,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t1)),
+ getWReg(wd)));
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), getWReg(ws)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ case 0x03: { /* BINSL.D */
+ DIP("BINSL.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 0x8000000000000000ULL;
+ assign(t1,
+ binop(Iop_Sar64x2,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ assign(t2,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t1)),
+ getWReg(wd)));
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), getWReg(ws)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x07: { /* BINSR.df */
+ switch (df) {
+ case 0x00: { /* BINSR.B */
+ DIP("BINSR.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 0xFEFEFEFEFEFEFEFEULL;
+ assign(t1,
+ binop(Iop_Shl8x16,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ assign(t2,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t1)),
+ getWReg(ws)));
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), getWReg(wd)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ case 0x01: { /* BINSR.H */
+ DIP("BINSR.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 0xFFFEFFFEFFFEFFFEULL;
+ assign(t1,
+ binop(Iop_Shl16x8,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ assign(t2,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t1)),
+ getWReg(ws)));
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), getWReg(wd)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ case 0x02: { /* BINSR.W */
+ DIP("BINSR.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = 0xFFFFFFFEFFFFFFFEULL;
+ assign(t1,
+ binop(Iop_Shl32x4,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ assign(t2,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t1)),
+ getWReg(ws)));
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), getWReg(wd)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ case 0x03: { /* BINSR.D */
+ DIP("BINSR.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ ULong tmp = -2;
+ assign(t1,
+ binop(Iop_Shl64x2,
+ binop(Iop_64HLtoV128,
+ mkU64(tmp), mkU64(tmp)),
+ getWReg(wt)));
+ assign(t2,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t1)),
+ getWReg(ws)));
+ assign(t3,
+ binop(Iop_AndV128,
+ mkexpr(t1), getWReg(wd)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_3R_0E(UInt cins, UChar wd, UChar ws) { /* 3R (0x0E) */
+ IRTemp t1, t2, t3, t4;
+ UShort operation;
+ UChar df, wt;
+
+ operation = (cins & 0x03800000) >> 23;
+ df = (cins & 0x00600000) >> 21;
+ wt = (cins & 0x001F0000) >> 16;
+
+ switch (operation) {
+ case 0x00: { /* ADDV.df */
+ switch (df) {
+ case 0x00: { /* ADDV.B */
+ DIP("ADDV.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Add8x16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* ADDV.H */
+ DIP("ADDV.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Add16x8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* ADDV.W */
+ DIP("ADDV.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Add32x4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* ADDV.D */
+ DIP("ADDV.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Add64x2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x01: { /* SUBV.df */
+ switch (df) {
+ case 0x00: { /* SUBV.B */
+ DIP("SUBV.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Sub8x16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* SUBV.H */
+ DIP("SUBV.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Sub16x8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* SUBV.W */
+ DIP("SUBV.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Sub32x4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* SUBV.D */
+ DIP("SUBV.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Sub64x2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x02: { /* MAX_S.df */
+ switch (df) {
+ case 0x00: { /* MAX_S.B */
+ DIP("MAX_S.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Max8Sx16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* MAX_S.H */
+ DIP("MAX_S.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Max16Sx8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* MAX_S.W */
+ DIP("MAX_S.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Max32Sx4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* MAX_S.D */
+ DIP("MAX_S.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Max64Sx2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x03: { /* MAX_U.df */
+ switch (df) {
+ case 0x00: { /* MAX_U.B */
+ DIP("MAX_U.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Max8Ux16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* MAX_U.H */
+ DIP("MAX_U.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Max16Ux8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* MAX_U.W */
+ DIP("MAX_U.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Max32Ux4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* MAX_U.D */
+ DIP("MAX_U.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Max64Ux2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x04: { /* MIN_S.df */
+ switch (df) {
+ case 0x00: { /* MIN_S.B */
+ DIP("MIN_S.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Min8Sx16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* MIN_S.H */
+ DIP("MIN_S.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Min16Sx8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* MIN_S.W */
+ DIP("MIN_S.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Min32Sx4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* MIN_S.D */
+ DIP("MIN_S.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Min64Sx2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x05: { /* MIN_U.df */
+ switch (df) {
+ case 0x00: { /* MIN_U.B */
+ DIP("MIN_U.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Min8Ux16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* MIN_U.H */
+ DIP("MIN_U.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Min16Ux8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* MIN_U.W */
+ DIP("MIN_U.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Min32Ux4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* MIN_U.D */
+ DIP("MIN_U.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Min64Ux2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x06: { /* MAX_A.df */
+ switch (df) {
+ case 0x00: { /* MAX_A.B */
+ DIP("MAX_A.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Abs8x16, getWReg(ws)));
+ assign(t2, unop(Iop_Abs8x16, getWReg(wt)));
+ assign(t4, binop(Iop_CmpGT8Ux16, mkexpr(t1), mkexpr(t2)));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ getWReg(ws)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t4)),
+ getWReg(wt))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* MAX_A.H */
+ DIP("MAX_A.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Abs16x8, getWReg(ws)));
+ assign(t2, unop(Iop_Abs16x8, getWReg(wt)));
+ assign(t4, binop(Iop_CmpGT16Ux8, mkexpr(t1), mkexpr(t2)));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ getWReg(ws)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t4)),
+ getWReg(wt))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* MAX_A.W */
+ DIP("MAX_A.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Abs32x4, getWReg(ws)));
+ assign(t2, unop(Iop_Abs32x4, getWReg(wt)));
+ assign(t4, binop(Iop_CmpGT32Ux4, mkexpr(t1), mkexpr(t2)));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ getWReg(ws)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t4)),
+ getWReg(wt))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* MAX_A.D */
+ DIP("MAX_A.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Abs64x2, getWReg(ws)));
+ assign(t2, unop(Iop_Abs64x2, getWReg(wt)));
+ assign(t4, binop(Iop_CmpGT64Ux2, mkexpr(t1), mkexpr(t2)));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ getWReg(ws)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t4)),
+ getWReg(wt))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x07: { /* MIN_A.df */
+ switch (df) {
+ case 0x00: { /* MIN_A.B */
+ DIP("MIN_A.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Abs8x16, getWReg(ws)));
+ assign(t2, unop(Iop_Abs8x16, getWReg(wt)));
+ assign(t4, binop(Iop_OrV128,
+ binop(Iop_CmpGT8Ux16,
+ mkexpr(t1), mkexpr(t2)),
+ binop(Iop_CmpEQ8x16,
+ mkexpr(t1), mkexpr(t2))));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ getWReg(wt)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t4)),
+ getWReg(ws))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* MIN_A.H */
+ DIP("MIN_A.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Abs16x8, getWReg(ws)));
+ assign(t2, unop(Iop_Abs16x8, getWReg(wt)));
+ assign(t4, binop(Iop_OrV128,
+ binop(Iop_CmpGT16Ux8,
+ mkexpr(t1), mkexpr(t2)),
+ binop(Iop_CmpEQ16x8,
+ mkexpr(t1), mkexpr(t2))));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ getWReg(wt)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t4)),
+ getWReg(ws))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* MIN_A.W */
+ DIP("MIN_A.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Abs32x4, getWReg(ws)));
+ assign(t2, unop(Iop_Abs32x4, getWReg(wt)));
+ assign(t4, binop(Iop_OrV128,
+ binop(Iop_CmpGT32Ux4,
+ mkexpr(t1), mkexpr(t2)),
+ binop(Iop_CmpEQ32x4,
+ mkexpr(t1), mkexpr(t2))));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ getWReg(wt)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t4)),
+ getWReg(ws))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* MIN_A.D */
+ DIP("MIN_A.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Abs64x2, getWReg(ws)));
+ assign(t2, unop(Iop_Abs64x2, getWReg(wt)));
+ assign(t4, binop(Iop_OrV128,
+ binop(Iop_CmpGT64Ux2,
+ mkexpr(t1), mkexpr(t2)),
+ binop(Iop_CmpEQ64x2,
+ mkexpr(t1), mkexpr(t2))));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ getWReg(wt)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t4)),
+ getWReg(ws))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_3R_0F(UInt cins, UChar wd, UChar ws) { /* 3R (0x0F) */
+ IRTemp t1, t2, t3;
+ UShort operation;
+ UChar df, wt;
+
+ operation = (cins & 0x03800000) >> 23;
+ df = (cins & 0x00600000) >> 21;
+ wt = (cins & 0x001F0000) >> 16;
+
+ switch (operation) {
+ case 0x00: { /* CEQ.df */
+ switch (df) {
+ case 0x00: { /* CEQ.B */
+ DIP("CEQ.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_CmpEQ8x16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* CEQ.H */
+ DIP("CEQ.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_CmpEQ16x8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* CEQ.W */
+ DIP("CEQ.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_CmpEQ32x4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* CEQ.D */
+ DIP("CEQ.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_CmpEQ64x2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x02: { /* CLT_S.df */
+ switch (df) {
+ case 0x00: { /* CLT_S.B */
+ DIP("CLT_S.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_CmpGT8Sx16, mkexpr(t2), mkexpr(t1)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* CLT_S.H */
+ DIP("CLT_S.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_CmpGT16Sx8, mkexpr(t2), mkexpr(t1)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* CLT_S.W */
+ DIP("CLT_S.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_CmpGT32Sx4, mkexpr(t2), mkexpr(t1)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* CLT_S.D */
+ DIP("CLT_S.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_CmpGT64Sx2, mkexpr(t2), mkexpr(t1)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x03: { /* CLT_U.df */
+ switch (df) {
+ case 0x00: { /* CLT_U.B */
+ DIP("CLT_U.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_CmpGT8Ux16, mkexpr(t2), mkexpr(t1)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* CLT_U.H */
+ DIP("CLT_U.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_CmpGT16Ux8, mkexpr(t2), mkexpr(t1)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* CLT_U.W */
+ DIP("CLT_U.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_CmpGT32Ux4, mkexpr(t2), mkexpr(t1)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* CLT_U.D */
+ DIP("CLT_U.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_CmpGT64Ux2, mkexpr(t2), mkexpr(t1)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x04: { /* CLE_S.df */
+ switch (df) {
+ case 0x00: { /* CLE_S.B */
+ DIP("CLE_S.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_CmpGT8Sx16,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_CmpEQ8x16,
+ mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* CLE_S.H */
+ DIP("CLE_S.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_CmpGT16Sx8,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_CmpEQ16x8,
+ mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* CLE_S.W */
+ DIP("CLE_S.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_CmpGT32Sx4,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_CmpEQ32x4,
+ mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* CLE_S.D */
+ DIP("CLE_S.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_CmpGT64Sx2,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_CmpEQ64x2,
+ mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x05: { /* CLE_U.df */
+ switch (df) {
+ case 0x00: { /* CLE_U.B */
+ DIP("CLE_U.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_CmpGT8Ux16,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_CmpEQ8x16,
+ mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* CLE_U.H */
+ DIP("CLE_U.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_CmpGT16Ux8,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_CmpEQ16x8,
+ mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* CLE_U.W */
+ DIP("CLE_U.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_CmpGT32Ux4,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_CmpEQ32x4,
+ mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* CLE_U.D */
+ DIP("CLE_U.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_OrV128,
+ binop(Iop_CmpGT64Ux2,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_CmpEQ64x2,
+ mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_3R_10(UInt cins, UChar wd, UChar ws) { /* 3R (0x10) */
+ IRTemp t1, t2, t3, t4;
+ UShort operation;
+ UChar df, wt;
+
+ operation = (cins & 0x03800000) >> 23;
+ df = (cins & 0x00600000) >> 21;
+ wt = (cins & 0x001F0000) >> 16;
+
+ switch (operation) {
+ case 0x00: { /* ADD_A.df */
+ switch (df) {
+ case 0x00: { /* ADD_A.B */
+ DIP("ADD_A.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Abs8x16, getWReg(ws)));
+ assign(t2, unop(Iop_Abs8x16, getWReg(wt)));
+ assign(t3, binop(Iop_Add8x16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* ADD_A.H */
+ DIP("ADD_A.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Abs16x8, getWReg(ws)));
+ assign(t2, unop(Iop_Abs16x8, getWReg(wt)));
+ assign(t3, binop(Iop_Add16x8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* ADD_A.W */
+ DIP("ADD_A.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Abs32x4, getWReg(ws)));
+ assign(t2, unop(Iop_Abs32x4, getWReg(wt)));
+ assign(t3, binop(Iop_Add32x4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* ADD_A.D */
+ DIP("ADD_A.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Abs64x2, getWReg(ws)));
+ assign(t2, unop(Iop_Abs64x2, getWReg(wt)));
+ assign(t3, binop(Iop_Add64x2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x01: { /* ADDS_A.df */
+ switch (df) {
+ case 0x00: { /* ADDS_A.B */
+ DIP("ADDS_A.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Abs8x16, getWReg(ws)));
+ assign(t2, unop(Iop_Abs8x16, getWReg(wt)));
+ assign(t3, binop(Iop_SarN8x16,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ getWReg(ws)),
+ mkU8(7)));
+ assign(t4, binop(Iop_SarN8x16,
+ binop(Iop_AndV128,
+ mkexpr(t2),
+ getWReg(wt)),
+ mkU8(7)));
+ putWReg(wd, binop(Iop_QAdd8Sx16,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t3)),
+ mkexpr(t1)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t1)),
+ mkexpr(t3))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t4)),
+ mkexpr(t2)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t2)),
+ mkexpr(t4)))));
+ break;
+ }
+
+ case 0x01: { /* ADDS_A.H */
+ DIP("ADDS_A.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Abs16x8, getWReg(ws)));
+ assign(t2, unop(Iop_Abs16x8, getWReg(wt)));
+ assign(t3, binop(Iop_SarN16x8,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ getWReg(ws)),
+ mkU8(15)));
+ assign(t4, binop(Iop_SarN16x8,
+ binop(Iop_AndV128,
+ mkexpr(t2),
+ getWReg(wt)),
+ mkU8(15)));
+ putWReg(wd, binop(Iop_QAdd16Sx8,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t3)),
+ mkexpr(t1)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t1)),
+ mkexpr(t3))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t4)),
+ mkexpr(t2)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t2)),
+ mkexpr(t4)))));
+ break;
+ }
+
+ case 0x02: { /* ADDS_A.W */
+ DIP("ADDS_A.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Abs32x4, getWReg(ws)));
+ assign(t2, unop(Iop_Abs32x4, getWReg(wt)));
+ assign(t3, binop(Iop_SarN32x4,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ getWReg(ws)),
+ mkU8(31)));
+ assign(t4, binop(Iop_SarN32x4,
+ binop(Iop_AndV128,
+ mkexpr(t2),
+ getWReg(wt)),
+ mkU8(31)));
+ putWReg(wd, binop(Iop_QAdd32Sx4,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t3)),
+ mkexpr(t1)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t1)),
+ mkexpr(t3))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t4)),
+ mkexpr(t2)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t2)),
+ mkexpr(t4)))));
+ break;
+ }
+
+ case 0x03: { /* ADDS_A.D */
+ DIP("ADDS_A.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Abs64x2, getWReg(ws)));
+ assign(t2, unop(Iop_Abs64x2, getWReg(wt)));
+ assign(t3, binop(Iop_SarN64x2,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ getWReg(ws)),
+ mkU8(63)));
+ assign(t4, binop(Iop_SarN64x2,
+ binop(Iop_AndV128,
+ mkexpr(t2),
+ getWReg(wt)),
+ mkU8(63)));
+ putWReg(wd,
+ binop(Iop_QAdd64Sx2,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t3)),
+ mkexpr(t1)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t1)),
+ mkexpr(t3))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t4)),
+ mkexpr(t2)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t2)),
+ mkexpr(t4)))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x02: { /* ADDS_S.df */
+ switch (df) {
+ case 0x00: { /* ADDS_S.B */
+ DIP("ADDS_S.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QAdd8Sx16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* ADDS_S.H */
+ DIP("ADDS_S.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QAdd16Sx8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* ADDS_S.W */
+ DIP("ADDS_S.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QAdd32Sx4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* ADDS_S.D */
+ DIP("ADDS_S.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QAdd64Sx2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x03: { /* ADDS_U.df */
+ switch (df) {
+ case 0x00: { /* ADDS_U.B */
+ DIP("ADDS_U.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QAdd8Ux16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* ADDS_U.H */
+ DIP("ADDS_U.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QAdd16Ux8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* ADDS_U.W */
+ DIP("ADDS_U.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QAdd32Ux4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* ADDS_U.D */
+ DIP("ADDS_U.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QAdd64Ux2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x04: { /* AVE_S.df */
+ switch (df) {
+ case 0x00: { /* AVE_S.B */
+ DIP("AVE_S.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Add8x16,
+ binop(Iop_Add8x16,
+ binop(Iop_SarN8x16,
+ mkexpr(t1), mkU8(1)),
+ binop(Iop_SarN8x16,
+ mkexpr(t2), mkU8(1))),
+ binop(Iop_ShrN8x16,
+ binop(Iop_ShlN8x16,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ mkexpr(t2)),
+ mkU8(7)),
+ mkU8(7))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* AVE_S.H */
+ DIP("AVE_S.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_Add16x8,
+ binop(Iop_Add16x8,
+ binop(Iop_SarN16x8,
+ mkexpr(t1), mkU8(1)),
+ binop(Iop_SarN16x8,
+ mkexpr(t2), mkU8(1))),
+ binop(Iop_ShrN16x8,
+ binop(Iop_ShlN16x8,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ mkexpr(t2)),
+ mkU8(15)),
+ mkU8(15))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* AVE_S.W */
+ DIP("AVE_S.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Add32x4,
+ binop(Iop_Add32x4,
+ binop(Iop_SarN32x4,
+ mkexpr(t1), mkU8(1)),
+ binop(Iop_SarN32x4,
+ mkexpr(t2), mkU8(1))),
+ binop(Iop_ShrN32x4,
+ binop(Iop_ShlN32x4,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ mkexpr(t2)),
+ mkU8(31)),
+ mkU8(31))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* AVE_S.D */
+ DIP("AVE_S.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Add64x2,
+ binop(Iop_Add64x2,
+ binop(Iop_SarN64x2,
+ mkexpr(t1), mkU8(1)),
+ binop(Iop_SarN64x2,
+ mkexpr(t2), mkU8(1))),
+ binop(Iop_ShrN64x2,
+ binop(Iop_ShlN64x2,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ mkexpr(t2)),
+ mkU8(63)),
+ mkU8(63))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x05: { /* AVE_U.df */
+ switch (df) {
+ case 0x00: { /* AVE_U.B */
+ DIP("AVE_U.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Add16x8,
+ binop(Iop_Add8x16,
+ binop(Iop_ShrN8x16,
+ mkexpr(t1), mkU8(1)),
+ binop(Iop_ShrN8x16,
+ mkexpr(t2), mkU8(1))),
+ binop(Iop_ShrN8x16,
+ binop(Iop_ShlN8x16,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ mkexpr(t2)),
+ mkU8(7)),
+ mkU8(7))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* AVE_U.H */
+ DIP("AVE_U.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Add16x8,
+ binop(Iop_Add16x8,
+ binop(Iop_ShrN16x8,
+ mkexpr(t1), mkU8(1)),
+ binop(Iop_ShrN16x8,
+ mkexpr(t2), mkU8(1))),
+ binop(Iop_ShrN16x8,
+ binop(Iop_ShlN16x8,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ mkexpr(t2)),
+ mkU8(15)),
+ mkU8(15))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* AVE_U.W */
+ DIP("AVE_U.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Add32x4,
+ binop(Iop_Add32x4,
+ binop(Iop_ShrN32x4,
+ mkexpr(t1), mkU8(1)),
+ binop(Iop_ShrN32x4,
+ mkexpr(t2), mkU8(1))),
+ binop(Iop_ShrN32x4,
+ binop(Iop_ShlN32x4,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ mkexpr(t2)),
+ mkU8(31)),
+ mkU8(31))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* AVE_U.D */
+ DIP("AVE_U.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Add64x2,
+ binop(Iop_Add64x2,
+ binop(Iop_ShrN64x2,
+ mkexpr(t1), mkU8(1)),
+ binop(Iop_ShrN64x2,
+ mkexpr(t2), mkU8(1))),
+ binop(Iop_ShrN64x2,
+ binop(Iop_ShlN64x2,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ mkexpr(t2)),
+ mkU8(63)),
+ mkU8(63))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x06: { /* AVER_S.df */
+ switch (df) {
+ case 0x00: { /* AVER_S.B */
+ DIP("AVER_S.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Avg8Sx16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* AVER_S.H */
+ DIP("AVER_S.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Avg16Sx8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* AVER_S.W */
+ DIP("AVER_S.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Avg32Sx4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* AVER_S.D */
+ DIP("AVER_S.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Add64x2,
+ binop(Iop_Add64x2,
+ binop(Iop_SarN64x2,
+ mkexpr(t1), mkU8(1)),
+ binop(Iop_SarN64x2,
+ mkexpr(t2), mkU8(1))),
+ binop(Iop_ShrN64x2,
+ binop(Iop_ShlN64x2,
+ binop(Iop_OrV128,
+ mkexpr(t1),
+ mkexpr(t2)),
+ mkU8(63)),
+ mkU8(63))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x07: { /* AVER_U.df */
+ switch (df) {
+ case 0x00: { /* AVER_U.B */
+ DIP("AVER_U.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Avg8Ux16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* AVER_U.H */
+ DIP("AVER_U.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Avg16Ux8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* AVER_U.W */
+ DIP("AVER_U.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Avg32Ux4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* AVER_U.D */
+ DIP("AVER_U.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_Add64x2,
+ binop(Iop_Add64x2,
+ binop(Iop_ShrN64x2,
+ mkexpr(t1), mkU8(1)),
+ binop(Iop_ShrN64x2,
+ mkexpr(t2), mkU8(1))),
+ binop(Iop_ShrN64x2,
+ binop(Iop_ShlN64x2,
+ binop(Iop_OrV128,
+ mkexpr(t1),
+ mkexpr(t2)),
+ mkU8(63)),
+ mkU8(63))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_3R_11(UInt cins, UChar wd, UChar ws) { /* 3R (0x11) */
+ IRTemp t1, t2, t3;
+ UShort operation;
+ UChar df, wt;
+
+ operation = (cins & 0x03800000) >> 23;
+ df = (cins & 0x00600000) >> 21;
+ wt = (cins & 0x001F0000) >> 16;
+
+ switch (operation) {
+ case 0x00: { /* SUBS_S.df */
+ switch (df) {
+ case 0x00: { /* SUBS_S.B */
+ DIP("SUBS_S.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QSub8Sx16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* SUBS_S.H */
+ DIP("SUBS_S.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QSub16Sx8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* SUBS_S.W */
+ DIP("SUBS_S.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QSub32Sx4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* SUBS_S.D */
+ DIP("SUBS_S.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QSub64Sx2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x01: { /* SUBS_U.df */
+ switch (df) {
+ case 0x00: { /* SUBS_U.B */
+ DIP("SUBS_U.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QSub8Ux16, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* SUBS_U.H */
+ DIP("SUBS_U.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QSub16Ux8, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* SUBS_U.W */
+ DIP("SUBS_U.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QSub32Ux4, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* SUBS_U.D */
+ DIP("SUBS_U.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QSub64Ux2, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x02: { /* SUBSUS_U.df */
+ switch (df) {
+ case 0x00: { /* SUBSUS_U.B */
+ DIP("SUBSUS_U.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, binop(Iop_Sub8x16, getWReg(ws), getWReg(wt)));
+ assign(t2, binop(Iop_SarN8x16, getWReg(wt), mkU8(7)));
+ assign(t3, binop(Iop_OrV128,
+ binop(Iop_CmpGT8Ux16,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_CmpEQ8x16,
+ getWReg(ws),
+ getWReg(wt))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t3), mkexpr(t2)),
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ binop(Iop_XorV128,
+ mkexpr(t3),
+ mkexpr(t2)))));
+ break;
+ }
+
+ case 0x01: { /* SUBSUS_U.H */
+ DIP("SUBSUS_U.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, binop(Iop_Sub16x8, getWReg(ws), getWReg(wt)));
+ assign(t2, binop(Iop_SarN16x8, getWReg(wt), mkU8(15)));
+ assign(t3,
+ binop(Iop_OrV128,
+ binop(Iop_CmpGT16Ux8,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_CmpEQ16x8,
+ getWReg(ws),
+ getWReg(wt))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t3), mkexpr(t2)),
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ binop(Iop_XorV128,
+ mkexpr(t3),
+ mkexpr(t2)))));
+ break;
+ }
+
+ case 0x02: { /* SUBSUS_U.W */
+ DIP("SUBSUS_U.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, binop(Iop_Sub32x4, getWReg(ws), getWReg(wt)));
+ assign(t2, binop(Iop_SarN32x4, getWReg(wt), mkU8(31)));
+ assign(t3,
+ binop(Iop_OrV128,
+ binop(Iop_CmpGT32Ux4,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_CmpEQ32x4,
+ getWReg(ws),
+ getWReg(wt))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t3), mkexpr(t2)),
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ binop(Iop_XorV128,
+ mkexpr(t3),
+ mkexpr(t2)))));
+ break;
+ }
+
+ case 0x03: { /* SUBSUS_U.D */
+ DIP("SUBSUS_U.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, binop(Iop_Sub64x2, getWReg(ws), getWReg(wt)));
+ assign(t2, binop(Iop_SarN64x2, getWReg(wt), mkU8(63)));
+ assign(t3,
+ binop(Iop_OrV128,
+ binop(Iop_CmpGT64Ux2,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_CmpEQ64x2,
+ getWReg(ws),
+ getWReg(wt))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t3), mkexpr(t2)),
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ binop(Iop_XorV128,
+ mkexpr(t3),
+ mkexpr(t2)))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x03: { /* SUBSUU_S.df */
+ switch (df) {
+ case 0x00: { /* SUBSUU_S.B */
+ DIP("SUBSUU_S.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, binop(Iop_Sub8x16, getWReg(ws), getWReg(wt)));
+ assign(t2,
+ binop(Iop_SarN8x16,
+ binop (Iop_AndV128,
+ binop(Iop_XorV128,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_XorV128,
+ mkexpr(t1),
+ getWReg(wt))),
+ mkU8(7)));
+ assign(t3,
+ binop(Iop_AndV128,
+ binop(Iop_SarN8x16,
+ getWReg(ws), mkU8(7)),
+ mkexpr(t2)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ unop(Iop_NotV128,
+ mkexpr(t2))),
+ binop(Iop_XorV128,
+ binop(Iop_ShlN8x16,
+ mkexpr(t2), mkU8(7)),
+ mkexpr(t3))));
+ break;
+ }
+
+ case 0x01: { /* SUBSUU_S.H */
+ DIP("SUBSUU_S.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, binop(Iop_Sub16x8, getWReg(ws), getWReg(wt)));
+ assign(t2,
+ binop(Iop_SarN16x8,
+ binop (Iop_AndV128,
+ binop(Iop_XorV128,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_XorV128,
+ mkexpr(t1),
+ getWReg(wt))),
+ mkU8(15)));
+ assign(t3,
+ binop(Iop_AndV128,
+ binop(Iop_SarN16x8,
+ getWReg(ws),
+ mkU8(15)),
+ mkexpr(t2)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ unop(Iop_NotV128,
+ mkexpr(t2))),
+ binop(Iop_XorV128,
+ binop(Iop_ShlN16x8,
+ mkexpr(t2), mkU8(15)),
+ mkexpr(t3))));
+ break;
+ }
+
+ case 0x02: { /* SUBSUU_S.W */
+ DIP("SUBSUU_S.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, binop(Iop_Sub32x4, getWReg(ws), getWReg(wt)));
+ assign(t2,
+ binop(Iop_SarN32x4,
+ binop (Iop_AndV128,
+ binop(Iop_XorV128,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_XorV128,
+ mkexpr(t1),
+ getWReg(wt))),
+ mkU8(31)));
+ assign(t3,
+ binop(Iop_AndV128,
+ binop(Iop_SarN32x4,
+ getWReg(ws),
+ mkU8(31)),
+ mkexpr(t2)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ unop(Iop_NotV128,
+ mkexpr(t2))),
+ binop(Iop_XorV128,
+ binop(Iop_ShlN32x4,
+ mkexpr(t2),
+ mkU8(31)),
+ mkexpr(t3))));
+ break;
+ }
+
+ case 0x03: { /* SUBSUU_S.D */
+ DIP("SUBSUU_S.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, binop(Iop_Sub64x2, getWReg(ws), getWReg(wt)));
+ assign(t2,
+ binop(Iop_SarN64x2,
+ binop (Iop_AndV128,
+ binop(Iop_XorV128,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_XorV128,
+ mkexpr(t1),
+ getWReg(wt))),
+ mkU8(63)));
+ assign(t3,
+ binop(Iop_AndV128,
+ binop(Iop_SarN64x2,
+ getWReg(ws),
+ mkU8(63)),
+ mkexpr(t2)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ unop(Iop_NotV128,
+ mkexpr(t2))),
+ binop(Iop_XorV128,
+ binop(Iop_ShlN64x2,
+ mkexpr(t2), mkU8(63)),
+ mkexpr(t3))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x04: { /* ASUB_S.df */
+ switch (df) {
+ case 0x00: { /* ASUB_S.B */
+ DIP("ASUB_S.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, binop(Iop_SarN8x16, getWReg(ws), mkU8(7)));
+ assign(t2, binop(Iop_SarN8x16, getWReg(wt), mkU8(7)));
+ assign(t3, binop(Iop_Sub8x16, getWReg(ws), getWReg(wt)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t1)),
+ mkexpr(t2)),
+ mkexpr(t3)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ binop(Iop_XorV128,
+ mkexpr(t1),
+ mkexpr(t2))),
+ unop(Iop_Abs8x16,
+ mkexpr(t3)))),
+ binop(Iop_AndV128,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ unop(Iop_NotV128,
+ mkexpr(t2))),
+ binop(Iop_Sub8x16,
+ getWReg(wt),
+ getWReg(ws)))));
+ break;
+ }
+
+ case 0x01: { /* ASUB_S.H */
+ DIP("ASUB_S.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, binop(Iop_SarN16x8, getWReg(ws), mkU8(15)));
+ assign(t2, binop(Iop_SarN16x8, getWReg(wt), mkU8(15)));
+ assign(t3, binop(Iop_Sub16x8, getWReg(ws), getWReg(wt)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t1)),
+ mkexpr(t2)),
+ mkexpr(t3)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ binop(Iop_XorV128,
+ mkexpr(t1),
+ mkexpr(t2))),
+ unop(Iop_Abs16x8,
+ mkexpr(t3)))),
+ binop(Iop_AndV128,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ unop(Iop_NotV128,
+ mkexpr(t2))),
+ binop(Iop_Sub16x8,
+ getWReg(wt),
+ getWReg(ws)))));
+ break;
+ }
+
+ case 0x02: { /* ASUB_S.W */
+ DIP("ASUB_S.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, binop(Iop_SarN32x4, getWReg(ws), mkU8(31)));
+ assign(t2, binop(Iop_SarN32x4, getWReg(wt), mkU8(31)));
+ assign(t3, binop(Iop_Sub32x4, getWReg(ws), getWReg(wt)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t1)),
+ mkexpr(t2)),
+ mkexpr(t3)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ binop(Iop_XorV128,
+ mkexpr(t1),
+ mkexpr(t2))),
+ unop(Iop_Abs32x4,
+ mkexpr(t3)))),
+ binop(Iop_AndV128,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ unop(Iop_NotV128,
+ mkexpr(t2))),
+ binop(Iop_Sub32x4,
+ getWReg(wt),
+ getWReg(ws)))));
+ break;
+ }
+
+ case 0x03: { /* ASUB_S.D */
+ DIP("ASUB_S.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, binop(Iop_SarN64x2, getWReg(ws), mkU8(63)));
+ assign(t2, binop(Iop_SarN64x2, getWReg(wt), mkU8(63)));
+ assign(t3, binop(Iop_Sub64x2, getWReg(ws), getWReg(wt)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t1)),
+ mkexpr(t2)),
+ mkexpr(t3)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ binop(Iop_XorV128,
+ mkexpr(t1),
+ mkexpr(t2))),
+ unop(Iop_Abs64x2,
+ mkexpr(t3)))),
+ binop(Iop_AndV128,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ unop(Iop_NotV128,
+ mkexpr(t2))),
+ binop(Iop_Sub64x2,
+ getWReg(wt),
+ getWReg(ws)))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x05: { /* ASUB_U.df */
+ switch (df) {
+ case 0x00: { /* ASUB_U.B */
+ DIP("ASUB_U.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_SarN8x16,
+ binop(Iop_XorV128,
+ mkexpr(t1), mkexpr(t2)),
+ mkU8(7)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t3)),
+ unop(Iop_Abs8x16,
+ binop(Iop_Sub8x16,
+ mkexpr(t1),
+ mkexpr(t2)))),
+ binop(Iop_AndV128, mkexpr(t3),
+ binop(Iop_Sub8x16,
+ binop(Iop_Max8Ux16,
+ mkexpr(t1),
+ mkexpr(t2)),
+ binop(Iop_Min8Ux16,
+ mkexpr(t1),
+ mkexpr(t2))))));
+ break;
+ }
+
+ case 0x01: { /* ASUB_U.H */
+ DIP("ASUB_U.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_SarN16x8,
+ binop(Iop_XorV128,
+ mkexpr(t1), mkexpr(t2)),
+ mkU8(15)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t3)),
+ unop(Iop_Abs16x8,
+ binop(Iop_Sub16x8,
+ mkexpr(t1),
+ mkexpr(t2)))),
+ binop(Iop_AndV128,
+ mkexpr(t3),
+ binop(Iop_Sub16x8,
+ binop(Iop_Max16Ux8,
+ mkexpr(t1),
+ mkexpr(t2)),
+ binop(Iop_Min16Ux8,
+ mkexpr(t1),
+ mkexpr(t2))))));
+ break;
+ }
+
+ case 0x02: { /* ASUB_U.W */
+ DIP("ASUB_U.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_SarN32x4,
+ binop(Iop_XorV128,
+ mkexpr(t1), mkexpr(t2)),
+ mkU8(31)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t3)),
+ unop(Iop_Abs32x4,
+ binop(Iop_Sub32x4,
+ mkexpr(t1),
+ mkexpr(t2)))),
+ binop(Iop_AndV128,
+ mkexpr(t3),
+ binop(Iop_Sub32x4,
+ binop(Iop_Max32Ux4,
+ mkexpr(t1),
+ mkexpr(t2)),
+ binop(Iop_Min32Ux4,
+ mkexpr(t1),
+ mkexpr(t2))))));
+ break;
+ }
+
+ case 0x03: { /* ASUB_U.D */
+ DIP("ASUB_U.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_SarN64x2,
+ binop(Iop_XorV128,
+ mkexpr(t1), mkexpr(t2)),
+ mkU8(63)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t3)),
+ unop(Iop_Abs64x2,
+ binop(Iop_Sub64x2,
+ mkexpr(t1),
+ mkexpr(t2)))),
+ binop(Iop_AndV128,
+ mkexpr(t3),
+ binop(Iop_Sub64x2,
+ binop(Iop_Max64Ux2,
+ mkexpr(t1),
+ mkexpr(t2)),
+ binop(Iop_Min64Ux2,
+ mkexpr(t1),
+ mkexpr(t2))))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_3R_12(UInt cins, UChar wd, UChar ws) { /* 3R (0x12) */
+ IRTemp t1, t2, t3, t4, t5, t6;
+ UShort operation;
+ UChar df, wt;
+
+ operation = (cins & 0x03800000) >> 23;
+ df = (cins & 0x00600000) >> 21;
+ wt = (cins & 0x001F0000) >> 16;
+
+ switch (operation) {
+ case 0x00: { /* MULV.df */
+ switch (df) {
+ case 0x00: { /* MULV.B */
+ DIP("MULV.B w%d, w%d, w%d", wd, ws, wt);
+ putWReg(wd, binop(Iop_Mul8x16, getWReg(ws), getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* MULV.H */
+ DIP("MULV.H w%d, w%d, w%d", wd, ws, wt);
+ putWReg(wd, binop(Iop_Mul16x8, getWReg(ws), getWReg(wt)));
+ break;
+ }
+
+ case 0x02: { /* MULV.W */
+ DIP("MULV.W w%d, w%d, w%d", wd, ws, wt);
+ putWReg(wd, binop(Iop_Mul32x4, getWReg(ws), getWReg(wt)));
+ break;
+ }
+
+ case 0x03: { /* MULV.D */
+ DIP("MULV.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_Mul64,
+ unop(Iop_V128HIto64,
+ mkexpr(t1)),
+ unop(Iop_V128HIto64,
+ mkexpr(t2))),
+ binop(Iop_Mul64,
+ unop(Iop_V128to64,
+ mkexpr(t1)),
+ unop(Iop_V128to64,
+ mkexpr(t2)))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x01: { /* MADDV.df */
+ switch (df) {
+ case 0x00: { /* MADDV.B */
+ DIP("MADDV.B w%d, w%d, w%d", wd, ws, wt);
+ putWReg(wd,
+ binop(Iop_Add8x16,
+ getWReg(wd),
+ binop(Iop_Mul8x16,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x01: { /* MADDV.H */
+ DIP("MADDV.H w%d, w%d, w%d", wd, ws, wt);
+ putWReg(wd,
+ binop(Iop_Add16x8,
+ getWReg(wd),
+ binop(Iop_Mul16x8,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x02: { /* MADDV.W */
+ DIP("MADDV.W w%d, w%d, w%d", wd, ws, wt);
+ putWReg(wd,
+ binop(Iop_Add32x4,
+ getWReg(wd),
+ binop(Iop_Mul32x4,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x03: { /* MADDV.D */
+ DIP("MADDV.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ putWReg(wd,
+ binop(Iop_Add64x2,
+ getWReg(wd),
+ binop(Iop_64HLtoV128,
+ binop(Iop_Mul64,
+ unop(Iop_V128HIto64,
+ mkexpr(t1)),
+ unop(Iop_V128HIto64,
+ mkexpr(t2))),
+ binop(Iop_Mul64,
+ unop(Iop_V128to64,
+ mkexpr(t1)),
+ unop(Iop_V128to64,
+ mkexpr(t2))))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x02: { /* MSUBV.df */
+ switch (df) {
+ case 0x00: { /* MSUBV.B */
+ DIP("MSUBV.B w%d, w%d, w%d", wd, ws, wt);
+ putWReg(wd,
+ binop(Iop_Sub8x16,
+ getWReg(wd),
+ binop(Iop_Mul8x16,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x01: { /* MSUBV.H */
+ DIP("MSUBV.H w%d, w%d, w%d", wd, ws, wt);
+ putWReg(wd,
+ binop(Iop_Sub16x8,
+ getWReg(wd),
+ binop(Iop_Mul16x8,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x02: { /* MSUBV.W */
+ DIP("MSUBV.W w%d, w%d, w%d", wd, ws, wt);
+ putWReg(wd,
+ binop(Iop_Sub32x4,
+ getWReg(wd),
+ binop(Iop_Mul32x4,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x03: { /* MSUBV.D */
+ DIP("MSUBV.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ putWReg(wd,
+ binop(Iop_Sub64x2,
+ getWReg(wd),
+ binop(Iop_64HLtoV128,
+ binop(Iop_Mul64,
+ unop(Iop_V128HIto64,
+ mkexpr(t1)),
+ unop(Iop_V128HIto64,
+ mkexpr(t2))),
+ binop(Iop_Mul64,
+ unop(Iop_V128to64,
+ mkexpr(t1)),
+ unop(Iop_V128to64,
+ mkexpr(t2))))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x04: { /* DIV_S.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+
+ switch (df) {
+ case 0x00: { /* DIV_S.B */
+ DIP("DIV_S.B w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[16];
+ Int i;
+
+ for (i = 0; i < 16; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ mkU32(0xFF),
+ binop(Iop_DivS32,
+ unop(Iop_8Sto32,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(i))),
+ unop(Iop_8Sto32,
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ mkU8(i))))),
+ mkU8((i & 3) << 3)));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(tmp[15]),
+ binop(Iop_Or32,
+ mkexpr(tmp[14]),
+ binop(Iop_Or32,
+ mkexpr(tmp[13]),
+ mkexpr(tmp[12])))),
+ binop(Iop_Or32,
+ mkexpr(tmp[11]),
+ binop(Iop_Or32,
+ mkexpr(tmp[10]),
+ binop(Iop_Or32,
+ mkexpr(tmp[9]),
+ mkexpr(tmp[8]))))),
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(tmp[7]),
+ binop(Iop_Or32,
+ mkexpr(tmp[6]),
+ binop(Iop_Or32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4])))),
+ binop(Iop_Or32,
+ mkexpr(tmp[3]),
+ binop(Iop_Or32,
+ mkexpr(tmp[2]),
+ binop(Iop_Or32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))))))
+ );
+ break;
+ }
+
+ case 0x01: { /* DIV_S.H */
+ DIP("DIV_S.H w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[8];
+ Int i;
+
+ for (i = 0; i < 8; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ mkU32(0xFFFF),
+ binop(Iop_DivS32,
+ unop(Iop_16Sto32,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(i))),
+ unop(Iop_16Sto32,
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ mkU8(i))))),
+ mkU8((i & 1) << 4)));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_Or32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_Or32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0])))));
+ break;
+ }
+
+ case 0x02: { /* DIV_S.W */
+ DIP("DIV_S.W w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[4];
+ Int i;
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_DivS32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1), mkU8(i)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2), mkU8(i))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128, \
+ binop(Iop_32HLto64,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_32HLto64,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))));
+ break;
+ }
+
+ case 0x03: { /* DIV_S.D */
+ DIP("DIV_S.D w%d, w%d, w%d", wd, ws, wt);
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_DivS64,
+ unop(Iop_V128HIto64,
+ mkexpr(t1)),
+ unop(Iop_V128HIto64,
+ mkexpr(t2))),
+ binop(Iop_DivS64,
+ unop(Iop_V128to64,
+ mkexpr(t1)),
+ unop(Iop_V128to64,
+ mkexpr(t2)))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x05: { /* DIV_U.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+
+ switch (df) {
+ case 0x00: { /* DIV_U.B */
+ DIP("DIV_U.B w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[16];
+ Int i;
+
+ for (i = 0; i < 16; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ mkU32(0xFF),
+ binop(Iop_DivU32,
+ unop(Iop_8Uto32,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(i))),
+ unop(Iop_8Uto32,
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ mkU8(i))))),
+ mkU8((i & 3) << 3)));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(tmp[15]),
+ binop(Iop_Or32,
+ mkexpr(tmp[14]),
+ binop(Iop_Or32,
+ mkexpr(tmp[13]),
+ mkexpr(tmp[12])))),
+ binop(Iop_Or32,
+ mkexpr(tmp[11]),
+ binop(Iop_Or32,
+ mkexpr(tmp[10]),
+ binop(Iop_Or32,
+ mkexpr(tmp[9]),
+ mkexpr(tmp[8]))))),
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(tmp[7]),
+ binop(Iop_Or32,
+ mkexpr(tmp[6]),
+ binop(Iop_Or32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4])))),
+ binop(Iop_Or32,
+ mkexpr(tmp[3]),
+ binop(Iop_Or32,
+ mkexpr(tmp[2]),
+ binop(Iop_Or32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))))))
+ );
+ break;
+ }
+
+ case 0x01: { /* DIV_U.H */
+ DIP("DIV_U.H w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[8];
+ Int i;
+
+ for (i = 0; i < 8; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ mkU32(0xFFFF),
+ binop(Iop_DivU32,
+ unop(Iop_16Uto32,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(i))),
+ unop(Iop_16Uto32,
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ mkU8(i))))),
+ mkU8((i & 1) << 4)));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_Or32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_Or32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0])))));
+ break;
+ }
+
+ case 0x02: { /* DIV_U.W */
+ DIP("DIV_U.W w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[4];
+ Int i;
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_DivU32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1), mkU8(i)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2), mkU8(i))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_32HLto64,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))));
+ break;
+ }
+
+ case 0x03: { /* DIV_U.D */
+ DIP("DIV_U.D w%d, w%d, w%d", wd, ws, wt);
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_DivU64,
+ unop(Iop_V128HIto64,
+ mkexpr(t1)),
+ unop(Iop_V128HIto64,
+ mkexpr(t2))),
+ binop(Iop_DivU64,
+ unop(Iop_V128to64,
+ mkexpr(t1)),
+ unop(Iop_V128to64,
+ mkexpr(t2)))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x06: { /* MOD_S.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+
+ switch (df) {
+ case 0x00: { /* MOD_S.B */
+ DIP("MOD_S.B w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[16];
+ Int i;
+
+ for (i = 0; i < 16; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ mkU32(0xFF),
+ unop(Iop_64HIto32,
+ binop(Iop_DivModS32to32,
+ unop(Iop_8Sto32,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(i))),
+ unop(Iop_8Sto32,
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ mkU8(i)))))),
+ mkU8((i & 3) << 3)));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(tmp[15]),
+ binop(Iop_Or32,
+ mkexpr(tmp[14]),
+ binop(Iop_Or32,
+ mkexpr(tmp[13]),
+ mkexpr(tmp[12])))),
+ binop(Iop_Or32,
+ mkexpr(tmp[11]),
+ binop(Iop_Or32,
+ mkexpr(tmp[10]),
+ binop(Iop_Or32,
+ mkexpr(tmp[9]),
+ mkexpr(tmp[8]))))),
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(tmp[7]),
+ binop(Iop_Or32,
+ mkexpr(tmp[6]),
+ binop(Iop_Or32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4])))),
+ binop(Iop_Or32,
+ mkexpr(tmp[3]),
+ binop(Iop_Or32,
+ mkexpr(tmp[2]),
+ binop(Iop_Or32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0])))))));
+ break;
+ }
+
+ case 0x01: { /* MOD_S.H */
+ DIP("MOD_S.H w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[8];
+ Int i;
+
+ for (i = 0; i < 8; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ mkU32(0xFFFF),
+ unop(Iop_64HIto32,
+ binop(Iop_DivModS32to32,
+ unop(Iop_16Sto32,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(i))),
+ unop(Iop_16Sto32,
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ mkU8(i)))))),
+ mkU8((i & 1) << 4)));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_Or32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_Or32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0])))));
+ break;
+ }
+
+ case 0x02: { /* MOD_S.W */
+ DIP("MOD_S.W w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[4];
+ Int i;
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ unop(Iop_64HIto32,
+ binop(Iop_DivModS32to32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(i)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2),
+ mkU8(i)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_32HLto64,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))));
+ break;
+ }
+
+ case 0x03: { /* MOD_S.D */
+ DIP("MOD_S.D w%d, w%d, w%d", wd, ws, wt);
+ t3 = newTemp(Ity_I64);
+ t4 = newTemp(Ity_I64);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I64);
+ assign(t3, unop(Iop_V128HIto64, mkexpr(t1)));
+ assign(t4, unop(Iop_V128HIto64, mkexpr(t2)));
+ assign(t5, unop(Iop_V128to64, mkexpr(t1)));
+ assign(t6, unop(Iop_V128to64, mkexpr(t2)));
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_Sub64,
+ mkexpr(t3),
+ binop(Iop_Mul64,
+ mkexpr(t4),
+ binop(Iop_DivS64,
+ mkexpr(t3),
+ mkexpr(t4)))),
+ binop(Iop_Sub64,
+ mkexpr(t5),
+ binop(Iop_Mul64,
+ mkexpr(t6),
+ binop(Iop_DivS64,
+ mkexpr(t5),
+ mkexpr(t6))))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x07: { /* MOD_U.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+
+ switch (df) {
+ case 0x00: { /* MOD_U.B */
+ DIP("MOD_U.B w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[16];
+ Int i;
+
+ for (i = 0; i < 16; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ mkU32(0xFF),
+ unop(Iop_64HIto32,
+ binop(Iop_DivModU32to32,
+ unop(Iop_8Uto32,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(i))),
+ unop(Iop_8Uto32,
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ mkU8(i)))))),
+ mkU8((i & 3) << 3)));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(tmp[15]),
+ binop(Iop_Or32,
+ mkexpr(tmp[14]),
+ binop(Iop_Or32,
+ mkexpr(tmp[13]),
+ mkexpr(tmp[12])))),
+ binop(Iop_Or32,
+ mkexpr(tmp[11]),
+ binop(Iop_Or32,
+ mkexpr(tmp[10]),
+ binop(Iop_Or32,
+ mkexpr(tmp[9]),
+ mkexpr(tmp[8]))))),
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(tmp[7]),
+ binop(Iop_Or32,
+ mkexpr(tmp[6]),
+ binop(Iop_Or32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4])))),
+ binop(Iop_Or32,
+ mkexpr(tmp[3]),
+ binop(Iop_Or32,
+ mkexpr(tmp[2]),
+ binop(Iop_Or32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0])))))));
+ break;
+ }
+
+ case 0x01: { /* MOD_U.H */
+ DIP("MOD_U.H w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[8];
+ Int i;
+
+ for (i = 0; i < 8; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ mkU32(0xFFFF),
+ unop(Iop_64HIto32,
+ binop(Iop_DivModU32to32,
+ unop(Iop_16Uto32,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(i))),
+ unop(Iop_16Uto32,
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ mkU8(i)))))),
+ mkU8((i & 1) << 4)));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_Or32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_Or32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0])))));
+ break;
+ }
+
+ case 0x02: { /* MOD_U.W */
+ DIP("MOD_U.W w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[4];
+ Int i;
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ unop(Iop_64HIto32,
+ binop(Iop_DivModU32to32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(i)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2),
+ mkU8(i)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_32HLto64,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))));
+ break;
+ }
+
+ case 0x03: { /* MOD_U.D */
+ DIP("MOD_U.D w%d, w%d, w%d", wd, ws, wt);
+ t3 = newTemp(Ity_I64);
+ t4 = newTemp(Ity_I64);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I64);
+ assign(t3, unop(Iop_V128HIto64, mkexpr(t1)));
+ assign(t4, unop(Iop_V128HIto64, mkexpr(t2)));
+ assign(t5, unop(Iop_V128to64, mkexpr(t1)));
+ assign(t6, unop(Iop_V128to64, mkexpr(t2)));
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_Sub64,
+ mkexpr(t3),
+ binop(Iop_Mul64,
+ mkexpr(t4),
+ binop(Iop_DivU64,
+ mkexpr(t3),
+ mkexpr(t4)))),
+ binop(Iop_Sub64,
+ mkexpr(t5),
+ binop(Iop_Mul64,
+ mkexpr(t6),
+ binop(Iop_DivU64,
+ mkexpr(t5),
+ mkexpr(t6))))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_3R_13(UInt cins, UChar wd, UChar ws) { /* 3R (0x13) */
+ IRTemp t1, t2;
+ UShort operation;
+ UChar df, wt;
+
+ operation = (cins & 0x03800000) >> 23;
+ df = (cins & 0x00600000) >> 21;
+ wt = (cins & 0x001F0000) >> 16;
+
+ switch (operation) {
+ case 0x00: { /* DOTP_S.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+
+ switch (df) {
+ case 0x01: { /* DOTP_S.H */
+ DIP("DOTP_S.H w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[8];
+ Int i;
+
+ for (i = 0; i < 8; i++) {
+ tmp[i] = newTemp(Ity_I16);
+ assign(tmp[i],
+ binop(Iop_Add16,
+ binop(Iop_MullS8,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullS8,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0])))));
+ break;
+ }
+
+ case 0x02: { /* DOTP_S.W */
+ DIP("DOTP_S.W w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[4];
+ Int i;
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_Add32,
+ binop(Iop_MullS16,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullS16,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_32HLto64,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))));
+ break;
+ }
+
+ case 0x03: { /* DOTP_S.D */
+ DIP("DOTP_S.D w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[2];
+ Int i;
+
+ for (i = 0; i < 2; i++) {
+ tmp[i] = newTemp(Ity_I64);
+ assign(tmp[i],
+ binop(Iop_Add64,
+ binop(Iop_MullS32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullS32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkexpr(tmp[1]), mkexpr(tmp[0])));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x01: { /* DOTP_U.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+
+ switch (df) {
+ case 0x01: { /* DOTP_U.H */
+ DIP("DOTP_U.H w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[8];
+ Int i;
+
+ for (i = 0; i < 8; i++) {
+ tmp[i] = newTemp(Ity_I16);
+ assign(tmp[i],
+ binop(Iop_Add16,
+ binop(Iop_MullU8,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullU8,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0])))));
+ break;
+ }
+
+ case 0x02: { /* DOTP_U.W */
+ DIP("DOTP_U.W w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[4];
+ Int i;
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_Add32,
+ binop(Iop_MullU16,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullU16,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_32HLto64,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))));
+ break;
+ }
+
+ case 0x03: { /* DOTP_U.D */
+ DIP("DOTP_U.D w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[2];
+ Int i;
+
+ for (i = 0; i < 2; i++) {
+ tmp[i] = newTemp(Ity_I64);
+ assign(tmp[i],
+ binop(Iop_Add64,
+ binop(Iop_MullU32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullU32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkexpr(tmp[1]), mkexpr(tmp[0])));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x02: { /* DPADD_S.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+
+ switch (df) {
+ case 0x01: { /* DPADD_S.H */
+ DIP("DPADD_S.H w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[8];
+ Int i;
+
+ for (i = 0; i < 8; i++) {
+ tmp[i] = newTemp(Ity_I16);
+ assign(tmp[i],
+ binop(Iop_Add16,
+ binop(Iop_MullS8,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullS8,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_Add16x8,
+ getWReg(wd),
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))))));
+ break;
+ }
+
+ case 0x02: { /* DPADD_S.W */
+ DIP("DPADD_S.W w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[4];
+ Int i;
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_Add32,
+ binop(Iop_MullS16,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullS16,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_Add32x4,
+ getWReg(wd),
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_32HLto64,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0])))));
+ break;
+ }
+
+ case 0x03: { /* DPADD_S.D */
+ DIP("DPADD_S.D w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[2];
+ Int i;
+
+ for (i = 0; i < 2; i++) {
+ tmp[i] = newTemp(Ity_I64);
+ assign(tmp[i],
+ binop(Iop_Add64,
+ binop(Iop_MullS32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullS32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_Add64x2,
+ getWReg(wd),
+ binop(Iop_64HLtoV128,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x03: { /* DPADD_U.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+
+ switch (df) {
+ case 0x01: { /* DPADD_U.H */
+ DIP("DPADD_U.H w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[8];
+ Int i;
+
+ for (i = 0; i < 8; i++) {
+ tmp[i] = newTemp(Ity_I16);
+ assign(tmp[i],
+ binop(Iop_Add16,
+ binop(Iop_MullU8,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullU8,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_Add16x8,
+ getWReg(wd),
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))))));
+ break;
+ }
+
+ case 0x02: { /* DPADD_U.W */
+ DIP("DPADD_U.W w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[4];
+ Int i;
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_Add32,
+ binop(Iop_MullU16,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullU16,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_Add32x4,
+ getWReg(wd),
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_32HLto64,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0])))));
+ break;
+ }
+
+ case 0x03: { /* DPADD_U.D */
+ DIP("DPADD_U.D w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[2];
+ Int i;
+
+ for (i = 0; i < 2; i++) {
+ tmp[i] = newTemp(Ity_I64);
+ assign(tmp[i],
+ binop(Iop_Add64,
+ binop(Iop_MullU32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullU32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_Add64x2,
+ getWReg(wd),
+ binop(Iop_64HLtoV128,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x04: { /* DPSUB_S.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+
+ switch (df) {
+ case 0x01: { /* DPSUB_S.H */
+ DIP("DPSUB_S.H w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[8];
+ Int i;
+
+ for (i = 0; i < 8; i++) {
+ tmp[i] = newTemp(Ity_I16);
+ assign(tmp[i],
+ binop(Iop_Add16,
+ binop(Iop_MullS8,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullS8,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_Sub16x8,
+ getWReg(wd),
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))))));
+ break;
+ }
+
+ case 0x02: { /* DPSUB_S.W */
+ DIP("DPSUB_S.W w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[4];
+ Int i;
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_Add32,
+ binop(Iop_MullS16,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullS16,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_Sub32x4,
+ getWReg(wd),
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_32HLto64,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0])))));
+ break;
+ }
+
+ case 0x03: { /* DPSUB_S.D */
+ DIP("DPSUB_S.D w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[2];
+ Int i;
+
+ for (i = 0; i < 2; i++) {
+ tmp[i] = newTemp(Ity_I64);
+ assign(tmp[i],
+ binop(Iop_Add64,
+ binop(Iop_MullS32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullS32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_Sub64x2,
+ getWReg(wd),
+ binop(Iop_64HLtoV128,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x05: { /* DPSUB_U.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+
+ switch (df) {
+ case 0x01: { /* DPSUB_U.H */
+ DIP("DPSUB_U.H w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[8];
+ Int i;
+
+ for (i = 0; i < 8; i++) {
+ tmp[i] = newTemp(Ity_I16);
+ assign(tmp[i],
+ binop(Iop_Add16,
+ binop(Iop_MullU8,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullU8,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_Sub16x8,
+ getWReg(wd),
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))))));
+ break;
+ }
+
+ case 0x02: { /* DPSUB_U.W */
+ DIP("DPSUB_U.W w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[4];
+ Int i;
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_Add32,
+ binop(Iop_MullU16,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullU16,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_Sub32x4,
+ getWReg(wd),
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_32HLto64,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0])))));
+ break;
+ }
+
+ case 0x03: { /* DPSUB_U.D */
+ DIP("DPSUB_U.D w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[2];
+ Int i;
+
+ for (i = 0; i < 2; i++) {
+ tmp[i] = newTemp(Ity_I64);
+ assign(tmp[i],
+ binop(Iop_Add64,
+ binop(Iop_MullU32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(2 * i)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2),
+ mkU8(2 * i))),
+ binop(Iop_MullU32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(2 * i + 1)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2),
+ mkU8(2 * i + 1)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_Sub64x2,
+ getWReg(wd),
+ binop(Iop_64HLtoV128,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_3R_14(UInt cins, UChar wd, UChar ws) { /* 3R (0x14) */
+ IRTemp t1, t2, t3, t4;
+ IRType ty;
+ UShort operation;
+ UChar df, wt;
+
+ operation = (cins & 0x03800000) >> 23;
+ df = (cins & 0x00600000) >> 21;
+ wt = (cins & 0x001F0000) >> 16;
+ ty = mode64 ? Ity_I64 : Ity_I32;
+
+ switch (operation) {
+ case 0x00: { /* SLD.df */
+ switch (df) {
+ case 0x00: {
+ DIP("SLD.B w%d, w%d[%d]", wd, ws, wt);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ mkNarrowTo32(ty,
+ getIReg(wt)),
+ mkU32(15)),
+ mkU8(3)));
+ assign(t2,
+ binop(Iop_ShrV128,
+ getWReg(ws),
+ unop(Iop_32to8, mkexpr(t1))));
+ assign(t3,
+ binop(Iop_ShlV128,
+ getWReg(wd),
+ unop(Iop_32to8,
+ binop(Iop_Sub32,
+ mkU32(128),
+ mkexpr(t1)))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t2), mkexpr(t3)));
+ break;
+ }
+
+ case 0x01: {/* SLD.H */
+ DIP("SLD.H w%d, w%d[%d]", wd, ws, wt);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ mkNarrowTo32(ty,
+ getIReg(wt)),
+ mkU32(7)),
+ mkU8(3)));
+ assign(t2,
+ binop(Iop_32HLto64, mkU32(0), mkexpr(t1)));
+ assign(t3,
+ binop(Iop_Shr64x2,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkexpr(t2), mkexpr(t2))));
+ assign(t4,
+ binop(Iop_Shl64x2,
+ getWReg(wd),
+ binop(Iop_Sub64x2,
+ binop(Iop_64HLtoV128,
+ mkU64(0x40ul),
+ mkU64(0x40ul)),
+ binop(Iop_64HLtoV128,
+ mkexpr(t2),
+ mkexpr(t2)))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t3),
+ IRExpr_ITE(
+ binop(Iop_CmpNE32,
+ mkexpr(t1), mkU32(0)),
+ mkexpr(t4),
+ binop(Iop_64HLtoV128,
+ mkU64(0), mkU64(0)))));
+ break;
+ }
+
+ case 0x02: {/* SLD.W */
+ DIP("SLD.W w%d, w%d[%d]", wd, ws, wt);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ mkNarrowTo32(ty,
+ getIReg(wt)),
+ mkU32(3)),
+ mkU8(3)));
+ assign(t2,
+ binop(Iop_32HLto64,
+ mkexpr(t1), mkexpr(t1)));
+ assign(t3,
+ binop(Iop_Shr32x4,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkexpr(t2), mkexpr(t2))));
+ assign(t4,
+ binop(Iop_Shl32x4,
+ getWReg(wd),
+ binop(Iop_Sub32x4,
+ binop(Iop_64HLtoV128,
+ mkU64(0x2000000020ul),
+ mkU64(0x2000000020ul)),
+ binop(Iop_64HLtoV128,
+ mkexpr(t2),
+ mkexpr(t2)))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t3),
+ IRExpr_ITE(
+ binop(Iop_CmpNE32,
+ mkexpr(t1), mkU32(0)),
+ mkexpr(t4),
+ binop(Iop_64HLtoV128,
+ mkU64(0), mkU64(0)))));
+ break;
+ }
+
+ case 0x03: { /* SLD.D */
+ DIP("SLD.D w%d, w%d[%d]", wd, ws, wt);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ mkNarrowTo32(ty,
+ getIReg(wt)),
+ mkU32(1)),
+ mkU8(3)));
+ assign(t2,
+ binop(Iop_32HLto64,
+ binop(Iop_Or32,
+ mkexpr(t1),
+ binop(Iop_Shl32,
+ mkexpr(t1), mkU8(16))),
+ binop(Iop_Or32,
+ mkexpr(t1),
+ binop(Iop_Shl32,
+ mkexpr(t1), mkU8(16)))));
+ assign(t3,
+ binop(Iop_Shr16x8,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkexpr(t2), mkexpr(t2))));
+ assign(t4,
+ binop(Iop_Shl16x8,
+ getWReg(wd),
+ binop(Iop_Sub16x8,
+ binop(Iop_64HLtoV128,
+ mkU64(0x10001000100010ul),
+ mkU64(0x10001000100010ul)),
+ binop(Iop_64HLtoV128,
+ mkexpr(t2),
+ mkexpr(t2)))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t3),
+ IRExpr_ITE(
+ binop(Iop_CmpNE32,
+ mkexpr(t1), mkU32(0)),
+ mkexpr(t4),
+ binop(Iop_64HLtoV128,
+ mkU64(0), mkU64(0)))));
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x01: { /* SPLAT.df */
+ switch (df) {
+ Int i;
+
+ case 0x00: { /* SPLAT.B */
+ DIP("SPLAT.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_I32);
+ assign(t1, getWReg(ws));
+ assign(t2,
+ mkNarrowTo32(ty, getIReg(wt)));
+ IRTemp tmp[16];
+
+ for (i = 0; i < 16; i++) {
+ tmp[i] = newTemp(Ity_I8);
+ assign(tmp[i],
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ unop(Iop_32to8, mkexpr(t2))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(tmp[15]),
+ mkexpr(tmp[14])),
+ binop(Iop_8HLto16,
+ mkexpr(tmp[13]),
+ mkexpr(tmp[12]))),
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(tmp[11]),
+ mkexpr(tmp[10])),
+ binop(Iop_8HLto16,
+ mkexpr(tmp[9]),
+ mkexpr(tmp[8])))),
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_8HLto16,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_8HLto16,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))))));
+ break;
+ }
+
+ case 0x01: { /* SPLAT.H */
+ DIP("SPLAT.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_I32);
+ assign(t1, getWReg(ws));
+ assign(t2,
+ mkNarrowTo32(ty, getIReg(wt)));
+ IRTemp tmp[8];
+
+ for (i = 0; i < 8; i++) {
+ tmp[i] = newTemp(Ity_I16);
+ assign(tmp[i],
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ unop(Iop_32to8, mkexpr(t2))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0])))));
+ break;
+ }
+
+ case 0x02: { /* SPLAT.W */
+ DIP("SPLAT.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_I32);
+ assign(t1, getWReg(ws));
+ assign(t2,
+ mkNarrowTo32(ty, getIReg(wt)));
+ IRTemp tmp[4];
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ unop(Iop_32to8, mkexpr(t2))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_32HLto64,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))));
+ break;
+ }
+
+ case 0x03: { /* SPLAT.D */
+ DIP("SPLAT.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_I32);
+ assign(t1, getWReg(ws));
+ assign(t2,
+ mkNarrowTo32(ty, getIReg(wt)));
+ IRTemp tmp[2];
+
+ for (i = 0; i < 2; i++) {
+ tmp[i] = newTemp(Ity_I64);
+ assign(tmp[i],
+ binop(Iop_GetElem64x2,
+ mkexpr(t1),
+ unop(Iop_32to8, mkexpr(t2))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkexpr(tmp[1]), mkexpr(tmp[0])));
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x02: { /* PCKEV.df */
+ switch (df) {
+ case 0x00: { /* PCKEV.B */
+ DIP("PCKEV.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_PackEvenLanes8x16,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* PCKEV.H */
+ DIP("PCKEV.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_PackEvenLanes16x8,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* PCKEV.W */
+ DIP("PCKEV.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_PackEvenLanes32x4,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* PCKEV.D */
+ DIP("PCKEV.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveLO64x2,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x03: { /* PCKOD.df */
+ switch (df) {
+ case 0x00: { /* PCKOD.B */
+ DIP("PCKOD.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_PackOddLanes8x16,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* PCKOD.H */
+ DIP("PCKOD.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_PackOddLanes16x8,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* PCKOD.W */
+ DIP("PCKOD.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_PackOddLanes32x4,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* PCKOD.D */
+ DIP("PCKOD.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveHI64x2,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x04: { /* ILVL.df */
+ switch (df) {
+ case 0x00: { /* ILVL.B */
+ DIP("ILVL.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveHI8x16,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* ILVL.H */
+ DIP("ILVL.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveHI16x8,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* ILVL.W */
+ DIP("ILVL.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveHI32x4,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* ILVL.D */
+ DIP("ILVL.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveHI64x2,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x05: { /* ILVR.df */
+ switch (df) {
+ case 0x00: { /* ILVL.B */
+ DIP("ILVL.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveLO8x16,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* ILVL.H */
+ DIP("ILVL.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveLO16x8,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* ILVL.W */
+ DIP("ILVL.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveLO32x4,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* ILVL.D */
+ DIP("ILVL.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveLO64x2,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 0x06: { /* ILVEV.df */
+ switch (df) {
+ case 0x00: { /* ILVEV.B */
+ DIP("ILVEV.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveEvenLanes8x16,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* ILVEV.H */
+ DIP("ILVEV.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveEvenLanes16x8,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* ILVEV.W */
+ DIP("ILVEV.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveEvenLanes32x4,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* ILVEV.D */
+ DIP("ILVEV.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveLO64x2,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x07: { /* ILVOD.df */
+ switch (df) {
+ case 0x00: { /* ILVOD.B */
+ DIP("ILVOD.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveOddLanes8x16,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* ILVOD.H */
+ DIP("ILVOD.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveOddLanes16x8,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* ILVOD.W */
+ DIP("ILVOD.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveOddLanes32x4,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* ILVOD.D */
+ DIP("ILVOD.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_InterleaveHI64x2,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_3R_15(UInt cins, UChar wd, UChar ws) { /* 3R (0x15) */
+ IRTemp t1, t2, t3, t4;
+ UShort operation;
+ UChar df, wt;
+
+ operation = (cins & 0x03800000) >> 23;
+ df = (cins & 0x00600000) >> 21;
+ wt = (cins & 0x001F0000) >> 16;
+
+ switch (operation) {
+ case 0x00: { /* VSHF.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(wd));
+ assign(t2, getWReg(ws));
+ assign(t3, getWReg(wt));
+
+ switch (df) {
+ case 0x00: { /* VSHF.B */
+ DIP("VSHF.B w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[16];
+ Int i;
+
+ for (i = 0; i < 16; i++) {
+ tmp[i] = newTemp(Ity_I8);
+ assign(tmp[i],
+ IRExpr_ITE(
+ binop(Iop_CmpEQ8,
+ binop(Iop_And8,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(i)),
+ mkU8(0xC0)),
+ mkU8(0x0)),
+ IRExpr_ITE(
+ binop(Iop_CmpEQ8,
+ binop(Iop_And8,
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(i)),
+ mkU8(0x10)),
+ mkU8(0x0)),
+ binop(Iop_GetElem8x16,
+ mkexpr(t3),
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(i))),
+ binop(Iop_GetElem8x16,
+ mkexpr(t2),
+ binop(Iop_GetElem8x16,
+ mkexpr(t1),
+ mkU8(i)))),
+ mkU8(0x0)));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(tmp[15]),
+ mkexpr(tmp[14])),
+ binop(Iop_8HLto16,
+ mkexpr(tmp[13]),
+ mkexpr(tmp[12]))),
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(tmp[11]),
+ mkexpr(tmp[10])),
+ binop(Iop_8HLto16,
+ mkexpr(tmp[9]),
+ mkexpr(tmp[8])))),
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_8HLto16,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_8HLto16,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))))));
+ break;
+ }
+
+ case 0x01: { /* VSHF.H */
+ DIP("VSHF.H w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[8];
+ Int i;
+
+ for (i = 0; i < 8; i++) {
+ tmp[i] = newTemp(Ity_I16);
+ assign(tmp[i],
+ IRExpr_ITE(
+ binop(Iop_CmpEQ16,
+ binop(Iop_And16,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(i)),
+ mkU16(0xC0)),
+ mkU16(0x0)),
+ IRExpr_ITE(
+ binop(Iop_CmpEQ16,
+ binop(Iop_And16,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(i)),
+ mkU16(0x08)),
+ mkU16(0x0)),
+ binop(Iop_GetElem16x8,
+ mkexpr(t3),
+ unop(Iop_16to8,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(i)))),
+ binop(Iop_GetElem16x8,
+ mkexpr(t2),
+ unop(Iop_16to8,
+ binop(Iop_GetElem16x8,
+ mkexpr(t1),
+ mkU8(i))))),
+ mkU16(0x0)));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0])))));
+ break;
+ }
+
+ case 0x02: { /* VSHF.W */
+ DIP("VSHF.W w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[4];
+ Int i;
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ IRExpr_ITE(
+ binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(i)),
+ mkU32(0xC0)),
+ mkU32(0x0)),
+ IRExpr_ITE(
+ binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(i)),
+ mkU32(0x04)),
+ mkU32(0x0)),
+ binop(Iop_GetElem32x4,
+ mkexpr(t3),
+ unop(Iop_32to8,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(i)))),
+ binop(Iop_GetElem32x4,
+ mkexpr(t2),
+ unop(Iop_32to8,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(i))))),
+ mkU32(0x0)));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_32HLto64,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))));
+ break;
+ }
+
+ case 0x03: { /* VSHF.D */
+ DIP("VSHF.D w%d, w%d, w%d", wd, ws, wt);
+ IRTemp tmp[2];
+ Int i;
+
+ for (i = 0; i < 2; i++) {
+ tmp[i] = newTemp(Ity_I64);
+ assign(tmp[i],
+ IRExpr_ITE(
+ binop(Iop_CmpEQ64,
+ binop(Iop_And64,
+ binop(Iop_GetElem64x2,
+ mkexpr(t1),
+ mkU8(i)),
+ mkU64(0xC0)),
+ mkU64(0x0)),
+ IRExpr_ITE(
+ binop(Iop_CmpEQ64,
+ binop(Iop_And64,
+ binop(Iop_GetElem64x2,
+ mkexpr(t1),
+ mkU8(i)),
+ mkU64(0x02)),
+ mkU64(0x0)),
+ binop(Iop_GetElem64x2,
+ mkexpr(t3),
+ unop(Iop_64to8,
+ binop(Iop_GetElem64x2,
+ mkexpr(t1),
+ mkU8(i)))),
+ binop(Iop_GetElem64x2,
+ mkexpr(t2),
+ unop(Iop_64to8,
+ binop(Iop_GetElem64x2,
+ mkexpr(t1),
+ mkU8(i))))),
+ mkU64(0x0)));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkexpr(tmp[1]), mkexpr(tmp[0])));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x01: { /* SRAR.df */
+ switch (df) {
+ case 0x00: { /* SRAR.B */
+ DIP("SRAR.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_Sar8x16,
+ getWReg(ws),
+ getWReg(wt)));
+ assign(t2,
+ binop(Iop_Sub8x16,
+ binop(Iop_64HLtoV128,
+ mkU64(0x808080808080808ull),
+ mkU64(0x808080808080808ull)),
+ getWReg(wt)));
+ assign(t4,
+ unop(Iop_NotV128,
+ binop(Iop_CmpEQ8x16,
+ binop(Iop_ShlN8x16,
+ getWReg(wt),
+ mkU8(5)),
+ binop(Iop_64HLtoV128,
+ mkU64(0), mkU64(0)))));
+ assign(t3,
+ binop(Iop_ShrN8x16,
+ binop(Iop_AndV128,
+ binop(Iop_Shl8x16,
+ getWReg(ws),
+ mkexpr(t2)),
+ mkexpr(t4)),
+ mkU8(7)));
+ putWReg(wd,
+ binop(Iop_Add8x16,
+ mkexpr(t1), mkexpr(t3)));
+ break;
+ }
+
+ case 0x01: { /* SRAR.H */
+ DIP("SRAR.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_Sar16x8,
+ getWReg(ws),
+ getWReg(wt)));
+ assign(t2,
+ binop(Iop_Sub16x8,
+ binop(Iop_64HLtoV128,
+ mkU64(0x10001000100010ul),
+ mkU64(0x10001000100010ul)),
+ getWReg(wt)));
+ assign(t4,
+ unop(Iop_NotV128,
+ binop(Iop_CmpEQ16x8,
+ binop(Iop_ShlN16x8,
+ getWReg(wt),
+ mkU8(12)),
+ binop(Iop_64HLtoV128,
+ mkU64(0), mkU64(0)))));
+ assign(t3,
+ binop(Iop_ShrN16x8,
+ binop(Iop_AndV128,
+ binop(Iop_Shl16x8,
+ getWReg(ws),
+ mkexpr(t2)),
+ mkexpr(t4)),
+ mkU8(15)));
+ putWReg(wd,
+ binop(Iop_Add16x8,
+ mkexpr(t1), mkexpr(t3)));
+ break;
+ }
+
+ case 0x02: { /* SRAR.W */
+ DIP("SRAR.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128); // shifted
+ t2 = newTemp(Ity_V128); // 32 - wt
+ t3 = newTemp(Ity_V128); // rv
+ t4 = newTemp(Ity_V128); // wt % 32 == 0
+ assign(t1,
+ binop(Iop_Sar32x4,
+ getWReg(ws),
+ getWReg(wt)));
+ assign(t2,
+ binop(Iop_Sub32x4,
+ binop(Iop_64HLtoV128,
+ mkU64(0x2000000020ul),
+ mkU64(0x2000000020ul)),
+ getWReg(wt)));
+ assign(t4,
+ unop(Iop_NotV128,
+ binop(Iop_CmpEQ32x4,
+ binop(Iop_ShlN32x4,
+ getWReg(wt),
+ mkU8(27)),
+ binop(Iop_64HLtoV128,
+ mkU64(0), mkU64(0)))));
+ assign(t3,
+ binop(Iop_ShrN32x4,
+ binop(Iop_AndV128,
+ binop(Iop_Shl32x4,
+ getWReg(ws),
+ mkexpr(t2)),
+ mkexpr(t4)),
+ mkU8(31)));
+ putWReg(wd,
+ binop(Iop_Add32x4,
+ mkexpr(t1), mkexpr(t3)));
+ break;
+ }
+
+ case 0x03: { /* SRAR.D */
+ DIP("SRAR.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_Sar64x2,
+ getWReg(ws),
+ getWReg(wt)));
+ assign(t2,
+ binop(Iop_Sub64x2,
+ binop(Iop_64HLtoV128,
+ mkU64(64ul), mkU64(64ul)),
+ getWReg(wt)));
+ assign(t4,
+ unop(Iop_NotV128,
+ binop(Iop_CmpEQ64x2,
+ binop(Iop_ShlN64x2,
+ getWReg(wt),
+ mkU8(58)),
+ binop(Iop_64HLtoV128,
+ mkU64(0), mkU64(0)))));
+ assign(t3,
+ binop(Iop_ShrN64x2,
+ binop(Iop_AndV128,
+ binop(Iop_Shl64x2,
+ getWReg(ws),
+ mkexpr(t2)),
+ mkexpr(t4)),
+ mkU8(63)));
+ putWReg(wd,
+ binop(Iop_Add64x2,
+ mkexpr(t1), mkexpr(t3)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x02: { /* SRLR.df */
+ switch (df) {
+ case 0x00: { /* SRLR.B */
+ DIP("SRLR.B w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_Shr8x16,
+ getWReg(ws),
+ getWReg(wt)));
+ assign(t2,
+ binop(Iop_Sub8x16,
+ binop(Iop_64HLtoV128,
+ mkU64(0x808080808080808ull),
+ mkU64(0x808080808080808ull)),
+ getWReg(wt)));
+ assign(t4,
+ unop(Iop_NotV128,
+ binop(Iop_CmpEQ8x16,
+ binop(Iop_ShlN8x16,
+ getWReg(wt),
+ mkU8(5)),
+ binop(Iop_64HLtoV128,
+ mkU64(0), mkU64(0)))));
+ assign(t3,
+ binop(Iop_ShrN8x16,
+ binop(Iop_AndV128,
+ binop(Iop_Shl8x16,
+ getWReg(ws),
+ mkexpr(t2)),
+ mkexpr(t4)),
+ mkU8(7)));
+ putWReg(wd,
+ binop(Iop_Add8x16,
+ mkexpr(t1), mkexpr(t3)));
+ break;
+ }
+
+ case 0x01: { /* SRLR.H */
+ DIP("SRLR.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_Shr16x8,
+ getWReg(ws),
+ getWReg(wt)));
+ assign(t2,
+ binop(Iop_Sub16x8,
+ binop(Iop_64HLtoV128,
+ mkU64(0x10001000100010ul),
+ mkU64(0x10001000100010ul)),
+ getWReg(wt)));
+ assign(t4,
+ unop(Iop_NotV128,
+ binop(Iop_CmpEQ16x8,
+ binop(Iop_ShlN16x8,
+ getWReg(wt),
+ mkU8(12)),
+ binop(Iop_64HLtoV128,
+ mkU64(0), mkU64(0)))));
+ assign(t3,
+ binop(Iop_ShrN16x8,
+ binop(Iop_AndV128,
+ binop(Iop_Shl16x8,
+ getWReg(ws),
+ mkexpr(t2)),
+ mkexpr(t4)),
+ mkU8(15)));
+ putWReg(wd,
+ binop(Iop_Add16x8,
+ mkexpr(t1), mkexpr(t3)));
+ break;
+ }
+
+ case 0x02: { /* SRLR.W */
+ DIP("SRLR.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_Shr32x4,
+ getWReg(ws),
+ getWReg(wt)));
+ assign(t2,
+ binop(Iop_Sub32x4,
+ binop(Iop_64HLtoV128,
+ mkU64(0x2000000020ul),
+ mkU64(0x2000000020ul)),
+ getWReg(wt)));
+ assign(t4,
+ unop(Iop_NotV128,
+ binop(Iop_CmpEQ32x4,
+ binop(Iop_ShlN32x4,
+ getWReg(wt),
+ mkU8(27)),
+ binop(Iop_64HLtoV128,
+ mkU64(0), mkU64(0)))));
+ assign(t3,
+ binop(Iop_ShrN32x4,
+ binop(Iop_AndV128,
+ binop(Iop_Shl32x4,
+ getWReg(ws),
+ mkexpr(t2)),
+ mkexpr(t4)),
+ mkU8(31)));
+ putWReg(wd,
+ binop(Iop_Add32x4,
+ mkexpr(t1), mkexpr(t3)));
+ break;
+ }
+
+ case 0x03: { /* SRLR.D */
+ DIP("SRLR.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_Shr64x2,
+ getWReg(ws),
+ getWReg(wt)));
+ assign(t2,
+ binop(Iop_Sub64x2,
+ binop(Iop_64HLtoV128,
+ mkU64(64ul), mkU64(64ul)),
+ getWReg(wt)));
+ assign(t4,
+ unop(Iop_NotV128,
+ binop(Iop_CmpEQ64x2,
+ binop(Iop_ShlN64x2,
+ getWReg(wt),
+ mkU8(58)),
+ binop(Iop_64HLtoV128,
+ mkU64(0), mkU64(0)))));
+ assign(t3,
+ binop(Iop_ShrN64x2,
+ binop(Iop_AndV128,
+ binop(Iop_Shl64x2,
+ getWReg(ws),
+ mkexpr(t2)),
+ mkexpr(t4)),
+ mkU8(63)));
+ putWReg(wd,
+ binop(Iop_Add64x2,
+ mkexpr(t1), mkexpr(t3)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x04: { /* HADD_S.df */
+ switch (df) {
+ case 0x01: { /* HADD_S.H */
+ DIP("HADD_S.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_Add16x8,
+ binop(Iop_SarN16x8,
+ mkexpr(t1), mkU8(8)),
+ binop(Iop_SarN16x8,
+ binop(Iop_ShlN16x8,
+ mkexpr(t2), mkU8(8)),
+ mkU8(8))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* HADD_S.W */
+ DIP("HADD_S.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_Add32x4,
+ binop(Iop_SarN32x4,
+ mkexpr(t1), mkU8(16)),
+ binop(Iop_SarN32x4,
+ binop(Iop_ShlN32x4,
+ mkexpr(t2), mkU8(16)),
+ mkU8(16))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* HADD_S.D */
+ DIP("HADD_S.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_Add64x2,
+ binop(Iop_SarN64x2,
+ mkexpr(t1), mkU8(32)),
+ binop(Iop_SarN64x2,
+ binop(Iop_ShlN64x2,
+ mkexpr(t2), mkU8(32)),
+ mkU8(32))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x05: { /* HADD_U.df */
+ switch (df) {
+ case 0x01: { /* HADD_U.H */
+ DIP("HADD_U.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_Add16x8,
+ binop(Iop_ShrN16x8,
+ mkexpr(t1), mkU8(8)),
+ binop(Iop_ShrN16x8,
+ binop(Iop_ShlN16x8,
+ mkexpr(t2), mkU8(8)),
+ mkU8(8))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* HADD_U.W */
+ DIP("HADD_U.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_Add32x4,
+ binop(Iop_ShrN32x4,
+ mkexpr(t1), mkU8(16)),
+ binop(Iop_ShrN32x4,
+ binop(Iop_ShlN32x4,
+ mkexpr(t2), mkU8(16)),
+ mkU8(16))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* HADD_U.D */
+ DIP("HADD_U.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_Add64x2,
+ binop(Iop_ShrN64x2,
+ mkexpr(t1), mkU8(32)),
+ binop(Iop_ShrN64x2,
+ binop(Iop_ShlN64x2,
+ mkexpr(t2), mkU8(32)),
+ mkU8(32))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x06: { /* HSUB_S.df */
+ switch (df) {
+ case 0x01: { /* HSUB_S.H */
+ DIP("HSUB_S.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_Sub16x8,
+ binop(Iop_SarN16x8,
+ mkexpr(t1), mkU8(8)),
+ binop(Iop_SarN16x8,
+ binop(Iop_ShlN16x8,
+ mkexpr(t2), mkU8(8)),
+ mkU8(8))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* HSUB_S.W */
+ DIP("HSUB_S.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_Sub32x4,
+ binop(Iop_SarN32x4,
+ mkexpr(t1), mkU8(16)),
+ binop(Iop_SarN32x4,
+ binop(Iop_ShlN32x4,
+ mkexpr(t2), mkU8(16)),
+ mkU8(16))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* HSUB_S.D */
+ DIP("HSUB_S.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_Sub64x2,
+ binop(Iop_SarN64x2,
+ mkexpr(t1), mkU8(32)),
+ binop(Iop_SarN64x2,
+ binop(Iop_ShlN64x2,
+ mkexpr(t2), mkU8(32)),
+ mkU8(32))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x07: { /* HSUB_U.df */
+ switch (df) {
+ case 0x01: { /* HSUB_U.H */
+ DIP("HSUB_U.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_Sub16x8,
+ binop(Iop_ShrN16x8,
+ mkexpr(t1), mkU8(8)),
+ binop(Iop_ShrN16x8,
+ binop(Iop_ShlN16x8,
+ mkexpr(t2), mkU8(8)),
+ mkU8(8))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* HSUB_U.W */
+ DIP("HSUB_U.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_Sub32x4,
+ binop(Iop_ShrN32x4,
+ mkexpr(t1), mkU8(16)),
+ binop(Iop_ShrN32x4,
+ binop(Iop_ShlN32x4,
+ mkexpr(t2), mkU8(16)),
+ mkU8(16))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* HSUB_U.D */
+ DIP("HSUB_U.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_Sub64x2,
+ binop(Iop_ShrN64x2,
+ mkexpr(t1), mkU8(32)),
+ binop(Iop_ShrN64x2,
+ binop(Iop_ShlN64x2,
+ mkexpr(t2), mkU8(32)),
+ mkU8(32))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_3R_1A(UInt cins, UChar wd, UChar ws) { /* 3R (0x1A) */
+ UShort operation;
+ UChar df, wt;
+
+ operation = (cins & 0x03C00000) >> 22;
+ df = (cins & 0x00200000) >> 21;
+ wt = (cins & 0x001F0000) >> 16;
+
+ switch (operation) {
+ case 0x00: { /* FCAF.df */
+ switch (df) {
+ case 0x00: { /* FCAF.W */
+ DIP("FCAF.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCAFW, 2);
+ putWReg(wd, binop(Iop_64HLtoV128, mkU64(0ul), mkU64(0ul)));
+ break;
+ }
+
+ case 0x01: { /* FCAF.D */
+ DIP("FCAF.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCAFD, 2);
+ putWReg(wd, binop(Iop_64HLtoV128, mkU64(0ul), mkU64(0ul)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x01: { /* FCUN.df */
+ switch (df) {
+ case 0x00: { /* FCUN.W */
+ DIP("FCUN.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCUNW, 2);
+ putWReg(wd, binop(Iop_CmpUN32Fx4,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* FCUN.D */
+ DIP("FCUN.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCUND, 2);
+ putWReg(wd, binop(Iop_CmpUN64Fx2,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x02: { /* FCEQ.df */
+ switch (df) {
+ case 0x00: { /* FCEQ.W */
+ DIP("FCEQ.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCEQW, 2);
+ putWReg(wd, binop(Iop_CmpEQ32Fx4,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* FCEQ.D */
+ DIP("FCEQ.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCEQD, 2);
+ putWReg(wd, binop(Iop_CmpEQ64Fx2,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x03: { /* FCUEQ.df */
+ switch (df) {
+ case 0x00: { /* FCUEQ.W */
+ DIP("FCUEQ.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCUEQW, 2);
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_CmpEQ32Fx4,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_CmpUN32Fx4,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x01: { /* FCUEQ.D */
+ DIP("FCUEQ.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCUEQD, 2);
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_CmpEQ64Fx2,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_CmpUN64Fx2,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x04: { /* FCLT.df */
+ switch (df) {
+ case 0x00: { /* FCLT.W */
+ DIP("FCLT.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCLTW, 2);
+ putWReg(wd,
+ binop(Iop_CmpLT32Fx4,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* FCLT.D */
+ DIP("FCLT.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCLTD, 2);
+ putWReg(wd,
+ binop(Iop_CmpLT64Fx2,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x05: { /* FCULT.df */
+ switch (df) {
+ case 0x00: { /* FCULT.W */
+ DIP("FCULT.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCULTW, 2);
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_CmpLT32Fx4,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_CmpUN32Fx4,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x01: { /* FCULT.D */
+ DIP("FCULT.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCULTD, 2);
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_CmpLT64Fx2,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_CmpUN64Fx2,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x06: { /* FCLE.df */
+ switch (df) {
+ case 0x00: { /* FCLE.W */
+ DIP("FCLE.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCLEW, 2);
+ putWReg(wd,
+ binop(Iop_CmpLE32Fx4,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* FCLE.D */
+ DIP("FCLE.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCLED, 2);
+ putWReg(wd,
+ binop(Iop_CmpLE64Fx2,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x07: { /* FCULE.df */
+ switch (df) {
+ case 0x00: { /* FCULE.W */
+ DIP("FCULE.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCULEW, 2);
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_CmpLE32Fx4,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_CmpUN32Fx4,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x01: { /* FCULE.D */
+ DIP("FCULE.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCULED, 2);
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_CmpLE64Fx2,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_CmpUN64Fx2,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x08: { /* FSAF.df */
+ switch (df) {
+ case 0x00: { /* FSAF.W */
+ DIP("FSAF.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSAFW, 2);
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkU64(0ul), mkU64(0ul)));
+ break;
+ }
+
+ case 0x01: { /* FSAF.D */
+ DIP("FSAF.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSAFD, 2);
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkU64(0ul), mkU64(0ul)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x09: { /* FSUN.df */
+ switch (df) {
+ case 0x00: { /* FSUN.W */
+ DIP("FSUN.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSUNW, 2);
+ putWReg(wd,
+ binop(Iop_CmpUN32Fx4,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* FSUN.D */
+ DIP("FSUN.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSUND, 2);
+ putWReg(wd,
+ binop(Iop_CmpUN64Fx2,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x0A: { /* FSEQ.df */
+ switch (df) {
+ case 0x00: { /* FSEQ.W */
+ DIP("FSEQ.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSEQW, 2);
+ putWReg(wd,
+ binop(Iop_CmpEQ32Fx4,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* FSEQ.D */
+ DIP("FSEQ.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSEQD, 2);
+ putWReg(wd,
+ binop(Iop_CmpEQ64Fx2,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x0B: { /* FSUEQ.df */
+ switch (df) {
+ case 0x00: { /* FSUEQ.W */
+ DIP("FSUEQ.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSUEQW, 2);
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_CmpEQ32Fx4,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_CmpUN32Fx4,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x01: { /* FSUEQ.D */
+ DIP("FSUEQ.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSUEQD, 2);
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_CmpEQ64Fx2,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_CmpUN64Fx2,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x0C: { /* FSLT.df */
+ switch (df) {
+ case 0x00: { /* FSLT.W */
+ DIP("FSLT.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSLTW, 2);
+ putWReg(wd,
+ binop(Iop_CmpLT32Fx4,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* FSLT.D */
+ DIP("FSLT.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSLTD, 2);
+ putWReg(wd,
+ binop(Iop_CmpLT64Fx2,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x0D: { /* FSULT.df */
+ switch (df) {
+ case 0x00: { /* FSULT.W */
+ DIP("FSULT.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSULTW, 2);
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_CmpLT32Fx4,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_CmpUN32Fx4,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x01: { /* FSULT.D */
+ DIP("FSULT.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSULTD, 2);
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_CmpLT64Fx2,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_CmpUN64Fx2,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x0E: { /* FSLE.df */
+ switch (df) {
+ case 0x00: { /* FSLE.W */
+ DIP("FSLE.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSLEW, 2);
+ putWReg(wd,
+ binop(Iop_CmpLE32Fx4,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* FSLE.D */
+ DIP("FSLE.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSLED, 2);
+ putWReg(wd,
+ binop(Iop_CmpLE64Fx2,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x0F: { /* FSULE.df */
+ switch (df) {
+ case 0x00: { /* FSULE.W */
+ DIP("FSULE.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSULEW, 2);
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_CmpLE32Fx4,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_CmpUN32Fx4,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x01: { /* FSULE.D */
+ DIP("FSULE.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSULED, 2);
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_CmpLE64Fx2,
+ getWReg(ws),
+ getWReg(wt)),
+ binop(Iop_CmpUN64Fx2,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_3R_1B(UInt cins, UChar wd, UChar ws) { /* 3R (0x1B) */
+ IRTemp t1, t2, t3, t4;
+ UShort operation;
+ UChar df, wt;
+
+ operation = (cins & 0x03C00000) >> 22;
+ df = (cins & 0x00200000) >> 21;
+ wt = (cins & 0x001F0000) >> 16;
+
+ switch (operation) {
+ case 0x00: { /* FADD.df */
+ switch (df) {
+ case 0x00: { /* FADD.W */
+ DIP("FADD.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FADDW, 2);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ putWReg(wd,
+ triop(Iop_Add32Fx4, rm,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* FADD.D */
+ DIP("FADD.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FADDD, 2);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ putWReg(wd,
+ triop(Iop_Add64Fx2, rm,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x01: { /* FSUB.df */
+ switch (df) {
+ case 0x00: { /* FSUB.W */
+ DIP("FSUB.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSUBW, 2);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ putWReg(wd,
+ triop(Iop_Sub32Fx4, rm,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* FSUB.D */
+ DIP("FSUB.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSUBD, 2);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ putWReg(wd,
+ triop(Iop_Sub64Fx2, rm,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x02: { /* FMUL.df */
+ switch (df) {
+ case 0x00: { /* FMUL.W */
+ DIP("FMUL.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FMULW, 2);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ putWReg(wd,
+ triop(Iop_Mul32Fx4, rm,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* FMUL.D */
+ DIP("FMUL.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FMULW, 2);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ putWReg(wd,
+ triop(Iop_Mul64Fx2, rm,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x03: { /* FDIV.df */
+ switch (df) {
+ case 0x00: { /* FDIV.W */
+ DIP("FDIV.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FDIVW, 2);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ putWReg(wd,
+ triop(Iop_Div32Fx4, rm,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* FDIV.D */
+ DIP("FDIV.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FDIVD, 2);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ putWReg(wd,
+ triop(Iop_Div64Fx2, rm,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x04: { /* FMADD.df */
+ switch (df) {
+ case 0x00: { /* FMADD.W */
+ DIP("FMADD.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FMADDW, 2);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ IRTemp tmp[4];
+ Int i;
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_F32);
+ assign(tmp[i],
+ qop(Iop_MAddF32, rm,
+ unop(Iop_ReinterpI32asF32,
+ binop(Iop_GetElem32x4,
+ getWReg(ws),
+ mkU8(i))),
+ unop(Iop_ReinterpI32asF32,
+ binop(Iop_GetElem32x4,
+ getWReg(wt),
+ mkU8(i))),
+ unop(Iop_ReinterpI32asF32,
+ binop(Iop_GetElem32x4,
+ getWReg(wd),
+ mkU8(i)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ unop(Iop_ReinterpF32asI32,
+ mkexpr(tmp[3])),
+ unop(Iop_ReinterpF32asI32,
+ mkexpr(tmp[2]))),
+ binop(Iop_32HLto64,
+ unop(Iop_ReinterpF32asI32,
+ mkexpr(tmp[1])),
+ unop(Iop_ReinterpF32asI32,
+ mkexpr(tmp[0])))));
+ break;
+ }
+
+ case 0x01: { /* FMADD.D */
+ DIP("FMADD.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FMADDW, 2);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ IRTemp tmp[2];
+ Int i;
+
+ for (i = 0; i < 2; i++) {
+ tmp[i] = newTemp(Ity_F64);
+ assign(tmp[i],
+ qop(Iop_MAddF64, rm,
+ unop(Iop_ReinterpI64asF64,
+ binop(Iop_GetElem64x2,
+ getWReg(ws),
+ mkU8(i))),
+ unop(Iop_ReinterpI64asF64,
+ binop(Iop_GetElem64x2,
+ getWReg(wt),
+ mkU8(i))),
+ unop(Iop_ReinterpI64asF64,
+ binop(Iop_GetElem64x2,
+ getWReg(wd),
+ mkU8(i)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ unop(Iop_ReinterpF64asI64,
+ mkexpr(tmp[1])),
+ unop(Iop_ReinterpF64asI64,
+ mkexpr(tmp[0]))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x05: { /* FMSUB.df */
+ switch (df) {
+ case 0x00: { /* FMSUB.W */
+ DIP("FMSUB.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FMADDW, 2);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ IRTemp tmp[4];
+ Int i;
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_F32);
+ assign(tmp[i],
+ qop(Iop_MSubF32, rm,
+ unop(Iop_ReinterpI32asF32,
+ binop(Iop_GetElem32x4,
+ getWReg(ws),
+ mkU8(i))),
+ unop(Iop_ReinterpI32asF32,
+ binop(Iop_GetElem32x4,
+ getWReg(wt),
+ mkU8(i))),
+ unop(Iop_ReinterpI32asF32,
+ binop(Iop_GetElem32x4,
+ getWReg(wd),
+ mkU8(i)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ unop(Iop_ReinterpF32asI32,
+ mkexpr(tmp[3])),
+ unop(Iop_ReinterpF32asI32,
+ mkexpr(tmp[2]))),
+ binop(Iop_32HLto64,
+ unop(Iop_ReinterpF32asI32,
+ mkexpr(tmp[1])),
+ unop(Iop_ReinterpF32asI32,
+ mkexpr(tmp[0])))));
+ break;
+ }
+
+ case 0x01: { /* FMSUB.D */
+ DIP("FMSUB.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FMADDD, 2);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ IRTemp tmp[2];
+ Int i;
+
+ for (i = 0; i < 2; i++) {
+ tmp[i] = newTemp(Ity_F64);
+ assign(tmp[i],
+ qop(Iop_MSubF64, rm,
+ unop(Iop_ReinterpI64asF64,
+ binop(Iop_GetElem64x2,
+ getWReg(ws),
+ mkU8(i))),
+ unop(Iop_ReinterpI64asF64,
+ binop(Iop_GetElem64x2,
+ getWReg(wt),
+ mkU8(i))),
+ unop(Iop_ReinterpI64asF64,
+ binop(Iop_GetElem64x2,
+ getWReg(wd),
+ mkU8(i)))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ unop(Iop_ReinterpF64asI64,
+ mkexpr(tmp[1])),
+ unop(Iop_ReinterpF64asI64,
+ mkexpr(tmp[0]))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x07: { /* FEXP2.df */
+ switch (df) {
+ case 0x00: { /* FEXP2.W */
+ DIP("FEXP2.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FEXP2W, 2);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ putWReg(wd,
+ triop(Iop_Scale2_32Fx4, rm,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* FEXP2.D */
+ DIP("FEXP2.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FEXP2D, 2);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ putWReg(wd,
+ triop(Iop_Scale2_64Fx2, rm,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x08: { /* FEXDO.df */
+ switch (df) {
+ case 0x00: { /* FEXDO.H */
+ DIP("FEXDO.H w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FEXDOH, 2);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ assign(t1,
+ unop(Iop_F32toF16x4,
+ getWReg(ws)));
+ assign(t2,
+ unop(Iop_F32toF16x4,
+ getWReg(wt)));
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkexpr(t1), mkexpr(t2)));
+ break;
+ }
+
+ case 0x01: { /* FEXDO.W */
+ DIP("FEXDO.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FEXDOW, 2);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ assign(t1,
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_F64toF32, rm,
+ unop(Iop_ReinterpI64asF64,
+ unop(Iop_V128to64,
+ getWReg(ws))))));
+ assign(t2,
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_F64toF32, rm,
+ unop(Iop_ReinterpI64asF64,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ assign(t3,
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_F64toF32, rm,
+ unop(Iop_ReinterpI64asF64,
+ unop(Iop_V128to64,
+ getWReg(wt))))));
+ assign(t4,
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_F64toF32, rm,
+ unop(Iop_ReinterpI64asF64,
+ unop(Iop_V128HIto64,
+ getWReg(wt))))));
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ mkexpr(t2), mkexpr(t1)),
+ binop(Iop_32HLto64,
+ mkexpr(t4), mkexpr(t3))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x0A: { /* FTQ.df */
+ switch (df) {
+ case 0x00: { /* FTQ.H */
+ DIP("FTQ.H w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FTQH, 2);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ putWReg(wd,
+ triop(Iop_F32x4_2toQ16x8, rm,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* FTQ.W */
+ DIP("FTQ.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FTQW, 2);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ putWReg(wd,
+ triop(Iop_F64x2_2toQ32x4, rm,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x0C: { /* FMIN.df */
+ switch (df) {
+ case 0x00: { /* FMIN.W */
+ DIP("FMIN.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FMINW, 2);
+ putWReg(wd,
+ binop(Iop_Min32Fx4,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* FMIN.D */
+ DIP("FMIN.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FMINW, 2);
+ putWReg(wd,
+ binop(Iop_Min64Fx2,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x0D: { /* FMIN_A.df */
+ switch (df) {
+ case 0x00: { /* FMIN_A.W */
+ DIP("FMIN_A.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FMINAW, 2);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_AndV128,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0x7FFFFFFF7FFFFFFF),
+ mkU64(0x7FFFFFFF7FFFFFFF))));
+ assign(t2,
+ binop(Iop_AndV128,
+ getWReg(wt),
+ binop(Iop_64HLtoV128,
+ mkU64(0x7FFFFFFF7FFFFFFF),
+ mkU64(0x7FFFFFFF7FFFFFFF))));
+ assign(t3,
+ binop(Iop_Min32Fx4,
+ mkexpr(t2), mkexpr(t1)));
+ assign(t4,
+ binop(Iop_AndV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ binop(Iop_CmpUN32Fx4,
+ mkexpr(t3),
+ mkexpr(t3))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_CmpEQ32Fx4,
+ mkexpr(t1),
+ mkexpr(t2)),
+ binop(Iop_OrV128,
+ getWReg(ws),
+ getWReg(wt))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_OrV128,
+ binop(Iop_CmpUN32Fx4,
+ mkexpr(t1),
+ mkexpr(t1)),
+ binop(Iop_CmpLT32Fx4,
+ mkexpr(t3),
+ mkexpr(t1))),
+ getWReg(wt)),
+ binop(Iop_AndV128,
+ binop(Iop_OrV128,
+ binop(Iop_CmpUN32Fx4,
+ mkexpr(t2),
+ mkexpr(t2)),
+ binop(Iop_CmpLT32Fx4,
+ mkexpr(t3),
+ mkexpr(t2))),
+ getWReg(ws))))),
+ binop(Iop_64HLtoV128,
+ mkU64(0x8000000080000000),
+ mkU64(0x8000000080000000))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t3), mkexpr(t4)));
+ break;
+ }
+
+ case 0x01: { /* FMIN_A.D */
+ DIP("FMIN_A.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FMINAD, 2);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_AndV128,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0x7FFFFFFFFFFFFFFF),
+ mkU64(0x7FFFFFFFFFFFFFFF))));
+ assign(t2,
+ binop(Iop_AndV128,
+ getWReg(wt),
+ binop(Iop_64HLtoV128,
+ mkU64(0x7FFFFFFFFFFFFFFF),
+ mkU64(0x7FFFFFFFFFFFFFFF))));
+ assign(t3,
+ binop(Iop_Min64Fx2,
+ mkexpr(t2), mkexpr(t1)));
+ assign(t4,
+ binop(Iop_AndV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ binop(Iop_CmpUN64Fx2,
+ mkexpr(t3),
+ mkexpr(t3))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_CmpEQ64Fx2,
+ mkexpr(t1),
+ mkexpr(t2)),
+ binop(Iop_OrV128,
+ getWReg(ws),
+ getWReg(wt))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_OrV128,
+ binop(Iop_CmpUN64Fx2,
+ mkexpr(t1),
+ mkexpr(t1)),
+ binop(Iop_CmpLT64Fx2,
+ mkexpr(t3),
+ mkexpr(t1))),
+ getWReg(wt)),
+ binop(Iop_AndV128,
+ binop(Iop_OrV128,
+ binop(Iop_CmpUN64Fx2,
+ mkexpr(t2),
+ mkexpr(t2)),
+ binop(Iop_CmpLT64Fx2,
+ mkexpr(t3),
+ mkexpr(t2))),
+ getWReg(ws))))),
+ binop(Iop_64HLtoV128,
+ mkU64(0x8000000000000000),
+ mkU64(0x8000000000000000))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t3), mkexpr(t4)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x0E: { /* FMAX.df */
+ switch (df) {
+ case 0x00: { /* FMAX.W */
+ DIP("FMAX.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FMAXW, 2);
+ putWReg(wd,
+ binop(Iop_Max32Fx4,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ case 0x01: { /* FMAX.D */
+ DIP("FMAX.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FMAXW, 2);
+ putWReg(wd,
+ binop(Iop_Max64Fx2,
+ getWReg(ws),
+ getWReg(wt)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x0F: { /* FMAX_A.df */
+ switch (df) {
+ case 0x00: { /* FMAX_A.W */
+ DIP("FMAX_A.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FMAXAW, 2);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_AndV128,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0x7FFFFFFF7FFFFFFF),
+ mkU64(0x7FFFFFFF7FFFFFFF))));
+ assign(t2,
+ binop(Iop_AndV128,
+ getWReg(wt),
+ binop(Iop_64HLtoV128,
+ mkU64(0x7FFFFFFF7FFFFFFF),
+ mkU64(0x7FFFFFFF7FFFFFFF))));
+ assign(t3,
+ binop(Iop_Max32Fx4,
+ mkexpr(t2), mkexpr(t1)));
+ assign(t4,
+ binop(Iop_AndV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ binop(Iop_CmpUN32Fx4,
+ mkexpr(t3),
+ mkexpr(t3))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_CmpEQ32Fx4,
+ mkexpr(t1),
+ mkexpr(t2)),
+ binop(Iop_AndV128,
+ getWReg(ws),
+ getWReg(wt))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_OrV128,
+ binop(Iop_CmpUN32Fx4,
+ mkexpr(t1),
+ mkexpr(t1)),
+ binop(Iop_CmpLT32Fx4,
+ mkexpr(t1),
+ mkexpr(t3))),
+ getWReg(wt)),
+ binop(Iop_AndV128,
+ binop(Iop_OrV128,
+ binop(Iop_CmpUN32Fx4,
+ mkexpr(t2),
+ mkexpr(t2)),
+ binop(Iop_CmpLT32Fx4,
+ mkexpr(t2),
+ mkexpr(t3))),
+ getWReg(ws))))),
+ binop(Iop_64HLtoV128,
+ mkU64(0x8000000080000000),
+ mkU64(0x8000000080000000))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t3), mkexpr(t4)));
+ break;
+ }
+
+ case 0x01: { /* FMAX_A.D */
+ DIP("FMAX_A.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FMAXAD, 2);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_AndV128,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0x7FFFFFFFFFFFFFFF),
+ mkU64(0x7FFFFFFFFFFFFFFF))));
+ assign(t2,
+ binop(Iop_AndV128,
+ getWReg(wt),
+ binop(Iop_64HLtoV128,
+ mkU64(0x7FFFFFFFFFFFFFFF),
+ mkU64(0x7FFFFFFFFFFFFFFF))));
+ assign(t3,
+ binop(Iop_Max64Fx2,
+ mkexpr(t2), mkexpr(t1)));
+ assign(t4,
+ binop(Iop_AndV128,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ binop(Iop_CmpUN64Fx2,
+ mkexpr(t3),
+ mkexpr(t3))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_CmpEQ64Fx2,
+ mkexpr(t1),
+ mkexpr(t2)),
+ binop(Iop_AndV128,
+ getWReg(ws),
+ getWReg(wt))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_OrV128,
+ binop(Iop_CmpUN64Fx2,
+ mkexpr(t1),
+ mkexpr(t1)),
+ binop(Iop_CmpLT64Fx2,
+ mkexpr(t1),
+ mkexpr(t3))),
+ getWReg(wt)),
+ binop(Iop_AndV128,
+ binop(Iop_OrV128,
+ binop(Iop_CmpUN64Fx2,
+ mkexpr(t2),
+ mkexpr(t2)),
+ binop(Iop_CmpLT64Fx2,
+ mkexpr(t2),
+ mkexpr(t3))),
+ getWReg(ws))))),
+ binop(Iop_64HLtoV128,
+ mkU64(0x8000000000000000),
+ mkU64(0x8000000000000000))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t3), mkexpr(t4)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_3R_1C(UInt cins, UChar wd, UChar ws) { /* 3R (0x1C) */
+ IRTemp t1, t2, t3, t4, t5, t6;
+ UShort operation;
+ UChar df, wt;
+
+ operation = (cins & 0x03C00000) >> 22;
+ df = (cins & 0x00200000) >> 21;
+ wt = (cins & 0x001F0000) >> 16;
+
+ switch (operation) {
+ case 0x01: { /* FCOR.df */
+ switch (df) {
+ case 0x00: { /* FCOR.W */
+ DIP("FCOR.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCORW, 2);
+ putWReg(wd,
+ unop(Iop_NotV128,
+ binop(Iop_CmpUN32Fx4,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x01: { /* FCOR.D */
+ DIP("FCOR.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCORD, 2);
+ putWReg(wd,
+ unop(Iop_NotV128,
+ binop(Iop_CmpUN64Fx2,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x02: { /* FCUNE.df */
+ switch (df) {
+ case 0x00: { /* FCUNE.W */
+ DIP("FCUNE.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCUNEW, 2);
+ putWReg(wd,
+ unop(Iop_NotV128,
+ binop(Iop_CmpEQ32Fx4,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x01: { /* FCUNE.D */
+ DIP("FCUNE.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCUNED, 2);
+ putWReg(wd,
+ unop(Iop_NotV128,
+ binop(Iop_CmpEQ64Fx2,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x03: { /* FCNE.df */
+ switch (df) {
+ case 0x00: { /* FCNE.W */
+ DIP("FCNE.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCNEW, 2);
+ putWReg(wd,
+ binop(Iop_XorV128,
+ unop(Iop_NotV128,
+ binop(Iop_CmpEQ32Fx4,
+ getWReg(ws),
+ getWReg(wt))),
+ binop(Iop_CmpUN32Fx4,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x01: { /* FCNE.D */
+ DIP("FCNE.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FCNED, 2);
+ putWReg(wd,
+ binop(Iop_XorV128,
+ unop(Iop_NotV128,
+ binop(Iop_CmpEQ64Fx2,
+ getWReg(ws),
+ getWReg(wt))),
+ binop(Iop_CmpUN64Fx2,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x04: { /* MUL_Q.df */
+ switch (df) {
+ case 0x00: { /* MUL_Q.H */
+ DIP("MUL_Q.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_QDMulHi16Sx8,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* MUL_Q.W */
+ DIP("MUL_Q.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ binop(Iop_QDMulHi32Sx4,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x05: { /* MADD_Q.df */
+ switch (df) {
+ case 0x00: { /* MADD_Q.W */
+ DIP("MADD_Q.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ t5 = newTemp(Ity_V128);
+ t6 = newTemp(Ity_V128);
+ assign(t1, // even
+ binop(Iop_SarN32x4,
+ binop(Iop_InterleaveEvenLanes16x8,
+ getWReg(ws),
+ getWReg(ws)),
+ mkU8(16)));
+ assign(t2, // odd
+ binop(Iop_SarN32x4,
+ getWReg(ws), mkU8(16)));
+ assign(t3, // even
+ binop(Iop_SarN32x4,
+ binop(Iop_InterleaveEvenLanes16x8,
+ getWReg(wt),
+ getWReg(wt)),
+ mkU8(16)));
+ assign(t4, // odd
+ binop(Iop_SarN32x4,
+ getWReg(wt), mkU8(16)));
+ assign(t5,
+ binop(Iop_Add32x4,
+ binop(Iop_ShlN32x4,
+ binop(Iop_SarN32x4,
+ binop(Iop_InterleaveEvenLanes16x8,
+ getWReg(wd),
+ getWReg(wd)),
+ mkU8(16)),
+ mkU8(15)),
+ binop(Iop_Mul32x4,
+ mkexpr(t1), mkexpr(t3))));
+ assign(t6,
+ binop(Iop_Add32x4,
+ binop(Iop_ShlN32x4,
+ binop(Iop_SarN32x4,
+ getWReg(wd),
+ mkU8(16)),
+ mkU8(15)),
+ binop(Iop_Mul32x4,
+ mkexpr(t2), mkexpr(t4))));
+ putWReg(wd,
+ binop(Iop_InterleaveEvenLanes16x8,
+ binop(Iop_QandQSarNnarrow32Sto16Sx4,
+ mkexpr(t6), mkU8(15)),
+ binop(Iop_QandQSarNnarrow32Sto16Sx4,
+ mkexpr(t5), mkU8(15))));
+ break;
+ }
+
+ case 0x01: { /* MADD_Q.W */
+ DIP("MADD_Q.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ t5 = newTemp(Ity_V128);
+ t6 = newTemp(Ity_V128);
+ assign(t1, // even
+ binop(Iop_SarN64x2,
+ binop(Iop_InterleaveEvenLanes32x4,
+ getWReg(ws),
+ getWReg(ws)),
+ mkU8(32)));
+ assign(t2, // odd
+ binop(Iop_SarN64x2,
+ getWReg(ws), mkU8(32)));
+ assign(t3, // even
+ binop(Iop_SarN64x2,
+ binop(Iop_InterleaveEvenLanes32x4,
+ getWReg(wt),
+ getWReg(wt)),
+ mkU8(32)));
+ assign(t4, // odd
+ binop(Iop_SarN64x2,
+ getWReg(wt), mkU8(32)));
+ assign(t5,
+ binop(Iop_Add64x2,
+ binop(Iop_ShlN64x2,
+ binop(Iop_SarN64x2,
+ binop(Iop_InterleaveEvenLanes32x4,
+ getWReg(wd),
+ getWReg(wd)),
+ mkU8(32)),
+ mkU8(31)),
+ binop(Iop_64HLtoV128,
+ binop(Iop_Mul64,
+ unop(Iop_V128HIto64,
+ mkexpr(t1)),
+ unop(Iop_V128HIto64,
+ mkexpr(t3))),
+ binop(Iop_Mul64,
+ unop(Iop_V128to64,
+ mkexpr(t1)),
+ unop(Iop_V128to64,
+ mkexpr(t3))))));
+ assign(t6,
+ binop(Iop_Add64x2,
+ binop(Iop_ShlN64x2,
+ binop(Iop_SarN64x2,
+ getWReg(wd),
+ mkU8(32)),
+ mkU8(31)),
+ binop(Iop_64HLtoV128,
+ binop(Iop_Mul64,
+ unop(Iop_V128HIto64,
+ mkexpr(t2)),
+ unop(Iop_V128HIto64,
+ mkexpr(t4))),
+ binop(Iop_Mul64,
+ unop(Iop_V128to64,
+ mkexpr(t2)),
+ unop(Iop_V128to64,
+ mkexpr(t4))))));
+ putWReg(wd,
+ binop(Iop_InterleaveEvenLanes32x4,
+ binop(Iop_QandQSarNnarrow64Sto32Sx2,
+ mkexpr(t6), mkU8(31)),
+ binop(Iop_QandQSarNnarrow64Sto32Sx2,
+ mkexpr(t5), mkU8(31))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x06: { /* MSUB_Q.df */
+ switch (df) {
+ case 0x00: { /* MSUB_Q.H */
+ DIP("MSUB_Q.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ t5 = newTemp(Ity_V128);
+ t6 = newTemp(Ity_V128);
+ assign(t1, // even
+ binop(Iop_SarN32x4,
+ binop(Iop_InterleaveEvenLanes16x8,
+ getWReg(ws),
+ getWReg(ws)),
+ mkU8(16)));
+ assign(t2, // odd
+ binop(Iop_SarN32x4,
+ getWReg(ws), mkU8(16)));
+ assign(t3, // even
+ binop(Iop_SarN32x4,
+ binop(Iop_InterleaveEvenLanes16x8,
+ getWReg(wt),
+ getWReg(wt)),
+ mkU8(16)));
+ assign(t4, // odd
+ binop(Iop_SarN32x4,
+ getWReg(wt), mkU8(16)));
+ assign(t5,
+ binop(Iop_Sub32x4,
+ binop(Iop_ShlN32x4,
+ binop(Iop_SarN32x4,
+ binop(Iop_InterleaveEvenLanes16x8,
+ getWReg(wd),
+ getWReg(wd)),
+ mkU8(16)),
+ mkU8(15)),
+ binop(Iop_Mul32x4,
+ mkexpr(t1), mkexpr(t3))));
+ assign(t6,
+ binop(Iop_Sub32x4,
+ binop(Iop_ShlN32x4,
+ binop(Iop_SarN32x4,
+ getWReg(wd),
+ mkU8(16)),
+ mkU8(15)),
+ binop(Iop_Mul32x4,
+ mkexpr(t2), mkexpr(t4))));
+ putWReg(wd,
+ binop(Iop_InterleaveEvenLanes16x8,
+ binop(Iop_QandQSarNnarrow32Sto16Sx4,
+ mkexpr(t6), mkU8(15)),
+ binop(Iop_QandQSarNnarrow32Sto16Sx4,
+ mkexpr(t5), mkU8(15))));
+ break;
+ }
+
+ case 0x01: { /* MSUB_Q.W */
+ DIP("MSUB_Q.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ t5 = newTemp(Ity_V128);
+ t6 = newTemp(Ity_V128);
+ assign(t1, // even
+ binop(Iop_SarN64x2,
+ binop(Iop_InterleaveEvenLanes32x4,
+ getWReg(ws),
+ getWReg(ws)),
+ mkU8(32)));
+ assign(t2, // odd
+ binop(Iop_SarN64x2,
+ getWReg(ws), mkU8(32)));
+ assign(t3, // even
+ binop(Iop_SarN64x2,
+ binop(Iop_InterleaveEvenLanes32x4,
+ getWReg(wt),
+ getWReg(wt)),
+ mkU8(32)));
+ assign(t4, // odd
+ binop(Iop_SarN64x2,
+ getWReg(wt), mkU8(32)));
+ assign(t5,
+ binop(Iop_Sub64x2,
+ binop(Iop_ShlN64x2,
+ binop(Iop_SarN64x2,
+ binop(Iop_InterleaveEvenLanes32x4,
+ getWReg(wd),
+ getWReg(wd)),
+ mkU8(32)),
+ mkU8(31)),
+ binop(Iop_64HLtoV128,
+ binop(Iop_Mul64,
+ unop(Iop_V128HIto64,
+ mkexpr(t1)),
+ unop(Iop_V128HIto64,
+ mkexpr(t3))),
+ binop(Iop_Mul64,
+ unop(Iop_V128to64,
+ mkexpr(t1)),
+ unop(Iop_V128to64,
+ mkexpr(t3))))));
+ assign(t6,
+ binop(Iop_Sub64x2,
+ binop(Iop_ShlN64x2,
+ binop(Iop_SarN64x2,
+ getWReg(wd),
+ mkU8(32)),
+ mkU8(31)),
+ binop(Iop_64HLtoV128,
+ binop(Iop_Mul64,
+ unop(Iop_V128HIto64,
+ mkexpr(t2)),
+ unop(Iop_V128HIto64,
+ mkexpr(t4))),
+ binop(Iop_Mul64,
+ unop(Iop_V128to64,
+ mkexpr(t2)),
+ unop(Iop_V128to64,
+ mkexpr(t4))))));
+ putWReg(wd,
+ binop(Iop_InterleaveEvenLanes32x4,
+ binop(Iop_QandQSarNnarrow64Sto32Sx2,
+ mkexpr(t6), mkU8(31)),
+ binop(Iop_QandQSarNnarrow64Sto32Sx2,
+ mkexpr(t5), mkU8(31))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x09: { /* FSOR.df */
+ switch (df) {
+ case 0x00: { /* FSOR.W */
+ DIP("FSOR.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSORW, 2);
+ putWReg(wd,
+ unop(Iop_NotV128,
+ binop(Iop_CmpUN32Fx4,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x01: { /* FSOR.D */
+ DIP("FSOR.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSORD, 2);
+ putWReg(wd,
+ unop(Iop_NotV128,
+ binop(Iop_CmpUN64Fx2,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x0A: { /* FSUNE.df */
+ switch (df) {
+ case 0x00: { /* FSUNE.W */
+ DIP("FSUNE.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSUNEW, 2);
+ putWReg(wd,
+ unop(Iop_NotV128,
+ binop(Iop_CmpEQ32Fx4,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x01: { /* FSUNE.D */
+ DIP("FSUNE.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSUNED, 2);
+ putWReg(wd,
+ unop(Iop_NotV128,
+ binop(Iop_CmpEQ64Fx2,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x0B: { /* FSNE.df */
+ switch (df) {
+ case 0x00: { /* FSNE.W */
+ DIP("FSNE.W w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSNEW, 2);
+ putWReg(wd,
+ binop(Iop_XorV128,
+ unop(Iop_NotV128,
+ binop(Iop_CmpEQ32Fx4,
+ getWReg(ws),
+ getWReg(wt))),
+ binop(Iop_CmpUN32Fx4,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ case 0x01: { /* FSNE.D */
+ DIP("FSNE.D w%d, w%d, w%d", wd, ws, wt);
+ calculateMSACSR(ws, wt, FSNED, 2);
+ putWReg(wd,
+ binop(Iop_XorV128,
+ unop(Iop_NotV128,
+ binop(Iop_CmpEQ64Fx2,
+ getWReg(ws),
+ getWReg(wt))),
+ binop(Iop_CmpUN64Fx2,
+ getWReg(ws),
+ getWReg(wt))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x0C: { /* MULR_Q.df */
+ switch (df) {
+ case 0x00: { /* MULR_Q.H */
+ DIP("MULR_Q.H w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QRDMulHi16Sx8,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* MULR_Q.W */
+ DIP("MULR_Q.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_QRDMulHi32Sx4,
+ mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x0D: { /* MADDR_Q.df */
+ switch (df) {
+ case 0x00: { /* MADDR_Q.W */
+ DIP("MADDR_Q.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ t5 = newTemp(Ity_V128);
+ t6 = newTemp(Ity_V128);
+ assign(t1, // even
+ binop(Iop_SarN32x4,
+ binop(Iop_InterleaveEvenLanes16x8,
+ getWReg(ws),
+ getWReg(ws)),
+ mkU8(16)));
+ assign(t2, // odd
+ binop(Iop_SarN32x4,
+ getWReg(ws), mkU8(16)));
+ assign(t3, // even
+ binop(Iop_SarN32x4,
+ binop(Iop_InterleaveEvenLanes16x8,
+ getWReg(wt),
+ getWReg(wt)),
+ mkU8(16)));
+ assign(t4, // odd
+ binop(Iop_SarN32x4,
+ getWReg(wt), mkU8(16)));
+ assign(t5,
+ binop(Iop_Add32x4,
+ binop(Iop_ShlN32x4,
+ binop(Iop_SarN32x4,
+ binop(Iop_InterleaveEvenLanes16x8,
+ getWReg(wd),
+ getWReg(wd)),
+ mkU8(16)),
+ mkU8(15)),
+ binop(Iop_Mul32x4,
+ mkexpr(t1), mkexpr(t3))));
+ assign(t6,
+ binop(Iop_Add32x4,
+ binop(Iop_ShlN32x4,
+ binop(Iop_SarN32x4,
+ getWReg(wd),
+ mkU8(16)),
+ mkU8(15)),
+ binop(Iop_Mul32x4,
+ mkexpr(t2), mkexpr(t4))));
+ putWReg(wd,
+ binop(Iop_InterleaveEvenLanes16x8,
+ binop(Iop_QandQRSarNnarrow32Sto16Sx4,
+ mkexpr(t6), mkU8(15)),
+ binop(Iop_QandQRSarNnarrow32Sto16Sx4,
+ mkexpr(t5), mkU8(15))));
+ break;
+ }
+
+ case 0x01: { /* MADDR_Q.D */
+ DIP("MADDR_Q.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ t5 = newTemp(Ity_V128);
+ t6 = newTemp(Ity_V128);
+ assign(t1, // even
+ binop(Iop_SarN64x2,
+ binop(Iop_InterleaveEvenLanes32x4,
+ getWReg(ws),
+ getWReg(ws)),
+ mkU8(32)));
+ assign(t2, // odd
+ binop(Iop_SarN64x2,
+ getWReg(ws), mkU8(32)));
+ assign(t3, // even
+ binop(Iop_SarN64x2,
+ binop(Iop_InterleaveEvenLanes32x4,
+ getWReg(wt),
+ getWReg(wt)),
+ mkU8(32)));
+ assign(t4, // odd
+ binop(Iop_SarN64x2,
+ getWReg(wt), mkU8(32)));
+ assign(t5,
+ binop(Iop_Add64x2,
+ binop(Iop_ShlN64x2,
+ binop(Iop_SarN64x2,
+ binop(Iop_InterleaveEvenLanes32x4,
+ getWReg(wd),
+ getWReg(wd)),
+ mkU8(32)),
+ mkU8(31)),
+ binop(Iop_64HLtoV128,
+ binop(Iop_Mul64,
+ unop(Iop_V128HIto64,
+ mkexpr(t1)),
+ unop(Iop_V128HIto64,
+ mkexpr(t3))),
+ binop(Iop_Mul64,
+ unop(Iop_V128to64,
+ mkexpr(t1)),
+ unop(Iop_V128to64,
+ mkexpr(t3))))));
+ assign(t6,
+ binop(Iop_Add64x2,
+ binop(Iop_ShlN64x2,
+ binop(Iop_SarN64x2,
+ getWReg(wd),
+ mkU8(32)),
+ mkU8(31)),
+ binop(Iop_64HLtoV128,
+ binop(Iop_Mul64,
+ unop(Iop_V128HIto64,
+ mkexpr(t2)),
+ unop(Iop_V128HIto64,
+ mkexpr(t4))),
+ binop(Iop_Mul64,
+ unop(Iop_V128to64,
+ mkexpr(t2)),
+ unop(Iop_V128to64,
+ mkexpr(t4))))));
+ putWReg(wd,
+ binop(Iop_InterleaveEvenLanes32x4,
+ binop(Iop_QandQRSarNnarrow64Sto32Sx2,
+ mkexpr(t6), mkU8(31)),
+ binop(Iop_QandQRSarNnarrow64Sto32Sx2,
+ mkexpr(t5), mkU8(31))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x0E: { /* MSUBR_Q.df */
+ switch (df) {
+ case 0x00: { /* MSUBR_Q.W */
+ DIP("MSUBR_Q.W w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ t5 = newTemp(Ity_V128);
+ t6 = newTemp(Ity_V128);
+ assign(t1, // even
+ binop(Iop_SarN32x4,
+ binop(Iop_InterleaveEvenLanes16x8,
+ getWReg(ws),
+ getWReg(ws)),
+ mkU8(16)));
+ assign(t2, // odd
+ binop(Iop_SarN32x4,
+ getWReg(ws), mkU8(16)));
+ assign(t3, // even
+ binop(Iop_SarN32x4,
+ binop(Iop_InterleaveEvenLanes16x8,
+ getWReg(wt),
+ getWReg(wt)),
+ mkU8(16)));
+ assign(t4, // odd
+ binop(Iop_SarN32x4,
+ getWReg(wt), mkU8(16)));
+ assign(t5,
+ binop(Iop_Sub32x4,
+ binop(Iop_ShlN32x4,
+ binop(Iop_SarN32x4,
+ binop(Iop_InterleaveEvenLanes16x8,
+ getWReg(wd),
+ getWReg(wd)),
+ mkU8(16)),
+ mkU8(15)),
+ binop(Iop_Mul32x4,
+ mkexpr(t1), mkexpr(t3))));
+ assign(t6,
+ binop(Iop_Sub32x4,
+ binop(Iop_ShlN32x4,
+ binop(Iop_SarN32x4,
+ getWReg(wd),
+ mkU8(16)),
+ mkU8(15)),
+ binop(Iop_Mul32x4,
+ mkexpr(t2), mkexpr(t4))));
+ putWReg(wd,
+ binop(Iop_InterleaveEvenLanes16x8,
+ binop(Iop_QandQRSarNnarrow32Sto16Sx4,
+ mkexpr(t6), mkU8(15)),
+ binop(Iop_QandQRSarNnarrow32Sto16Sx4,
+ mkexpr(t5), mkU8(15))));
+ break;
+ }
+
+ case 0x01: { /* MSUBR_Q.D */
+ DIP("MSUBR_Q.D w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ t5 = newTemp(Ity_V128);
+ t6 = newTemp(Ity_V128);
+ assign(t1, // even
+ binop(Iop_SarN64x2,
+ binop(Iop_InterleaveEvenLanes32x4,
+ getWReg(ws),
+ getWReg(ws)),
+ mkU8(32)));
+ assign(t2, // odd
+ binop(Iop_SarN64x2,
+ getWReg(ws), mkU8(32)));
+ assign(t3, // even
+ binop(Iop_SarN64x2,
+ binop(Iop_InterleaveEvenLanes32x4,
+ getWReg(wt),
+ getWReg(wt)),
+ mkU8(32)));
+ assign(t4, // odd
+ binop(Iop_SarN64x2,
+ getWReg(wt), mkU8(32)));
+ assign(t5,
+ binop(Iop_Sub64x2,
+ binop(Iop_ShlN64x2,
+ binop(Iop_SarN64x2,
+ binop(Iop_InterleaveEvenLanes32x4,
+ getWReg(wd),
+ getWReg(wd)),
+ mkU8(32)),
+ mkU8(31)),
+ binop(Iop_64HLtoV128,
+ binop(Iop_Mul64,
+ unop(Iop_V128HIto64,
+ mkexpr(t1)),
+ unop(Iop_V128HIto64,
+ mkexpr(t3))),
+ binop(Iop_Mul64,
+ unop(Iop_V128to64,
+ mkexpr(t1)),
+ unop(Iop_V128to64,
+ mkexpr(t3))))));
+ assign(t6,
+ binop(Iop_Sub64x2,
+ binop(Iop_ShlN64x2,
+ binop(Iop_SarN64x2,
+ getWReg(wd),
+ mkU8(32)),
+ mkU8(31)),
+ binop(Iop_64HLtoV128,
+ binop(Iop_Mul64,
+ unop(Iop_V128HIto64,
+ mkexpr(t2)),
+ unop(Iop_V128HIto64,
+ mkexpr(t4))),
+ binop(Iop_Mul64,
+ unop(Iop_V128to64,
+ mkexpr(t2)),
+ unop(Iop_V128to64,
+ mkexpr(t4))))));
+ putWReg(wd,
+ binop(Iop_InterleaveEvenLanes32x4,
+ binop(Iop_QandQRSarNnarrow64Sto32Sx2,
+ mkexpr(t6), mkU8(31)),
+ binop(Iop_QandQRSarNnarrow64Sto32Sx2,
+ mkexpr(t5), mkU8(31))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_ELM(UInt cins, UChar wd, UChar ws) { /* ELM (0x19) */
+ IRTemp t1, t2, t3, t4, t5;
+ IRType ty;
+ UShort operation;
+ UChar df, n;
+
+ operation = (cins & 0x03C00000) >> 22;
+ ty = mode64 ? Ity_I64 : Ity_I32;
+
+ switch ((cins & 0x03FF0000) >> 16) {
+ case 0x07E: /* CFCMSA */
+ DIP("CFCMSA r%d, c%d", wd, ws);
+
+ switch (ws) {
+ case 0: { /* MSAIR */
+ IRDirty *d;
+ t1 = newTemp(Ity_I32);
+ /* IRExpr_BBPTR() =>
+ Need to pass pointer to
+ guest state to helper. */
+ d = unsafeIRDirty_1_N(t1, 0,
+ "mips_dirtyhelper_get_MSAIR",
+ &mips_dirtyhelper_get_MSAIR,
+ mkIRExprVec_0());
+ /* d->nFxState = 0; */
+ stmt(IRStmt_Dirty(d));
+ putIReg(wd,
+ mkWidenFrom32(ty, mkexpr(t1), True));
+ break;
+ }
+
+ case 1: /* MSACSR */
+ putIReg(wd,
+ mkWidenFrom32(ty, getMSACSR(), True));
+ break;
+
+ default:
+ putIReg(wd,
+ mkWidenFrom32(ty, mkU32(0), False));
+ break;
+ }
+
+ break;
+
+ case 0x03E: /* CTCMSA */
+ DIP("CTCMSA r%d, c%d", ws, wd);
+
+ if (wd == 1) { /* MSACSR */
+ putMSACSR(
+ binop(Iop_And32, mkNarrowTo32(ty, getIReg(ws)),
+ mkU32(0x1FFFFFF)));
+ }
+
+ break;
+
+ case 0x0BE: /* MOVE.V */
+ DIP("MOVE.V w%d, w%d", ws, wd);
+ putWReg(wd, getWReg(ws));
+ break;
+
+ default:
+ df = (cins & 0x003F0000) >> 16;
+ if ((df & 0x38) == 0x38) { // 11100n; dw
+ n = df & 0x01;
+ df = 0x38;
+ } else if ((df & 0x30) == 0x30) { // 1100nn; w
+ n = df & 0x03;
+ df = 0x30;
+ } else if ((df & 0x20) == 0x20) { // 100nnn; hw
+ n = df & 0x07;
+ df = 0x20;
+ } else if ((df & 0x00) == 0x00) { // 00nnnn; b
+ n = df & 0x0F;
+ df = 0x00;
+ }
+
+ switch (operation) {
+ case 0x00: /* SLDI.df */
+ switch (df) {
+ case 0x00: /* SLDI.B */
+ DIP("SLDI.B w%d, w%d[%d]", wd, ws, n);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_ShrV128,
+ getWReg(ws),
+ mkU8(n << 3)));
+ assign(t2,
+ binop(Iop_ShlV128,
+ getWReg(wd),
+ mkU8(n ?
+ (16 - n) << 3 : 0)));
+ putWReg(wd,
+ binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
+ break;
+
+ case 0x20: /* SLDI.H */
+ DIP("SLDI.H w%d, w%d[%d]", wd, ws, n);
+
+ if (n == 0) {
+ putWReg(wd, getWReg(ws));
+ } else {
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_ShrN64x2,
+ getWReg(ws),
+ mkU8(n << 3)));
+ assign(t2,
+ binop(Iop_ShlN64x2,
+ getWReg(wd),
+ mkU8((8 - n) << 3)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t1),
+ mkexpr(t2)));
+ }
+
+ break;
+
+ case 0x30: /* SLDI.W */
+ DIP("SLDI.W w%d, w%d[%d]", wd, ws, n);
+
+ if (n == 0) {
+ putWReg(wd, getWReg(ws));
+ } else {
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_ShrN32x4,
+ getWReg(ws),
+ mkU8(n << 3)));
+ assign(t2,
+ binop(Iop_ShlN32x4,
+ getWReg(wd),
+ mkU8((4 - n) << 3)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t1),
+ mkexpr(t2)));
+ }
+
+ break;
+
+ case 0x38: /* SLDI.D */
+ DIP("SLDI.D w%d, w%d[%d]", wd, ws, n);
+
+ if (n == 0) {
+ putWReg(wd, getWReg(ws));
+ } else {
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_ShrN16x8,
+ getWReg(ws),
+ mkU8(n << 3)));
+ assign(t2,
+ binop(Iop_ShlN16x8,
+ getWReg(wd),
+ mkU8((2 - n) << 3)));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t1),
+ mkexpr(t2)));
+ }
+
+ break;
+
+ default:
+ return -1;
+ }
+
+ break;
+
+ case 0x01: /* SPLATI.df */
+ switch (df) {
+ case 0x00: { /* SPLATI.B */
+ DIP("SPLATI.B w%d, w%d[%d]", wd, ws, n);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+
+ if (n & 1)
+ assign(t1,
+ binop(Iop_InterleaveOddLanes8x16,
+ getWReg(ws),
+ getWReg(ws)));
+ else
+ assign(t1,
+ binop(Iop_InterleaveEvenLanes8x16,
+ getWReg(ws),
+ getWReg(ws)));
+
+ n /= 2;
+
+ if (n & 1)
+ assign(t2,
+ binop(Iop_InterleaveOddLanes16x8,
+ mkexpr(t1), mkexpr(t1)));
+ else
+ assign(t2,
+ binop(Iop_InterleaveEvenLanes16x8,
+ mkexpr(t1), mkexpr(t1)));
+
+ n /= 2;
+
+ if (n & 1)
+ assign(t3,
+ binop(Iop_InterleaveOddLanes32x4,
+ mkexpr(t2), mkexpr(t2)));
+ else
+ assign(t3,
+ binop(Iop_InterleaveEvenLanes32x4,
+ mkexpr(t2), mkexpr(t2)));
+
+ n /= 2;
+
+ if (n & 1)
+ assign(t4,
+ binop(Iop_InterleaveHI64x2,
+ mkexpr(t3), mkexpr(t3)));
+ else
+ assign(t4,
+ binop(Iop_InterleaveLO64x2,
+ mkexpr(t3), mkexpr(t3)));
+
+ putWReg(wd, mkexpr(t4));
+ break;
+ }
+
+ case 0x20: { /* SPLATI.H */
+ DIP("SPLATI.H w%d, w%d[%d]", wd, ws, n);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+
+ if (n & 1)
+ assign(t1,
+ binop(Iop_InterleaveOddLanes16x8,
+ getWReg(ws),
+ getWReg(ws)));
+ else
+ assign(t1,
+ binop(Iop_InterleaveEvenLanes16x8,
+ getWReg(ws),
+ getWReg(ws)));
+
+ n /= 2;
+
+ if (n & 1)
+ assign(t2,
+ binop(Iop_InterleaveOddLanes32x4,
+ mkexpr(t1), mkexpr(t1)));
+ else
+ assign(t2,
+ binop(Iop_InterleaveEvenLanes32x4,
+ mkexpr(t1), mkexpr(t1)));
+
+ n /= 2;
+
+ if (n & 1)
+ assign(t3,
+ binop(Iop_InterleaveHI64x2,
+ mkexpr(t2), mkexpr(t2)));
+ else
+ assign(t3,
+ binop(Iop_InterleaveLO64x2,
+ mkexpr(t2), mkexpr(t2)));
+
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x30: { /* SPLATI.W */
+ DIP("SPLATI.W w%d, w%d[%d]", wd, ws, n);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+
+ if (n & 1)
+ assign(t2,
+ binop(Iop_InterleaveOddLanes32x4,
+ mkexpr(t1), mkexpr(t1)));
+ else
+ assign(t2,
+ binop(Iop_InterleaveEvenLanes32x4,
+ mkexpr(t1), mkexpr(t1)));
+
+ n /= 2;
+
+ if (n & 1)
+ assign(t3,
+ binop(Iop_InterleaveHI64x2,
+ mkexpr(t2), mkexpr(t2)));
+ else
+ assign(t3,
+ binop(Iop_InterleaveLO64x2,
+ mkexpr(t2), mkexpr(t2)));
+
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x38: /* SPLATI.D */
+ DIP("SPLATI.D w%d, w%d[%d]", wd, ws, n);
+ t1 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+
+ if (n)
+ assign(t3,
+ binop(Iop_InterleaveHI64x2,
+ mkexpr(t1), mkexpr(t1)));
+ else
+ assign(t3,
+ binop(Iop_InterleaveLO64x2,
+ mkexpr(t1), mkexpr(t1)));
+
+ putWReg(wd, mkexpr(t3));
+ break;
+
+ default:
+ return -1;
+ }
+
+ break;
+
+ case 0x02: /* COPY_S.df */
+ switch (df) {
+ case 0x00: /* COPY_S.B */
+ DIP("COPY_S.B r%d, w%d[%d]", wd, ws, n);
+ t1 = newTemp(Ity_I8);
+
+ switch (n) {
+ case 0:
+ assign(t1,
+ unop(Iop_32to8,
+ unop(Iop_V128to32,
+ getWReg(ws))));
+ break;
+
+ case 1:
+ assign(t1,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ unop(Iop_V128to32,
+ getWReg(ws)))));
+ break;
+
+ case 2:
+ assign(t1,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ unop(Iop_64to32,
+ unop(Iop_V128to64,
+ getWReg(ws))))));
+ break;
+
+ case 3:
+ assign(t1,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ unop(Iop_64to32,
+ unop(Iop_V128to64,
+ getWReg(ws))))));
+ break;
+
+ case 4:
+ assign(t1,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128to64,
+ getWReg(ws))))));
+ break;
+
+ case 5:
+ assign(t1,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128to64,
+ getWReg(ws))))));
+ break;
+
+ case 6:
+ assign(t1,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128to64,
+ getWReg(ws))))));
+ break;
+
+ case 7:
+ assign(t1,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128to64,
+ getWReg(ws))))));
+ break;
+
+ case 8:
+ assign(t1,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ unop(Iop_64to32,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ break;
+
+ case 9:
+ assign(t1,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ unop(Iop_64to32,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ break;
+
+ case 10:
+ assign(t1,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ unop(Iop_64to32,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ break;
+
+ case 11:
+ assign(t1,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ unop(Iop_64to32,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ break;
+
+ case 12:
+ assign(t1,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ break;
+
+ case 13:
+ assign(t1,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ break;
+
+ case 14:
+ assign(t1,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ break;
+
+ case 15:
+ assign(t1,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ break;
+ }
+
+ putIReg(wd,
+ unop(mode64 ? Iop_8Sto64 : Iop_8Sto32,
+ mkexpr(t1)));
+ break;
+
+ case 0x20: /* COPY_S.H */
+ DIP("COPY_S.H r%d, w%d[%d]", wd, ws, n);
+ t1 = newTemp(Ity_I16);
+
+ switch (n) {
+ case 0:
+ assign(t1,
+ unop(Iop_32to16,
+ unop(Iop_64to32,
+ unop(Iop_V128to64,
+ getWReg(ws)))));
+ break;
+
+ case 1:
+ assign(t1,
+ unop(Iop_32HIto16,
+ unop(Iop_64to32,
+ unop(Iop_V128to64,
+ getWReg(ws)))));
+ break;
+
+ case 2:
+ assign(t1,
+ unop(Iop_32to16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128to64,
+ getWReg(ws)))));
+ break;
+
+ case 3:
+ assign(t1,
+ unop(Iop_32HIto16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128to64,
+ getWReg(ws)))));
+ break;
+
+ case 4:
+ assign(t1,
+ unop(Iop_32to16,
+ unop(Iop_64to32,
+ unop(Iop_V128HIto64,
+ getWReg(ws)))));
+ break;
+
+ case 5:
+ assign(t1,
+ unop(Iop_32HIto16,
+ unop(Iop_64to32,
+ unop(Iop_V128HIto64,
+ getWReg(ws)))));
+ break;
+
+ case 6:
+ assign(t1,
+ unop(Iop_32to16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64,
+ getWReg(ws)))));
+ break;
+
+ case 7:
+ assign(t1,
+ unop(Iop_32HIto16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64,
+ getWReg(ws)))));
+ break;
+ }
+
+ putIReg(wd,
+ unop(mode64 ? Iop_16Sto64 : Iop_16Sto32,
+ mkexpr(t1)));
+ break;
+
+ case 0x30: /* COPY_S.W */
+ DIP("COPY_S.W r%d, w%d[%d]", wd, ws, n);
+
+ switch (n) {
+ case 0:
+ putIReg(wd,
+ mkWidenFrom32(ty,
+ unop(Iop_V128to32,
+ getWReg(ws)),
+ True));
+ break;
+
+ case 1:
+ t2 = newTemp(Ity_I64);
+ assign(t2,
+ unop(Iop_V128to64, getWReg(ws)));
+ putIReg(wd,
+ mkWidenFrom32(ty,
+ unop(Iop_64HIto32,
+ mkexpr(t2)),
+ True));
+ break;
+
+ case 2:
+ t2 = newTemp(Ity_I64);
+ assign(t2,
+ unop(Iop_V128HIto64,
+ getWReg(ws)));
+ putIReg(wd,
+ mkWidenFrom32(ty,
+ unop(Iop_64to32,
+ mkexpr(t2)),
+ True));
+ break;
+
+ case 3:
+ t2 = newTemp(Ity_I64);
+ assign(t2,
+ unop(Iop_V128HIto64,
+ getWReg(ws)));
+ putIReg(wd,
+ mkWidenFrom32(ty,
+ unop(Iop_64HIto32,
+ mkexpr(t2)),
+ True));
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case 0x38: /* COPY_S.D */
+ if (mode64) {
+ DIP("COPY_S.D r%d, w%d[%d]", wd, ws, n);
+
+ switch (n) {
+ case 0:
+ putIReg(wd,
+ unop(Iop_V128to64,
+ getWReg(ws)));
+ break;
+
+ case 1:
+ putIReg(wd,
+ unop(Iop_V128HIto64,
+ getWReg(ws)));
+ break;
+ }
+ } else {
+ return -2;
+ }
+
+ break;
+
+ default:
+ return -1;
+ }
+
+ break;
+
+ case 0x03: { /* COPY_U.df */
+ switch (df) {
+ case 0x00: /* COPY_U.B */
+ DIP("COPY_U.B r%d, w%d[%d]", wd, ws, n);
+ t1 = newTemp(Ity_I8);
+
+ switch (n) {
+ case 0:
+ assign(t1,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ unop(Iop_64to32,
+ unop(Iop_V128to64,
+ getWReg(ws))))));
+ break;
+
+ case 1:
+ assign(t1,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ unop(Iop_64to32,
+ unop(Iop_V128to64,
+ getWReg(ws))))));
+ break;
+
+ case 2:
+ assign(t1,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ unop(Iop_64to32,
+ unop(Iop_V128to64,
+ getWReg(ws))))));
+ break;
+
+ case 3:
+ assign(t1,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ unop(Iop_64to32,
+ unop(Iop_V128to64,
+ getWReg(ws))))));
+ break;
+
+ case 4:
+ assign(t1,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128to64,
+ getWReg(ws))))));
+ break;
+
+ case 5:
+ assign(t1,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128to64,
+ getWReg(ws))))));
+ break;
+
+ case 6:
+ assign(t1,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128to64,
+ getWReg(ws))))));
+ break;
+
+ case 7:
+ assign(t1,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128to64,
+ getWReg(ws))))));
+ break;
+
+ case 8:
+ assign(t1,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ unop(Iop_64to32,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ break;
+
+ case 9:
+ assign(t1,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ unop(Iop_64to32,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ break;
+
+ case 10:
+ assign(t1,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ unop(Iop_64to32,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ break;
+
+ case 11:
+ assign(t1,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ unop(Iop_64to32,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ break;
+
+ case 12:
+ assign(t1,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ break;
+
+ case 13:
+ assign(t1,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ break;
+
+ case 14:
+ assign(t1,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ break;
+
+ case 15:
+ assign(t1,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64,
+ getWReg(ws))))));
+ break;
+ }
+
+ putIReg(wd,
+ unop(mode64 ? Iop_8Uto64 : Iop_8Uto32,
+ mkexpr(t1)));
+ break;
+
+ case 0x20: /* COPY_U.H */
+ DIP("COPY_U.H r%d, w%d[%d]", wd, ws, n);
+ t1 = newTemp(Ity_I16);
+
+ switch (n) {
+ case 0:
+ assign(t1,
+ unop(Iop_32to16,
+ unop(Iop_64to32,
+ unop(Iop_V128to64,
+ getWReg(ws)))));
+ break;
+
+ case 1:
+ assign(t1,
+ unop(Iop_32HIto16,
+ unop(Iop_64to32,
+ unop(Iop_V128to64,
+ getWReg(ws)))));
+ break;
+
+ case 2:
+ assign(t1,
+ unop(Iop_32to16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128to64,
+ getWReg(ws)))));
+ break;
+
+ case 3:
+ assign(t1,
+ unop(Iop_32HIto16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128to64,
+ getWReg(ws)))));
+ break;
+
+ case 4:
+ assign(t1,
+ unop(Iop_32to16,
+ unop(Iop_64to32,
+ unop(Iop_V128HIto64,
+ getWReg(ws)))));
+ break;
+
+ case 5:
+ assign(t1,
+ unop(Iop_32HIto16,
+ unop(Iop_64to32,
+ unop(Iop_V128HIto64,
+ getWReg(ws)))));
+ break;
+
+ case 6:
+ assign(t1,
+ unop(Iop_32to16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64,
+ getWReg(ws)))));
+ break;
+
+ case 7:
+ assign(t1,
+ unop(Iop_32HIto16,
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64,
+ getWReg(ws)))));
+ break;
+ }
+
+ putIReg(wd,
+ unop(mode64 ? Iop_16Uto64 : Iop_16Uto32,
+ mkexpr(t1)));
+ break;
+
+ case 0x30: /* COPY_U.W */
+ DIP("COPY_U.W r%d, w%d[%d]", wd, ws, n);
+
+ switch (n) {
+ case 0:
+ putIReg(wd,
+ mkWidenFrom32(ty,
+ unop(Iop_V128to32,
+ getWReg(ws)),
+ False));
+ break;
+
+ case 1:
+ t2 = newTemp(Ity_I64);
+ assign(t2,
+ unop(Iop_V128to64,
+ getWReg(ws)));
+ putIReg(wd,
+ mkWidenFrom32(ty,
+ unop(Iop_64HIto32,
+ mkexpr(t2)),
+ False));
+ break;
+
+ case 2:
+ t2 = newTemp(Ity_I64);
+ assign(t2,
+ unop(Iop_V128HIto64,
+ getWReg(ws)));
+ putIReg(wd,
+ mkWidenFrom32(ty,
+ unop(Iop_64to32,
+ mkexpr(t2)),
+ False));
+ break;
+
+ case 3:
+ t2 = newTemp(Ity_I64);
+ assign(t2,
+ unop(Iop_V128HIto64,
+ getWReg(ws)));
+ putIReg(wd,
+ mkWidenFrom32(ty,
+ unop(Iop_64HIto32,
+ mkexpr(t2)),
+ False));
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x04: { /* INSERT.df */
+ t5 = newTemp(Ity_I64);
+ UInt hi = 1;
+ ULong mask;
+ IRTemp *src, *dst;
+ assign(t5, mode64 ? getIReg(ws) :
+ unop(Iop_32Uto64, getIReg(ws)));
+
+ if (df == 0x38) { /* INSERT.D */
+ if (mode64) {
+ DIP("INSERT.D w%d[%d], r%d", wd, n, ws);
+
+ if (n == 0) {
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ unop(Iop_V128HIto64,
+ getWReg(wd)),
+ mkexpr(t5)));
+ } else {
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkexpr(t5),
+ unop(Iop_V128to64,
+ getWReg(wd))));
+ }
+
+ break;
+ } else {
+ return -2;
+ }
+ } else {
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ assign(t1, unop(Iop_V128to64, getWReg(wd)));
+ assign(t2, unop(Iop_V128HIto64, getWReg(wd)));
+ }
+
+ switch (df) {
+ case 0x00: /* INSERT.B */
+ DIP("INSERT.B w%d[%d], r%d", wd, n, ws);
+
+ if (n >= 8) {
+ n -= 8;
+ } else {
+ hi = 0;
+ }
+
+ n <<= 3;
+ mask = 0xFFull;
+ break;
+
+ case 0x20: /* INSERT.H */
+ DIP("INSERT.H w%d[%d], r%d", wd, n, ws);
+
+ if (n >= 4) {
+ n -= 4;
+ } else {
+ hi = 0;
+ }
+
+ n <<= 4;
+ mask = 0xFFFFull;
+ break;
+
+ case 0x30: /* INSERT.W */
+ DIP("INSERT.W w%d[%d], r%d", wd, n, ws);
+
+ if (n >= 2) {
+ n -= 2;
+ } else {
+ hi = 0;
+ }
+
+ n <<= 5;
+ mask = 0xFFFFFFFFull;
+ break;
+
+ default:
+ return -1;
+ }
+
+ if (hi) {
+ t4 = newTemp(Ity_I64);
+ src = &t2;
+ dst = &t4;
+ t3 = t1;
+ } else {
+ t3 = newTemp(Ity_I64);
+ src = &t1;
+ dst = &t3;
+ t4 = t2;
+ }
+
+ mask <<= n;
+ assign(*dst,
+ binop(Iop_Or64,
+ binop(Iop_And64, mkexpr(*src), mkU64(~mask)),
+ binop(Iop_And64,
+ binop(Iop_Shl64, mkexpr(t5), mkU8(n)),
+ mkU64(mask))));
+ putWReg(wd,
+ binop(Iop_64HLtoV128, mkexpr(t4), mkexpr(t3)));
+ break;
+ }
+
+ case 0x05: { /* INSVE.df */
+ switch (df) {
+ case 0x00: { /* INSVE.B */
+ DIP("INSVE.B w%d[%d], w%d[0]", wd, n, ws);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(wd));
+ assign(t2, getWReg(ws));
+ Int i;
+ IRTemp tmp[16];
+
+ for (i = 0; i < 16; i++) {
+ tmp[i] = newTemp(Ity_I8);
+
+ if (n == i)
+ assign(tmp[i],
+ binop(Iop_GetElem8x16,
+ mkexpr(t2), mkU8(0x0)));
+ else
+ assign(tmp[i],
+ binop(Iop_GetElem8x16,
+ mkexpr(t1), mkU8(i)));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(tmp[15]),
+ mkexpr(tmp[14])),
+ binop(Iop_8HLto16,
+ mkexpr(tmp[13]),
+ mkexpr(tmp[12]))),
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(tmp[11]),
+ mkexpr(tmp[10])),
+ binop(Iop_8HLto16,
+ mkexpr(tmp[9]),
+ mkexpr(tmp[8])))),
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_8HLto16,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_8HLto16,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))))));
+ break;
+ }
+
+ case 0x20: { /* INSVE.H */
+ DIP("INSVE.H w%d[%d], r%d[0]", wd, n, ws);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(wd));
+ assign(t2, getWReg(ws));
+ Int i;
+ IRTemp tmp[8];
+
+ for (i = 0; i < 8; i++) {
+ tmp[i] = newTemp(Ity_I16);
+
+ if (n == i)
+ assign(tmp[i],
+ binop(Iop_GetElem16x8,
+ mkexpr(t2), mkU8(0x0)));
+ else
+ assign(tmp[i],
+ binop(Iop_GetElem16x8,
+ mkexpr(t1), mkU8(i)));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[7]),
+ mkexpr(tmp[6])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[5]),
+ mkexpr(tmp[4]))),
+ binop(Iop_32HLto64,
+ binop(Iop_16HLto32,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_16HLto32,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0])))));
+ break;
+ }
+
+ case 0x30: { /* INSVE.W */
+ DIP("INSVE.W w%d[%d], r%d[0]", wd, n, ws);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(wd));
+ assign(t2, getWReg(ws));
+ Int i;
+ IRTemp tmp[4];
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_I32);
+
+ if (n == i)
+ assign(tmp[i],
+ binop(Iop_GetElem32x4,
+ mkexpr(t2), mkU8(0x0)));
+ else
+ assign(tmp[i],
+ binop(Iop_GetElem32x4,
+ mkexpr(t1), mkU8(i)));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_32HLto64,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))));
+ break;
+ }
+
+ case 0x38: { /* INSVE.D */
+ DIP("INSVE.D w%d[%d], r%d[0]", wd, n, ws);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, getWReg(wd));
+ assign(t2, getWReg(ws));
+ Int i;
+ IRTemp tmp[2];
+
+ for (i = 0; i < 2; i++) {
+ tmp[i] = newTemp(Ity_I64);
+
+ if (n == i)
+ assign(tmp[i],
+ binop(Iop_GetElem64x2,
+ mkexpr(t2), mkU8(0x0)));
+ else
+ assign(tmp[i],
+ binop(Iop_GetElem64x2,
+ mkexpr(t1), mkU8(i)));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkexpr(tmp[1]), mkexpr(tmp[0])));
+ break;
+ }
+ }
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static Int msa_VEC(UInt cins, UChar wd, UChar ws) { /* VEC */
+ IRTemp t1, t2, t3;
+ UShort operation;
+ UChar wt;
+
+ vassert((cins & 0x03000000) == 0);
+
+ operation = (cins & 0x03E00000) >> 21;
+ wt = (cins & 0x001F0000) >> 16;
+
+ switch (operation) {
+ case 0x00: { /* AND.V */
+ DIP("AND.V w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_AndV128, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x01: { /* OR.V */
+ DIP("OR.V w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x02: { /* NOR.V */
+ DIP("NOR.V w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3,
+ unop(Iop_NotV128,
+ binop(Iop_OrV128, mkexpr(t1), mkexpr(t2))));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x03: { /* XOR.V */
+ DIP("XOR.V w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ assign(t2, getWReg(wt));
+ assign(t3, binop(Iop_XorV128, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x04: { /* BMNZ (ws AND wt) OR (wd AND NOT wt) */
+ DIP("BMNZ.V w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_AndV128,
+ getWReg(ws), getWReg(wt)));
+ assign(t2,
+ binop(Iop_AndV128,
+ getWReg(wd),
+ unop(Iop_NotV128, getWReg(wt))));
+ assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x05: { /* BMZ.V (ws AND NOT wt) OR (wd AND wt) */
+ DIP("BMZ.V w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_AndV128,
+ getWReg(wd), getWReg(wt)));
+ assign(t2,
+ binop(Iop_AndV128,
+ getWReg(ws),
+ unop(Iop_NotV128, getWReg(wt))));
+ assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ case 0x06: { /* BSEL (ws AND NOT wd) OR (wt AND wd) */
+ DIP("BSEL.V w%d, w%d, w%d", wd, ws, wt);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1,
+ binop(Iop_AndV128,
+ getWReg(wd), getWReg(wt)));
+ assign(t2,
+ binop(Iop_AndV128,
+ getWReg(ws),
+ unop(Iop_NotV128, getWReg(wd))));
+ assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
+ putWReg(wd, mkexpr(t3));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_2R(UInt cins, UChar wd, UChar ws) { /* 2R */
+ IRTemp t1, t2, t3, t4;
+ IRType ty;
+ UShort operation;
+ UChar df;
+
+ vassert((cins & 0x00200000) == 0);
+
+ operation = (cins & 0x03FC0000) >> 18;
+ df = (cins & 0x00030000) >> 16;
+ ty = mode64 ? Ity_I64 : Ity_I32;
+
+ switch (operation) {
+ case 0xC0: { /* FILL.df */
+ t1 = newTemp(Ity_I64);
+
+ switch (df) {
+ case 0x00: /* FILL.B */
+ DIP("FILL.B w%d, r%d", wd, ws);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I16);
+ t4 = newTemp(Ity_I8);
+ assign(t4, mkNarrowTo8(ty, getIReg(ws)));
+ assign(t3,
+ binop(Iop_8HLto16, mkexpr(t4), mkexpr(t4)));
+ assign(t2,
+ binop(Iop_16HLto32, mkexpr(t3), mkexpr(t3)));
+ assign(t1,
+ binop(Iop_32HLto64, mkexpr(t2), mkexpr(t2)));
+ break;
+
+ case 0x01: /* FILL.H */
+ DIP("FILL.H w%d, r%d", wd, ws);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I16);
+ assign(t3, mkNarrowTo16(ty, getIReg(ws)));
+ assign(t2,
+ binop(Iop_16HLto32, mkexpr(t3), mkexpr(t3)));
+ assign(t1,
+ binop(Iop_32HLto64, mkexpr(t2), mkexpr(t2)));
+ break;
+
+ case 0x02: /* FILL.W */
+ DIP("FILL.W w%d, r%d", wd, ws);
+ t2 = newTemp(Ity_I32);
+ assign(t2, mkNarrowTo32(ty, getIReg(ws)));
+ assign(t1,
+ binop(Iop_32HLto64, mkexpr(t2), mkexpr(t2)));
+ break;
+
+ case 0x03: /* FILL.D */
+ if (mode64) {
+ DIP("FILL.W w%d, r%d", wd, ws);
+ t2 = newTemp(Ity_I32);
+ assign(t1, getIReg(ws));
+ } else {
+ return -2;
+ }
+
+ break;
+
+ default:
+ return -1;
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128, mkexpr(t1), mkexpr(t1)));
+ break;
+ }
+
+ case 0xC1: { /* PCNT.df */
+ switch (df) {
+ case 0x00: /* PCNT.B */
+ DIP("PCNT.B w%d, r%d", wd, ws);
+ putWReg(wd,
+ unop(Iop_Cnt8x16, getWReg(ws)));
+ break;
+
+ case 0x01: /* PCNT.H */
+ DIP("PCNT.H w%d, r%d", wd, ws);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Cnt8x16, getWReg(ws)));
+ assign(t2,
+ binop(Iop_Add16x8,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ binop(Iop_64HLtoV128,
+ mkU64(0x00FF00FF00FF00FFULL),
+ mkU64(0x00FF00FF00FF00FFULL))),
+ binop(Iop_AndV128,
+ binop(Iop_ShrN16x8,
+ mkexpr(t1), mkU8(8)),
+ binop(Iop_64HLtoV128,
+ mkU64(0x00FF00FF00FF00FFULL),
+ mkU64(0x00FF00FF00FF00FFULL)))));
+ putWReg(wd, mkexpr(t2));
+ break;
+
+ case 0x02: /* PCNT.W */
+ DIP("PCNT.W w%d, r%d", wd, ws);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_Cnt8x16, getWReg(ws)));
+ assign(t2,
+ binop(Iop_Add32x4,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ binop(Iop_64HLtoV128,
+ mkU64(0x00FF00FF00FF00FFULL),
+ mkU64(0x00FF00FF00FF00FFULL))),
+ binop(Iop_AndV128,
+ binop(Iop_ShrN32x4,
+ mkexpr(t1), mkU8(8)),
+ binop(Iop_64HLtoV128,
+ mkU64(0x00FF00FF00FF00FFULL),
+ mkU64(0x00FF00FF00FF00FFULL)))));
+ assign(t3,
+ binop(Iop_Add32x4,
+ binop(Iop_AndV128,
+ mkexpr(t2),
+ binop(Iop_64HLtoV128,
+ mkU64(0x0000FFFF0000FFFFULL),
+ mkU64(0x0000FFFF0000FFFFULL))),
+ binop(Iop_AndV128,
+ binop(Iop_ShrN32x4,
+ mkexpr(t2), mkU8(16)),
+ binop(Iop_64HLtoV128,
+ mkU64(0x0000FFFF0000FFFFULL),
+ mkU64(0x0000FFFF0000FFFFULL)))));
+ putWReg(wd, mkexpr(t3));
+ break;
+
+ case 0x03: /* PCNT.D */
+ DIP("PCNT.D w%d, r%d", wd, ws);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);;
+ assign(t1, unop(Iop_Cnt8x16, getWReg(ws)));
+ assign(t2,
+ binop(Iop_Add64x2,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ binop(Iop_64HLtoV128,
+ mkU64(0x00FF00FF00FF00FFULL),
+ mkU64(0x00FF00FF00FF00FFULL))),
+ binop(Iop_AndV128,
+ binop(Iop_ShrN64x2,
+ mkexpr(t1), mkU8(8)),
+ binop(Iop_64HLtoV128,
+ mkU64(0x00FF00FF00FF00FFULL),
+ mkU64(0x00FF00FF00FF00FFULL)))));
+ assign(t3,
+ binop(Iop_Add64x2,
+ binop(Iop_AndV128,
+ mkexpr(t2),
+ binop(Iop_64HLtoV128,
+ mkU64(0x0000FFFF0000FFFFULL),
+ mkU64(0x0000FFFF0000FFFFULL))),
+ binop(Iop_AndV128,
+ binop(Iop_ShrN64x2,
+ mkexpr(t2), mkU8(16)),
+ binop(Iop_64HLtoV128,
+ mkU64(0x0000FFFF0000FFFFULL),
+ mkU64(0x0000FFFF0000FFFFULL)))));
+ assign(t4,
+ binop(Iop_Add64x2,
+ binop(Iop_AndV128,
+ mkexpr(t3),
+ binop(Iop_64HLtoV128,
+ mkU64(0x00000000FFFFFFFFULL),
+ mkU64(0x00000000FFFFFFFFULL))),
+ binop(Iop_AndV128,
+ binop(Iop_ShrN64x2,
+ mkexpr(t3), mkU8(32)),
+ binop(Iop_64HLtoV128,
+ mkU64(0x00000000FFFFFFFFULL),
+ mkU64(0x00000000FFFFFFFFULL)))));
+ putWReg(wd, mkexpr(t4));
+ break;
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0xC2: { /* NLOC.df */
+ switch (df) {
+ case 0x00: /* NLOC.B */
+ DIP("NLOC.B w%d, w%d", wd, ws);
+ putWReg(wd,
+ unop(Iop_Cls8x16, getWReg(ws)));
+ break;
+
+ case 0x01: /* NLOC.H */
+ DIP("NLOC.H w%d, w%d", wd, ws);
+ putWReg(wd,
+ unop(Iop_Cls16x8, getWReg(ws)));
+ break;
+
+ case 0x02: /* NLOC.W */
+ DIP("NLOC.W w%d, w%d", wd, ws);
+ putWReg(wd,
+ unop(Iop_Cls32x4, getWReg(ws)));
+ break;
+
+ case 0x03: /* NLOC.D */
+ DIP("NLOC.D w%d, w%d", wd, ws);
+ t1 = newTemp(Ity_V128);
+ assign(t1, unop(Iop_NotV128, getWReg(ws)));
+ putWReg(wd, unop(Iop_Clz64x2, mkexpr(t1)));
+ break;
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0xC3: { /* NLZC.df */
+ switch (df) {
+ case 0x00: /* NLZC.B */
+ DIP("NLZC.W w%d, w%d", wd, ws);
+ putWReg(wd,
+ unop(Iop_Clz8x16, getWReg(ws)));
+ break;
+
+ case 0x01: /* NLZC.H */
+ DIP("NLZC.H w%d, w%d", wd, ws);
+ putWReg(wd,
+ unop(Iop_Clz16x8, getWReg(ws)));
+ break;
+
+ case 0x02: /* NLZC.W */
+ DIP("NLZC.W w%d, w%d", wd, ws);
+ putWReg(wd,
+ unop(Iop_Clz32x4, getWReg(ws)));
+ break;
+
+ case 0x03: {/* NLZC.D */
+ putWReg(wd,
+ unop(Iop_Clz64x2, getWReg(ws)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_2RF(UInt cins, UChar wd, UChar ws) { /* 2RF */
+ IRTemp t1, t2, t3, t4, t5;
+ UShort operation;
+ UChar df, wt;
+
+ operation = (cins & 0x03FE0000) >> 17;
+ df = (cins & 0x00010000) >> 16;
+ wt = (cins & 0x001F0000) >> 16;
+
+ switch (operation) {
+
+ case 0x190: { /* FCLASS.df */
+ IRTemp t0 = newTemp(Ity_V128);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ t5 = newTemp(Ity_V128);
+
+ switch (df) {
+ case 0x00: { /* FCLASS.W */
+ DIP("FCLASS.W w%d, w%d", wd, ws);
+ assign(t0,
+ binop(Iop_CmpEQ32x4,
+ binop(Iop_AndV128,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0x7F8000007F800000ull),
+ mkU64(0x7F8000007F800000ull))),
+ binop(Iop_64HLtoV128,
+ mkU64(0ull), mkU64(0ull))));
+ assign(t1,
+ binop(Iop_CmpEQ32x4,
+ binop(Iop_AndV128,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0x7F8000007F800000ull),
+ mkU64(0x7F8000007F800000ull))),
+ binop(Iop_64HLtoV128,
+ mkU64(0x7F8000007F800000ull),
+ mkU64(0x7F8000007F800000ull))));
+ assign(t2,
+ binop(Iop_SarN32x4,
+ getWReg(ws), mkU8(31)));
+ assign(t3,
+ binop(Iop_CmpEQ32x4,
+ binop(Iop_AndV128,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0x0040000000400000ull),
+ mkU64(0x0040000000400000ull))),
+ binop(Iop_64HLtoV128,
+ mkU64(0x0040000000400000ull),
+ mkU64(0x0040000000400000ull))));
+ assign(t4,
+ binop(Iop_CmpEQ32x4,
+ binop(Iop_AndV128,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0x007FFFFF007FFFFFULL),
+ mkU64(0x007FFFFF007FFFFFULL))),
+ binop(Iop_64HLtoV128,
+ mkU64(0ull), mkU64(0ull))));
+ assign(t5,
+ binop(Iop_Shl32x4,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ binop(Iop_64HLtoV128,
+ mkU64(0x100000001ull),
+ mkU64(0x100000001ull)))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t0),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ binop(Iop_64HLtoV128,
+ mkU64(0x800000008ull),
+ mkU64(0x800000008ull))),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t4)),
+ binop(Iop_64HLtoV128,
+ mkU64(0x400000004ull),
+ mkU64(0x400000004ull))))),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t1)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t0)),
+ binop(Iop_64HLtoV128,
+ mkU64(0x200000002ull),
+ mkU64(0x200000002ull)))))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t2),
+ binop(Iop_64HLtoV128,
+ mkU64(0x200000002ull),
+ mkU64(0x200000002ull))),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t2)),
+ binop(Iop_64HLtoV128,
+ mkU64(0x600000006ull),
+ mkU64(0x600000006ull))))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t5),
+ binop(Iop_AndV128,
+ binop(Iop_CmpEQ32x4,
+ mkexpr(t5),
+ binop(Iop_64HLtoV128,
+ mkU64(0ull),
+ mkU64(0ull))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t3),
+ binop(Iop_64HLtoV128,
+ mkU64(0x100000001ull),
+ mkU64(0x100000001ull))),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t3)),
+ binop(Iop_64HLtoV128,
+ mkU64(0x200000002ull),
+ mkU64(0x200000002ull)))))));
+ break;
+ }
+
+ case 0x01: { /* FCLASS.D */
+ DIP("FCLASS.D w%d, w%d", wd, ws);
+ assign(t0,
+ binop(Iop_CmpEQ64x2,
+ binop(Iop_AndV128,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0x7FF0000000000000ull),
+ mkU64(0x7FF0000000000000ull))),
+ binop(Iop_64HLtoV128,
+ mkU64(0ull), mkU64(0ull))));
+ assign(t1,
+ binop(Iop_CmpEQ64x2,
+ binop(Iop_AndV128,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0x7FF0000000000000ull),
+ mkU64(0x7FF0000000000000ull))),
+ binop(Iop_64HLtoV128,
+ mkU64(0x7FF0000000000000ull),
+ mkU64(0x7FF0000000000000ull))));
+ assign(t2,
+ binop(Iop_SarN64x2,
+ getWReg(ws), mkU8(63)));
+ assign(t3,
+ binop(Iop_CmpEQ64x2,
+ binop(Iop_AndV128,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0x0008000000000000ull),
+ mkU64(0x0008000000000000ull))),
+ binop(Iop_64HLtoV128,
+ mkU64(0x0008000000000000ull),
+ mkU64(0x0008000000000000ull))));
+ assign(t4,
+ binop(Iop_CmpEQ64x2,
+ binop(Iop_AndV128,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0x000FFFFFFFFFFFFFULL),
+ mkU64(0x000FFFFFFFFFFFFFULL))),
+ binop(Iop_64HLtoV128,
+ mkU64(0ull), mkU64(0ull))));
+ assign(t5,
+ binop(Iop_Shl64x2,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ binop(Iop_64HLtoV128,
+ mkU64(1ull),
+ mkU64(1ull)))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t0),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ binop(Iop_64HLtoV128,
+ mkU64(8ull),
+ mkU64(8ull))),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t4)),
+ binop(Iop_64HLtoV128,
+ mkU64(4ull),
+ mkU64(4ull))))),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t1)),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t0)),
+ binop(Iop_64HLtoV128,
+ mkU64(2ull),
+ mkU64(2ull)))))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t2),
+ binop(Iop_64HLtoV128,
+ mkU64(2ull),
+ mkU64(2ull))),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t2)),
+ binop(Iop_64HLtoV128,
+ mkU64(6ull),
+ mkU64(6ull))))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ mkexpr(t5),
+ binop(Iop_AndV128,
+ binop(Iop_CmpEQ64x2,
+ mkexpr(t5),
+ binop(Iop_64HLtoV128,
+ mkU64(0ull),
+ mkU64(0ull))),
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t3),
+ binop(Iop_64HLtoV128,
+ mkU64(1ull),
+ mkU64(1ull))),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ mkexpr(t3)),
+ binop(Iop_64HLtoV128,
+ mkU64(2ull),
+ mkU64(2ull)))))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x191: { /* FTRUNC_S.df */
+ switch (df) {
+ case 0x00: { /* FTRUNC_S.W */
+ DIP("FTRUNC_S.W w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wd, FTRUNCSW, 1);
+ putWReg(wd, unop(Iop_FtoI32Sx4_RZ, getWReg(ws)));
+ break;
+ }
+
+ case 0x01: { /* FTRUNC_S.D */
+ DIP("FTRUNC_S.D w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wd, FTRUNCSD, 1);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_V128);
+ assign(t3,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ binop(Iop_CmpUN64Fx2,
+ getWReg(ws),
+ getWReg(ws))),
+ binop(Iop_Max64Fx2,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0xC3E0000000000000),
+ mkU64(0xC3E0000000000000)))));
+ assign(t1,
+ unop(Iop_ReinterpF64asI64,
+ binop(Iop_RoundF64toInt,
+ mkU32(0x3),
+ unop(Iop_ReinterpI64asF64,
+ unop(Iop_V128to64,
+ mkexpr(t3))))));
+ assign(t2,
+ unop(Iop_ReinterpF64asI64,
+ binop(Iop_RoundF64toInt,
+ mkU32(0x3),
+ unop(Iop_ReinterpI64asF64,
+ unop(Iop_V128HIto64,
+ mkexpr(t3))))));
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkexpr(t2), mkexpr(t1)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x192: { /* FTRUNC_U.df */
+ switch (df) {
+ case 0x00: { /* FTRUNC_U.W */
+ DIP("FTRUNC_U.W w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wd, FTRUNCUW, 1);
+ putWReg(wd, unop(Iop_FtoI32Ux4_RZ, getWReg(ws)));
+ break;
+ }
+
+ case 0x01: { /* FTRUNC_U.D */
+ DIP("FTRUNC_U.D w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wd, FTRUNCUD, 1);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ assign(t1,
+ binop(Iop_F64toI64U,
+ mkU32(0x3),
+ unop(Iop_ReinterpI64asF64,
+ unop(Iop_V128to64,
+ getWReg(ws)))));
+ assign(t2,
+ binop(Iop_F64toI64U,
+ mkU32(0x3),
+ unop(Iop_ReinterpI64asF64,
+ unop(Iop_V128HIto64,
+ getWReg(ws)))));
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkexpr(t2), mkexpr(t1)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x193: { /* FSQRT.df */
+ switch (df) {
+ case 0x00: { /* FSQRT.W */
+ DIP("FSQRT.W w%d, w%d", wd, ws);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ calculateMSACSR(ws, wd, FSQRTW, 1);
+ putWReg(wd, binop(Iop_Sqrt32Fx4, rm, getWReg(ws)));
+ break;
+ }
+
+ case 0x01: { /* FSQRT.D */
+ DIP("FSQRT.D w%d, w%d", wd, ws);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ calculateMSACSR(ws, wd, FSQRTD, 1);
+ putWReg(wd, binop(Iop_Sqrt64Fx2, rm, getWReg(ws)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x194: { /* FRSQRT.df */
+ switch (df) {
+ case 0x00: { /* FRSQRT.W */
+ DIP("FRSQRT.W w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wd, FRSQRTW, 1);
+ putWReg(wd, unop(Iop_RSqrtEst32Fx4, getWReg(ws)));
+ break;
+ }
+
+ case 0x01: { /* FRSQRT.D */
+ DIP("FRSQRT.D w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wd, FRSQRTD, 1);
+ putWReg(wd, unop(Iop_RSqrtEst64Fx2, getWReg(ws)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x195: { /* FRCP.df */
+ switch (df) { /* FRCP.W */
+ case 0x00: {
+ DIP("FRCP.W w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wd, FRCPW, 1);
+ putWReg(wd, unop(Iop_RecipEst32Fx4, getWReg(ws)));
+ break;
+ }
+
+ case 0x01: { /* FRCP.D */
+ DIP("FRCP.D w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wd, FRCPD, 1);
+ putWReg(wd, unop(Iop_RecipEst64Fx2, getWReg(ws)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x196: { /* FRINT.df */
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ assign(t1, getWReg(ws));
+
+ switch (df) {
+ case 0x00: { /* FRINT.W */
+ DIP("FRINT.W w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wt, FRINTW, 1);
+ assign(t2,
+ binop(Iop_OrV128,
+ binop(Iop_CmpLT32Fx4,
+ mkexpr(t1),
+ binop(Iop_64HLtoV128,
+ mkU64(0xCF000000CF000000ull),
+ mkU64(0xCF000000CF000000ull))),
+ binop(Iop_CmpLT32Fx4,
+ binop(Iop_64HLtoV128,
+ mkU64(0x4F0000004F000000ull),
+ mkU64(0x4F0000004F000000ull)),
+ mkexpr(t1))));
+ assign(t3,
+ binop(Iop_CmpEQ32x4,
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ binop(Iop_64HLtoV128,
+ mkU64(0x0040000000400000ull),
+ mkU64(0x0040000000400000ull))),
+ binop(Iop_64HLtoV128,
+ mkU64(0x0040000000400000ull),
+ mkU64(0x0040000000400000ull))));
+ assign(t4,
+ binop(Iop_CmpUN32Fx4,
+ mkexpr(t1), mkexpr(t1)));
+ IRTemp tmp[4];
+ Int i;
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_I32);
+ assign(tmp[i],
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_I32StoF32, rm,
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_RoundF32toInt, rm,
+ unop(Iop_ReinterpI32asF32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(i))))))));
+ }
+
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_OrV128,
+ mkexpr(t2),
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ unop(Iop_NotV128,
+ mkexpr(t3)))),
+ mkexpr(t1)),
+ binop(Iop_AndV128,
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ mkexpr(t3)),
+ binop(Iop_64HLtoV128,
+ mkU64(0x7FBFFFFF7FBFFFFF),
+ mkU64(0x7FBFFFFF7FBFFFFF)))),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ binop(Iop_OrV128,
+ mkexpr(t2),
+ mkexpr(t4))),
+ binop(Iop_OrV128,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ mkexpr(tmp[3]),
+ mkexpr(tmp[2])),
+ binop(Iop_32HLto64,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0]))),
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ binop(Iop_64HLtoV128,
+ mkU64(0x8000000080000000ull),
+ mkU64(0x8000000080000000ull)))
+ ))));
+ break;
+ }
+
+ case 0x01: { /* FRINT.D */
+ DIP("FRINT.D w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wt, FRINTD, 1);
+ assign(t2,
+ binop(Iop_OrV128,
+ binop(Iop_CmpLT64Fx2,
+ mkexpr(t1),
+ binop(Iop_64HLtoV128,
+ mkU64(0xC3E0000000000000ull),
+ mkU64(0xC3E0000000000000ull))),
+ binop(Iop_CmpLT64Fx2,
+ binop(Iop_64HLtoV128,
+ mkU64(0x43E0000000000000ull),
+ mkU64(0x43E0000000000000ull)),
+ mkexpr(t1))));
+ assign(t3,
+ binop(Iop_CmpEQ64x2,
+ binop(Iop_AndV128,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0x0008000000000000ull),
+ mkU64(0x0008000000000000ull))),
+ binop(Iop_64HLtoV128,
+ mkU64(0x0008000000000000ull),
+ mkU64(0x0008000000000000ull))));
+ assign(t4,
+ binop(Iop_CmpUN64Fx2,
+ mkexpr(t1), mkexpr(t1)));
+ IRTemp tmp[2];
+ Int i;
+
+ for (i = 0; i < 2; i++) {
+ tmp[i] = newTemp(Ity_I64);
+ assign(tmp[i],
+ unop(Iop_ReinterpF64asI64,
+ binop(Iop_I64StoF64, rm,
+ unop(Iop_ReinterpF64asI64,
+ binop(Iop_RoundF64toInt, rm,
+ unop(Iop_ReinterpI64asF64,
+ binop(Iop_GetElem64x2,
+ mkexpr(t1),
+ mkU8(i))))))));
+ }
+
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ binop(Iop_OrV128,
+ mkexpr(t2),
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ unop(Iop_NotV128,
+ mkexpr(t3)))),
+ mkexpr(t1)),
+ binop(Iop_AndV128,
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ mkexpr(t3)),
+ binop(Iop_64HLtoV128,
+ mkU64(0x7FF7FFFFFFFFFFFF),
+ mkU64(0x7FF7FFFFFFFFFFFF)))),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ binop(Iop_OrV128,
+ mkexpr(t2),
+ mkexpr(t4))),
+ binop(Iop_OrV128,
+ binop(Iop_64HLtoV128,
+ mkexpr(tmp[1]),
+ mkexpr(tmp[0])),
+ binop(Iop_AndV128,
+ mkexpr(t1),
+ binop(Iop_64HLtoV128,
+ mkU64(0x8000000000000000ull),
+ mkU64(0x8000000000000000ull))
+ )))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x197: { /* FLOG2.df */
+
+ switch (df) {
+ case 0x00: { /* FLOG2.W */
+ DIP("FLOG2.W w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wt, FLOG2W, 1);
+ putWReg(wd, unop(Iop_Log2_32Fx4, getWReg(ws)));
+ break;
+ }
+
+ case 0x01: { /* FLOG2.D */
+ DIP("FLOG2.D w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wt, FLOG2D, 1);
+ putWReg(wd, unop(Iop_Log2_64Fx2, getWReg(ws)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x198: { /* FEXUPL.df */
+ switch (df) {
+ case 0x00: { /* FEXUPL.W */
+ DIP("FEXUPL.W w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wt, FEXUPLW, 1);
+ putWReg(wd,
+ unop(Iop_F16toF32x4,
+ unop(Iop_V128HIto64,
+ getWReg(ws))));
+ break;
+ }
+
+ case 0x01: { /* FEXUPL.D */
+ DIP("FEXUPL.D w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wt, FEXUPLD, 1);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ assign(t1,
+ unop(Iop_ReinterpF64asI64,
+ unop(Iop_F32toF64,
+ unop(Iop_ReinterpI32asF32,
+ unop(Iop_64to32,
+ unop(Iop_V128HIto64,
+ getWReg(ws)))))));
+ assign(t2,
+ unop(Iop_ReinterpF64asI64,
+ unop(Iop_F32toF64,
+ unop(Iop_ReinterpI32asF32,
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64,
+ getWReg(ws)))))));
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkexpr(t2), mkexpr(t1)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x199: { /* FEXUPR.df */
+ switch (df) {
+ case 0x00: { /* FEXUPR.W */
+ DIP("FEXUPR.W w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wt, FEXUPRW, 1);
+ putWReg(wd,
+ unop(Iop_F16toF32x4,
+ unop(Iop_V128to64,
+ getWReg(ws))));
+ break;
+ }
+
+ case 0x01: { /* FEXUPR.D */
+ DIP("FEXUPR.D w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wt, FEXUPRD, 1);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ assign(t1,
+ unop(Iop_ReinterpF64asI64,
+ unop(Iop_F32toF64,
+ unop(Iop_ReinterpI32asF32,
+ unop(Iop_64to32,
+ unop(Iop_V128to64,
+ getWReg(ws)))))));
+ assign(t2,
+ unop(Iop_ReinterpF64asI64,
+ unop(Iop_F32toF64,
+ unop(Iop_ReinterpI32asF32,
+ unop(Iop_64HIto32,
+ unop(Iop_V128to64,
+ getWReg(ws)))))));
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkexpr(t2), mkexpr(t1)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x19A: { /* FFQL.df */
+ switch (df) {
+ case 0x00: { /* FFQL.W */
+ DIP("FFQL.W w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wt, FFQLW, 1);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_I64);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ assign(t1,
+ binop(Iop_SarN32x4,
+ binop(Iop_InterleaveHI16x8,
+ getWReg(ws),
+ getWReg(ws)),
+ mkU8(16)));
+ assign(t2,
+ binop(Iop_32HLto64,
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_I32StoF32, rm,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(1)))),
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_I32StoF32, rm,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(0))))));
+ assign(t3,
+ binop(Iop_32HLto64,
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_I32StoF32, rm,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(3)))),
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_I32StoF32, rm,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(2))))));
+ putWReg(wd,
+ triop(Iop_Div32Fx4, rm,
+ binop(Iop_64HLtoV128,
+ mkexpr(t3), mkexpr(t2)),
+ binop(Iop_64HLtoV128,
+ mkU64(0x4700000047000000),
+ mkU64(0x4700000047000000))));
+ break;
+ }
+
+ case 0x01: { /* FFQL.D */
+ DIP("FFQL.D w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wt, FFQLD, 1);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_I64);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ assign(t1,
+ binop(Iop_SarN64x2,
+ binop(Iop_InterleaveHI32x4,
+ getWReg(ws),
+ getWReg(ws)),
+ mkU8(32)));
+ assign(t2,
+ unop(Iop_ReinterpF64asI64,
+ binop(Iop_I64StoF64, rm,
+ unop(Iop_V128to64,
+ mkexpr(t1)))));
+ assign(t3,
+ unop(Iop_ReinterpF64asI64,
+ binop(Iop_I64StoF64, rm,
+ unop(Iop_V128HIto64,
+ mkexpr(t1)))));
+ putWReg(wd,
+ triop(Iop_Div64Fx2, rm,
+ binop(Iop_64HLtoV128,
+ mkexpr(t3), mkexpr(t2)),
+ binop(Iop_64HLtoV128,
+ mkU64(0x41E0000000000000),
+ mkU64(0x41E0000000000000))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x19B: { /* FFQR.df */
+ switch (df) {
+ case 0x00: { /* FFQR.W */
+ DIP("FFQR.W w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wt, FFQRW, 1);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_I64);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ assign(t1,
+ binop(Iop_SarN32x4,
+ binop(Iop_InterleaveLO16x8,
+ getWReg(ws),
+ getWReg(ws)),
+ mkU8(16)));
+ assign(t2,
+ binop(Iop_32HLto64,
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_I32StoF32, rm,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(1)))),
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_I32StoF32, rm,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(0))))));
+ assign(t3,
+ binop(Iop_32HLto64,
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_I32StoF32, rm,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(3)))),
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_I32StoF32, rm,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1),
+ mkU8(2))))));
+ putWReg(wd,
+ triop(Iop_Div32Fx4, rm,
+ binop(Iop_64HLtoV128,
+ mkexpr(t3), mkexpr(t2)),
+ binop(Iop_64HLtoV128,
+ mkU64(0x4700000047000000),
+ mkU64(0x4700000047000000))));
+ break;
+ }
+
+ case 0x01: { /* FFQR.D */
+ DIP("FFQR.D w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wt, FFQRD, 1);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_I64);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ assign(t1,
+ binop(Iop_SarN64x2,
+ binop(Iop_InterleaveLO32x4,
+ getWReg(ws),
+ getWReg(ws)),
+ mkU8(32)));
+ assign(t2,
+ unop(Iop_ReinterpF64asI64,
+ binop(Iop_I64StoF64, rm,
+ unop(Iop_V128to64,
+ mkexpr(t1)))));
+ assign(t3,
+ unop(Iop_ReinterpF64asI64,
+ binop(Iop_I64StoF64, rm,
+ unop(Iop_V128HIto64,
+ mkexpr(t1)))));
+ putWReg(wd,
+ triop(Iop_Div64Fx2, rm,
+ binop(Iop_64HLtoV128,
+ mkexpr(t3), mkexpr(t2)),
+ binop(Iop_64HLtoV128,
+ mkU64(0x41E0000000000000),
+ mkU64(0x41E0000000000000))));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x19C: { /* FTINT_S.df */
+ switch (df) { /* FTINT_S.W */
+ case 0x00: {
+ DIP("FTINT_S.W w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wd, FTINT_SW, 1);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_I32);
+ assign(t3,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ binop(Iop_CmpUN32Fx4,
+ getWReg(ws),
+ getWReg(ws))),
+ binop(Iop_Max32Fx4,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0xCF000000CF000000),
+ mkU64(0xCF000000CF000000)))));
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ assign(t1,
+ binop(Iop_32HLto64,
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_RoundF32toInt, rm,
+ unop(Iop_ReinterpI32asF32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t3),
+ mkU8(1))))),
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_RoundF32toInt, rm,
+ unop(Iop_ReinterpI32asF32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t3),
+ mkU8(0)))))));
+ assign(t2,
+ binop(Iop_32HLto64,
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_RoundF32toInt, rm,
+ unop(Iop_ReinterpI32asF32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t3),
+ mkU8(3))))),
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_RoundF32toInt, rm,
+ unop(Iop_ReinterpI32asF32,
+ binop(Iop_GetElem32x4,
+ mkexpr(t3),
+ mkU8(2)))))));
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkexpr(t2), mkexpr(t1)));
+ break;
+ }
+
+ case 0x01: { /* FTINT_S.D */
+ DIP("FTINT_S.D w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wd, FTINT_SD, 1);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_V128);
+ assign(t3,
+ binop(Iop_AndV128,
+ unop(Iop_NotV128,
+ binop(Iop_CmpUN64Fx2,
+ getWReg(ws),
+ getWReg(ws))),
+ binop(Iop_Max64Fx2,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0xC3E0000000000000),
+ mkU64(0xC3E0000000000000)))));
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ assign(t1,
+ unop(Iop_ReinterpF64asI64,
+ binop(Iop_RoundF64toInt, rm,
+ unop(Iop_ReinterpI64asF64,
+ unop(Iop_V128to64,
+ mkexpr(t3))))));
+ assign(t2,
+ unop(Iop_ReinterpF64asI64,
+ binop(Iop_RoundF64toInt, rm,
+ unop(Iop_ReinterpI64asF64,
+ unop(Iop_V128HIto64,
+ mkexpr(t3))))));
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkexpr(t2), mkexpr(t1)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x19D: {/* FTINT_U.df */
+ switch (df) { /* FTINT_U.W */
+ case 0x00: {
+ DIP("FTINT_U.W w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wd, FTINT_UW, 1);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_V128);
+ t4 = newTemp(Ity_V128);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ assign(t1,
+ binop(Iop_32HLto64,
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_RoundF32toInt, rm,
+ unop(Iop_ReinterpI32asF32,
+ binop(Iop_GetElem32x4,
+ getWReg(ws),
+ mkU8(1))))),
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_RoundF32toInt, rm,
+ unop(Iop_ReinterpI32asF32,
+ binop(Iop_GetElem32x4,
+ getWReg(ws),
+ mkU8(0)))))));
+ assign(t2,
+ binop(Iop_32HLto64,
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_RoundF32toInt, rm,
+ unop(Iop_ReinterpI32asF32,
+ binop(Iop_GetElem32x4,
+ getWReg(ws),
+ mkU8(3))))),
+ unop(Iop_ReinterpF32asI32,
+ binop(Iop_RoundF32toInt, rm,
+ unop(Iop_ReinterpI32asF32,
+ binop(Iop_GetElem32x4,
+ getWReg(ws),
+ mkU8(2)))))));
+ assign(t3,
+ unop(Iop_NotV128,
+ binop(Iop_SarN32x4,
+ getWReg(ws),
+ mkU8(31))));
+ assign(t4,
+ binop(Iop_CmpLT32Fx4,
+ getWReg(ws),
+ binop(Iop_64HLtoV128,
+ mkU64(0x4EFFFFFF4EFFFFFF),
+ mkU64(0x4EFFFFFF4EFFFFFF))));
+ putWReg(wd,
+ binop(Iop_OrV128,
+ binop(Iop_AndV128,
+ mkexpr(t4),
+ binop(Iop_AndV128,
+ binop(Iop_64HLtoV128,
+ mkexpr(t2),
+ mkexpr(t1)),
+ mkexpr(t3))),
+ binop(Iop_AndV128,
+ unop(Iop_NotV128, mkexpr(t4)),
+ unop(Iop_FtoI32Ux4_RZ,
+ getWReg(ws)))));
+ break;
+ }
+
+ case 0x01: { /* FTINT_U.D */
+ DIP("FTINT_U.D w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wd, FTINT_UD, 1);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ IRExpr *rm = get_IR_roundingmode_MSA();
+ assign(t1,
+ binop(Iop_F64toI64U, rm,
+ unop(Iop_ReinterpI64asF64,
+ unop(Iop_V128to64,
+ getWReg(ws)))));
+ assign(t2,
+ binop(Iop_F64toI64U, rm,
+ unop(Iop_ReinterpI64asF64,
+ unop(Iop_V128HIto64,
+ getWReg(ws)))));
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkexpr(t2), mkexpr(t1)));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ break;
+ }
+
+ case 0x19E: { /* FFINT_S.df */
+ t1 = newTemp(Ity_V128);
+ assign(t1, getWReg(ws));
+ IRExpr *rm = get_IR_roundingmode_MSA();
+
+ switch (df) {
+ case 0x00: { /* FFINT_S.W */
+ DIP("FFINT_S.W w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wt, FFINTSW, 1);
+ IRTemp tmp[4];
+ Int i;
+
+ for (i = 0; i < 4; i++) {
+ tmp[i] = newTemp(Ity_F32);
+ assign(tmp[i],
+ binop(Iop_I32StoF32, rm,
+ binop(Iop_GetElem32x4,
+ mkexpr(t1), mkU8(i))));
+ }
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ binop(Iop_32HLto64,
+ unop(Iop_ReinterpF32asI32,
+ mkexpr(tmp[3])),
+ unop(Iop_ReinterpF32asI32,
+ mkexpr(tmp[2]))),
+ binop(Iop_32HLto64,
+ unop(Iop_ReinterpF32asI32,
+ mkexpr(tmp[1])),
+ unop(Iop_ReinterpF32asI32,
+ mkexpr(tmp[0])))));
+ break;
+ }
- putIReg(rt, binop(Iop_Or32,
- mkexpr(t1),
- binop(Iop_And32,
- getIReg(rs), mkexpr(t2))));
+ case 0x01: { /* FFINT_S.D */
+ DIP("FFINT_S.D w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wt, FFINTSD, 1);
+ IRTemp tmp[2];
+ Int i;
+
+ for (i = 0; i < 2; i++) {
+ tmp[i] = newTemp(Ity_F64);
+ assign(tmp[i],
+ binop(Iop_I64StoF64, rm,
+ binop(Iop_GetElem64x2,
+ mkexpr(t1), mkU8(i))));
}
+
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ unop(Iop_ReinterpF64asI64,
+ mkexpr(tmp[1])),
+ unop(Iop_ReinterpF64asI64,
+ mkexpr(tmp[0]))));
break;
}
- case 0x1: { /* PREPEND */
- DIP("prepend r%u, r%u, %u", 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)));
+ default:
+ return -1;
+ }
- 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)));
+ break;
+ }
- assign(t3, unop(Iop_Not32,
- binop(Iop_Shl32,
- mkU32(0xffffffff),
- unop(Iop_32to8, mkexpr(t2)))));
+ case 0x19F: { /* FFINT_U.df */
+ IRExpr *rm = get_IR_roundingmode_MSA();
- putIReg(rt, binop(Iop_Or32,
- mkexpr(t1),
- binop(Iop_Shl32,
- binop(Iop_And32,
- getIReg(rs),
- mkexpr(t3)),
- mkU8(32-rd))));
- }
- }
+ switch (df) {
+ case 0x00: { /* FFINT_U.W */
+ DIP("FFINT_U.W w%d, w%d", wd, ws);
+ calculateMSACSR(ws, wt, FFINT_UW, 1);
+ putWReg(wd, unop(Iop_I32UtoFx4, getWReg(ws)));
break;
}
- case 0x10: { /* BALIGN */
- DIP("balign r%u, r%u, %u", 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)));
- }
+ case 0x01: { /* FFINT_U.D */
+ DIP("FFINT_U.D w%d, w%d",
+ wd, ws);
+ calculateMSACSR(ws, wt,
+ FFINT_UD, 1);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ assign(t1,
+ unop(Iop_ReinterpF64asI64,
+ binop(Iop_I64UtoF64, rm,
+ unop(Iop_V128to64,
+ getWReg(ws)))));
+ assign(t2,
+ unop(Iop_ReinterpF64asI64,
+ binop(Iop_I64UtoF64, rm,
+ unop(Iop_V128HIto64,
+ getWReg(ws)))));
+ putWReg(wd,
+ binop(Iop_64HLtoV128,
+ mkexpr(t2), mkexpr(t1)));
break;
}
- default:
- return -1;
- }
- break; /* end of APPEND */
+
+ default:
+ return -1;
}
- default:
- return -1;
+
+ break;
}
- break;
- }
+
default:
- return -1;
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_MI10_load(UInt cins, UChar wd, UChar ws) { /* MI10 (0x20) */
+ IRTemp t1;
+ UShort i10;
+ UChar df;
+
+ i10 = (cins & 0x03FF0000) >> 16;
+ df = cins & 0x00000003;
+
+ switch (df) {
+ case 0x00: { /* LD.B */
+ DIP("LD.B w%d, %d(r%d)", wd, ws, i10);
+ LOAD_STORE_PATTERN_MSA(i10);
+ putWReg(wd, load(Ity_V128, mkexpr(t1)));
+ break;
+ }
+
+ case 0x01: { /* LD.H */
+ DIP("LD.H w%d, %d(r%d)", wd, ws, i10);
+ LOAD_STORE_PATTERN_MSA(i10 << 1);
+#if defined (_MIPSEL)
+ putWReg(wd, load(Ity_V128, mkexpr(t1)));
+#elif defined (_MIPSEB)
+ putWReg(wd,
+ unop(Iop_Reverse8sIn16_x8,
+ load(Ity_V128, mkexpr(t1))));
+#endif
+ break;
+ }
+
+ case 0x02: { /* LD.W */
+ DIP("LD.W w%d, %d(r%d)", wd, ws, i10);
+ LOAD_STORE_PATTERN_MSA(i10 << 2);
+#if defined (_MIPSEL)
+ putWReg(wd, load(Ity_V128, mkexpr(t1)));
+#elif defined (_MIPSEB)
+ putWReg(wd,
+ unop(Iop_Reverse8sIn32_x4,
+ load(Ity_V128, mkexpr(t1))));
+#endif
+ break;
+ }
+
+ case 0x03: { /* LD.D */
+ DIP("LD.D w%d, %d(r%d)", wd, ws, i10);
+ LOAD_STORE_PATTERN_MSA(i10 << 3);
+#if defined (_MIPSEL)
+ putWReg(wd, load(Ity_V128, mkexpr(t1)));
+#elif defined (_MIPSEB)
+ putWReg(wd,
+ unop(Iop_Reverse8sIn64_x2,
+ load(Ity_V128, mkexpr(t1))));
+#endif
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static Int msa_MI10_store(UInt cins, UChar wd, UChar ws) { /* MI10 (0x24) */
+ IRTemp t1;
+ UShort i10;
+ UChar df;
+
+ df = cins & 0x00000003;
+ i10 = (cins & 0x03FF0000) >> 16;
+
+ switch (df) {
+ case 0x00: { /* ST.B */
+ DIP("ST.B w%d, %d(r%d)", wd, ws, i10);
+ LOAD_STORE_PATTERN_MSA(i10);
+ store(mkexpr(t1), getWReg(wd));
+ break;
+ }
+
+ case 0x01: { /* ST.H */
+ DIP("ST.H w%d, %d(r%d)", wd, ws, i10);
+ LOAD_STORE_PATTERN_MSA(i10 << 1);
+#if defined (_MIPSEL)
+ store(mkexpr(t1), getWReg(wd));
+#elif defined (_MIPSEB)
+ store(mkexpr(t1),
+ unop(Iop_Reverse8sIn16_x8, getWReg(wd)));
+#endif
+ break;
+ }
+
+ case 0x02: { /* ST.W */
+ DIP("ST.W w%d, %d(r%d)", wd, ws, i10);
+ LOAD_STORE_PATTERN_MSA(i10 << 2);
+#if defined (_MIPSEL)
+ store(mkexpr(t1), getWReg(wd));
+#elif defined (_MIPSEB)
+ store(mkexpr(t1),
+ unop(Iop_Reverse8sIn32_x4, getWReg(wd)));
+#endif
+ break;
+ }
+
+ case 0x03: { /* ST.D */
+ DIP("ST.D w%d, %d(r%d)", wd, ws, i10);
+ LOAD_STORE_PATTERN_MSA(i10 << 3);
+#if defined (_MIPSEL)
+ store(mkexpr(t1), getWReg(wd));
+#elif defined (_MIPSEB)
+ store(mkexpr(t1),
+ unop(Iop_Reverse8sIn64_x2, getWReg(wd)));
+#endif
+ break;
+ }
+
+ default:
+ return -1;
}
+
return 0;
}
+/*------------------------------------------------------------*/
+/*--- Disassemble a single MIPS MSA (SIMD) instruction ---*/
+/*--- Return values: ---*/
+/*--- 0: Success ---*/
+/*--- -1: Decode failure (unknown instruction) ---*/
+/*--- -2: Illegal instruction ---*/
+/*------------------------------------------------------------*/
+static Int disMSAInstr_MIPS_WRK ( UInt cins ) {
+ UChar minor_opcode, wd, ws;
+
+ vassert(has_msa);
+ vassert((cins & 0xFC000000) == 0x78000000);
+
+ minor_opcode = (cins & 0x20) > 0 ? (cins & 0x3C) : (cins & 0x3F);
+ wd = (cins & 0x000007C0) >> 6;
+ ws = (cins & 0x0000F800) >> 11;
+
+ switch (minor_opcode) {
+ case 0x0:
+ return msa_I8_logical(cins, wd, ws);
+
+ case 0x01:
+ return msa_I8_branch(cins, wd, ws);
+
+ case 0x02:
+ return msa_I8_shift(cins, wd, ws);
+
+ case 0x06:
+ return msa_I5_06(cins, wd, ws);
+
+ case 0x07:
+ return msa_I5_07(cins, wd, ws);
+
+ case 0x09:
+ return msa_BIT_09(cins, wd, ws);
+
+ case 0x0A:
+ return msa_BIT_0A(cins, wd, ws);
+
+ case 0x0D:
+ return msa_3R_0D(cins, wd, ws);
+
+ case 0x0E:
+ return msa_3R_0E(cins, wd, ws);
+
+ case 0x0F:
+ return msa_3R_0F(cins, wd, ws);
+
+ case 0x10:
+ return msa_3R_10(cins, wd, ws);
+
+ case 0x11:
+ return msa_3R_11(cins, wd, ws);
+
+ case 0x12:
+ return msa_3R_12(cins, wd, ws);
+
+ case 0x13:
+ return msa_3R_13(cins, wd, ws);
+
+ case 0x14:
+ return msa_3R_14(cins, wd, ws);
+
+ case 0x15:
+ return msa_3R_15(cins, wd, ws);
+
+ case 0x19:
+ return msa_ELM(cins, wd, ws);
+
+ case 0x1A:
+ return msa_3R_1A(cins, wd, ws);
+
+ case 0x1B:
+ return msa_3R_1B(cins, wd, ws);
+
+ case 0x1C:
+ return msa_3R_1C(cins, wd, ws);
+
+ case 0x1E:
+ if ((cins & 0x03000000) == 0)
+ return msa_VEC(cins, wd, ws);
+ else if ((cins & 0x00200000) == 0)
+ return msa_2R(cins, wd, ws);
+ else
+ return msa_2RF(cins, wd, ws);
+
+ case 0x20:
+ return msa_MI10_load(cins, wd, ws);
+
+ case 0x24:
+ return msa_MI10_store(cins, wd, ws);
+ }
+
+ return -1;
+}
+
/*------------------------------------------------------------*/
/*--- Disassemble a single instruction ---*/
/*------------------------------------------------------------*/
break;
} else
goto decode_failure;
+ } else if (fmt >= 0x1c && has_msa) { /* BNZ.df */
+ Int df = fmt & 3;
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ft));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(0), mkU64(0)));
+
+ switch (df) {
+ case 0x00: { /* BNZ.B */
+ DIP("BNZ.B w%d, %d", ft, imm);
+ assign(t3, binop(Iop_CmpEQ8x16, mkexpr(t1), mkexpr(t2)));
+ break;
+ }
+
+ case 0x01: { /* BNZ.H */
+ DIP("BNZ.H w%d, %d", ft, imm);
+ assign(t3, binop(Iop_CmpEQ16x8, mkexpr(t1), mkexpr(t2)));
+ break;
+ }
+
+ case 0x02: { /* BNZ.W */
+ DIP("BNZ.W w%d, %d", ft, imm);
+ assign(t3, binop(Iop_CmpEQ32x4, mkexpr(t1), mkexpr(t2)));
+ break;
+ }
+
+ case 0x03: { /* BNZ.D */
+ DIP("BNZ.D w%d, %d", ft, imm);
+ assign(t3, binop(Iop_CmpEQ64x2, mkexpr(t1), mkexpr(t2)));
+ break;
+ }
+ }
+
+ assign(t0,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ unop(Iop_V128to32, mkexpr(t3)),
+ unop(Iop_64HIto32, unop(Iop_V128to64, mkexpr(t3)))),
+ binop(Iop_Or32,
+ unop(Iop_64to32,
+ unop(Iop_V128HIto64, mkexpr(t3))),
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64, mkexpr(t3))))));
+ dis_branch(False,
+ binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0)), imm, &bstmt);
+ } else if (fmt == 0x0F && has_msa) { /* BNZ.V */
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_V128);
+ assign(t1, getWReg(ft));
+ assign(t0,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ unop(Iop_V128to32, mkexpr(t1)),
+ unop(Iop_64HIto32, unop(Iop_V128to64, mkexpr(t1)))),
+ binop(Iop_Or32,
+ unop(Iop_64to32, unop(Iop_V128HIto64, mkexpr(t1))),
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64, mkexpr(t1))))));
+ dis_branch(False,
+ binop(Iop_CmpNE32, mkexpr(t0), mkU32(0)), imm, &bstmt);
+ } else if (fmt >= 0x18 && has_msa) { /* BZ.df */
+ Int df = fmt & 3;
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_V128);
+ t2 = newTemp(Ity_V128);
+ t3 = newTemp(Ity_V128);
+ assign(t1, getWReg(ft));
+ assign(t2, binop(Iop_64HLtoV128, mkU64(0), mkU64(0)));
+
+ switch (df) {
+ case 0x00: { /* BZ.B */
+ DIP("BZ.B w%d, %d", ft, imm);
+ assign(t3, binop(Iop_CmpEQ8x16, mkexpr(t1), mkexpr(t2)));
+ break;
+ }
+
+ case 0x01: { /* BZ.H */
+ DIP("BZ.H w%d, %d", ft, imm);
+ assign(t3, binop(Iop_CmpEQ16x8, mkexpr(t1), mkexpr(t2)));
+ break;
+ }
+
+ case 0x02: { /* BZ.W */
+ DIP("BZ.W w%d, %d", ft, imm);
+ assign(t3, binop(Iop_CmpEQ32x4, mkexpr(t1), mkexpr(t2)));
+ break;
+ }
+
+ case 0x03: { /* BZ.D */
+ DIP("BZ.D w%d, %d", ft, imm);
+ assign(t3, binop(Iop_CmpEQ64x2, mkexpr(t1), mkexpr(t2)));
+ break;
+ }
+ }
+
+ assign(t0,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ unop(Iop_V128to32, mkexpr(t3)),
+ unop(Iop_64HIto32, unop(Iop_V128to64, mkexpr(t3)))),
+ binop(Iop_Or32,
+ unop(Iop_64to32, unop(Iop_V128HIto64, mkexpr(t3))),
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64, mkexpr(t3))))));
+ dis_branch(False,
+ binop(Iop_CmpNE32, mkexpr(t0), mkU32(0)), imm, &bstmt);
+ } else if (fmt == 0x0B && has_msa) { /* BZ.V */
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_V128);
+ assign(t1, getWReg(ft));
+ assign(t0,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ unop(Iop_V128to32, mkexpr(t1)),
+ unop(Iop_64HIto32, unop(Iop_V128to64, mkexpr(t1)))),
+ binop(Iop_Or32,
+ unop(Iop_64to32, unop(Iop_V128HIto64, mkexpr(t1))),
+ unop(Iop_64HIto32,
+ unop(Iop_V128HIto64, mkexpr(t1))))));
+ dis_branch(False,
+ binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0)), imm, &bstmt);
} else {
switch (function) {
case 0x4: { /* SQRT.fmt */
DIP("madd.s f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
IRExpr *rm = get_IR_roundingmode();
t1 = newTemp(Ity_F32);
- assign(t1, qop(Iop_MAddF32, rm,
- getLoFromF64(tyF, getFReg(fmt)),
- getLoFromF64(tyF, getFReg(fs)),
- getLoFromF64(tyF, getFReg(ft))));
+ assign(t1, triop(Iop_AddF32, rm, getLoFromF64(tyF, getFReg(fmt)),
+ triop(Iop_MulF32, rm, getLoFromF64(tyF, getFReg(fs)),
+ getLoFromF64(tyF, getFReg(ft)))));
putFReg(fd, mkWidenFromF32(tyF, mkexpr(t1)));
break; /* MADD.S */
}
case 0x21: { /* MADD.D */
DIP("madd.d f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
IRExpr *rm = get_IR_roundingmode();
- putDReg(fd, qop(Iop_MAddF64, rm, getDReg(fmt), getDReg(fs),
- getDReg(ft)));
+ putDReg(fd, triop(Iop_AddF64, rm, getDReg(fmt),
+ triop(Iop_MulF64, rm, getDReg(fs),
+ getDReg(ft))));
break; /* MADD.D */
}
case 0x28: { /* MSUB.S */
DIP("msub.s f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
IRExpr *rm = get_IR_roundingmode();
t1 = newTemp(Ity_F32);
- assign(t1, qop(Iop_MSubF32, rm,
- getLoFromF64(tyF, getFReg(fmt)),
- getLoFromF64(tyF, getFReg(fs)),
- getLoFromF64(tyF, getFReg(ft))));
+ assign(t1, triop(Iop_SubF32, rm,
+ triop(Iop_MulF32, rm, getLoFromF64(tyF, getFReg(fs)),
+ getLoFromF64(tyF, getFReg(ft))),
+ getLoFromF64(tyF, getFReg(fmt))));
putFReg(fd, mkWidenFromF32(tyF, mkexpr(t1)));
break; /* MSUB.S */
}
case 0x29: { /* MSUB.D */
DIP("msub.d f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
IRExpr *rm = get_IR_roundingmode();
- putDReg(fd, qop(Iop_MSubF64, rm, getDReg(fmt), getDReg(fs),
- getDReg(ft)));
+ putDReg(fd, triop(Iop_SubF64, rm, triop(Iop_MulF64, rm, getDReg(fs),
+ getDReg(ft)), getDReg(fmt)));
break; /* MSUB.D */
}
case 0x30: { /* NMADD.S */
DIP("nmadd.s f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
IRExpr *rm = get_IR_roundingmode();
t1 = newTemp(Ity_F32);
- assign(t1, qop(Iop_MAddF32, rm,
- getLoFromF64(tyF, getFReg(fmt)),
- getLoFromF64(tyF, getFReg(fs)),
- getLoFromF64(tyF, getFReg(ft))));
-
+ assign(t1, triop(Iop_AddF32, rm, getLoFromF64(tyF, getFReg(fmt)),
+ triop(Iop_MulF32, rm, getLoFromF64(tyF, getFReg(fs)),
+ getLoFromF64(tyF, getFReg(ft)))));
putFReg(fd, mkWidenFromF32(tyF, unop(Iop_NegF32, mkexpr(t1))));
break; /* NMADD.S */
}
DIP("nmadd.d f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
IRExpr *rm = get_IR_roundingmode();
t1 = newTemp(Ity_F64);
- assign(t1, qop(Iop_MAddF64, rm, getDReg(fmt), getDReg(fs),
- getDReg(ft)));
+ assign(t1, triop(Iop_AddF64, rm, getDReg(fmt),
+ triop(Iop_MulF64, rm, getDReg(fs),
+ getDReg(ft))));
putDReg(fd, unop(Iop_NegF64, mkexpr(t1)));
break; /* NMADD.D */
}
DIP("nmsub.s f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
IRExpr *rm = get_IR_roundingmode();
t1 = newTemp(Ity_F32);
- assign(t1, qop(Iop_MSubF32, rm,
- getLoFromF64(tyF, getFReg(fmt)),
- getLoFromF64(tyF, getFReg(fs)),
- getLoFromF64(tyF, getFReg(ft))));
-
+ assign(t1, triop(Iop_SubF32, rm,
+ triop(Iop_MulF32, rm, getLoFromF64(tyF, getFReg(fs)),
+ getLoFromF64(tyF, getFReg(ft))),
+ getLoFromF64(tyF, getFReg(fmt))));
putFReg(fd, mkWidenFromF32(tyF, unop(Iop_NegF32, mkexpr(t1))));
break; /* NMSUBB.S */
}
DIP("nmsub.d f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
IRExpr *rm = get_IR_roundingmode();
t1 = newTemp(Ity_F64);
- assign(t1, qop(Iop_MSubF64, rm, getDReg(fmt), getDReg(fs),
- getDReg(ft)));
+ assign(t1, triop(Iop_SubF64, rm, triop(Iop_MulF64, rm, getDReg(fs),
+ getDReg(ft)), getDReg(fmt)));
putDReg(fd, unop(Iop_NegF64, mkexpr(t1)));
break; /* NMSUBB.D */
}
}
}
+ case 0x05: /* LSA */
+ if (has_msa) {
+ UInt imm2 = (imm & 0xC0) >> 6;
+ DIP("lsa r%u, r%u, r%u, imm: 0x%x", rd, rs, rt, imm2);
+ if (mode64) {
+ putIReg(rd,
+ unop(Iop_32Sto64,
+ binop(Iop_Add32,
+ binop(Iop_Shl32,
+ unop(Iop_64to32, getIReg(rs)),
+ mkU8(imm2 + 1)),
+ unop(Iop_64to32, getIReg(rt)))));
+ } else {
+ putIReg(rd,
+ binop(Iop_Add32,
+ binop(Iop_Shl32, getIReg(rs), mkU8(imm2 + 1)),
+ getIReg(rt)));
+ }
+ } else {
+ ILLEGAL_INSTRUCTON;
+ }
+ break;
+ case 0x15:{ /* DLSA */
+ UInt imm2 = (imm & 0xC0) >> 6;
+ DIP("dlsa r%u, r%u, r%u, imm: 0x%x", rd, rs, rt, imm2);
+ putIReg(rd,
+ binop(Iop_Add64,
+ binop(Iop_Shl64, getIReg(rs), mkU8(imm2 + 1)),
+ getIReg(rt)));
+ break;
+ }
+
case 0x0D: /* BREAK */
DIP("break 0x%x", trap_code);
if (mode64)
goto decode_failure;
}
+ case 0x1E: /* MIPS MSA (SIMD) */
+ if (has_msa) {
+ Int retVal = disMSAInstr_MIPS_WRK(cins);
+ if (retVal == 0) {
+ break;
+ } else if (retVal == -2) {
+ ILLEGAL_INSTRUCTON
+ break;
+ }
+ }
+ vex_printf("Error occured while trying to decode MIPS MSA "
+ "instruction.\nYour platform probably doesn't support "
+ "MIPS MSA (SIMD) ASE.\n");
+
default:
goto decode_failure;
mode64 = guest_arch != VexArchMIPS32;
fp_mode64 = abiinfo->guest_mips_fp_mode64;
+ has_msa = VEX_MIPS_PROC_MSA(archinfo->hwcaps);
vassert(VEX_MIPS_HOST_FP_MODE(archinfo->hwcaps) >= fp_mode64);
/* Host hwcaps */
static UInt hwcaps_host = 0;
+/* Host CPU has MSA ASE */
+static Bool has_msa = False;
+
/* GPR register class for mips32/64 */
#define HRcGPR(_mode64) ((_mode64) ? HRcInt64 : HRcInt32)
return reg;
}
+static HReg newVRegV ( ISelEnv* env )
+{
+ HReg reg = mkHReg(True/*virtual reg*/, HRcVec128, 0, env->vreg_ctr);
+ env->vreg_ctr++;
+ return reg;
+}
+
static void add_to_sp(ISelEnv * env, UInt n)
{
HReg sp = StackPointer(mode64);
static MIPSRH *iselWordExpr_RH6u_wrk(ISelEnv * env, IRExpr * e);
static MIPSRH *iselWordExpr_RH6u(ISelEnv * env, IRExpr * e);
+/* Compute an I8 into a reg-or-7-bit-unsigned-immediate, the latter being an
+ immediate in the range 1 .. 127 inclusive. Used for doing shift amounts. */
+static MIPSRH *iselWordExpr_RH7u_wrk(ISelEnv * env, IRExpr * e);
+static MIPSRH *iselWordExpr_RH7u(ISelEnv * env, IRExpr * e);
+
/* compute an I8/I16/I32 into a GPR*/
static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e);
static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e);
ISelEnv * env, IRExpr * e);
static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e);
+static HReg iselV128Expr( ISelEnv* env, IRExpr* e );
+static HReg iselV128Expr_wrk( ISelEnv* env, IRExpr* e );
+
static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e);
static MIPSCondCode iselCondCode(ISelEnv * env, IRExpr * e);
addInstr(env, MIPSInstr_MtFCSR(tmp));
}
+static void set_MIPS_rounding_mode_MSA(ISelEnv * env, IRExpr * mode) {
+ /*
+ rounding mode | MIPS | IR
+ ------------------------
+ to nearest | 00 | 00
+ to zero | 01 | 11
+ to +infinity | 10 | 10
+ to -infinity | 11 | 01
+ */
+ /* rm_MIPS32 = XOR(rm_IR , (rm_IR << 1)) & 3 */
+ HReg irrm = iselWordExpr_R(env, mode);
+ HReg tmp = newVRegI(env);
+ HReg msacsr_old = newVRegI(env);
+ MIPSAMode *am_addr;
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, irrm,
+ MIPSRH_Imm(False, 1)));
+ addInstr(env, MIPSInstr_Alu(Malu_XOR, tmp, irrm, MIPSRH_Reg(tmp)));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp, MIPSRH_Imm(False, 3)));
+ /* save old value of MSACSR */
+ addInstr(env, MIPSInstr_MsaElm(MSA_CFCMSA, hregMIPS_GPR0(mode64), msacsr_old,
+ MSA_DFN_W));
+ sub_from_sp(env, 8); /* Move SP down 8 bytes */
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+ /* store old MSACSR to stack */
+ addInstr(env, MIPSInstr_Store(4, am_addr, msacsr_old, mode64));
+ /* set new value of MSACSR */
+ addInstr(env, MIPSInstr_MsaElm(MSA_CTCMSA, tmp, hregMIPS_GPR0(mode64),
+ MSA_DFN_W));
+}
+
+
+static void set_guest_MIPS_rounding_mode_MSA(ISelEnv * env) {
+ /*
+ rounding mode | MIPS | IR
+ ------------------------
+ to nearest | 00 | 00
+ to zero | 01 | 11
+ to +infinity | 10 | 10
+ to -infinity | 11 | 01
+ */
+ /* rm_MIPS32 = XOR(rm_IR , (rm_IR << 1)) & 3 */
+ HReg irrm = newVRegI(env);
+ HReg msacsr_old = newVRegI(env);
+ MIPSAMode *am_addr;
+ MIPSAMode *rm_addr = MIPSAMode_IR(MSACSR_OFFSET(mode64),
+ GuestStatePointer(mode64));
+ addInstr(env, MIPSInstr_Load(4, irrm, rm_addr, mode64));
+ /* save old value of MSACSR */
+ addInstr(env, MIPSInstr_MsaElm(MSA_CFCMSA, hregMIPS_GPR0(mode64), msacsr_old,
+ MSA_DFN_W));
+ sub_from_sp(env, 8); /* Move SP down 8 bytes */
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+ /* store old MSACSR to stack */
+ addInstr(env, MIPSInstr_Store(4, am_addr, msacsr_old, mode64));
+ /* set new value of MSACSR */
+ addInstr(env, MIPSInstr_MsaElm(MSA_CTCMSA, irrm, hregMIPS_GPR0(mode64),
+ MSA_DFN_W));
+}
+
+
static void set_MIPS_rounding_default(ISelEnv * env)
{
HReg fcsr = newVRegI(env);
addInstr(env, MIPSInstr_MtFCSR(fcsr));
}
+static void set_MIPS_rounding_default_MSA(ISelEnv * env) {
+ HReg msacsr = newVRegI(env);
+ /* load as float */
+ MIPSAMode *am_addr;
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+ addInstr(env, MIPSInstr_Load(4, msacsr, am_addr, mode64));
+ add_to_sp(env, 8); /* Reset SP */
+ /* set new value of FCSR*/
+ addInstr(env, MIPSInstr_MsaElm(MSA_CTCMSA, msacsr, hregMIPS_GPR0(mode64),
+ MSA_DFN_W));
+}
+
/*---------------------------------------------------------*/
/*--- ISEL: Misc helpers ---*/
/*---------------------------------------------------------*/
if (LIKELY(!is_IRExpr_VECRET_or_GSPTR(arg)))
aTy = typeOfIRExpr(env->type_env, arg);
- if (aTy == Ity_I32 || mode64) {
+ if (aTy == Ity_I32 || (mode64 && aTy != Ity_INVALID)) {
argiregs |= (1 << (argreg + 4));
addInstr(env, mk_iMOVds_RR(argregs[argreg],
iselWordExpr_R(env, arg)));
if (LIKELY(!is_IRExpr_VECRET_or_GSPTR(arg)))
aTy = typeOfIRExpr(env->type_env, arg);
- if (aTy == Ity_I32 || (mode64 && arg->tag != Iex_GSPTR)) {
+ if (aTy == Ity_I32 || (mode64 && aTy != Ity_INVALID)) {
tmpregs[argreg] = iselWordExpr_R(env, arg);
argreg++;
} else if (aTy == Ity_I64) { /* Ity_I64 */
argreg++;
}
else if (arg->tag == Iex_VECRET) {
- // If this happens, it denotes ill-formed IR
- vassert(0);
+ tmpregs[argreg++] = StackPointer(mode64);
+ sub_from_sp(env, 16); /* Move SP down 16 bytes */
}
}
*retloc = mk_RetLoc_simple(RLPri_Int);
break;
case Ity_V128:
- vassert(0); // ATC
*retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 0);
*stackAdjustAfterCall = 16;
break;
return r_dst;
}
+ if (!mode64 && (e->Iex.Binop.op == Iop_CasCmpEQ64
+ || e->Iex.Binop.op == Iop_CmpEQ64)) {
+ HReg tmp1, tmp2, tmp3, tmp4;
+ HReg dst1 = newVRegI(env);
+ HReg dst2 = newVRegI(env);
+ iselInt64Expr(&tmp1, &tmp2, env, e->Iex.Binop.arg1);
+ iselInt64Expr(&tmp3, &tmp4, env, e->Iex.Binop.arg2);
+ addInstr(env, MIPSInstr_Cmp(False, True, dst1, tmp1, tmp3, MIPScc_EQ));
+ addInstr(env, MIPSInstr_Cmp(False, True, dst2, tmp2, tmp4, MIPScc_EQ));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, dst1, dst1, MIPSRH_Reg(dst2)));
+ return dst1;
+ }
+
/* Cmp*32*(x,y) ? */
if (e->Iex.Binop.op == Iop_CmpEQ32
+ || e->Iex.Binop.op == Iop_CmpEQ8
|| e->Iex.Binop.op == Iop_CmpEQ16
|| e->Iex.Binop.op == Iop_CmpNE32
|| e->Iex.Binop.op == Iop_CmpNE64
cc = MIPScc_EQ;
size32 = True;
break;
+ case Iop_CmpEQ8:
case Iop_CmpEQ16:
cc = MIPScc_EQ;
size32 = True;
return r_tmpR;
}
+ if (e->Iex.Binop.op == Iop_MullU8 ||
+ e->Iex.Binop.op == Iop_MullS8 ||
+ e->Iex.Binop.op == Iop_MullU16 ||
+ e->Iex.Binop.op == Iop_MullS16) {
+ Bool syned = toBool((e->Iex.Binop.op == Iop_MullS8) ||
+ (e->Iex.Binop.op == Iop_MullS16));
+ HReg r_dst = newVRegI(env);
+ HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ if (syned) {
+ Int no_bits = (e->Iex.Binop.op == Iop_MullS16) ? 16 : 24;
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True,
+ r_srcL, r_srcL,
+ MIPSRH_Imm(False, no_bits)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRA, True,
+ r_srcL, r_srcL,
+ MIPSRH_Imm(False, no_bits)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True,
+ r_srcR, r_srcR,
+ MIPSRH_Imm(False, no_bits)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRA, True,
+ r_srcR, r_srcR,
+ MIPSRH_Imm(False, no_bits)));
+ addInstr(env, MIPSInstr_Mul(r_dst, r_srcL, r_srcR));
+
+ } else {
+ addInstr(env, MIPSInstr_Mult(syned, r_srcL, r_srcR));
+ addInstr(env, MIPSInstr_Mflo(r_dst));
+ }
+ return r_dst;
+ }
+
if (e->Iex.Binop.op == Iop_CmpF64) {
HReg r_srcL, r_srcR;
if (mode64) {
return r_dst;
}
+ if (e->Iex.Binop.op == Iop_DivS32 ||
+ e->Iex.Binop.op == Iop_DivU32 ||
+ (e->Iex.Binop.op == Iop_DivS64 && mode64) ||
+ (e->Iex.Binop.op == Iop_DivU64 && mode64)) {
+ HReg r_dst = newVRegI(env);
+ Bool syned = toBool(e->Iex.Binop.op == Iop_DivS32 ||
+ e->Iex.Binop.op == Iop_DivS64);
+ Bool div32 = toBool(e->Iex.Binop.op == Iop_DivS32 ||
+ e->Iex.Binop.op == Iop_DivU32);
+ HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ addInstr(env, MIPSInstr_Div(syned, div32, r_srcL, r_srcR));
+ addInstr(env, MIPSInstr_Mflo(r_dst));
+ return r_dst;
+ }
+
if (e->Iex.Binop.op == Iop_8HLto16
|| e->Iex.Binop.op == Iop_16HLto32) {
HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
return r_dst;
}
+ if (e->Iex.Binop.op == Iop_F32toI32U) {
+ HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
+ HReg tmpD = newVRegD(env);
+ HReg r_dst = newVRegI(env);
+ MIPSAMode *am_addr;
+
+ /* CVTLS tmpD, valF */
+ set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
+ addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLS, tmpD, valF));
+ set_MIPS_rounding_default(env);
+
+ sub_from_sp(env, 16); /* Move SP down 16 bytes */
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ /* store as F64 */
+ addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, tmpD,
+ am_addr));
+ /* load as 2xI32 */
+#if defined (_MIPSEL)
+ addInstr(env, MIPSInstr_Load(4, r_dst, am_addr, mode64));
+#elif defined (_MIPSEB)
+ addInstr(env, MIPSInstr_Load(4, r_dst, nextMIPSAModeFloat(am_addr),
+ mode64));
+#endif
+
+ /* Reset SP */
+ add_to_sp(env, 16);
+
+ return r_dst;
+ }
+
+ if (e->Iex.Binop.op == Iop_F64toI64U) {
+ HReg r_src;
+ HReg tmp = newVRegV(env);
+ vassert(has_msa);
+ r_src = iselFltExpr( env, e->Iex.Binop.arg2);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Binop.arg1);
+ addInstr(env, MIPSInstr_Msa2RF(MSA_FTINT_U, MSA_F_DW, tmp, r_src));
+ HReg r_dst = newVRegI(env);
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_S, tmp, r_dst, MSA_DFN_D | 0));
+ set_MIPS_rounding_default_MSA(env);
+ return r_dst;
+ }
+
+ if (e->Iex.Binop.op == Iop_GetElem8x16) {
+ HReg v_src = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg r_dst = newVRegI(env);
+ MIPSRH *tmp = iselWordExpr_RH(env, False, e->Iex.Binop.arg2);
+ vassert(has_msa);
+ switch (tmp->tag) {
+ case Mrh_Imm:
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_U, v_src, r_dst,
+ MSA_DFN_B |
+ (tmp->Mrh.Imm.imm16 & 0x0f)));
+ break;
+
+ case Mrh_Reg: {
+ HReg v_tmp = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SPLAT, MSA_B, v_tmp, v_src,
+ tmp->Mrh.Reg.reg));
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_U, v_tmp, r_dst,
+ MSA_DFN_B));
+ break;
+ }
+ }
+
+ return r_dst;
+ }
+
+
+ if (e->Iex.Binop.op == Iop_GetElem16x8) {
+ HReg v_src = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg r_dst = newVRegI(env);
+ MIPSRH *tmp = iselWordExpr_RH(env, False, e->Iex.Binop.arg2);
+ vassert(has_msa);
+ switch (tmp->tag) {
+ case Mrh_Imm:
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_U, v_src, r_dst,
+ MSA_DFN_H |
+ (tmp->Mrh.Imm.imm16 & 0x07)));
+ break;
+
+ case Mrh_Reg: {
+ HReg v_tmp = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SPLAT, MSA_H, v_tmp, v_src,
+ tmp->Mrh.Reg.reg));
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_U, v_tmp, r_dst,
+ MSA_DFN_H));
+ break;
+ }
+ }
+
+ return r_dst;
+ }
+
+ if (e->Iex.Binop.op == Iop_GetElem32x4) {
+ HReg v_src = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg r_dst = newVRegI(env);
+ MIPSRH *tmp = iselWordExpr_RH(env, False, e->Iex.Binop.arg2);
+ vassert(has_msa);
+ switch (tmp->tag) {
+ case Mrh_Imm:
+ addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, v_src, r_dst,
+ MSA_DFN_W |
+ (tmp->Mrh.Imm.imm16 & 0x03)));
+ break;
+
+ case Mrh_Reg: {
+ HReg v_tmp = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SPLAT, MSA_W, v_tmp, v_src,
+ tmp->Mrh.Reg.reg));
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_S, v_tmp, r_dst,
+ MSA_DFN_W));
+ break;
+ }
+ }
+
+ return r_dst;
+ }
+ if (e->Iex.Binop.op == Iop_GetElem64x2) {
+ vassert(mode64);
+ HReg v_src = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg r_dst = newVRegI(env);
+ MIPSRH *tmp = iselWordExpr_RH(env, False, e->Iex.Binop.arg2);
+ vassert(has_msa);
+ switch (tmp->tag) {
+ case Mrh_Imm:
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_S, v_src, r_dst,
+ MSA_DFN_D |
+ (tmp->Mrh.Imm.imm16 & 0x01)));
+ break;
+
+ case Mrh_Reg: {
+ HReg v_tmp = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SPLAT, MSA_D, v_tmp, v_src,
+ tmp->Mrh.Reg.reg));
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_S, v_tmp, r_dst,
+ MSA_DFN_D));
+ break;
+ }
+ }
+
+ return r_dst;
+ }
+
/* -------- DSP ASE -------- */
/* All used cases involving host-side helper calls. */
void* fn = NULL;
case Iop_64to1:
case Iop_64to8: {
- vassert(mode64);
HReg r_src, r_dst;
UShort mask = (op_unop == Iop_64to1) ? 0x1 : 0xFF;
r_dst = newVRegI(env);
- r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ if (mode64)
+ r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ else {
+ HReg tmp;
+ iselInt64Expr(&tmp, &r_src, env, e->Iex.Unop.arg);
+ }
addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src,
MIPSRH_Imm(False, mask)));
return r_dst;
return rLo; /* and abandon rLo .. poor wee thing :-) */
}
+ case Iop_V128to32: {
+ HReg i_dst = newVRegI(env);
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ vassert(has_msa);
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_S, v_src, i_dst, MSA_DFN_W));
+ return i_dst;
+ }
+
+ case Iop_V128HIto64: {
+ vassert(mode64);
+ vassert(has_msa);
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg reg = newVRegI(env);
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_S, v_src, reg, MSA_DFN_D | 1));
+ return reg;
+ }
+
+ case Iop_V128to64: {
+ vassert(mode64);
+ vassert(has_msa);
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg reg = newVRegI(env);
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_S, v_src, reg, MSA_DFN_D | 0));
+ return reg;
+ }
+
+ case Iop_F32toF16x4: {
+ vassert(mode64);
+ vassert(has_msa);
+ HReg v_arg = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_src = newVRegV(env);
+ set_guest_MIPS_rounding_mode_MSA(env);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FEXDO, MSA_F_WH,
+ v_src, v_arg, v_arg));
+ set_MIPS_rounding_default_MSA(env);
+ HReg reg = newVRegI(env);
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_S, v_src, reg, MSA_DFN_D | 0));
+ return reg;
+ }
+
+
default:
break;
}
/* --------------------- RH6u --------------------- */
-/* Only used in 64-bit mode. */
static MIPSRH *iselWordExpr_RH6u ( ISelEnv * env, IRExpr * e )
{
MIPSRH *ri;
vassert(hregIsVirtual(ri->Mrh.Reg.reg));
return ri;
default:
- vpanic("iselIntExpr_RH6u: unknown mips64 RI tag");
+ vpanic("iselIntExpr_RH6u: unknown RI tag");
}
}
/* default case: calculate into a register and return that */
return MIPSRH_Reg(iselWordExpr_R(env, e));
}
+/* --------------------- RH7u --------------------- */
+
+static MIPSRH *iselWordExpr_RH7u ( ISelEnv * env, IRExpr * e )
+{
+ MIPSRH *ri;
+ ri = iselWordExpr_RH7u_wrk(env, e);
+ /* sanity checks ... */
+ switch (ri->tag) {
+ case Mrh_Imm:
+ vassert(ri->Mrh.Imm.imm16 >= 1 && ri->Mrh.Imm.imm16 <= 127);
+ vassert(!ri->Mrh.Imm.syned);
+ return ri;
+ case Mrh_Reg:
+ vassert(hregClass(ri->Mrh.Reg.reg) == HRcGPR(env->mode64));
+ vassert(hregIsVirtual(ri->Mrh.Reg.reg));
+ return ri;
+ default:
+ vpanic("iselIntExpr_RH7u: unknown RI tag");
+ }
+}
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static MIPSRH *iselWordExpr_RH7u_wrk ( ISelEnv * env, IRExpr * e )
+{
+ IRType ty = typeOfIRExpr(env->type_env, e);
+ vassert(ty == Ity_I8);
+
+ /* special case: immediate */
+ if (e->tag == Iex_Const
+ && e->Iex.Const.con->tag == Ico_U8
+ && e->Iex.Const.con->Ico.U8 >= 1 && e->Iex.Const.con->Ico.U8 <= 127)
+ {
+ return MIPSRH_Imm(False /*unsigned */ ,
+ e->Iex.Const.con->Ico.U8);
+ }
+
+ /* default case: calculate into a register and return that */
+ return MIPSRH_Reg(iselWordExpr_R(env, e));
+}
+
/* --------------------- CONDCODE --------------------- */
}
/*---------------------------------------------------------*/
-/*--- ISEL: Integer expressions (128 bit) ---*/
+/*--- ISEL: Vector expressions (128 bit - SIMD) ---*/
/*---------------------------------------------------------*/
-/* 64-bit mode ONLY: compute a 128-bit value into a register pair,
- which is returned as the first two parameters. As with
- iselWordExpr_R, these may be either real or virtual regs; in any
- case they must not be changed by subsequent code emitted by the
- caller. */
-
-static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
-{
- vassert(env->mode64);
- iselInt128Expr_wrk(rHi, rLo, env, e);
- vassert(hregClass(*rHi) == HRcGPR(env->mode64));
- vassert(hregIsVirtual(*rHi));
- vassert(hregClass(*rLo) == HRcGPR(env->mode64));
- vassert(hregIsVirtual(*rLo));
+/* Compute a vector value into vector register. */
+static HReg iselV128Expr (ISelEnv* env, IRExpr* e) {
+ vassert(has_msa);
+ HReg r = iselV128Expr_wrk(env, e);
+ vassert(hregClass(r) == HRcVec128);
+ vassert(hregIsVirtual(r));
+ return r;
}
/* DO NOT CALL THIS DIRECTLY ! */
-static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env,
- IRExpr * e)
-{
+static HReg iselV128Expr_wrk(ISelEnv* env, IRExpr* e) {
+ IRType ty = typeOfIRExpr(env->type_env, e);
vassert(e);
- vassert(typeOfIRExpr(env->type_env, e) == Ity_I128);
+ vassert(ty == Ity_V128);
- /* read 128-bit IRTemp */
if (e->tag == Iex_RdTmp) {
- lookupIRTempPair(rHi, rLo, env, e->Iex.RdTmp.tmp);
- return;
+ return lookupIRTemp(env, e->Iex.RdTmp.tmp);
}
- /* --------- BINARY ops --------- */
- if (e->tag == Iex_Binop) {
- switch (e->Iex.Binop.op) {
- /* 64 x 64 -> 128 multiply */
- case Iop_MullU64:
- case Iop_MullS64: {
- HReg tLo = newVRegI(env);
- HReg tHi = newVRegI(env);
- Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64);
- HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
- HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
- addInstr(env, MIPSInstr_Mult(syned, r_srcL, r_srcR));
- addInstr(env, MIPSInstr_Mfhi(tHi));
- addInstr(env, MIPSInstr_Mflo(tLo));
- *rHi = tHi;
- *rLo = tLo;
- return;
- }
+ if (e->tag == Iex_Load) {
+ vassert (e->Iex.Load.ty == Ity_V128);
+ HReg v_dst = newVRegV(env);
+ addInstr(env, MIPSInstr_MsaMi10(MSA_LD, 0, iselWordExpr_R(env,
+ e->Iex.Load.addr), v_dst, MSA_B));
+ return v_dst;
+ }
- /* 64HLto128(e1,e2) */
- case Iop_64HLto128:
- *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
- *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
- return;
+ if (e->tag == Iex_Get) {
+ HReg v_dst = newVRegV(env);
+#if defined(_MIPSEB)
+ HReg r_addr = newVRegI(env);
+ addInstr(env, MIPSInstr_Alu(mode64 ? Malu_DADD : Malu_ADD, r_addr, GuestStatePointer(mode64),
+ MIPSRH_Imm(False, e->Iex.Get.offset)));
+ addInstr(env, MIPSInstr_MsaMi10(MSA_LD, 0, r_addr, v_dst, MSA_B));
+#else
+ vassert(!(e->Iex.Get.offset & 7));
+ addInstr(env, MIPSInstr_MsaMi10(MSA_LD, e->Iex.Get.offset >> 3,
+ GuestStatePointer(mode64), v_dst, MSA_D));
+#endif
+ return v_dst;
+ }
- case Iop_DivModU64to64:
- case Iop_DivModS64to64: {
- HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
- HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
- HReg tLo = newVRegI(env);
- HReg tHi = newVRegI(env);
- Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to64);
+ if (e->tag == Iex_Unop) {
+ IROp op_unop = e->Iex.Unop.op;
- addInstr(env, MIPSInstr_Div(syned, False, r_srcL, r_srcR));
- addInstr(env, MIPSInstr_Mfhi(tHi));
- addInstr(env, MIPSInstr_Mflo(tLo));
- *rHi = tHi;
- *rLo = tLo;
- return;
- }
+ switch (op_unop) {
+ case Iop_Abs64x2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_help = newVRegV(env);
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBV, MSA_D, v_help, v_src, v_src));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ADD_A, MSA_D,
+ v_dst, v_src, v_help));
+ return v_dst;
+ }
+
+ case Iop_Abs32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_help = newVRegV(env);
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBV, MSA_W, v_help, v_src, v_src));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ADD_A, MSA_W,
+ v_dst, v_src, v_help));
+ return v_dst;
+ }
+
+ case Iop_Abs16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_help = newVRegV(env);
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBV, MSA_H, v_help, v_src, v_src));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ADD_A, MSA_H,
+ v_dst, v_src, v_help));
+ return v_dst;
+ }
+
+ case Iop_Abs8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_help = newVRegV(env);
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBV, MSA_B, v_help, v_src, v_src));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ADD_A, MSA_B,
+ v_dst, v_src, v_help));
+ return v_dst;
+ }
+
+ case Iop_Cnt8x16: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg res = newVRegV(env);
+ addInstr(env, MIPSInstr_Msa2R(MSA_PCNT, MSA_B, v_src, res));
+ return res;
+ }
+
+ case Iop_NotV128: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ addInstr(env, MIPSInstr_MsaVec(MSA_NORV, v_dst, v_src, v_src));
+ return v_dst;
+ }
+
+ case Iop_Reverse8sIn16_x8: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_tmp = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVEV, MSA_B, v_tmp, v_src, v_src));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVOD, MSA_B, v_src, v_tmp, v_src));
+ return v_src;
+ }
+
+ case Iop_Reverse8sIn32_x4: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_tmp = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVEV, MSA_H, v_tmp, v_src, v_src));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVOD, MSA_H, v_src, v_tmp, v_src));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVEV, MSA_B, v_tmp, v_src, v_src));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVOD, MSA_B, v_src, v_tmp, v_src));
+ return v_src;
+ }
+
+ case Iop_Reverse8sIn64_x2: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_tmp = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVEV, MSA_W, v_tmp, v_src, v_src));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVOD, MSA_W, v_src, v_tmp, v_src));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVEV, MSA_H, v_tmp, v_src, v_src));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVOD, MSA_H, v_src, v_tmp, v_src));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVEV, MSA_B, v_tmp, v_src, v_src));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVOD, MSA_B, v_src, v_tmp, v_src));
+ return v_src;
+ }
+
+ case Iop_Cls8x16: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ addInstr(env, MIPSInstr_Msa2R(MSA_NLOC, MSA_B, v_src, v_dst));
+ return v_dst;
+ }
+
+ case Iop_Cls16x8: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ addInstr(env, MIPSInstr_Msa2R(MSA_NLOC, MSA_H, v_src, v_dst));
+ return v_dst;
+ }
+
+ case Iop_Cls32x4: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ addInstr(env, MIPSInstr_Msa2R(MSA_NLOC, MSA_W, v_src, v_dst));
+ return v_dst;
+ }
+
+ case Iop_Clz8x16: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ addInstr(env, MIPSInstr_Msa2R(MSA_NLZC, MSA_B, v_src, v_dst));
+ return v_dst;
+ }
+
+ case Iop_Clz16x8: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ addInstr(env, MIPSInstr_Msa2R(MSA_NLZC, MSA_H, v_src, v_dst));
+ return v_dst;
+ }
+
+ case Iop_Clz32x4: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ addInstr(env, MIPSInstr_Msa2R(MSA_NLZC, MSA_W, v_src, v_dst));
+ return v_dst;
+ }
+
+ case Iop_Clz64x2: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ addInstr(env, MIPSInstr_Msa2R(MSA_NLZC, MSA_D, v_src, v_dst));
+ return v_dst;
+ }
+
+ case Iop_Abs32Fx4: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ HReg v_help = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FMUL, MSA_F_WH,
+ v_help, v_src, v_src));
+ addInstr(env,
+ MIPSInstr_Msa2RF(MSA_FSQRT, MSA_F_WH, v_dst, v_help));
+ return v_dst;
+ }
+
+ case Iop_Abs64Fx2: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ HReg v_help = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FMUL, MSA_F_DW,
+ v_help, v_src, v_src));
+ addInstr(env,
+ MIPSInstr_Msa2RF(MSA_FSQRT, MSA_F_DW, v_dst, v_help));
+ return v_dst;
+ }
+
+ case Iop_RecipEst32Fx4: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ set_guest_MIPS_rounding_mode_MSA(env);
+ addInstr(env,
+ MIPSInstr_Msa2RF(MSA_FRCP, MSA_F_WH, v_dst, v_src));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_RecipEst64Fx2: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ set_guest_MIPS_rounding_mode_MSA(env);
+ addInstr(env,
+ MIPSInstr_Msa2RF(MSA_FRCP, MSA_F_DW, v_dst, v_src));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_RSqrtEst32Fx4: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ set_guest_MIPS_rounding_mode_MSA(env);
+ addInstr(env,
+ MIPSInstr_Msa2RF(MSA_FRSQRT, MSA_F_WH, v_dst, v_src));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_RSqrtEst64Fx2: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ set_guest_MIPS_rounding_mode_MSA(env);
+ addInstr(env,
+ MIPSInstr_Msa2RF(MSA_FRSQRT, MSA_F_DW, v_dst, v_src));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_F16toF32x4: {
+ HReg v_dst = newVRegV(env);
+
+ if (mode64) {
+ HReg r_src;
+ r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ addInstr(env,
+ MIPSInstr_Msa2R(MSA_FILL, MSA_D, r_src, v_dst));
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_INSERT, r_src, v_dst,
+ MSA_DFN_D | 1));
+ } else {
+ HReg r_srch, r_srcl;
+ iselInt64Expr(&r_srch, &r_srcl, env, e->Iex.Unop.arg);
+ addInstr(env,
+ MIPSInstr_Msa2R(MSA_FILL, MSA_W, r_srcl, v_dst));
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_INSERT, r_srch, v_dst,
+ MSA_DFN_W | 1));
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_INSERT, r_srcl, v_dst,
+ MSA_DFN_W | 2));
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_INSERT, r_srch, v_dst,
+ MSA_DFN_W | 3));
+ }
+
+ addInstr(env,
+ MIPSInstr_Msa2RF(MSA_FEXUPR, MSA_F_WH, v_dst, v_dst));
+ return v_dst;
+ }
+
+ case Iop_I32UtoFx4: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ set_guest_MIPS_rounding_mode_MSA(env);
+ addInstr(env,
+ MIPSInstr_Msa2RF(MSA_FFINT_U, MSA_F_WH, v_dst, v_src));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_FtoI32Sx4_RZ: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa2RF(MSA_FTRUNC_S, MSA_F_WH, v_dst, v_src));
+ return v_dst;
+ }
+
+ case Iop_FtoI32Ux4_RZ: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa2RF(MSA_FTRUNC_U, MSA_F_WH, v_dst, v_src));
+ return v_dst;
+ }
+
+ case Iop_Log2_32Fx4: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa2RF(MSA_FLOG2, MSA_F_WH, v_dst, v_src));
+ return v_dst;
+ }
+
+ case Iop_Log2_64Fx2: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa2RF(MSA_FLOG2, MSA_F_DW, v_dst, v_src));
+ return v_dst;
+ }
+ case Iop_CmpNEZ8x16: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ HReg zero = Zero(mode64);
+ addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, zero, v_dst));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_CEQ, MSA_B, v_dst, v_src, v_dst));
+ addInstr(env, MIPSInstr_MsaVec(MSA_NORV, v_dst, v_dst, v_dst));
+ return v_dst;
+ }
+ case Iop_CmpNEZ16x8: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ HReg zero = Zero(mode64);
+ addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, zero, v_dst));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_CEQ, MSA_H, v_dst, v_src, v_dst));
+ addInstr(env, MIPSInstr_MsaVec(MSA_NORV, v_dst, v_dst, v_dst));
+ return v_dst;
+ }
+ case Iop_CmpNEZ32x4: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ HReg zero = Zero(mode64);
+ addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, zero, v_dst));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_CEQ, MSA_W, v_dst, v_src, v_dst));
+ addInstr(env, MIPSInstr_MsaVec(MSA_NORV, v_dst, v_dst, v_dst));
+ return v_dst;
+ }
+ case Iop_CmpNEZ64x2: {
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_dst = newVRegV(env);
+ HReg zero = Zero(mode64);
+ addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, zero, v_dst));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_CEQ, MSA_D, v_dst, v_src, v_dst));
+ addInstr(env, MIPSInstr_MsaVec(MSA_NORV, v_dst, v_dst, v_dst));
+ return v_dst;
+ }
+ default:
+ vex_printf("iselV128Expr_wrk: Unsupported unop: %u\n", op_unop);
+ }
+ }
+
+ if (e->tag == Iex_Binop) {
+ IROp op_binop = e->Iex.Binop.op;
+
+ switch (op_binop) {
+ case Iop_Add8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ADDV, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Add16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ADDV, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Add32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ADDV, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Add64x2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ADDV, MSA_D,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Sub8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBV, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Sub16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBV, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Sub32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBV, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Sub64x2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBV, MSA_D,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QAdd8Sx16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ADDS_S, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QAdd16Sx8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ADDS_S, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QAdd32Sx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ADDS_S, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QAdd64Sx2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ADDS_S, MSA_D,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QAdd8Ux16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ADDS_U, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QAdd16Ux8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ADDS_U, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QAdd32Ux4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ADDS_U, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QAdd64Ux2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ADDS_U, MSA_D,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QSub8Sx16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBS_S, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QSub16Sx8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBS_S, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QSub32Sx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBS_S, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QSub64Sx2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBS_S, MSA_D,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QSub8Ux16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBS_U, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QSub16Ux8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBS_U, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QSub32Ux4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBS_U, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QSub64Ux2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBS_U, MSA_D,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QDMulHi32Sx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_MUL_Q, MSA_F_DW,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QDMulHi16Sx8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_MUL_Q, MSA_F_WH,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QRDMulHi32Sx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_MULR_Q, MSA_F_DW,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_QRDMulHi16Sx8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_MULR_Q, MSA_F_WH,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Max8Sx16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MAX_S, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Max16Sx8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MAX_S, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Max32Sx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MAX_S, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Max64Sx2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MAX_S, MSA_D,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Max8Ux16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MAX_U, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Max16Ux8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MAX_U, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Max32Ux4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MAX_U, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Max64Ux2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MAX_U, MSA_D,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Min8Sx16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MIN_S, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Min16Sx8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MIN_S, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Min32Sx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MIN_S, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Min64Sx2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MIN_S, MSA_D,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Min8Ux16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MIN_U, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Min16Ux8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MIN_U, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Min32Ux4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MIN_U, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Min64Ux2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MIN_U, MSA_D,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Shl8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SLL, MSA_B, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Shl16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SLL, MSA_H, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Shl32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SLL, MSA_W, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Shl64x2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SLL, MSA_D, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Shr8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SRL, MSA_B, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Shr16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SRL, MSA_H, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Shr32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SRL, MSA_W, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Shr64x2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SRL, MSA_D, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Sar8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SRA, MSA_B, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Sar16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SRA, MSA_H, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Sar32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SRA, MSA_W, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Sar64x2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SRA, MSA_D, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_InterleaveHI8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVL, MSA_B, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_InterleaveHI16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVL, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_InterleaveHI32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVL, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_InterleaveHI64x2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVL, MSA_D,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_InterleaveLO8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVR, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_InterleaveLO16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVR, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_InterleaveLO32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVR, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_InterleaveLO64x2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVR, MSA_D,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_InterleaveEvenLanes8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVEV, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_InterleaveEvenLanes16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVEV, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_InterleaveEvenLanes32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVEV, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_InterleaveOddLanes8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVOD, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_InterleaveOddLanes16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVOD, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_InterleaveOddLanes32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_ILVOD, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_PackEvenLanes8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_PCKEV, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_PackEvenLanes16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_PCKEV, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_PackEvenLanes32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_PCKEV, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_PackOddLanes8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_PCKOD, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_PackOddLanes16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_PCKOD, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_PackOddLanes32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_PCKOD, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_CmpEQ8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_CEQ, MSA_B, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_CmpEQ16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_CEQ, MSA_H, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_CmpEQ32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_CEQ, MSA_W, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_CmpEQ64x2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_CEQ, MSA_D, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_CmpGT8Sx16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_CLT_S, MSA_B,
+ v_dst, v_src2, v_src1));
+ return v_dst;
+ }
+
+ case Iop_CmpGT16Sx8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_CLT_S, MSA_H,
+ v_dst, v_src2, v_src1));
+ return v_dst;
+ }
+
+ case Iop_CmpGT32Sx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_CLT_S, MSA_W,
+ v_dst, v_src2, v_src1));
+ return v_dst;
+ }
+
+ case Iop_CmpGT64Sx2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_CLT_S, MSA_D,
+ v_dst, v_src2, v_src1));
+ return v_dst;
+ }
+
+ case Iop_CmpGT8Ux16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_CLT_U, MSA_B,
+ v_dst, v_src2, v_src1));
+ return v_dst;
+ }
+
+ case Iop_CmpGT16Ux8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_CLT_U, MSA_H,
+ v_dst, v_src2, v_src1));
+ return v_dst;
+ }
+
+ case Iop_CmpGT32Ux4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_CLT_U, MSA_W,
+ v_dst, v_src2, v_src1));
+ return v_dst;
+ }
+
+ case Iop_CmpGT64Ux2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_CLT_U, MSA_D,
+ v_dst, v_src2, v_src1));
+ return v_dst;
+ }
+
+ case Iop_Avg8Sx16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_AVER_S, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Avg16Sx8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_AVER_S, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Avg32Sx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_AVER_S, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Avg8Ux16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_AVER_U, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Avg16Ux8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_AVER_U, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Avg32Ux4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_AVER_U, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Mul8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MULV, MSA_B,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Mul16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MULV, MSA_H,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Mul32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_MULV, MSA_W,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_AndV128: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env, MIPSInstr_MsaVec(MSA_ANDV, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_OrV128: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env, MIPSInstr_MsaVec(MSA_ORV, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_XorV128: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env, MIPSInstr_MsaVec(MSA_XORV, v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_ShrV128: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ MIPSRH *sm;
+ sm = iselWordExpr_RH7u(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBV, MSA_B,
+ v_dst, v_src1, v_src1));
+
+ if (sm->tag == Mrh_Imm) {
+ int n = (sm->Mrh.Imm.imm16) >> 3;
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_SLDI, v_src1, v_dst,
+ MSA_DFN_B | n));
+ } else {
+ HReg v_src2 = sm->Mrh.Reg.reg;
+ MIPSRH *ri = MIPSRH_Imm(False, 3);
+ HReg r_dst = newVRegI(env);
+ addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /*32bit shift */,
+ r_dst, v_src2, ri));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SLD, MSA_B,
+ v_dst, v_src1, r_dst));
+ }
+
+ return v_dst;
+ }
+
+ case Iop_ShlV128: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ MIPSRH *sm;
+ sm = iselWordExpr_RH7u(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SUBV, MSA_B,
+ v_dst, v_src1, v_src1));
+
+ if (sm->tag == Mrh_Imm) {
+ int n = 16 - ((sm->Mrh.Imm.imm16) >> 3);
+
+ if (n == 16) n = 0;
+
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_SLDI, v_dst, v_src1,
+ MSA_DFN_B | n));
+ } else {
+ HReg v_src2 = sm->Mrh.Reg.reg;
+ MIPSRH *ri = MIPSRH_Imm(False, 3);
+ HReg r_dst = newVRegI(env);
+ HReg help = newVRegI(env);
+ addInstr(env, MIPSInstr_Alu(Malu_XOR, help, v_src2, sm));
+ addInstr(env, MIPSInstr_Alu(Malu_SUB, help, help, sm));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /*32bit shift */,
+ r_dst, help, ri));
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SLD, MSA_B,
+ v_src1, v_dst, r_dst));
+ }
+
+ return v_src1;
+ }
+
+ case Iop_ShlN8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ vassert(e->Iex.Binop.arg2->tag == Iex_Const);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SLLI, MSA_B,
+ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
+ v_src1, v_dst));
+ return v_dst;
+ }
+
+ case Iop_ShlN16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ vassert(e->Iex.Binop.arg2->tag == Iex_Const);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SLLI, MSA_H,
+ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
+ v_src1, v_dst));
+ return v_dst;
+ }
+
+ case Iop_ShlN32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ vassert(e->Iex.Binop.arg2->tag == Iex_Const);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SLLI, MSA_W,
+ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
+ v_src1, v_dst));
+ return v_dst;
+ }
+
+ case Iop_ShlN64x2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ vassert(e->Iex.Binop.arg2->tag == Iex_Const);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SLLI, MSA_D,
+ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
+ v_src1, v_dst));
+ return v_dst;
+ }
+
+ case Iop_SarN8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ vassert(e->Iex.Binop.arg2->tag == Iex_Const);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SRAI, MSA_B,
+ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
+ v_src1, v_dst));
+ return v_dst;
+ }
+
+ case Iop_SarN16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ vassert(e->Iex.Binop.arg2->tag == Iex_Const);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SRAI, MSA_H,
+ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
+ v_src1, v_dst));
+ return v_dst;
+ }
+
+ case Iop_SarN32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ vassert(e->Iex.Binop.arg2->tag == Iex_Const);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SRAI, MSA_W,
+ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
+ v_src1, v_dst));
+ return v_dst;
+ }
+
+ case Iop_SarN64x2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ vassert(e->Iex.Binop.arg2->tag == Iex_Const);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SRAI, MSA_D,
+ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
+ v_src1, v_dst));
+ return v_dst;
+ }
+
+ case Iop_ShrN8x16: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ vassert(e->Iex.Binop.arg2->tag == Iex_Const);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SRLI, MSA_B,
+ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
+ v_src1, v_dst));
+ return v_dst;
+ }
+
+ case Iop_ShrN16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ vassert(e->Iex.Binop.arg2->tag == Iex_Const);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SRLI, MSA_H,
+ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
+ v_src1, v_dst));
+ return v_dst;
+ }
+
+ case Iop_ShrN32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ vassert(e->Iex.Binop.arg2->tag == Iex_Const);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SRLI, MSA_W,
+ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
+ v_src1, v_dst));
+ return v_dst;
+ }
+
+ case Iop_ShrN64x2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ vassert(e->Iex.Binop.arg2->tag == Iex_Const);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SRLI, MSA_D,
+ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
+ v_src1, v_dst));
+ return v_dst;
+ }
+
+ case Iop_QandQSarNnarrow64Sto32Sx2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ vassert(e->Iex.Binop.arg2->tag == Iex_Const);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SRAI, MSA_D,
+ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
+ v_src1, v_dst));
+ addInstr(env, MIPSInstr_MsaBit(MSA_SAT_S, MSA_D, 31, v_dst, v_dst));
+ return v_dst;
+ }
+
+ case Iop_QandQSarNnarrow32Sto16Sx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ vassert(e->Iex.Binop.arg2->tag == Iex_Const);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SRAI, MSA_W,
+ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
+ v_src1, v_dst));
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SAT_S, MSA_W, 15, v_dst, v_dst));
+ return v_dst;
+ }
+
+ case Iop_QandQRSarNnarrow64Sto32Sx2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ vassert(e->Iex.Binop.arg2->tag == Iex_Const);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SRARI, MSA_D,
+ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
+ v_src1, v_dst));
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SAT_S, MSA_D, 31, v_dst, v_dst));
+ return v_dst;
+ }
+
+ case Iop_QandQRSarNnarrow32Sto16Sx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ vassert(e->Iex.Binop.arg2->tag == Iex_Const);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
+ vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SRARI, MSA_W,
+ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
+ v_src1, v_dst));
+ addInstr(env,
+ MIPSInstr_MsaBit(MSA_SAT_S, MSA_W, 15, v_dst, v_dst));
+ return v_dst;
+ }
+
+ case Iop_CmpEQ32Fx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FCEQ, MSA_F_WH,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_CmpEQ64Fx2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FCEQ, MSA_F_DW,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_CmpLT32Fx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FCLT, MSA_F_WH,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_CmpLT64Fx2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FCLT, MSA_F_DW,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_CmpLE32Fx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FCLE, MSA_F_WH,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_CmpLE64Fx2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FCLE, MSA_F_DW,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_CmpUN32Fx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FCUN, MSA_F_WH,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_CmpUN64Fx2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FCUN, MSA_F_DW,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_64HLtoV128: {
+ HReg v_dst = newVRegV(env);
+
+ if (mode64) {
+ HReg r_src1;
+ HReg r_src2;
+ r_src1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ r_src2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa2R(MSA_FILL, MSA_D, r_src2, v_dst));
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_INSERT, r_src1, v_dst,
+ MSA_DFN_D | 1));
+ } else {
+ HReg r_src1h, r_src1l;
+ HReg r_src2h, r_src2l;
+ iselInt64Expr(&r_src1h, &r_src1l, env, e->Iex.Binop.arg1);
+ iselInt64Expr(&r_src2h, &r_src2l, env, e->Iex.Binop.arg2);
+ addInstr(env,
+ MIPSInstr_Msa2R(MSA_FILL, MSA_W, r_src2l, v_dst));
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_INSERT, r_src2h, v_dst,
+ MSA_DFN_W | 1));
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_INSERT, r_src1l, v_dst,
+ MSA_DFN_W | 2));
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_INSERT, r_src1h, v_dst,
+ MSA_DFN_W | 3));
+ }
+
+ return v_dst;
+ }
+
+ case Iop_Min32Fx4: {
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ HReg v_dst = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FMIN, MSA_F_WH,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Min64Fx2: {
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ HReg v_dst = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FMIN, MSA_F_DW,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Max32Fx4: {
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ HReg v_dst = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FMAX, MSA_F_WH,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Max64Fx2: {
+ HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
+ HReg v_dst = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FMAX, MSA_F_DW,
+ v_dst, v_src1, v_src2));
+ return v_dst;
+ }
+
+ case Iop_Sqrt32Fx4: {
+ HReg v_src = iselV128Expr(env, e->Iex.Binop.arg2);
+ HReg v_dst = newVRegV(env);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Binop.arg1);
+ addInstr(env,
+ MIPSInstr_Msa2RF(MSA_FSQRT, MSA_F_WH, v_dst, v_src));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_Sqrt64Fx2: {
+ HReg v_src = iselV128Expr(env, e->Iex.Binop.arg2);
+ HReg v_dst = newVRegV(env);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Binop.arg1);
+ addInstr(env,
+ MIPSInstr_Msa2RF(MSA_FSQRT, MSA_F_DW, v_dst, v_src));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ default:
+ vex_printf("iselV128Expr_wrk: unsupported binop: %x\n", op_binop);
+ }
+ }
+
+ if (e->tag == Iex_Triop) {
+ IROp op_triop = e->Iex.Triop.details->op;
+
+ switch (op_triop) {
+ case Iop_Add32Fx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FADD, MSA_F_WH,
+ v_dst, v_src1, v_src2));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_Add64Fx2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FADD, MSA_F_DW,
+ v_dst, v_src1, v_src2));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_Sub32Fx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FSUB, MSA_F_WH,
+ v_dst, v_src1, v_src2));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_Sub64Fx2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FSUB, MSA_F_DW,
+ v_dst, v_src1, v_src2));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_Mul32Fx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FMUL, MSA_F_WH,
+ v_dst, v_src1, v_src2));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_Mul64Fx2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FMUL, MSA_F_DW,
+ v_dst, v_src1, v_src2));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_Div32Fx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FDIV, MSA_F_WH,
+ v_dst, v_src1, v_src2));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_Div64Fx2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FDIV, MSA_F_DW,
+ v_dst, v_src1, v_src2));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_F32x4_2toQ16x8: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FTQ, MSA_F_WH,
+ v_dst, v_src1, v_src2));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_F64x2_2toQ32x4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FTQ, MSA_F_DW,
+ v_dst, v_src1, v_src2));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_Scale2_32Fx4: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FEXP2, MSA_F_WH,
+ v_dst, v_src1, v_src2));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ case Iop_Scale2_64Fx2: {
+ HReg v_dst = newVRegV(env);
+ HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
+ HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
+ addInstr(env,
+ MIPSInstr_Msa3RF(MSA_FEXP2, MSA_F_DW,
+ v_dst, v_src1, v_src2));
+ set_MIPS_rounding_default_MSA(env);
+ return v_dst;
+ }
+
+ default:
+ vex_printf("iselV128Expr_wrk: unsupported triop: %x\n", op_triop);
+ }
+ }
+
+ if (e->tag == Iex_Const) {
+ IRConst *con = e->Iex.Const.con;
+
+ if (con->tag != Ico_V128) {
+ vpanic("iselV128Expr.const(mips)");
+ } else {
+ HReg v_dst = newVRegV(env);
+ UShort val = con->Ico.V128;
+ HReg zero = Zero(mode64);
+
+ switch (val) {
+ case 0: /* likely */
+ addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, zero, v_dst));
+ break;
+
+ default: {
+ HReg r_tmp = newVRegI(env);
+ UInt i;
+ addInstr(env, MIPSInstr_LI(r_tmp, 0xfful));
+
+ if (val & 1) {
+ addInstr(env,
+ MIPSInstr_Msa2R(MSA_FILL, MSA_B, r_tmp, v_dst));
+ } else {
+ addInstr(env,
+ MIPSInstr_Msa2R(MSA_FILL, MSA_B, zero, v_dst));
+ }
+
+ for (i = 1; i < 16; i++) {
+ val >>= 1;
+
+ if (val & 1) {
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_INSERT, r_tmp, v_dst,
+ MSA_DFN_B | i));
+ } else {
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_INSERT, zero, v_dst,
+ MSA_DFN_B | i));
+ }
+ }
+
+ break;
+ }
+ }
+
+ return v_dst;
+ }
+ }
+
+ if (e->tag == Iex_ITE) {
+ HReg v_dst = newVRegV(env);
+ HReg iff = iselV128Expr(env, e->Iex.ITE.iffalse);
+ HReg ift = iselV128Expr(env, e->Iex.ITE.iftrue);
+ HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond);
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_cond, r_cond,
+ MIPSRH_Imm(False, 1)));
+ addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, r_cond, v_dst));
+ addInstr(env,
+ MIPSInstr_Alu(Malu_ADD, r_cond, r_cond, MIPSRH_Imm(True, 1)));
+ addInstr(env, MIPSInstr_MsaElm(MSA_INSERT, r_cond, v_dst, MSA_DFN_W | 2));
+ addInstr(env, MIPSInstr_Msa3R(MSA_VSHF, MSA_D, v_dst, ift, iff));
+ return v_dst;
+ }
+
+ vex_printf("iselV128Expr_wrk: Unsupported tag: %x\n", e->tag);
+ ppIRExpr(e);
+ vpanic("iselV128Expr(mips)");
+}
+
+/*---------------------------------------------------------*/
+/*--- ISEL: Integer expressions (128 bit) ---*/
+/*---------------------------------------------------------*/
+
+/* 64-bit mode ONLY: compute a 128-bit value into a register pair,
+ which is returned as the first two parameters. As with
+ iselWordExpr_R, these may be either real or virtual regs; in any
+ case they must not be changed by subsequent code emitted by the
+ caller. */
+
+static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
+{
+ vassert(env->mode64);
+ iselInt128Expr_wrk(rHi, rLo, env, e);
+ vassert(hregClass(*rHi) == HRcGPR(env->mode64));
+ vassert(hregIsVirtual(*rHi));
+ vassert(hregClass(*rLo) == HRcGPR(env->mode64));
+ vassert(hregIsVirtual(*rLo));
+}
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env,
+ IRExpr * e)
+{
+ vassert(e);
+ vassert(typeOfIRExpr(env->type_env, e) == Ity_I128);
+
+ /* read 128-bit IRTemp */
+ if (e->tag == Iex_RdTmp) {
+ lookupIRTempPair(rHi, rLo, env, e->Iex.RdTmp.tmp);
+ return;
+ }
+
+ /* --------- BINARY ops --------- */
+ if (e->tag == Iex_Binop) {
+ switch (e->Iex.Binop.op) {
+ /* 64 x 64 -> 128 multiply */
+ case Iop_MullU64:
+ case Iop_MullS64: {
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64);
+ HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ addInstr(env, MIPSInstr_Mult(syned, r_srcL, r_srcR));
+ addInstr(env, MIPSInstr_Mfhi(tHi));
+ addInstr(env, MIPSInstr_Mflo(tLo));
+ *rHi = tHi;
+ *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_DivModU64to64:
+ case Iop_DivModS64to64: {
+ HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to64);
+
+ addInstr(env, MIPSInstr_Div(syned, False, r_srcL, r_srcR));
+ addInstr(env, MIPSInstr_Mfhi(tHi));
+ addInstr(env, MIPSInstr_Mflo(tLo));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
default:
break;
return;
}
+ if (e->tag == Iex_CCall) {
+ HReg r_dstH = newVRegI(env);
+ HReg r_dstL = newVRegI(env);
+ vassert(e->Iex.CCall.retty == Ity_I64);
+
+ /* Marshal args, do the call, clear stack. */
+ UInt addToSp = 0;
+ RetLoc rloc = mk_RetLoc_INVALID();
+ doHelperCall(&addToSp, &rloc, env, NULL/*guard*/, e->Iex.CCall.cee,
+ e->Iex.CCall.retty, e->Iex.CCall.args );
+
+ vassert(is_sane_RetLoc(rloc));
+ vassert(rloc.pri == RLPri_2Int);
+ vassert(addToSp == 0);
+ addInstr(env, mk_iMOVds_RR(r_dstL, hregMIPS_GPR2(False)));
+ addInstr(env, mk_iMOVds_RR(r_dstH, hregMIPS_GPR3(False)));
+ *rHi = r_dstH;
+ *rLo = r_dstL;
+ return;
+ }
+
/* --------- BINARY ops --------- */
if (e->tag == Iex_Binop) {
IROp op_binop = e->Iex.Binop.op;
return;
}
+ case Iop_F64toI64U: {
+ HReg r_src;
+ HReg tmp = newVRegV(env);
+ vassert(has_msa);
+ r_src = iselDblExpr( env, e->Iex.Binop.arg2);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Binop.arg1);
+ addInstr(env, MIPSInstr_Msa2RF(MSA_FTINT_U, MSA_F_DW, tmp, r_src));
+ HReg r_dsth = newVRegI(env);
+ HReg r_dstl = newVRegI(env);
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_S, tmp, r_dstl, MSA_DFN_W | 0));
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_S, tmp, r_dsth, MSA_DFN_W | 1));
+ *rHi = r_dsth;
+ *rLo = r_dstl;
+ set_MIPS_rounding_default_MSA(env);
+ return;
+ }
+
+ case Iop_GetElem64x2: {
+ vassert(has_msa);
+ HReg v_src = iselV128Expr(env, e->Iex.Binop.arg1);
+ HReg r_dstHI = newVRegI(env);
+ HReg r_dstLO = newVRegI(env);
+ MIPSRH *tmp = iselWordExpr_RH(env, False, e->Iex.Binop.arg2);
+
+ switch (tmp->tag) {
+ case Mrh_Imm:
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_S, v_src, r_dstHI,
+ MSA_DFN_W |
+ (((tmp->Mrh.Imm.imm16 & 0x01) << 1)
+ + 1)));
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_S, v_src, r_dstLO,
+ MSA_DFN_W |
+ ((tmp->Mrh.Imm.imm16 & 0x01) << 1)));
+ break;
+
+ case Mrh_Reg: {
+ HReg v_tmp = newVRegV(env);
+ addInstr(env,
+ MIPSInstr_Msa3R(MSA_SPLAT, MSA_D, v_tmp, v_src,
+ tmp->Mrh.Reg.reg));
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_S, v_tmp, r_dstHI,
+ MSA_DFN_W | 1));
+ addInstr(env,
+ MIPSInstr_MsaElm(MSA_COPY_S, v_tmp, r_dstLO,
+ MSA_DFN_W));
+ break;
+ }
+ }
+
+ *rHi = r_dstHI;
+ *rLo = r_dstLO;
+ return;
+ }
+
+ case Iop_Mul64: {
+ HReg a_L, a_H, b_L, b_H;
+ HReg dst_L = newVRegI(env);
+ HReg dst_H = newVRegI(env);
+
+ iselInt64Expr(&a_H, &a_L, env, e->Iex.Binop.arg1);
+ iselInt64Expr(&b_H, &b_L, env, e->Iex.Binop.arg2);
+ addInstr(env, MIPSInstr_Mul(dst_H, a_H, b_L));
+ addInstr(env, MIPSInstr_Mult(True, b_H, a_L));
+ addInstr(env, MIPSInstr_Mflo(dst_L));
+ addInstr(env, MIPSInstr_Alu(Malu_ADD, dst_H, dst_H,
+ MIPSRH_Reg(dst_L)));
+ addInstr(env, MIPSInstr_Mult(False, a_L, b_L));
+ addInstr(env, MIPSInstr_Mfhi(dst_L));
+
+ addInstr(env, MIPSInstr_Alu(Malu_ADD, dst_H, dst_H,
+ MIPSRH_Reg(dst_L)));
+ addInstr(env, MIPSInstr_Mflo(dst_L));
+ *rHi = dst_H;
+ *rLo = dst_L;
+ return;
+ }
+
+ case Iop_DivS64: {
+ HReg src1_L, src1_H, src2_L, src2_H;
+ HReg dst_L = newVRegI(env);
+ HReg dst_H = newVRegI(env);
+ HReg tmp1 = newVRegV(env);
+ HReg tmp2 = newVRegV(env);
+ vassert(has_msa);
+ iselInt64Expr(&src1_H, &src1_L, env, e->Iex.Binop.arg1);
+ iselInt64Expr(&src2_H, &src2_L, env, e->Iex.Binop.arg2);
+ addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, src1_L, tmp1));
+ addInstr(env, MIPSInstr_MsaElm(MSA_INSERT, src1_H, tmp1, MSA_DFN_W | 1));
+ addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, src2_L, tmp2));
+ addInstr(env, MIPSInstr_MsaElm(MSA_INSERT, src2_H, tmp2, MSA_DFN_W | 1));
+ addInstr(env, MIPSInstr_Msa3R(MSA_DIVS, MSA_D, tmp1, tmp1, tmp2));
+ addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, tmp1, dst_H, MSA_DFN_W | 1));
+ addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, tmp1, dst_L, MSA_DFN_W | 0));
+ *rHi = dst_H;
+ *rLo = dst_L;
+ return;
+ }
+
+ case Iop_DivU64: {
+ HReg src1_L, src1_H, src2_L, src2_H;
+ HReg dst_L = newVRegI(env);
+ HReg dst_H = newVRegI(env);
+ HReg tmp1 = newVRegV(env);
+ HReg tmp2 = newVRegV(env);
+ vassert(has_msa);
+ iselInt64Expr(&src1_H, &src1_L, env, e->Iex.Binop.arg1);
+ iselInt64Expr(&src2_H, &src2_L, env, e->Iex.Binop.arg2);
+ addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, src1_L, tmp1));
+ addInstr(env, MIPSInstr_MsaElm(MSA_INSERT, src1_H, tmp1, MSA_DFN_W | 1));
+ addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, src2_L, tmp2));
+ addInstr(env, MIPSInstr_MsaElm(MSA_INSERT, src2_H, tmp2, MSA_DFN_W | 1));
+ addInstr(env, MIPSInstr_Msa3R(MSA_DIVU, MSA_D, tmp1, tmp1, tmp2));
+ addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, tmp1, dst_H, MSA_DFN_W | 1));
+ addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, tmp1, dst_L, MSA_DFN_W | 0));
+ *rHi = dst_H;
+ *rLo = dst_L;
+ return;
+ }
default:
break;
return;
}
+ case Iop_8Sto64:
+ case Iop_16Sto64: {
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ UInt no_bits = (e->Iex.Unop.op == Iop_8Sto64) ? 24 : 16;
+ addInstr(env, mk_iMOVds_RR(tLo, src));
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tLo, tLo,
+ MIPSRH_Imm(False, no_bits)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tHi, tLo,
+ MIPSRH_Imm(False, 31)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tLo, tLo,
+ MIPSRH_Imm(False, no_bits)));
+ addInstr(env, mk_iMOVds_RR(tHi, tLo));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
/* 32Sto64(e) */
case Iop_32Sto64: {
HReg tLo = newVRegI(env);
return;
}
- /* 8Uto64(e) */
- case Iop_8Uto64: {
+ case Iop_8Uto64:
+ case Iop_16Uto64: {
HReg tLo = newVRegI(env);
HReg tHi = newVRegI(env);
HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ UInt mask = (e->Iex.Unop.op == Iop_8Sto64) ? 0xFF : 0xFFFF;
addInstr(env, MIPSInstr_Alu(Malu_AND, tLo, src,
- MIPSRH_Imm(False, 0xFF)));
+ MIPSRH_Imm(False, mask)));
addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, hregMIPS_GPR0(mode64),
MIPSRH_Reg(hregMIPS_GPR0(mode64))));
*rHi = tHi;
*rHi = tHi;
*rLo = tLo;
+ return;
+ }
+
+ case Iop_V128HIto64: {
+ vassert(has_msa);
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, v_src, tLo, MSA_DFN_W | 2));
+ addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, v_src, tHi, MSA_DFN_W | 3));
+ *rLo = tLo;
+ *rHi = tHi;
+ return;
+ }
+
+ case Iop_V128to64: {
+ vassert(has_msa);
+ HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, v_src, tLo, MSA_DFN_W | 0));
+ addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, v_src, tHi, MSA_DFN_W | 1));
+ *rLo = tLo;
+ *rHi = tHi;
+ return;
+ }
+ case Iop_F32toF16x4: {
+ vassert(has_msa);
+ HReg v_arg = iselV128Expr(env, e->Iex.Unop.arg);
+ HReg v_src = newVRegV(env);
+ set_guest_MIPS_rounding_mode_MSA(env);
+ addInstr(env, MIPSInstr_Msa3RF(MSA_FEXDO, MSA_F_WH, v_src, v_arg, v_arg));
+ set_MIPS_rounding_default_MSA(env);
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, v_src, tLo, MSA_DFN_W | 0));
+ addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, v_src, tHi, MSA_DFN_W | 1));
+ *rLo = tLo;
+ *rHi = tHi;
return;
}
set_MIPS_rounding_default(env);
return dst;
}
+ case Iop_ScaleF64: {
+ HReg src1 = iselFltExpr(env, e->Iex.Triop.details->arg2);
+ HReg src2 = iselFltExpr(env, e->Iex.Triop.details->arg3);
+ HReg v_help = newVRegV(env);
+ HReg dst = newVRegF(env);
+ vassert(has_msa);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
+ addInstr(env, MIPSInstr_Msa2RF(MSA_FTINT_S, MSA_F_DW, v_help, src2));
+ addInstr(env, MIPSInstr_Msa3RF(MSA_FEXP2, MSA_F_DW, dst, src1, v_help));
+ set_MIPS_rounding_default_MSA(env);
+
+ return dst;
+ }
default:
break;
}
return dst;
}
+ case Iop_I64UtoF64: {
+ vassert(mode64);
+ HReg r_dst = newVRegF(env);
+ HReg tmp = newVRegV(env);
+ HReg r_src;
+ vassert(has_msa);
+ r_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Binop.arg1);
+ addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_D, r_src, tmp));
+ HReg r_srch = newVRegI(env);
+ addInstr(env, MIPSInstr_Msa2RF(MSA_FFINT_U, MSA_F_DW, tmp, tmp));
+ addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, tmp, r_srch, MSA_DFN_D | 0));
+ sub_from_sp(env, 8);
+ MIPSAMode *am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ /* store as I64 */
+ addInstr(env, MIPSInstr_Store(8, am_addr, r_srch, mode64));
+
+ /* load as Ity_F64 */
+ addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, r_dst, am_addr));
+
+ /* Reset SP */
+ add_to_sp(env, 8);
+ set_MIPS_rounding_default_MSA(env);
+ return r_dst;
+ }
+
+
default:
break;
}
case Iop_MAddF64:
case Iop_MSubF32:
case Iop_MSubF64: {
- MIPSFpOp op = 0;
+ Int op = 0;
+ MSADFFlx type = 0;
switch (e->Iex.Qop.details->op) {
case Iop_MAddF32:
- op = Mfp_MADDS;
+ op = has_msa ? MSA_FMADD : Mfp_MADDS;
+ type = MSA_F_WH;
break;
case Iop_MAddF64:
- op = Mfp_MADDD;
+ op = has_msa ? MSA_FMADD : Mfp_MADDD;
+ type = MSA_F_DW;
break;
case Iop_MSubF32:
- op = Mfp_MSUBS;
+ op = has_msa ? MSA_FMSUB : Mfp_MSUBS;
+ type = MSA_F_WH;
break;
case Iop_MSubF64:
- op = Mfp_MSUBD;
+ op = has_msa ? MSA_FMSUB : Mfp_MSUBD;
+ type = MSA_F_DW;
break;
default:
vassert(0);
}
+
HReg dst = newVRegF(env);
HReg src1 = iselFltExpr(env, e->Iex.Qop.details->arg2);
HReg src2 = iselFltExpr(env, e->Iex.Qop.details->arg3);
HReg src3 = iselFltExpr(env, e->Iex.Qop.details->arg4);
- set_MIPS_rounding_mode(env, e->Iex.Qop.details->arg1);
- addInstr(env, MIPSInstr_FpTernary(op, dst,
- src1, src2, src3));
- set_MIPS_rounding_default(env);
+
+ if (has_msa) {
+ addInstr(env, MIPSInstr_MsaElm(MSA_MOVE, src3, dst, 0));
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Qop.details->arg1);
+ addInstr(env, MIPSInstr_Msa3RF(op, type, dst, src1, src2));
+ set_MIPS_rounding_default_MSA(env);
+ } else {
+ set_MIPS_rounding_mode(env, e->Iex.Qop.details->arg1);
+ addInstr(env, MIPSInstr_FpTernary(op, dst,
+ src1, src2, src3));
+ set_MIPS_rounding_default(env);
+ }
return dst;
}
return dst;
}
+ case Iop_I64StoF64: {
+ HReg r_dst = newVRegD(env);
+ MIPSAMode *am_addr;
+ HReg tmp, fr_src;
+ if (mode64) {
+ tmp = newVRegD(env);
+ fr_src = iselDblExpr(env, e->Iex.Binop.arg2);
+ /* Move SP down 8 bytes */
+ sub_from_sp(env, 8);
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ /* store as I64 */
+ addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
+
+ /* load as Ity_F64 */
+ addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr));
+
+ /* Reset SP */
+ add_to_sp(env, 8);
+ } else {
+ HReg Hi, Lo;
+ tmp = newVRegD(env);
+ iselInt64Expr(&Hi, &Lo, env, e->Iex.Binop.arg2);
+ tmp = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
+ }
+
+ set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
+ addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDL, r_dst, tmp));
+ set_MIPS_rounding_default(env);
+
+ return r_dst;
+ }
+
+ case Iop_I64UtoF64: {
+ HReg r_dst;
+ HReg tmp = newVRegV(env);
+ HReg r_src2h, r_src2l;
+ vassert(has_msa);
+ iselInt64Expr(&r_src2h, &r_src2l, env, e->Iex.Binop.arg2);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Binop.arg1);
+ addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, r_src2l, tmp));
+ addInstr(env, MIPSInstr_MsaElm(MSA_INSERT, r_src2h, tmp, MSA_DFN_W | 1));
+ addInstr(env, MIPSInstr_MsaElm(MSA_INSERT, r_src2l, tmp, MSA_DFN_W | 2));
+ addInstr(env, MIPSInstr_MsaElm(MSA_INSERT, r_src2h, tmp, MSA_DFN_W | 3));
+ HReg r_srchh = newVRegI(env);
+ HReg r_srchl = newVRegI(env);
+ addInstr(env, MIPSInstr_Msa2RF(MSA_FFINT_U, MSA_F_DW, tmp, tmp));
+ addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, tmp, r_srchl, MSA_DFN_W | 0));
+ addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, tmp, r_srchh, MSA_DFN_W | 1));
+ r_dst = mk_LoadRR32toFPR(env, r_srchh, r_srchl);
+ set_MIPS_rounding_default_MSA(env);
+ return r_dst;
+ }
+
default:
break;
set_MIPS_rounding_default(env);
return dst;
}
+
+ case Iop_ScaleF64: {
+ HReg src1 = iselDblExpr(env, e->Iex.Triop.details->arg2);
+ HReg src2 = iselDblExpr(env, e->Iex.Triop.details->arg3);
+ HReg v_help = newVRegV(env);
+ HReg dst = newVRegD(env);
+ vassert(has_msa);
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
+ addInstr(env, MIPSInstr_Msa2RF(MSA_FTINT_S, MSA_F_DW, v_help, src2));
+ addInstr(env, MIPSInstr_Msa3RF(MSA_FEXP2, MSA_F_DW, dst, src1, v_help));
+ set_MIPS_rounding_default_MSA(env);
+ return dst;
+ }
default:
break;
}
}
if (e->tag == Iex_Qop) {
+ vassert(has_msa);
switch (e->Iex.Qop.details->op) {
- case Iop_MAddF32:
case Iop_MAddF64:
- case Iop_MSubF32:
case Iop_MSubF64: {
- MIPSFpOp op = 0;
+ MSA3RFOp op = 0;
switch (e->Iex.Qop.details->op) {
- case Iop_MAddF32:
- op = Mfp_MADDS;
- break;
case Iop_MAddF64:
- op = Mfp_MADDD;
- break;
- case Iop_MSubF32:
- op = Mfp_MSUBS;
+ op = MSA_FMADD;
break;
case Iop_MSubF64:
- op = Mfp_MSUBD;
+ op = MSA_FMSUB;
break;
default:
vassert(0);
HReg src1 = iselDblExpr(env, e->Iex.Qop.details->arg2);
HReg src2 = iselDblExpr(env, e->Iex.Qop.details->arg3);
HReg src3 = iselDblExpr(env, e->Iex.Qop.details->arg4);
- set_MIPS_rounding_mode(env, e->Iex.Qop.details->arg1);
- addInstr(env, MIPSInstr_FpTernary(op, dst,
- src1, src2, src3));
- set_MIPS_rounding_default(env);
+ addInstr(env, MIPSInstr_MsaElm(MSA_MOVE, src3, dst, 0));
+ set_MIPS_rounding_mode_MSA(env, e->Iex.Qop.details->arg1);
+ addInstr(env, MIPSInstr_Msa3RF(op, MSA_F_DW, dst, src1, src2));
+ set_MIPS_rounding_default_MSA(env);
return dst;
}
MIPSAMode *am_addr;
IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
+ if (tyd == Ity_V128) {
+ vassert(has_msa);
+ HReg res = iselV128Expr(env, stmt->Ist.Store.data);
+ HReg addr = iselWordExpr_R(env, stmt->Ist.Store.addr);
+ addInstr(env, MIPSInstr_MsaMi10(MSA_ST, 0, addr, res, MSA_B));
+ return;
+ }
+
/*constructs addressing mode from address provided */
am_addr = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd);
am_addr));
return;
}
+ if (ty == Ity_V128) {
+ vassert(has_msa);
+ HReg v_src = iselV128Expr(env, stmt->Ist.Put.data);
+#if defined(_MIPSEB)
+ HReg r_addr = newVRegI(env);
+ addInstr(env, MIPSInstr_Alu(mode64 ? Malu_DADD : Malu_ADD, r_addr, GuestStatePointer(mode64),
+ MIPSRH_Imm(False, stmt->Ist.Put.offset)));
+ addInstr(env, MIPSInstr_MsaMi10(MSA_ST, 0, r_addr, v_src, MSA_B));
+#else
+ vassert(!(stmt->Ist.Put.offset & 7));
+ addInstr(env, MIPSInstr_MsaMi10(MSA_ST, stmt->Ist.Put.offset >> 3,
+ GuestStatePointer(mode64), v_src, MSA_D));
+#endif
+ return;
+ }
break;
}
return;
}
}
+
+ if (ty == Ity_V128) {
+ vassert(has_msa);
+ HReg v_dst = lookupIRTemp(env, tmp);
+ HReg v_src = iselV128Expr(env, stmt->Ist.WrTmp.data);
+ addInstr(env, MIPSInstr_MsaElm(MSA_MOVE, v_src, v_dst, 0));
+ return;
+ }
break;
}
}
}
case Ity_V128: {
- /* ATC. The code that this produces really
- needs to be looked at, to verify correctness.
- I don't think this can ever happen though, since the
- MIPS front end never produces 128-bit loads/stores. */
- vassert(0);
+ vassert(has_msa);
vassert(rloc.pri == RLPri_V128SpRel);
+ vassert((rloc.spOff < 512) && (rloc.spOff > -512));
vassert(addToSp >= 16);
HReg dst = lookupIRTemp(env, d->tmp);
- MIPSAMode* am = MIPSAMode_IR(rloc.spOff, StackPointer(mode64));
- addInstr(env, MIPSInstr_Load(mode64 ? 8 : 4, dst, am, mode64));
+ addInstr(env, MIPSInstr_MsaMi10(MSA_LD, rloc.spOff, StackPointer(mode64), dst, MSA_B));
add_to_sp(env, addToSp);
return;
mode64 = arch_host != VexArchMIPS32;
fp_mode64 = VEX_MIPS_HOST_FP_MODE(hwcaps_host);
+ has_msa = VEX_MIPS_PROC_MSA(archinfo_host->hwcaps);
/* Make up an initial environment to use. */
env = LibVEX_Alloc_inline(sizeof(ISelEnv));
case Ity_F64:
hreg = mkHReg(True, HRcFlt64, 0, j++);
break;
+ case Ity_V128:
+ hreg = mkHReg(True, HRcVec128, 0, j++);
+ break;
default:
ppIRType(bb->tyenv->types[i]);
vpanic("iselBB(mips): IRTemp type");