diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp index 052d0ea9bf..d8d9e7ca07 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp @@ -63,45 +63,6 @@ void Arm64RegCache::UnlockRegister(ARM64Reg host_reg) // GPR Cache 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) @@ -116,77 +77,34 @@ bool Arm64GPRCache::IsCalleeSaved(ARM64Reg reg) void Arm64GPRCache::FlushRegister(u32 preg) { - u32 base_reg = preg; OpArg& reg = m_guest_registers[preg]; if (reg.GetType() == REG_REG) { ARM64Reg host_reg = reg.GetReg(); m_emit->STR(INDEX_UNSIGNED, host_reg, X29, PPCSTATE_OFF(gpr[preg])); - Unlock(host_reg); + UnlockRegister(host_reg); reg.Flush(); } else if (reg.GetType() == REG_IMM) { - ARM64Reg host_reg = GetReg(); - - 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) + if (!reg.GetImm()) { - // We never loaded this register - // 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); - } + m_emit->STR(INDEX_UNSIGNED, WSP, X29, PPCSTATE_OFF(gpr[preg])); } else { - m_emit->STR(INDEX_UNSIGNED, host_reg_1, X29, PPCSTATE_OFF(gpr[base_reg])); - Unlock(host_reg_1); - } - // Flush both registers - reg.Flush(); - reg2.Flush(); - Unlock(DecodeReg(host_reg)); - } + ARM64Reg host_reg = GetReg(); + 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) @@ -196,11 +114,7 @@ void Arm64GPRCache::Flush(FlushMode mode, PPCAnalyst::CodeOp* op) bool flush = true; if (mode == FLUSH_INTERPRETER) { - if (!(op->regsOut[0] == i || - op->regsOut[1] == i || - op->regsIn[0] == i || - op->regsIn[1] == i || - op->regsIn[2] == i)) + if (!(op->regsOut[i] || op->regsIn[i])) { // This interpreted instruction doesn't use this register flush = false; @@ -219,39 +133,6 @@ void Arm64GPRCache::Flush(FlushMode mode, PPCAnalyst::CodeOp* op) if (flush) 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; } 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/ { // 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; } +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() { // 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(); if (last_used > most_stale_amount && - m_guest_registers[i].GetType() != REG_IMM && - m_guest_registers[i].GetType() != REG_NOTLOADED) + m_guest_registers[i].GetType() == REG_REG) { most_stale_preg = i; most_stale_amount = last_used; diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h index 1eb1afd3d2..9f1c341624 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h @@ -19,7 +19,6 @@ enum RegType REG_NOTLOADED = 0, REG_REG, // Reg type is register REG_IMM, // Reg is really a IMM - REG_AWAY, // Reg is away }; enum RegLocation { @@ -56,14 +55,6 @@ public: { return m_reg; } - ARM64Reg GetAwayReg() - { - return m_away_reg; - } - RegLocation GetAwayLocation() - { - return m_away_location; - } u32 GetImm() { return m_value; @@ -72,16 +63,6 @@ public: { m_type = 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) { @@ -89,14 +70,12 @@ public: m_value = imm; m_reg = INVALID_REG; - m_away_reg = INVALID_REG; } void Flush() { // Invalidate any previous information m_type = REG_NOTLOADED; m_reg = INVALID_REG; - m_away_reg = INVALID_REG; // Arbitrarily large value that won't roll over on a lot of increments m_last_used = 0xFFFF; @@ -111,12 +90,6 @@ private: RegType m_type; // store type 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 u32 m_value; // IMM value @@ -227,7 +200,7 @@ public: ARM64Reg R(u32 preg); // 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 bool IsImm(u32 reg) { return m_guest_registers[reg].GetType() == REG_IMM; }