From ad167e7b52e1ea39c910e7a070a37007ff5b873f Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Wed, 30 Apr 2014 00:17:39 -0500 Subject: [PATCH] Adds support to the new PPCAnalyst to the ARM JIT cores. ArmJit32 supports OPTION_CONDITIONAL_CONTINUE with this. --- Source/Core/Core/PowerPC/JitArm32/Jit.cpp | 69 +++++++++---------- Source/Core/Core/PowerPC/JitArm32/Jit.h | 1 + .../Core/PowerPC/JitArm32/JitArm_Branch.cpp | 25 +++---- .../Core/PowerPC/JitArm32/JitArm_Integer.cpp | 4 +- Source/Core/Core/PowerPC/JitArmIL/JitIL.cpp | 44 ++++-------- Source/Core/Core/PowerPC/JitCommon/JitBase.h | 3 + 6 files changed, 63 insertions(+), 83 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm32/Jit.cpp b/Source/Core/Core/PowerPC/JitArm32/Jit.cpp index 80562f5fe8..cdddb4211e 100644 --- a/Source/Core/Core/PowerPC/JitArm32/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm32/Jit.cpp @@ -40,6 +40,11 @@ void JitArm::Init() fpr.Init(this); jo.enableBlocklink = true; jo.optimizeGatherPipe = true; + + code_block.m_stats = &js.st; + code_block.m_gpa = &js.gpa; + code_block.m_fpa = &js.fpa; + analyser.SetOption(PPCAnalyst::PPCAnalyser::OPTION_CONDITIONAL_CONTINUE); } void JitArm::ClearCache() @@ -250,27 +255,27 @@ void JitArm::Trace() void JitArm::PrintDebug(UGeckoInstruction inst, u32 level) { if (level > 0) - printf("Start: %08x OP '%s' Info\n", (u32)GetCodePtr(), PPCTables::GetInstructionName(inst)); + WARN_LOG(DYNA_REC, "Start: %08x OP '%s' Info", (u32)GetCodePtr(), PPCTables::GetInstructionName(inst)); if (level > 1) { GekkoOPInfo* Info = GetOpInfo(inst.hex); - printf("\tOuts\n"); + WARN_LOG(DYNA_REC, "\tOuts"); if (Info->flags & FL_OUT_A) - printf("\t-OUT_A: %x\n", inst.RA); + WARN_LOG(DYNA_REC, "\t-OUT_A: %x", inst.RA); if (Info->flags & FL_OUT_D) - printf("\t-OUT_D: %x\n", inst.RD); - printf("\tIns\n"); + WARN_LOG(DYNA_REC, "\t-OUT_D: %x", inst.RD); + WARN_LOG(DYNA_REC, "\tIns"); // A, AO, B, C, S if (Info->flags & FL_IN_A) - printf("\t-IN_A: %x\n", inst.RA); + WARN_LOG(DYNA_REC, "\t-IN_A: %x", inst.RA); if (Info->flags & FL_IN_A0) - printf("\t-IN_A0: %x\n", inst.RA); + WARN_LOG(DYNA_REC, "\t-IN_A0: %x", inst.RA); if (Info->flags & FL_IN_B) - printf("\t-IN_B: %x\n", inst.RB); + WARN_LOG(DYNA_REC, "\t-IN_B: %x", inst.RB); if (Info->flags & FL_IN_C) - printf("\t-IN_C: %x\n", inst.RC); + WARN_LOG(DYNA_REC, "\t-IN_C: %x", inst.RC); if (Info->flags & FL_IN_S) - printf("\t-IN_S: %x\n", inst.RS); + WARN_LOG(DYNA_REC, "\t-IN_S: %x", inst.RS); } } @@ -298,14 +303,10 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo // Memory exception on instruction fetch bool memory_exception = false; - // A broken block is a block that does not end in a branch - bool broken_block = false; - if (Core::g_CoreStartupParameter.bEnableDebugging) { // Comment out the following to disable breakpoints (speed-up) blockSize = 1; - broken_block = true; Trace(); } @@ -324,8 +325,6 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo } } - - int size = 0; js.isLastInstruction = false; js.blockStart = em_address; js.fifoBytesThisBlock = 0; @@ -333,17 +332,12 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo js.block_flags = 0; js.cancel = false; + u32 nextPC = em_address; // Analyze the block, collect all instructions it is made of (including inlining, // if that is enabled), reorder instructions for optimal performance, and join joinable instructions. - u32 nextPC = em_address; - u32 merged_addresses[32]; - const int capacity_of_merged_addresses = sizeof(merged_addresses) / sizeof(merged_addresses[0]); - int size_of_merged_addresses = 0; if (!memory_exception) - { - // If there is a memory exception inside a block (broken_block==true), compile up to that instruction. - nextPC = PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, broken_block, code_buf, blockSize, merged_addresses, capacity_of_merged_addresses, size_of_merged_addresses); - } + nextPC = analyser.Analyse(em_address, &code_block, code_buf, blockSize); + PPCAnalyst::CodeOp *ops = code_buf->codebuffer; const u8 *start = GetCodePtr(); @@ -398,20 +392,21 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo gpr.Start(js.gpa); fpr.Start(js.fpa); js.downcountAmount = 0; + if (!Core::g_CoreStartupParameter.bEnableDebugging) - { - for (int i = 0; i < size_of_merged_addresses; ++i) - { - const u32 address = merged_addresses[i]; - js.downcountAmount += PatchEngine::GetSpeedhackCycles(address); - } - } + js.downcountAmount += PatchEngine::GetSpeedhackCycles(em_address); js.skipnext = false; - js.blockSize = size; + js.blockSize = code_block.m_instructions; js.compilerPC = nextPC; + + const int DEBUG_OUTPUT = 0; + + if (DEBUG_OUTPUT) + WARN_LOG(DYNA_REC, "-------0x%08x-------", em_address); + // Translate instructions - for (int i = 0; i < (int)size; i++) + for (u32 i = 0; i < code_block.m_instructions; i++) { js.compilerPC = ops[i].address; js.op = &ops[i]; @@ -419,7 +414,7 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo const GekkoOPInfo *opinfo = ops[i].opinfo; js.downcountAmount += opinfo->numCycles; - if (i == (int)size - 1) + if (i == (code_block.m_instructions - 1)) { // WARNING - cmp->branch merging will screw this up. js.isLastInstruction = true; @@ -468,7 +463,7 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo } if (!ops[i].skip) { - PrintDebug(ops[i].inst, 0); + PrintDebug(ops[i].inst, DEBUG_OUTPUT); if (js.memcheck && (opinfo->flags & FL_USE_FPU)) { // Don't do this yet @@ -485,7 +480,7 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo } if (memory_exception) BKPT(0x500); - if (broken_block) + if (code_block.m_broken) { printf("Broken Block going to 0x%08x\n", nextPC); WriteExit(nextPC); @@ -493,7 +488,7 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo b->flags = js.block_flags; b->codeSize = (u32)(GetCodePtr() - normalEntry); - b->originalSize = size; + b->originalSize = code_block.m_instructions; FlushIcache(); return start; } diff --git a/Source/Core/Core/PowerPC/JitArm32/Jit.h b/Source/Core/Core/PowerPC/JitArm32/Jit.h index 163c1a3fc1..30681d63e5 100644 --- a/Source/Core/Core/PowerPC/JitArm32/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm32/Jit.h @@ -42,6 +42,7 @@ private: ArmFPRCache fpr; PPCAnalyst::CodeBuffer code_buffer; + void DoDownCount(); void PrintDebug(UGeckoInstruction inst, u32 level); diff --git a/Source/Core/Core/PowerPC/JitArm32/JitArm_Branch.cpp b/Source/Core/Core/PowerPC/JitArm32/JitArm_Branch.cpp index 8a45349066..6cd413a941 100644 --- a/Source/Core/Core/PowerPC/JitArm32/JitArm_Branch.cpp +++ b/Source/Core/Core/PowerPC/JitArm32/JitArm_Branch.cpp @@ -149,7 +149,6 @@ void JitArm::bcx(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITBranchOff) // USES_CR - _assert_msg_(DYNA_REC, js.isLastInstruction, "bcx not last instruction of block"); gpr.Flush(); fpr.Flush(); @@ -203,7 +202,8 @@ void JitArm::bcx(UGeckoInstruction inst) if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) SetJumpTarget( pCTRDontBranch ); - WriteExit(js.compilerPC + 4); + if (!analyser.HasOption(PPCAnalyst::PPCAnalyser::OPTION_CONDITIONAL_CONTINUE)) + WriteExit(js.compilerPC + 4); } void JitArm::bcctrx(UGeckoInstruction inst) { @@ -265,25 +265,16 @@ void JitArm::bcctrx(UGeckoInstruction inst) WriteExitDestInR(rA); SetJumpTarget(b); - WriteExit(js.compilerPC + 4); + + if (!analyser.HasOption(PPCAnalyst::PPCAnalyser::OPTION_CONDITIONAL_CONTINUE)) + WriteExit(js.compilerPC + 4); } } void JitArm::bclrx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITBranchOff) - if (!js.isLastInstruction && - (inst.BO & (1 << 4)) && (inst.BO & (1 << 2))) { - if (inst.LK) - { - ARMReg rA = gpr.GetReg(false); - u32 Jumpto = js.compilerPC + 4; - MOVI2R(rA, Jumpto); - STR(rA, R9, PPCSTATE_OFF(spr[SPR_LR])); - // ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4); - } - return; - } + gpr.Flush(); fpr.Flush(); @@ -342,5 +333,7 @@ void JitArm::bclrx(UGeckoInstruction inst) SetJumpTarget( pConditionDontBranch ); if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) SetJumpTarget( pCTRDontBranch ); - WriteExit(js.compilerPC + 4); + + if (!analyser.HasOption(PPCAnalyst::PPCAnalyser::OPTION_CONDITIONAL_CONTINUE)) + WriteExit(js.compilerPC + 4); } diff --git a/Source/Core/Core/PowerPC/JitArm32/JitArm_Integer.cpp b/Source/Core/Core/PowerPC/JitArm32/JitArm_Integer.cpp index 12c5976d7a..71295ac860 100644 --- a/Source/Core/Core/PowerPC/JitArm32/JitArm_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm32/JitArm_Integer.cpp @@ -1014,7 +1014,9 @@ void JitArm::twx(UGeckoInstruction inst) SetJumpTarget(exit3); SetJumpTarget(exit4); SetJumpTarget(exit5); - WriteExit(js.compilerPC + 4); + + if (!analyser.HasOption(PPCAnalyst::PPCAnalyser::OPTION_CONDITIONAL_CONTINUE)) + WriteExit(js.compilerPC + 4); gpr.Unlock(RA, RB); } diff --git a/Source/Core/Core/PowerPC/JitArmIL/JitIL.cpp b/Source/Core/Core/PowerPC/JitArmIL/JitIL.cpp index 5db50b6399..91754f6d69 100644 --- a/Source/Core/Core/PowerPC/JitArmIL/JitIL.cpp +++ b/Source/Core/Core/PowerPC/JitArmIL/JitIL.cpp @@ -34,6 +34,10 @@ void JitArmIL::Init() AllocCodeSpace(CODE_SIZE); blocks.Init(); asm_routines.Init(); + + code_block.m_stats = &js.st; + code_block.m_gpa = &js.gpa; + code_block.m_fpa = &js.fpa; } void JitArmIL::ClearCache() @@ -202,14 +206,10 @@ const u8* JitArmIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB // Memory exception on instruction fetch bool memory_exception = false; - // A broken block is a block that does not end in a branch - bool broken_block = false; - if (Core::g_CoreStartupParameter.bEnableDebugging) { // Comment out the following to disable breakpoints (speed-up) blockSize = 1; - broken_block = true; } if (em_address == 0) @@ -228,7 +228,6 @@ const u8* JitArmIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB } - int size = 0; js.isLastInstruction = false; js.blockStart = em_address; js.fifoBytesThisBlock = 0; @@ -236,17 +235,12 @@ const u8* JitArmIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB js.block_flags = 0; js.cancel = false; + u32 nextPC = em_address; // Analyze the block, collect all instructions it is made of (including inlining, // if that is enabled), reorder instructions for optimal performance, and join joinable instructions. - u32 nextPC = em_address; - u32 merged_addresses[32]; - const int capacity_of_merged_addresses = sizeof(merged_addresses) / sizeof(merged_addresses[0]); - int size_of_merged_addresses = 0; if (!memory_exception) - { - // If there is a memory exception inside a block (broken_block==true), compile up to that instruction. - nextPC = PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, broken_block, code_buf, blockSize, merged_addresses, capacity_of_merged_addresses, size_of_merged_addresses); - } + nextPC = analyser.Analyse(em_address, &code_block, code_buf, blockSize); + PPCAnalyst::CodeOp *ops = code_buf->codebuffer; const u8 *start = GetCodePtr(); @@ -271,7 +265,7 @@ const u8* JitArmIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB u64 codeHash = -1; { // For profiling and IR Writer - for (int i = 0; i < (int)size; i++) + for (u32 i = 0; i < code_block.m_instructions; i++) { const u64 inst = ops[i].inst.hex; // Ported from boost::hash @@ -289,19 +283,13 @@ const u8* JitArmIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB js.downcountAmount = 0; if (!Core::g_CoreStartupParameter.bEnableDebugging) - { - for (int i = 0; i < size_of_merged_addresses; ++i) - { - const u32 address = merged_addresses[i]; - js.downcountAmount += PatchEngine::GetSpeedhackCycles(address); - } - } + js.downcountAmount += PatchEngine::GetSpeedhackCycles(em_address); js.skipnext = false; - js.blockSize = size; + js.blockSize = code_block.m_instructions; js.compilerPC = nextPC; // Translate instructions - for (int i = 0; i < (int)size; i++) + for (u32 i = 0; i < code_block.m_instructions; i++) { js.compilerPC = ops[i].address; js.op = &ops[i]; @@ -309,7 +297,7 @@ const u8* JitArmIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB const GekkoOPInfo *opinfo = ops[i].opinfo; js.downcountAmount += opinfo->numCycles; - if (i == (int)size - 1) + if (i == (code_block.m_instructions - 1)) { // WARNING - cmp->branch merging will screw this up. js.isLastInstruction = true; @@ -348,21 +336,19 @@ const u8* JitArmIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB } if (memory_exception) BKPT(0x500); - if (broken_block) + + if (code_block.m_broken) { printf("Broken Block going to 0x%08x\n", nextPC); WriteExit(nextPC); } // Perform actual code generation - WriteCode(nextPC); b->flags = js.block_flags; b->codeSize = (u32)(GetCodePtr() - normalEntry); - b->originalSize = size; + b->originalSize = code_block.m_instructions;; - { - } FlushIcache(); return start; diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBase.h b/Source/Core/Core/PowerPC/JitCommon/JitBase.h index 9bebdf1411..27f307dad9 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBase.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitBase.h @@ -83,6 +83,9 @@ protected: std::unordered_set fifoWriteAddresses; }; + PPCAnalyst::CodeBlock code_block; + PPCAnalyst::PPCAnalyser analyser; + public: // This should probably be removed from public: JitOptions jo;