From: Julian Seward Date: Tue, 13 Jul 2004 18:42:17 +0000 (+0000) Subject: x86toIR: some multiply stuff X-Git-Tag: svn/VALGRIND_3_0_1^2~1255 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7e20fc8cb9525a2826d42f4996775aeee929b5e8;p=thirdparty%2Fvalgrind.git x86toIR: some multiply stuff git-svn-id: svn://svn.valgrind.org/vex/trunk@79 --- diff --git a/VEX/priv/guest-x86/x86guest_defs.h b/VEX/priv/guest-x86/x86guest_defs.h index ef781e9eb9..55cf447789 100644 --- a/VEX/priv/guest-x86/x86guest_defs.h +++ b/VEX/priv/guest-x86/x86guest_defs.h @@ -43,10 +43,6 @@ IRBB* bbToIR_X86Instr ( UChar* x86code, enum { CC_OP_COPY, /* nothing to do -- ccs are in CC_SRC and up to date */ - CC_OP_MULB, /* modify all flags, C, O = (CC_SRC != 0) */ - CC_OP_MULW, - CC_OP_MULL, - CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ CC_OP_ADDW, CC_OP_ADDL, @@ -83,7 +79,19 @@ enum { CC_OP_SARW, /* where res' is like res but shifted one bit less */ CC_OP_SARL, - CC_OP_NB, + CC_OP_MULB, /* modify all flags, CC_DST = one arg */ + CC_OP_MULW, /* CC_SRC = the other arg */ + CC_OP_MULL, + + CC_OP_MULLSB, /* modify all flags, CC_DST = one arg */ + CC_OP_MULLSW, /* CC_SRC = the other arg */ + CC_OP_MULLSL, + + CC_OP_MULLUB, /* modify all flags, CC_DST = one arg */ + CC_OP_MULLUW, /* CC_SRC = the other arg */ + CC_OP_MULLUL, + + CC_OP_NUMBER }; /* called from generated code to evaluate the flags-thunk. */ diff --git a/VEX/priv/guest-x86/x86toIR.c b/VEX/priv/guest-x86/x86toIR.c index 272c2a919d..e1a8603773 100644 --- a/VEX/priv/guest-x86/x86toIR.c +++ b/VEX/priv/guest-x86/x86toIR.c @@ -472,6 +472,34 @@ static void setFlags_INC_DEC ( Bool inc, IRTemp dst, IRType ty ) } +/* For multiplies, just remember the two operands and a + description of what kind of multiply. */ + +static +void setFlags_MUL ( IRType ty, IRTemp src1, IRTemp src2, UInt base_op ) +{ + switch (ty) { + case Ity_I8: + stmt( IRStmt_Put( NULL, OFFB_CC_OP, mkU32(base_op+0) ) ); + stmt( IRStmt_Put( NULL, OFFB_CC_SRC, unop(Iop_8Uto32,mkexpr(src1)) ) ); + stmt( IRStmt_Put( NULL, OFFB_CC_DST, unop(Iop_8Uto32,mkexpr(src2)) ) ); + break; + case Ity_I16: + stmt( IRStmt_Put( NULL, OFFB_CC_OP, mkU32(base_op+1) ) ); + stmt( IRStmt_Put( NULL, OFFB_CC_SRC, unop(Iop_16Uto32,mkexpr(src1)) ) ); + stmt( IRStmt_Put( NULL, OFFB_CC_DST, unop(Iop_16Uto32,mkexpr(src2)) ) ); + break; + case Ity_I32: + stmt( IRStmt_Put( NULL, OFFB_CC_OP, mkU32(base_op+2) ) ); + stmt( IRStmt_Put( NULL, OFFB_CC_SRC, mkexpr(src1) ) ); + stmt( IRStmt_Put( NULL, OFFB_CC_DST, mkexpr(src2) ) ); + break; + default: + vpanic("setFlags_MUL(x86)"); + } +} + + /* Condition codes, using the Intel encoding. */ typedef @@ -2081,15 +2109,18 @@ UInt dis_Grp2 ( UChar sorb, //-- //-- # undef MODIFY_t2_AND_SET_CARRY_FLAG //-- } -//-- -//-- -//-- -//-- /* Generate ucode to multiply the value in EAX/AX/AL by the register -//-- specified by the ereg of modrm, and park the result in -//-- EDX:EAX/DX:AX/AX. */ -//-- static void codegen_mul_A_D_Reg ( UCodeBlock* cb, Int sz, -//-- UChar modrm, Bool signed_multiply ) -//-- { + + + +/* Generate ucode to multiply the value in EAX/AX/AL by the register + specified by the ereg of modrm, and park the result in + EDX:EAX/DX:AX/AX. + + Viz, signed/unsigned widening multiply. +*/ +static void codegen_mul_A_D_Reg ( Int sz, + UChar modrm, Bool signed_multiply ) +{ //-- Int helper = signed_multiply //-- ? //-- (sz==1 ? VGOFF_(helper_imul_8_16) @@ -2099,10 +2130,35 @@ UInt dis_Grp2 ( UChar sorb, //-- (sz==1 ? VGOFF_(helper_mul_8_16) //-- : (sz==2 ? VGOFF_(helper_mul_16_32) //-- : VGOFF_(helper_mul_32_64))); -//-- Int t1 = newTemp(cb); -//-- Int ta = newTemp(cb); + IRType ty = szToITy(sz); + IRTemp t1 = newTemp(ty); + IRTemp t2 = newTemp(ty); + IRTemp tr = newTemp(ty); + //-- uInstr0(cb, CALLM_S, 0); //-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1); + assign( t1, getIReg(sz, eregOfRM(modrm)) ); + assign( t2, getIReg(sz, R_EAX) ); + + switch (ty) { + case Ity_I32: { + IROp hiOp = signed_multiply ? Iop_MullS32_hi32 : Iop_MullU32_hi32; + IRTemp trHi32 = newTemp(Ity_I32); + setFlags_MUL ( Ity_I32, t1, t2, + signed_multiply ? CC_OP_MULLSB : CC_OP_MULLUB ); + assign( tr, binop(Iop_Mul32, mkexpr(t1), mkexpr(t2) ) ); + assign( trHi32, binop(hiOp, mkexpr(t1), mkexpr(t2) ) ); + putIReg(4, R_EAX, mkexpr(tr)); + putIReg(4, R_EDX, mkexpr(trHi32)); + break; + } + default: + vpanic("codegen_mul_A_D_Reg(x86)"); + } + DIP("%s%c %s\n", signed_multiply ? "imul" : "mul", + nameISize(sz), nameIReg(sz, eregOfRM(modrm))); +} + //-- uInstr1(cb, PUSH, sz, TempReg, t1); //-- uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta); //-- uInstr1(cb, PUSH, sz, TempReg, ta); @@ -2119,8 +2175,6 @@ UInt dis_Grp2 ( UChar sorb, //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX); //-- } //-- uInstr0(cb, CALLM_E, 0); -//-- DIP("%s%c %s\n", signed_multiply ? "imul" : "mul", -//-- nameISize(sz), nameIReg(sz, eregOfRM(modrm))); //-- //-- } //-- @@ -2209,10 +2263,10 @@ UInt dis_Grp3 ( UChar sorb, Int sz, UInt delta ) putIReg(sz, eregOfRM(modrm), mkexpr(dst1)); DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm))); break; -//-- case 4: /* MUL */ -//-- eip++; -//-- codegen_mul_A_D_Reg ( cb, sz, modrm, False ); -//-- break; + case 4: /* MUL (unsigned widening) */ + delta++; + codegen_mul_A_D_Reg ( sz, modrm, False ); + break; //-- case 5: /* IMUL */ //-- eip++; //-- codegen_mul_A_D_Reg ( cb, sz, modrm, True ); @@ -2655,51 +2709,84 @@ void dis_REP_op ( Condcode cond, /*--- Arithmetic, etc. ---*/ /*------------------------------------------------------------*/ -//-- /* (I)MUL E, G. Supplied eip points to the modR/M byte. */ -//-- static -//-- Addr dis_mul_E_G ( UCodeBlock* cb, -//-- UChar sorb, -//-- Int size, -//-- Addr eip0, -//-- Bool signed_multiply ) -//-- { -//-- Int ta, tg, te; -//-- UChar dis_buf[50]; -//-- UChar rm = getIByte(delta0); -//-- ta = INVALID_TEMPREG; -//-- te = newTemp(cb); -//-- tg = newTemp(cb); -//-- -//-- if (epartIsReg(rm)) { -//-- vg_assert(signed_multiply); -//-- uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tg); -//-- uInstr2(cb, MUL, size, ArchReg, eregOfRM(rm), TempReg, tg); -//-- setFlagsFromUOpcode(cb, MUL); -//-- uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm)); -//-- DIP("%smul%c %s, %s\n", signed_multiply ? "i" : "", -//-- nameISize(size), -//-- nameIReg(size,eregOfRM(rm)), -//-- nameIReg(size,gregOfRM(rm))); -//-- return 1+eip0; -//-- } else { -//-- UInt pair; -//-- vg_assert(signed_multiply); -//-- pair = disAMode ( cb, sorb, eip0, dis_buf ); -//-- ta = LOW24(pair); -//-- uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te); -//-- uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tg); -//-- uInstr2(cb, MUL, size, TempReg, te, TempReg, tg); -//-- setFlagsFromUOpcode(cb, MUL); -//-- uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm)); -//-- -//-- DIP("%smul%c %s, %s\n", signed_multiply ? "i" : "", -//-- nameISize(size), -//-- dis_buf, nameIReg(size,gregOfRM(rm))); -//-- return HI8(pair)+eip0; -//-- } -//-- } -//-- -//-- +#if 0 +static +void do_mul_and_setFlags ( IRType ty, + IRTemp dst, IRTemp src1, IRTemp src2 ) +{ + vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32); + setFlags_MUL( ty, src1, src2, CC_OP_MULB ); + assign( dst, binop( mkSizedOp(ty,Iop_Mul8), + mkexpr(src1), + mkexpr(src2)) ); +} + +static +void do_mull_and_setFlags ( IRType ty, + Bool sign, + IRTemp dst, IRTemp src1, IRTemp src2 ) +{ + vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32); + setFlags_MUL( ty, src1, src2, + sign ? CC_OP_MULLSB : CC_OP_MULLUB ); + assign( dst, + binop( mkSizedOp(ty, sign ? Iop_MullS8 : Iop_MullU8), + mkexpr(src1), + mkexpr(src2)) ); +} +#endif + +/* (I)MUL E, G. Supplied eip points to the modR/M byte. */ +static +UInt dis_mul_E_G ( UChar sorb, + Int size, + UInt delta0, + Bool signed_multiply ) +{ + + // UChar dis_buf[50]; + UChar rm = getIByte(delta0); + IRType ty = szToITy(size); + //IRTemp ta = INVALID_IRTEMP; + IRTemp te = newTemp(size); + IRTemp tg = newTemp(size); + + if (epartIsReg(rm)) { + vassert(signed_multiply); + assign( tg, getIReg(size, gregOfRM(rm)) ); + assign( te, getIReg(size, eregOfRM(rm)) ); + setFlags_MUL ( ty, te, tg, CC_OP_MULB ); + putIReg(size, gregOfRM(rm), + binop(mkSizedOp(ty,Iop_Mul8), + mkexpr(te), mkexpr(tg))); + + DIP("%smul%c %s, %s\n", signed_multiply ? "i" : "", + nameISize(size), + nameIReg(size,eregOfRM(rm)), + nameIReg(size,gregOfRM(rm))); + return 1+delta0; + } else { + vassert(0+0==0); +#if 0 + UInt pair; + vg_assert(signed_multiply); + pair = disAMode ( cb, sorb, eip0, dis_buf ); + ta = LOW24(pair); + uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te); + uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tg); + uInstr2(cb, MUL, size, TempReg, te, TempReg, tg); + setFlagsFromUOpcode(cb, MUL); + uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm)); + + DIP("%smul%c %s, %s\n", signed_multiply ? "i" : "", + nameISize(size), + dis_buf, nameIReg(size,gregOfRM(rm))); + return HI8(pair)+eip0; +#endif + } +} + + //-- /* IMUL I * E -> G. Supplied eip points to the modR/M byte. */ //-- static //-- Addr dis_imul_I_E_G ( UCodeBlock* cb, @@ -7107,12 +7194,12 @@ static UInt disInstr ( UInt delta, Bool* isEnd ) //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2); //-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf); //-- break; -//-- -//-- /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */ -//-- -//-- case 0xAF: /* IMUL Ev, Gv */ -//-- eip = dis_mul_E_G ( cb, sorb, sz, eip, True ); -//-- break; + + /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */ + + case 0xAF: /* IMUL Ev, Gv */ + delta = dis_mul_E_G ( sorb, sz, delta, True ); + break; /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */ case 0x80: diff --git a/VEX/priv/ir/ir_defs.c b/VEX/priv/ir/ir_defs.c index 4a7af191e7..6defc2e93e 100644 --- a/VEX/priv/ir/ir_defs.c +++ b/VEX/priv/ir/ir_defs.c @@ -87,6 +87,12 @@ void ppIROp ( IROp op ) case Iop_16Sto32: vex_printf("16Sto32"); return; case Iop_32to1: vex_printf("32to1"); return; case Iop_1Uto8: vex_printf("1Uto8"); return; + case Iop_MullS8: vex_printf("MullS8"); return; + case Iop_MullS16: vex_printf("MullS16"); return; + case Iop_MullS32_hi32: vex_printf("MullS32_hi32"); return; + case Iop_MullU8: vex_printf("MullU8"); return; + case Iop_MullU16: vex_printf("MullU16"); return; + case Iop_MullU32_hi32: vex_printf("MullU32_hi32"); return; default: vpanic("ppIROp(1)"); } diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index 6393e7c8ae..72e2238cc6 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -89,7 +89,10 @@ typedef /* Conversions */ Iop_8Uto16, Iop_8Uto32, Iop_16Uto32, Iop_8Sto16, Iop_8Sto32, Iop_16Sto32, - /* Specials */ + /* Widening multiplies */ + Iop_MullS8, Iop_MullS16, Iop_MullS32_hi32, + Iop_MullU8, Iop_MullU16, Iop_MullU32_hi32, + /* 1-bit stuff */ Iop_32to1, /* :: Ity_I32 -> Ity_Bit, just select bit[0] */ Iop_1Uto8 /* :: Ity_Bit -> Ity_I8, unsigned widen */ }