From: Julian Seward Date: Fri, 30 Jul 2004 10:17:50 +0000 (+0000) Subject: Finally finish pissing around with x86 integer multiply instructions. X-Git-Tag: svn/VALGRIND_3_0_1^2~1173 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=476bce8da3db6ab62946cbddc313dd46de279f66;p=thirdparty%2Fvalgrind.git Finally finish pissing around with x86 integer multiply instructions. The amount of random illogical crap in the x86 instruction set is just mind-numbing. Anyway, 8/16/32-bit multiply and multiply longs should now work correctly, including setting the flags. git-svn-id: svn://svn.valgrind.org/vex/trunk@161 --- diff --git a/VEX/priv/guest-x86/ghelpers.c b/VEX/priv/guest-x86/ghelpers.c index 9ab4beb5b8..64f86d2c2f 100644 --- a/VEX/priv/guest-x86/ghelpers.c +++ b/VEX/priv/guest-x86/ghelpers.c @@ -345,9 +345,13 @@ static inline int lshift(int x, int n) case CC_OP_RORW: ACTIONS_ROR( 16, UShort ); case CC_OP_RORL: ACTIONS_ROR( 32, UInt ); - case CC_OP_UMULL: ACTIONS_UMUL( 32, UInt, ULong ); + case CC_OP_UMULB: ACTIONS_UMUL( 8, UChar, UShort ); + case CC_OP_UMULW: ACTIONS_UMUL( 16, UShort, UInt ); + case CC_OP_UMULL: ACTIONS_UMUL( 32, UInt, ULong ); - case CC_OP_SMULL: ACTIONS_SMUL( 32, Int, Long ); + case CC_OP_SMULB: ACTIONS_SMUL( 8, Char, Short ); + case CC_OP_SMULW: ACTIONS_SMUL( 16, Short, Int ); + case CC_OP_SMULL: ACTIONS_SMUL( 32, Int, Long ); default: /* shouldn't really make these calls from generated code */ diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 0830474b57..b760858057 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -2459,30 +2459,37 @@ static void codegen_mulL_A_D ( Int sz, Bool syned, assign( t1, getIReg(sz, R_EAX) ); switch (ty) { - case Ity_I32: { - IRTemp res64 = newTemp(Ity_I64); - IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32; - UInt thunkOp = syned ? CC_OP_SMULB : CC_OP_UMULB; - setFlags_MUL ( Ity_I32, t1, tmp, thunkOp ); - assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) ); - putIReg(4, R_EDX, unop(Iop_64HIto32,mkexpr(res64))); - putIReg(4, R_EAX, unop(Iop_64to32,mkexpr(res64))); - break; - } -#if 0 - case Ity_I16: { - IRTemp res32 = newTemp(Ity_I32); - IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16; - UInt thunkOp = syned ? CC_OP_MULLSB : CC_OP_MULLUB; - setFlags_MUL ( Ity_I16, t1, tmp, thunkOp ); - assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) ); - putIReg(2, R_EDX, unop(Iop_32HIto16,mkexpr(res32))); - putIReg(2, R_EAX, unop(Iop_32to16,mkexpr(res32))); - break; - } -#endif - default: - vpanic("codegen_mulL_A_D(x86)"); + case Ity_I32: { + IRTemp res64 = newTemp(Ity_I64); + IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32; + UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB; + setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp ); + assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) ); + putIReg(4, R_EDX, unop(Iop_64HIto32,mkexpr(res64))); + putIReg(4, R_EAX, unop(Iop_64to32,mkexpr(res64))); + break; + } + case Ity_I16: { + IRTemp res32 = newTemp(Ity_I32); + IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16; + UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB; + setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp ); + assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) ); + putIReg(2, R_EDX, unop(Iop_32HIto16,mkexpr(res32))); + putIReg(2, R_EAX, unop(Iop_32to16,mkexpr(res32))); + break; + } + case Ity_I8: { + IRTemp res16 = newTemp(Ity_I16); + IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8; + UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB; + setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp ); + assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) ); + putIReg(2, R_EAX, mkexpr(res16)); + break; + } + default: + vpanic("codegen_mulL_A_D(x86)"); } DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt); } @@ -3029,14 +3036,15 @@ UInt dis_imul_I_E_G ( UChar sorb, UInt delta, Int litsize ) { - Int d32; - Char dis_buf[50]; - UChar rm = getIByte(delta); - // ta = INVALID_TEMPREG; + Int d32; + Char dis_buf[50]; + UChar rm = getIByte(delta); IRType ty = szToITy(size); IRTemp te = newTemp(ty); IRTemp tl = newTemp(ty); + vassert(size == 1 || size == 2 || size == 4); + if (epartIsReg(rm)) { assign(te, getIReg(size, eregOfRM(rm))); delta++; @@ -3052,6 +3060,9 @@ UInt dis_imul_I_E_G ( UChar sorb, d32 = getSDisp(litsize,delta); delta += litsize; + if (size == 1) d32 &= 0xFF; + if (size == 2) d32 &= 0xFFFF; + assign(tl, mkU(ty,d32)); setFlags_MUL ( ty, te, tl, CC_OP_SMULB ); putIReg(size, gregOfRM(rm), diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index 0fdf658075..460e2ba5ba 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -294,8 +294,10 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e ) aluOp = Xalu_OR; break; case Iop_Xor8: case Iop_Xor16: case Iop_Xor32: aluOp = Xalu_XOR; break; - case Iop_Mul32: aluOp = Xalu_MUL; break; - default: aluOp = Xalu_INVALID; break; + case Iop_Mul16: case Iop_Mul32: + aluOp = Xalu_MUL; break; + default: + aluOp = Xalu_INVALID; break; } /* For commutative ops we assume any literal values are on the second operand. */ @@ -356,6 +358,7 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e ) nshift = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8; vassert(nshift >= 0); if (nshift > 0) + /* Can't allow nshift==0 since that means %cl */ addInstr(env, X86Instr_Sh32( shOp, nshift, @@ -383,6 +386,29 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e ) return hi16; } + if (e->Iex.Binop.op == Iop_MullS16 || e->Iex.Binop.op == Iop_MullS8 + || e->Iex.Binop.op == Iop_MullU16 || e->Iex.Binop.op == Iop_MullU8) { + HReg a16 = newVRegI(env); + HReg b16 = newVRegI(env); + HReg a16s = iselIntExpr_R(env, e->Iex.Binop.arg1); + HReg b16s = iselIntExpr_R(env, e->Iex.Binop.arg2); + Int shift = (e->Iex.Binop.op == Iop_MullS8 + || e->Iex.Binop.op == Iop_MullU8) + ? 24 : 16; + X86ShiftOp shr_op = (e->Iex.Binop.op == Iop_MullS8 + || e->Iex.Binop.op == Iop_MullS16) + ? Xsh_SAR : Xsh_SHR; + + addInstr(env, mk_MOVsd_RR(a16s, a16)); + addInstr(env, mk_MOVsd_RR(b16s, b16)); + addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, X86RM_Reg(a16))); + addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, X86RM_Reg(b16))); + addInstr(env, X86Instr_Sh32(shr_op, shift, X86RM_Reg(a16))); + addInstr(env, X86Instr_Sh32(shr_op, shift, X86RM_Reg(b16))); + addInstr(env, X86Instr_Alu32R(Xalu_MUL, X86RMI_Reg(a16), b16)); + return b16; + } + break; } @@ -441,16 +467,19 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e ) iselIntExpr64(&rHi,&rLo, env, e->Iex.Unop.arg); return rLo; /* similar stupid comment to the above ... */ } + case Iop_16HIto8: case Iop_32HIto16: { - HReg dst = newVRegI(env); - HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); + HReg dst = newVRegI(env); + HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); + Int shift = e->Iex.Unop.op == Iop_16HIto8 ? 8 : 16; addInstr(env, mk_MOVsd_RR(src,dst) ); - addInstr(env, X86Instr_Sh32(Xsh_SHR, 16, X86RM_Reg(dst))); + addInstr(env, X86Instr_Sh32(Xsh_SHR, shift, X86RM_Reg(dst))); return dst; } + case Iop_16to8: case Iop_32to8: case Iop_32to16: - /* These are both no-ops. */ + /* These are no-ops. */ return iselIntExpr_R(env, e->Iex.Unop.arg); default: diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index e9201a4cb3..00179e4ba2 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -102,6 +102,10 @@ void ppIROp ( IROp op ) case Iop_DivModU64to32: vex_printf("DivModU64to32"); return; case Iop_DivModS64to32: vex_printf("DivModS64to32"); return; + case Iop_16HIto8: vex_printf("16HIto8"); return; + case Iop_16to8: vex_printf("16to8"); return; + case Iop_8HLto16: vex_printf("8HLto16"); return; + case Iop_32HIto16: vex_printf("32HIto16"); return; case Iop_32to16: vex_printf("32to16"); return; case Iop_16HLto32: vex_printf("16HLto32"); return; @@ -477,6 +481,10 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) case Iop_CmpEQ64: case Iop_CmpNE64: COMPARISON(Ity_I64); + case Iop_MullU8: case Iop_MullS8: + BINARY(Ity_I16,Ity_I8,Ity_I8); + case Iop_MullU16: case Iop_MullS16: + BINARY(Ity_I32,Ity_I16,Ity_I16); case Iop_MullU32: case Iop_MullS32: BINARY(Ity_I64,Ity_I32,Ity_I32); @@ -484,6 +492,11 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) case Iop_DivModS64to32: BINARY(Ity_I64,Ity_I64,Ity_I32); + case Iop_16HIto8: case Iop_16to8: + UNARY(Ity_I8,Ity_I16); + case Iop_8HLto16: + BINARY(Ity_I16,Ity_I8,Ity_I8); + case Iop_32HIto16: case Iop_32to16: UNARY(Ity_I16,Ity_I32); case Iop_16HLto32: diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index 959a24f228..c769d21340 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -99,6 +99,10 @@ typedef Iop_8Sto16, Iop_8Sto32, Iop_16Sto32, /* Narrowing conversions */ Iop_32to8, + /* 8 <-> 16 bit conversions */ + Iop_16to8, // :: I16 -> I8, low half + Iop_16HIto8, // :: I16 -> I8, high half + Iop_8HLto16, // :: (I8,I8) -> I16 /* 16 <-> 32 bit conversions */ Iop_32to16, // :: I32 -> I16, low half Iop_32HIto16, // :: I32 -> I16, high half