as to form a basis for SSE2 floating point support.
git-svn-id: svn://svn.valgrind.org/vex/trunk@630
}
}
+/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
+
+static UInt dis_SSE_E_to_G_lo64 ( UChar sorb, UInt delta,
+ HChar* opname, IROp op )
+{
+ HChar dis_buf[50];
+ Int alen;
+ IRTemp addr;
+ UChar rm = getIByte(delta);
+ IRExpr* gpart = getXMMReg(gregOfRM(rm));
+ if (epartIsReg(rm)) {
+ putXMMReg( gregOfRM(rm),
+ binop(op, gpart,
+ getXMMReg(eregOfRM(rm))) );
+ DIP("%s %s,%s\n", opname,
+ nameXMMReg(eregOfRM(rm)),
+ nameXMMReg(gregOfRM(rm)) );
+ return delta+1;
+ } else {
+ /* We can only do a 64-bit memory read, so the upper half of the
+ E operand needs to be made simply of zeroes. */
+ IRTemp epart = newTemp(Ity_V128);
+ addr = disAMode ( &alen, sorb, delta, dis_buf );
+ assign( epart, unop( Iop_64Uto128,
+ loadLE(Ity_I64, mkexpr(addr))) );
+ putXMMReg( gregOfRM(rm),
+ binop(op, gpart, mkexpr(epart)) );
+ DIP("%s %s,%s\n", opname,
+ dis_buf,
+ nameXMMReg(gregOfRM(rm)) );
+ return delta+alen;
+ }
+}
+
/* All lanes unary SSE operation, G = op(E). */
static UInt dis_SSE_E_to_G_unary_all (
mkU32(3) );
}
+static void put_sse_roundingmode ( IRExpr* sseround )
+{
+ vassert(typeOfIRExpr(irbb->tyenv, sseround) == Ity_I32);
+ stmt( IRStmt_Put( OFFB_SSEROUND, sseround ) );
+}
+
/* Break a 128-bit value up into four 32-bit ints. */
static void breakup128to32s ( IRTemp t128,
insn = (UChar*)&guest_code[delta];
/* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
- if (insn[0] == 0x0F && insn[1] == 0x58) {
- vassert(sz == 4);
+ if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x58) {
delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
goto decode_success;
}
}
/* 0F 55 = ANDNPS -- G = (not G) and E */
- if (insn[0] == 0x0F && insn[1] == 0x55) {
- vassert(sz == 4);
+ if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x55) {
delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_And128 );
goto decode_success;
}
/* 0F 54 = ANDPS -- G = G and E */
- if (insn[0] == 0x0F && insn[1] == 0x54) {
- vassert(sz == 4);
+ if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x54) {
delta = dis_SSE_E_to_G_all( sorb, delta+2, "andps", Iop_And128 );
goto decode_success;
}
/* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
- if (insn[0] == 0x0F && insn[1] == 0xC2) {
- vassert(sz == 4);
+ if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC2) {
delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
goto decode_success;
}
)
);
- //put_sseround( unop(Iop_64to32, mkexpr(t64)) );
+ put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
put_emwarn( mkexpr(ew) );
/* Finally, if an emulation warning was reported, side-exit to
goto decode_success;
}
+ /* ---------------------------------------------------- */
+ /* --- end of the SSE decoder. --- */
+ /* ---------------------------------------------------- */
+
+ /* ---------------------------------------------------- */
+ /* --- start of the SSE2 decoder. --- */
+ /* ---------------------------------------------------- */
+
+ insn = (UChar*)&guest_code[delta];
+
+ /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
+ if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x58) {
+ delta = dis_SSE_E_to_G_all( sorb, delta+2, "addpd", Iop_Add64Fx2 );
+ goto decode_success;
+ }
+
+ /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
+ if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x58) {
+ vassert(sz == 4);
+ delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "addsd", Iop_Add64F0x2 );
+ goto decode_success;
+ }
+
+ /* 66 0F 55 = ANDNPD -- G = (not G) and E */
+ if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x55) {
+ delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnpd", Iop_And128 );
+ goto decode_success;
+ }
+
+ /* 66 0F 54 = ANDPD -- G = G and E */
+ if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x54) {
+ delta = dis_SSE_E_to_G_all( sorb, delta+2, "andpd", Iop_And128 );
+ goto decode_success;
+ }
+
+
//--
//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
//-- if (insn[0] == 0x0F && insn[1] == 0xAE
|| op == Xsse_AND || op == Xsse_OR || op == Xsse_XOR);
return i;
}
-X86Instr* X86Instr_Sse32Fx4 ( X86SseOp op, HReg src, HReg dst ) {
+X86Instr* X86Instr_Sse32Fx4 ( X86SseOp op, HReg src, HReg dst ) {
X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
i->tag = Xin_Sse32Fx4;
i->Xin.Sse32Fx4.op = op;
i->Xin.Sse32Fx4.dst = dst;
return i;
}
-X86Instr* X86Instr_Sse32FLo ( X86SseOp op, HReg src, HReg dst ) {
+X86Instr* X86Instr_Sse32FLo ( X86SseOp op, HReg src, HReg dst ) {
X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
i->tag = Xin_Sse32FLo;
i->Xin.Sse32FLo.op = op;
i->Xin.Sse32FLo.dst = dst;
return i;
}
+X86Instr* X86Instr_Sse64Fx2 ( X86SseOp op, HReg src, HReg dst ) {
+ X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
+ i->tag = Xin_Sse64Fx2;
+ i->Xin.Sse64Fx2.op = op;
+ i->Xin.Sse64Fx2.src = src;
+ i->Xin.Sse64Fx2.dst = dst;
+ return i;
+}
+X86Instr* X86Instr_Sse64FLo ( X86SseOp op, HReg src, HReg dst ) {
+ X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
+ i->tag = Xin_Sse64FLo;
+ i->Xin.Sse64FLo.op = op;
+ i->Xin.Sse64FLo.src = src;
+ i->Xin.Sse64FLo.dst = dst;
+ return i;
+}
void ppX86Instr ( X86Instr* i ) {
switch (i->tag) {
vex_printf(",");
ppHRegX86(i->Xin.Sse32FLo.dst);
return;
+ case Xin_Sse64Fx2:
+ vex_printf("%spd ", showX86SseOp(i->Xin.Sse64Fx2.op));
+ ppHRegX86(i->Xin.Sse64Fx2.src);
+ vex_printf(",");
+ ppHRegX86(i->Xin.Sse64Fx2.dst);
+ return;
+ case Xin_Sse64FLo:
+ vex_printf("%ssd ", showX86SseOp(i->Xin.Sse64FLo.op));
+ ppHRegX86(i->Xin.Sse64FLo.src);
+ vex_printf(",");
+ ppHRegX86(i->Xin.Sse64FLo.dst);
+ return;
default:
vpanic("ppX86Instr");
addHRegUse(u, unary ? HRmWrite : HRmModify,
i->Xin.Sse32FLo.dst);
return;
+ case Xin_Sse64Fx2:
+ vassert(i->Xin.Sse64Fx2.op != Xsse_MOV);
+ unary = i->Xin.Sse64Fx2.op == Xsse_RCPF
+ || i->Xin.Sse64Fx2.op == Xsse_RSQRTF
+ || i->Xin.Sse64Fx2.op == Xsse_SQRTF;
+ addHRegUse(u, HRmRead, i->Xin.Sse64Fx2.src);
+ addHRegUse(u, unary ? HRmWrite : HRmModify,
+ i->Xin.Sse64Fx2.dst);
+ return;
+ case Xin_Sse64FLo:
+ vassert(i->Xin.Sse64FLo.op != Xsse_MOV);
+ unary = i->Xin.Sse64FLo.op == Xsse_RCPF
+ || i->Xin.Sse64FLo.op == Xsse_RSQRTF
+ || i->Xin.Sse64FLo.op == Xsse_SQRTF;
+ addHRegUse(u, HRmRead, i->Xin.Sse64FLo.src);
+ addHRegUse(u, unary ? HRmWrite : HRmModify,
+ i->Xin.Sse64FLo.dst);
+ return;
default:
ppX86Instr(i);
vpanic("getRegUsage_X86Instr");
mapReg(m, &i->Xin.Sse32FLo.src);
mapReg(m, &i->Xin.Sse32FLo.dst);
return;
+ case Xin_Sse64Fx2:
+ mapReg(m, &i->Xin.Sse64Fx2.src);
+ mapReg(m, &i->Xin.Sse64Fx2.dst);
+ return;
+ case Xin_Sse64FLo:
+ mapReg(m, &i->Xin.Sse64FLo.src);
+ mapReg(m, &i->Xin.Sse64FLo.dst);
+ return;
default:
ppX86Instr(i);
vpanic("mapRegs_X86Instr");
goto done;
case Xin_SseLdzLO:
- if (i->Xin.SseLdzLO.sz == 4) {
- /* movss amode, %xmm-dst */
- *p++ = 0xF3;
- *p++ = 0x0F;
- *p++ = 0x10;
- p = doAMode_M(p, fake(vregNo(i->Xin.SseLdzLO.reg)),
- i->Xin.SseLdzLO.addr);
- goto done;
- }
- break;
+ vassert(i->Xin.SseLdzLO.sz == 4 || i->Xin.SseLdzLO.sz == 8);
+ /* movs[sd] amode, %xmm-dst */
+ *p++ = i->Xin.SseLdzLO.sz==4 ? 0xF3 : 0xF2;
+ *p++ = 0x0F;
+ *p++ = 0x10;
+ p = doAMode_M(p, fake(vregNo(i->Xin.SseLdzLO.reg)),
+ i->Xin.SseLdzLO.addr);
+ goto done;
case Xin_Sse128:
*p++ = 0x0F;
*p++ = (UChar)(xtra & 0xFF);
goto done;
+ case Xin_Sse64Fx2:
+ xtra = 0;
+ *p++ = 0x66;
+ *p++ = 0x0F;
+ switch (i->Xin.Sse64Fx2.op) {
+ case Xsse_ADDF: *p++ = 0x58; break;
+ case Xsse_DIVF: *p++ = 0x5E; break;
+ case Xsse_MAXF: *p++ = 0x5F; break;
+ case Xsse_MINF: *p++ = 0x5D; break;
+ case Xsse_MULF: *p++ = 0x59; break;
+ case Xsse_RCPF: *p++ = 0x53; break;
+ case Xsse_RSQRTF: *p++ = 0x52; break;
+ case Xsse_SQRTF: *p++ = 0x51; break;
+ case Xsse_SUBF: *p++ = 0x5C; break;
+ case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
+ case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
+ case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
+ default: goto bad;
+ }
+ p = doAMode_R(p, fake(vregNo(i->Xin.Sse64Fx2.dst)),
+ fake(vregNo(i->Xin.Sse64Fx2.src)) );
+ if (xtra & 0x100)
+ *p++ = (UChar)(xtra & 0xFF);
+ goto done;
+
case Xin_Sse32FLo:
xtra = 0;
*p++ = 0xF3;
*p++ = (UChar)(xtra & 0xFF);
goto done;
+ case Xin_Sse64FLo:
+ xtra = 0;
+ *p++ = 0xF2;
+ *p++ = 0x0F;
+ switch (i->Xin.Sse64FLo.op) {
+ case Xsse_ADDF: *p++ = 0x58; break;
+ case Xsse_DIVF: *p++ = 0x5E; break;
+ case Xsse_MAXF: *p++ = 0x5F; break;
+ case Xsse_MINF: *p++ = 0x5D; break;
+ case Xsse_MULF: *p++ = 0x59; break;
+ case Xsse_RCPF: *p++ = 0x53; break;
+ case Xsse_RSQRTF: *p++ = 0x52; break;
+ case Xsse_SQRTF: *p++ = 0x51; break;
+ case Xsse_SUBF: *p++ = 0x5C; break;
+ case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
+ case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
+ case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
+ default: goto bad;
+ }
+ p = doAMode_R(p, fake(vregNo(i->Xin.Sse64FLo.dst)),
+ fake(vregNo(i->Xin.Sse64FLo.src)) );
+ if (xtra & 0x100)
+ *p++ = (UChar)(xtra & 0xFF);
+ goto done;
+
default:
goto bad;
}
Xin_SseLdzLO, /* SSE load low 32/64 bits, zero remainder of reg */
Xin_Sse128, /* SSE binary typeless (and/or/xor/andn) */
Xin_Sse32Fx4, /* SSE binary, 32Fx4 */
- Xin_Sse32FLo /* SSE binary, 32F in lowest lane only */
- // Xin_Sse64Fx2, /* SSE binary, 64Fx2 */
- // Xin_Sse64FLo, /* SSE binary, 64F in lowest lane only */
+ Xin_Sse32FLo, /* SSE binary, 32F in lowest lane only */
+ Xin_Sse64Fx2, /* SSE binary, 64Fx2 */
+ Xin_Sse64FLo /* SSE binary, 64F in lowest lane only */
/* Xin_SseUn32Fx4 */
}
X86InstrTag;
HReg src;
HReg dst;
} Sse32FLo;
+ struct {
+ X86SseOp op;
+ HReg src;
+ HReg dst;
+ } Sse64Fx2;
+ struct {
+ X86SseOp op;
+ HReg src;
+ HReg dst;
+ } Sse64FLo;
} Xin;
}
extern X86Instr* X86Instr_Sse128 ( X86SseOp, HReg, HReg );
extern X86Instr* X86Instr_Sse32Fx4 ( X86SseOp, HReg, HReg );
extern X86Instr* X86Instr_Sse32FLo ( X86SseOp, HReg, HReg );
+extern X86Instr* X86Instr_Sse64Fx2 ( X86SseOp, HReg, HReg );
+extern X86Instr* X86Instr_Sse64FLo ( X86SseOp, HReg, HReg );
extern void ppX86Instr ( X86Instr* );
return dst;
}
+ case Iop_Recip64Fx2: op = Xsse_RCPF; goto do_64Fx2_unary;
+ case Iop_RSqrt64Fx2: op = Xsse_RSQRTF; goto do_64Fx2_unary;
+ case Iop_Sqrt64Fx2: op = Xsse_SQRTF; goto do_64Fx2_unary;
+ do_64Fx2_unary:
+ {
+ HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
+ HReg dst = newVRegV(env);
+ addInstr(env, X86Instr_Sse64Fx2(op, arg, dst));
+ return dst;
+ }
+
case Iop_Recip32F0x4: op = Xsse_RCPF; goto do_32F0x4_unary;
case Iop_RSqrt32F0x4: op = Xsse_RSQRTF; goto do_32F0x4_unary;
case Iop_Sqrt32F0x4: op = Xsse_SQRTF; goto do_32F0x4_unary;
return dst;
}
+ case Iop_Recip64F0x2: op = Xsse_RCPF; goto do_64F0x2_unary;
+ case Iop_RSqrt64F0x2: op = Xsse_RSQRTF; goto do_64F0x2_unary;
+ case Iop_Sqrt64F0x2: op = Xsse_SQRTF; goto do_64F0x2_unary;
+ do_64F0x2_unary:
+ {
+ /* A bit subtle. We have to copy the arg to the result
+ register first, because actually doing the SSE scalar insn
+ leaves the upper half of the destination register
+ unchanged. Whereas the required semantics of these
+ primops is that the upper half is simply copied in from the
+ argument. */
+ HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
+ HReg dst = newVRegV(env);
+ addInstr(env, mk_vMOVsd_RR(arg, dst));
+ addInstr(env, X86Instr_Sse64FLo(op, arg, dst));
+ return dst;
+ }
+
case Iop_32Uto128: {
HReg dst = newVRegV(env);
X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
return dst;
}
+ case Iop_64Uto128: {
+ HReg rHi, rLo;
+ HReg dst = newVRegV(env);
+ X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
+ iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
+ addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
+ addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
+ addInstr(env, X86Instr_SseLdzLO(8, dst, esp0));
+ add_to_esp(env, 8);
+ return dst;
+ }
+
default:
break;
} /* switch (e->Iex.Unop.op) */
return dst;
}
+ case Iop_CmpEQ64Fx2: op = Xsse_CMPEQF; goto do_64Fx2;
+ case Iop_CmpLT64Fx2: op = Xsse_CMPLTF; goto do_64Fx2;
+ case Iop_CmpLE64Fx2: op = Xsse_CMPLEF; goto do_64Fx2;
+ case Iop_Add64Fx2: op = Xsse_ADDF; goto do_64Fx2;
+ case Iop_Div64Fx2: op = Xsse_DIVF; goto do_64Fx2;
+ case Iop_Max64Fx2: op = Xsse_MAXF; goto do_64Fx2;
+ case Iop_Min64Fx2: op = Xsse_MINF; goto do_64Fx2;
+ case Iop_Mul64Fx2: op = Xsse_MULF; goto do_64Fx2;
+ case Iop_Sub64Fx2: op = Xsse_SUBF; goto do_64Fx2;
+ do_64Fx2:
+ {
+ HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
+ HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
+ HReg dst = newVRegV(env);
+ addInstr(env, mk_vMOVsd_RR(argL, dst));
+ addInstr(env, X86Instr_Sse64Fx2(op, argR, dst));
+ return dst;
+ }
+
case Iop_CmpEQ32F0x4: op = Xsse_CMPEQF; goto do_32F0x4;
case Iop_CmpLT32F0x4: op = Xsse_CMPLTF; goto do_32F0x4;
case Iop_CmpLE32F0x4: op = Xsse_CMPLEF; goto do_32F0x4;
return dst;
}
+ case Iop_CmpEQ64F0x2: op = Xsse_CMPEQF; goto do_64F0x2;
+ case Iop_CmpLT64F0x2: op = Xsse_CMPLTF; goto do_64F0x2;
+ case Iop_CmpLE64F0x2: op = Xsse_CMPLEF; goto do_64F0x2;
+ case Iop_Add64F0x2: op = Xsse_ADDF; goto do_64F0x2;
+ case Iop_Div64F0x2: op = Xsse_DIVF; goto do_64F0x2;
+ case Iop_Max64F0x2: op = Xsse_MAXF; goto do_64F0x2;
+ case Iop_Min64F0x2: op = Xsse_MINF; goto do_64F0x2;
+ case Iop_Mul64F0x2: op = Xsse_MULF; goto do_64F0x2;
+ case Iop_Sub64F0x2: op = Xsse_SUBF; goto do_64F0x2;
+ do_64F0x2: {
+ HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
+ HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
+ HReg dst = newVRegV(env);
+ addInstr(env, mk_vMOVsd_RR(argL, dst));
+ addInstr(env, X86Instr_Sse64FLo(op, argR, dst));
+ return dst;
+ }
+
default:
break;
} /* switch (e->Iex.Binop.op) */
case Iop_Add32Fx4: vex_printf("Add32Fx4"); return;
case Iop_Add32F0x4: vex_printf("Add32F0x4"); return;
+ case Iop_Add64Fx2: vex_printf("Add64Fx2"); return;
+ case Iop_Add64F0x2: vex_printf("Add64F0x2"); return;
case Iop_Div32Fx4: vex_printf("Div32Fx4"); return;
case Iop_Div32F0x4: vex_printf("Div32F0x4"); return;
+ case Iop_Div64Fx2: vex_printf("Div64Fx2"); return;
+ case Iop_Div64F0x2: vex_printf("Div64F0x2"); return;
case Iop_Max32Fx4: vex_printf("Max32Fx4"); return;
case Iop_Max32F0x4: vex_printf("Max32F0x4"); return;
+ case Iop_Max64Fx2: vex_printf("Max64Fx2"); return;
+ case Iop_Max64F0x2: vex_printf("Max64F0x2"); return;
case Iop_Min32Fx4: vex_printf("Min32Fx4"); return;
case Iop_Min32F0x4: vex_printf("Min32F0x4"); return;
+ case Iop_Min64Fx2: vex_printf("Min64Fx2"); return;
+ case Iop_Min64F0x2: vex_printf("Min64F0x2"); return;
case Iop_Mul32Fx4: vex_printf("Mul32Fx4"); return;
case Iop_Mul32F0x4: vex_printf("Mul32F0x4"); return;
+ case Iop_Mul64Fx2: vex_printf("Mul64Fx2"); return;
+ case Iop_Mul64F0x2: vex_printf("Mul64F0x2"); return;
case Iop_Recip32Fx4: vex_printf("Recip32Fx4"); return;
case Iop_Recip32F0x4: vex_printf("Recip32F0x4"); return;
+ case Iop_Recip64Fx2: vex_printf("Recip64Fx2"); return;
+ case Iop_Recip64F0x2: vex_printf("Recip64F0x2"); return;
case Iop_RSqrt32Fx4: vex_printf("RSqrt32Fx4"); return;
case Iop_RSqrt32F0x4: vex_printf("RSqrt32F0x4"); return;
+ case Iop_RSqrt64Fx2: vex_printf("RSqrt64Fx2"); return;
+ case Iop_RSqrt64F0x2: vex_printf("RSqrt64F0x2"); return;
- case Iop_Sqrt32Fx4: vex_printf("Sqrt32Fx4"); return;
- case Iop_Sqrt32F0x4 : vex_printf("Sqrt32F0x4"); return;
+ case Iop_Sqrt32Fx4: vex_printf("Sqrt32Fx4"); return;
+ case Iop_Sqrt32F0x4: vex_printf("Sqrt32F0x4"); return;
+ case Iop_Sqrt64Fx2: vex_printf("Sqrt64Fx2"); return;
+ case Iop_Sqrt64F0x2: vex_printf("Sqrt64F0x2"); return;
case Iop_Sub32Fx4: vex_printf("Sub32Fx4"); return;
case Iop_Sub32F0x4: vex_printf("Sub32F0x4"); return;
+ case Iop_Sub64Fx2: vex_printf("Sub64Fx2"); return;
+ case Iop_Sub64F0x2: vex_printf("Sub64F0x2"); return;
case Iop_CmpEQ32Fx4: vex_printf("CmpEQ32Fx4"); return;
case Iop_CmpLT32Fx4: vex_printf("CmpLT32Fx4"); return;
case Iop_CmpLE32Fx4: vex_printf("CmpLE32Fx4"); return;
case Iop_CmpUN32Fx4: vex_printf("CmpUN32Fx4"); return;
+ case Iop_CmpEQ64Fx2: vex_printf("CmpEQ64Fx2"); return;
+ case Iop_CmpLT64Fx2: vex_printf("CmpLT64Fx2"); return;
+ case Iop_CmpLE64Fx2: vex_printf("CmpLE64Fx2"); return;
+ case Iop_CmpUN64Fx2: vex_printf("CmpUN64Fx2"); return;
case Iop_CmpEQ32F0x4: vex_printf("CmpEQ32F0x4"); return;
case Iop_CmpLT32F0x4: vex_printf("CmpLT32F0x4"); return;
case Iop_CmpLE32F0x4: vex_printf("CmpLE32F0x4"); return;
case Iop_CmpUN32F0x4: vex_printf("CmpUN32F0x4"); return;
+ case Iop_CmpEQ64F0x2: vex_printf("CmpEQ64F0x2"); return;
+ case Iop_CmpLT64F0x2: vex_printf("CmpLT64F0x2"); return;
+ case Iop_CmpLE64F0x2: vex_printf("CmpLE64F0x2"); return;
+ case Iop_CmpUN64F0x2: vex_printf("CmpUN64F0x2"); return;
case Iop_64HLto128: vex_printf("64HLto128"); return;
case Iop_128to64: vex_printf("128to64"); return;
case Iop_128HIto64: vex_printf("128HIto64"); return;
case Iop_32Uto128: vex_printf("32Uto128"); return;
+ case Iop_64Uto128: vex_printf("64Uto128"); return;
case Iop_Set128lo32: vex_printf("Set128lo32"); return;
default: vpanic("ppIROp(1)");
UNARY(Ity_I64, Ity_V128);
case Iop_32Uto128: UNARY(Ity_V128, Ity_I32);
+ case Iop_64Uto128: UNARY(Ity_V128, Ity_I64);
case Iop_Set128lo32: BINARY(Ity_V128, Ity_V128,Ity_I32);
case Iop_CmpEQ32Fx4: case Iop_CmpLT32Fx4:
+ case Iop_CmpEQ64Fx2: case Iop_CmpLT64Fx2:
case Iop_CmpLE32Fx4: case Iop_CmpUN32Fx4:
+ case Iop_CmpLE64Fx2: case Iop_CmpUN64Fx2:
case Iop_CmpEQ32F0x4: case Iop_CmpLT32F0x4:
+ case Iop_CmpEQ64F0x2: case Iop_CmpLT64F0x2:
case Iop_CmpLE32F0x4: case Iop_CmpUN32F0x4:
+ case Iop_CmpLE64F0x2: case Iop_CmpUN64F0x2:
case Iop_Add32Fx4: case Iop_Add32F0x4:
+ case Iop_Add64Fx2: case Iop_Add64F0x2:
case Iop_Div32Fx4: case Iop_Div32F0x4:
+ case Iop_Div64Fx2: case Iop_Div64F0x2:
case Iop_Max32Fx4: case Iop_Max32F0x4:
+ case Iop_Max64Fx2: case Iop_Max64F0x2:
case Iop_Min32Fx4: case Iop_Min32F0x4:
+ case Iop_Min64Fx2: case Iop_Min64F0x2:
case Iop_Mul32Fx4: case Iop_Mul32F0x4:
+ case Iop_Mul64Fx2: case Iop_Mul64F0x2:
case Iop_Sub32Fx4: case Iop_Sub32F0x4:
+ case Iop_Sub64Fx2: case Iop_Sub64F0x2:
case Iop_And128: case Iop_Or128: case Iop_Xor128:
BINARY(Ity_V128, Ity_V128,Ity_V128);
case Iop_Recip32Fx4: case Iop_Recip32F0x4:
+ case Iop_Recip64Fx2: case Iop_Recip64F0x2:
case Iop_RSqrt32Fx4: case Iop_RSqrt32F0x4:
+ case Iop_RSqrt64Fx2: case Iop_RSqrt64F0x2:
case Iop_Sqrt32Fx4: case Iop_Sqrt32F0x4:
+ case Iop_Sqrt64Fx2: case Iop_Sqrt64F0x2:
UNARY(Ity_V128, Ity_V128);
default:
Iop_Add32Fx4, Iop_Sub32Fx4, Iop_Mul32Fx4, Iop_Div32Fx4,
Iop_Max32Fx4, Iop_Min32Fx4,
Iop_CmpEQ32Fx4, Iop_CmpLT32Fx4, Iop_CmpLE32Fx4, Iop_CmpUN32Fx4,
- Iop_CmpEQ32F0x4, Iop_CmpLT32F0x4, Iop_CmpLE32F0x4, Iop_CmpUN32F0x4,
/* unary */
Iop_Recip32Fx4, Iop_Sqrt32Fx4, Iop_RSqrt32Fx4,
- //Iop_ItoF32x4, /* first arg is IRRoundingMode (Ity_I32) */
- //Iop_FtoI32x4, /* first arg is IRRoundingMode (Ity_I32) */
/* --- 32x4 lowest-lane-only scalar FP --- */
/* binary */
Iop_Add32F0x4, Iop_Sub32F0x4, Iop_Mul32F0x4, Iop_Div32F0x4,
Iop_Max32F0x4, Iop_Min32F0x4,
+ Iop_CmpEQ32F0x4, Iop_CmpLT32F0x4, Iop_CmpLE32F0x4, Iop_CmpUN32F0x4,
/* unary */
Iop_Recip32F0x4, Iop_Sqrt32F0x4, Iop_RSqrt32F0x4,
- //Iop_ItoF320x4, /* first arg is IRRoundingMode (Ity_I32) */
- //Iop_FtoI320x4, /* first arg is IRRoundingMode (Ity_I32) */
+
+ /* --- 64x2 vector FP --- */
+
+ /* binary */
+ Iop_Add64Fx2, Iop_Sub64Fx2, Iop_Mul64Fx2, Iop_Div64Fx2,
+ Iop_Max64Fx2, Iop_Min64Fx2,
+ Iop_CmpEQ64Fx2, Iop_CmpLT64Fx2, Iop_CmpLE64Fx2, Iop_CmpUN64Fx2,
+
+ /* unary */
+ Iop_Recip64Fx2, Iop_Sqrt64Fx2, Iop_RSqrt64Fx2,
+
+ /* --- 64x2 lowest-lane-only scalar FP --- */
+
+ /* In binary cases, upper half is copied from first operand. In
+ unary cases, upper half is copied from the operand. */
+
+ /* binary */
+ Iop_Add64F0x2, Iop_Sub64F0x2, Iop_Mul64F0x2, Iop_Div64F0x2,
+ Iop_Max64F0x2, Iop_Min64F0x2,
+ Iop_CmpEQ64F0x2, Iop_CmpLT64F0x2, Iop_CmpLE64F0x2, Iop_CmpUN64F0x2,
+
+ /* unary */
+ Iop_Recip64F0x2, Iop_Sqrt64F0x2, Iop_RSqrt64F0x2,
/* --- pack / unpack --- */
Iop_64HLto128, // :: (I64,I64) -> V128
Iop_32Uto128,
+ Iop_64Uto128,
Iop_Set128lo32,
/* 128 -> 32 bit unpack */
//Iop_128W3to32, // :: V128 -> I32, bits 127-96