mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 21:37:52 -07:00
Merge pull request #1639 from Sonicadvance1/aarch64_improvements
Aarch64 improvements
This commit is contained in:
commit
d8cb976bba
@ -491,6 +491,42 @@ void ARM64XEmitter::EncodeLogicalImmInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 i
|
|||||||
(immr << 16) | (imms << 10) | (Rn << 5) | Rd);
|
(immr << 16) | (imms << 10) | (Rn << 5) | Rd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ARM64XEmitter::EncodeLoadStorePair(u32 op, u32 load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm)
|
||||||
|
{
|
||||||
|
bool b64Bit = Is64Bit(Rt);
|
||||||
|
u32 type_encode = 0;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case INDEX_UNSIGNED:
|
||||||
|
type_encode = 0b010;
|
||||||
|
break;
|
||||||
|
case INDEX_POST:
|
||||||
|
type_encode = 0b001;
|
||||||
|
break;
|
||||||
|
case INDEX_PRE:
|
||||||
|
type_encode = 0b011;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b64Bit)
|
||||||
|
{
|
||||||
|
op |= 0b10;
|
||||||
|
imm >>= 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
imm >>= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rt = DecodeReg(Rt);
|
||||||
|
Rt2 = DecodeReg(Rt2);
|
||||||
|
Rn = DecodeReg(Rn);
|
||||||
|
|
||||||
|
Write32((op << 30) | (0b101 << 27) | (type_encode << 23) | (load << 22) | \
|
||||||
|
((imm & 0x7F) << 15) | (Rt2 << 10) | (Rn << 5) | Rt);
|
||||||
|
}
|
||||||
|
|
||||||
// FixupBranch branching
|
// FixupBranch branching
|
||||||
void ARM64XEmitter::SetJumpTarget(FixupBranch const& branch)
|
void ARM64XEmitter::SetJumpTarget(FixupBranch const& branch)
|
||||||
{
|
{
|
||||||
@ -1120,6 +1156,20 @@ void ARM64XEmitter::PRFM(ARM64Reg Rt, u32 imm)
|
|||||||
EncodeLoadRegisterInst(3, Rt, imm);
|
EncodeLoadRegisterInst(3, Rt, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load/Store pair
|
||||||
|
void ARM64XEmitter::LDP(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm)
|
||||||
|
{
|
||||||
|
EncodeLoadStorePair(0, 1, type, Rt, Rt2, Rn, imm);
|
||||||
|
}
|
||||||
|
void ARM64XEmitter::LDPSW(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm)
|
||||||
|
{
|
||||||
|
EncodeLoadStorePair(1, 1, type, Rt, Rt2, Rn, imm);
|
||||||
|
}
|
||||||
|
void ARM64XEmitter::STP(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm)
|
||||||
|
{
|
||||||
|
EncodeLoadStorePair(0, 0, type, Rt, Rt2, Rn, imm);
|
||||||
|
}
|
||||||
|
|
||||||
// Load/Store Exclusive
|
// Load/Store Exclusive
|
||||||
void ARM64XEmitter::STXRB(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn)
|
void ARM64XEmitter::STXRB(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn)
|
||||||
{
|
{
|
||||||
|
@ -299,6 +299,7 @@ private:
|
|||||||
void EncodeLoadStoreRegisterOffset(u32 size, u32 opc, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend);
|
void EncodeLoadStoreRegisterOffset(u32 size, u32 opc, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend);
|
||||||
void EncodeAddSubImmInst(u32 op, bool flags, u32 shift, u32 imm, ARM64Reg Rn, ARM64Reg Rd);
|
void EncodeAddSubImmInst(u32 op, bool flags, u32 shift, u32 imm, ARM64Reg Rn, ARM64Reg Rd);
|
||||||
void EncodeLogicalImmInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms);
|
void EncodeLogicalImmInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms);
|
||||||
|
void EncodeLoadStorePair(u32 op, u32 load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
inline void Write32(u32 value)
|
inline void Write32(u32 value)
|
||||||
@ -313,6 +314,12 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ARM64XEmitter(u8* code_ptr) {
|
||||||
|
m_code = code_ptr;
|
||||||
|
m_lastCacheFlushEnd = code_ptr;
|
||||||
|
m_startcode = code_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~ARM64XEmitter()
|
virtual ~ARM64XEmitter()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -539,6 +546,11 @@ public:
|
|||||||
void LDRSW(ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend = EXTEND_LSL);
|
void LDRSW(ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend = EXTEND_LSL);
|
||||||
void PRFM(ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend = EXTEND_LSL);
|
void PRFM(ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend = EXTEND_LSL);
|
||||||
|
|
||||||
|
// Load/Store pair
|
||||||
|
void LDP(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm);
|
||||||
|
void LDPSW(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm);
|
||||||
|
void STP(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm);
|
||||||
|
|
||||||
// Wrapper around MOVZ+MOVK
|
// Wrapper around MOVZ+MOVK
|
||||||
void MOVI2R(ARM64Reg Rd, u64 imm, bool optimize = true);
|
void MOVI2R(ARM64Reg Rd, u64 imm, bool optimize = true);
|
||||||
};
|
};
|
||||||
|
@ -351,7 +351,7 @@ public:
|
|||||||
ARMXEmitter() : code(nullptr), startcode(nullptr), lastCacheFlushEnd(nullptr) {
|
ARMXEmitter() : code(nullptr), startcode(nullptr), lastCacheFlushEnd(nullptr) {
|
||||||
condition = CC_AL << 28;
|
condition = CC_AL << 28;
|
||||||
}
|
}
|
||||||
ARMXEmitter(u8 *code_ptr) {
|
ARMXEmitter(u8* code_ptr) {
|
||||||
code = code_ptr;
|
code = code_ptr;
|
||||||
lastCacheFlushEnd = code_ptr;
|
lastCacheFlushEnd = code_ptr;
|
||||||
startcode = code_ptr;
|
startcode = code_ptr;
|
||||||
|
@ -49,8 +49,8 @@ void JitArm64::unknown_instruction(UGeckoInstruction inst)
|
|||||||
|
|
||||||
void JitArm64::FallBackToInterpreter(UGeckoInstruction inst)
|
void JitArm64::FallBackToInterpreter(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
gpr.Flush(FlushMode::FLUSH_ALL);
|
gpr.Flush(FlushMode::FLUSH_INTERPRETER, js.op);
|
||||||
fpr.Flush(FlushMode::FLUSH_ALL);
|
fpr.Flush(FlushMode::FLUSH_INTERPRETER, js.op);
|
||||||
Interpreter::_interpreterInstruction instr = GetInterpreterOp(inst);
|
Interpreter::_interpreterInstruction instr = GetInterpreterOp(inst);
|
||||||
MOVI2R(W0, inst.hex);
|
MOVI2R(W0, inst.hex);
|
||||||
MOVI2R(X30, (u64)instr);
|
MOVI2R(X30, (u64)instr);
|
||||||
@ -59,8 +59,17 @@ void JitArm64::FallBackToInterpreter(UGeckoInstruction inst)
|
|||||||
|
|
||||||
void JitArm64::HLEFunction(UGeckoInstruction inst)
|
void JitArm64::HLEFunction(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
WARN_LOG(DYNA_REC, "HLEFunction %08x - Fix me ;)", inst.hex);
|
gpr.Flush(FlushMode::FLUSH_ALL);
|
||||||
exit(0);
|
fpr.Flush(FlushMode::FLUSH_ALL);
|
||||||
|
|
||||||
|
MOVI2R(W0, js.compilerPC);
|
||||||
|
MOVI2R(W1, inst.hex);
|
||||||
|
MOVI2R(X30, (u64)&HLE::Execute);
|
||||||
|
BLR(X30);
|
||||||
|
|
||||||
|
ARM64Reg WA = gpr.GetReg();
|
||||||
|
LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(npc));
|
||||||
|
WriteExitDestInR(WA);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitArm64::DoNothing(UGeckoInstruction inst)
|
void JitArm64::DoNothing(UGeckoInstruction inst)
|
||||||
@ -97,6 +106,8 @@ void JitArm64::DoDownCount()
|
|||||||
// Exits
|
// Exits
|
||||||
void JitArm64::WriteExit(u32 destination)
|
void JitArm64::WriteExit(u32 destination)
|
||||||
{
|
{
|
||||||
|
DoDownCount();
|
||||||
|
|
||||||
//If nobody has taken care of this yet (this can be removed when all branches are done)
|
//If nobody has taken care of this yet (this can be removed when all branches are done)
|
||||||
JitBlock *b = js.curBlock;
|
JitBlock *b = js.curBlock;
|
||||||
JitBlock::LinkData linkData;
|
JitBlock::LinkData linkData;
|
||||||
@ -104,8 +115,6 @@ void JitArm64::WriteExit(u32 destination)
|
|||||||
linkData.exitPtrs = GetWritableCodePtr();
|
linkData.exitPtrs = GetWritableCodePtr();
|
||||||
linkData.linkStatus = false;
|
linkData.linkStatus = false;
|
||||||
|
|
||||||
DoDownCount();
|
|
||||||
|
|
||||||
// Link opportunity!
|
// Link opportunity!
|
||||||
int block;
|
int block;
|
||||||
if (jo.enableBlocklink && (block = blocks.GetBlockNumberFromStartAddress(destination)) >= 0)
|
if (jo.enableBlocklink && (block = blocks.GetBlockNumberFromStartAddress(destination)) >= 0)
|
||||||
@ -163,13 +172,12 @@ void JitArm64::SingleStep()
|
|||||||
pExecAddr();
|
pExecAddr();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitArm64::Jit(u32 em_address)
|
void JitArm64::Jit(u32)
|
||||||
{
|
{
|
||||||
if (GetSpaceLeft() < 0x10000 || blocks.IsFull() || SConfig::GetInstance().m_LocalCoreStartupParameter.bJITNoBlockCache)
|
if (GetSpaceLeft() < 0x10000 || blocks.IsFull() || SConfig::GetInstance().m_LocalCoreStartupParameter.bJITNoBlockCache)
|
||||||
{
|
{
|
||||||
ClearCache();
|
ClearCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
int block_num = blocks.AllocateBlock(PowerPC::ppcState.pc);
|
int block_num = blocks.AllocateBlock(PowerPC::ppcState.pc);
|
||||||
JitBlock *b = blocks.GetBlock(block_num);
|
JitBlock *b = blocks.GetBlock(block_num);
|
||||||
const u8* BlockPtr = DoJit(PowerPC::ppcState.pc, &code_buffer, b);
|
const u8* BlockPtr = DoJit(PowerPC::ppcState.pc, &code_buffer, b);
|
||||||
@ -282,6 +290,7 @@ const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB
|
|||||||
|
|
||||||
b->codeSize = (u32)(GetCodePtr() - normalEntry);
|
b->codeSize = (u32)(GetCodePtr() - normalEntry);
|
||||||
b->originalSize = code_block.m_num_instructions;
|
b->originalSize = code_block.m_num_instructions;
|
||||||
|
|
||||||
FlushIcache();
|
FlushIcache();
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ public:
|
|||||||
void Run();
|
void Run();
|
||||||
void SingleStep();
|
void SingleStep();
|
||||||
|
|
||||||
void Jit(u32 em_address);
|
void Jit(u32);
|
||||||
|
|
||||||
const char *GetName()
|
const char *GetName()
|
||||||
{
|
{
|
||||||
|
@ -8,9 +8,18 @@
|
|||||||
|
|
||||||
void JitArm64BlockCache::WriteLinkBlock(u8* location, const u8* address)
|
void JitArm64BlockCache::WriteLinkBlock(u8* location, const u8* address)
|
||||||
{
|
{
|
||||||
|
ARM64XEmitter emit(location);
|
||||||
|
emit.B(address);
|
||||||
|
emit.FlushIcache();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitArm64BlockCache::WriteDestroyBlock(const u8* location, u32 address)
|
void JitArm64BlockCache::WriteDestroyBlock(const u8* location, u32 address)
|
||||||
{
|
{
|
||||||
|
ARM64XEmitter emit((u8 *)location);
|
||||||
|
emit.MOVI2R(W0, address);
|
||||||
|
emit.MOVI2R(X30, (u64)jit->GetAsmRoutines()->dispatcher);
|
||||||
|
emit.STR(INDEX_UNSIGNED, W0, X29, PPCSTATE_OFF(pc));
|
||||||
|
emit.BR(X30);
|
||||||
|
emit.FlushIcache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,8 +22,8 @@ void JitArm64::ComputeRC(u32 d)
|
|||||||
|
|
||||||
if (gpr.IsImm(d))
|
if (gpr.IsImm(d))
|
||||||
{
|
{
|
||||||
MOVI2R(XA, gpr.GetImm(d));
|
MOVI2R(WA, gpr.GetImm(d));
|
||||||
SXTW(XA, XA);
|
SXTW(XA, WA);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -252,20 +252,9 @@ void JitArm64::cntlzwx(UGeckoInstruction inst)
|
|||||||
int s = inst.RS;
|
int s = inst.RS;
|
||||||
|
|
||||||
if (gpr.IsImm(s))
|
if (gpr.IsImm(s))
|
||||||
{
|
gpr.SetImmediate(a, __builtin_clz(gpr.GetImm(s)));
|
||||||
u32 mask = 0x80000000;
|
|
||||||
u32 i = 0;
|
|
||||||
for (; i < 32; i++, mask >>= 1)
|
|
||||||
{
|
|
||||||
if ((u32)gpr.GetImm(s) & mask)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gpr.SetImmediate(a, i);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
CLZ(gpr.R(a), gpr.R(s));
|
CLZ(gpr.R(a), gpr.R(s));
|
||||||
}
|
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(a);
|
ComputeRC(a);
|
||||||
|
@ -63,45 +63,6 @@ void Arm64RegCache::UnlockRegister(ARM64Reg host_reg)
|
|||||||
// GPR Cache
|
// GPR Cache
|
||||||
void Arm64GPRCache::Start(PPCAnalyst::BlockRegStats &stats)
|
void Arm64GPRCache::Start(PPCAnalyst::BlockRegStats &stats)
|
||||||
{
|
{
|
||||||
// To make this technique easy, let's just work on pairs of even/odd registers
|
|
||||||
// We could do simple odd/even as well to get a few spare temporary registers
|
|
||||||
// but it isn't really needed, we aren't starved for registers
|
|
||||||
for (int reg = 0; reg < 32; reg += 2)
|
|
||||||
{
|
|
||||||
u32 regs_used = (stats.IsUsed(reg) << 1) | stats.IsUsed(reg + 1);
|
|
||||||
switch (regs_used)
|
|
||||||
{
|
|
||||||
case 0x02: // Reg+0 used
|
|
||||||
{
|
|
||||||
ARM64Reg host_reg = GetReg();
|
|
||||||
m_guest_registers[reg].LoadToReg(host_reg);
|
|
||||||
m_emit->LDR(INDEX_UNSIGNED, host_reg, X29, PPCSTATE_OFF(gpr[reg]));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x01: // Reg+1 used
|
|
||||||
{
|
|
||||||
ARM64Reg host_reg = GetReg();
|
|
||||||
m_guest_registers[reg + 1].LoadToReg(host_reg);
|
|
||||||
m_emit->LDR(INDEX_UNSIGNED, host_reg, X29, PPCSTATE_OFF(gpr[reg + 1]));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x03: // Both registers used
|
|
||||||
{
|
|
||||||
// Get a 64bit host register
|
|
||||||
ARM64Reg host_reg = EncodeRegTo64(GetReg());
|
|
||||||
m_guest_registers[reg].LoadToAway(host_reg, REG_LOW);
|
|
||||||
m_guest_registers[reg + 1].LoadToAway(host_reg, REG_HIGH);
|
|
||||||
|
|
||||||
// host_reg is 64bit here.
|
|
||||||
// It'll load both guest_registers in one LDR
|
|
||||||
m_emit->LDR(INDEX_UNSIGNED, host_reg, X29, PPCSTATE_OFF(gpr[reg]));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x00: // Neither used
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Arm64GPRCache::IsCalleeSaved(ARM64Reg reg)
|
bool Arm64GPRCache::IsCalleeSaved(ARM64Reg reg)
|
||||||
@ -116,77 +77,34 @@ bool Arm64GPRCache::IsCalleeSaved(ARM64Reg reg)
|
|||||||
|
|
||||||
void Arm64GPRCache::FlushRegister(u32 preg)
|
void Arm64GPRCache::FlushRegister(u32 preg)
|
||||||
{
|
{
|
||||||
u32 base_reg = preg;
|
|
||||||
OpArg& reg = m_guest_registers[preg];
|
OpArg& reg = m_guest_registers[preg];
|
||||||
if (reg.GetType() == REG_REG)
|
if (reg.GetType() == REG_REG)
|
||||||
{
|
{
|
||||||
ARM64Reg host_reg = reg.GetReg();
|
ARM64Reg host_reg = reg.GetReg();
|
||||||
|
|
||||||
m_emit->STR(INDEX_UNSIGNED, host_reg, X29, PPCSTATE_OFF(gpr[preg]));
|
m_emit->STR(INDEX_UNSIGNED, host_reg, X29, PPCSTATE_OFF(gpr[preg]));
|
||||||
Unlock(host_reg);
|
UnlockRegister(host_reg);
|
||||||
|
|
||||||
reg.Flush();
|
reg.Flush();
|
||||||
}
|
}
|
||||||
else if (reg.GetType() == REG_IMM)
|
else if (reg.GetType() == REG_IMM)
|
||||||
{
|
{
|
||||||
ARM64Reg host_reg = GetReg();
|
if (!reg.GetImm())
|
||||||
|
|
||||||
m_emit->MOVI2R(host_reg, reg.GetImm());
|
|
||||||
m_emit->STR(INDEX_UNSIGNED, host_reg, X29, PPCSTATE_OFF(gpr[preg]));
|
|
||||||
|
|
||||||
Unlock(host_reg);
|
|
||||||
|
|
||||||
reg.Flush();
|
|
||||||
}
|
|
||||||
else if (reg.GetType() == REG_AWAY)
|
|
||||||
{
|
|
||||||
u32 next_reg = 0;
|
|
||||||
if (reg.GetAwayLocation() == REG_LOW)
|
|
||||||
next_reg = base_reg + 1;
|
|
||||||
else
|
|
||||||
next_reg = base_reg - 1;
|
|
||||||
OpArg& reg2 = m_guest_registers[next_reg];
|
|
||||||
ARM64Reg host_reg = reg.GetAwayReg();
|
|
||||||
ARM64Reg host_reg_1 = reg.GetReg();
|
|
||||||
ARM64Reg host_reg_2 = reg2.GetReg();
|
|
||||||
// Flush if either of these shared registers are used.
|
|
||||||
if (host_reg_1 == INVALID_REG)
|
|
||||||
{
|
{
|
||||||
// We never loaded this register
|
m_emit->STR(INDEX_UNSIGNED, WSP, X29, PPCSTATE_OFF(gpr[preg]));
|
||||||
// We've got to test the state of our shared register
|
|
||||||
// Currently it is always reg+1
|
|
||||||
if (host_reg_2 == INVALID_REG)
|
|
||||||
{
|
|
||||||
// We didn't load either of these registers
|
|
||||||
// This can happen in cases where we had to flush register state
|
|
||||||
// or if we hit an interpreted instruction before we could use it
|
|
||||||
// Dump the whole thing in one go and flush both registers
|
|
||||||
|
|
||||||
// 64bit host register will store 2 32bit store registers in one go
|
|
||||||
if (reg.GetAwayLocation() == REG_LOW)
|
|
||||||
m_emit->STR(INDEX_UNSIGNED, host_reg, X29, PPCSTATE_OFF(gpr[base_reg]));
|
|
||||||
else
|
|
||||||
m_emit->STR(INDEX_UNSIGNED, host_reg, X29, PPCSTATE_OFF(gpr[next_reg]));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Alright, bottom register isn't used, but top one is
|
|
||||||
// Only store the top one
|
|
||||||
m_emit->STR(INDEX_UNSIGNED, host_reg_2, X29, PPCSTATE_OFF(gpr[next_reg]));
|
|
||||||
Unlock(host_reg_2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_emit->STR(INDEX_UNSIGNED, host_reg_1, X29, PPCSTATE_OFF(gpr[base_reg]));
|
ARM64Reg host_reg = GetReg();
|
||||||
Unlock(host_reg_1);
|
|
||||||
}
|
|
||||||
// Flush both registers
|
|
||||||
reg.Flush();
|
|
||||||
reg2.Flush();
|
|
||||||
Unlock(DecodeReg(host_reg));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
m_emit->MOVI2R(host_reg, reg.GetImm());
|
||||||
|
m_emit->STR(INDEX_UNSIGNED, host_reg, X29, PPCSTATE_OFF(gpr[preg]));
|
||||||
|
|
||||||
|
UnlockRegister(host_reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
reg.Flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arm64GPRCache::Flush(FlushMode mode, PPCAnalyst::CodeOp* op)
|
void Arm64GPRCache::Flush(FlushMode mode, PPCAnalyst::CodeOp* op)
|
||||||
@ -196,11 +114,7 @@ void Arm64GPRCache::Flush(FlushMode mode, PPCAnalyst::CodeOp* op)
|
|||||||
bool flush = true;
|
bool flush = true;
|
||||||
if (mode == FLUSH_INTERPRETER)
|
if (mode == FLUSH_INTERPRETER)
|
||||||
{
|
{
|
||||||
if (!(op->regsOut[0] == i ||
|
if (!(op->regsOut[i] || op->regsIn[i]))
|
||||||
op->regsOut[1] == i ||
|
|
||||||
op->regsIn[0] == i ||
|
|
||||||
op->regsIn[1] == i ||
|
|
||||||
op->regsIn[2] == i))
|
|
||||||
{
|
{
|
||||||
// This interpreted instruction doesn't use this register
|
// This interpreted instruction doesn't use this register
|
||||||
flush = false;
|
flush = false;
|
||||||
@ -219,39 +133,6 @@ void Arm64GPRCache::Flush(FlushMode mode, PPCAnalyst::CodeOp* op)
|
|||||||
if (flush)
|
if (flush)
|
||||||
FlushRegister(i);
|
FlushRegister(i);
|
||||||
}
|
}
|
||||||
else if (m_guest_registers[i].GetType() == REG_AWAY)
|
|
||||||
{
|
|
||||||
// We are away, that means that this register and the next are stored in a single 64bit register
|
|
||||||
// There is a very good chance that both the registers are out in some "temp" register
|
|
||||||
bool flush_2 = true;
|
|
||||||
if (mode == FLUSH_INTERPRETER)
|
|
||||||
{
|
|
||||||
if (!(op->regsOut[0] == (i + 1) ||
|
|
||||||
op->regsOut[1] == (i + 1) ||
|
|
||||||
op->regsIn[0] == (i + 1) ||
|
|
||||||
op->regsIn[1] == (i + 1) ||
|
|
||||||
op->regsIn[2] == (i + 1)))
|
|
||||||
{
|
|
||||||
// This interpreted instruction doesn't use this register
|
|
||||||
flush_2 = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ARM64Reg host_reg = m_guest_registers[i].GetAwayReg();
|
|
||||||
ARM64Reg host_reg_1 = m_guest_registers[i].GetReg();
|
|
||||||
ARM64Reg host_reg_2 = m_guest_registers[i + 1].GetReg();
|
|
||||||
// Flush if either of these shared registers are used.
|
|
||||||
if (flush ||
|
|
||||||
flush_2 ||
|
|
||||||
!IsCalleeSaved(host_reg) ||
|
|
||||||
!IsCalleeSaved(host_reg_1) ||
|
|
||||||
!IsCalleeSaved(host_reg_2))
|
|
||||||
{
|
|
||||||
FlushRegister(i); // Will flush both pairs of registers
|
|
||||||
}
|
|
||||||
// Skip the next register since we've handled it here
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,71 +155,6 @@ ARM64Reg Arm64GPRCache::R(u32 preg)
|
|||||||
return host_reg;
|
return host_reg;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case REG_AWAY: // Register is away in a shared register
|
|
||||||
{
|
|
||||||
// Let's do the voodoo that we dodo
|
|
||||||
if (reg.GetReg() == INVALID_REG)
|
|
||||||
{
|
|
||||||
// Alright, we need to extract from our away register
|
|
||||||
// To our new 32bit register
|
|
||||||
if (reg.GetAwayLocation() == REG_LOW)
|
|
||||||
{
|
|
||||||
OpArg& upper_reg = m_guest_registers[preg + 1];
|
|
||||||
if (upper_reg.GetType() == REG_REG)
|
|
||||||
{
|
|
||||||
// If the upper reg is already moved away, just claim this one as ours now
|
|
||||||
ARM64Reg host_reg = reg.GetAwayReg();
|
|
||||||
reg.LoadToReg(DecodeReg(host_reg));
|
|
||||||
return host_reg;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Top register is still loaded
|
|
||||||
// Make sure to move to a new register
|
|
||||||
ARM64Reg host_reg = GetReg();
|
|
||||||
ARM64Reg current_reg = reg.GetAwayReg();
|
|
||||||
reg.LoadToReg(host_reg);
|
|
||||||
|
|
||||||
// We are in the low bits
|
|
||||||
// Just move it over to the low bits of the new register
|
|
||||||
m_emit->UBFM(EncodeRegTo64(host_reg), current_reg, 0, 31);
|
|
||||||
return host_reg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
OpArg& lower_reg = m_guest_registers[preg - 1];
|
|
||||||
if (lower_reg.GetType() == REG_REG)
|
|
||||||
{
|
|
||||||
// If the lower register is moved away, claim this one as ours
|
|
||||||
ARM64Reg host_reg = reg.GetAwayReg();
|
|
||||||
reg.LoadToReg(DecodeReg(host_reg));
|
|
||||||
|
|
||||||
// Make sure to move our register from the high bits to the low bits
|
|
||||||
m_emit->UBFM(EncodeRegTo64(host_reg), host_reg, 32, 63);
|
|
||||||
return host_reg;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Load this register in to the new low bits
|
|
||||||
// We are no longer away
|
|
||||||
ARM64Reg host_reg = GetReg();
|
|
||||||
ARM64Reg current_reg = reg.GetAwayReg();
|
|
||||||
reg.LoadToReg(host_reg);
|
|
||||||
|
|
||||||
// We are in the high bits
|
|
||||||
m_emit->UBFM(EncodeRegTo64(host_reg), current_reg, 32, 63);
|
|
||||||
return host_reg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We've already moved to a valid place to work on
|
|
||||||
return reg.GetReg();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case REG_NOTLOADED: // Register isn't loaded at /all/
|
case REG_NOTLOADED: // Register isn't loaded at /all/
|
||||||
{
|
{
|
||||||
// This is a bit annoying. We try to keep these preloaded as much as possible
|
// This is a bit annoying. We try to keep these preloaded as much as possible
|
||||||
@ -357,6 +173,14 @@ ARM64Reg Arm64GPRCache::R(u32 preg)
|
|||||||
return INVALID_REG;
|
return INVALID_REG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Arm64GPRCache::SetImmediate(u32 preg, u32 imm)
|
||||||
|
{
|
||||||
|
OpArg& reg = m_guest_registers[preg];
|
||||||
|
if (reg.GetType() == REG_REG)
|
||||||
|
Unlock(reg.GetReg());
|
||||||
|
reg.LoadToImm(imm);
|
||||||
|
}
|
||||||
|
|
||||||
void Arm64GPRCache::GetAllocationOrder()
|
void Arm64GPRCache::GetAllocationOrder()
|
||||||
{
|
{
|
||||||
// Callee saved registers first in hopes that we will keep everything stored there first
|
// Callee saved registers first in hopes that we will keep everything stored there first
|
||||||
@ -380,8 +204,7 @@ void Arm64GPRCache::FlushMostStaleRegister()
|
|||||||
{
|
{
|
||||||
u32 last_used = m_guest_registers[i].GetLastUsed();
|
u32 last_used = m_guest_registers[i].GetLastUsed();
|
||||||
if (last_used > most_stale_amount &&
|
if (last_used > most_stale_amount &&
|
||||||
m_guest_registers[i].GetType() != REG_IMM &&
|
m_guest_registers[i].GetType() == REG_REG)
|
||||||
m_guest_registers[i].GetType() != REG_NOTLOADED)
|
|
||||||
{
|
{
|
||||||
most_stale_preg = i;
|
most_stale_preg = i;
|
||||||
most_stale_amount = last_used;
|
most_stale_amount = last_used;
|
||||||
|
@ -19,7 +19,6 @@ enum RegType
|
|||||||
REG_NOTLOADED = 0,
|
REG_NOTLOADED = 0,
|
||||||
REG_REG, // Reg type is register
|
REG_REG, // Reg type is register
|
||||||
REG_IMM, // Reg is really a IMM
|
REG_IMM, // Reg is really a IMM
|
||||||
REG_AWAY, // Reg is away
|
|
||||||
};
|
};
|
||||||
enum RegLocation
|
enum RegLocation
|
||||||
{
|
{
|
||||||
@ -56,14 +55,6 @@ public:
|
|||||||
{
|
{
|
||||||
return m_reg;
|
return m_reg;
|
||||||
}
|
}
|
||||||
ARM64Reg GetAwayReg()
|
|
||||||
{
|
|
||||||
return m_away_reg;
|
|
||||||
}
|
|
||||||
RegLocation GetAwayLocation()
|
|
||||||
{
|
|
||||||
return m_away_location;
|
|
||||||
}
|
|
||||||
u32 GetImm()
|
u32 GetImm()
|
||||||
{
|
{
|
||||||
return m_value;
|
return m_value;
|
||||||
@ -72,16 +63,6 @@ public:
|
|||||||
{
|
{
|
||||||
m_type = REG_REG;
|
m_type = REG_REG;
|
||||||
m_reg = reg;
|
m_reg = reg;
|
||||||
|
|
||||||
m_away_reg = INVALID_REG;
|
|
||||||
}
|
|
||||||
void LoadToAway(ARM64Reg reg, RegLocation location)
|
|
||||||
{
|
|
||||||
m_type = REG_AWAY;
|
|
||||||
m_away_reg = reg;
|
|
||||||
m_away_location = location;
|
|
||||||
|
|
||||||
m_reg = INVALID_REG;
|
|
||||||
}
|
}
|
||||||
void LoadToImm(u32 imm)
|
void LoadToImm(u32 imm)
|
||||||
{
|
{
|
||||||
@ -89,14 +70,12 @@ public:
|
|||||||
m_value = imm;
|
m_value = imm;
|
||||||
|
|
||||||
m_reg = INVALID_REG;
|
m_reg = INVALID_REG;
|
||||||
m_away_reg = INVALID_REG;
|
|
||||||
}
|
}
|
||||||
void Flush()
|
void Flush()
|
||||||
{
|
{
|
||||||
// Invalidate any previous information
|
// Invalidate any previous information
|
||||||
m_type = REG_NOTLOADED;
|
m_type = REG_NOTLOADED;
|
||||||
m_reg = INVALID_REG;
|
m_reg = INVALID_REG;
|
||||||
m_away_reg = INVALID_REG;
|
|
||||||
|
|
||||||
// Arbitrarily large value that won't roll over on a lot of increments
|
// Arbitrarily large value that won't roll over on a lot of increments
|
||||||
m_last_used = 0xFFFF;
|
m_last_used = 0xFFFF;
|
||||||
@ -111,12 +90,6 @@ private:
|
|||||||
RegType m_type; // store type
|
RegType m_type; // store type
|
||||||
ARM64Reg m_reg; // host register we are in
|
ARM64Reg m_reg; // host register we are in
|
||||||
|
|
||||||
// For REG_AWAY
|
|
||||||
// Host register that we are away in
|
|
||||||
// This is a 64bit register
|
|
||||||
ARM64Reg m_away_reg;
|
|
||||||
RegLocation m_away_location;
|
|
||||||
|
|
||||||
// For REG_IMM
|
// For REG_IMM
|
||||||
u32 m_value; // IMM value
|
u32 m_value; // IMM value
|
||||||
|
|
||||||
@ -227,7 +200,7 @@ public:
|
|||||||
ARM64Reg R(u32 preg);
|
ARM64Reg R(u32 preg);
|
||||||
|
|
||||||
// Set a register to an immediate
|
// Set a register to an immediate
|
||||||
void SetImmediate(u32 reg, u32 imm) { m_guest_registers[reg].LoadToImm(imm); }
|
void SetImmediate(u32 preg, u32 imm);
|
||||||
|
|
||||||
// Returns if a register is set as an immediate
|
// Returns if a register is set as an immediate
|
||||||
bool IsImm(u32 reg) { return m_guest_registers[reg].GetType() == REG_IMM; }
|
bool IsImm(u32 reg) { return m_guest_registers[reg].GetType() == REG_IMM; }
|
||||||
|
@ -15,6 +15,9 @@ void JitArm64AsmRoutineManager::Generate()
|
|||||||
{
|
{
|
||||||
enterCode = GetCodePtr();
|
enterCode = GetCodePtr();
|
||||||
|
|
||||||
|
SUB(SP, SP, 16);
|
||||||
|
STR(INDEX_UNSIGNED, X30, SP, 0);
|
||||||
|
|
||||||
MOVI2R(X29, (u64)&PowerPC::ppcState);
|
MOVI2R(X29, (u64)&PowerPC::ppcState);
|
||||||
|
|
||||||
dispatcher = GetCodePtr();
|
dispatcher = GetCodePtr();
|
||||||
@ -64,14 +67,20 @@ void JitArm64AsmRoutineManager::Generate()
|
|||||||
|
|
||||||
// Check the state pointer to see if we are exiting
|
// Check the state pointer to see if we are exiting
|
||||||
// Gets checked on every exception check
|
// Gets checked on every exception check
|
||||||
MOVI2R(W0, (u64)PowerPC::GetStatePtr());
|
MOVI2R(X0, (u64)PowerPC::GetStatePtr());
|
||||||
LDR(INDEX_UNSIGNED, W0, W0, 0);
|
LDR(INDEX_UNSIGNED, W0, X0, 0);
|
||||||
FixupBranch Exit = CBNZ(W0);
|
|
||||||
|
CMP(W0, 0);
|
||||||
|
FixupBranch Exit = B(CC_NEQ);
|
||||||
|
|
||||||
B(dispatcher);
|
B(dispatcher);
|
||||||
|
|
||||||
SetJumpTarget(Exit);
|
SetJumpTarget(Exit);
|
||||||
|
|
||||||
|
LDR(INDEX_UNSIGNED, X30, SP, 0);
|
||||||
|
ADD(SP, SP, 16);
|
||||||
|
RET(X30);
|
||||||
|
|
||||||
FlushIcache();
|
FlushIcache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user