Add a way to force alignment in JitSafeMem().

This commit is contained in:
Unknown W. Brackets 2013-07-04 15:46:07 -07:00
parent d2b874436d
commit 2d25d1eb05
3 changed files with 45 additions and 21 deletions

View File

@ -347,8 +347,8 @@ void Jit::Comp_SVQ(u32 op)
}
safe.Finish();
fpr.ReleaseSpillLocks();
gpr.UnlockAll();
fpr.ReleaseSpillLocks();
}
break;

View File

@ -469,8 +469,8 @@ bool Jit::CheckJitBreakpoint(u32 addr, int downcountOffset)
return false;
}
Jit::JitSafeMem::JitSafeMem(Jit *jit, int raddr, s32 offset)
: jit_(jit), raddr_(raddr), offset_(offset), needsCheck_(false), needsSkip_(false)
Jit::JitSafeMem::JitSafeMem(Jit *jit, int raddr, s32 offset, u32 alignMask)
: jit_(jit), raddr_(raddr), offset_(offset), needsCheck_(false), needsSkip_(false), alignMask_(alignMask)
{
// This makes it more instructions, so let's play it safe and say we need a far jump.
far_ = !g_Config.bIgnoreBadMemAccess || !CBreakPoints::GetMemChecks().empty();
@ -497,9 +497,9 @@ bool Jit::JitSafeMem::PrepareWrite(OpArg &dest, int size)
MemCheckImm(MEM_WRITE);
#ifdef _M_IX86
dest = M(Memory::base + (iaddr_ & Memory::MEMVIEW32_MASK));
dest = M(Memory::base + (iaddr_ & Memory::MEMVIEW32_MASK & alignMask_));
#else
dest = MDisp(RBX, iaddr_);
dest = MDisp(RBX, iaddr_ & alignMask_);
#endif
return true;
}
@ -522,9 +522,9 @@ bool Jit::JitSafeMem::PrepareRead(OpArg &src, int size)
MemCheckImm(MEM_READ);
#ifdef _M_IX86
src = M(Memory::base + (iaddr_ & Memory::MEMVIEW32_MASK));
src = M(Memory::base + (iaddr_ & Memory::MEMVIEW32_MASK & alignMask_));
#else
src = MDisp(RBX, iaddr_);
src = MDisp(RBX, iaddr_ & alignMask_);
#endif
return true;
}
@ -540,7 +540,7 @@ OpArg Jit::JitSafeMem::NextFastAddress(int suboffset)
{
if (jit_->gpr.IsImmediate(raddr_))
{
u32 addr = jit_->gpr.GetImmediate32(raddr_) + offset_ + suboffset;
u32 addr = (jit_->gpr.GetImmediate32(raddr_) + offset_ + suboffset) & alignMask_;
#ifdef _M_IX86
return M(Memory::base + (addr & Memory::MEMVIEW32_MASK));
@ -549,6 +549,8 @@ OpArg Jit::JitSafeMem::NextFastAddress(int suboffset)
#endif
}
_dbg_assert_msg_(HLE, (suboffset 0xFFFFFFFF) == suboffset, "suboffset must be aligned");
#ifdef _M_IX86
return MDisp(xaddr_, (u32) Memory::base + offset_ + suboffset);
#else
@ -559,8 +561,13 @@ OpArg Jit::JitSafeMem::NextFastAddress(int suboffset)
OpArg Jit::JitSafeMem::PrepareMemoryOpArg(ReadType type)
{
// We may not even need to move into EAX as a temporary.
// TODO: Except on x86 in fastmem mode.
if (jit_->gpr.R(raddr_).IsSimpleReg())
bool needTemp = alignMask_ != 0xFFFFFFFF;
#ifdef _M_IX86
// We always mask on 32 bit in fast memory mode.
needTemp = needTemp || g_Config.bFastMemory;
#endif
if (jit_->gpr.R(raddr_).IsSimpleReg() && !needTemp)
{
jit_->gpr.BindToRegister(raddr_, true, false);
xaddr_ = jit_->gpr.RX(raddr_);
@ -587,18 +594,24 @@ OpArg Jit::JitSafeMem::PrepareMemoryOpArg(ReadType type)
else
{
#ifdef _M_IX86
// Need to modify it, too bad.
if (xaddr_ != EAX)
jit_->MOV(32, R(EAX), R(xaddr_));
jit_->AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK));
xaddr_ = EAX;
#endif
}
// TODO: This could be more optimal, but the common case is that we want xaddr_ not to include offset_.
// Since we need to align them after add, we add and subtract.
if (alignMask_ != 0xFFFFFFFF)
{
jit_->ADD(32, R(xaddr_), Imm32(offset_));
jit_->AND(32, R(xaddr_), Imm32(alignMask_));
jit_->SUB(32, R(xaddr_), Imm32(offset_));
}
#ifdef _M_IX86
return MDisp(xaddr_, (u32) Memory::base + offset_);
return MDisp(xaddr_, (u32) Memory::base + offset_);
#else
return MComplex(RBX, xaddr_, SCALE_1, offset_);
return MComplex(RBX, xaddr_, SCALE_1, offset_);
#endif
}
@ -636,9 +649,13 @@ bool Jit::JitSafeMem::PrepareSlowWrite()
void Jit::JitSafeMem::DoSlowWrite(void *safeFunc, const OpArg src, int suboffset)
{
if (iaddr_ != (u32) -1)
jit_->MOV(32, R(EAX), Imm32(iaddr_ + suboffset));
jit_->MOV(32, R(EAX), Imm32((iaddr_ + suboffset) & alignMask_));
else
{
jit_->LEA(32, EAX, MDisp(xaddr_, offset_ + suboffset));
if (alignMask_ != 0xFFFFFFFF)
jit_->AND(32, R(EAX), Imm32(alignMask_));
}
jit_->ABI_CallFunctionAA(jit_->thunks.ProtectFunction(safeFunc, 2), src, R(EAX));
needsCheck_ = true;
@ -653,12 +670,14 @@ bool Jit::JitSafeMem::PrepareSlowRead(void *safeFunc)
// No slow read necessary.
if (ImmValid())
return false;
jit_->MOV(32, R(EAX), Imm32(iaddr_));
jit_->MOV(32, R(EAX), Imm32(iaddr_ & alignMask_));
}
else
{
PrepareSlowAccess();
jit_->LEA(32, EAX, MDisp(xaddr_, offset_));
if (alignMask_ != 0xFFFFFFFF)
jit_->AND(32, R(EAX), Imm32(alignMask_));
}
jit_->ABI_CallFunctionA(jit_->thunks.ProtectFunction(safeFunc, 1), R(EAX));
@ -679,13 +698,17 @@ void Jit::JitSafeMem::NextSlowRead(void *safeFunc, int suboffset)
if (jit_->gpr.IsImmediate(raddr_))
{
_dbg_assert_msg_(JIT, !Memory::IsValidAddress(iaddr_ + suboffset), "NextSlowRead() for a valid immediate address?");
_dbg_assert_msg_(JIT, !Memory::IsValidAddress(iaddr_ + suboffset), "NextSlowRead() for an invalid immediate address?");
jit_->MOV(32, R(EAX), Imm32(iaddr_ + suboffset));
jit_->MOV(32, R(EAX), Imm32((iaddr_ + suboffset) & alignMask_));
}
// For GPR, if xaddr_ was the dest register, this will be wrong. Don't use in GPR.
else
{
jit_->LEA(32, EAX, MDisp(xaddr_, offset_ + suboffset));
if (alignMask_ != 0xFFFFFFFF)
jit_->AND(32, R(EAX), Imm32(alignMask_));
}
jit_->ABI_CallFunctionA(jit_->thunks.ProtectFunction(safeFunc, 1), R(EAX));
}

View File

@ -292,7 +292,7 @@ private:
class JitSafeMem
{
public:
JitSafeMem(Jit *jit, int raddr, s32 offset);
JitSafeMem(Jit *jit, int raddr, s32 offset, u32 alignMask = 0xFFFFFFFF);
// Emit code necessary for a memory write, returns true if MOV to dest is needed.
bool PrepareWrite(OpArg &dest, int size);
@ -336,6 +336,7 @@ private:
bool needsCheck_;
bool needsSkip_;
bool far_;
u32 alignMask_;
u32 iaddr_;
X64Reg xaddr_;
FixupBranch tooLow_, tooHigh_, skip_;