From: Julian Seward Date: Mon, 6 Dec 2004 14:29:12 +0000 (+0000) Subject: x86 guest: Implement various insns: X-Git-Tag: svn/VALGRIND_3_0_1^2~705 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c73a5a146c0ea383dee30dc6f6ed5877407f5f61;p=thirdparty%2Fvalgrind.git x86 guest: Implement various insns: ldmxcsr/stmxcsr fldenv/fstenv prefetch of various flavours (no-op for us) fclex (no-op for us) Some segment reg stuff, but nothing usable yet git-svn-id: svn://svn.valgrind.org/vex/trunk@629 --- diff --git a/VEX/priv/guest-x86/gdefs.h b/VEX/priv/guest-x86/gdefs.h index 63141307c0..dd058f543f 100644 --- a/VEX/priv/guest-x86/gdefs.h +++ b/VEX/priv/guest-x86/gdefs.h @@ -97,7 +97,11 @@ extern ULong x86g_calculate_RCR ( extern ULong x86h_check_fldcw ( UInt fpucw ); -extern UInt x86h_create_fpucw ( UInt fptrz ); +extern UInt x86h_create_fpucw ( UInt fpround ); + +extern ULong x86h_check_ldmxcsr ( UInt mxcsr ); + +extern UInt x86h_create_mxcsr ( UInt sseround ); /* --- Clean helpers for MMX --- */ @@ -179,7 +183,13 @@ extern void x86g_dirtyhelper_CPUID ( VexGuestX86State* ); extern void x86g_dirtyhelper_FSAVE ( VexGuestX86State*, HWord ); -extern void x86g_dirtyhelper_FRSTOR ( VexGuestX86State*, HWord ); +extern VexEmWarn + x86g_dirtyhelper_FRSTOR ( VexGuestX86State*, HWord ); + +extern void x86g_dirtyhelper_FSTENV ( VexGuestX86State*, HWord ); + +extern VexEmWarn + x86g_dirtyhelper_FLDENV ( VexGuestX86State*, HWord ); /*---------------------------------------------------------*/ diff --git a/VEX/priv/guest-x86/ghelpers.c b/VEX/priv/guest-x86/ghelpers.c index 056b30564d..34410f2a9b 100644 --- a/VEX/priv/guest-x86/ghelpers.c +++ b/VEX/priv/guest-x86/ghelpers.c @@ -1387,11 +1387,11 @@ typedef #define FP_REG(ii) (10*(7-(ii))) +/* CLEAN HELPER */ /* native_fpucw[15:0] contains a x87 native format FPU control word. Extract from it the required FPROUND value and any resulting emulation warning, and return (warn << 32) | fpround value. */ -/* CLEAN HELPER */ ULong x86h_check_fldcw ( UInt fpucw ) { /* Decide on a rounding mode. fpucw[11:10] holds it. */ @@ -1415,8 +1415,8 @@ ULong x86h_check_fldcw ( UInt fpucw ) } /* CLEAN HELPER */ -/* Given fprtz as 1 or 0, create a suitable x87 native format - FPU control word. */ +/* Given fpround as an IRRoundingMode value, create a suitable x87 + native format FPU control word. */ UInt x86h_create_fpucw ( UInt fpround ) { fpround &= 3; @@ -1424,9 +1424,51 @@ UInt x86h_create_fpucw ( UInt fpround ) } -/* VISIBLE TO LIBVEX CLIENT */ -VexEmWarn LibVEX_GuestX86_put_x87 ( /*IN*/UChar* x87_state, - /*OUT*/VexGuestX86State* vex_state ) +/* CLEAN HELPER */ +/* native_fpucw[15:0] contains a SSE native format MXCSR value. + Extract from it the required SSEROUND value and any resulting + emulation warning, and return (warn << 32) | sseround value. +*/ +ULong x86h_check_ldmxcsr ( UInt mxcsr ) +{ + /* Decide on a rounding mode. mxcsr[14:13] holds it. */ + /* NOTE, encoded exactly as per enum IRRoundingMode. */ + UInt rmode = (mxcsr >> 13) & 3; + + /* Detect any required emulation warnings. */ + VexEmWarn ew = EmWarn_NONE; + + if ((mxcsr & 0x1F80) != 0x1F80) { + /* unmasked exceptions! */ + ew = EmWarn_X86_sseExns; + } + else + if ((mxcsr & (1<<6)) || (mxcsr & (1<<15))) { + /* FZ or DAZ is set */ + ew = EmWarn_X86_fz_daz; + } + + return (((ULong)ew) << 32) | ((ULong)rmode); +} + + +/* CLEAN HELPER */ +/* Given sseround as an IRRoundingMode value, create a suitable SSE + native format MXCSR value. */ +UInt x86h_create_mxcsr ( UInt sseround ) +{ + sseround &= 3; + return 0x1F80 | (sseround << 13); +} + + +/* This is used to implement both 'frstor' and 'fldenv'. The latter + appears to differ from the former only in that the 8 FP registers + themselves are not transferred into the guest state. */ +static +VexEmWarn put_x87 ( Bool moveRegs, + /*IN*/UChar* x87_state, + /*OUT*/VexGuestX86State* vex_state ) { Int r; UInt tag; @@ -1450,7 +1492,9 @@ VexEmWarn LibVEX_GuestX86_put_x87 ( /*IN*/UChar* x87_state, vexTags[r] = 0; } else { /* register is non-empty */ - convert_f80le_to_f64le( &x87->reg[FP_REG(r)], (UChar*)&vexRegs[r] ); + if (moveRegs) + convert_f80le_to_f64le( &x87->reg[FP_REG(r)], + (UChar*)&vexRegs[r] ); vexTags[r] = 1; } } @@ -1474,6 +1518,14 @@ VexEmWarn LibVEX_GuestX86_put_x87 ( /*IN*/UChar* x87_state, } +/* VISIBLE TO LIBVEX CLIENT */ +VexEmWarn LibVEX_GuestX86_put_x87 ( /*IN*/UChar* x87_state, + /*OUT*/VexGuestX86State* vex_state ) +{ + return put_x87(True, x87_state, vex_state); +} + + /* VISIBLE TO LIBVEX CLIENT */ void LibVEX_GuestX86_get_x87 ( /*IN*/VexGuestX86State* vex_state, /*OUT*/UChar* x87_state ) @@ -1503,7 +1555,7 @@ void LibVEX_GuestX86_get_x87 ( /*IN*/VexGuestX86State* vex_state, } else { /* register is full. */ tagw |= (0 << (2*r)); - convert_f64le_to_f80le( (UChar*)&vexRegs[r], &x87->reg[FP_REG(r)] ); + convert_f64le_to_f80le( (UChar*)&vexRegs[r], &x87->reg[FP_REG(r)] ); } } x87->env[FP_ENV_TAG] = tagw; @@ -1693,9 +1745,29 @@ void x86g_dirtyhelper_FSAVE ( VexGuestX86State* gst, HWord addr ) /* CALLED FROM GENERATED CODE */ /* DIRTY HELPER (writes guest state, reads guest mem) */ -void x86g_dirtyhelper_FRSTOR ( VexGuestX86State* gst, HWord addr ) +VexEmWarn x86g_dirtyhelper_FRSTOR ( VexGuestX86State* gst, HWord addr ) +{ + return LibVEX_GuestX86_put_x87( (UChar*)addr, gst ); +} + +/* CALLED FROM GENERATED CODE */ +/* DIRTY HELPER (reads guest state, writes guest mem) */ +void x86g_dirtyhelper_FSTENV ( VexGuestX86State* gst, HWord addr ) +{ + /* Somewhat roundabout, but at least it's simple. */ + Int i; + UShort* addrP = (UShort*)addr; + Fpu_State tmp; + LibVEX_GuestX86_get_x87( gst, (UChar*)&tmp ); + for (i = 0; i < 14; i++) + addrP[i] = tmp.env[i]; +} + +/* CALLED FROM GENERATED CODE */ +/* DIRTY HELPER (writes guest state, reads guest mem) */ +VexEmWarn x86g_dirtyhelper_FLDENV ( VexGuestX86State* gst, HWord addr ) { - LibVEX_GuestX86_put_x87( (UChar*)addr, gst ); + return put_x87(False, (UChar*)addr, gst); } diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 69ca91c07a..b5b18a5441 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -582,13 +582,11 @@ static IRExpr* getSReg ( UInt sreg ) return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 ); } -#if 0 static void putSReg ( UInt sreg, IRExpr* e ) { vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16); stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) ); } -#endif static IRExpr* getXMMReg ( UInt xmmreg ) { @@ -1574,39 +1572,43 @@ UChar* sorbTxt ( UChar sorb ) case 0x26: return "%es:"; case 0x64: return "%fs:"; case 0x65: return "%gs:"; - default: vpanic("sorbTxt(x86)"); + default: vpanic("sorbTxt(x86,guest)"); } } -/* Tmp is a TempReg holding a virtual address. Convert it to a linear - address by adding any required segment override as indicated by - sorb. */ +/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a + linear address by adding any required segment override as indicated + by sorb. */ static IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual ) { - //Int sreg, tsreg; + //IRTemp tsreg; //Int sreg, tsreg; if (sorb == 0) /* the common case - no override */ return virtual; - unimplemented("segment overrides in new x86->IR phase"); + unimplemented("vex x86->IR: segment override prefix"); #if 0 switch (sorb) { case 0x3E: sreg = R_DS; break; case 0x26: sreg = R_ES; break; case 0x64: sreg = R_FS; break; case 0x65: sreg = R_GS; break; - default: VG_(core_panic)("handleSegOverride"); + default: vpanic("handleSegOverride(x86,guest)"); } - tsreg = newTemp(cb); + tsreg = newTemp(Ity_I32); + + /* tsreg becomes the relevant LDT descriptor */ + assign( tsreg, unop(Iop_16Uto32, getSReg(sreg)) ); + + /* virtual += segment_base(ldt[tsreg]); also do limit check */ +return + binop(Iop_Add32, mkexpr(virtual), - /* sreg -> tsreg */ - uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, tsreg ); - /* tmp += segment_base(ldt[tsreg]); also do limit check */ uInstr2(cb, USESEG, 0, TempReg, tsreg, TempReg, tmp ); #endif } @@ -1996,7 +1998,6 @@ UInt dis_op2_E_G ( UChar sorb, assign( src, getIReg(size,eregOfRM(rm)) ); if (addSubCarry && op8 == Iop_Add8) { - vassert(0); helper_ADC( size, dst1, dst0, src ); putIReg(size, gregOfRM(rm), mkexpr(dst1)); } else @@ -3927,6 +3928,65 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) fp_pop(); break; + case 4: { /* FLDENV m108 */ + /* Uses dirty helper: + VexEmWarn x86g_do_FLDENV ( VexGuestX86State*, Addr32 ) */ + IRTemp ew = newTemp(Ity_I32); + IRDirty* d = unsafeIRDirty_0_N ( + 0/*regparms*/, + "x86g_dirtyhelper_FLDENV", + &x86g_dirtyhelper_FLDENV, + mkIRExprVec_1( mkexpr(addr) ) + ); + d->needsBBP = True; + d->tmp = ew; + /* declare we're reading memory */ + d->mFx = Ifx_Read; + d->mAddr = mkexpr(addr); + d->mSize = 28; + + /* declare we're writing guest state */ + d->nFxState = 5; + + d->fxState[0].fx = Ifx_Write; + d->fxState[0].offset = OFFB_FTOP; + d->fxState[0].size = sizeof(UInt); + + d->fxState[1].fx = Ifx_Write; + d->fxState[1].offset = OFFB_FPREGS; + d->fxState[1].size = 8 * sizeof(ULong); + + d->fxState[2].fx = Ifx_Write; + d->fxState[2].offset = OFFB_FPTAGS; + d->fxState[2].size = 8 * sizeof(UChar); + + d->fxState[3].fx = Ifx_Write; + d->fxState[3].offset = OFFB_FPROUND; + d->fxState[3].size = sizeof(UInt); + + d->fxState[4].fx = Ifx_Write; + d->fxState[4].offset = OFFB_FC3210; + d->fxState[4].size = sizeof(UInt); + + stmt( IRStmt_Dirty(d) ); + + /* ew contains any emulation warning we may need to + issue. If needed, side-exit to the next insn, + reporting the warning, so that Valgrind's dispatcher + sees the warning. */ + put_emwarn( mkexpr(ew) ); + stmt( + IRStmt_Exit( + binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)), + Ijk_EmWarn, + IRConst_U32( ((Addr32)guest_eip_bbstart)+delta) + ) + ); + + DIP("fldenv %s", dis_buf); + break; + } + case 5: {/* FLDCW */ /* The only thing we observe in the control word is the rounding mode. Therefore, pass the 16-bit value @@ -3967,6 +4027,46 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) break; } + case 6: { /* FNSTENV m28 */ + /* Uses dirty helper: + void x86g_do_FSTENV ( VexGuestX86State*, UInt ) */ + IRDirty* d = unsafeIRDirty_0_N ( + 0/*regparms*/, + "x86g_dirtyhelper_FSTENV", + &x86g_dirtyhelper_FSTENV, + mkIRExprVec_1( mkexpr(addr) ) + ); + d->needsBBP = True; + /* declare we're writing memory */ + d->mFx = Ifx_Write; + d->mAddr = mkexpr(addr); + d->mSize = 28; + + /* declare we're reading guest state */ + d->nFxState = 4; + + d->fxState[0].fx = Ifx_Read; + d->fxState[0].offset = OFFB_FTOP; + d->fxState[0].size = sizeof(UInt); + + d->fxState[1].fx = Ifx_Read; + d->fxState[1].offset = OFFB_FPTAGS; + d->fxState[1].size = 8 * sizeof(UChar); + + d->fxState[2].fx = Ifx_Read; + d->fxState[2].offset = OFFB_FPROUND; + d->fxState[2].size = sizeof(UInt); + + d->fxState[3].fx = Ifx_Read; + d->fxState[3].offset = OFFB_FC3210; + d->fxState[3].size = sizeof(UInt); + + stmt( IRStmt_Dirty(d) ); + + DIP("fnstenv %s", dis_buf); + break; + } + case 7: /* FNSTCW */ /* Fake up a native x87 FPU control word. The only thing it depends on is FPROUND[1:0], so call a clean @@ -4395,6 +4495,10 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) get_ST(0), get_ST(r_src)) ); break; + case 0xE2: + DIP("fnclex\n"); + break; + case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */ fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False ); break; @@ -6128,34 +6232,33 @@ UInt dis_xadd_G_E ( UChar sorb, Int sz, UInt delta0 ) //-- LDw (tmpa), tmpb //-- PUTSEG tmpb, %Sw //-- */ -//-- static -//-- Addr dis_mov_Ew_Sw ( UCodeBlock* cb, -//-- UChar sorb, -//-- Addr eip0 ) -//-- { -//-- UChar rm = getUChar(eip0); -//-- HChar dis_buf[50]; -//-- -//-- if (epartIsReg(rm)) { -//-- Int tmpv = newTemp(cb); -//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(rm), TempReg, tmpv); -//-- uInstr2(cb, PUTSEG, 2, TempReg, tmpv, ArchRegS, gregOfRM(rm)); -//-- DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm))); -//-- return 1+eip0; -//-- } -//-- -//-- /* E refers to memory */ -//-- { -//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf ); -//-- Int tmpa = LOW24(pair); -//-- Int tmpb = newTemp(cb); -//-- uInstr2(cb, LOAD, 2, TempReg, tmpa, TempReg, tmpb); -//-- uInstr2(cb, PUTSEG, 2, TempReg, tmpb, ArchRegS, gregOfRM(rm)); -//-- DIP("movw %s,%s\n", dis_buf,nameSReg(gregOfRM(rm))); -//-- return HI8(pair)+eip0; -//-- } -//-- } -//-- +static +UInt dis_mov_Ew_Sw ( UChar sorb, UInt delta0 ) +{ + UChar rm = getIByte(delta0); + //HChar dis_buf[50]; + + if (epartIsReg(rm)) { + putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) ); + DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm))); + return 1+delta0; + } + + /* E refers to memory */ + { + vassert(0); + /* + UInt pair = disAMode ( cb, sorb, eip0, dis_buf ); + Int tmpa = LOW24(pair); + Int tmpb = newTemp(cb); + uInstr2(cb, LOAD, 2, TempReg, tmpa, TempReg, tmpb); + uInstr2(cb, PUTSEG, 2, TempReg, tmpb, ArchRegS, gregOfRM(rm)); + DIP("movw %s,%s\n", dis_buf,nameSReg(gregOfRM(rm))); + return HI8(pair)+eip0; + */ + } +} + //-- //-- /* Moves of a segment register to Ew. //-- mov Sw, Ew meaning @@ -7459,7 +7562,7 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, } if (r2zero) { - assign(rmode, mkU32((UInt)Irrm_ZERO) ); + assign( rmode, mkU32((UInt)Irrm_ZERO) ); } else { assign( rmode, get_sse_roundingmode() ); } @@ -7487,6 +7590,53 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, goto decode_success; } + /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */ + if (insn[0] == 0x0F && insn[1] == 0xAE + && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) { + + IRTemp t64 = newTemp(Ity_I64); + IRTemp ew = newTemp(Ity_I32); + + modrm = getIByte(delta+2); + vassert(!epartIsReg(modrm)); + vassert(sz == 4); + + addr = disAMode ( &alen, sorb, delta+2, dis_buf ); + delta += 2+alen; + DIP("ldmxcsr %s", dis_buf); + + /* The only thing we observe in %mxcsr is the rounding mode. + Therefore, pass the 32-bit value (SSE native-format control + word) to a clean helper, getting back a 64-bit value, the + lower half of which is the SSEROUND value to store, and the + upper half of which is the emulation-warning token which may + be generated. + */ + /* ULong x86h_check_ldmxcsr ( UInt ); */ + assign( t64, mkIRExprCCall( + Ity_I64, 0/*regparms*/, + "x86h_check_ldmxcsr", + &x86h_check_ldmxcsr, + mkIRExprVec_1( loadLE(Ity_I32, mkexpr(addr)) ) + ) + ); + + //put_sseround( unop(Iop_64to32, mkexpr(t64)) ); + assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) ); + put_emwarn( mkexpr(ew) ); + /* Finally, if an emulation warning was reported, side-exit to + the next insn, reporting the warning, so that Valgrind's + dispatcher sees the warning. */ + stmt( + IRStmt_Exit( + binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)), + Ijk_EmWarn, + IRConst_U32( ((Addr32)guest_eip_bbstart)+delta) + ) + ); + goto decode_success; + } + /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */ if (insn[0] == 0x0F && insn[1] == 0x5F) { vassert(sz == 4); @@ -7957,6 +8107,33 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, goto decode_success; } + /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */ + /* 0F 18 /1 = PREFETCH0 -- with various different hints */ + /* 0F 18 /2 = PREFETCH1 */ + /* 0F 18 /3 = PREFETCH2 */ + if (insn[0] == 0x0F && insn[1] == 0x18 + && !epartIsReg(insn[2]) + && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 3) { + HChar* hintstr = "??"; + + modrm = getIByte(delta+2); + vassert(!epartIsReg(modrm)); + + addr = disAMode ( &alen, sorb, delta+2, dis_buf ); + delta += 2+alen; + + switch (gregOfRM(modrm)) { + case 0: hintstr = "nta"; break; + case 1: hintstr = "t0"; break; + case 2: hintstr = "t1"; break; + case 3: hintstr = "t2"; break; + default: vassert(0); + } + + DIP("prefetch%s %s\n", hintstr, dis_buf); + goto decode_success; + } + /* ***--- this is an MMX class insn introduced in SSE1 ---*** */ /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */ if (insn[0] == 0x0F && insn[1] == 0xF6) { @@ -8122,6 +8299,31 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, goto decode_success; } + /* 0F AE /3 = STMXCSR m32 -- load %mxcsr */ + if (insn[0] == 0x0F && insn[1] == 0xAE + && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 3) { + modrm = getIByte(delta+2); + vassert(sz == 4); + vassert(!epartIsReg(modrm)); + + addr = disAMode ( &alen, sorb, delta+2, dis_buf ); + delta += 2+alen; + + /* Fake up a native SSE mxcsr word. The only thing it depends + on is SSEROUND[1:0], so call a clean helper to cook it up. + */ + /* UInt x86h_create_mxcsr ( UInt sseround ) */ + DIP("stmxcsr %s", dis_buf); + storeLE( mkexpr(addr), + mkIRExprCCall( + Ity_I32, 0/*regp*/, + "x86h_create_mxcsr", &x86h_create_mxcsr, + mkIRExprVec_1( get_fpround() ) + ) + ); + goto decode_success; + } + /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */ if (insn[0] == 0x0F && insn[1] == 0x5C) { vassert(sz == 4); @@ -9867,10 +10069,10 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, delta = dis_mov_Sw_Ew(sorb, sz, delta); break; -//-- case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */ -//-- eip = dis_mov_Ew_Sw(cb, sorb, eip); -//-- break; -//-- + case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */ + delta = dis_mov_Ew_Sw(sorb, delta); + break; + case 0xA0: /* MOV Ob,AL */ sz = 1; /* Fall through ... */ diff --git a/VEX/priv/main/vex_main.c b/VEX/priv/main/vex_main.c index 4fb486092b..fa3e732fee 100644 --- a/VEX/priv/main/vex_main.c +++ b/VEX/priv/main/vex_main.c @@ -456,6 +456,8 @@ HChar* LibVEX_EmWarn_string ( VexEmWarn ew ) return "Selection of non-80-bit x87 FP precision"; case EmWarn_X86_sseExns: return "Unmasking SSE FP exceptionss"; + case EmWarn_X86_fz_daz: + return "Setting MXCSR.FZ or MXCSR.DAZ"; default: vpanic("LibVEX_EmWarn_string: unknown warning"); } diff --git a/VEX/priv/main/vex_util.c b/VEX/priv/main/vex_util.c index d45b11cf8e..9fb32afc0e 100644 --- a/VEX/priv/main/vex_util.c +++ b/VEX/priv/main/vex_util.c @@ -124,7 +124,7 @@ void* LibVEX_Alloc ( Int nbytes ) void LibVEX_ClearTemporary ( Bool verb ) { - vassert(vex_initdone); + /* vassert(vex_initdone); */ /* causes infinite assert loops */ temporary_bytes_allocd_TOT += (ULong)temporary_bytes_allocd; temporary_count_allocs_TOT += (ULong)temporary_count_allocs; if (verb) { diff --git a/VEX/pub/libvex_emwarn.h b/VEX/pub/libvex_emwarn.h index 9b1c6ac0e7..0da0db0195 100644 --- a/VEX/pub/libvex_emwarn.h +++ b/VEX/pub/libvex_emwarn.h @@ -67,6 +67,9 @@ typedef /* unmasking SSE FP exceptions is not supported */ EmWarn_X86_sseExns, + /* setting mxcsr.fz or mxcsr.daz is not supported */ + EmWarn_X86_fz_daz, + EmWarn_NUMBER } VexEmWarn; diff --git a/VEX/pub/libvex_guest_x86.h b/VEX/pub/libvex_guest_x86.h index c80fafd3b1..22011945a0 100644 --- a/VEX/pub/libvex_guest_x86.h +++ b/VEX/pub/libvex_guest_x86.h @@ -94,14 +94,33 @@ FPROUND[1:0] is the FPU's notional rounding mode, encoded as per the IRRoundingMode type (see libvex_ir.h). This just happens to be the Intel encoding. Note carefully, the rounding mode is only - observed on float-to-int conversions, and not for float-to-float - operations. + observed on float-to-int conversions, and on float-to-float + rounding, but not for general float-to-float operations, which are + always rounded-to-nearest. + + Loads/stores of the FPU control word are faked accordingly -- on + loads, everything except the rounding mode is ignored, and on + stores, you get a vanilla control world (0x037F) with the rounding + mode patched in. Hence the only values you can get are 0x037F, + 0x077F, 0x0B7F or 0x0F7F. Vex will emit an emulation warning if + you try and load a control word which either (1) unmasks FP + exceptions, or (2) changes the default (80-bit) precision. FC3210 contains the C3, C2, C1 and C0 bits in the same place they are in the FPU's status word. (bits 14, 10, 9, 8 respectively). All other bits should be zero. The relevant mask to select just those bits is 0x4700. To select C3, C2 and C0 only, the mask is - 0x4500. */ + 0x4500. + + SSEROUND[1:0] is the SSE unit's notional rounding mode, encoded as + per the IRRoundingMode type. As with the FPU control word, the + rounding mode is the only part of %MXCSR that Vex observes. On + storing %MXCSR, you will get a vanilla word (0x1F80) with the + rounding mode patched in. Hence the only values you will get are + 0x1F80, 0x3F80, 0x5F80 or 0x7F80. Vex will emit an emulation + warning if you try and load a control word which either (1) unmasks + any exceptions, (2) sets FZ (flush-to-zero) to 1, or (3) sets DAZ + (denormals-are-zeroes) to 1. */ typedef struct {