Permalink
Browse files

Jit_LoadStore: lXXx

  • Loading branch information...
MerryMage committed Oct 15, 2018
1 parent 00d65f7 commit 534db3b2ed34e5a13691b902c8f14ce951bedbf1
@@ -756,7 +756,6 @@ u8* Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
js.downcountAmount += opinfo->numCycles;
js.fastmemLoadStore = nullptr;
js.fixupExceptionHandler = false;
js.revertGprLoad = -1;
js.revertFprLoad = -1;

if (!SConfig::GetInstance().bEnableDebugging)
@@ -925,8 +924,6 @@ u8* Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)

BitSet32 gprToFlush = BitSet32::AllTrue(32);
BitSet32 fprToFlush = BitSet32::AllTrue(32);
if (js.revertGprLoad >= 0)
gprToFlush[js.revertGprLoad] = false;
if (js.revertFprLoad >= 0)
fprToFlush[js.revertFprLoad] = false;
gpr.Flush(RegCache::FlushMode::MaintainState, gprToFlush);
@@ -126,12 +126,14 @@ void Jit64::lXXx(UGeckoInstruction inst)
js.op[2].inst.hex == 0x4182fff8)
{
s32 offset = (s32)(s16)inst.SIMM_16;
gpr.BindToRegister(a, true, false);
gpr.BindToRegister(d, false, true);
SafeLoadToReg(gpr.RX(d), gpr.R(a), accessSize, offset, CallerSavedRegistersInUse(), signExtend);
RCX64Reg Ra = gpr.Bind(a, RCMode::Read);
RCX64Reg Rd = gpr.Bind(d, RCMode::Write);
RegCache::Realize(Ra, Rd);

SafeLoadToReg(Rd, Ra, accessSize, offset, CallerSavedRegistersInUse(), signExtend);

// if it's still 0, we can wait until the next event
TEST(32, gpr.R(d), gpr.R(d));
TEST(32, Rd, Rd);
FixupBranch noIdle = J_CC(CC_NZ);

BitSet32 registersInUse = CallerSavedRegistersInUse();
@@ -155,7 +157,7 @@ void Jit64::lXXx(UGeckoInstruction inst)
// Determine whether this instruction updates inst.RA
bool update;
if (inst.OPCD == 31)
update = ((inst.SUBOP10 & 0x20) != 0) && (!gpr.R(b).IsImm() || gpr.R(b).Imm32() != 0);
update = ((inst.SUBOP10 & 0x20) != 0) && (!gpr.IsImm(b) || gpr.Imm32(b) != 0);
else
update = ((inst.OPCD & 1) != 0) && inst.SIMM_16 != 0;

@@ -165,19 +167,20 @@ void Jit64::lXXx(UGeckoInstruction inst)
bool storeAddress = false;
s32 loadOffset = 0;

// Prepare result
RCX64Reg Rd = jo.memcheck ? gpr.RevertableBind(d, RCMode::Write) : gpr.Bind(d, RCMode::Write);

// Prepare address operand
OpArg opAddress;
RCOpArg opAddress;
if (!update && !a)
{
if (indexed)
{
if (!gpr.R(b).IsImm())
gpr.BindToRegister(b, true, false);
opAddress = gpr.R(b);
opAddress = gpr.BindOrImm(b, RCMode::Read);
}
else
{
opAddress = Imm32((u32)(s32)inst.SIMM_16);
opAddress = RCOpArg::Imm32((u32)(s32)inst.SIMM_16);
}
}
else if (update && ((a == 0) || (d == a)))
@@ -186,88 +189,77 @@ void Jit64::lXXx(UGeckoInstruction inst)
}
else
{
if (!indexed && gpr.R(a).IsImm() && !jo.memcheck)
if (!indexed && gpr.IsImm(a) && !jo.memcheck)
{
u32 val = gpr.R(a).Imm32() + inst.SIMM_16;
opAddress = Imm32(val);
u32 val = gpr.Imm32(a) + inst.SIMM_16;
opAddress = RCOpArg::Imm32(val);
if (update)
gpr.SetImmediate32(a, val);
}
else if (indexed && gpr.R(a).IsImm() && gpr.R(b).IsImm() && !jo.memcheck)
else if (indexed && gpr.IsImm(a) && gpr.IsImm(b) && !jo.memcheck)
{
u32 val = gpr.R(a).Imm32() + gpr.R(b).Imm32();
opAddress = Imm32(val);
u32 val = gpr.Imm32(a) + gpr.Imm32(b);
opAddress = RCOpArg::Imm32(val);
if (update)
gpr.SetImmediate32(a, val);
}
else
{
// If we're using reg+reg mode and b is an immediate, pretend we're using constant offset mode
bool use_constant_offset = !indexed || gpr.R(b).IsImm();
const bool use_constant_offset = !indexed || gpr.IsImm(b);

s32 offset = 0;
if (use_constant_offset)
offset = indexed ? gpr.R(b).SImm32() : (s32)inst.SIMM_16;
offset = indexed ? gpr.SImm32(b) : (s32)inst.SIMM_16;

RCOpArg Rb = use_constant_offset ? RCOpArg{} : gpr.Use(b, RCMode::Read);

// Depending on whether we have an immediate and/or update, find the optimum way to calculate
// the load address.
if ((update || use_constant_offset) && !jo.memcheck)
{
gpr.BindToRegister(a, true, update);
opAddress = gpr.R(a);
opAddress = gpr.Bind(a, update ? RCMode::ReadWrite : RCMode::Read);
RegCache::Realize(opAddress, Rb);

if (!use_constant_offset)
ADD(32, opAddress, gpr.R(b));
ADD(32, opAddress, Rb);
else if (update)
ADD(32, opAddress, Imm32((u32)offset));
else
loadOffset = offset;
}
else
{
// In this case we need an extra temporary register.
opAddress = R(RSCRATCH2);
storeAddress = true;
// In this case we need an extra temporary register.
opAddress = RCOpArg::R(RSCRATCH2);
RCOpArg Ra = gpr.Use(a, RCMode::Read);
RegCache::Realize(opAddress, Ra, Rb);

if (use_constant_offset)
MOV_sum(32, RSCRATCH2, gpr.R(a), Imm32((u32)offset));
MOV_sum(32, RSCRATCH2, Ra, Imm32((u32)offset));
else
MOV_sum(32, RSCRATCH2, gpr.R(a), gpr.R(b));
MOV_sum(32, RSCRATCH2, Ra, Rb);
}
}
}

gpr.Lock(a, b, d);

if (update && storeAddress)
gpr.BindToRegister(a, true, true);

// A bit of an evil hack here. We need to retain the original value of this register for the
// exception path, but we'd rather not needlessly pass it around if we don't have to, since
// the exception path is very rare. So we store the value in the regcache, let the load path
// clobber it, then restore the value in the exception path.
// TODO: no other load has to do this at the moment, since no other loads go directly to the
// target registers, but if that ever changes, we need to do it there too.
if (jo.memcheck)
{
gpr.StoreFromRegister(d);
js.revertGprLoad = d;
}
gpr.BindToRegister(d, false, true);
RCX64Reg Ra = (update && storeAddress) ? gpr.Bind(a, RCMode::Write) : RCX64Reg{};
RegCache::Realize(opAddress, Ra, Rd);

BitSet32 registersInUse = CallerSavedRegistersInUse();
// We need to save the (usually scratch) address register for the update.
if (update && storeAddress)
registersInUse[RSCRATCH2] = true;

SafeLoadToReg(gpr.RX(d), opAddress, accessSize, loadOffset, registersInUse, signExtend);
SafeLoadToReg(Rd, opAddress, accessSize, loadOffset, registersInUse, signExtend);

if (update && storeAddress)
MOV(32, gpr.R(a), opAddress);
MOV(32, Ra, opAddress);

// TODO: support no-swap in SafeLoadToReg instead
if (byte_reversed)
BSWAP(accessSize, gpr.RX(d));

gpr.UnlockAll();
gpr.UnlockAllX();
BSWAP(accessSize, Rd);
}

void Jit64::dcbx(UGeckoInstruction inst)
@@ -73,7 +73,6 @@ class JitBase : public CPUCoreBase
// If these are set, we've stored the old value of a register which will be loaded in
// revertLoad,
// which lets us revert it on the exception path.
int revertGprLoad;
int revertFprLoad;

bool assumeNoPairedQuantize;

0 comments on commit 534db3b

Please sign in to comment.