X64Emitter: support shorter mov reg, imm opcodes

Also refactor WriteNormalOp a little bit and add comments.
This commit is contained in:
Fiora 2014-09-10 23:54:06 -07:00
parent 67f7e7e28b
commit 18d83a310e
1 changed files with 39 additions and 15 deletions

View File

@ -1053,7 +1053,6 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg &o
emit->Write8(0x66); emit->Write8(0x66);
int immToWrite = 0; int immToWrite = 0;
bool skip_rest = false;
if (operand.IsImm()) if (operand.IsImm())
{ {
@ -1066,15 +1065,22 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg &o
if (operand.scale == SCALE_IMM8 && bits == 8) if (operand.scale == SCALE_IMM8 && bits == 8)
{ {
// op al, imm8
if (!scale && offsetOrBaseReg == AL && normalops[op].eaximm8 != 0xCC) if (!scale && offsetOrBaseReg == AL && normalops[op].eaximm8 != 0xCC)
{ {
emit->Write8(normalops[op].eaximm8); emit->Write8(normalops[op].eaximm8);
skip_rest = true; emit->Write8((u8)operand.offset);
return;
} }
else // mov reg, imm8
if (!scale && op == nrmMOV)
{ {
emit->Write8(normalops[op].imm8); emit->Write8(0xB0 + (offsetOrBaseReg & 7));
emit->Write8((u8)operand.offset);
return;
} }
// op r/m8, imm8
emit->Write8(normalops[op].imm8);
immToWrite = 8; immToWrite = 8;
} }
else if ((operand.scale == SCALE_IMM16 && bits == 16) || else if ((operand.scale == SCALE_IMM16 && bits == 16) ||
@ -1083,6 +1089,7 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg &o
{ {
// Try to save immediate size if we can, but first check to see // Try to save immediate size if we can, but first check to see
// if the instruction supports simm8. // if the instruction supports simm8.
// op r/m, imm8
if (normalops[op].simm8 != 0xCC && if (normalops[op].simm8 != 0xCC &&
((operand.scale == SCALE_IMM16 && (s16)operand.offset == (s8)operand.offset) || ((operand.scale == SCALE_IMM16 && (s16)operand.offset == (s8)operand.offset) ||
(operand.scale == SCALE_IMM32 && (s32)operand.offset == (s8)operand.offset))) (operand.scale == SCALE_IMM32 && (s32)operand.offset == (s8)operand.offset)))
@ -1092,15 +1099,28 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg &o
} }
else else
{ {
// mov reg, imm
if (!scale && op == nrmMOV && bits != 64)
{
emit->Write8(0xB8 + (offsetOrBaseReg & 7));
if (bits == 16)
emit->Write16((u16)operand.offset);
else
emit->Write32((u32)operand.offset);
return;
}
// op eax, imm
if (!scale && offsetOrBaseReg == EAX && normalops[op].eaximm32 != 0xCC) if (!scale && offsetOrBaseReg == EAX && normalops[op].eaximm32 != 0xCC)
{ {
emit->Write8(normalops[op].eaximm32); emit->Write8(normalops[op].eaximm32);
skip_rest = true; if (bits == 16)
} emit->Write16((u16)operand.offset);
else else
{ emit->Write32((u32)operand.offset);
emit->Write8(normalops[op].imm32); return;
} }
// op r/m, imm
emit->Write8(normalops[op].imm32);
immToWrite = bits == 16 ? 16 : 32; immToWrite = bits == 16 ? 16 : 32;
} }
} }
@ -1108,12 +1128,18 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg &o
(operand.scale == SCALE_IMM8 && bits == 32) || (operand.scale == SCALE_IMM8 && bits == 32) ||
(operand.scale == SCALE_IMM8 && bits == 64)) (operand.scale == SCALE_IMM8 && bits == 64))
{ {
// op r/m, imm8
emit->Write8(normalops[op].simm8); emit->Write8(normalops[op].simm8);
immToWrite = 8; immToWrite = 8;
} }
else if (operand.scale == SCALE_IMM64 && bits == 64) else if (operand.scale == SCALE_IMM64 && bits == 64)
{ {
if (op == nrmMOV) if (scale)
{
_assert_msg_(DYNA_REC, 0, "WriteNormalOp - MOV with 64-bit imm requres register destination");
}
// mov reg64, imm64
else if (op == nrmMOV)
{ {
emit->Write8(0xB8 + (offsetOrBaseReg & 7)); emit->Write8(0xB8 + (offsetOrBaseReg & 7));
emit->Write64((u64)operand.offset); emit->Write64((u64)operand.offset);
@ -1131,20 +1157,18 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg &o
{ {
_operandReg = (X64Reg)operand.offsetOrBaseReg; _operandReg = (X64Reg)operand.offsetOrBaseReg;
WriteRex(emit, bits, bits, _operandReg); WriteRex(emit, bits, bits, _operandReg);
// mem/reg or reg/reg op // op r/m, reg
if (toRM) if (toRM)
{ {
emit->Write8(bits == 8 ? normalops[op].toRm8 : normalops[op].toRm32); emit->Write8(bits == 8 ? normalops[op].toRm8 : normalops[op].toRm32);
// _assert_msg_(DYNA_REC, code[-1] != 0xCC, "ARGH4");
} }
// op reg, r/m
else else
{ {
emit->Write8(bits == 8 ? normalops[op].fromRm8 : normalops[op].fromRm32); emit->Write8(bits == 8 ? normalops[op].fromRm8 : normalops[op].fromRm32);
// _assert_msg_(DYNA_REC, code[-1] != 0xCC, "ARGH5");
} }
} }
if (!skip_rest) WriteRest(emit, immToWrite >> 3, _operandReg);
WriteRest(emit, immToWrite>>3, _operandReg);
switch (immToWrite) switch (immToWrite)
{ {
case 0: case 0: