From dc83c8912f5ff2e474c59bdef6c67b3c7c9c70d4 Mon Sep 17 00:00:00 2001 From: degasus Date: Sun, 28 Jun 2015 11:06:16 +0200 Subject: [PATCH 1/3] JitArm64: Support branching fallbacks --- Source/Core/Core/ConfigManager.cpp | 1 + Source/Core/Core/PowerPC/JitArm64/Jit.cpp | 35 +++++++++++++++++++ .../Core/PowerPC/JitArm64/JitArm64_Branch.cpp | 6 ++++ .../JitArm64/JitArm64_SystemRegisters.cpp | 4 +-- 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 75f047129d..bace9b7971 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -621,6 +621,7 @@ void SConfig::LoadDefaults() bJITIntegerOff = false; bJITPairedOff = false; bJITSystemRegistersOff = false; + bJITBranchOff = false; m_strName = "NONE"; m_strUniqueID = "00000000"; diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index b968aeacf9..a658252043 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -51,10 +51,45 @@ void JitArm64::FallBackToInterpreter(UGeckoInstruction inst) { gpr.Flush(FlushMode::FLUSH_INTERPRETER, js.op); fpr.Flush(FlushMode::FLUSH_INTERPRETER, js.op); + + if (js.op->opinfo->flags & FL_ENDBLOCK) + { + // also flush the program counter + ARM64Reg WA = gpr.GetReg(); + MOVI2R(WA, js.compilerPC); + STR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(pc)); + ADD(WA, WA, 4); + STR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(npc)); + gpr.Unlock(WA); + } + Interpreter::_interpreterInstruction instr = GetInterpreterOp(inst); MOVI2R(W0, inst.hex); MOVI2R(X30, (u64)instr); BLR(X30); + + if (js.op->opinfo->flags & FL_ENDBLOCK) + { + if (js.isLastInstruction) + { + ARM64Reg WA = gpr.GetReg(); + LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(npc)); + WriteExceptionExit(WA); + } + else + { + // only exit if ppcstate.npc was changed + ARM64Reg WA = gpr.GetReg(); + LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(npc)); + ARM64Reg WB = gpr.GetReg(); + MOVI2R(WB, js.compilerPC + 4); + CMP(WB, WA); + gpr.Unlock(WB); + FixupBranch c = B(CC_EQ); + WriteExceptionExit(WA); + SetJumpTarget(c); + } + } } void JitArm64::HLEFunction(UGeckoInstruction inst) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp index 8efd81e0f1..2abe7d1016 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp @@ -18,6 +18,7 @@ using namespace Arm64Gen; void JitArm64::sc(UGeckoInstruction inst) { INSTRUCTION_START + JITDISABLE(bJITBranchOff); gpr.Flush(FlushMode::FLUSH_ALL); fpr.Flush(FlushMode::FLUSH_ALL); @@ -38,6 +39,7 @@ void JitArm64::sc(UGeckoInstruction inst) void JitArm64::rfi(UGeckoInstruction inst) { INSTRUCTION_START + JITDISABLE(bJITBranchOff); gpr.Flush(FlushMode::FLUSH_ALL); fpr.Flush(FlushMode::FLUSH_ALL); @@ -78,6 +80,7 @@ void JitArm64::rfi(UGeckoInstruction inst) void JitArm64::bx(UGeckoInstruction inst) { INSTRUCTION_START + JITDISABLE(bJITBranchOff); gpr.Flush(FlushMode::FLUSH_ALL); fpr.Flush(FlushMode::FLUSH_ALL); @@ -115,6 +118,7 @@ void JitArm64::bx(UGeckoInstruction inst) void JitArm64::bcx(UGeckoInstruction inst) { INSTRUCTION_START + JITDISABLE(bJITBranchOff); ARM64Reg WA = gpr.GetReg(); FixupBranch pCTRDontBranch; @@ -173,6 +177,7 @@ void JitArm64::bcx(UGeckoInstruction inst) void JitArm64::bcctrx(UGeckoInstruction inst) { INSTRUCTION_START + JITDISABLE(bJITBranchOff); // bcctrx doesn't decrement and/or test CTR _assert_msg_(DYNA_REC, inst.BO_2 & BO_DONT_DECREMENT_FLAG, "bcctrx with decrement and test CTR option is invalid!"); @@ -212,6 +217,7 @@ void JitArm64::bcctrx(UGeckoInstruction inst) void JitArm64::bclrx(UGeckoInstruction inst) { INSTRUCTION_START + JITDISABLE(bJITBranchOff); ARM64Reg WA = gpr.GetReg(); FixupBranch pCTRDontBranch; diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp index 72e42c1769..212c12fa8c 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp @@ -48,8 +48,7 @@ FixupBranch JitArm64::JumpIfCRFieldBit(int field, int bit, bool jump_if_set) void JitArm64::mtmsr(UGeckoInstruction inst) { INSTRUCTION_START - // Don't interpret this, if we do we get thrown out - //JITDISABLE(bJITSystemRegistersOff) + JITDISABLE(bJITSystemRegistersOff); gpr.BindToRegister(inst.RS, true); STR(INDEX_UNSIGNED, gpr.R(inst.RS), X29, PPCSTATE_OFF(msr)); @@ -143,6 +142,7 @@ void JitArm64::mtsrin(UGeckoInstruction inst) void JitArm64::twx(UGeckoInstruction inst) { INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); s32 a = inst.RA; From 0054c4e0d9799765cdeb99f117fb664aa9d19c84 Mon Sep 17 00:00:00 2001 From: degasus Date: Sun, 28 Jun 2015 18:40:24 +0200 Subject: [PATCH 2/3] JitArm64: Drop icbi instruction It was already just a fallback + exit. Now we emit the exit for all affected fallbacks. --- Source/Core/Core/PowerPC/JitArm64/Jit.h | 1 - Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp | 9 --------- Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp | 2 +- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h index aa9f43add3..6b2d0c3fe8 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h @@ -114,7 +114,6 @@ public: void mtspr(UGeckoInstruction inst); // LoadStore - void icbi(UGeckoInstruction inst); void lXX(UGeckoInstruction inst); void stX(UGeckoInstruction inst); void lmw(UGeckoInstruction inst); diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp index 9739fb35c1..19433dcda0 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp @@ -18,15 +18,6 @@ using namespace Arm64Gen; -void JitArm64::icbi(UGeckoInstruction inst) -{ - gpr.Flush(FlushMode::FLUSH_ALL); - fpr.Flush(FlushMode::FLUSH_ALL); - - FallBackToInterpreter(inst); - WriteExit(js.compilerPC + 4); -} - void JitArm64::SafeLoadToReg(u32 dest, s32 addr, s32 offsetReg, u32 flags, s32 offset, bool update) { // We want to make sure to not get LR as a temp register diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp index fe3bb519a4..7bf211bdc5 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp @@ -302,7 +302,7 @@ static GekkoOPTemplate table31[] = {4, &JitArm64::twx}, // tw {598, &JitArm64::DoNothing}, // sync - {982, &JitArm64::icbi}, // icbi + {982, &JitArm64::FallBackToInterpreter}, // icbi // Unused instructions on GC {310, &JitArm64::FallBackToInterpreter}, // eciwx From 245a639e2c729af3f9ef22a7d1d36e2b85d79aa9 Mon Sep 17 00:00:00 2001 From: degasus Date: Sun, 28 Jun 2015 20:27:50 +0200 Subject: [PATCH 3/3] JitArm64: Partially fallback on bcctrx No need to assert, fallbacks on branching instructions now works fine. --- .../Core/PowerPC/JitArm64/JitArm64_Branch.cpp | 51 +++++++++---------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp index 2abe7d1016..4dfd88b92e 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp @@ -179,39 +179,34 @@ void JitArm64::bcctrx(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITBranchOff); + // Rare condition seen in (just some versions of?) Nintendo's NES Emulator + // BO_2 == 001zy -> b if false + // BO_2 == 011zy -> b if true + FALLBACK_IF(!(inst.BO_2 & BO_DONT_CHECK_CONDITION)); + // bcctrx doesn't decrement and/or test CTR _assert_msg_(DYNA_REC, inst.BO_2 & BO_DONT_DECREMENT_FLAG, "bcctrx with decrement and test CTR option is invalid!"); - if (inst.BO_2 & BO_DONT_CHECK_CONDITION) + // BO_2 == 1z1zz -> b always + + //NPC = CTR & 0xfffffffc; + gpr.Flush(FlushMode::FLUSH_ALL); + fpr.Flush(FlushMode::FLUSH_ALL); + + if (inst.LK_3) { - // BO_2 == 1z1zz -> b always - - //NPC = CTR & 0xfffffffc; - gpr.Flush(FlushMode::FLUSH_ALL); - fpr.Flush(FlushMode::FLUSH_ALL); - - if (inst.LK_3) - { - ARM64Reg WB = gpr.GetReg(); - u32 Jumpto = js.compilerPC + 4; - MOVI2R(WB, Jumpto); - STR(INDEX_UNSIGNED, WB, X29, PPCSTATE_OFF(spr[SPR_LR])); - gpr.Unlock(WB); - } - - ARM64Reg WA = gpr.GetReg(); - - LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(spr[SPR_CTR])); - AND(WA, WA, 30, 29); // Wipe the bottom 2 bits. - WriteExitDestInR(WA); - } - else - { - // Rare condition seen in (just some versions of?) Nintendo's NES Emulator - // BO_2 == 001zy -> b if false - // BO_2 == 011zy -> b if true - _assert_msg_(DYNA_REC, false, "Haven't implemented rare form of bcctrx yet"); + ARM64Reg WB = gpr.GetReg(); + u32 Jumpto = js.compilerPC + 4; + MOVI2R(WB, Jumpto); + STR(INDEX_UNSIGNED, WB, X29, PPCSTATE_OFF(spr[SPR_LR])); + gpr.Unlock(WB); } + + ARM64Reg WA = gpr.GetReg(); + + LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(spr[SPR_CTR])); + AND(WA, WA, 30, 29); // Wipe the bottom 2 bits. + WriteExitDestInR(WA); } void JitArm64::bclrx(UGeckoInstruction inst)