diff --git a/Source/Core/Core/PowerPC/JitArm32/JitArm_Integer.cpp b/Source/Core/Core/PowerPC/JitArm32/JitArm_Integer.cpp index 7888e31835..533615a880 100644 --- a/Source/Core/Core/PowerPC/JitArm32/JitArm_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm32/JitArm_Integer.cpp @@ -143,6 +143,7 @@ void JitArm::subfic(UGeckoInstruction inst) else { ARMReg tmp = gpr.GetReg(); + gpr.BindToRegister(d, false); MOVI2R(gpr.R(d), imm); LDRB(tmp, R9, PPCSTATE_OFF(xer_ca)); BIC(tmp, tmp, 1); @@ -252,7 +253,7 @@ void JitArm::arith(UGeckoInstruction inst) Imm[0] = gpr.GetImm(s); } isImm[1] = true; - Imm[1] = inst.UIMM << (shiftedImm ? 16 : 0); + Imm[1] = inst.UIMM; break; case 27: // xoris shiftedImm = true; @@ -353,7 +354,7 @@ void JitArm::arith(UGeckoInstruction inst) break; case 24: case 25: - gpr.SetImmediate(a, Or(Imm[0], Imm[1])); + gpr.SetImmediate(a, Or(Imm[0], Imm[1] << (shiftedImm ? 16 : 0))); dest = a; break; case 26: @@ -445,6 +446,7 @@ void JitArm::arith(UGeckoInstruction inst) { case 7: { + gpr.BindToRegister(d, d == a); ARMReg rA = gpr.GetReg(); RD = gpr.R(d); RA = gpr.R(a); @@ -456,24 +458,42 @@ void JitArm::arith(UGeckoInstruction inst) case 12: case 13: { - ARMReg rA = gpr.GetReg(); + gpr.BindToRegister(d, d == a); RD = gpr.R(d); RA = gpr.R(a); - MOVI2R(rA, Imm[1]); - ADDS(RD, RA, rA); - gpr.Unlock(rA); + + if (Imm[1] < 256) + { + ADDS(RD, RA, Imm[1]); + } + else + { + ARMReg rA = gpr.GetReg(); + MOVI2R(rA, Imm[1]); + ADDS(RD, RA, rA); + gpr.Unlock(rA); + } } break; case 14: case 15: // Arg2 is always Imm if (!isImm[0]) { - ARMReg rA = gpr.GetReg(); + gpr.BindToRegister(d, d == a); RD = gpr.R(d); RA = gpr.R(a); - MOVI2R(rA, Imm[1]); - ADD(RD, RA, rA); - gpr.Unlock(rA); + + if (Imm[1] < 256) + { + ADD(RD, RA, Imm[1]); + } + else + { + ARMReg rA = gpr.GetReg(); + MOVI2R(rA, Imm[1]); + ADD(RD, RA, rA); + gpr.Unlock(rA); + } } else { @@ -484,18 +504,30 @@ void JitArm::arith(UGeckoInstruction inst) case 25: { dest = a; - ARMReg rA = gpr.GetReg(); + gpr.BindToRegister(a, s == a); RS = gpr.R(s); RA = gpr.R(a); - MOVI2R(rA, Imm[1]); - ORR(RA, RS, rA); - gpr.Unlock(rA); + + if (Imm[1] < 256) + { + // Rotation of encoding 8 is the same as << 16 + Operand2 imm(Imm[1], shiftedImm ? 8 : 0); + ORR(RA, RS, imm); + } + else + { + ARMReg rA = gpr.GetReg(); + MOVI2R(rA, Imm[1] << (shiftedImm ? 16 : 0)); + ORR(RA, RS, rA); + gpr.Unlock(rA); + } } break; case 26: case 27: { dest = a; + gpr.BindToRegister(a, s == a); ARMReg rA = gpr.GetReg(); RS = gpr.R(s); RA = gpr.R(a); @@ -509,6 +541,7 @@ void JitArm::arith(UGeckoInstruction inst) case 29: { dest = a; + gpr.BindToRegister(a, s == a); ARMReg rA = gpr.GetReg(); RS = gpr.R(s); RA = gpr.R(a); @@ -522,6 +555,7 @@ void JitArm::arith(UGeckoInstruction inst) { case 24: dest = a; + gpr.BindToRegister(a, a == s || a == b); RA = gpr.R(a); RS = gpr.R(s); RB = gpr.R(b); @@ -529,12 +563,14 @@ void JitArm::arith(UGeckoInstruction inst) break; case 28: dest = a; + gpr.BindToRegister(a, a == s || a == b); RA = gpr.R(a); RS = gpr.R(s); RB = gpr.R(b); ANDS(RA, RS, RB); break; case 40: // subfx + gpr.BindToRegister(d, d == s || d == b); RD = gpr.R(d); RA = gpr.R(a); RB = gpr.R(b); @@ -542,6 +578,7 @@ void JitArm::arith(UGeckoInstruction inst) break; case 60: dest = a; + gpr.BindToRegister(a, a == s || a == b); RA = gpr.R(a); RS = gpr.R(s); RB = gpr.R(b); @@ -549,6 +586,7 @@ void JitArm::arith(UGeckoInstruction inst) break; case 124: dest = a; + gpr.BindToRegister(a, a == s || a == b); RA = gpr.R(a); RS = gpr.R(s); RB = gpr.R(b); @@ -557,6 +595,7 @@ void JitArm::arith(UGeckoInstruction inst) break; case 747: case 235: + gpr.BindToRegister(d, d == a || d == b); RD = gpr.R(d); RA = gpr.R(a); RB = gpr.R(b); @@ -564,6 +603,7 @@ void JitArm::arith(UGeckoInstruction inst) break; case 284: dest = a; + gpr.BindToRegister(a, a == s || a == b); RA = gpr.R(a); RS = gpr.R(s); RB = gpr.R(b); @@ -572,6 +612,7 @@ void JitArm::arith(UGeckoInstruction inst) break; case 316: dest = a; + gpr.BindToRegister(a, a == s || a == b); RA = gpr.R(a); RS = gpr.R(s); RB = gpr.R(b); @@ -581,6 +622,7 @@ void JitArm::arith(UGeckoInstruction inst) { dest = a; ARMReg rA = gpr.GetReg(); + gpr.BindToRegister(a, a == s || a == b); RA = gpr.R(a); RS = gpr.R(s); RB = gpr.R(b); @@ -591,6 +633,7 @@ void JitArm::arith(UGeckoInstruction inst) break; case 444: dest = a; + gpr.BindToRegister(a, a == s || a == b); RA = gpr.R(a); RS = gpr.R(s); RB = gpr.R(b); @@ -598,6 +641,7 @@ void JitArm::arith(UGeckoInstruction inst) break; case 476: dest = a; + gpr.BindToRegister(a, a == s || a == b); RA = gpr.R(a); RS = gpr.R(s); RB = gpr.R(b); @@ -606,6 +650,7 @@ void JitArm::arith(UGeckoInstruction inst) break; case 536: dest = a; + gpr.BindToRegister(a, a == s || a == b); RA = gpr.R(a); RS = gpr.R(s); RB = gpr.R(b); @@ -613,6 +658,7 @@ void JitArm::arith(UGeckoInstruction inst) break; case 792: dest = a; + gpr.BindToRegister(a, a == s || a == b); RA = gpr.R(a); RS = gpr.R(s); RB = gpr.R(b); @@ -621,6 +667,7 @@ void JitArm::arith(UGeckoInstruction inst) case 10: // addcx case 266: case 778: // both addx + gpr.BindToRegister(d, d == a || d == b); RD = gpr.R(d); RA = gpr.R(a); RB = gpr.R(b); @@ -666,6 +713,7 @@ void JitArm::cntlzwx(UGeckoInstruction inst) JITDISABLE(bJITIntegerOff); u32 a = inst.RA, s = inst.RS; + gpr.BindToRegister(a, a == s); ARMReg RA = gpr.R(a); ARMReg RS = gpr.R(s); CLZ(RA, RS); @@ -705,6 +753,8 @@ void JitArm::extshx(UGeckoInstruction inst) return; } + + gpr.BindToRegister(a, a == s); ARMReg rA = gpr.R(a); ARMReg rS = gpr.R(s); SXTH(rA, rS); @@ -726,6 +776,8 @@ void JitArm::extsbx(UGeckoInstruction inst) return; } + + gpr.BindToRegister(a, a == s); ARMReg rA = gpr.R(a); ARMReg rS = gpr.R(s); SXTB(rA, rS); @@ -746,7 +798,14 @@ void JitArm::cmp (UGeckoInstruction inst) return; } - FALLBACK_IF(true); + ARMReg rA = gpr.GetReg(); + ARMReg RA = gpr.R(a); + ARMReg RB = gpr.R(b); + + SUB(rA, RA, RB); + ComputeRC(rA, crf); + + gpr.Unlock(rA); } void JitArm::cmpi(UGeckoInstruction inst) { @@ -759,8 +818,21 @@ void JitArm::cmpi(UGeckoInstruction inst) ComputeRC((s32)gpr.GetImm(a) - inst.SIMM_16, crf); return; } + ARMReg rA = gpr.GetReg(); + ARMReg RA = gpr.R(a); - FALLBACK_IF(true); + if (inst.SIMM_16 >= 0 && inst.SIMM_16 < 256) + { + SUB(rA, RA, inst.SIMM_16); + } + else + { + MOVI2R(rA, inst.SIMM_16); + SUB(rA, RA, rA); + } + ComputeRC(rA, crf); + + gpr.Unlock(rA); } void JitArm::negx(UGeckoInstruction inst) @@ -768,6 +840,7 @@ void JitArm::negx(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITIntegerOff); + gpr.BindToRegister(inst.RD, inst.RD == inst.RA); ARMReg RA = gpr.R(inst.RA); ARMReg RD = gpr.R(inst.RD); @@ -787,6 +860,7 @@ void JitArm::rlwimix(UGeckoInstruction inst) JITDISABLE(bJITIntegerOff); u32 mask = Helper_Mask(inst.MB,inst.ME); + gpr.BindToRegister(inst.RA, inst.RA == inst.RS); ARMReg RA = gpr.R(inst.RA); ARMReg RS = gpr.R(inst.RS); ARMReg rA = gpr.GetReg(); @@ -809,6 +883,7 @@ void JitArm::rlwinmx(UGeckoInstruction inst) JITDISABLE(bJITIntegerOff); u32 mask = Helper_Mask(inst.MB,inst.ME); + gpr.BindToRegister(inst.RA, inst.RA == inst.RS); ARMReg RA = gpr.R(inst.RA); ARMReg RS = gpr.R(inst.RS); ARMReg rA = gpr.GetReg(); @@ -829,6 +904,7 @@ void JitArm::rlwnmx(UGeckoInstruction inst) JITDISABLE(bJITIntegerOff); u32 mask = Helper_Mask(inst.MB,inst.ME); + gpr.BindToRegister(inst.RA, inst.RA == inst.RS || inst.RA == inst.RB); ARMReg RA = gpr.R(inst.RA); ARMReg RS = gpr.R(inst.RS); ARMReg RB = gpr.R(inst.RB); @@ -856,6 +932,7 @@ void JitArm::srawix(UGeckoInstruction inst) int s = inst.RS; int amount = inst.SH; + gpr.BindToRegister(a, a == s); if (amount != 0) { ARMReg RA = gpr.R(a); diff --git a/Source/Core/Core/PowerPC/JitArm32/JitArm_SystemRegisters.cpp b/Source/Core/Core/PowerPC/JitArm32/JitArm_SystemRegisters.cpp index 4946bc4d32..9970f280e6 100644 --- a/Source/Core/Core/PowerPC/JitArm32/JitArm_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/JitArm32/JitArm_SystemRegisters.cpp @@ -132,6 +132,7 @@ void JitArm::mfspr(UGeckoInstruction inst) { case SPR_XER: { + gpr.BindToRegister(inst.RD, false); ARMReg RD = gpr.R(inst.RD); ARMReg tmp = gpr.GetReg(); LDRH(RD, R9, PPCSTATE_OFF(xer_stringctrl)); @@ -150,6 +151,7 @@ void JitArm::mfspr(UGeckoInstruction inst) case SPR_TU: FALLBACK_IF(true); default: + gpr.BindToRegister(inst.RD, false); ARMReg RD = gpr.R(inst.RD); LDR(RD, R9, PPCSTATE_OFF(spr) + iIndex * 4); break; @@ -169,6 +171,7 @@ void JitArm::mfsr(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITSystemRegistersOff); + gpr.BindToRegister(inst.RD, false); LDR(gpr.R(inst.RD), R9, PPCSTATE_OFF(sr[inst.SR])); } @@ -191,6 +194,7 @@ void JitArm::mfmsr(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITSystemRegistersOff); + gpr.BindToRegister(inst.RD, false); LDR(gpr.R(inst.RD), R9, PPCSTATE_OFF(msr)); } diff --git a/Source/Core/Core/PowerPC/JitArm32/JitRegCache.cpp b/Source/Core/Core/PowerPC/JitArm32/JitRegCache.cpp index d82abaca36..e8bc5bb0bf 100644 --- a/Source/Core/Core/PowerPC/JitArm32/JitRegCache.cpp +++ b/Source/Core/Core/PowerPC/JitArm32/JitRegCache.cpp @@ -143,7 +143,7 @@ bool ArmRegCache::FindFreeRegister(u32 ®index) ARMReg ArmRegCache::R(u32 preg) { if (regs[preg].GetType() == REG_IMM) - return BindToRegister(preg); + return BindToRegister(preg, true, true); u32 lastRegIndex = GetLeastUsedRegister(true); @@ -181,31 +181,76 @@ ARMReg ArmRegCache::R(u32 preg) return ArmCRegs[lastRegIndex].Reg; } -ARMReg ArmRegCache::BindToRegister(u32 preg) +void ArmRegCache::BindToRegister(u32 preg, bool doLoad) +{ + BindToRegister(preg, doLoad, false); +} + +ARMReg ArmRegCache::BindToRegister(u32 preg, bool doLoad, bool kill_imm) { - _assert_msg_(DYNA_REC, regs[preg].GetType() == REG_IMM, "Can't BindToRegister with a REG"); u32 lastRegIndex = GetLeastUsedRegister(false); u32 freeRegIndex; - if (FindFreeRegister(freeRegIndex)) + bool found_free = FindFreeRegister(freeRegIndex); + if (regs[preg].GetType() == REG_IMM) { - emit->MOVI2R(ArmCRegs[freeRegIndex].Reg, regs[preg].GetImm()); - ArmCRegs[freeRegIndex].PPCReg = preg; - ArmCRegs[freeRegIndex].LastLoad = 0; - regs[preg].LoadToReg(freeRegIndex); - return ArmCRegs[freeRegIndex].Reg; + if (!kill_imm) + return INVALID_REG; + if (found_free) + { + if (doLoad) + 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); + if (doLoad) + emit->MOVI2R(ArmCRegs[lastRegIndex].Reg, regs[preg].GetImm()); + + regs[ArmCRegs[lastRegIndex].PPCReg].Flush(); + + ArmCRegs[lastRegIndex].PPCReg = preg; + ArmCRegs[lastRegIndex].LastLoad = 0; + + regs[preg].LoadToReg(lastRegIndex); + return ArmCRegs[lastRegIndex].Reg; + } + } + else if (regs[preg].GetType() == REG_NOTLOADED) + { + if (found_free) + { + if (doLoad) + emit->LDR(ArmCRegs[freeRegIndex].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4); + + 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); + + if (doLoad) + 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; + } } else { - emit->STR(ArmCRegs[lastRegIndex].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[lastRegIndex].PPCReg * 4); - emit->MOVI2R(ArmCRegs[lastRegIndex].Reg, regs[preg].GetImm()); - - regs[ArmCRegs[lastRegIndex].PPCReg].Flush(); - - ArmCRegs[lastRegIndex].PPCReg = preg; - ArmCRegs[lastRegIndex].LastLoad = 0; - - regs[preg].LoadToReg(lastRegIndex); - return ArmCRegs[lastRegIndex].Reg; + u8 a = regs[preg].GetRegIndex(); + return ArmCRegs[a].Reg; } } @@ -230,7 +275,7 @@ void ArmRegCache::Flush(FlushMode mode) if (mode == FLUSH_ALL) { // This changes the type over to a REG_REG and gets caught below. - BindToRegister(a); + BindToRegister(a, true, true); } else { diff --git a/Source/Core/Core/PowerPC/JitArm32/JitRegCache.h b/Source/Core/Core/PowerPC/JitArm32/JitRegCache.h index 3b895329d5..7e7acaaf9a 100644 --- a/Source/Core/Core/PowerPC/JitArm32/JitRegCache.h +++ b/Source/Core/Core/PowerPC/JitArm32/JitRegCache.h @@ -110,6 +110,10 @@ private: u32 GetLeastUsedRegister(bool increment); bool FindFreeRegister(u32 ®index); + + // Private function can kill immediates + ArmGen::ARMReg BindToRegister(u32 preg, bool doLoad, bool kill_imm); + protected: ArmGen::ARMXEmitter *emit; @@ -127,5 +131,8 @@ public: bool IsImm(u32 preg) { return regs[preg].GetType() == REG_IMM; } u32 GetImm(u32 preg) { return regs[preg].GetImm(); } void SetImmediate(u32 preg, u32 imm); - ArmGen::ARMReg BindToRegister(u32 preg); + + // Public function doesn't kill immediates + // In reality when you call R(u32) it'll bind an immediate there + void BindToRegister(u32 preg, bool doLoad = true); };