Re-enable lwl/lwr/swl/swr on the x86 jit.

Now correctly handling ECX on x64.
This commit is contained in:
Unknown W. Brackets 2013-07-06 01:21:52 -07:00
parent 662ae77214
commit 2d15eb2acd
3 changed files with 61 additions and 42 deletions

View File

@ -104,25 +104,28 @@ namespace MIPSComp
void Jit::CompITypeMemUnpairedLR(u32 op, bool isStore)
{
// TODO: ECX getting overwritten? Why?
DISABLE;
CONDITIONAL_DISABLE;
int o = op>>26;
int offset = (signed short)(op&0xFFFF);
int rt = _RT;
int rs = _RS;
X64Reg shiftReg = ECX;
gpr.FlushLockX(ECX, EDX);
#ifdef _M_X64
// On x64, we need ECX for CL, but it's also the first arg and gets lost. Annoying.
gpr.FlushLockX(R9);
shiftReg = R9;
#endif
gpr.Lock(rt);
gpr.BindToRegister(rt, true, !isStore);
// Grab the offset from alignment for shifting (<< 3 for bytes -> bits.)
MOV(32, R(ECX), gpr.R(rs));
ADD(32, R(ECX), Imm32(offset));
AND(32, R(ECX), Imm32(3));
SHL(32, R(ECX), Imm8(3));
MOV(32, R(shiftReg), gpr.R(rs));
ADD(32, R(shiftReg), Imm32(offset));
AND(32, R(shiftReg), Imm32(3));
SHL(32, R(shiftReg), Imm8(3));
{
JitSafeMem safe(this, rs, offset, ~3);
@ -133,10 +136,10 @@ namespace MIPSComp
if (!src.IsSimpleReg(EAX))
MOV(32, R(EAX), src);
CompITypeMemUnpairedLRInner(op);
CompITypeMemUnpairedLRInner(op, shiftReg);
}
if (safe.PrepareSlowRead((void *) &Memory::Read_U32))
CompITypeMemUnpairedLRInner(op);
CompITypeMemUnpairedLRInner(op, shiftReg);
safe.Finish();
}
@ -156,37 +159,69 @@ namespace MIPSComp
gpr.UnlockAllX();
}
void Jit::CompITypeMemUnpairedLRInner(u32 op)
void Jit::CompITypeMemUnpairedLRInner(u32 op, X64Reg shiftReg)
{
CONDITIONAL_DISABLE;
int o = op>>26;
int rt = _RT;
// Make sure we have the shift for the target in ECX.
if (shiftReg != ECX)
MOV(32, R(ECX), R(shiftReg));
// Now use that shift (left on target, right on source.)
switch (o)
{
case 34: //lwl
// First clear the target bits.
MOV(32, R(EDX), Imm32(0x00ffffff));
SHR(32, R(EDX), R(CL));
AND(32, gpr.R(rt), R(EDX));
break;
// Adjust the shift to the bits we want.
case 38: //lwr
SHR(32, R(EAX), R(CL));
break;
case 42: //swl
MOV(32, R(EDX), Imm32(0xffffff00));
SHL(32, R(EDX), R(CL));
AND(32, R(EAX), R(EDX));
break;
case 46: //swr
MOV(32, R(EDX), gpr.R(rt));
SHL(32, R(EDX), R(CL));
// EDX is already the target value to write, but may be overwritten below. Save it.
PUSH(EDX);
break;
default:
_dbg_assert_msg_(JIT, 0, "Unsupported left/right load/store instruction.");
}
// Flip ECX around from 3 bytes / 24 bits.
if (shiftReg == ECX)
{
MOV(32, R(EDX), Imm32(24));
SUB(32, R(EDX), R(ECX));
MOV(32, R(ECX), R(EDX));
}
else
{
MOV(32, R(ECX), Imm32(24));
SUB(32, R(ECX), R(shiftReg));
}
// Use the flipped shift (left on source, right on target) and write target.
switch (o)
{
case 34: //lwl
SHL(32, R(EAX), R(CL));
OR(32, gpr.R(rt), R(EAX));
break;
case 38: //lwr
// Adjust the shift to the bits we want.
SHR(32, R(EAX), R(CL));
// Clear the target bits we're replacing.
MOV(32, R(EDX), Imm32(24));
SUB(32, R(EDX), R(ECX));
MOV(32, R(ECX), R(EDX));
MOV(32, R(EDX), Imm32(0xffffff00));
SHL(32, R(EDX), R(CL));
AND(32, gpr.R(rt), R(EDX));
@ -195,15 +230,6 @@ namespace MIPSComp
break;
case 42: //swl
// First clear the target memory bits.
MOV(32, R(EDX), Imm32(0xffffff00));
SHL(32, R(EDX), R(CL));
AND(32, R(EAX), R(EDX));
// Flip the shift, and adjust the shift in a temporary.
MOV(32, R(EDX), Imm32(24));
SUB(32, R(EDX), R(ECX));
MOV(32, R(ECX), R(EDX));
MOV(32, R(EDX), gpr.R(rt));
SHR(32, R(EDX), R(CL));
@ -211,19 +237,11 @@ namespace MIPSComp
break;
case 46: //swr
// Adjust the shift to the bits we want.
MOV(32, R(EDX), gpr.R(rt));
SHL(32, R(EDX), R(CL));
PUSH(EDX);
// Clear the target bits we're replacing.
MOV(32, R(EDX), Imm32(24));
SUB(32, R(EDX), R(ECX));
MOV(32, R(ECX), R(EDX));
MOV(32, R(EDX), Imm32(0x00ffffff));
SHR(32, R(EDX), R(CL));
AND(32, R(EAX), R(EDX));
// This is the target value we saved earlier.
POP(EDX);
OR(32, R(EDX), R(EAX));
break;

View File

@ -275,7 +275,7 @@ private:
void CompITypeMemRead(u32 op, u32 bits, void (XEmitter::*mov)(int, int, X64Reg, OpArg), void *safeFunc);
void CompITypeMemWrite(u32 op, u32 bits, void *safeFunc);
void CompITypeMemUnpairedLR(u32 op, bool isStore);
void CompITypeMemUnpairedLRInner(u32 op);
void CompITypeMemUnpairedLRInner(u32 op, X64Reg shiftReg);
void CompFPTriArith(u32 op, void (XEmitter::*arith)(X64Reg reg, OpArg), bool orderMatters);
void CompFPComp(int lhs, int rhs, u8 compare, bool allowNaN = false);

View File

@ -26,15 +26,16 @@ using namespace Gen;
static const int allocationOrder[] =
{
// R12, when used as base register, for example in a LEA, can generate bad code! Need to look into this.
// R12, when used as base register, for example in a LEA, can generate bad code! Need to look into this.
// On x64, RCX and RDX are the first args. CallProtectedFunction() assumes they're not regcached.
#ifdef _M_X64
#ifdef _WIN32
RSI, RDI, R13, R14, R8, R9, R10, R11, R12, //, RCX
RSI, RDI, R13, R14, R8, R9, R10, R11, R12,
#else
RBP, R13, R14, R8, R9, R10, R11, R12, //, RCX
RBP, R13, R14, R8, R9, R10, R11, R12,
#endif
#elif _M_IX86
ESI, EDI, EBP, EDX, ECX, // Let's try to free up EBX as well.
ESI, EDI, EBP, EDX, ECX, // Let's try to free up EBX as well.
#endif
};