From: Julian Seward Date: Fri, 25 Feb 2005 02:48:47 +0000 (+0000) Subject: Fill in a huge number of amd64 floating point cases, and start to X-Git-Tag: svn/VALGRIND_3_0_1^2~374 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7d761cb6a7369230564636131348bb42f024340c;p=thirdparty%2Fvalgrind.git Fill in a huge number of amd64 floating point cases, and start to reinstate the old x87 instruction decoder. git-svn-id: svn://svn.valgrind.org/vex/trunk@960 --- diff --git a/VEX/priv/guest-amd64/ghelpers.c b/VEX/priv/guest-amd64/ghelpers.c index 26934d7a30..3008fff3fc 100644 --- a/VEX/priv/guest-amd64/ghelpers.c +++ b/VEX/priv/guest-amd64/ghelpers.c @@ -1141,6 +1141,26 @@ IRExpr* guest_amd64_spechelper ( HChar* function_name, } +/*---------------------------------------------------------------*/ +/*--- Supporting functions for x87 FPU activities. ---*/ +/*---------------------------------------------------------------*/ + +// MAYBE NOT TRUE: /* CALLED FROM GENERATED CODE */ +// MAYBE NOT TRUE: /* DIRTY HELPER (writes guest state) */ +/* Initialise the x87 FPU state as per 'finit'. */ +static +void amd64g_dirtyhelper_FINIT ( VexGuestAMD64State* gst ) +{ + Int i; + gst->guest_FTOP = 0; + for (i = 0; i < 8; i++) { + gst->guest_FPTAG[i] = 0; /* empty */ + gst->guest_FPREG[i] = 0; /* IEEE754 64-bit zero */ + } + gst->guest_FPROUND = (ULong)Irrm_NEAREST; + gst->guest_FC3210 = 0; +} + /*---------------------------------------------------------------*/ /*--- Misc integer helpers, including rotates and CPUID. ---*/ @@ -1262,6 +1282,9 @@ void LibVEX_GuestAMD64_initialise ( /*OUT*/VexGuestAMD64State* vex_state ) vex_state->guest_RIP = 0; + /* Initialise the simulated FPU */ + amd64g_dirtyhelper_FINIT( vex_state ); + /* Initialise the SSE state. */ # define SSEZERO(_xmm) _xmm[0]=_xmm[1]=_xmm[2]=_xmm[3] = 0; @@ -1339,7 +1362,7 @@ VexGuestLayout /* Describe any sections to be regarded by Memcheck as 'always-defined'. */ - .n_alwaysDefd = 7, + .n_alwaysDefd = 11, /* flags thunk: OP and NDEP are always defd, whereas DEP1 and DEP2 have to be tracked. See detailed comment in @@ -1351,10 +1374,10 @@ VexGuestLayout /* 3 */ ALWAYSDEFD(guest_IDFLAG), /* 4 */ ALWAYSDEFD(guest_RIP), /* 5 */ ALWAYSDEFD(guest_FS_ZERO), - // /* */ ALWAYSDEFD(guest_FTOP), - // /* */ ALWAYSDEFD(guest_FPTAG), - // /* */ ALWAYSDEFD(guest_FPROUND), - // /* */ ALWAYSDEFD(guest_FC3210), + /* 6 */ ALWAYSDEFD(guest_FTOP), + /* 7 */ ALWAYSDEFD(guest_FPTAG), + /* 8 */ ALWAYSDEFD(guest_FPROUND), + /* 9 */ ALWAYSDEFD(guest_FC3210), // /* */ ALWAYSDEFD(guest_CS), // /* */ ALWAYSDEFD(guest_DS), // /* */ ALWAYSDEFD(guest_ES), diff --git a/VEX/priv/guest-amd64/toIR.c b/VEX/priv/guest-amd64/toIR.c index 6295f9a5ab..4f1518b5bf 100644 --- a/VEX/priv/guest-amd64/toIR.c +++ b/VEX/priv/guest-amd64/toIR.c @@ -339,11 +339,11 @@ static void unimplemented ( HChar* str ) #define OFFB_CC_DEP2 offsetof(VexGuestAMD64State,guest_CC_DEP2) #define OFFB_CC_NDEP offsetof(VexGuestAMD64State,guest_CC_NDEP) -//.. #define OFFB_FPREGS offsetof(VexGuestX86State,guest_FPREG[0]) -//.. #define OFFB_FPTAGS offsetof(VexGuestX86State,guest_FPTAG[0]) +#define OFFB_FPREGS offsetof(VexGuestAMD64State,guest_FPREG[0]) +#define OFFB_FPTAGS offsetof(VexGuestAMD64State,guest_FPTAG[0]) #define OFFB_DFLAG offsetof(VexGuestAMD64State,guest_DFLAG) #define OFFB_IDFLAG offsetof(VexGuestAMD64State,guest_IDFLAG) -//.. #define OFFB_FTOP offsetof(VexGuestX86State,guest_FTOP) +#define OFFB_FTOP offsetof(VexGuestAMD64State,guest_FTOP) //.. #define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210) //.. #define OFFB_FPROUND offsetof(VexGuestX86State,guest_FPROUND) //.. @@ -818,21 +818,28 @@ static Bool haveF3 ( Prefix pfx ) { static Bool have66noF2noF3 ( Prefix pfx ) { return - toBool(((pfx & PFX_66) | ((~pfx) & (PFX_F2|PFX_F3))) > 0); + toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_66); } /* Return True iff pfx has F2 set and 66 and F3 clear */ static Bool haveF2no66noF3 ( Prefix pfx ) { return - toBool(((pfx & PFX_F2) | ((~pfx) & (PFX_66|PFX_F3))) > 0); + toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_F2); +} + +/* Return True iff pfx has F3 set and 66 and F2 clear */ +static Bool haveF3no66noF2 ( Prefix pfx ) +{ + return + toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_F3); } /* Return True iff pfx has 66, F2 and F3 clear */ static Bool haveNo66noF2noF3 ( Prefix pfx ) { return - toBool((((~pfx) & (PFX_66|PFX_F2|PFX_F3))) > 0); + toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == 0); } /* Clear all the segment-override bits in a prefix. */ @@ -1159,14 +1166,14 @@ static Int xmmGuestRegOffset ( UInt xmmreg ) //.. vassert(laneno >= 0 && laneno < 8); //.. return xmmGuestRegOffset( xmmreg ) + 2 * laneno; //.. } -//.. -//.. static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno ) -//.. { -//.. /* Correct for little-endian host only. */ -//.. vassert(!host_is_bigendian); -//.. vassert(laneno >= 0 && laneno < 4); -//.. return xmmGuestRegOffset( xmmreg ) + 4 * laneno; -//.. } + +static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno ) +{ + /* Correct for little-endian host only. */ + vassert(!host_is_bigendian); + vassert(laneno >= 0 && laneno < 4); + return xmmGuestRegOffset( xmmreg ) + 4 * laneno; +} static Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno ) { @@ -1202,11 +1209,11 @@ static IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno ) return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 ); } -//.. static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno ) -//.. { -//.. return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 ); -//.. } -//.. +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 ); @@ -1230,18 +1237,18 @@ static void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e ) stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) ); } -//.. static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e ) -//.. { -//.. vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F32); -//.. stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) ); -//.. } -//.. -//.. static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e ) -//.. { -//.. vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32); -//.. stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) ); -//.. } -//.. +static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e ) +{ + vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F32); + stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) ); +} + +static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e ) +{ + vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32); + stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) ); +} + //.. static void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e ) //.. { //.. vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16); @@ -3896,30 +3903,31 @@ ULong dis_imul_I_E_G ( Prefix pfx, //.. { //.. stmt( IRStmt_Put( OFFB_EMWARN, e ) ); //.. } -//.. -//.. /* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */ -//.. -//.. static IRExpr* mkQNaN64 ( void ) -//.. { -//.. /* QNaN is 0 2047 1 0(51times) -//.. == 0b 11111111111b 1 0(51times) -//.. == 0x7FF8 0000 0000 0000 -//.. */ -//.. return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL)); -//.. } -//.. -//.. /* --------- Get/put the top-of-stack pointer. --------- */ -//.. -//.. static IRExpr* get_ftop ( void ) -//.. { -//.. return IRExpr_Get( OFFB_FTOP, Ity_I32 ); -//.. } -//.. -//.. static void put_ftop ( IRExpr* e ) -//.. { -//.. stmt( IRStmt_Put( OFFB_FTOP, e ) ); -//.. } -//.. + +/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */ + +static IRExpr* mkQNaN64 ( void ) +{ + /* QNaN is 0 2047 1 0(51times) + == 0b 11111111111b 1 0(51times) + == 0x7FF8 0000 0000 0000 + */ + return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL)); +} + +/* --------- Get/put the top-of-stack pointer :: Ity_I32 --------- */ + +static IRExpr* get_ftop ( void ) +{ + return IRExpr_Get( OFFB_FTOP, Ity_I32 ); +} + +static void put_ftop ( IRExpr* e ) +{ + vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32); + stmt( IRStmt_Put( OFFB_FTOP, e ) ); +} + //.. /* --------- Get/put the C3210 bits. --------- */ //.. //.. static IRExpr* get_C3210 ( void ) @@ -3954,104 +3962,104 @@ ULong dis_imul_I_E_G ( Prefix pfx, //.. { //.. 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'. */ -//.. -//.. static void put_ST_TAG ( Int i, IRExpr* value ) -//.. { -//.. IRArray* descr; -//.. vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8); -//.. descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 ); -//.. stmt( IRStmt_PutI( descr, get_ftop(), i, value ) ); -//.. } -//.. -//.. /* Given i, generate an expression yielding 'ST_TAG(i)'. This will be -//.. zero to indicate "Empty" and nonzero to indicate "NonEmpty". */ -//.. -//.. static IRExpr* get_ST_TAG ( Int i ) -//.. { -//.. IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 ); -//.. return IRExpr_GetI( descr, get_ftop(), i ); -//.. } -//.. -//.. -//.. /* --------- Get/set FP registers. --------- */ -//.. -//.. /* Given i, and some expression e, emit 'ST(i) = e' and set the -//.. register's tag to indicate the register is full. The previous -//.. state of the register is not checked. */ -//.. -//.. static void put_ST_UNCHECKED ( Int i, IRExpr* value ) -//.. { -//.. IRArray* descr; -//.. vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64); -//.. descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 ); -//.. stmt( IRStmt_PutI( descr, get_ftop(), i, value ) ); -//.. /* Mark the register as in-use. */ -//.. put_ST_TAG(i, mkU8(1)); -//.. } -//.. -//.. /* Given i, and some expression e, emit -//.. ST(i) = is_full(i) ? NaN : e -//.. and set the tag accordingly. -//.. */ -//.. -//.. static void put_ST ( Int i, IRExpr* value ) -//.. { -//.. put_ST_UNCHECKED( i, -//.. IRExpr_Mux0X( get_ST_TAG(i), -//.. /* 0 means empty */ -//.. value, -//.. /* non-0 means full */ -//.. mkQNaN64() -//.. ) -//.. ); -//.. } -//.. -//.. -//.. /* Given i, generate an expression yielding 'ST(i)'. */ -//.. -//.. static IRExpr* get_ST_UNCHECKED ( Int i ) -//.. { -//.. IRArray* descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 ); -//.. return IRExpr_GetI( descr, get_ftop(), i ); -//.. } -//.. -//.. -//.. /* Given i, generate an expression yielding -//.. is_full(i) ? ST(i) : NaN -//.. */ -//.. -//.. static IRExpr* get_ST ( Int i ) -//.. { -//.. return -//.. IRExpr_Mux0X( get_ST_TAG(i), -//.. /* 0 means empty */ -//.. mkQNaN64(), -//.. /* non-0 means full */ -//.. get_ST_UNCHECKED(i)); -//.. } -//.. -//.. -//.. /* Adjust FTOP downwards by one register. */ -//.. -//.. static void fp_push ( void ) -//.. { -//.. put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) ); -//.. } -//.. -//.. /* Adjust FTOP upwards by one register, and mark the vacated register -//.. as empty. */ -//.. -//.. static void fp_pop ( void ) -//.. { -//.. put_ST_TAG(0, mkU8(0)); -//.. put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) ); -//.. } -//.. + + +/* --------- Get/set FP register tag bytes. --------- */ + +/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */ + +static void put_ST_TAG ( Int i, IRExpr* value ) +{ + IRArray* descr; + vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8); + descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 ); + stmt( IRStmt_PutI( descr, get_ftop(), i, value ) ); +} + +/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be + zero to indicate "Empty" and nonzero to indicate "NonEmpty". */ + +static IRExpr* get_ST_TAG ( Int i ) +{ + IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 ); + return IRExpr_GetI( descr, get_ftop(), i ); +} + + +/* --------- Get/set FP registers. --------- */ + +/* Given i, and some expression e, emit 'ST(i) = e' and set the + register's tag to indicate the register is full. The previous + state of the register is not checked. */ + +static void put_ST_UNCHECKED ( Int i, IRExpr* value ) +{ + IRArray* descr; + vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64); + descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 ); + stmt( IRStmt_PutI( descr, get_ftop(), i, value ) ); + /* Mark the register as in-use. */ + put_ST_TAG(i, mkU8(1)); +} + +/* Given i, and some expression e, emit + ST(i) = is_full(i) ? NaN : e + and set the tag accordingly. +*/ + +static void put_ST ( Int i, IRExpr* value ) +{ + put_ST_UNCHECKED( i, + IRExpr_Mux0X( get_ST_TAG(i), + /* 0 means empty */ + value, + /* non-0 means full */ + mkQNaN64() + ) + ); +} + + +/* Given i, generate an expression yielding 'ST(i)'. */ + +static IRExpr* get_ST_UNCHECKED ( Int i ) +{ + IRArray* descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 ); + return IRExpr_GetI( descr, get_ftop(), i ); +} + + +/* Given i, generate an expression yielding + is_full(i) ? ST(i) : NaN +*/ + +static IRExpr* get_ST ( Int i ) +{ + return + IRExpr_Mux0X( get_ST_TAG(i), + /* 0 means empty */ + mkQNaN64(), + /* non-0 means full */ + get_ST_UNCHECKED(i)); +} + + +/* Adjust FTOP downwards by one register. */ + +static void fp_push ( void ) +{ + put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) ); +} + +/* Adjust FTOP upwards by one register, and mark the vacated register + as empty. */ + +static void fp_pop ( void ) +{ + put_ST_TAG(0, mkU8(0)); + put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) ); +} + //.. /* Clear the C2 bit of the FPU status register, for //.. sin/cos/tan/sincos. */ //.. @@ -4166,21 +4174,21 @@ ULong dis_imul_I_E_G ( Prefix pfx, //.. if (pop_after) //.. fp_pop(); //.. } -//.. -//.. -//.. static -//.. UInt dis_FPU ( Bool* decode_ok, UChar sorb, ULong delta ) -//.. { -//.. Int len; -//.. UInt r_src, r_dst; -//.. HChar dis_buf[50]; -//.. IRTemp t1, t2; -//.. -//.. /* On entry, delta points at the second byte of the insn (the modrm -//.. byte).*/ -//.. UChar first_opcode = getUChar(delta-1); -//.. UChar modrm = getUChar(delta+0); -//.. + + +static +ULong dis_FPU ( Bool* decode_ok, Prefix pfx, ULong delta ) +{ + Int len; + UInt r_src, r_dst; + HChar dis_buf[50]; + IRTemp t1, t2; + + /* On entry, delta points at the second byte of the insn (the modrm + byte).*/ + UChar first_opcode = getUChar(delta-1); + UChar modrm = getUChar(delta+0); + //.. /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */ //.. //.. if (first_opcode == 0xD8) { @@ -4317,19 +4325,19 @@ ULong dis_imul_I_E_G ( Prefix pfx, //.. } //.. } //.. } -//.. -//.. /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */ + + /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */ //.. else -//.. if (first_opcode == 0xD9) { -//.. 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)) { -//.. + if (first_opcode == 0xD9) { + 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: /* FLD single-real */ //.. DIP("flds %s\n", dis_buf); //.. fp_push(); @@ -4506,17 +4514,17 @@ ULong dis_imul_I_E_G ( Prefix pfx, //.. ) //.. ); //.. break; -//.. -//.. default: -//.. vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm)); -//.. vex_printf("first_opcode == 0xD9\n"); -//.. goto decode_fail; -//.. } -//.. -//.. } else { -//.. delta++; -//.. switch (modrm) { -//.. + + default: + vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm)); + vex_printf("first_opcode == 0xD9\n"); + goto decode_fail; + } + + } else { + delta++; + switch (modrm) { + //.. case 0xC0 ... 0xC7: /* FLD %st(?) */ //.. r_src = (UInt)modrm - 0xC0; //.. DIP("fld %%st(%d)\n", r_src); @@ -4525,23 +4533,23 @@ ULong dis_imul_I_E_G ( Prefix pfx, //.. fp_push(); //.. put_ST(0, mkexpr(t1)); //.. break; -//.. -//.. case 0xC8 ... 0xCF: /* FXCH %st(?) */ -//.. r_src = (UInt)modrm - 0xC8; -//.. DIP("fxch %%st(%d)\n", r_src); -//.. t1 = newTemp(Ity_F64); -//.. t2 = newTemp(Ity_F64); -//.. assign(t1, get_ST(0)); -//.. assign(t2, get_ST(r_src)); -//.. put_ST_UNCHECKED(0, mkexpr(t2)); -//.. put_ST_UNCHECKED(r_src, mkexpr(t1)); -//.. break; -//.. -//.. case 0xE0: /* FCHS */ -//.. DIP("fchs\n"); -//.. put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0))); -//.. break; -//.. + + case 0xC8 ... 0xCF: /* FXCH %st(?) */ + r_src = (UInt)modrm - 0xC8; + DIP("fxch %%st(%d)\n", r_src); + t1 = newTemp(Ity_F64); + t2 = newTemp(Ity_F64); + assign(t1, get_ST(0)); + assign(t2, get_ST(r_src)); + put_ST_UNCHECKED(0, mkexpr(t2)); + put_ST_UNCHECKED(r_src, mkexpr(t1)); + break; + + case 0xE0: /* FCHS */ + DIP("fchs\n"); + 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))); @@ -4721,26 +4729,26 @@ ULong dis_imul_I_E_G ( Prefix pfx, //.. put_ST_UNCHECKED(0, unop(Iop_CosF64, get_ST(0))); //.. clear_C2(); /* HACK */ //.. break; -//.. -//.. default: -//.. goto decode_fail; -//.. } -//.. } -//.. } -//.. -//.. /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */ -//.. else -//.. if (first_opcode == 0xDA) { -//.. -//.. 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 ); -//.. delta += len; -//.. switch (gregOfRM(modrm)) { -//.. + + default: + goto decode_fail; + } + } + } + + /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */ + else + if (first_opcode == 0xDA) { + + if (modrm < 0xC0) { + + /* bits 5,4,3 are an opcode extension, and the modRM also + specifies an address. */ + IROp fop; + IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 ); + delta += len; + switch (gregOfRM(modrm)) { + //.. case 0: /* FIADD m32int */ /* ST(0) += m32int */ //.. DIP("fiaddl %s\n", dis_buf); //.. fop = Iop_AddF64; @@ -4786,18 +4794,18 @@ ULong dis_imul_I_E_G ( Prefix pfx, //.. loadLE(Ity_I32, mkexpr(addr))), //.. get_ST(0))); //.. break; -//.. -//.. default: -//.. vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm)); -//.. vex_printf("first_opcode == 0xDA\n"); -//.. goto decode_fail; -//.. } -//.. -//.. } else { -//.. -//.. delta++; -//.. switch (modrm) { -//.. + + default: + vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm)); + vex_printf("first_opcode == 0xDA\n"); + goto decode_fail; + } + + } else { + + delta++; + switch (modrm) { + //.. case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */ //.. r_src = (UInt)modrm - 0xC0; //.. DIP("fcmovb %%st(%d), %%st(0)\n", r_src); @@ -4807,17 +4815,17 @@ ULong dis_imul_I_E_G ( Prefix pfx, //.. mk_x86g_calculate_condition(X86CondB)), //.. get_ST(0), get_ST(r_src)) ); //.. break; -//.. -//.. case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */ -//.. r_src = (UInt)modrm - 0xC8; -//.. DIP("fcmovz %%st(%d), %%st(0)\n", r_src); -//.. put_ST_UNCHECKED(0, -//.. IRExpr_Mux0X( -//.. unop(Iop_1Uto8, -//.. mk_x86g_calculate_condition(X86CondZ)), -//.. get_ST(0), get_ST(r_src)) ); -//.. break; -//.. + + case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */ + r_src = (UInt)modrm - 0xC8; + DIP("fcmovz %%st(%d), %%st(0)\n", r_src); + put_ST_UNCHECKED(0, + IRExpr_Mux0X( + unop(Iop_1Uto8, + mk_amd64g_calculate_condition(AMD64CondZ)), + get_ST(0), get_ST(r_src)) ); + break; + //.. case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */ //.. r_src = (UInt)modrm - 0xD0; //.. DIP("fcmovbe %%st(%d), %%st(0)\n", r_src); @@ -4841,14 +4849,14 @@ ULong dis_imul_I_E_G ( Prefix pfx, //.. fp_pop(); //.. fp_pop(); //.. break; -//.. -//.. default: -//.. goto decode_fail; -//.. } -//.. -//.. } -//.. } -//.. + + default: + goto decode_fail; + } + + } + } + //.. /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */ //.. else //.. if (first_opcode == 0xDB) { @@ -5138,37 +5146,37 @@ ULong dis_imul_I_E_G ( Prefix pfx, //.. //.. } //.. } -//.. -//.. /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */ -//.. else -//.. if (first_opcode == 0xDD) { -//.. -//.. 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)) { -//.. -//.. case 0: /* FLD double-real */ -//.. DIP("fldl %s\n", dis_buf); -//.. fp_push(); -//.. put_ST(0, IRExpr_LDle(Ity_F64, mkexpr(addr))); -//.. break; -//.. + + /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */ + else + if (first_opcode == 0xDD) { + + 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: /* FLD double-real */ + DIP("fldl %s\n", dis_buf); + fp_push(); + 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 3: /* FSTP double-real */ -//.. DIP("fstpl %s\n", dis_buf); -//.. storeLE(mkexpr(addr), get_ST(0)); -//.. fp_pop(); -//.. break; -//.. + + case 3: /* FSTP double-real */ + DIP("fstpl %s\n", dis_buf); + storeLE(mkexpr(addr), get_ST(0)); + fp_pop(); + break; + //.. case 4: { /* FRSTOR m108 */ //.. /* Uses dirty helper: //.. VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */ @@ -5271,16 +5279,16 @@ ULong dis_imul_I_E_G ( Prefix pfx, //.. DIP("fnsave %s\n", dis_buf); //.. break; //.. } -//.. -//.. default: -//.. vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm)); -//.. vex_printf("first_opcode == 0xDD\n"); -//.. goto decode_fail; -//.. } -//.. } else { -//.. delta++; -//.. switch (modrm) { -//.. + + default: + vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm)); + vex_printf("first_opcode == 0xDD\n"); + goto decode_fail; + } + } else { + delta++; + switch (modrm) { + //.. case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */ //.. r_dst = (UInt)modrm - 0xD0; //.. DIP("fst %%st(0),%%st(%d)\n", r_dst); @@ -5289,17 +5297,17 @@ ULong dis_imul_I_E_G ( Prefix pfx, //.. is not generated. Hence put_ST_UNCHECKED. */ //.. put_ST_UNCHECKED(r_dst, get_ST(0)); //.. break; -//.. -//.. case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */ -//.. r_dst = (UInt)modrm - 0xD8; -//.. DIP("fstp %%st(0),%%st(%d)\n", r_dst); -//.. /* P4 manual says: "If the destination operand is a -//.. non-empty register, the invalid-operation exception -//.. is not generated. Hence put_ST_UNCHECKED. */ -//.. put_ST_UNCHECKED(r_dst, get_ST(0)); -//.. fp_pop(); -//.. break; -//.. + + case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */ + r_dst = (UInt)modrm - 0xD8; + DIP("fstp %%st(0),%%st(%d)\n", r_dst); + /* P4 manual says: "If the destination operand is a + non-empty register, the invalid-operation exception + is not generated. Hence put_ST_UNCHECKED. */ + put_ST_UNCHECKED(r_dst, get_ST(0)); + fp_pop(); + break; + //.. case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */ //.. r_dst = (UInt)modrm - 0xE0; //.. DIP("fucom %%st(0),%%st(%d)\n", r_dst); @@ -5326,13 +5334,13 @@ ULong dis_imul_I_E_G ( Prefix pfx, //.. )); //.. fp_pop(); //.. break; -//.. -//.. default: -//.. goto decode_fail; -//.. } -//.. } -//.. } -//.. + + default: + goto decode_fail; + } + } + } + //.. /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */ //.. else //.. if (first_opcode == 0xDE) { @@ -5542,19 +5550,19 @@ ULong dis_imul_I_E_G ( Prefix pfx, //.. } //.. //.. } -//.. -//.. else -//.. vpanic("dis_FPU(x86): invalid primary opcode"); -//.. -//.. *decode_ok = True; -//.. return delta; -//.. -//.. decode_fail: -//.. *decode_ok = False; -//.. return delta; -//.. } -//.. -//.. + + else + goto decode_fail; //vpanic("dis_FPU(amd64): invalid primary opcode"); + + *decode_ok = True; + return delta; + + decode_fail: + *decode_ok = False; + return delta; +} + + //.. /*------------------------------------------------------------*/ //.. /*--- ---*/ //.. /*--- MMX INSTRUCTIONS ---*/ @@ -6976,11 +6984,11 @@ void dis_ret ( ULong d64 ) Handles full width G = G `op` E and G = (not G) `op` E. */ -static UInt dis_SSE_E_to_G_all_wrk ( - Prefix pfx, ULong delta, - HChar* opname, IROp op, - Bool invertG - ) +static ULong dis_SSE_E_to_G_all_wrk ( + Prefix pfx, ULong delta, + HChar* opname, IROp op, + Bool invertG + ) { HChar dis_buf[50]; Int alen; @@ -7013,60 +7021,61 @@ static UInt dis_SSE_E_to_G_all_wrk ( /* All lanes SSE binary operation, G = G `op` E. */ static -UInt dis_SSE_E_to_G_all ( Prefix pfx, ULong delta, HChar* opname, IROp op ) +ULong dis_SSE_E_to_G_all ( Prefix pfx, ULong delta, + HChar* opname, IROp op ) { return dis_SSE_E_to_G_all_wrk( pfx, delta, opname, op, False ); } -//.. /* All lanes SSE binary operation, G = (not G) `op` E. */ -//.. -//.. static -//.. UInt dis_SSE_E_to_G_all_invG ( UChar sorb, ULong delta, -//.. HChar* opname, IROp op ) -//.. { -//.. return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True ); -//.. } -//.. -//.. -//.. /* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */ -//.. -//.. static UInt dis_SSE_E_to_G_lo32 ( UChar sorb, ULong delta, -//.. HChar* opname, IROp op ) -//.. { -//.. HChar dis_buf[50]; -//.. Int alen; -//.. IRTemp addr; -//.. UChar rm = getUChar(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 32-bit memory read, so the upper 3/4 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_32Uto128, -//.. loadLE(Ity_I32, 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 SSE binary operation, G = (not G) `op` E. */ + +static +ULong dis_SSE_E_to_G_all_invG ( Prefix pfx, ULong delta, + HChar* opname, IROp op ) +{ + return dis_SSE_E_to_G_all_wrk( pfx, delta, opname, op, True ); +} + + +/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */ + +static ULong dis_SSE_E_to_G_lo32 ( Prefix pfx, ULong delta, + HChar* opname, IROp op ) +{ + HChar dis_buf[50]; + Int alen; + IRTemp addr; + UChar rm = getUChar(delta); + IRExpr* gpart = getXMMReg(gregOfRM(rm)); + if (epartIsReg(rm)) { + putXMMReg( gregOfRM(rm), + binop(op, gpart, + getXMMReg(eregOfRexRM(pfx,rm))) ); + DIP("%s %s,%s\n", opname, + nameXMMReg(eregOfRexRM(pfx,rm)), + nameXMMReg(gregOfRexRM(pfx,rm)) ); + return delta+1; + } else { + /* We can only do a 32-bit memory read, so the upper 3/4 of the + E operand needs to be made simply of zeroes. */ + IRTemp epart = newTemp(Ity_V128); + addr = disAMode ( &alen, pfx, delta, dis_buf, 0 ); + assign( epart, unop( Iop_32UtoV128, + loadLE(Ity_I32, mkexpr(addr))) ); + putXMMReg( gregOfRexRM(pfx,rm), + binop(op, gpart, mkexpr(epart)) ); + DIP("%s %s,%s\n", opname, + dis_buf, + nameXMMReg(gregOfRexRM(pfx,rm)) ); + return delta+alen; + } +} /* Lower 64-bit lane only SSE binary operation, G = G `op` E. */ -static UInt dis_SSE_E_to_G_lo64 ( Prefix pfx, ULong delta, - HChar* opname, IROp op ) +static ULong dis_SSE_E_to_G_lo64 ( Prefix pfx, ULong delta, + HChar* opname, IROp op ) { HChar dis_buf[50]; Int alen; @@ -7173,10 +7182,10 @@ static UInt dis_SSE_E_to_G_lo64 ( Prefix pfx, ULong delta, /* Lowest 64-bit lane only unary SSE operation, G = op(E). */ -static UInt dis_SSE_E_to_G_unary_lo64 ( - Prefix pfx, ULong delta, - HChar* opname, IROp op - ) +static ULong dis_SSE_E_to_G_unary_lo64 ( + Prefix pfx, ULong delta, + HChar* opname, IROp op + ) { /* First we need to get the old G value and patch the low 64 bits of the E operand into it. Then apply op and write back to G. */ @@ -7249,115 +7258,115 @@ static UInt dis_SSE_E_to_G_unary_lo64 ( //.. : binop(op, gpart, epart) ); //.. return delta; //.. } -//.. -//.. -//.. /* Helper for doing SSE FP comparisons. */ -//.. -//.. static void findSSECmpOp ( Bool* needNot, IROp* op, -//.. Int imm8, Bool all_lanes, Int sz ) -//.. { -//.. imm8 &= 7; -//.. *needNot = False; -//.. *op = Iop_INVALID; -//.. if (imm8 >= 4) { -//.. *needNot = True; -//.. imm8 -= 4; -//.. } -//.. -//.. if (sz == 4 && all_lanes) { -//.. switch (imm8) { -//.. case 0: *op = Iop_CmpEQ32Fx4; return; -//.. case 1: *op = Iop_CmpLT32Fx4; return; -//.. case 2: *op = Iop_CmpLE32Fx4; return; -//.. case 3: *op = Iop_CmpUN32Fx4; return; -//.. default: break; -//.. } -//.. } -//.. if (sz == 4 && !all_lanes) { -//.. switch (imm8) { -//.. case 0: *op = Iop_CmpEQ32F0x4; return; -//.. case 1: *op = Iop_CmpLT32F0x4; return; -//.. case 2: *op = Iop_CmpLE32F0x4; return; -//.. case 3: *op = Iop_CmpUN32F0x4; return; -//.. default: break; -//.. } -//.. } -//.. if (sz == 8 && all_lanes) { -//.. switch (imm8) { -//.. case 0: *op = Iop_CmpEQ64Fx2; return; -//.. case 1: *op = Iop_CmpLT64Fx2; return; -//.. case 2: *op = Iop_CmpLE64Fx2; return; -//.. case 3: *op = Iop_CmpUN64Fx2; return; -//.. default: break; -//.. } -//.. } -//.. if (sz == 8 && !all_lanes) { -//.. switch (imm8) { -//.. case 0: *op = Iop_CmpEQ64F0x2; return; -//.. case 1: *op = Iop_CmpLT64F0x2; return; -//.. case 2: *op = Iop_CmpLE64F0x2; return; -//.. case 3: *op = Iop_CmpUN64F0x2; return; -//.. default: break; -//.. } -//.. } -//.. vpanic("findSSECmpOp(x86,guest)"); -//.. } -//.. -//.. /* Handles SSE 32F comparisons. */ -//.. -//.. static UInt dis_SSEcmp_E_to_G ( UChar sorb, ULong delta, -//.. HChar* opname, Bool all_lanes, Int sz ) -//.. { -//.. HChar dis_buf[50]; -//.. Int alen, imm8; -//.. IRTemp addr; -//.. Bool needNot = False; -//.. IROp op = Iop_INVALID; -//.. IRTemp plain = newTemp(Ity_V128); -//.. UChar rm = getUChar(delta); -//.. UShort mask = 0; -//.. vassert(sz == 4 || sz == 8); -//.. if (epartIsReg(rm)) { -//.. imm8 = getUChar(delta+1); -//.. findSSECmpOp(&needNot, &op, imm8, all_lanes, sz); -//.. assign( plain, binop(op, getXMMReg(gregOfRM(rm)), -//.. getXMMReg(eregOfRM(rm))) ); -//.. delta += 2; -//.. DIP("%s $%d,%s,%s\n", opname, -//.. (Int)imm8, -//.. nameXMMReg(eregOfRM(rm)), -//.. nameXMMReg(gregOfRM(rm)) ); -//.. } else { -//.. addr = disAMode ( &alen, sorb, delta, dis_buf ); -//.. imm8 = getUChar(delta+alen); -//.. findSSECmpOp(&needNot, &op, imm8, all_lanes, sz); -//.. assign( plain, binop(op, getXMMReg(gregOfRM(rm)), -//.. loadLE(Ity_V128, mkexpr(addr))) ); -//.. delta += alen+1; -//.. DIP("%s $%d,%s,%s\n", opname, -//.. (Int)imm8, -//.. dis_buf, -//.. nameXMMReg(gregOfRM(rm)) ); -//.. } -//.. -//.. if (needNot && all_lanes) { -//.. putXMMReg( gregOfRM(rm), -//.. unop(Iop_Not128, mkexpr(plain)) ); -//.. } -//.. else -//.. if (needNot && !all_lanes) { -//.. mask = sz==4 ? 0x000F : 0x00FF; -//.. putXMMReg( gregOfRM(rm), -//.. binop(Iop_Xor128, mkexpr(plain), mkV128(mask)) ); -//.. } -//.. else { -//.. putXMMReg( gregOfRM(rm), mkexpr(plain) ); -//.. } -//.. -//.. return delta; -//.. } -//.. -//.. + + +/* Helper for doing SSE FP comparisons. */ + +static void findSSECmpOp ( Bool* needNot, IROp* op, + Int imm8, Bool all_lanes, Int sz ) +{ + imm8 &= 7; + *needNot = False; + *op = Iop_INVALID; + if (imm8 >= 4) { + *needNot = True; + imm8 -= 4; + } + + if (sz == 4 && all_lanes) { + switch (imm8) { + case 0: *op = Iop_CmpEQ32Fx4; return; + case 1: *op = Iop_CmpLT32Fx4; return; + case 2: *op = Iop_CmpLE32Fx4; return; + case 3: *op = Iop_CmpUN32Fx4; return; + default: break; + } + } + if (sz == 4 && !all_lanes) { + switch (imm8) { + case 0: *op = Iop_CmpEQ32F0x4; return; + case 1: *op = Iop_CmpLT32F0x4; return; + case 2: *op = Iop_CmpLE32F0x4; return; + case 3: *op = Iop_CmpUN32F0x4; return; + default: break; + } + } + if (sz == 8 && all_lanes) { + switch (imm8) { + case 0: *op = Iop_CmpEQ64Fx2; return; + case 1: *op = Iop_CmpLT64Fx2; return; + case 2: *op = Iop_CmpLE64Fx2; return; + case 3: *op = Iop_CmpUN64Fx2; return; + default: break; + } + } + if (sz == 8 && !all_lanes) { + switch (imm8) { + case 0: *op = Iop_CmpEQ64F0x2; return; + case 1: *op = Iop_CmpLT64F0x2; return; + case 2: *op = Iop_CmpLE64F0x2; return; + case 3: *op = Iop_CmpUN64F0x2; return; + default: break; + } + } + vpanic("findSSECmpOp(amd64,guest)"); +} + +/* Handles SSE 32F comparisons. */ + +static ULong dis_SSEcmp_E_to_G ( Prefix pfx, ULong delta, + HChar* opname, Bool all_lanes, Int sz ) +{ + HChar dis_buf[50]; + Int alen, imm8; + IRTemp addr; + Bool needNot = False; + IROp op = Iop_INVALID; + IRTemp plain = newTemp(Ity_V128); + UChar rm = getUChar(delta); + UShort mask = 0; + vassert(sz == 4 || sz == 8); + if (epartIsReg(rm)) { + imm8 = getUChar(delta+1); + findSSECmpOp(&needNot, &op, imm8, all_lanes, sz); + assign( plain, binop(op, getXMMReg(gregOfRexRM(pfx,rm)), + getXMMReg(eregOfRexRM(pfx,rm))) ); + delta += 2; + DIP("%s $%d,%s,%s\n", opname, + (Int)imm8, + nameXMMReg(eregOfRexRM(pfx,rm)), + nameXMMReg(gregOfRexRM(pfx,rm)) ); + } else { + addr = disAMode ( &alen, pfx, delta, dis_buf, 1 ); + imm8 = getUChar(delta+alen); + findSSECmpOp(&needNot, &op, imm8, all_lanes, sz); + assign( plain, binop(op, getXMMReg(gregOfRexRM(pfx,rm)), + loadLE(Ity_V128, mkexpr(addr))) ); + delta += alen+1; + DIP("%s $%d,%s,%s\n", opname, + (Int)imm8, + dis_buf, + nameXMMReg(gregOfRexRM(pfx,rm)) ); + } + + if (needNot && all_lanes) { + putXMMReg( gregOfRM(rm), + unop(Iop_NotV128, mkexpr(plain)) ); + } + else + if (needNot && !all_lanes) { + mask = sz==4 ? 0x000F : 0x00FF; + putXMMReg( gregOfRexRM(pfx,rm), + binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) ); + } + else { + putXMMReg( gregOfRexRM(pfx,rm), mkexpr(plain) ); + } + + return delta; +} + + //.. /* Vector by scalar shift of G by the amount specified at the bottom //.. of E. */ //.. @@ -7895,14 +7904,14 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 ); //.. goto decode_success; //.. } -//.. -//.. /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */ -//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x58) { -//.. vassert(sz == 4); -//.. delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "addss", Iop_Add32F0x4 ); -//.. goto decode_success; -//.. } -//.. + + /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */ + if (haveF3no66noF2(pfx) && sz == 4 + && insn[0] == 0x0F && insn[1] == 0x58) { + delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "addss", Iop_Add32F0x4 ); + goto decode_success; + } + //.. /* 0F 55 = ANDNPS -- G = (not G) and E */ //.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x55) { //.. delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_And128 ); @@ -7978,7 +7987,7 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. nameXMMReg(gregOfRM(modrm))); //.. } else { //.. addr = disAMode ( &alen, sorb, delta+2, dis_buf ); -//.. assign( arg64, loadLE(Ity_I64, mkexpr(addr)) ); +//.. assign( arg64, loadLE(Ity_I64, mkexpr(addr)) ); //.. delta += 2+alen; //.. DIP("cvtpi2ps %s,%s\n", dis_buf, //.. nameXMMReg(gregOfRM(modrm)) ); @@ -7994,47 +8003,67 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. unop(Iop_64to32, mkexpr(arg64)) )) ); //.. //.. putXMMRegLane32F( -//.. gregOfRM(modrm), 1, -//.. binop(Iop_F64toF32, -//.. mkexpr(rmode), -//.. unop(Iop_I32toF64, -//.. unop(Iop_64HIto32, mkexpr(arg64)) )) ); -//.. -//.. goto decode_success; -//.. } -//.. -//.. /* F3 0F 2A = CVTSI2SS -- convert I32 in mem/ireg to F32 in low -//.. quarter xmm */ -//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x2A) { -//.. IRTemp arg32 = newTemp(Ity_I32); -//.. IRTemp rmode = newTemp(Ity_I32); -//.. vassert(sz == 4); -//.. -//.. modrm = getUChar(delta+3); -//.. if (epartIsReg(modrm)) { -//.. assign( arg32, getIReg(4, eregOfRM(modrm)) ); -//.. delta += 3+1; -//.. DIP("cvtsi2ss %s,%s\n", nameIReg(4, eregOfRM(modrm)), -//.. nameXMMReg(gregOfRM(modrm))); -//.. } else { -//.. addr = disAMode ( &alen, sorb, delta+3, dis_buf ); -//.. assign( arg32, loadLE(Ity_I32, mkexpr(addr)) ); -//.. delta += 3+alen; -//.. DIP("cvtsi2ss %s,%s\n", dis_buf, -//.. nameXMMReg(gregOfRM(modrm)) ); -//.. } -//.. -//.. assign( rmode, get_sse_roundingmode() ); -//.. -//.. putXMMRegLane32F( -//.. gregOfRM(modrm), 0, -//.. binop(Iop_F64toF32, +//.. gregOfRM(modrm), 1, +//.. binop(Iop_F64toF32, //.. mkexpr(rmode), -//.. unop(Iop_I32toF64, mkexpr(arg32)) ) ); +//.. unop(Iop_I32toF64, +//.. unop(Iop_64HIto32, mkexpr(arg64)) )) ); //.. //.. goto decode_success; //.. } -//.. + + /* F3 0F 2A = CVTSI2SS + -- sz==4: convert I32 in mem/ireg to F32 in low quarter xmm + -- sz==8: convert I64 in mem/ireg to F32 in low quarter xmm */ + if (haveF3no66noF2(pfx) && (sz == 4 || sz == 8) + && insn[0] == 0x0F && insn[1] == 0x2A) { + + IRTemp rmode = newTemp(Ity_I32); + assign( rmode, get_sse_roundingmode() ); + modrm = getUChar(delta+2); + + if (sz == 4) { + IRTemp arg32 = newTemp(Ity_I32); + if (epartIsReg(modrm)) { + goto decode_failure; /* awaiting test case */ + assign( arg32, getIRegB(pfx, 4, eregOfRM(modrm)) ); + delta += 2+1; + 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; + DIP("cvtsi2ss %s,%s\n", dis_buf, + nameXMMReg(gregOfRexRM(pfx,modrm)) ); + } + putXMMRegLane32F( + gregOfRexRM(pfx,modrm), 0, + binop(Iop_F64toF32, + mkexpr(rmode), + unop(Iop_I32toF64, mkexpr(arg32)) ) ); + } else { + /* sz == 8 */ + IRTemp arg64 = newTemp(Ity_I64); + if (epartIsReg(modrm)) { + assign( arg64, getIRegB(pfx, 8, eregOfRM(modrm)) ); + delta += 2+1; + DIP("cvtsi2ssq %s,%s\n", nameIRegB(pfx, 8, eregOfRM(modrm)), + nameXMMReg(gregOfRexRM(pfx,modrm))); + } else { + goto decode_failure; /* awaiting test case */ + } + putXMMRegLane32F( + gregOfRexRM(pfx,modrm), 0, + binop(Iop_F64toF32, + mkexpr(rmode), + binop(Iop_I64toF64, mkexpr(rmode), mkexpr(arg64)) ) ); + } + + goto decode_success; + } + //.. /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x //.. I32 in mmx, according to prevailing SSE rounding mode */ //.. /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x @@ -8217,30 +8246,32 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "minss", Iop_Min32F0x4 ); //.. goto decode_success; //.. } -//.. -//.. /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */ -//.. /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */ -//.. if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) { -//.. modrm = getUChar(delta+2); -//.. if (epartIsReg(modrm)) { -//.. putXMMReg( gregOfRM(modrm), -//.. getXMMReg( eregOfRM(modrm) )); -//.. DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRM(modrm)), -//.. nameXMMReg(gregOfRM(modrm))); -//.. delta += 2+1; -//.. } else { -//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf ); -//.. putXMMReg( gregOfRM(modrm), -//.. loadLE(Ity_V128, mkexpr(addr)) ); -//.. DIP("mov[ua]ps %s,%s\n", dis_buf, -//.. nameXMMReg(gregOfRM(modrm))); -//.. delta += 2+alen; -//.. } -//.. goto decode_success; -//.. } + + /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */ + /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */ + if (haveNo66noF2noF3(pfx) && sz == 4 + && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) { + modrm = getUChar(delta+2); + if (epartIsReg(modrm)) { + putXMMReg( gregOfRexRM(pfx,modrm), + getXMMReg( eregOfRexRM(pfx,modrm) )); + DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)), + nameXMMReg(gregOfRexRM(pfx,modrm))); + delta += 2+1; + } else { + addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 ); + putXMMReg( gregOfRexRM(pfx,modrm), + loadLE(Ity_V128, mkexpr(addr)) ); + DIP("mov[ua]ps %s,%s\n", dis_buf, + nameXMMReg(gregOfRexRM(pfx,modrm))); + delta += 2+alen; + } + goto decode_success; + } /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */ - if (haveNo66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x29) { + if (haveNo66noF2noF3(pfx) && sz == 4 + && insn[0] == 0x0F && insn[1] == 0x29) { modrm = getUChar(delta+2); if (epartIsReg(modrm)) { /* fall through; awaiting test case */ @@ -8399,61 +8430,61 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. } //.. /* else fall through */ //.. } -//.. -//.. /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G -//.. (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */ -//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x10) { -//.. vassert(sz == 4); -//.. modrm = getUChar(delta+3); -//.. if (epartIsReg(modrm)) { -//.. putXMMRegLane32( gregOfRM(modrm), 0, -//.. getXMMRegLane32( eregOfRM(modrm), 0 )); -//.. DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)), -//.. nameXMMReg(gregOfRM(modrm))); -//.. delta += 3+1; -//.. } else { -//.. addr = disAMode ( &alen, sorb, delta+3, dis_buf ); -//.. putXMMReg( gregOfRM(modrm), mkV128(0) ); -//.. putXMMRegLane32( gregOfRM(modrm), 0, -//.. loadLE(Ity_I32, mkexpr(addr)) ); -//.. DIP("movss %s,%s\n", dis_buf, -//.. nameXMMReg(gregOfRM(modrm))); -//.. delta += 3+alen; -//.. } -//.. goto decode_success; -//.. } -//.. -//.. /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem -//.. or lo 1/4 xmm). */ -//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x11) { -//.. vassert(sz == 4); -//.. modrm = getUChar(delta+3); -//.. if (epartIsReg(modrm)) { -//.. /* fall through, we don't yet have a test case */ -//.. } else { -//.. addr = disAMode ( &alen, sorb, delta+3, dis_buf ); -//.. storeLE( mkexpr(addr), -//.. getXMMRegLane32(gregOfRM(modrm), 0) ); -//.. DIP("movss %s,%s\n", nameXMMReg(gregOfRM(modrm)), -//.. dis_buf); -//.. delta += 3+alen; -//.. goto decode_success; -//.. } -//.. } -//.. + + /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G + (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */ + if (haveF3no66noF2(pfx) && sz == 4 + && insn[0] == 0x0F && insn[1] == 0x10) { + modrm = getUChar(delta+2); + if (epartIsReg(modrm)) { + putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, + getXMMRegLane32( eregOfRexRM(pfx,modrm), 0 )); + DIP("movss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)), + nameXMMReg(gregOfRexRM(pfx,modrm))); + delta += 2+1; + } else { + addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 ); + putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) ); + putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, + loadLE(Ity_I32, mkexpr(addr)) ); + DIP("movss %s,%s\n", dis_buf, + nameXMMReg(gregOfRexRM(pfx,modrm))); + delta += 2+alen; + } + goto decode_success; + } + + /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem + or lo 1/4 xmm). */ + if (haveF3no66noF2(pfx) && sz == 4 + && insn[0] == 0x0F && insn[1] == 0x11) { + modrm = getUChar(delta+2); + if (epartIsReg(modrm)) { + /* fall through, we don't yet have a test case */ + } else { + addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 ); + storeLE( mkexpr(addr), + getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) ); + DIP("movss %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), + dis_buf); + delta += 2+alen; + goto decode_success; + } + } + //.. /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */ //.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) { //.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 ); //.. goto decode_success; //.. } -//.. -//.. /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */ -//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) { -//.. vassert(sz == 4); -//.. delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "mulss", Iop_Mul32F0x4 ); -//.. goto decode_success; -//.. } -//.. + + /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */ + if (haveF3no66noF2(pfx) && sz == 4 + && insn[0] == 0x0F && insn[1] == 0x59) { + delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "mulss", Iop_Mul32F0x4 ); + goto decode_success; + } + //.. /* 0F 56 = ORPS -- G = G and E */ //.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) { //.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_Or128 ); @@ -8674,7 +8705,7 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. } else { //.. addr = disAMode ( &alen, sorb, delta+2, dis_buf ); //.. assign( sV, loadLE(Ity_I64, mkexpr(addr)) ); -//.. order = (Int)insn[2+alen]; +//.. order = (Int)insn[2+alen]; //.. delta += 3+alen; //.. DIP("pshufw $%d,%s,%s\n", order, //.. dis_buf, @@ -8828,14 +8859,14 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 ); //.. goto decode_success; //.. } -//.. -//.. /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */ -//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5C) { -//.. vassert(sz == 4); -//.. delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "subss", Iop_Sub32F0x4 ); -//.. goto decode_success; -//.. } -//.. + + /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */ + if (haveF3no66noF2(pfx) && sz == 4 + && insn[0] == 0x0F && insn[1] == 0x5C) { + delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "subss", Iop_Sub32F0x4 ); + goto decode_success; + } + //.. /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */ //.. /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */ //.. /* These just appear to be special cases of SHUFPS */ @@ -8875,13 +8906,14 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. //.. goto decode_success; //.. } -//.. -//.. /* 0F 57 = XORPS -- G = G and E */ -//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x57) { -//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorps", Iop_Xor128 ); -//.. goto decode_success; -//.. } -//.. + + /* 0F 57 = XORPS -- G = G and E */ + if (haveNo66noF2noF3(pfx) && sz == 4 + && insn[0] == 0x0F && insn[1] == 0x57) { + delta = dis_SSE_E_to_G_all( pfx, delta+2, "xorps", Iop_XorV128 ); + goto decode_success; + } + //.. /* ---------------------------------------------------- */ //.. /* --- end of the SSE decoder. --- */ //.. /* ---------------------------------------------------- */ @@ -8910,11 +8942,12 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, 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 55 = ANDNPD -- G = (not G) and E */ + if (have66noF2noF3(pfx) && sz == 2 + && insn[0] == 0x0F && insn[1] == 0x55) { + delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "andnpd", Iop_AndV128 ); + goto decode_success; + } /* 66 0F 54 = ANDPD -- G = G and E */ if (have66noF2noF3(pfx) && sz == 2 @@ -8928,13 +8961,13 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmppd", True, 8 ); //.. goto decode_success; //.. } -//.. -//.. /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */ -//.. if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) { -//.. vassert(sz == 4); -//.. delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpsd", False, 8 ); -//.. goto decode_success; -//.. } + + /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */ + if (haveF2no66noF3(pfx) && sz == 4 + && insn[0] == 0x0F && insn[1] == 0xC2) { + delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpsd", False, 8 ); + goto decode_success; + } /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */ /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */ @@ -8988,7 +9021,7 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. nameXMMReg(gregOfRM(modrm))); //.. } else { //.. addr = disAMode ( &alen, sorb, delta+3, dis_buf ); -//.. assign( arg64, loadLE(Ity_I64, mkexpr(addr)) ); +//.. assign( arg64, loadLE(Ity_I64, mkexpr(addr)) ); //.. delta += 3+alen; //.. DIP("cvtdq2pd %s,%s\n", dis_buf, //.. nameXMMReg(gregOfRM(modrm)) ); @@ -9338,42 +9371,43 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, goto decode_success; } -//.. /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in -//.. low 1/4 xmm(G), according to prevailing SSE rounding mode */ -//.. if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) { -//.. IRTemp rmode = newTemp(Ity_I32); -//.. IRTemp f64lo = newTemp(Ity_F64); -//.. vassert(sz == 4); -//.. -//.. modrm = getUChar(delta+3); -//.. if (epartIsReg(modrm)) { -//.. delta += 3+1; -//.. assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0)); -//.. DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRM(modrm)), -//.. nameXMMReg(gregOfRM(modrm))); -//.. } else { -//.. addr = disAMode ( &alen, sorb, delta+3, dis_buf ); -//.. assign(f64lo, loadLE(Ity_F64, mkexpr(addr))); -//.. delta += 3+alen; -//.. DIP("cvtsd2ss %s,%s\n", dis_buf, -//.. nameXMMReg(gregOfRM(modrm))); -//.. } -//.. -//.. assign( rmode, get_sse_roundingmode() ); -//.. putXMMRegLane32F( -//.. gregOfRM(modrm), 0, -//.. binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) ) -//.. ); -//.. -//.. goto decode_success; -//.. } + /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in + low 1/4 xmm(G), according to prevailing SSE rounding mode */ + if (haveF2no66noF3(pfx) && sz == 4 + && insn[0] == 0x0F && insn[1] == 0x5A) { + IRTemp rmode = newTemp(Ity_I32); + IRTemp f64lo = newTemp(Ity_F64); + vassert(sz == 4); + + modrm = getUChar(delta+2); + if (epartIsReg(modrm)) { + delta += 2+1; + assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0)); + DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)), + nameXMMReg(gregOfRexRM(pfx,modrm))); + } else { + addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 ); + assign(f64lo, loadLE(Ity_F64, mkexpr(addr))); + delta += 2+alen; + DIP("cvtsd2ss %s,%s\n", dis_buf, + nameXMMReg(gregOfRexRM(pfx,modrm))); + } + + assign( rmode, get_sse_roundingmode() ); + putXMMRegLane32F( + gregOfRexRM(pfx,modrm), 0, + binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) ) + ); + + goto decode_success; + } /* F2 0F 2A = CVTSI2SD when sz==4 -- convert I32 in mem/ireg to F64 in low half xmm when sz==8 -- convert I64 in mem/ireg to F64 in low half xmm */ - if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x2A) { - vassert(sz == 4 || sz == 8); + if (haveF2no66noF3(pfx) && (sz == 4 || sz == 8) + && insn[0] == 0x0F && insn[1] == 0x2A) { modrm = getUChar(delta+2); if (sz == 4) { @@ -9399,14 +9433,14 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, if (epartIsReg(modrm)) { assign( arg64, getIRegB(pfx, 8, eregOfRM(modrm)) ); delta += 2+1; - DIP("cvtsi2sd %s,%s\n", nameIRegB(pfx, 8, eregOfRM(modrm)), - nameXMMReg(gregOfRexRM(pfx,modrm))); + DIP("cvtsi2sdq %s,%s\n", nameIRegB(pfx, 8, eregOfRM(modrm)), + nameXMMReg(gregOfRexRM(pfx,modrm))); } else { addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 ); assign( arg64, loadLE(Ity_I64, mkexpr(addr)) ); delta += 2+alen; - DIP("cvtsi2sd %s,%s\n", dis_buf, - nameXMMReg(gregOfRexRM(pfx,modrm)) ); + DIP("cvtsi2sdq %s,%s\n", dis_buf, + nameXMMReg(gregOfRexRM(pfx,modrm)) ); } putXMMRegLane64F( gregOfRexRM(pfx,modrm), @@ -9585,32 +9619,33 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "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). */ -//.. /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */ -//.. if (sz == 2 && insn[0] == 0x0F -//.. && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) { -//.. HChar* wot = insn[1]==0x28 ? "apd" : -//.. insn[1]==0x10 ? "upd" : "dqa"; -//.. modrm = getUChar(delta+2); -//.. if (epartIsReg(modrm)) { -//.. putXMMReg( gregOfRM(modrm), -//.. getXMMReg( eregOfRM(modrm) )); -//.. DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRM(modrm)), -//.. nameXMMReg(gregOfRM(modrm))); -//.. delta += 2+1; -//.. } else { -//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf ); -//.. putXMMReg( gregOfRM(modrm), -//.. loadLE(Ity_V128, mkexpr(addr)) ); -//.. DIP("mov%s %s,%s\n", wot, dis_buf, -//.. nameXMMReg(gregOfRM(modrm))); -//.. delta += 2+alen; -//.. } -//.. 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). */ + /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */ + if (have66noF2noF3(pfx) && sz == 2 + && insn[0] == 0x0F + && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) { + HChar* wot = insn[1]==0x28 ? "apd" : + insn[1]==0x10 ? "upd" : "dqa"; + modrm = getUChar(delta+2); + if (epartIsReg(modrm)) { + putXMMReg( gregOfRexRM(pfx,modrm), + getXMMReg( eregOfRexRM(pfx,modrm) )); + DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRexRM(pfx,modrm)), + nameXMMReg(gregOfRexRM(pfx,modrm))); + delta += 2+1; + } else { + addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 ); + putXMMReg( gregOfRexRM(pfx,modrm), + loadLE(Ity_V128, mkexpr(addr)) ); + DIP("mov%s %s,%s\n", wot, dis_buf, + nameXMMReg(gregOfRexRM(pfx,modrm))); + delta += 2+alen; + } + goto decode_success; + } + //.. /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */ //.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x29) { //.. modrm = getUChar(delta+2); @@ -9936,8 +9971,8 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem or lo half xmm). */ - if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x11) { - vassert(sz == 4); + if (haveF2no66noF3(pfx) && sz == 4 + && insn[0] == 0x0F && insn[1] == 0x11) { modrm = getUChar(delta+2); if (epartIsReg(modrm)) { /* fall through, we don't yet have a test case */ @@ -9959,18 +9994,19 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. } /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */ - if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x59) { - vassert(sz == 4); + if (haveF2no66noF3(pfx) && sz == 4 + && insn[0] == 0x0F && insn[1] == 0x59) { delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "mulsd", Iop_Mul64F0x2 ); goto decode_success; } -//.. /* 66 0F 56 = ORPD -- G = G and E */ -//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x56) { -//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "orpd", Iop_Or128 ); -//.. goto decode_success; -//.. } -//.. + /* 66 0F 56 = ORPD -- G = G and E */ + if (have66noF2noF3(pfx) && sz == 2 + && insn[0] == 0x0F && insn[1] == 0x56) { + delta = dis_SSE_E_to_G_all( pfx, delta+2, "orpd", Iop_OrV128 ); + goto decode_success; + } + //.. /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */ //.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) { //.. Int select; @@ -11173,8 +11209,8 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, : "cqo\n")); break; -//.. /* ------------------------ FPU ops -------------------- */ -//.. + /* ------------------------ FPU ops -------------------- */ + //.. case 0x9E: /* SAHF */ //.. codegen_SAHF(); //.. DIP("sahf\n"); @@ -11189,25 +11225,28 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. /* ignore? */ //.. DIP("fwait\n"); //.. break; -//.. -//.. case 0xD8: -//.. case 0xD9: -//.. case 0xDA: -//.. case 0xDB: -//.. case 0xDC: -//.. case 0xDD: -//.. case 0xDE: -//.. case 0xDF: { -//.. ULong delta0 = delta; -//.. Bool decode_OK = False; -//.. delta = dis_FPU ( &decode_OK, sorb, delta ); -//.. if (!decode_OK) { -//.. delta = delta0; -//.. goto decode_failure; -//.. } -//.. break; -//.. } -//.. + + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + if (sz == 4 && haveNo66noF2noF3(pfx)) { + ULong delta0 = delta; + Bool decode_OK = False; + delta = dis_FPU ( &decode_OK, pfx, delta ); + if (!decode_OK) { + delta = delta0; + goto decode_failure; + } + break; + } else { + goto decode_failure; + } + //.. /* ------------------------ INC & DEC ------------------ */ //.. //.. case 0x40: /* INC eAX */ @@ -12295,11 +12334,8 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, case 0x90: /* XCHG eAX,eAX */ if (haveF2orF3(pfx)) goto decode_failure; - if (sz == 2 || sz == 4 || sz == 8) { - DIP("nop\n"); - break; - } - /* else fall through */ + DIP("nop\n"); + break; case 0x91: /* XCHG rAX,rCX */ case 0x92: /* XCHG rAX,rDX */ case 0x93: /* XCHG rAX,rBX */ diff --git a/VEX/priv/host-amd64/hdefs.c b/VEX/priv/host-amd64/hdefs.c index 79a3c0c06b..d3e8c46639 100644 --- a/VEX/priv/host-amd64/hdefs.c +++ b/VEX/priv/host-amd64/hdefs.c @@ -574,10 +574,10 @@ HChar* showAMD64SseOp ( AMD64SseOp op ) { case Asse_DIVF: return "div"; case Asse_MAXF: return "max"; case Asse_MINF: return "min"; -//.. case Xsse_CMPEQF: return "cmpFeq"; -//.. case Xsse_CMPLTF: return "cmpFlt"; -//.. case Xsse_CMPLEF: return "cmpFle"; -//.. case Xsse_CMPUNF: return "cmpFun"; + case Asse_CMPEQF: return "cmpFeq"; + case Asse_CMPLTF: return "cmpFlt"; + case Asse_CMPLEF: return "cmpFle"; + case Asse_CMPUNF: return "cmpFun"; //.. case Xsse_RCPF: return "rcp"; //.. case Xsse_RSQRTF: return "rsqrt"; case Asse_SQRTF: return "sqrt"; @@ -891,6 +891,16 @@ AMD64Instr* AMD64Instr_SseSF2SI ( Int szS, Int szD, HReg src, HReg dst ) { vassert(szD == 4 || szD == 8); return i; } +AMD64Instr* AMD64Instr_SseSDSS ( Bool from64, HReg src, HReg dst ) +{ + AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr)); + i->tag = Ain_SseSDSS; + i->Ain.SseSDSS.from64 = from64; + i->Ain.SseSDSS.src = src; + i->Ain.SseSDSS.dst = dst; + return i; +} + //.. AMD64Instr* AMD64Instr_SseConst ( UShort con, HReg dst ) { //.. AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr)); //.. i->tag = Xin_SseConst; @@ -920,24 +930,24 @@ AMD64Instr* AMD64Instr_SseLdzLO ( Int sz, HReg reg, AMD64AMode* addr ) vassert(sz == 4 || sz == 8); return i; } -//.. AMD64Instr* AMD64Instr_Sse32Fx4 ( AMD64SseOp op, HReg src, HReg dst ) { -//.. AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr)); -//.. i->tag = Xin_Sse32Fx4; -//.. i->Xin.Sse32Fx4.op = op; -//.. i->Xin.Sse32Fx4.src = src; -//.. i->Xin.Sse32Fx4.dst = dst; -//.. vassert(op != Xsse_MOV); -//.. return i; -//.. } -//.. AMD64Instr* AMD64Instr_Sse32FLo ( AMD64SseOp op, HReg src, HReg dst ) { -//.. AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr)); -//.. i->tag = Xin_Sse32FLo; -//.. i->Xin.Sse32FLo.op = op; -//.. i->Xin.Sse32FLo.src = src; -//.. i->Xin.Sse32FLo.dst = dst; -//.. vassert(op != Xsse_MOV); -//.. return i; -//.. } +AMD64Instr* AMD64Instr_Sse32Fx4 ( AMD64SseOp op, HReg src, HReg dst ) { + AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr)); + i->tag = Ain_Sse32Fx4; + i->Ain.Sse32Fx4.op = op; + i->Ain.Sse32Fx4.src = src; + i->Ain.Sse32Fx4.dst = dst; + vassert(op != Asse_MOV); + return i; +} +AMD64Instr* AMD64Instr_Sse32FLo ( AMD64SseOp op, HReg src, HReg dst ) { + AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr)); + i->tag = Ain_Sse32FLo; + i->Ain.Sse32FLo.op = op; + i->Ain.Sse32FLo.src = src; + i->Ain.Sse32FLo.dst = dst; + vassert(op != Asse_MOV); + return i; +} //.. AMD64Instr* AMD64Instr_Sse64Fx2 ( AMD64SseOp op, HReg src, HReg dst ) { //.. AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr)); //.. i->tag = Xin_Sse64Fx2; @@ -964,15 +974,15 @@ AMD64Instr* AMD64Instr_SseReRg ( AMD64SseOp op, HReg re, HReg rg ) { i->Ain.SseReRg.dst = rg; return i; } -//.. AMD64Instr* AMD64Instr_SseCMov ( AMD64CondCode cond, HReg src, HReg dst ) { -//.. AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr)); -//.. i->tag = Xin_SseCMov; -//.. i->Xin.SseCMov.cond = cond; -//.. i->Xin.SseCMov.src = src; -//.. i->Xin.SseCMov.dst = dst; -//.. vassert(cond != Xcc_ALWAYS); -//.. return i; -//.. } +AMD64Instr* AMD64Instr_SseCMov ( AMD64CondCode cond, HReg src, HReg dst ) { + AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr)); + i->tag = Ain_SseCMov; + i->Ain.SseCMov.cond = cond; + i->Ain.SseCMov.src = src; + i->Ain.SseCMov.dst = dst; + vassert(cond != Acc_ALWAYS); + return i; +} //.. AMD64Instr* AMD64Instr_SseShuf ( Int order, HReg src, HReg dst ) { //.. AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr)); //.. i->tag = Xin_SseShuf; @@ -1206,6 +1216,12 @@ void ppAMD64Instr ( AMD64Instr* i ) (i->Ain.SseSF2SI.szD==4 ? ppHRegAMD64_lo32 : ppHRegAMD64) (i->Ain.SseSF2SI.dst); break; + case Ain_SseSDSS: + vex_printf(i->Ain.SseSDSS.from64 ? "cvtsd2ss " : "cvtss2sd "); + ppHRegAMD64(i->Ain.SseSDSS.src); + vex_printf(","); + ppHRegAMD64(i->Ain.SseSDSS.dst); + break; //.. case Xin_SseConst: //.. vex_printf("const $0x%04x,", (Int)i->Xin.SseConst.con); //.. ppHRegAMD64(i->Xin.SseConst.dst); @@ -1233,18 +1249,18 @@ void ppAMD64Instr ( AMD64Instr* i ) vex_printf(","); ppHRegAMD64(i->Ain.SseLdzLO.reg); return; -//.. case Xin_Sse32Fx4: -//.. vex_printf("%sps ", showAMD64SseOp(i->Xin.Sse32Fx4.op)); -//.. ppHRegAMD64(i->Xin.Sse32Fx4.src); -//.. vex_printf(","); -//.. ppHRegAMD64(i->Xin.Sse32Fx4.dst); -//.. return; -//.. case Xin_Sse32FLo: -//.. vex_printf("%sss ", showAMD64SseOp(i->Xin.Sse32FLo.op)); -//.. ppHRegAMD64(i->Xin.Sse32FLo.src); -//.. vex_printf(","); -//.. ppHRegAMD64(i->Xin.Sse32FLo.dst); -//.. return; + case Ain_Sse32Fx4: + vex_printf("%sps ", showAMD64SseOp(i->Ain.Sse32Fx4.op)); + ppHRegAMD64(i->Ain.Sse32Fx4.src); + vex_printf(","); + ppHRegAMD64(i->Ain.Sse32Fx4.dst); + return; + case Ain_Sse32FLo: + vex_printf("%sss ", showAMD64SseOp(i->Ain.Sse32FLo.op)); + ppHRegAMD64(i->Ain.Sse32FLo.src); + vex_printf(","); + ppHRegAMD64(i->Ain.Sse32FLo.dst); + return; //.. case Xin_Sse64Fx2: //.. vex_printf("%spd ", showAMD64SseOp(i->Xin.Sse64Fx2.op)); //.. ppHRegAMD64(i->Xin.Sse64Fx2.src); @@ -1263,12 +1279,12 @@ void ppAMD64Instr ( AMD64Instr* i ) vex_printf(","); ppHRegAMD64(i->Ain.SseReRg.dst); return; -//.. case Xin_SseCMov: -//.. vex_printf("cmov%s ", showAMD64CondCode(i->Xin.SseCMov.cond)); -//.. ppHRegAMD64(i->Xin.SseCMov.src); -//.. vex_printf(","); -//.. ppHRegAMD64(i->Xin.SseCMov.dst); -//.. return; + case Ain_SseCMov: + vex_printf("cmov%s ", showAMD64CondCode(i->Ain.SseCMov.cond)); + ppHRegAMD64(i->Ain.SseCMov.src); + vex_printf(","); + ppHRegAMD64(i->Ain.SseCMov.dst); + return; //.. case Xin_SseShuf: //.. vex_printf("pshufd $0x%x,", i->Xin.SseShuf.order); //.. ppHRegAMD64(i->Xin.SseShuf.src); @@ -1469,6 +1485,10 @@ void getRegUsage_AMD64Instr ( HRegUsage* u, AMD64Instr* i ) addHRegUse(u, HRmRead, i->Ain.SseSF2SI.src); addHRegUse(u, HRmWrite, i->Ain.SseSF2SI.dst); return; + case Ain_SseSDSS: + addHRegUse(u, HRmRead, i->Ain.SseSDSS.src); + addHRegUse(u, HRmWrite, i->Ain.SseSDSS.dst); + return; case Ain_SseLdSt: addRegUsage_AMD64AMode(u, i->Ain.SseLdSt.addr); addHRegUse(u, i->Ain.SseLdSt.isLoad ? HRmWrite : HRmRead, @@ -1481,24 +1501,24 @@ void getRegUsage_AMD64Instr ( HRegUsage* u, AMD64Instr* i ) //.. case Xin_SseConst: //.. addHRegUse(u, HRmWrite, i->Xin.SseConst.dst); //.. return; -//.. case Xin_Sse32Fx4: -//.. vassert(i->Xin.Sse32Fx4.op != Xsse_MOV); -//.. unary = i->Xin.Sse32Fx4.op == Xsse_RCPF -//.. || i->Xin.Sse32Fx4.op == Xsse_RSQRTF -//.. || i->Xin.Sse32Fx4.op == Xsse_SQRTF; -//.. addHRegUse(u, HRmRead, i->Xin.Sse32Fx4.src); -//.. addHRegUse(u, unary ? HRmWrite : HRmModify, -//.. i->Xin.Sse32Fx4.dst); -//.. return; -//.. case Xin_Sse32FLo: -//.. vassert(i->Xin.Sse32FLo.op != Xsse_MOV); -//.. unary = i->Xin.Sse32FLo.op == Xsse_RCPF -//.. || i->Xin.Sse32FLo.op == Xsse_RSQRTF -//.. || i->Xin.Sse32FLo.op == Xsse_SQRTF; -//.. addHRegUse(u, HRmRead, i->Xin.Sse32FLo.src); -//.. addHRegUse(u, unary ? HRmWrite : HRmModify, -//.. i->Xin.Sse32FLo.dst); -//.. return; + case Ain_Sse32Fx4: + vassert(i->Ain.Sse32Fx4.op != Asse_MOV); + unary = i->Ain.Sse32Fx4.op == Asse_RCPF + || i->Ain.Sse32Fx4.op == Asse_RSQRTF + || i->Ain.Sse32Fx4.op == Asse_SQRTF; + addHRegUse(u, HRmRead, i->Ain.Sse32Fx4.src); + addHRegUse(u, unary ? HRmWrite : HRmModify, + i->Ain.Sse32Fx4.dst); + return; + case Ain_Sse32FLo: + vassert(i->Ain.Sse32FLo.op != Asse_MOV); + unary = i->Ain.Sse32FLo.op == Asse_RCPF + || i->Ain.Sse32FLo.op == Asse_RSQRTF + || i->Ain.Sse32FLo.op == Asse_SQRTF; + addHRegUse(u, HRmRead, i->Ain.Sse32FLo.src); + addHRegUse(u, unary ? HRmWrite : HRmModify, + i->Ain.Sse32FLo.dst); + return; //.. case Xin_Sse64Fx2: //.. vassert(i->Xin.Sse64Fx2.op != Xsse_MOV); //.. unary = i->Xin.Sse64Fx2.op == Xsse_RCPF @@ -1530,10 +1550,10 @@ void getRegUsage_AMD64Instr ( HRegUsage* u, AMD64Instr* i ) i->Ain.SseReRg.dst); } return; -//.. case Xin_SseCMov: -//.. addHRegUse(u, HRmRead, i->Xin.SseCMov.src); -//.. addHRegUse(u, HRmModify, i->Xin.SseCMov.dst); -//.. return; + case Ain_SseCMov: + addHRegUse(u, HRmRead, i->Ain.SseCMov.src); + addHRegUse(u, HRmModify, i->Ain.SseCMov.dst); + return; //.. case Xin_SseShuf: //.. addHRegUse(u, HRmRead, i->Xin.SseShuf.src); //.. addHRegUse(u, HRmWrite, i->Xin.SseShuf.dst); @@ -1660,6 +1680,10 @@ void mapRegs_AMD64Instr ( HRegRemap* m, AMD64Instr* i ) mapReg(m, &i->Ain.SseSF2SI.src); mapReg(m, &i->Ain.SseSF2SI.dst); return; + case Ain_SseSDSS: + mapReg(m, &i->Ain.SseSDSS.src); + mapReg(m, &i->Ain.SseSDSS.dst); + return; //.. case Xin_SseConst: //.. mapReg(m, &i->Xin.SseConst.dst); //.. return; @@ -1671,14 +1695,14 @@ void mapRegs_AMD64Instr ( HRegRemap* m, AMD64Instr* i ) mapReg(m, &i->Ain.SseLdzLO.reg); mapRegs_AMD64AMode(m, i->Ain.SseLdzLO.addr); break; -//.. case Xin_Sse32Fx4: -//.. mapReg(m, &i->Xin.Sse32Fx4.src); -//.. mapReg(m, &i->Xin.Sse32Fx4.dst); -//.. return; -//.. case Xin_Sse32FLo: -//.. mapReg(m, &i->Xin.Sse32FLo.src); -//.. mapReg(m, &i->Xin.Sse32FLo.dst); -//.. return; + case Ain_Sse32Fx4: + mapReg(m, &i->Ain.Sse32Fx4.src); + mapReg(m, &i->Ain.Sse32Fx4.dst); + return; + case Ain_Sse32FLo: + mapReg(m, &i->Ain.Sse32FLo.src); + mapReg(m, &i->Ain.Sse32FLo.dst); + return; //.. case Xin_Sse64Fx2: //.. mapReg(m, &i->Xin.Sse64Fx2.src); //.. mapReg(m, &i->Xin.Sse64Fx2.dst); @@ -1691,10 +1715,10 @@ void mapRegs_AMD64Instr ( HRegRemap* m, AMD64Instr* i ) mapReg(m, &i->Ain.SseReRg.src); mapReg(m, &i->Ain.SseReRg.dst); return; -//.. case Xin_SseCMov: -//.. mapReg(m, &i->Xin.SseCMov.src); -//.. mapReg(m, &i->Xin.SseCMov.dst); -//.. return; + case Ain_SseCMov: + mapReg(m, &i->Ain.SseCMov.src); + mapReg(m, &i->Ain.SseCMov.dst); + return; //.. case Xin_SseShuf: //.. mapReg(m, &i->Xin.SseShuf.src); //.. mapReg(m, &i->Xin.SseShuf.dst); @@ -2934,6 +2958,18 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i ) vreg2ireg(i->Ain.SseSF2SI.src) ); goto done; + case Ain_SseSDSS: + /* cvtsd2ss/cvtss2sd %src, %dst */ + *p++ = i->Ain.SseSDSS.from64 ? 0xF2 : 0xF3; + *p++ = clearWBit( + rexAMode_R( vreg2ireg(i->Ain.SseSDSS.dst), + vreg2ireg(i->Ain.SseSDSS.src) )); + *p++ = 0x0F; + *p++ = 0x5A; + p = doAMode_R( p, vreg2ireg(i->Ain.SseSDSS.dst), + vreg2ireg(i->Ain.SseSDSS.src) ); + goto done; + //.. //.. case Xin_FpCmp: //.. /* gcmp %fL, %fR, %dst @@ -2978,7 +3014,6 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i ) *p++ = 0xF2; } else if (i->Ain.SseLdSt.sz == 4) { - goto bad; /* awaiting test case */ *p++ = 0xF3; } else if (i->Ain.SseLdSt.sz != 16) { @@ -3004,30 +3039,33 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i ) i->Ain.SseLdzLO.addr); goto done; -//.. case Xin_Sse32Fx4: -//.. xtra = 0; -//.. *p++ = 0x0F; -//.. switch (i->Xin.Sse32Fx4.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.Sse32Fx4.dst)), -//.. fake(vregNo(i->Xin.Sse32Fx4.src)) ); -//.. if (xtra & 0x100) -//.. *p++ = (UChar)(xtra & 0xFF); -//.. goto done; -//.. + case Ain_Sse32Fx4: + xtra = 0; + *p++ = clearWBit( + rexAMode_R( vreg2ireg(i->Ain.Sse32Fx4.dst), + vreg2ireg(i->Ain.Sse32Fx4.src) )); + *p++ = 0x0F; + switch (i->Ain.Sse32Fx4.op) { + //case Asse_ADDF: *p++ = 0x58; break; + //case Asse_DIVF: *p++ = 0x5E; break; + //case Asse_MAXF: *p++ = 0x5F; break; + //case Asse_MINF: *p++ = 0x5D; break; + //case Asse_MULF: *p++ = 0x59; break; + //case Asse_RCPF: *p++ = 0x53; break; + //case Asse_RSQRTF: *p++ = 0x52; break; + //case Asse_SQRTF: *p++ = 0x51; break; + //case Asse_SUBF: *p++ = 0x5C; break; + case Asse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break; + //case Asse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break; + //case Asse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break; + default: goto bad; + } + p = doAMode_R(p, vreg2ireg(i->Ain.Sse32Fx4.dst), + vreg2ireg(i->Ain.Sse32Fx4.src) ); + if (xtra & 0x100) + *p++ = (UChar)(xtra & 0xFF); + goto done; + //.. case Xin_Sse64Fx2: //.. xtra = 0; //.. *p++ = 0x66; @@ -3052,31 +3090,34 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i ) //.. if (xtra & 0x100) //.. *p++ = (UChar)(xtra & 0xFF); //.. goto done; -//.. -//.. case Xin_Sse32FLo: -//.. xtra = 0; -//.. *p++ = 0xF3; -//.. *p++ = 0x0F; -//.. switch (i->Xin.Sse32FLo.op) { -//.. case Xsse_ADDF: *p++ = 0x58; break; + + case Ain_Sse32FLo: + xtra = 0; + *p++ = 0xF3; + *p++ = clearWBit( + rexAMode_R( vreg2ireg(i->Ain.Sse32FLo.dst), + vreg2ireg(i->Ain.Sse32FLo.src) )); + *p++ = 0x0F; + switch (i->Ain.Sse32FLo.op) { + case Asse_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 Asse_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 Asse_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.Sse32FLo.dst)), -//.. fake(vregNo(i->Xin.Sse32FLo.src)) ); -//.. if (xtra & 0x100) -//.. *p++ = (UChar)(xtra & 0xFF); -//.. goto done; + default: goto bad; + } + p = doAMode_R(p, vreg2ireg(i->Ain.Sse32FLo.dst), + vreg2ireg(i->Ain.Sse32FLo.src) ); + if (xtra & 0x100) + *p++ = (UChar)(xtra & 0xFF); + goto done; case Ain_Sse64FLo: xtra = 0; @@ -3096,7 +3137,7 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i ) case Asse_SQRTF: *p++ = 0x51; break; case Asse_SUBF: *p++ = 0x5C; break; //.. case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break; -//.. case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break; + case Asse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break; //.. case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break; default: goto bad; } @@ -3115,7 +3156,7 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i ) switch (i->Ain.SseReRg.op) { case Asse_MOV: /*movups*/ XX(rex); XX(0x0F); XX(0x10); break; -//.. case Xsse_OR: XX(rex); XX(0x0F); XX(0x56); break; + case Asse_OR: XX(rex); XX(0x0F); XX(0x56); break; case Asse_XOR: XX(rex); XX(0x0F); XX(0x57); break; case Asse_AND: XX(rex); XX(0x0F); XX(0x54); break; //.. case Xsse_PACKSSD: XX(0x66); XX(rex); XX(0x0F); XX(0x6B); break; @@ -3175,22 +3216,25 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i ) # undef XX goto done; -//.. case Xin_SseCMov: -//.. /* jmp fwds if !condition */ -//.. *p++ = 0x70 + (i->Xin.SseCMov.cond ^ 1); -//.. *p++ = 0; /* # of bytes in the next bit, which we don't know yet */ -//.. ptmp = p; -//.. -//.. /* movaps %src, %dst */ -//.. *p++ = 0x0F; -//.. *p++ = 0x28; -//.. p = doAMode_R(p, fake(vregNo(i->Xin.SseCMov.dst)), -//.. fake(vregNo(i->Xin.SseCMov.src)) ); -//.. -//.. /* Fill in the jump offset. */ -//.. *(ptmp-1) = p - ptmp; -//.. goto done; -//.. + case Ain_SseCMov: + /* jmp fwds if !condition */ + *p++ = 0x70 + (i->Ain.SseCMov.cond ^ 1); + *p++ = 0; /* # of bytes in the next bit, which we don't know yet */ + ptmp = p; + + /* movaps %src, %dst */ + *p++ = clearWBit( + rexAMode_R( vreg2ireg(i->Ain.SseCMov.dst), + vreg2ireg(i->Ain.SseCMov.src) )); + *p++ = 0x0F; + *p++ = 0x28; + p = doAMode_R(p, vreg2ireg(i->Ain.SseCMov.dst), + vreg2ireg(i->Ain.SseCMov.src) ); + + /* Fill in the jump offset. */ + *(ptmp-1) = p - ptmp; + goto done; + //.. case Xin_SseShuf: //.. *p++ = 0x66; //.. *p++ = 0x0F; diff --git a/VEX/priv/host-amd64/hdefs.h b/VEX/priv/host-amd64/hdefs.h index 587cac3ce2..cf1b006eee 100644 --- a/VEX/priv/host-amd64/hdefs.h +++ b/VEX/priv/host-amd64/hdefs.h @@ -316,7 +316,7 @@ typedef /* Floating point binary */ Asse_ADDF, Asse_SUBF, Asse_MULF, Asse_DIVF, Asse_MAXF, Asse_MINF, -//.. Xsse_CMPEQF, Xsse_CMPLTF, Xsse_CMPLEF, Xsse_CMPUNF, + Asse_CMPEQF, Asse_CMPLTF, Asse_CMPLEF, Asse_CMPUNF, /* Floating point unary */ Asse_RCPF, Asse_RSQRTF, Asse_SQRTF, /* Bitwise */ @@ -385,17 +385,18 @@ typedef register */ Ain_SseSI2SF, /* scalar 32/64 int to 32/64 float conversion */ Ain_SseSF2SI, /* scalar 32/64 float to 32/64 int conversion */ + Ain_SseSDSS, /* scalar float32 to/from float64 */ //.. //.. Xin_SseConst, /* Generate restricted SSE literal */ Ain_SseLdSt, /* SSE load/store 32/64/128 bits, no alignment constraints, upper 96/64/0 bits arbitrary */ Ain_SseLdzLO, /* SSE load low 32/64 bits, zero remainder of reg */ -//.. Xin_Sse32Fx4, /* SSE binary, 32Fx4 */ -//.. Xin_Sse32FLo, /* SSE binary, 32F in lowest lane only */ + Ain_Sse32Fx4, /* SSE binary, 32Fx4 */ + Ain_Sse32FLo, /* SSE binary, 32F in lowest lane only */ //.. Xin_Sse64Fx2, /* SSE binary, 64Fx2 */ Ain_Sse64FLo, /* SSE binary, 64F in lowest lane only */ Ain_SseReRg, /* SSE binary general reg-reg, Re, Rg */ -//.. Xin_SseCMov, /* SSE conditional move */ + Ain_SseCMov, /* SSE conditional move */ //.. Xin_SseShuf /* SSE2 shuffle (pshufd) */ } AMD64InstrTag; @@ -586,6 +587,12 @@ typedef HReg src; /* v class */ HReg dst; /* i class */ } SseSF2SI; + /* scalar float32 to/from float64 */ + struct { + Bool from64; /* True: 64->32; False: 32->64 */ + HReg src; + HReg dst; + } SseSDSS; //.. //.. /* Simplistic SSE[123] */ //.. struct { @@ -603,16 +610,16 @@ typedef HReg reg; AMD64AMode* addr; } SseLdzLO; -//.. struct { -//.. X86SseOp op; -//.. HReg src; -//.. HReg dst; -//.. } Sse32Fx4; -//.. struct { -//.. X86SseOp op; -//.. HReg src; -//.. HReg dst; -//.. } Sse32FLo; + struct { + AMD64SseOp op; + HReg src; + HReg dst; + } Sse32Fx4; + struct { + AMD64SseOp op; + HReg src; + HReg dst; + } Sse32FLo; //.. struct { //.. X86SseOp op; //.. HReg src; @@ -628,13 +635,13 @@ typedef HReg src; HReg dst; } SseReRg; -//.. /* Mov src to dst on the given condition, which may not -//.. be the bogus Xcc_ALWAYS. */ -//.. struct { -//.. X86CondCode cond; -//.. HReg src; -//.. HReg dst; -//.. } SseCMov; + /* Mov src to dst on the given condition, which may not + be the bogus Xcc_ALWAYS. */ + struct { + AMD64CondCode cond; + HReg src; + HReg dst; + } SseCMov; //.. struct { //.. Int order; /* 0 <= order <= 0xFF */ //.. HReg src; @@ -677,16 +684,17 @@ extern AMD64Instr* AMD64Instr_LdMXCSR ( AMD64AMode* ); extern AMD64Instr* AMD64Instr_SseUComIS ( Int sz, HReg srcL, HReg srcR, HReg dst ); extern AMD64Instr* AMD64Instr_SseSI2SF ( Int szS, Int szD, HReg src, HReg dst ); extern AMD64Instr* AMD64Instr_SseSF2SI ( Int szS, Int szD, HReg src, HReg dst ); +extern AMD64Instr* AMD64Instr_SseSDSS ( Bool from64, HReg src, HReg dst ); //.. //.. extern AMD64Instr* AMD64Instr_SseConst ( UShort con, HReg dst ); extern AMD64Instr* AMD64Instr_SseLdSt ( Bool isLoad, Int sz, HReg, AMD64AMode* ); extern AMD64Instr* AMD64Instr_SseLdzLO ( Int sz, HReg, AMD64AMode* ); -//.. extern AMD64Instr* AMD64Instr_Sse32Fx4 ( AMD64SseOp, HReg, HReg ); -//.. extern AMD64Instr* AMD64Instr_Sse32FLo ( AMD64SseOp, HReg, HReg ); +extern AMD64Instr* AMD64Instr_Sse32Fx4 ( AMD64SseOp, HReg, HReg ); +extern AMD64Instr* AMD64Instr_Sse32FLo ( AMD64SseOp, HReg, HReg ); //.. extern AMD64Instr* AMD64Instr_Sse64Fx2 ( AMD64SseOp, HReg, HReg ); extern AMD64Instr* AMD64Instr_Sse64FLo ( AMD64SseOp, HReg, HReg ); extern AMD64Instr* AMD64Instr_SseReRg ( AMD64SseOp, HReg, HReg ); -//.. extern AMD64Instr* AMD64Instr_SseCMov ( AMD64CondCode, HReg src, HReg dst ); +extern AMD64Instr* AMD64Instr_SseCMov ( AMD64CondCode, HReg src, HReg dst ); //.. extern AMD64Instr* AMD64Instr_SseShuf ( Int order, HReg src, HReg dst ); diff --git a/VEX/priv/host-amd64/isel.c b/VEX/priv/host-amd64/isel.c index 7159afd7ac..01718ddec3 100644 --- a/VEX/priv/host-amd64/isel.c +++ b/VEX/priv/host-amd64/isel.c @@ -233,8 +233,8 @@ static AMD64CondCode iselCondCode ( ISelEnv* env, IRExpr* e ); static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ); static HReg iselDblExpr ( ISelEnv* env, IRExpr* e ); -//static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e ); -//static HReg iselFltExpr ( ISelEnv* env, IRExpr* e ); +static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e ); +static HReg iselFltExpr ( ISelEnv* env, IRExpr* e ); static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ); static HReg iselVecExpr ( ISelEnv* env, IRExpr* e ); @@ -567,48 +567,50 @@ void doHelperCall ( ISelEnv* env, } -//.. /* Given a guest-state array descriptor, an index expression and a -//.. bias, generate an X86AMode holding the relevant guest state -//.. offset. */ -//.. -//.. static -//.. X86AMode* genGuestArrayOffset ( ISelEnv* env, IRArray* descr, -//.. IRExpr* off, Int bias ) -//.. { -//.. HReg tmp, roff; -//.. Int elemSz = sizeofIRType(descr->elemTy); -//.. Int nElems = descr->nElems; -//.. -//.. /* throw out any cases not generated by an x86 front end. In -//.. theory there might be a day where we need to handle them -- if -//.. we ever run non-x86-guest on x86 host. */ -//.. -//.. if (nElems != 8 || (elemSz != 1 && elemSz != 8)) -//.. vpanic("genGuestArrayOffset(x86 host)"); -//.. -//.. /* Compute off into a reg, %off. Then return: -//.. -//.. movl %off, %tmp -//.. addl $bias, %tmp (if bias != 0) -//.. andl %tmp, 7 -//.. ... base(%ebp, %tmp, shift) ... -//.. */ -//.. tmp = newVRegI(env); -//.. roff = iselIntExpr_R(env, off); -//.. addInstr(env, mk_iMOVsd_RR(roff, tmp)); -//.. if (bias != 0) { -//.. addInstr(env, -//.. X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(bias), tmp)); -//.. } -//.. addInstr(env, -//.. X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(7), tmp)); -//.. vassert(elemSz == 1 || elemSz == 8); -//.. return -//.. X86AMode_IRRS( descr->base, hregX86_EBP(), tmp, -//.. elemSz==8 ? 3 : 0); -//.. } -//.. -//.. +/* Given a guest-state array descriptor, an index expression and a + bias, generate an AMD64AMode holding the relevant guest state + offset. */ + +static +AMD64AMode* genGuestArrayOffset ( ISelEnv* env, IRArray* descr, + IRExpr* off, Int bias ) +{ + HReg tmp, roff; + Int elemSz = sizeofIRType(descr->elemTy); + Int nElems = descr->nElems; + + /* Throw out any cases not generated by an amd64 front end. In + theory there might be a day where we need to handle them -- if + we ever run non-amd64-guest on amd64 host. */ + + if (nElems != 8 || (elemSz != 1 && elemSz != 8)) + vpanic("genGuestArrayOffset(amd64 host)"); + + /* Compute off into a reg, %off. Then return: + + movq %off, %tmp + addq $bias, %tmp (if bias != 0) + andq %tmp, 7 + ... base(%rbp, %tmp, shift) ... + */ + tmp = newVRegI(env); + roff = iselIntExpr_R(env, off); + addInstr(env, mk_iMOVsd_RR(roff, tmp)); + if (bias != 0) { + /* Make sure the bias is sane, in the sense that there are + no significant bits above bit 30 in it. */ + vassert(-10000 < bias && bias < 10000); + addInstr(env, + AMD64Instr_Alu64R(Aalu_ADD, AMD64RMI_Imm(bias), tmp)); + } + addInstr(env, + AMD64Instr_Alu64R(Aalu_AND, AMD64RMI_Imm(7), tmp)); + vassert(elemSz == 1 || elemSz == 8); + return + AMD64AMode_IRRS( descr->base, hregAMD64_RBP(), tmp, + elemSz==8 ? 3 : 0); +} + /* Set the SSE unit's rounding mode to default (%mxcsr = 0x1F80) */ static @@ -703,27 +705,27 @@ void set_SSE_rounding_mode ( ISelEnv* env, IRExpr* mode ) //.. addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp)); //.. add_to_esp(env, 4); //.. } -//.. -//.. -//.. /* Generate !src into a new vector register, and be sure that the code -//.. is SSE1 compatible. Amazing that Intel doesn't offer a less crappy -//.. way to do this. -//.. */ -//.. static HReg do_sse_Not128 ( ISelEnv* env, HReg src ) -//.. { -//.. HReg dst = newVRegV(env); -//.. /* Set dst to zero. Not strictly necessary, but the idea of doing -//.. a FP comparison on whatever junk happens to be floating around -//.. in it is just too scary. */ -//.. addInstr(env, X86Instr_SseReRg(Xsse_XOR, dst, dst)); -//.. /* And now make it all 1s ... */ -//.. addInstr(env, X86Instr_Sse32Fx4(Xsse_CMPEQF, dst, dst)); -//.. /* Finally, xor 'src' into it. */ -//.. addInstr(env, X86Instr_SseReRg(Xsse_XOR, src, dst)); -//.. return dst; -//.. } -//.. -//.. + + +/* Generate !src into a new vector register, and be sure that the code + is SSE1 compatible. Amazing that Intel doesn't offer a less crappy + way to do this. +*/ +static HReg do_sse_NotV128 ( ISelEnv* env, HReg src ) +{ + HReg dst = newVRegV(env); + /* Set dst to zero. Not strictly necessary, but the idea of doing + a FP comparison on whatever junk happens to be floating around + in it is just too scary. */ + addInstr(env, AMD64Instr_SseReRg(Asse_XOR, dst, dst)); + /* And now make it all 1s ... */ + addInstr(env, AMD64Instr_Sse32Fx4(Asse_CMPEQF, dst, dst)); + /* Finally, xor 'src' into it. */ + addInstr(env, AMD64Instr_SseReRg(Asse_XOR, src, dst)); + return dst; +} + + //.. /* Round an x87 FPU value to 53-bit-mantissa precision, to be used //.. after most non-simple FPU operations (simple = +, -, *, / and //.. sqrt). @@ -1374,18 +1376,18 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) break; } -//.. case Iex_GetI: { -//.. X86AMode* am -//.. = genGuestArrayOffset( -//.. env, e->Iex.GetI.descr, -//.. e->Iex.GetI.ix, e->Iex.GetI.bias ); -//.. HReg dst = newVRegI(env); -//.. if (ty == Ity_I8) { -//.. addInstr(env, X86Instr_LoadEX( 1, False, am, dst )); -//.. return dst; -//.. } -//.. break; -//.. } + case Iex_GetI: { + AMD64AMode* am + = genGuestArrayOffset( + env, e->Iex.GetI.descr, + e->Iex.GetI.ix, e->Iex.GetI.bias ); + HReg dst = newVRegI(env); + if (ty == Ity_I8) { + addInstr(env, AMD64Instr_LoadEX( 1, False, am, dst )); + return dst; + } + break; + } /* --------- CCALL --------- */ case Iex_CCall: { @@ -2549,30 +2551,30 @@ static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo, } -//.. /*---------------------------------------------------------*/ -//.. /*--- ISEL: Floating point expressions (32 bit) ---*/ -//.. /*---------------------------------------------------------*/ -//.. -//.. /* Nothing interesting here; really just wrappers for -//.. 64-bit stuff. */ -//.. -//.. static HReg iselFltExpr ( ISelEnv* env, IRExpr* e ) -//.. { -//.. HReg r = iselFltExpr_wrk( env, e ); -//.. # if 0 -//.. vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); -//.. # endif -//.. vassert(hregClass(r) == HRcFlt64); /* yes, really Flt64 */ -//.. vassert(hregIsVirtual(r)); -//.. return r; -//.. } -//.. -//.. /* DO NOT CALL THIS DIRECTLY */ -//.. static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e ) -//.. { -//.. IRType ty = typeOfIRExpr(env->type_env,e); -//.. vassert(ty == Ity_F32); -//.. +/*---------------------------------------------------------*/ +/*--- ISEL: Floating point expressions (32 bit) ---*/ +/*---------------------------------------------------------*/ + +/* Nothing interesting here; really just wrappers for + 64-bit stuff. */ + +static HReg iselFltExpr ( ISelEnv* env, IRExpr* e ) +{ + HReg r = iselFltExpr_wrk( env, e ); +# if 0 + vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); +# endif + vassert(hregClass(r) == HRcVec128); + vassert(hregIsVirtual(r)); + return r; +} + +/* DO NOT CALL THIS DIRECTLY */ +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); //.. } @@ -2585,20 +2587,20 @@ static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo, //.. addInstr(env, X86Instr_FpLdSt(True/*load*/, 4, res, am)); //.. return res; //.. } -//.. -//.. if (e->tag == Iex_Binop -//.. && e->Iex.Binop.op == Iop_F64toF32) { -//.. /* Although the result is still held in a standard FPU register, -//.. we need to round it to reflect the loss of accuracy/range -//.. entailed in casting it to a 32-bit float. */ -//.. HReg dst = newVRegF(env); -//.. HReg src = iselDblExpr(env, e->Iex.Binop.arg2); -//.. set_FPU_rounding_mode( env, e->Iex.Binop.arg1 ); -//.. addInstr(env, X86Instr_Fp64to32(src,dst)); -//.. set_FPU_rounding_default( env ); -//.. return dst; -//.. } -//.. + + if (e->tag == Iex_Binop + && e->Iex.Binop.op == Iop_F64toF32) { + /* Although the result is still held in a standard SSE register, + we need to round it to reflect the loss of accuracy/range + entailed in casting it to a 32-bit float. */ + HReg dst = newVRegV(env); + HReg src = iselDblExpr(env, e->Iex.Binop.arg2); + set_SSE_rounding_mode( env, e->Iex.Binop.arg1 ); + addInstr(env, AMD64Instr_SseSDSS(True/*D->S*/,src,dst)); + set_SSE_rounding_default( env ); + return dst; + } + //.. if (e->tag == Iex_Get) { //.. X86AMode* am = X86AMode_IR( e->Iex.Get.offset, //.. hregX86_EBP() ); @@ -2621,10 +2623,10 @@ static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo, //.. add_to_esp(env, 4); //.. return dst; //.. } -//.. -//.. ppIRExpr(e); -//.. vpanic("iselFltExpr_wrk"); -//.. } + + ppIRExpr(e); + vpanic("iselFltExpr_wrk"); +} /*---------------------------------------------------------*/ @@ -2677,30 +2679,32 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) return lookupIRTemp(env, e->Iex.Tmp.tmp); } -//.. if (e->tag == Iex_Const) { -//.. union { UInt u32x2[2]; ULong u64; Double f64; } u; -//.. HReg freg = newVRegF(env); -//.. vassert(sizeof(u) == 8); -//.. vassert(sizeof(u.u64) == 8); -//.. vassert(sizeof(u.f64) == 8); -//.. vassert(sizeof(u.u32x2) == 8); -//.. -//.. if (e->Iex.Const.con->tag == Ico_F64) { -//.. u.f64 = e->Iex.Const.con->Ico.F64; -//.. } -//.. else if (e->Iex.Const.con->tag == Ico_F64i) { -//.. u.u64 = e->Iex.Const.con->Ico.F64i; -//.. } -//.. else -//.. vpanic("iselDblExpr(x86): const"); -//.. -//.. addInstr(env, X86Instr_Push(X86RMI_Imm(u.u32x2[1]))); -//.. addInstr(env, X86Instr_Push(X86RMI_Imm(u.u32x2[0]))); -//.. addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, freg, -//.. X86AMode_IR(0, hregX86_ESP()))); -//.. add_to_esp(env, 8); -//.. return freg; -//.. } + if (e->tag == Iex_Const) { + union { ULong u64; Double f64; } u; + HReg res = newVRegV(env); + HReg tmp = newVRegI(env); + vassert(sizeof(u) == 8); + vassert(sizeof(u.u64) == 8); + vassert(sizeof(u.f64) == 8); + + if (e->Iex.Const.con->tag == Ico_F64) { + u.f64 = e->Iex.Const.con->Ico.F64; + } + else if (e->Iex.Const.con->tag == Ico_F64i) { + u.u64 = e->Iex.Const.con->Ico.F64i; + } + else + vpanic("iselDblExpr(amd64): const"); + + addInstr(env, AMD64Instr_Imm64(u.u64, tmp)); + addInstr(env, AMD64Instr_Push(AMD64RMI_Reg(tmp))); + addInstr(env, AMD64Instr_SseLdSt( + True/*load*/, 8, res, + AMD64AMode_IR(0, hregAMD64_RSP()) + )); + add_to_rsp(env, 8); + return res; + } if (e->tag == Iex_LDle) { AMD64AMode* am; @@ -2719,16 +2723,16 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) return res; } -//.. if (e->tag == Iex_GetI) { -//.. X86AMode* am -//.. = genGuestArrayOffset( -//.. env, e->Iex.GetI.descr, -//.. e->Iex.GetI.ix, e->Iex.GetI.bias ); -//.. HReg res = newVRegF(env); -//.. addInstr(env, X86Instr_FpLdSt( True/*load*/, 8, res, am )); -//.. return res; -//.. } -//.. + if (e->tag == Iex_GetI) { + AMD64AMode* am + = genGuestArrayOffset( + env, e->Iex.GetI.descr, + e->Iex.GetI.ix, e->Iex.GetI.bias ); + HReg res = newVRegV(env); + addInstr(env, AMD64Instr_SseLdSt( True/*load*/, 8, res, am )); + return res; + } + //.. if (e->tag == Iex_Binop) { //.. X86FpOp fpop = Xfp_INVALID; //.. switch (e->Iex.Binop.op) { @@ -2792,6 +2796,23 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) return dst; } + if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_NegF64) { + /* Sigh ... very rough code. Could do much better. */ + HReg r1 = newVRegI(env); + HReg dst = newVRegV(env); + HReg tv = 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, 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)); + add_to_rsp(env, 16); + return dst; + } + //.. if (e->tag == Iex_Unop) { //.. X86FpOp fpop = Xfp_INVALID; //.. switch (e->Iex.Unop.op) { @@ -2853,21 +2874,21 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) //.. break; //.. } //.. } -//.. -//.. /* --------- MULTIPLEX --------- */ -//.. if (e->tag == Iex_Mux0X) { -//.. if (ty == Ity_F64 -//.. && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) { -//.. HReg r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond); -//.. HReg rX = iselDblExpr(env, e->Iex.Mux0X.exprX); -//.. HReg r0 = iselDblExpr(env, e->Iex.Mux0X.expr0); -//.. HReg dst = newVRegF(env); -//.. addInstr(env, X86Instr_FpUnary(Xfp_MOV,rX,dst)); -//.. addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8))); -//.. addInstr(env, X86Instr_FpCMov(Xcc_Z,r0,dst)); -//.. return dst; -//.. } -//.. } + + /* --------- MULTIPLEX --------- */ + if (e->tag == Iex_Mux0X) { + HReg r8, rX, r0, dst; + vassert(ty == Ity_F64); + vassert(typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8); + r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond); + rX = iselDblExpr(env, e->Iex.Mux0X.exprX); + r0 = iselDblExpr(env, e->Iex.Mux0X.expr0); + dst = newVRegV(env); + addInstr(env, mk_vMOVsd_RR(rX,dst)); + addInstr(env, AMD64Instr_Test64(AMD64RI_Imm(0xFF), AMD64RM_Reg(r8))); + addInstr(env, AMD64Instr_SseCMov(Acc_Z,r0,dst)); + return dst; + } ppIRExpr(e); vpanic("iselDblExpr_wrk"); @@ -2925,26 +2946,35 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) if (e->tag == Iex_Const) { HReg dst = newVRegV(env); vassert(e->Iex.Const.con->tag == Ico_V128); - if (e->Iex.Const.con->Ico.V128 == 0) { + if (e->Iex.Const.con->Ico.V128 == 0x0000) { addInstr(env, AMD64Instr_SseReRg(Asse_XOR, dst, dst)); return dst; + } else + if (e->Iex.Const.con->Ico.V128 == 0x00FF) { + AMD64AMode* rsp0 = AMD64AMode_IR(0, hregAMD64_RSP()); + /* Both of these literals are sign-extended to 64 bits. */ + addInstr(env, AMD64Instr_Push(AMD64RMI_Imm(0))); + addInstr(env, AMD64Instr_Push(AMD64RMI_Imm(0xFFFFFFFF))); + addInstr(env, AMD64Instr_SseLdSt( True/*load*/, 16, dst, rsp0 )); + add_to_rsp(env, 16); + return dst; } else { goto vec_fail; -#if 0 - addInstr(env, X86Instr_SseConst(e->Iex.Const.con->Ico.V128, dst)); - return dst; -#endif +# if 0 + addInstr(env, X86Instr_SseConst(e->Iex.Const.con->Ico.V128, dst)); + return dst; +# endif } } if (e->tag == Iex_Unop) { switch (e->Iex.Unop.op) { -//.. case Iop_Not128: { -//.. HReg arg = iselVecExpr(env, e->Iex.Unop.arg); -//.. return do_sse_Not128(env, arg); -//.. } -//.. + case Iop_NotV128: { + HReg arg = iselVecExpr(env, e->Iex.Unop.arg); + return do_sse_NotV128(env, arg); + } + //.. case Iop_CmpNEZ64x2: { //.. /* We can use SSE2 instructions for this. */ //.. /* Ideally, we want to do a 64Ix2 comparison against zero of @@ -3086,15 +3116,14 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) return dst; } -//.. case Iop_32Uto128: { -//.. HReg dst = newVRegV(env); -//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP()); -//.. X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Unop.arg); -//.. addInstr(env, X86Instr_Push(rmi)); -//.. addInstr(env, X86Instr_SseLdzLO(4, dst, esp0)); -//.. add_to_esp(env, 4); -//.. return dst; -//.. } + case Iop_32UtoV128: { + HReg dst = newVRegV(env); + AMD64AMode* rsp_m32 = AMD64AMode_IR(-32, hregAMD64_RSP()); + AMD64RI* ri = iselIntExpr_RI(env, e->Iex.Unop.arg); + addInstr(env, AMD64Instr_Alu64M(Aalu_MOV, ri, rsp_m32)); + addInstr(env, AMD64Instr_SseLdzLO(4, dst, rsp_m32)); + return dst; + } case Iop_64UtoV128: { HReg dst = newVRegV(env); @@ -3189,27 +3218,27 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) //.. 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; -//.. case Iop_Add32F0x4: op = Xsse_ADDF; goto do_32F0x4; + case Iop_Add32F0x4: op = Asse_ADDF; goto do_32F0x4; //.. case Iop_Div32F0x4: op = Xsse_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 = Xsse_MULF; goto do_32F0x4; -//.. case Iop_Sub32F0x4: op = Xsse_SUBF; goto do_32F0x4; -//.. do_32F0x4: { -//.. 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_Sse32FLo(op, argR, dst)); -//.. return dst; -//.. } -//.. + case Iop_Mul32F0x4: op = Asse_MULF; goto do_32F0x4; + case Iop_Sub32F0x4: op = Asse_SUBF; goto do_32F0x4; + do_32F0x4: { + 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, AMD64Instr_Sse32FLo(op, argR, dst)); + return dst; + } + //.. case Iop_CmpEQ64F0x2: op = Xsse_CMPEQF; goto do_64F0x2; -//.. case Iop_CmpLT64F0x2: op = Xsse_CMPLTF; goto do_64F0x2; + case Iop_CmpLT64F0x2: op = Asse_CMPLTF; goto do_64F0x2; //.. case Iop_CmpLE64F0x2: op = Xsse_CMPLEF; goto do_64F0x2; case Iop_Add64F0x2: op = Asse_ADDF; goto do_64F0x2; case Iop_Div64F0x2: op = Asse_DIVF; goto do_64F0x2; @@ -3252,7 +3281,7 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) //.. op = Xsse_UNPCKLQ; arg1isEReg = True; goto do_SseReRg; //.. case Iop_AndV128: op = Asse_AND; goto do_SseReRg; -//.. case Iop_Or128: op = Xsse_OR; goto do_SseReRg; + case Iop_OrV128: op = Asse_OR; goto do_SseReRg; case Iop_XorV128: op = Asse_XOR; goto do_SseReRg; //.. case Iop_Add8x16: op = Xsse_ADD8; goto do_SseReRg; //.. case Iop_Add16x8: op = Xsse_ADD16; goto do_SseReRg; @@ -3382,11 +3411,11 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) r,am)); return; } -//.. if (tyd == Ity_F64) { -//.. HReg r = iselDblExpr(env, stmt->Ist.STle.data); -//.. addInstr(env, X86Instr_FpLdSt(False/*store*/, 8, r, am)); -//.. return; -//.. } + if (tyd == Ity_F64) { + HReg r = iselDblExpr(env, stmt->Ist.STle.data); + 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)); @@ -3442,13 +3471,13 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) addInstr(env, AMD64Instr_SseLdSt(False/*store*/, 16, vec, am)); return; } -//.. if (ty == Ity_F32) { -//.. HReg f32 = iselFltExpr(env, stmt->Ist.Put.data); -//.. X86AMode* am = X86AMode_IR(stmt->Ist.Put.offset, hregX86_EBP()); -//.. set_FPU_rounding_default(env); /* paranoia */ -//.. addInstr(env, X86Instr_FpLdSt( False/*store*/, 4, f32, am )); -//.. return; -//.. } + if (ty == Ity_F32) { + HReg f32 = iselFltExpr(env, stmt->Ist.Put.data); + AMD64AMode* am = AMD64AMode_IR(stmt->Ist.Put.offset, hregAMD64_RBP()); + set_SSE_rounding_default(env); /* paranoia */ + addInstr(env, AMD64Instr_SseLdSt( False/*store*/, 4, f32, am )); + return; + } if (ty == Ity_F64) { HReg f64 = iselDblExpr(env, stmt->Ist.Put.data); AMD64AMode* am = AMD64AMode_IR( stmt->Ist.Put.offset, @@ -3459,24 +3488,24 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) break; } -//.. /* --------- Indexed PUT --------- */ -//.. case Ist_PutI: { -//.. X86AMode* am -//.. = genGuestArrayOffset( -//.. env, stmt->Ist.PutI.descr, -//.. stmt->Ist.PutI.ix, stmt->Ist.PutI.bias ); -//.. -//.. IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data); -//.. if (ty == Ity_F64) { -//.. HReg val = iselDblExpr(env, stmt->Ist.PutI.data); -//.. addInstr(env, X86Instr_FpLdSt( False/*store*/, 8, val, am )); -//.. return; -//.. } -//.. if (ty == Ity_I8) { -//.. HReg r = iselIntExpr_R(env, stmt->Ist.PutI.data); -//.. addInstr(env, X86Instr_Store( 1, r, am )); -//.. return; -//.. } + /* --------- Indexed PUT --------- */ + case Ist_PutI: { + AMD64AMode* am + = genGuestArrayOffset( + env, stmt->Ist.PutI.descr, + stmt->Ist.PutI.ix, stmt->Ist.PutI.bias ); + + IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data); + if (ty == Ity_F64) { + HReg val = iselDblExpr(env, stmt->Ist.PutI.data); + addInstr(env, AMD64Instr_SseLdSt( False/*store*/, 8, val, am )); + return; + } + if (ty == Ity_I8) { + HReg r = iselIntExpr_R(env, stmt->Ist.PutI.data); + addInstr(env, AMD64Instr_Store( 1, r, am )); + return; + } //.. if (ty == Ity_I64) { //.. HReg rHi, rLo; //.. X86AMode* am4 = advance4(am); @@ -3485,8 +3514,8 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) //.. addInstr(env, X86Instr_Alu32M( Xalu_MOV, X86RI_Reg(rHi), am4 )); //.. return; //.. } -//.. break; -//.. } + break; + } /* --------- TMP --------- */ case Ist_Tmp: { diff --git a/VEX/pub/libvex_guest_amd64.h b/VEX/pub/libvex_guest_amd64.h index a5d4c5b415..8d30985977 100644 --- a/VEX/pub/libvex_guest_amd64.h +++ b/VEX/pub/libvex_guest_amd64.h @@ -45,11 +45,8 @@ /*---------------------------------------------------------------*/ /* See detailed comments at the top of libvex_guest_x86.h for - further info. This representation pretty closely mimics the + further info. This representation closely follows the x86 representation. - - SSEROUND[1:0] is the SSE unit's notional rounding mode, encoded as - per the IRRoundingMode type. */ @@ -114,6 +111,16 @@ typedef U128 guest_XMM14; U128 guest_XMM15; + /* FPU */ + /* Note. Setting guest_FTOP to be ULong messes up the + delicately-balanced PutI/GetI optimisation machinery. + Therefore best to leave it as a UInt. */ + UInt guest_FTOP; + ULong guest_FPREG[8]; + UChar guest_FPTAG[8]; + ULong guest_FPROUND; + ULong guest_FC3210; + /* Emulation warnings */ UInt guest_EMWARN; /* Padding to make it have an 8-aligned size */