fp_pop();
}
-//.. /* ST(dst) = ST(src) `op` ST(dst).
-//.. Check dst and src tags when reading but not on write.
-//.. */
-//.. static
-//.. void fp_do_oprev_ST_ST ( UChar* op_txt, IROp op, UInt st_src, UInt st_dst,
-//.. Bool pop_after )
-//.. {
-//.. DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"", st_src, st_dst );
-//.. put_ST_UNCHECKED(
-//.. st_dst,
-//.. binop(op, get_ST(st_src), get_ST(st_dst) )
-//.. );
-//.. if (pop_after)
-//.. fp_pop();
-//.. }
+/* ST(dst) = ST(src) `op` ST(dst).
+ Check dst and src tags when reading but not on write.
+*/
+static
+void fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
+ Bool pop_after )
+{
+ DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
+ put_ST_UNCHECKED(
+ st_dst,
+ binop(op, get_ST(st_src), get_ST(st_dst) )
+ );
+ if (pop_after)
+ fp_pop();
+}
/* %rflags(Z,P,C) = UCOMI( st(0), st(i) ) */
static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
break;
-//.. case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
-//.. fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
-//.. break;
-//..
+ case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
+ fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
+ break;
+
//.. #if 1
//.. /* Dunno if this is right */
//.. case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
//.. fp_pop();
//.. break;
//.. #endif
-//.. case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
-//.. fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
-//.. break;
-//..
+ case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
+ fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
+ break;
+
//.. case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
//.. fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
//.. break;
-//..
-//.. case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
-//.. fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
-//.. break;
-//..
+
+ case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
+ fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
+ break;
+
//.. case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
//.. fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
//.. break;
put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
break;
-//.. case 0xE1: /* FABS */
-//.. DIP("fabs\n");
-//.. put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
-//.. break;
-//..
+ case 0xE1: /* FABS */
+ DIP("fabs\n");
+ put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
+ break;
+
//.. case 0xE5: { /* FXAM */
//.. /* This is an interesting one. It examines %st(0),
//.. regardless of whether the tag says it's empty or not.
case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
r_src = (UInt)modrm - 0xC8;
DIP("fcmovnz %%st(%d), %%st(0)\n", r_src);
- put_ST_UNCHECKED(0,
- IRExpr_Mux0X(
- unop(Iop_1Uto8,
- mk_amd64g_calculate_condition(AMD64CondNZ)),
- get_ST(0), get_ST(r_src)) );
+ put_ST_UNCHECKED(
+ 0,
+ IRExpr_Mux0X(
+ unop(Iop_1Uto8,
+ mk_amd64g_calculate_condition(AMD64CondNZ)),
+ get_ST(0),
+ get_ST(r_src)
+ )
+ );
+ break;
+
+ case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
+ r_src = (UInt)modrm - 0xD0;
+ DIP("fcmovnbe %%st(%d), %%st(0)\n", r_src);
+ put_ST_UNCHECKED(
+ 0,
+ IRExpr_Mux0X(
+ unop(Iop_1Uto8,
+ mk_amd64g_calculate_condition(AMD64CondNBE)),
+ get_ST(0),
+ get_ST(r_src)
+ )
+ );
break;
-//.. case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
-//.. r_src = (UInt)modrm - 0xD0;
-//.. DIP("fcmovnbe %%st(%d), %%st(0)\n", r_src);
-//.. put_ST_UNCHECKED(0,
-//.. IRExpr_Mux0X(
-//.. unop(Iop_1Uto8,
-//.. mk_x86g_calculate_condition(X86CondNBE)),
-//.. get_ST(0), get_ST(r_src)) );
-//.. break;
-//..
//.. case 0xE2:
//.. DIP("fnclex\n");
//.. break;
}
}
-//.. /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
-//.. else
-//.. if (first_opcode == 0xDC) {
-//.. if (modrm < 0xC0) {
-//..
+ /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
+ else
+ if (first_opcode == 0xDC) {
+ if (modrm < 0xC0) {
+
//.. /* bits 5,4,3 are an opcode extension, and the modRM also
//.. specifies an address. */
//.. IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
//.. vex_printf("first_opcode == 0xDC\n");
//.. goto decode_fail;
//.. }
-//..
-//.. } else {
-//..
-//.. delta++;
-//.. switch (modrm) {
-//..
-//.. case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
-//.. fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
-//.. break;
-//..
+
+ } else {
+
+ delta++;
+ switch (modrm) {
+
+ case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
+ fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
+ break;
+
//.. case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
//.. fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
//.. break;
//.. case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
//.. fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
//.. break;
-//..
-//.. case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
-//.. fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
-//.. break;
-//..
-//.. default:
-//.. goto decode_fail;
-//.. }
-//..
-//.. }
-//.. }
+
+ case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
+ fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
+ break;
+
+ default:
+ goto decode_fail;
+ }
+
+ }
+ }
/* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
else
}
}
-//.. /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
-//.. else
-//.. if (first_opcode == 0xDE) {
-//..
-//.. if (modrm < 0xC0) {
-//..
+ /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
+ else
+ if (first_opcode == 0xDE) {
+
+ if (modrm < 0xC0) {
+
//.. /* bits 5,4,3 are an opcode extension, and the modRM also
//.. specifies an address. */
-//.. IROp fop;
-//.. IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
+//.. IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
//.. delta += len;
//..
-//.. switch (gregOfRM(modrm)) {
+//.. switch (gregLO3ofRM(modrm)) {
//..
//.. case 0: /* FIADD m16int */ /* ST(0) += m16int */
//.. DIP("fiaddw %s\n", dis_buf);
//.. break;
//..
//.. default:
-//.. vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
+//.. vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
//.. vex_printf("first_opcode == 0xDE\n");
//.. goto decode_fail;
//.. }
-//..
-//.. } else {
-//..
-//.. delta++;
-//.. switch (modrm) {
-//..
-//.. case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
-//.. fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
-//.. break;
-//..
-//.. case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
-//.. fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
-//.. break;
-//..
+
+ } else {
+
+ delta++;
+ switch (modrm) {
+
+ case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
+ fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
+ break;
+
+ case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
+ fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
+ break;
+
//.. case 0xD9: /* FCOMPP %st(0),%st(1) */
//.. DIP("fuompp %%st(0),%%st(1)\n");
//.. /* This forces C1 to zero, which isn't right. */
//.. fp_pop();
//.. fp_pop();
//.. break;
-//..
-//.. case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
-//.. fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
-//.. break;
-//..
-//.. case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
-//.. fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
-//.. break;
-//..
-//.. case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
-//.. fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
-//.. break;
-//..
-//.. case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
-//.. fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
-//.. break;
-//..
-//.. default:
-//.. goto decode_fail;
-//.. }
-//..
-//.. }
-//.. }
+
+ case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
+ fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
+ break;
+
+ case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
+ fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
+ break;
+
+ case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
+ fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
+ break;
+
+ case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
+ fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
+ break;
+
+ default:
+ goto decode_fail;
+ }
+
+ }
+ }
/* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
else
}
else
- goto decode_fail; //vpanic("dis_FPU(amd64): invalid primary opcode");
+ goto decode_fail;
*decode_ok = True;
return delta;
delta = dis_op_imm_A( sz, Iop_And8, True, delta, "and" );
break;
-//.. case 0x2C: /* SUB Ib, AL */
-//.. delta = dis_op_imm_A(1, Iop_Sub8, True, delta, "sub" );
-//.. break;
+ case 0x2C: /* SUB Ib, AL */
+ if (haveF2orF3(pfx)) goto decode_failure;
+ delta = dis_op_imm_A(1, Iop_Sub8, True, delta, "sub" );
+ break;
case 0x2D: /* SUB Iv, eAX */
if (haveF2orF3(pfx)) goto decode_failure;
delta = dis_op_imm_A( sz, Iop_Sub8, True, delta, "sub" );
return res;
}
+ if (e->tag == Iex_Binop) {
+ AMD64SseOp op = Asse_INVALID;
+ switch (e->Iex.Binop.op) {
+ case Iop_AddF64: op = Asse_ADDF; break;
+ case Iop_SubF64: op = Asse_SUBF; break;
+ case Iop_MulF64: op = Asse_MULF; break;
+ case Iop_DivF64: op = Asse_DIVF; break;
+ default: break;
+ }
+ if (op != Asse_INVALID) {
+ HReg dst = newVRegV(env);
+ HReg argL = iselDblExpr(env, e->Iex.Binop.arg1);
+ HReg argR = iselDblExpr(env, e->Iex.Binop.arg2);
+ addInstr(env, mk_vMOVsd_RR(argL, dst));
+ addInstr(env, AMD64Instr_Sse64FLo(op, argR, dst));
+ return dst;
+ }
+ }
+
//.. if (e->tag == Iex_Binop) {
//.. X86FpOp fpop = Xfp_INVALID;
//.. switch (e->Iex.Binop.op) {
return dst;
}
- if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_NegF64) {
+ if (e->tag == Iex_Unop
+ && (e->Iex.Unop.op == Iop_NegF64
+ || e->Iex.Unop.op == Iop_AbsF64)) {
/* Sigh ... very rough code. Could do much better. */
+ /* Get the 128-bit literal 00---0 10---0 into a register
+ and xor/nand it with the value to be negated. */
HReg r1 = newVRegI(env);
HReg dst = newVRegV(env);
- HReg tv = newVRegV(env);
+ HReg tmp = newVRegV(env);
HReg src = iselDblExpr(env, e->Iex.Unop.arg);
AMD64AMode* rsp0 = AMD64AMode_IR(0, hregAMD64_RSP());
- addInstr(env, mk_vMOVsd_RR(src,dst));
+ addInstr(env, mk_vMOVsd_RR(src,tmp));
addInstr(env, AMD64Instr_Push(AMD64RMI_Imm(0)));
addInstr(env, AMD64Instr_Imm64( 1ULL<<63, r1 ));
addInstr(env, AMD64Instr_Push(AMD64RMI_Reg(r1)));
- addInstr(env, AMD64Instr_SseLdSt(True, 16, tv, rsp0));
- addInstr(env, AMD64Instr_SseReRg(Asse_XOR, tv, dst));
+ addInstr(env, AMD64Instr_SseLdSt(True, 16, dst, rsp0));
+
+ if (e->Iex.Unop.op == Iop_NegF64)
+ addInstr(env, AMD64Instr_SseReRg(Asse_XOR, tmp, dst));
+ else
+ addInstr(env, AMD64Instr_SseReRg(Asse_ANDN, tmp, dst));
+
add_to_rsp(env, 16);
return dst;
}
return dst;
}
-//.. case Iop_CmpEQ64F0x2: op = Xsse_CMPEQF; goto do_64F0x2;
+ case Iop_CmpEQ64F0x2: op = Asse_CMPEQF; goto do_64F0x2;
case Iop_CmpLT64F0x2: op = Asse_CMPLTF; goto do_64F0x2;
-//.. case Iop_CmpLE64F0x2: op = Xsse_CMPLEF; goto do_64F0x2;
+ case Iop_CmpLE64F0x2: op = Asse_CMPLEF; goto do_64F0x2;
case Iop_Add64F0x2: op = Asse_ADDF; goto do_64F0x2;
case Iop_Div64F0x2: op = Asse_DIVF; goto do_64F0x2;
case Iop_Max64F0x2: op = Asse_MAXF; goto do_64F0x2;