From: Julian Seward Date: Fri, 25 Feb 2005 13:03:03 +0000 (+0000) Subject: Fill in a bunch more amd64 floating point cases. Some non-trivial X-Git-Tag: svn/VALGRIND_3_0_1^2~369 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=aa4d1e2dcccd1ebb424b4fa66e8da8b95d06be2d;p=thirdparty%2Fvalgrind.git Fill in a bunch more amd64 floating point cases. Some non-trivial FP programs are beginning to work now. git-svn-id: svn://svn.valgrind.org/vex/trunk@965 --- diff --git a/VEX/priv/guest-amd64/toIR.c b/VEX/priv/guest-amd64/toIR.c index 4f1518b5bf..2962f929e8 100644 --- a/VEX/priv/guest-amd64/toIR.c +++ b/VEX/priv/guest-amd64/toIR.c @@ -345,7 +345,7 @@ static void unimplemented ( HChar* str ) #define OFFB_IDFLAG offsetof(VexGuestAMD64State,guest_IDFLAG) #define OFFB_FTOP offsetof(VexGuestAMD64State,guest_FTOP) //.. #define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210) -//.. #define OFFB_FPROUND offsetof(VexGuestX86State,guest_FPROUND) +#define OFFB_FPROUND offsetof(VexGuestAMD64State,guest_FPROUND) //.. //.. #define OFFB_CS offsetof(VexGuestX86State,guest_CS) //.. #define OFFB_DS offsetof(VexGuestX86State,guest_DS) @@ -1214,10 +1214,10 @@ static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno ) return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 ); } -//.. static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno ) -//.. { -//.. return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 ); -//.. } +static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno ) +{ + return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 ); +} static void putXMMReg ( UInt xmmreg, IRExpr* e ) { @@ -3939,31 +3939,32 @@ static void put_ftop ( IRExpr* e ) //.. { //.. stmt( IRStmt_Put( OFFB_FC3210, e ) ); //.. } -//.. -//.. /* --------- Get/put the FPU rounding mode. --------- */ -//.. static IRExpr* /* :: Ity_I32 */ get_fpround ( void ) -//.. { -//.. return IRExpr_Get( OFFB_FPROUND, Ity_I32 ); -//.. } -//.. + +/* --------- Get/put the FPU rounding mode. --------- */ +static IRExpr* /* :: Ity_I32 */ get_fpround ( void ) +{ + return unop(Iop_64to32, IRExpr_Get( OFFB_FPROUND, Ity_I64 )); +} + //.. static void put_fpround ( IRExpr* /* :: Ity_I32 */ e ) //.. { -//.. stmt( IRStmt_Put( OFFB_FPROUND, e ) ); -//.. } -//.. -//.. -//.. /* --------- Synthesise a 2-bit FPU rounding mode. --------- */ -//.. /* Produces a value in 0 .. 3, which is encoded as per the type -//.. IRRoundingMode. Since the guest_FPROUND value is also encoded as -//.. per IRRoundingMode, we merely need to get it and mask it for -//.. safety. -//.. */ -//.. static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void ) -//.. { -//.. return binop( Iop_And32, get_fpround(), mkU32(3) ); +//.. vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32); +//.. stmt( IRStmt_Put( OFFB_FPROUND, unop(Iop_32Uto64,e) ) ); //.. } +/* --------- Synthesise a 2-bit FPU rounding mode. --------- */ +/* Produces a value in 0 .. 3, which is encoded as per the type + IRRoundingMode. Since the guest_FPROUND value is also encoded as + per IRRoundingMode, we merely need to get it and mask it for + safety. +*/ +static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void ) +{ + return binop( Iop_And32, get_fpround(), mkU32(3) ); +} + + /* --------- Get/set FP register tag bytes. --------- */ /* Given i, and some expression e, generate 'ST_TAG(i) = e'. */ @@ -4153,27 +4154,29 @@ static void fp_pop ( void ) //.. if (pop_after) //.. fp_pop(); //.. } -//.. -//.. /* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */ -//.. static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after ) -//.. { -//.. DIP("fucomi%s %%st(0),%%st(%d)\n", pop_after ? "p" : "", i); -//.. /* This is a bit of a hack (and isn't really right). It sets -//.. 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, -//.. binop( Iop_And32, -//.. binop(Iop_CmpF64, get_ST(0), get_ST(i)), -//.. mkU32(0x45) -//.. ))); -//.. 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 ) +{ + DIP("fucomi%s %%st(0),%%st(%d)\n", pop_after ? "p" : "", i); + /* This is a bit of a hack (and isn't really right). It sets + 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, mkU64(AMD64G_CC_OP_COPY) )); + stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) )); + stmt( IRStmt_Put( + OFFB_CC_DEP1, + binop( Iop_And64, + unop( Iop_32Uto64, + binop(Iop_CmpF64, get_ST(0), get_ST(i))), + mkU64(0x45) + ))); + if (pop_after) + fp_pop(); +} static @@ -4338,26 +4341,26 @@ ULong dis_FPU ( Bool* decode_ok, Prefix pfx, ULong delta ) switch (gregOfRM(modrm)) { -//.. case 0: /* FLD single-real */ -//.. DIP("flds %s\n", dis_buf); -//.. fp_push(); -//.. put_ST(0, unop(Iop_F32toF64, -//.. loadLE(Ity_F32, mkexpr(addr)))); -//.. break; -//.. -//.. case 2: /* FST single-real */ -//.. DIP("fsts %s\n", dis_buf); -//.. storeLE(mkexpr(addr), -//.. binop(Iop_F64toF32, get_roundingmode(), get_ST(0))); -//.. break; -//.. -//.. case 3: /* FSTP single-real */ -//.. DIP("fstps %s\n", dis_buf); -//.. storeLE(mkexpr(addr), -//.. binop(Iop_F64toF32, get_roundingmode(), get_ST(0))); -//.. fp_pop(); -//.. break; -//.. + case 0: /* FLD single-real */ + DIP("flds %s\n", dis_buf); + fp_push(); + put_ST(0, unop(Iop_F32toF64, + loadLE(Ity_F32, mkexpr(addr)))); + break; + + case 2: /* FST single-real */ + DIP("fsts %s\n", dis_buf); + storeLE(mkexpr(addr), + binop(Iop_F64toF32, get_roundingmode(), get_ST(0))); + break; + + case 3: /* FSTP single-real */ + DIP("fstps %s\n", dis_buf); + storeLE(mkexpr(addr), + binop(Iop_F64toF32, get_roundingmode(), get_ST(0))); + fp_pop(); + break; + //.. case 4: { /* FLDENV m108 */ //.. /* Uses dirty helper: //.. VexEmWarn x86g_do_FLDENV ( VexGuestX86State*, Addr32 ) */ @@ -4525,14 +4528,14 @@ ULong dis_FPU ( Bool* decode_ok, Prefix pfx, ULong delta ) delta++; switch (modrm) { -//.. case 0xC0 ... 0xC7: /* FLD %st(?) */ -//.. r_src = (UInt)modrm - 0xC0; -//.. DIP("fld %%st(%d)\n", r_src); -//.. t1 = newTemp(Ity_F64); -//.. assign(t1, get_ST(r_src)); -//.. fp_push(); -//.. put_ST(0, mkexpr(t1)); -//.. break; + case 0xC0 ... 0xC7: /* FLD %st(?) */ + r_src = (UInt)modrm - 0xC0; + DIP("fld %%st(%d)\n", r_src); + t1 = newTemp(Ity_F64); + assign(t1, get_ST(r_src)); + fp_push(); + put_ST(0, mkexpr(t1)); + break; case 0xC8 ... 0xCF: /* FXCH %st(?) */ r_src = (UInt)modrm - 0xC8; @@ -4574,14 +4577,14 @@ ULong dis_FPU ( Bool* decode_ok, Prefix pfx, ULong delta ) //.. DIP("fxam\n"); //.. break; //.. } -//.. -//.. case 0xE8: /* FLD1 */ -//.. DIP("fld1\n"); -//.. fp_push(); -//.. /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */ -//.. put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL))); -//.. break; -//.. + + case 0xE8: /* FLD1 */ + DIP("fld1\n"); + fp_push(); + /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */ + put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL))); + break; + //.. case 0xE9: /* FLDL2T */ //.. DIP("fldl2t\n"); //.. fp_push(); @@ -4616,14 +4619,14 @@ ULong dis_FPU ( Bool* decode_ok, Prefix pfx, ULong delta ) //.. /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */ //.. put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL))); //.. break; -//.. -//.. case 0xEE: /* FLDZ */ -//.. DIP("fldz\n"); -//.. fp_push(); -//.. /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */ -//.. put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL))); -//.. break; -//.. + + case 0xEE: /* FLDZ */ + DIP("fldz\n"); + fp_push(); + /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */ + put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL))); + break; + //.. case 0xF0: /* F2XM1 */ //.. DIP("f2xm1\n"); //.. put_ST_UNCHECKED(0, unop(Iop_2xm1F64, get_ST(0))); @@ -4857,18 +4860,18 @@ ULong dis_FPU ( Bool* decode_ok, Prefix pfx, ULong delta ) } } -//.. /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */ -//.. else -//.. if (first_opcode == 0xDB) { -//.. 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 ); -//.. delta += len; -//.. -//.. switch (gregOfRM(modrm)) { -//.. + /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */ + else + if (first_opcode == 0xDB) { + if (modrm < 0xC0) { + + /* bits 5,4,3 are an opcode extension, and the modRM also + specifies an address. */ + IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 ); + delta += len; + + switch (gregOfRM(modrm)) { + //.. case 0: /* FILD m32int */ //.. DIP("fildl %s\n", dis_buf); //.. fp_push(); @@ -4940,18 +4943,18 @@ ULong dis_FPU ( Bool* decode_ok, Prefix pfx, ULong delta ) //.. DIP("fstpt\n %s", dis_buf); //.. break; //.. } -//.. -//.. default: -//.. vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm)); -//.. vex_printf("first_opcode == 0xDB\n"); -//.. goto decode_fail; -//.. } -//.. -//.. } else { -//.. -//.. delta++; -//.. switch (modrm) { -//.. + + default: + vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm)); + vex_printf("first_opcode == 0xDB\n"); + goto decode_fail; + } + + } else { + + delta++; + switch (modrm) { + //.. case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */ //.. r_src = (UInt)modrm - 0xC0; //.. DIP("fcmovnb %%st(%d), %%st(0)\n", r_src); @@ -5025,21 +5028,21 @@ ULong dis_FPU ( Bool* decode_ok, Prefix pfx, ULong delta ) //.. DIP("fninit\n"); //.. break; //.. } -//.. -//.. case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */ -//.. fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False ); -//.. break; -//.. + + case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */ + fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False ); + break; + //.. case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */ //.. fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False ); //.. break; -//.. -//.. default: -//.. goto decode_fail; -//.. } -//.. } -//.. } -//.. + + default: + goto decode_fail; + } + } + } + //.. /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */ //.. else //.. if (first_opcode == 0xDC) { @@ -5166,10 +5169,10 @@ ULong dis_FPU ( Bool* decode_ok, Prefix pfx, ULong delta ) put_ST(0, IRExpr_LDle(Ity_F64, mkexpr(addr))); break; -//.. case 2: /* FST double-real */ -//.. DIP("fstl %s\n", dis_buf); -//.. storeLE(mkexpr(addr), get_ST(0)); -//.. break; + case 2: /* FST double-real */ + DIP("fstl %s\n", dis_buf); + storeLE(mkexpr(addr), get_ST(0)); + break; case 3: /* FSTP double-real */ DIP("fstpl %s\n", dis_buf); @@ -5458,20 +5461,20 @@ ULong dis_FPU ( Bool* decode_ok, Prefix pfx, ULong delta ) //.. //.. } //.. } -//.. -//.. /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */ -//.. else -//.. if (first_opcode == 0xDF) { -//.. -//.. 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 ); -//.. delta += len; -//.. -//.. switch (gregOfRM(modrm)) { -//.. + + /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */ + else + if (first_opcode == 0xDF) { + + if (modrm < 0xC0) { + + /* bits 5,4,3 are an opcode extension, and the modRM also + specifies an address. */ + IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 ); + delta += len; + + switch (gregOfRM(modrm)) { + //.. case 0: /* FILD m16int */ //.. DIP("fildw %s\n", dis_buf); //.. fp_push(); @@ -5507,18 +5510,24 @@ ULong dis_FPU ( Bool* decode_ok, Prefix pfx, ULong delta ) //.. binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) ); //.. fp_pop(); //.. break; -//.. -//.. default: -//.. vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm)); -//.. vex_printf("first_opcode == 0xDF\n"); -//.. goto decode_fail; -//.. } -//.. -//.. } else { -//.. -//.. delta++; -//.. switch (modrm) { -//.. + + default: + vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm)); + vex_printf("first_opcode == 0xDF\n"); + goto decode_fail; + } + + } else { + + delta++; + switch (modrm) { + + case 0xC0: /* FFREEP %st(0) */ + DIP("ffreep %%st(%d)\n", 0); + put_ST_TAG ( 0, mkU8(0) ); + fp_pop(); + break; + //.. case 0xE0: /* FNSTSW %ax */ //.. DIP("fnstsw %%ax\n"); //.. /* Invent a plausible-looking FPU status word value and @@ -5543,13 +5552,13 @@ ULong dis_FPU ( Bool* decode_ok, Prefix pfx, ULong delta ) //.. /* not really right since COMIP != UCOMIP */ //.. fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True ); //.. break; -//.. -//.. default: -//.. goto decode_fail; -//.. } -//.. } -//.. -//.. } + + default: + goto decode_fail; + } + } + + } else goto decode_fail; //vpanic("dis_FPU(amd64): invalid primary opcode"); @@ -7936,41 +7945,47 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 ); //.. goto decode_success; //.. } -//.. -//.. /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */ -//.. /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */ -//.. if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) { -//.. IRTemp argL = newTemp(Ity_F32); -//.. IRTemp argR = newTemp(Ity_F32); -//.. modrm = getUChar(delta+2); -//.. if (epartIsReg(modrm)) { -//.. assign( argR, getXMMRegLane32F( eregOfRM(modrm), 0/*lowest lane*/ ) ); -//.. delta += 2+1; -//.. DIP("[u]comiss %s,%s\n", nameXMMReg(eregOfRM(modrm)), -//.. nameXMMReg(gregOfRM(modrm)) ); -//.. } else { -//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf ); -//.. assign( argR, loadLE(Ity_F32, mkexpr(addr)) ); -//.. delta += 2+alen; -//.. DIP("[u]comiss %s,%s\n", dis_buf, -//.. nameXMMReg(gregOfRM(modrm)) ); -//.. } -//.. assign( argL, getXMMRegLane32F( gregOfRM(modrm), 0/*lowest lane*/ ) ); -//.. -//.. 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, -//.. binop( Iop_And32, -//.. binop(Iop_CmpF64, -//.. unop(Iop_F32toF64,mkexpr(argL)), -//.. unop(Iop_F32toF64,mkexpr(argR))), -//.. mkU32(0x45) -//.. ))); -//.. -//.. goto decode_success; -//.. } -//.. + + /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */ + /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */ + if (haveNo66noF2noF3(pfx) && sz == 4 + && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) { + IRTemp argL = newTemp(Ity_F32); + IRTemp argR = newTemp(Ity_F32); + modrm = getUChar(delta+2); + if (epartIsReg(modrm)) { + assign( argR, getXMMRegLane32F( eregOfRexRM(pfx,modrm), + 0/*lowest lane*/ ) ); + delta += 2+1; + DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "", + nameXMMReg(eregOfRexRM(pfx,modrm)), + nameXMMReg(gregOfRexRM(pfx,modrm)) ); + } else { + addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 ); + assign( argR, loadLE(Ity_F32, mkexpr(addr)) ); + delta += 2+alen; + DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "", + dis_buf, + nameXMMReg(gregOfRexRM(pfx,modrm)) ); + } + assign( argL, getXMMRegLane32F( gregOfRexRM(pfx,modrm), + 0/*lowest lane*/ ) ); + + stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) )); + stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) )); + stmt( IRStmt_Put( + OFFB_CC_DEP1, + binop( Iop_And64, + unop( Iop_32Uto64, + binop(Iop_CmpF64, + unop(Iop_F32toF64,mkexpr(argL)), + unop(Iop_F32toF64,mkexpr(argR)))), + mkU64(0x45) + ))); + + goto decode_success; + } + //.. /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low //.. half xmm */ //.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x2A) { @@ -8031,7 +8046,6 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, DIP("cvtsi2ss %s,%s\n", nameIRegB(pfx, 4, eregOfRM(modrm)), nameXMMReg(gregOfRexRM(pfx,modrm))); } else { - goto decode_failure; /* awaiting test case */ addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 ); assign( arg32, loadLE(Ity_I32, mkexpr(addr)) ); delta += 2+alen; @@ -8166,14 +8180,14 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 ); //.. goto decode_success; //.. } -//.. -//.. /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */ -//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5E) { -//.. vassert(sz == 4); -//.. delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "divss", Iop_Div32F0x4 ); -//.. goto decode_success; -//.. } -//.. + + /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */ + if (haveF3no66noF2(pfx) && sz == 4 + && insn[0] == 0x0F && insn[1] == 0x5E) { + delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "divss", Iop_Div32F0x4 ); + goto decode_success; + } + //.. /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */ //.. if (insn[0] == 0x0F && insn[1] == 0xAE //.. && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) { @@ -8971,7 +8985,7 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */ /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */ - if (have66noF2noF3(pfx) + if (have66noF2noF3(pfx) && sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) { IRTemp argL = newTemp(Ity_F64); IRTemp argR = newTemp(Ity_F64); @@ -9456,32 +9470,32 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, goto decode_success; } -//.. /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in -//.. low half xmm(G) */ -//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) { -//.. IRTemp f32lo = newTemp(Ity_F32); -//.. vassert(sz == 4); -//.. -//.. modrm = getUChar(delta+3); -//.. if (epartIsReg(modrm)) { -//.. delta += 3+1; -//.. assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0)); -//.. DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRM(modrm)), -//.. nameXMMReg(gregOfRM(modrm))); -//.. } else { -//.. addr = disAMode ( &alen, sorb, delta+3, dis_buf ); -//.. assign(f32lo, loadLE(Ity_F32, mkexpr(addr))); -//.. delta += 3+alen; -//.. DIP("cvtss2sd %s,%s\n", dis_buf, -//.. nameXMMReg(gregOfRM(modrm))); -//.. } -//.. -//.. putXMMRegLane64F( gregOfRM(modrm), 0, -//.. unop( Iop_F32toF64, mkexpr(f32lo) ) ); -//.. -//.. goto decode_success; -//.. } -//.. + /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in + low half xmm(G) */ + if (haveF3no66noF2(pfx) && sz == 4 + && insn[0] == 0x0F && insn[1] == 0x5A) { + IRTemp f32lo = newTemp(Ity_F32); + + modrm = getUChar(delta+2); + if (epartIsReg(modrm)) { + delta += 2+1; + assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0)); + DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)), + nameXMMReg(gregOfRexRM(pfx,modrm))); + } else { + addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 ); + assign(f32lo, loadLE(Ity_F32, mkexpr(addr))); + delta += 2+alen; + DIP("cvtss2sd %s,%s\n", dis_buf, + nameXMMReg(gregOfRexRM(pfx,modrm))); + } + + putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0, + unop( Iop_F32toF64, mkexpr(f32lo) ) ); + + goto decode_success; + } + //.. /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in //.. lo half xmm(G), and zero upper half, rounding towards zero */ //.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE6) { @@ -9612,13 +9626,13 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "minpd", Iop_Min64Fx2 ); //.. goto decode_success; //.. } -//.. -//.. /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */ -//.. if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5D) { -//.. vassert(sz == 4); -//.. delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "minsd", Iop_Min64F0x2 ); -//.. goto decode_success; -//.. } + + /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */ + if (haveF2no66noF3(pfx) && sz == 4 + && insn[0] == 0x0F && insn[1] == 0x5D) { + delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "minsd", Iop_Min64F0x2 ); + goto decode_success; + } /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */ /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */ diff --git a/VEX/priv/host-amd64/hdefs.c b/VEX/priv/host-amd64/hdefs.c index d3e8c46639..ff678e5adc 100644 --- a/VEX/priv/host-amd64/hdefs.c +++ b/VEX/priv/host-amd64/hdefs.c @@ -3100,7 +3100,7 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i ) *p++ = 0x0F; switch (i->Ain.Sse32FLo.op) { case Asse_ADDF: *p++ = 0x58; break; -//.. case Xsse_DIVF: *p++ = 0x5E; break; + case Asse_DIVF: *p++ = 0x5E; break; //.. case Xsse_MAXF: *p++ = 0x5F; break; //.. case Xsse_MINF: *p++ = 0x5D; break; case Asse_MULF: *p++ = 0x59; break; @@ -3130,7 +3130,7 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i ) case Asse_ADDF: *p++ = 0x58; break; case Asse_DIVF: *p++ = 0x5E; break; case Asse_MAXF: *p++ = 0x5F; break; -//.. case Xsse_MINF: *p++ = 0x5D; break; + case Asse_MINF: *p++ = 0x5D; break; case Asse_MULF: *p++ = 0x59; break; //.. case Xsse_RCPF: *p++ = 0x53; break; //.. case Xsse_RSQRTF: *p++ = 0x52; break; diff --git a/VEX/priv/host-amd64/isel.c b/VEX/priv/host-amd64/isel.c index 01718ddec3..47e3f6759d 100644 --- a/VEX/priv/host-amd64/isel.c +++ b/VEX/priv/host-amd64/isel.c @@ -2575,18 +2575,18 @@ static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e ) IRType ty = typeOfIRExpr(env->type_env,e); vassert(ty == Ity_F32); -//.. if (e->tag == Iex_Tmp) { -//.. return lookupIRTemp(env, e->Iex.Tmp.tmp); -//.. } -//.. -//.. if (e->tag == Iex_LDle) { -//.. X86AMode* am; -//.. HReg res = newVRegF(env); -//.. vassert(e->Iex.LDle.ty == Ity_F32); -//.. am = iselIntExpr_AMode(env, e->Iex.LDle.addr); -//.. addInstr(env, X86Instr_FpLdSt(True/*load*/, 4, res, am)); -//.. return res; -//.. } + if (e->tag == Iex_Tmp) { + return lookupIRTemp(env, e->Iex.Tmp.tmp); + } + + if (e->tag == Iex_LDle) { + AMD64AMode* am; + HReg res = newVRegV(env); + vassert(e->Iex.LDle.ty == Ity_F32); + am = iselIntExpr_AMode(env, e->Iex.LDle.addr); + addInstr(env, AMD64Instr_SseLdSt(True/*load*/, 4, res, am)); + return res; + } if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_F64toF32) { @@ -2601,14 +2601,14 @@ static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e ) return dst; } -//.. if (e->tag == Iex_Get) { -//.. X86AMode* am = X86AMode_IR( e->Iex.Get.offset, -//.. hregX86_EBP() ); -//.. HReg res = newVRegF(env); -//.. addInstr(env, X86Instr_FpLdSt( True/*load*/, 4, res, am )); -//.. return res; -//.. } -//.. + if (e->tag == Iex_Get) { + AMD64AMode* am = AMD64AMode_IR( e->Iex.Get.offset, + hregAMD64_RBP() ); + HReg res = newVRegV(env); + addInstr(env, AMD64Instr_SseLdSt( True/*load*/, 4, res, am )); + return res; + } + //.. if (e->tag == Iex_Unop //.. && e->Iex.Unop.op == Iop_ReinterpI32asF32) { //.. /* Given an I32, produce an IEEE754 float with the same bit @@ -2835,9 +2835,9 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) //.. return res; //.. } //.. } -//.. -//.. if (e->tag == Iex_Unop) { -//.. switch (e->Iex.Unop.op) { + + if (e->tag == Iex_Unop) { + switch (e->Iex.Unop.op) { //.. case Iop_I32toF64: { //.. HReg dst = newVRegF(env); //.. HReg ri = iselIntExpr_R(env, e->Iex.Unop.arg); @@ -2846,7 +2846,7 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) //.. addInstr(env, X86Instr_FpLdStI( //.. True/*load*/, 4, dst, //.. X86AMode_IR(0, hregX86_ESP()))); -//.. add_to_esp(env, 4); +//.. add_to_esp(env, 4); //.. return dst; //.. } //.. case Iop_ReinterpI64asF64: { @@ -2854,7 +2854,7 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) //.. bit pattern. */ //.. HReg dst = newVRegF(env); //.. HReg rHi, rLo; -//.. iselInt64Expr( &rHi, &rLo, env, e->Iex.Unop.arg); +//.. iselInt64Expr( &rHi, &rLo, env, e->Iex.Unop.arg); //.. /* paranoia */ //.. set_FPU_rounding_default(env); //.. addInstr(env, X86Instr_Push(X86RMI_Reg(rHi))); @@ -2862,18 +2862,21 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) //.. addInstr(env, X86Instr_FpLdSt( //.. True/*load*/, 8, dst, //.. X86AMode_IR(0, hregX86_ESP()))); -//.. add_to_esp(env, 8); +//.. add_to_esp(env, 8); //.. return dst; -//.. } -//.. case Iop_F32toF64: { -//.. /* this is a no-op */ -//.. HReg res = iselFltExpr(env, e->Iex.Unop.arg); -//.. return res; -//.. } -//.. default: -//.. break; -//.. } -//.. } +//.. } + case Iop_F32toF64: { + HReg f64 = newVRegV(env); + /* this shouldn't be necessary, but be paranoid ... */ + set_SSE_rounding_default(env); + HReg f32 = iselFltExpr(env, e->Iex.Unop.arg); + addInstr(env, AMD64Instr_SseSDSS(False/*S->D*/, f32, f64)); + return f64; + } + default: + break; + } + } /* --------- MULTIPLEX --------- */ if (e->tag == Iex_Mux0X) { @@ -3223,7 +3226,7 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) //.. case Iop_CmpLT32F0x4: op = Xsse_CMPLTF; goto do_32F0x4; //.. case Iop_CmpLE32F0x4: op = Xsse_CMPLEF; goto do_32F0x4; case Iop_Add32F0x4: op = Asse_ADDF; goto do_32F0x4; -//.. case Iop_Div32F0x4: op = Xsse_DIVF; goto do_32F0x4; + case Iop_Div32F0x4: op = Asse_DIVF; goto do_32F0x4; //.. case Iop_Max32F0x4: op = Xsse_MAXF; goto do_32F0x4; //.. case Iop_Min32F0x4: op = Xsse_MINF; goto do_32F0x4; case Iop_Mul32F0x4: op = Asse_MULF; goto do_32F0x4; @@ -3243,7 +3246,7 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) 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; -//.. case Iop_Min64F0x2: op = Xsse_MINF; goto do_64F0x2; + case Iop_Min64F0x2: op = Asse_MINF; goto do_64F0x2; case Iop_Mul64F0x2: op = Asse_MULF; goto do_64F0x2; case Iop_Sub64F0x2: op = Asse_SUBF; goto do_64F0x2; do_64F0x2: { @@ -3416,11 +3419,11 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) addInstr(env, AMD64Instr_SseLdSt(False/*store*/, 8, r, am)); return; } -//.. if (tyd == Ity_F32) { -//.. HReg r = iselFltExpr(env, stmt->Ist.STle.data); -//.. addInstr(env, X86Instr_FpLdSt(False/*store*/, 4, r, am)); -//.. return; -//.. } + if (tyd == Ity_F32) { + HReg r = iselFltExpr(env, stmt->Ist.STle.data); + addInstr(env, AMD64Instr_SseLdSt(False/*store*/, 4, r, am)); + return; + } //.. if (tyd == Ity_I64) { //.. HReg vHi, vLo, rA; //.. iselInt64Expr(&vHi, &vLo, env, stmt->Ist.STle.data); @@ -3548,12 +3551,12 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) addInstr(env, mk_vMOVsd_RR(src, dst)); return; } -//.. if (ty == Ity_F32) { -//.. HReg dst = lookupIRTemp(env, tmp); -//.. HReg src = iselFltExpr(env, stmt->Ist.Tmp.data); -//.. addInstr(env, X86Instr_FpUnary(Xfp_MOV,src,dst)); -//.. return; -//.. } + if (ty == Ity_F32) { + HReg dst = lookupIRTemp(env, tmp); + HReg src = iselFltExpr(env, stmt->Ist.Tmp.data); + addInstr(env, mk_vMOVsd_RR(src, dst)); + return; + } if (ty == Ity_V128) { HReg dst = lookupIRTemp(env, tmp); HReg src = iselVecExpr(env, stmt->Ist.Tmp.data);