From: Julian Seward Date: Sun, 15 Aug 2004 03:12:41 +0000 (+0000) Subject: More FPU stuff. X-Git-Tag: svn/VALGRIND_3_0_1^2~1166 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6101194d5fefe213673b249f8acc6e56c64c7c8e;p=thirdparty%2Fvalgrind.git More FPU stuff. git-svn-id: svn://svn.valgrind.org/vex/trunk@168 --- diff --git a/VEX/hacked104/vg_translate.c b/VEX/hacked104/vg_translate.c index b62d691d2c..13f7fb52fe 100644 --- a/VEX/hacked104/vg_translate.c +++ b/VEX/hacked104/vg_translate.c @@ -3122,7 +3122,7 @@ void VG_(translate) ( ThreadState* tst, Bool debugging_translation; static Int v0thresh = 940; - static Int v2thresh = 940; + static Int v2thresh = 940000; TranslateResult tres; static Bool vex_init_done = False; diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 1b15922143..6848a29b00 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -3127,7 +3127,7 @@ static IRExpr* get_ST ( Int i ) /* Adjust FTOP downwards by one register. */ -static IRStmt* do_push ( void ) +static IRStmt* fp_push ( void ) { return put_ftop( @@ -3137,13 +3137,37 @@ static IRStmt* do_push ( void ) ); } +/* Adjust FTOP upwards by one register. */ + +static IRStmt* fp_pop ( void ) +{ + return + put_ftop( + binop(Iop_And32, + binop(Iop_Add32, get_ftop(), mkU32(1)), + mkU32(7)) + ); +} + +static +void fp_do_op_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf, + IROp op, Bool dbl ) +{ + DIP("f%s%c %s", op_txt, dbl?'l':'s', dis_buf); + if (dbl) { + stmt( put_ST(0, binop(op, get_ST(0), loadLE(Ity_F64,mkexpr(addr))))); + } else { + vassert(0); + } +} + static UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) { - Int len; - UInt src; - Char dis_buf[32]; + Int len; + UInt r_src, r_dst; + Char dis_buf[32]; IRTemp t1; /* On entry, delta points at the second byte of the insn (the modrm @@ -3166,14 +3190,20 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) delta++; switch (modrm) { case 0xC0 ... 0xC7: /* FLD %st(?) */ - src = (UInt)modrm - 0xC0; - DIP("fld %%st(%d)\n", src); + r_src = (UInt)modrm - 0xC0; + DIP("fld %%st(%d)\n", r_src); t1 = newTemp(Ity_F64); - assign(t1, get_ST(src)); - stmt( do_push() ); + assign(t1, get_ST(r_src)); + stmt( fp_push() ); stmt( put_ST(0, mkexpr(t1)) ); break; + case 0xEE: /* FLDZ */ + DIP("fldz"); + stmt( fp_push() ); + stmt( put_ST(0, IRExpr_Const(IRConst_F64(0.0))) ); + break; + default: goto decode_fail; } @@ -3221,7 +3251,28 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */ else if (first_opcode == 0xDC) { - goto decode_fail; + 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: /* FADD double-real */ + fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True ); + break; + + default: + vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm)); + vex_printf("first_opcode == 0xDC\n"); + goto decode_fail; + } + + } else { + goto decode_fail; + } } /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */ @@ -3239,7 +3290,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) case 0: /* FLD double-real */ DIP("fldD %s\n", dis_buf); - stmt( do_push() ); + stmt( fp_push() ); stmt( put_ST(0, IRExpr_LDle(Ity_F64, mkexpr(addr))) ); break; @@ -3254,19 +3305,12 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) } setDMem(a_addr,vd_addr); break; - +#endif case 3: /* FSTP double-real */ - IFDB( if (dis) printf("\tfstpD\t%s\n",t_addr); ) - if (!fp_is_empty_tag(fp_get_tag_ST(0))) { - vd_addr = fp_pop(); - } else { - vd_addr = fp_pop(); /* then throw away result */ - vd_addr = NAN; - fp_set_stack_underflow(); - } - setDMem(a_addr,vd_addr); + DIP("fstpD %s", dis_buf); + storeLE(mkexpr(addr), get_ST(0)); + stmt( fp_pop() ); break; -#endif default: vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm)); @@ -3274,7 +3318,17 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) goto decode_fail; } } else { - goto decode_fail; + delta++; + switch (modrm) { + case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */ + r_dst = (UInt)modrm - 0xD8; + DIP("fstp %%st(0),%%st(%d)\n", r_dst); + stmt( put_ST(r_dst, get_ST(0)) ); + stmt( fp_pop() ); + break; + default: + goto decode_fail; + } } } diff --git a/VEX/priv/host-x86/hdefs.c b/VEX/priv/host-x86/hdefs.c index 9ae499ffbc..451bf9bff6 100644 --- a/VEX/priv/host-x86/hdefs.c +++ b/VEX/priv/host-x86/hdefs.c @@ -1028,6 +1028,8 @@ static Bool fits8bits ( UInt w32 ) greg, d32(ereg) | ereg != ESP = 10 greg ereg, d32 + greg, d8(%esp) = 01 greg 100, 0x24, d8 + ----------------------------------------------- greg, d8(base,index,scale) @@ -1058,6 +1060,13 @@ static UChar* doAMode_M ( UChar* p, HReg greg, X86AMode* am ) p = emit32(p, am->Xam.IR.imm); return p; } + if (am->Xam.IR.reg == hregX86_ESP() + && fits8bits(am->Xam.IR.imm)) { + *p++ = mkModRegRM(1, iregNo(greg), 4); + *p++ = 0x24; + *p++ = am->Xam.IR.imm & 0xFF; + return p; + } ppX86AMode(am); vpanic("doAMode_M: can't emit amode IR"); /*NOTREACHED*/ @@ -1127,6 +1136,7 @@ static UChar* do_fop_st ( UChar* p, X86FpOp op, Int i ) # define fake(_n) mkHReg((_n), HRcInt, False) Int subopc; switch (op) { + case Xfp_ADD: subopc = 0; break; case Xfp_MUL: subopc = 1; break; default: vpanic("do_fop_st: unknown op"); } @@ -1411,7 +1421,11 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) *p++ = 0xFF; p = doAMode_M(p, fake(6), i->Xin.Push.src->Xrmi.Mem.am); goto done; - default: + case Xrmi_Imm: + *p++ = 0x68; + p = emit32(p, i->Xin.Push.src->Xrmi.Imm.imm32); + goto done; + default: goto bad; } diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index 622241e970..a653da2071 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -92,6 +92,10 @@ static Bool matchWrk ( MatchInfo* mi, IRExpr* p/*attern*/, IRExpr* e/*xpr*/ ) ? (p->Iex.Const.con->Ico.U64 == e->Iex.Const.con->Ico.U64) : False; + case Ico_F64: return e->Iex.Const.con->tag==Ico_F64 + ? (p->Iex.Const.con->Ico.F64 + == e->Iex.Const.con->Ico.F64) + : False; } vpanic("matchIRExpr.Iex_Const"); /*NOTREACHED*/ @@ -967,6 +971,24 @@ static HReg iselDblExpr ( ISelEnv* env, IRExpr* e ) return lookupIRTemp(env, e->Iex.Tmp.tmp); } + if (e->tag == Iex_Const) { + union { UInt i64[2]; Double f64; } u; + HReg freg = newVRegF(env); + vassert(sizeof(u) == 8); + vassert(sizeof(u.i64) == 8); + vassert(sizeof(u.f64) == 8); + vassert(e->Iex.Const.con->tag == Ico_F64); + u.f64 = e->Iex.Const.con->Ico.F64; + addInstr(env, X86Instr_Push(X86RMI_Imm(u.i64[1]))); + addInstr(env, X86Instr_Push(X86RMI_Imm(u.i64[0]))); + addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, freg, + X86AMode_IR(0, hregX86_ESP()))); + addInstr(env, X86Instr_Alu32R(Xalu_ADD, + X86RMI_Imm(8), + hregX86_ESP())); + return freg; + } + if (e->tag == Iex_LDle) { X86AMode* am; HReg res = newVRegF(env); @@ -991,6 +1013,7 @@ static HReg iselDblExpr ( ISelEnv* env, IRExpr* e ) if (e->tag == Iex_Binop) { X86FpOp fpop = Xfp_INVALID; switch (e->Iex.Binop.op) { + case Iop_AddF64: fpop = Xfp_ADD; break; case Iop_MulF64: fpop = Xfp_MUL; break; default: break; } @@ -1035,22 +1058,27 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) /* --------- STORE --------- */ case Ist_STle: { + X86AMode* am; IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.STle.addr); IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.STle.data); vassert(tya == Ity_I32); + am = iselIntExpr_AMode(env, stmt->Ist.STle.addr); if (tyd == Ity_I32) { - X86AMode* am = iselIntExpr_AMode(env, stmt->Ist.STle.addr); - X86RI* ri = iselIntExpr_RI(env, stmt->Ist.STle.data); + X86RI* ri = iselIntExpr_RI(env, stmt->Ist.STle.data); addInstr(env, X86Instr_Alu32M(Xalu_MOV,ri,am)); return; } if (tyd == Ity_I8 || tyd == Ity_I16) { - X86AMode* am = iselIntExpr_AMode(env, stmt->Ist.STle.addr); - HReg r = iselIntExpr_R(env, stmt->Ist.STle.data); + HReg r = iselIntExpr_R(env, stmt->Ist.STle.data); addInstr(env, X86Instr_Store(tyd==Ity_I8 ? 1 : 2, 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; + } break; } diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index 2ce5bd97e7..f6862ff040 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -40,6 +40,7 @@ void ppIRConst ( IRConst* con ) case Ico_U16: vex_printf( "0x%x", (UInt)(con->Ico.U16)); break; case Ico_U32: vex_printf( "0x%x", (UInt)(con->Ico.U32)); break; case Ico_U64: vex_printf( "0x%llx", (ULong)(con->Ico.U64)); break; + case Ico_F64: vex_printf("(f64 value)"); break; default: vpanic("ppIRConst"); } } @@ -117,6 +118,7 @@ void ppIROp ( IROp op ) case Iop_64to32: vex_printf("64to32"); return; case Iop_32HLto64: vex_printf("32HLto64"); return; + case Iop_AddF64: vex_printf("AddF64"); return; case Iop_MulF64: vex_printf("MulF64"); return; case Iop_I64toF64: vex_printf("I64toF64"); return; @@ -321,7 +323,13 @@ IRConst* IRConst_U64 ( ULong u64 ) c->Ico.U64 = u64; return c; } - +IRConst* IRConst_F64 ( Double f64 ) +{ + IRConst* c = LibVEX_Alloc(sizeof(IRConst)); + c->tag = Ico_F64; + c->Ico.F64 = f64; + return c; +} /* Constructors -- IRExpr */ @@ -555,7 +563,8 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) case Iop_32Sto64: UNARY(Ity_I64,Ity_I32); case Iop_32to8: UNARY(Ity_I8,Ity_I32); - case Iop_MulF64: BINARY(Ity_F64,Ity_F64,Ity_F64); + case Iop_AddF64: case Iop_MulF64: + BINARY(Ity_F64,Ity_F64,Ity_F64); case Iop_I64toF64: UNARY(Ity_F64,Ity_I64); default: @@ -620,6 +629,7 @@ IRType typeOfIRConst ( IRConst* con ) case Ico_U16: return Ity_I16; case Ico_U32: return Ity_I32; case Ico_U64: return Ity_I64; + case Ico_F64: return Ity_F64; default: vpanic("typeOfIRConst"); } } diff --git a/VEX/pub/libvex_basictypes.h b/VEX/pub/libvex_basictypes.h index bd0860ac9a..9505b49149 100644 --- a/VEX/pub/libvex_basictypes.h +++ b/VEX/pub/libvex_basictypes.h @@ -21,6 +21,9 @@ typedef signed int Int; typedef unsigned long long int ULong; typedef signed long long int Long; +typedef float Float; /* IEEE754 single-precision (32-bit) value */ +typedef double Double; /* IEEE754 double-precision (64-bit) value */ + typedef unsigned char Bool; #define True ((Bool)1) #define False ((Bool)0) diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index 880cfb8e9c..cdcb9fc01d 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -33,7 +33,7 @@ extern void ppIRType ( IRType ); typedef enum { Ico_U8=0x12000, - Ico_U16, Ico_U32, Ico_U64 } + Ico_U16, Ico_U32, Ico_U64, Ico_F64 } IRConstTag; typedef @@ -44,6 +44,7 @@ typedef UShort U16; UInt U32; ULong U64; + Double F64; } Ico; } IRConst; @@ -52,6 +53,7 @@ extern IRConst* IRConst_U8 ( UChar ); extern IRConst* IRConst_U16 ( UShort ); extern IRConst* IRConst_U32 ( UInt ); extern IRConst* IRConst_U64 ( ULong ); +extern IRConst* IRConst_F64 ( Double ); extern void ppIRConst ( IRConst* );