guest x87: Add enough x87 FP gunk to get through
none/tests/x86/insn_fpu without dying.
git-svn-id: svn://svn.valgrind.org/vex/trunk@597 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest-x86/toIR.c b/priv/guest-x86/toIR.c
index 685dd8a..40b13fe 100644
--- a/priv/guest-x86/toIR.c
+++ b/priv/guest-x86/toIR.c
@@ -3624,6 +3624,8 @@
Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
documentation implies A and S are unchanged.
*/
+ /* It's also fishy in that it is used both for COMIP and
+ UCOMIP, and they aren't the same (although similar). */
stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
stmt( IRStmt_Put( OFFB_CC_DEP1,
@@ -3792,7 +3794,7 @@
if (modrm < 0xC0) {
/* bits 5,4,3 are an opcode extension, and the modRM also
- specifies an address. */
+ specifies an address. */
IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
delta += len;
@@ -4017,6 +4019,11 @@
break;
}
+ case 0xF7: /* FINCSTP */
+ DIP("fprem\n");
+ put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
+ break;
+
case 0xF8: { /* FPREM -- not IEEE compliant */
IRTemp a1 = newTemp(Ity_F64);
IRTemp a2 = newTemp(Ity_F64);
@@ -4079,7 +4086,7 @@
if (modrm < 0xC0) {
- /* bits 5,4,3 are an opcode extension, and the modRM also
+ /* 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 );
@@ -4178,7 +4185,7 @@
if (first_opcode == 0xDB) {
if (modrm < 0xC0) {
- /* bits 5,4,3 are an opcode extension, and the modRM also
+ /* bits 5,4,3 are an opcode extension, and the modRM also
specifies an address. */
IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
delta += len;
@@ -4298,7 +4305,7 @@
if (modrm < 0xC0) {
/* bits 5,4,3 are an opcode extension, and the modRM also
- specifies an address. */
+ specifies an address. */
IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
delta += len;
@@ -4405,7 +4412,7 @@
if (modrm < 0xC0) {
- /* bits 5,4,3 are an opcode extension, and the modRM also
+ /* bits 5,4,3 are an opcode extension, and the modRM also
specifies an address. */
IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
delta += len;
@@ -4598,7 +4605,68 @@
if (first_opcode == 0xDE) {
if (modrm < 0xC0) {
- goto decode_fail;
+
+ /* 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 );
+ delta += len;
+
+ switch (gregOfRM(modrm)) {
+
+ case 0: /* FIADD m16int */ /* ST(0) += m16int */
+ DIP("fiaddw %s", dis_buf);
+ fop = Iop_AddF64;
+ goto do_fop_m16;
+
+ case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
+ DIP("fimulw %s", dis_buf);
+ fop = Iop_MulF64;
+ goto do_fop_m16;
+
+ case 4: /* FISUB m16int */ /* ST(0) -= m16int */
+ DIP("fisubw %s", dis_buf);
+ fop = Iop_SubF64;
+ goto do_fop_m16;
+
+ case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
+ DIP("fisubrw %s", dis_buf);
+ fop = Iop_SubF64;
+ goto do_foprev_m16;
+
+ case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
+ DIP("fisubw %s", dis_buf);
+ fop = Iop_DivF64;
+ goto do_fop_m16;
+
+ case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
+ DIP("fidivrw %s", dis_buf);
+ fop = Iop_DivF64;
+ goto do_foprev_m16;
+
+ do_fop_m16:
+ put_ST_UNCHECKED(0,
+ binop(fop,
+ get_ST(0),
+ unop(Iop_I32toF64,
+ unop(Iop_16Sto32,
+ loadLE(Ity_I16, mkexpr(addr))))));
+ break;
+
+ do_foprev_m16:
+ put_ST_UNCHECKED(0,
+ binop(fop,
+ unop(Iop_I32toF64,
+ unop(Iop_16Sto32,
+ loadLE(Ity_I16, mkexpr(addr)))),
+ get_ST(0)));
+ break;
+
+ default:
+ vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
+ vex_printf("first_opcode == 0xDE\n");
+ goto decode_fail;
+ }
} else {
@@ -4656,7 +4724,7 @@
if (modrm < 0xC0) {
- /* bits 5,4,3 are an opcode extension, and the modRM also
+ /* bits 5,4,3 are an opcode extension, and the modRM also
specifies an address. */
IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
delta += len;
@@ -4729,6 +4797,11 @@
fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
break;
+ case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
+ /* not really right since COMIP != UCOMIP */
+ fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
+ break;
+
default:
goto decode_fail;
}
@@ -6619,7 +6692,7 @@
/*OUT*/ Addr64* whereNext )
{
IRType ty;
- IRTemp addr, t1, t2;
+ IRTemp addr, t1, t2, t3, t4;
Int alen;
UChar opc, modrm, abyte;
UInt d32;
@@ -6646,8 +6719,7 @@
assert. */
*size = 0;
- addr = t1 = t2 = IRTemp_INVALID;
- //t3 = t4 = IRTemp_INVALID;
+ addr = t1 = t2 = t3 = t4 = IRTemp_INVALID;
DIP("\t0x%x: ", guest_eip_bbstart+delta);
@@ -8786,47 +8858,40 @@
//-- DIP("popa%c\n", nameISize(sz));
//-- break;
//-- }
-//--
-//-- case 0x8F: /* POPL/POPW m32 */
-//-- { UInt pair1;
-//-- Int tmpa;
-//-- UChar rm = getIByte(delta);
-//--
-//-- /* make sure this instruction is correct POP */
-//-- vg_assert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
-//-- /* and has correct size */
-//-- vg_assert(sz == 4);
-//--
-//-- t1 = newTemp(cb); t3 = newTemp(cb);
-//-- /* set t1 to ESP: t1 = ESP */
-//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
-//-- /* load M[ESP] to virtual register t3: t3 = M[t1] */
-//-- uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t3);
-//--
-//-- /* increase ESP; must be done before the STORE. Intel manual says:
-//-- If the ESP register is used as a base register for addressing
-//-- a destination operand in memory, the POP instruction computes
-//-- the effective address of the operand after it increments the
-//-- ESP register.
-//-- */
-//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
-//-- uLiteral(cb, sz);
-//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
-//--
-//-- /* resolve MODR/M */
-//-- pair1 = disAMode ( cb, sorb, eip, dis_buf );
-//--
-//-- tmpa = LOW24(pair1);
-//-- /* uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpa); */
-//-- /* store value from stack in memory, M[m32] = t3 */
-//-- uInstr2(cb, STORE, 4, TempReg, t3, TempReg, tmpa);
-//--
-//-- DIP("popl %s\n", dis_buf);
-//--
-//-- eip += HI8(pair1);
-//-- break;
-//-- }
-//--
+
+ case 0x8F: /* POPL/POPW m32 */
+ { Int len;
+ UChar rm = getIByte(delta);
+
+ /* make sure this instruction is correct POP */
+ vassert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
+ /* and has correct size */
+ vassert(sz == 4);
+
+ t1 = newTemp(Ity_I32); t3 = newTemp(Ity_I32);
+ /* set t1 to ESP: t1 = ESP */
+ assign( t1, getIReg(4, R_ESP) );
+ /* load M[ESP] to virtual register t3: t3 = M[t1] */
+ assign( t3, loadLE(Ity_I32, mkexpr(t1)) );
+
+ /* increase ESP; must be done before the STORE. Intel manual says:
+ If the ESP register is used as a base register for addressing
+ a destination operand in memory, the POP instruction computes
+ the effective address of the operand after it increments the
+ ESP register.
+ */
+ putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(sz)) );
+
+ /* resolve MODR/M */
+ addr = disAMode ( &len, sorb, delta, dis_buf);
+ storeLE( mkexpr(addr), mkexpr(t3) );
+
+ DIP("popl %s\n", dis_buf);
+
+ delta += len;
+ break;
+ }
+
//-- case 0x1F: /* POP %DS */
//-- dis_pop_segreg( cb, R_DS, sz ); break;
//-- case 0x07: /* POP %ES */
@@ -8874,7 +8939,6 @@
break;
case 0x9C: /* PUSHF */ {
- IRTemp t3, t4;
vassert(sz == 2 || sz == 4);
vassert(sz == 4); // wait for sz==2 test case