From: Julian Seward Date: Sat, 11 Sep 2004 09:30:24 +0000 (+0000) Subject: Fill in many x86 integer and FP cases, enough to get konqueror X-Git-Tag: svn/VALGRIND_3_0_1^2~1079 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=069fbcb6388e2d9c2f1f5376fc2817e70bff5bed;p=thirdparty%2Fvalgrind.git Fill in many x86 integer and FP cases, enough to get konqueror running. This also involves adding some iropt const-folding rules. git-svn-id: svn://svn.valgrind.org/vex/trunk@255 --- diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index fda5c61fce..6b42c97241 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -9,9 +9,10 @@ /* TODO: SBB reg with itself is Iop_Neg* used? - xadd %reg,%reg fix MOVAPS fix (vg_to_ucode rev 1.143) check flag settings for cmpxchg + FUCOMI(P): what happens to A and S flags? Currently are forced + to zero. */ /* Translates x86 code to IR. */ @@ -3033,7 +3034,7 @@ UInt dis_imul_I_E_G ( UChar sorb, UInt delta, Int litsize ) { - Int d32; + Int d32, alen; Char dis_buf[50]; UChar rm = getIByte(delta); IRType ty = szToITy(size); @@ -3046,13 +3047,9 @@ UInt dis_imul_I_E_G ( UChar sorb, assign(te, getIReg(size, eregOfRM(rm))); delta++; } else { - vassert(0); -#if 0 - UInt pair = disAMode ( cb, sorb, eip, dis_buf ); - ta = LOW24(pair); - uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te); - eip += HI8(pair); -#endif + IRTemp addr = disAMode( &alen, sorb, delta, dis_buf ); + assign(te, loadLE(ty, mkexpr(addr))); + delta += alen; } d32 = getSDisp(litsize,delta); delta += litsize; @@ -3317,7 +3314,7 @@ void fp_do_op_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf, */ static void fp_do_oprev_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf, - IROp op, Bool dbl ) + IROp op, Bool dbl ) { DIP("f%s%c %s", op_txt, dbl?'l':'s', dis_buf); if (dbl) { @@ -3357,7 +3354,7 @@ void fp_do_op_ST_ST ( UChar* op_txt, IROp op, UInt st_src, UInt st_dst, */ static void fp_do_oprev_ST_ST ( UChar* op_txt, IROp op, UInt st_src, UInt st_dst, - Bool pop_after ) + Bool pop_after ) { DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"", st_src, st_dst ); put_ST_UNCHECKED( @@ -3524,23 +3521,28 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0))); break; - case 0xE5: { /* FXAM */ - /* This is an interesting one. It examines %st(0), - regardless of whether the tag says it's empty or not. - Here, just pass both the tag (in our format) and the - value (as a double, actually a ULong) to a helper - function. */ - IRExpr** args; - DIP("fxam"); - args = LibVEX_Alloc(3 * sizeof(IRExpr*)); - args[0] = unop(Iop_8Uto32, get_ST_TAG(0)); - args[1] = get_ST_UNCHECKED_as_ULong(0); - args[2] = NULL; - put_C3210(IRExpr_CCall("calculate_FXAM", Ity_I32, args)); - break; - } - - case 0xE8: /* FLD1 */ + case 0xE1: /* FABS */ + DIP("fabs\n"); + put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0))); + break; + + case 0xE5: { /* FXAM */ + /* This is an interesting one. It examines %st(0), + regardless of whether the tag says it's empty or not. + Here, just pass both the tag (in our format) and the + value (as a double, actually a ULong) to a helper + function. */ + IRExpr** args; + DIP("fxam"); + args = LibVEX_Alloc(3 * sizeof(IRExpr*)); + args[0] = unop(Iop_8Uto32, get_ST_TAG(0)); + args[1] = get_ST_UNCHECKED_as_ULong(0); + args[2] = NULL; + put_C3210(IRExpr_CCall("calculate_FXAM", Ity_I32, args)); + break; + } + + case 0xE8: /* FLD1 */ DIP("fld1"); fp_push(); put_ST(0, IRExpr_Const(IRConst_F64(1.0))); @@ -3755,6 +3757,21 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True ); break; + case 3: /* FCOMP double-real */ + DIP("fcomp %s\n", dis_buf); + /* This forces C1 to zero, which isn't right. */ + put_C3210( + binop( Iop_And32, + binop(Iop_Shl32, + binop(Iop_CmpF64, + get_ST(0), + loadLE(Ity_F64,mkexpr(addr))), + mkU8(8)), + mkU32(0x4500) + )); + fp_pop(); + break; + case 4: /* FSUB double-real */ fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True ); break; @@ -3767,6 +3784,10 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True ); break; + case 7: /* FDIVR double-real */ + fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True ); + break; + default: vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm)); vex_printf("first_opcode == 0xDC\n"); @@ -3939,6 +3960,14 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) switch (gregOfRM(modrm)) { + case 0: /* FILD m16int */ + DIP("fildw %s\n", dis_buf); + fp_push(); + put_ST(0, unop(Iop_I32toF64, + unop(Iop_16Sto32, + loadLE(Ity_I16, mkexpr(addr))))); + break; + case 3: /* FISTP m16 */ DIP("fistps %s", dis_buf); storeLE( mkexpr(addr), @@ -3987,6 +4016,23 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) ))); break; + case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */ + r_dst = (UInt)modrm - 0xE8; + DIP("fucomip %%st(0),%%st(%d)\n", r_dst); + /* This is a bit of a hack (and isn't really right). + It sets Z,P,C,O correctly, but forces A and S to + zero, whereas the Intel documentation implies A and + S are unchanged. */ + stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) )); + stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) )); + stmt( IRStmt_Put( OFFB_CC_SRC, + binop( Iop_And32, + binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)), + mkU32(0x45) + ))); + fp_pop(); + break; + default: goto decode_fail; } @@ -4869,7 +4915,7 @@ UInt dis_cmov_E_G ( UChar sorb, UChar dis_buf[50]; Int len; - IRType ty = szToITy(sz); + IRType ty = szToITy(sz); IRTemp tmps = newTemp(ty); IRTemp tmpd = newTemp(ty); @@ -4910,44 +4956,48 @@ UInt dis_cmov_E_G ( UChar sorb, } -//-- static -//-- Addr dis_xadd_G_E ( UCodeBlock* cb, -//-- UChar sorb, -//-- Int sz, -//-- Addr eip0 ) -//-- { -//-- UChar rm = getUChar(eip0); -//-- UChar dis_buf[50]; -//-- -//-- Int tmpd = newTemp(cb); -//-- Int tmpt = newTemp(cb); -//-- -//-- if (epartIsReg(rm)) { -//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd); -//-- uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt); -//-- uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt); -//-- setFlagsFromUOpcode(cb, ADD); -//-- uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm)); -//-- uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm)); -//-- DIP("xadd%c %s, %s\n", -//-- nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm))); -//-- return 1+eip0; -//-- } else { -//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf ); -//-- Int tmpa = LOW24(pair); -//-- uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpd); -//-- uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt); -//-- uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt); -//-- setFlagsFromUOpcode(cb, ADD); -//-- uInstr2(cb, STORE, sz, TempReg, tmpt, TempReg, tmpa); -//-- uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm)); -//-- DIP("xadd%c %s, %s\n", -//-- nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf); -//-- return HI8(pair)+eip0; -//-- } -//-- } -//-- -//-- +static +UInt dis_xadd_G_E ( UChar sorb, Int sz, UInt delta0 ) +{ + Int len; + UChar rm = getIByte(delta0); + UChar dis_buf[50]; + + // Int tmpd = newTemp(cb); + //Int tmpt = newTemp(cb); + + IRType ty = szToITy(sz); + IRTemp tmpd = newTemp(ty); + IRTemp tmpt0 = newTemp(ty); + IRTemp tmpt1 = newTemp(ty); + + if (epartIsReg(rm)) { + vassert(0); +#if 0 + uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd); + uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt); + uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt); + setFlagsFromUOpcode(cb, ADD); + uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm)); + uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm)); + DIP("xadd%c %s, %s\n", + nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm))); + return 1+eip0; +#endif + } else { + IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf ); + assign( tmpd, loadLE(ty, mkexpr(addr)) ); + assign( tmpt0, getIReg(sz, gregOfRM(rm)) ); + setFlags_ADD_SUB( Iop_Add8, tmpt0, tmpd, ty ); + assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) ); + storeLE( mkexpr(addr), mkexpr(tmpt1) ); + putIReg(sz, gregOfRM(rm), mkexpr(tmpd)); + DIP("xadd%c %s, %s\n", + nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf); + return len+delta0; + } +} + //-- /* Moves of Ew into a segment register. //-- mov Ew, Sw meaning //-- mov reg-or-mem, reg @@ -7835,7 +7885,7 @@ static UInt disInstr ( UInt delta, Bool* isEnd ) correctly pushes the old value. */ vassert(sz == 2 || sz == 4); ty = sz==2 ? Ity_I16 : Ity_I32; - t1 = newTemp(ty); t2 = newTemp(ty); + t1 = newTemp(ty); t2 = newTemp(Ity_I32); assign(t1, getIReg(sz, opc-0x50)); assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz))); putIReg(4, R_ESP, mkexpr(t2) ); @@ -7954,10 +8004,10 @@ static UInt disInstr ( UInt delta, Bool* isEnd ) //-- dis_string_op( cb, dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb ); //-- break; //-- -//-- case 0xAA: /* STOS, no REP prefix */ + case 0xAA: /* STOS, no REP prefix */ //-- case 0xAB: -//-- dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb ); -//-- break; + dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb ); + break; //-- //-- case 0xAC: /* LODS, no REP prefix */ //-- case 0xAD: @@ -8653,15 +8703,15 @@ static UInt disInstr ( UInt delta, Bool* isEnd ) "%cl", False ); break; -//-- /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */ +//-- /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */ //-- //-- case 0xC0: /* XADD Gb,Eb */ //-- eip = dis_xadd_G_E ( cb, sorb, 1, eip ); //-- break; -//-- case 0xC1: /* XADD Gv,Ev */ -//-- eip = dis_xadd_G_E ( cb, sorb, sz, eip ); -//-- break; -//-- + case 0xC1: /* XADD Gv,Ev */ + delta = dis_xadd_G_E ( sorb, sz, delta ); + break; + //-- /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */ //-- //-- case 0x0D: /* PREFETCH / PREFETCHW - 3Dnow!ery*/ diff --git a/VEX/priv/host-x86/hdefs.c b/VEX/priv/host-x86/hdefs.c index 37707b2cd6..b7b89fa9af 100644 --- a/VEX/priv/host-x86/hdefs.c +++ b/VEX/priv/host-x86/hdefs.c @@ -415,7 +415,8 @@ Char* showX86FpOp ( X86FpOp op ) { case Xfp_MUL: return "mul"; case Xfp_DIV: return "div"; case Xfp_SQRT: return "sqrt"; - case Xfp_NEGATE: return "chs"; + case Xfp_NEG: return "chs"; + case Xfp_ABS: return "abs"; case Xfp_MOV: return "mov"; case Xfp_SIN: return "sin"; case Xfp_COS: return "cos"; @@ -1258,7 +1259,8 @@ static UChar* do_fld_st ( UChar* p, Int i ) static UChar* do_fop1_st ( UChar* p, X86FpOp op ) { switch (op) { - case Xfp_NEGATE: *p++ = 0xD9; *p++ = 0xE0; break; + case Xfp_NEG: *p++ = 0xD9; *p++ = 0xE0; break; + case Xfp_ABS: *p++ = 0xD9; *p++ = 0xE1; break; case Xfp_SQRT: *p++ = 0xD9; *p++ = 0xFA; break; case Xfp_ROUND: *p++ = 0xD9; *p++ = 0xFC; break; case Xfp_SIN: *p++ = 0xD9; *p++ = 0xFE; break; diff --git a/VEX/priv/host-x86/hdefs.h b/VEX/priv/host-x86/hdefs.h index f40771576d..5e163e8ea4 100644 --- a/VEX/priv/host-x86/hdefs.h +++ b/VEX/priv/host-x86/hdefs.h @@ -249,7 +249,7 @@ typedef /* Binary */ Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV, Xfp_ATANYX, /* Unary */ - Xfp_SQRT, Xfp_NEGATE, Xfp_MOV, Xfp_SIN, Xfp_COS, + Xfp_SQRT, Xfp_ABS, Xfp_NEG, Xfp_MOV, Xfp_SIN, Xfp_COS, Xfp_ROUND } X86FpOp; diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index 713cc9ba39..9d9c29a083 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -1669,7 +1669,8 @@ static HReg iselDblExpr ( ISelEnv* env, IRExpr* e ) if (e->tag == Iex_Unop) { X86FpOp fpop = Xfp_INVALID; switch (e->Iex.Unop.op) { - case Iop_NegF64: fpop = Xfp_NEGATE; break; + case Iop_NegF64: fpop = Xfp_NEG; break; + case Iop_AbsF64: fpop = Xfp_ABS; break; case Iop_SqrtF64: fpop = Xfp_SQRT; break; case Iop_SinF64: fpop = Xfp_SIN; break; case Iop_CosF64: fpop = Xfp_COS; break; diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index cdb019238a..a930d70076 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -136,6 +136,7 @@ void ppIROp ( IROp op ) case Iop_DivF64: vex_printf("DivF64"); return; case Iop_CmpF64: vex_printf("CmpF64"); return; case Iop_NegF64: vex_printf("NegF64"); return; + case Iop_AbsF64: vex_printf("AbsF64"); return; case Iop_SqrtF64: vex_printf("SqrtF64"); return; case Iop_SinF64: vex_printf("SinF64"); return; case Iop_CosF64: vex_printf("CosF64"); return; @@ -637,7 +638,8 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) BINARY(Ity_F64,Ity_F64,Ity_F64); case Iop_CmpF64: BINARY(Ity_I32,Ity_F64,Ity_F64); - case Iop_NegF64: case Iop_SqrtF64: case Iop_SinF64: case Iop_CosF64: + case Iop_NegF64: case Iop_AbsF64: case Iop_SqrtF64: + case Iop_SinF64: case Iop_CosF64: UNARY(Ity_F64,Ity_F64); case Iop_I32toF64: UNARY(Ity_F64,Ity_I32); diff --git a/VEX/priv/ir/iropt.c b/VEX/priv/ir/iropt.c index 807fcaecee..59ebba9c58 100644 --- a/VEX/priv/ir/iropt.c +++ b/VEX/priv/ir/iropt.c @@ -317,6 +317,13 @@ static IRExpr* fold_Expr ( IRExpr* e ) if (e->tag == Iex_Unop && e->Iex.Unop.arg->tag == Iex_Const) { switch (e->Iex.Unop.op) { + case Iop_8Sto32: { + /* signed */ Int s32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U8; + s32 <<= 24; + s32 >>= 24; + e2 = IRExpr_Const(IRConst_U32((UInt)s32)); + break; + } case Iop_8Uto32: e2 = IRExpr_Const(IRConst_U32( 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8)); @@ -325,6 +332,10 @@ static IRExpr* fold_Expr ( IRExpr* e ) e2 = IRExpr_Const(IRConst_U32( 0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U16)); break; + case Iop_Not32: + e2 = IRExpr_Const(IRConst_U32( + ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U32))); + break; default: goto unhandled; } @@ -336,6 +347,11 @@ static IRExpr* fold_Expr ( IRExpr* e ) && e->Iex.Binop.arg2->tag == Iex_Const) { /* cases where both args are consts */ switch (e->Iex.Binop.op) { + case Iop_Xor8: + e2 = IRExpr_Const(IRConst_U8(0xFF & + (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8 + ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))); + break; case Iop_And8: e2 = IRExpr_Const(IRConst_U8(0xFF & (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8 @@ -356,6 +372,11 @@ static IRExpr* fold_Expr ( IRExpr* e ) (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))); break; + case Iop_Xor32: + e2 = IRExpr_Const(IRConst_U32( + (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32 + ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))); + break; case Iop_And32: e2 = IRExpr_Const(IRConst_U32( (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32 @@ -414,8 +435,6 @@ static IRExpr* fold_Expr ( IRExpr* e ) | ((ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)) )); break; - case Iop_MullS32: - break; default: goto unhandled; } @@ -460,9 +479,16 @@ static IRExpr* fold_Expr ( IRExpr* e ) return e2; unhandled: +# if 0 vex_printf("\n\n"); ppIRExpr(e); vpanic("fold_Expr: no rule for the above"); +# else + vex_printf("vex iropt: fold_Expr: no rule for: "); + ppIRExpr(e); + vex_printf("\n"); + return e2; +# endif } diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index ce39516605..bda1794406 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -164,13 +164,13 @@ typedef Iop_AtanYXF64, /* Unary operations */ - Iop_NegF64, Iop_SqrtF64, Iop_SinF64, Iop_CosF64, + Iop_NegF64, Iop_AbsF64, Iop_SqrtF64, Iop_SinF64, Iop_CosF64, /* Comparison, yielding GT/LT/EQ/UN(ordered), as per the following: - 0x85 Unordered + 0x45 Unordered 0x01 LT 0x00 GT - 0x80 EQ + 0x40 EQ This just happens to be the Intel encoding. The values are recorded in the type IRCmpF64Result. */