Add MOV optimization and MOV_sum

Replaces incarnations of the A=B+C pattern throughout the
code so we can apply optimizations consistently.
This commit is contained in:
Matt Mastracci
2016-06-26 20:05:45 -06:00
parent adcef046f6
commit 1e08ad0d97
5 changed files with 92 additions and 88 deletions

View File

@ -1540,6 +1540,13 @@ void XEmitter::XOR(int bits, const OpArg& a1, const OpArg& a2)
}
void XEmitter::MOV(int bits, const OpArg& a1, const OpArg& a2)
{
// Shortcut to zero a register
if (a2.IsZero() && a1.IsSimpleReg() && !flags_locked)
{
XOR(bits, a1, a1);
return;
}
if (a1.IsSimpleReg() && a2.IsSimpleReg() && a1.GetSimpleReg() == a2.GetSimpleReg())
ERROR_LOG(DYNA_REC, "Redundant MOV @ %p - bug in JIT?", code);
WriteNormalOp(bits, nrmMOV, a1, a2);
@ -1572,6 +1579,76 @@ void XEmitter::CMP_or_TEST(int bits, const OpArg& a1, const OpArg& a2)
}
}
void XEmitter::MOV_sum(int bits, X64Reg dest, const OpArg& a1, const OpArg& a2)
{
// This stomps on flags, so ensure they aren't locked
_dbg_assert_(DYNA_REC, !flags_locked);
// Zero shortcuts (note that this can generate no code in the case where a1 == dest && a2 == zero
// or a2 == dest && a1 == zero)
if (a1.IsZero())
{
if (!a2.IsSimpleReg() || a2.GetSimpleReg() != dest)
{
MOV(bits, R(dest), a2);
}
return;
}
if (a2.IsZero())
{
if (!a1.IsSimpleReg() || a1.GetSimpleReg() != dest)
{
MOV(bits, R(dest), a1);
}
return;
}
// If dest == a1 or dest == a2 we can simplify this
if (a1.IsSimpleReg() && a1.GetSimpleReg() == dest)
{
ADD(bits, R(dest), a2);
return;
}
if (a2.IsSimpleReg() && a2.GetSimpleReg() == dest)
{
ADD(bits, R(dest), a1);
return;
}
// TODO: 32-bit optimizations may apply to other bit sizes (confirm)
if (bits == 32)
{
if (a1.IsImm() && a2.IsImm())
{
MOV(32, R(dest), Imm32(a1.Imm32() + a2.Imm32()));
return;
}
if (a1.IsSimpleReg() && a2.IsSimpleReg())
{
LEA(32, dest, MRegSum(a1.GetSimpleReg(), a2.GetSimpleReg()));
return;
}
if (a1.IsSimpleReg() && a2.IsImm())
{
LEA(32, dest, MDisp(a1.GetSimpleReg(), a2.Imm32()));
return;
}
if (a1.IsImm() && a2.IsSimpleReg())
{
LEA(32, dest, MDisp(a2.GetSimpleReg(), a1.Imm32()));
return;
}
}
// Fallback
MOV(bits, R(dest), a1);
ADD(bits, R(dest), a2);
}
void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a1, const OpArg& a2)
{
CheckFlags();

View File

@ -310,6 +310,7 @@ struct OpArg
}
bool IsSimpleReg() const { return scale == SCALE_NONE; }
bool IsSimpleReg(X64Reg reg) const { return IsSimpleReg() && GetSimpleReg() == reg; }
bool IsZero() const { return IsImm() && offset == 0; }
int GetImmBits() const
{
switch (scale)
@ -639,6 +640,7 @@ public:
void TEST(int bits, const OpArg& a1, const OpArg& a2);
void CMP_or_TEST(int bits, const OpArg& a1, const OpArg& a2);
void MOV_sum(int bits, X64Reg dest, const OpArg& a1, const OpArg& a2);
// Are these useful at all? Consider removing.
void XCHG(int bits, const OpArg& a1, const OpArg& a2);