This creates a new UInstr for multiply. This is mainly so that memcheck

can treat it like add and generate partially-defined results of multiply
with partially defined arguments.  It may also speed things up a bit,
if they use lots of multiplies.

This change only deals with signed "new style" multiplies.  That the x86
has two quite different kinds of multiply instructions: the "old-style"
signed and unsigned multiply which uses fixed registers (eax:edx) and
generates a result twice the size of the arguments, and the newer signed
multiple which takes general addressing modes.  It seems that gcc always
(almost always?) generates the new signed multiply instructions, except
for byte-sized multiplies.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1925
This commit is contained in:
Jeremy Fitzhardinge 2003-10-14 21:49:11 +00:00
parent 32c9b08d6e
commit bab09402f1
5 changed files with 139 additions and 53 deletions

View File

@ -2879,6 +2879,91 @@ static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
}
static void synth_mul_reg_reg ( Bool upd_cc,
Opcode opcode, Int size,
Int reg1, Int reg2 )
{
VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
switch (size) {
case 2:
VG_(emitB)(0x66);
/* FALLTHROUGH */
case 4:
VG_(emitB)(0x0F);
VG_(emitB)(0xAF);
VG_(emit_amode_ereg_greg)(reg1, reg2);
break;
case 1:
VG_(core_panic)("can't do byte mul");
break;
}
if (dis)
VG_(printf)("\n\t\timul%c\t%s, %s\n",
nameISize(size),
nameIReg(size, reg1),
nameIReg(size, reg2));
}
static void synth_mul_lit_reg ( Bool upd_cc,
Opcode opcode, Int size,
UInt lit, Int reg )
{
VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
switch (size) {
case 2:
VG_(emitB)(0x66);
/* FALLTHROUGH */
case 4:
VG_(emitB)(0x69);
VG_(emit_amode_ereg_greg)(reg, 0);
if (size == 2)
VG_(emitW)(lit);
else
VG_(emitL)(lit);
break;
case 1:
VG_(core_panic)("can't do byte mul");
break;
}
if (dis)
VG_(printf)("\n\t\timul%c\t%d, %s\n",
nameISize(size),
lit,
nameIReg(size, reg));
}
static void synth_mul_offregmem_reg (
Bool upd_cc,
Opcode opcode, Int size,
Int off, Int areg, Int reg )
{
VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
switch(size) {
case 2:
VG_(emitB)(0x66);
/* FALLTHROUGH */
case 4:
VG_(emitB)(0x0F);
VG_(emitB)(0xAF);
VG_(emit_amode_offregmem_reg)(off, areg, reg);
break;
case 1:
VG_(core_panic)("can't do byte mul");
}
if (dis)
VG_(printf)("\n\t\timul%c\t0x%x(%s), %s\n",
nameISize(size), off, nameIReg(4,areg),nameIReg(size,reg));
}
static void synth_push_reg ( Int size, Int reg )
{
switch (size) {
@ -3528,6 +3613,30 @@ static void emitUInstr ( UCodeBlock* cb, Int i,
break;
}
case MUL: {
vg_assert(u->tag2 == RealReg);
switch(u->tag1) {
case Literal:
synth_mul_lit_reg(anyFlagUse(u),
u->opcode, u->size, u->lit32, u->val2);
break;
case RealReg:
synth_mul_reg_reg(anyFlagUse(u),
u->opcode, u->size, u->val1, u->val2);
break;
case ArchReg:
synth_mul_offregmem_reg(anyFlagUse(u),
u->opcode, u->size,
spillOrArchOffset(u->size, u->tag1, u->val1),
R_EBP, u->val2);
break;
default: VG_(core_panic)("emitUInstr:MUL");
}
break;
}
case SBB:
case ADC:
case XOR:

View File

@ -271,6 +271,8 @@ static void setFlagsFromUOpcode ( UCodeBlock* cb, Int uopc )
uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
case ADC: case SBB:
uFlagsRWU(cb, FlagC, FlagsOSZACP, FlagsEmpty); break;
case MUL: case UMUL:
uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP); break;
case ADD: case SUB: case NEG:
uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty); break;
case INC: case DEC:
@ -1446,7 +1448,7 @@ static void codegen_mul_A_D_Reg ( UCodeBlock* cb, Int sz,
uInstr1(cb, POP, 2, TempReg, t1);
uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
}
uInstr0(cb, CALLM_E, 0);
uInstr0(cb, CALLM_E, 0);
if (dis) VG_(printf)("%s%c %s\n", signed_multiply ? "imul" : "mul",
nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
@ -2200,38 +2202,19 @@ Addr dis_mul_E_G ( UCodeBlock* cb,
Addr eip0,
Bool signed_multiply )
{
Int ta, tg, te, helper;
Int ta, tg, te;
UChar dis_buf[50];
UChar rm = getUChar(eip0);
ta = INVALID_TEMPREG;
te = newTemp(cb);
tg = newTemp(cb);
switch (size) {
case 4: helper = signed_multiply ? VGOFF_(helper_imul_32_64)
: VGOFF_(helper_mul_32_64);
break;
case 2: helper = signed_multiply ? VGOFF_(helper_imul_16_32)
: VGOFF_(helper_mul_16_32);
break;
case 1: helper = signed_multiply ? VGOFF_(helper_imul_8_16)
: VGOFF_(helper_mul_8_16);
break;
default: VG_(core_panic)("dis_mul_E_G");
}
uInstr0(cb, CALLM_S, 0);
if (epartIsReg(rm)) {
uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, te);
uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tg);
uInstr1(cb, PUSH, size, TempReg, te);
uInstr1(cb, PUSH, size, TempReg, tg);
uInstr1(cb, CALLM, 0, Lit16, helper);
uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
uInstr1(cb, CLEAR, 0, Lit16, 4);
uInstr1(cb, POP, size, TempReg, tg);
uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm));
uInstr0(cb, CALLM_E, 0);
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));
if (dis) VG_(printf)("%smul%c %s, %s\n",
signed_multiply ? "i" : "",
nameISize(size),
@ -2239,18 +2222,16 @@ Addr dis_mul_E_G ( UCodeBlock* cb,
nameIReg(size,gregOfRM(rm)));
return 1+eip0;
} else {
UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
UInt pair;
vg_assert(signed_multiply);
pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
ta = LOW24(pair);
uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te);
uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tg);
uInstr1(cb, PUSH, size, TempReg, te);
uInstr1(cb, PUSH, size, TempReg, tg);
uInstr1(cb, CALLM, 0, Lit16, helper);
uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
uInstr1(cb, CLEAR, 0, Lit16, 4);
uInstr1(cb, POP, size, TempReg, tg);
uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm));
uInstr0(cb, CALLM_E, 0);
uInstr2(cb, MUL, size, TempReg, te, TempReg, tg);
setFlagsFromUOpcode(cb, MUL);
uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm));
if (dis) VG_(printf)("%smul%c %s, %s\n",
signed_multiply ? "i" : "",
nameISize(size),
@ -2268,30 +2249,20 @@ Addr dis_imul_I_E_G ( UCodeBlock* cb,
Addr eip,
Int litsize )
{
Int ta, te, tl, helper, d32;
Int ta, te, tl, d32;
UChar dis_buf[50];
UChar rm = getUChar(eip);
ta = INVALID_TEMPREG;
te = newTemp(cb);
tl = newTemp(cb);
switch (size) {
case 4: helper = VGOFF_(helper_imul_32_64); break;
case 2: helper = VGOFF_(helper_imul_16_32); break;
case 1: helper = VGOFF_(helper_imul_8_16); break;
default: VG_(core_panic)("dis_imul_I_E_G");
}
uInstr0(cb, CALLM_S, 0);
if (epartIsReg(rm)) {
uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, te);
uInstr1(cb, PUSH, size, TempReg, te);
eip++;
} else {
UInt pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL);
ta = LOW24(pair);
uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te);
uInstr1(cb, PUSH, size, TempReg, te);
eip += HI8(pair);
}
@ -2300,13 +2271,9 @@ Addr dis_imul_I_E_G ( UCodeBlock* cb,
uInstr2(cb, MOV, size, Literal, 0, TempReg, tl);
uLiteral(cb, d32);
uInstr1(cb, PUSH, size, TempReg, tl);
uInstr1(cb, CALLM, 0, Lit16, helper);
uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
uInstr1(cb, CLEAR, 0, Lit16, 4);
uInstr1(cb, POP, size, TempReg, te);
uInstr2(cb, MUL, size, TempReg, tl, TempReg, te);
setFlagsFromUOpcode(cb, MUL);
uInstr2(cb, PUT, size, TempReg, te, ArchReg, gregOfRM(rm));
uInstr0(cb, CALLM_E, 0);
if (dis) {
if (epartIsReg(rm)) {

View File

@ -461,6 +461,8 @@ Bool VG_(saneUInstr) ( Bool beforeRA, Bool beforeLiveness, UInstr* u )
# define Ls3 (u->tag3 == Lit16)
# define TRL1 (TR1 || L1)
# define TRAL1 (TR1 || A1 || L1)
# define TRA1 (TR1 || A1)
# define TRA2 (TR2 || A2)
# define N1 (u->tag1 == NoValue)
# define N2 (u->tag2 == NoValue)
# define N3 (u->tag3 == NoValue)
@ -519,6 +521,7 @@ Bool VG_(saneUInstr) ( Bool beforeRA, Bool beforeLiveness, UInstr* u )
case CLEAR: return LIT0 && SZ0 && CC0 && Ls1 && N2 && N3 && XOTHER;
case AND:
case OR: return LIT0 && SZi && CCa && TR1 && TR2 && N3 && XOTHER;
case MUL: return LIT0 && SZ42 && CCa && TRA1 &&TRA2 && N3 && XOTHER;
case ADD:
case XOR:
case SUB: return LITm && SZi && CCa &&TRAL1 && TR2 && N3 && XOTHER;
@ -840,6 +843,7 @@ Char* VG_(name_UOpcode) ( Bool upper, Opcode opc )
case ROR: return (upper ? "ROR" : "ror");
case RCL: return (upper ? "RCL" : "rcl");
case RCR: return (upper ? "RCR" : "rcr");
case MUL: return (upper ? "MUL" : "mul");
case NOT: return (upper ? "NOT" : "not");
case NEG: return (upper ? "NEG" : "neg");
case INC: return (upper ? "INC" : "inc");
@ -1172,7 +1176,8 @@ void pp_UInstrWorker ( Int instrNo, UInstr* u, Bool ppRegsLiveness )
case ADD: case ADC: case AND: case OR:
case XOR: case SUB: case SBB:
case SHL: case SHR: case SAR:
case ROL: case ROR: case RCL: case RCR:
case ROL: case ROR: case RCL: case RCR:
case MUL:
VG_(pp_UOperand)(u, 1, u->size, False);
VG_(printf)(", ");
VG_(pp_UOperand)(u, 2, u->size, False);
@ -1308,6 +1313,7 @@ Int VG_(get_reg_usage) ( UInstr* u, Tag tag, Int* regs, Bool* isWrites )
case CMOV:
case ADD: case ADC: case AND: case OR:
case XOR: case SUB: case SBB:
case MUL:
RD(1); RD(2); WR(2); break;
case SHL: case SHR: case SAR:
@ -1398,6 +1404,7 @@ Int maybe_uinstrReadsArchReg ( UInstr* u )
case XOR: case SUB: case SBB:
case SHL: case SHR: case SAR: case ROL:
case ROR: case RCL: case RCR:
case MUL:
if (u->tag1 == ArchReg)
return containingArchRegOf ( u->size, u->val1 );
else
@ -1614,6 +1621,7 @@ static void vg_improve ( UCodeBlock* cb )
case ADC: case SBB:
case SHL: case SHR: case SAR: case ROL: case ROR:
case RCL: case RCR:
case MUL:
if (dis)
VG_(printf)(
" at %2d: change ArchReg %S to TempReg t%d\n",

View File

@ -551,6 +551,7 @@ typedef
CMOV, /* Used for cmpxchg and cmov */
/* Arithmetic/logical ops */
MUL, UMUL, /* Multiply */
ADD, ADC, SUB, SBB, /* Add/subtract (w/wo carry) */
AND, OR, XOR, NOT, /* Boolean ops */
SHL, SHR, SAR, ROL, ROR, RCL, RCR, /* Shift/rotate (w/wo carry) */

View File

@ -860,6 +860,7 @@ static UCodeBlock* memcheck_instrument ( UCodeBlock* cb_in )
*/
case ADD: case SUB:
case ADC: case SBB:
case MUL:
qd = SHADOW(u_in->val2);
qs = getOperandShadow(cb, u_in->size, u_in->tag1, u_in->val1);
create_UifU(cb, u_in->size, qs, qd);