diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/Jit.cpp b/Source/Core/Core/Src/PowerPC/JitArm32/Jit.cpp index a4988f7c17..6942e1ed2c 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/JitArm32/Jit.cpp @@ -48,13 +48,8 @@ void JitArm::Init() AllocCodeSpace(CODE_SIZE); blocks.Init(); asm_routines.Init(); - // TODO: Investigate why the register cache crashes when only doing Init with - // the pointer to this. Seems for some reason it doesn't set the emitter pointer - // In the class for some reason? gpr.Init(this); - gpr.SetEmitter(this); fpr.Init(this); - fpr.SetEmitter(this); jo.enableBlocklink = true; jo.optimizeGatherPipe = false; } diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_SystemRegisters.cpp b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_SystemRegisters.cpp index 6013d7d66b..0c58b43ff3 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_SystemRegisters.cpp +++ b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_SystemRegisters.cpp @@ -33,7 +33,6 @@ void JitArm::mtspr(UGeckoInstruction inst) JITDISABLE(SystemRegisters) u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); - ARMReg RD = gpr.R(inst.RD); switch (iIndex) { @@ -70,6 +69,7 @@ void JitArm::mtspr(UGeckoInstruction inst) } // OK, this is easy. + ARMReg RD = gpr.R(inst.RD); STR(RD, R9, PPCSTATE_OFF(spr) + iIndex * 4); } void JitArm::mftb(UGeckoInstruction inst) @@ -115,7 +115,6 @@ void JitArm::mfmsr(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(SystemRegisters) - Default(inst); return; LDR(gpr.R(inst.RD), R9, PPCSTATE_OFF(msr)); } diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/JitRegCache.cpp b/Source/Core/Core/Src/PowerPC/JitArm32/JitRegCache.cpp index 2a9aa2154f..5aa92c7e5c 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/JitRegCache.cpp +++ b/Source/Core/Core/Src/PowerPC/JitArm32/JitRegCache.cpp @@ -28,13 +28,7 @@ void ArmRegCache::Init(ARMXEmitter *emitter) emit = emitter; ARMReg *PPCRegs = GetPPCAllocationOrder(NUMPPCREG); ARMReg *Regs = GetAllocationOrder(NUMARMREG); - for(u8 a = 0; a < 32; ++a) - { - // This gives us the memory locations of the gpr registers so we can - // load them. - regs[a].location = (u8*)&PowerPC::ppcState.gpr[a]; - regs[a].UsesLeft = 0; - } + for(u8 a = 0; a < NUMPPCREG; ++a) { ArmCRegs[a].PPCReg = 33; @@ -49,14 +43,8 @@ void ArmRegCache::Init(ARMXEmitter *emitter) } void ArmRegCache::Start(PPCAnalyst::BlockRegStats &stats) { - for(u8 a = 0; a < NUMPPCREG; ++a) - { - ArmCRegs[a].PPCReg = 33; - ArmCRegs[a].LastLoad = 0; - } - for(u8 a = 0; a < 32; ++a) - regs[a].UsesLeft = stats.GetTotalNumAccesses(a); } + ARMReg *ArmRegCache::GetPPCAllocationOrder(int &count) { // This will return us the allocation order of the registers we can use on @@ -94,16 +82,7 @@ ARMReg ArmRegCache::GetReg(bool AutoLock) _assert_msg_(_DYNA_REC_, false, "All available registers are locked dumb dumb"); return R0; } -void ArmRegCache::Lock(ARMReg Reg) -{ - for(u8 RegNum = 0; RegNum < NUMARMREG; ++RegNum) - if(ArmRegs[RegNum].Reg == Reg) - { - _assert_msg_(_DYNA_REC, ArmRegs[RegNum].free, "This register is already locked"); - ArmRegs[RegNum].free = false; - } - _assert_msg_(_DYNA_REC, false, "Register %d can't be used with lock", Reg); -} + void ArmRegCache::Unlock(ARMReg R0, ARMReg R1, ARMReg R2, ARMReg R3) { for(u8 RegNum = 0; RegNum < NUMARMREG; ++RegNum) @@ -118,51 +97,115 @@ void ArmRegCache::Unlock(ARMReg R0, ARMReg R1, ARMReg R2, ARMReg R3) if( R3 != INVALID_REG && ArmRegs[RegNum].Reg == R3) ArmRegs[RegNum].free = true; } } - -ARMReg ArmRegCache::R(u32 preg) +u32 ArmRegCache::GetLeastUsedRegister(bool increment) { u32 HighestUsed = 0; - u8 Num = 0; + u8 lastRegIndex = 0; for(u8 a = 0; a < NUMPPCREG; ++a){ - ++ArmCRegs[a].LastLoad; + if (increment) + ++ArmCRegs[a].LastLoad; if (ArmCRegs[a].LastLoad > HighestUsed) { HighestUsed = ArmCRegs[a].LastLoad; - Num = a; + lastRegIndex = a; } } - // Check if already Loaded - for(u8 a = 0; a < NUMPPCREG; ++a) - if (ArmCRegs[a].PPCReg == preg) - { - ArmCRegs[a].LastLoad = 0; - return ArmCRegs[a].Reg; - } - // Check if we have a free register + return lastRegIndex; +} +bool ArmRegCache::FindFreeRegister(u32 ®index) +{ for (u8 a = 0; a < NUMPPCREG; ++a) if (ArmCRegs[a].PPCReg == 33) { - emit->LDR(ArmCRegs[a].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4); - ArmCRegs[a].PPCReg = preg; - ArmCRegs[a].LastLoad = 0; - return ArmCRegs[a].Reg; + regindex = a; + return true; } + return false; +} + +ARMReg ArmRegCache::R(u32 preg) +{ + if (regs[preg].GetType() == REG_IMM) + { + return BindToRegister(preg); + //asm ("bkpt #1;"); + } + u32 lastRegIndex = GetLeastUsedRegister(true); + + // Check if already Loaded + if(regs[preg].GetType() == REG_REG) + { + u8 a = regs[preg].GetRegIndex(); + ArmCRegs[a].LastLoad = 0; + return ArmCRegs[a].Reg; + } + + // Check if we have a free register + u32 regindex; + if (FindFreeRegister(regindex)) + { + emit->LDR(ArmCRegs[regindex].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4); + ArmCRegs[regindex].PPCReg = preg; + ArmCRegs[regindex].LastLoad = 0; + + regs[preg].LoadToReg(regindex); + return ArmCRegs[regindex].Reg; + } + // Alright, we couldn't get a free space, dump that least used register - emit->STR(ArmCRegs[Num].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[Num].PPCReg * 4); - emit->LDR(ArmCRegs[Num].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4); - ArmCRegs[Num].PPCReg = preg; - ArmCRegs[Num].LastLoad = 0; - return ArmCRegs[Num].Reg; + emit->STR(ArmCRegs[lastRegIndex].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[lastRegIndex].PPCReg * 4); + emit->LDR(ArmCRegs[lastRegIndex].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4); + + regs[ArmCRegs[lastRegIndex].PPCReg].Flush(); + + ArmCRegs[lastRegIndex].PPCReg = preg; + ArmCRegs[lastRegIndex].LastLoad = 0; + + regs[preg].LoadToReg(lastRegIndex); + + return ArmCRegs[lastRegIndex].Reg; +} + +ARMReg ArmRegCache::BindToRegister(u32 preg) +{ + _assert_msg_(DYNA_REC, regs[preg].GetType() == REG_IMM, "Can't BindToRegister with a REG"); + u32 lastRegIndex = GetLeastUsedRegister(false); + u32 freeRegIndex; + if (FindFreeRegister(freeRegIndex)) + { + emit->MOVI2R(ArmCRegs[freeRegIndex].Reg, regs[preg].GetImm()); + ArmCRegs[freeRegIndex].PPCReg = preg; + ArmCRegs[freeRegIndex].LastLoad = 0; + regs[preg].LoadToReg(freeRegIndex); + return ArmCRegs[freeRegIndex].Reg; + } + else + { + emit->STR(ArmCRegs[lastRegIndex].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[lastRegIndex].PPCReg * 4); + emit->MOVI2R(ArmCRegs[lastRegIndex].Reg, regs[preg].GetImm()); + ArmCRegs[lastRegIndex].PPCReg = preg; + ArmCRegs[lastRegIndex].LastLoad = 0; + regs[preg].LoadToReg(lastRegIndex); + return ArmCRegs[lastRegIndex].Reg; + } } void ArmRegCache::Flush() { - for(u8 a = 0; a < NUMPPCREG; ++a) - if (ArmCRegs[a].PPCReg != 33) + for (u8 a = 0; a < 32; ++a) + { + if (regs[a].GetType() == REG_IMM) + BindToRegister(a); + if (regs[a].GetType() == REG_REG) { - emit->STR(ArmCRegs[a].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[a].PPCReg * 4); - ArmCRegs[a].PPCReg = 33; - ArmCRegs[a].LastLoad = 0; + u32 regindex = regs[a].GetRegIndex(); + emit->STR(ArmCRegs[regindex].Reg, R9, PPCSTATE_OFF(gpr) + a * 4); + ArmCRegs[regindex].PPCReg = 33; + ArmCRegs[regindex].LastLoad = 0; + } + + regs[a].Flush(); + } } diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/JitRegCache.h b/Source/Core/Core/Src/PowerPC/JitArm32/JitRegCache.h index 7292ce1581..5b8d0e04d0 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/JitRegCache.h +++ b/Source/Core/Core/Src/PowerPC/JitArm32/JitRegCache.h @@ -35,11 +35,61 @@ using namespace ArmGen; // it // So we have R14, R12, R11, R10 to work with instructions -struct PPCCachedReg +enum RegType { - const u8 *location; - u32 UsesLeft; + REG_NOTLOADED = 0, + REG_REG, + REG_IMM, }; + +class OpArg +{ + private: + class Reg{ + public: + RegType m_type; + u8 m_reg; // index to register + u32 m_value; + Reg() + { + m_type = REG_NOTLOADED; + m_reg = 33; + m_value = 0; + } + } Reg; + + public: + OpArg(){} + + RegType GetType() + { + return Reg.m_type; + } + + u8 GetRegIndex() + { + return Reg.m_reg; + } + u32 GetImm() + { + return Reg.m_value; + } + void LoadToReg(u8 reg) + { + Reg.m_type = REG_REG; + Reg.m_reg = reg; + } + void LoadToImm(u32 imm) + { + Reg.m_type = REG_IMM; + Reg.m_value = imm; + } + void Flush() + { + Reg.m_type = REG_NOTLOADED; + } +}; + struct JRCPPC { u32 PPCReg; // Tied to which PPC Register @@ -55,7 +105,7 @@ struct JRCReg class ArmRegCache { private: - PPCCachedReg regs[32]; + OpArg regs[32]; JRCPPC ArmCRegs[ARMREGS]; JRCReg ArmRegs[ARMREGS]; // Four registers remaining @@ -64,7 +114,9 @@ private: ARMReg *GetAllocationOrder(int &count); ARMReg *GetPPCAllocationOrder(int &count); - + + u32 GetLeastUsedRegister(bool increment); + bool FindFreeRegister(u32 ®index); protected: ARMXEmitter *emit; @@ -74,16 +126,16 @@ public: void Init(ARMXEmitter *emitter); void Start(PPCAnalyst::BlockRegStats &stats); - - void SetEmitter(ARMXEmitter *emitter) {emit = emitter;} ARMReg GetReg(bool AutoLock = true); // Return a ARM register we can use. - void Lock(ARMReg reg); void Unlock(ARMReg R0, ARMReg R1 = INVALID_REG, ARMReg R2 = INVALID_REG, ARMReg R3 = INVALID_REG); void Flush(); ARMReg R(u32 preg); // Returns a cached register - + bool IsImm(u32 preg) { return regs[preg].GetType() == REG_IMM; } + u32 GetImm(u32 preg) { return regs[preg].GetImm(); } + void SetImmediate(u32 preg, u32 imm) { regs[preg].LoadToImm(imm); } + ARMReg BindToRegister(u32 preg); };