Adds support to the new PPCAnalyst to the ARM JIT cores.

ArmJit32 supports OPTION_CONDITIONAL_CONTINUE with this.
This commit is contained in:
Ryan Houdek 2014-04-30 00:17:39 -05:00
parent da2ed2e17d
commit ad167e7b52
6 changed files with 63 additions and 83 deletions

View File

@ -40,6 +40,11 @@ void JitArm::Init()
fpr.Init(this); fpr.Init(this);
jo.enableBlocklink = true; jo.enableBlocklink = true;
jo.optimizeGatherPipe = 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() void JitArm::ClearCache()
@ -250,27 +255,27 @@ void JitArm::Trace()
void JitArm::PrintDebug(UGeckoInstruction inst, u32 level) void JitArm::PrintDebug(UGeckoInstruction inst, u32 level)
{ {
if (level > 0) 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) if (level > 1)
{ {
GekkoOPInfo* Info = GetOpInfo(inst.hex); GekkoOPInfo* Info = GetOpInfo(inst.hex);
printf("\tOuts\n"); WARN_LOG(DYNA_REC, "\tOuts");
if (Info->flags & FL_OUT_A) 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) if (Info->flags & FL_OUT_D)
printf("\t-OUT_D: %x\n", inst.RD); WARN_LOG(DYNA_REC, "\t-OUT_D: %x", inst.RD);
printf("\tIns\n"); WARN_LOG(DYNA_REC, "\tIns");
// A, AO, B, C, S // A, AO, B, C, S
if (Info->flags & FL_IN_A) 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) 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) 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) 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) 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 // Memory exception on instruction fetch
bool memory_exception = false; 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) if (Core::g_CoreStartupParameter.bEnableDebugging)
{ {
// Comment out the following to disable breakpoints (speed-up) // Comment out the following to disable breakpoints (speed-up)
blockSize = 1; blockSize = 1;
broken_block = true;
Trace(); Trace();
} }
@ -324,8 +325,6 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
} }
} }
int size = 0;
js.isLastInstruction = false; js.isLastInstruction = false;
js.blockStart = em_address; js.blockStart = em_address;
js.fifoBytesThisBlock = 0; js.fifoBytesThisBlock = 0;
@ -333,17 +332,12 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
js.block_flags = 0; js.block_flags = 0;
js.cancel = false; js.cancel = false;
u32 nextPC = em_address;
// Analyze the block, collect all instructions it is made of (including inlining, // 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. // 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 (!memory_exception)
{ nextPC = analyser.Analyse(em_address, &code_block, code_buf, blockSize);
// 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);
}
PPCAnalyst::CodeOp *ops = code_buf->codebuffer; PPCAnalyst::CodeOp *ops = code_buf->codebuffer;
const u8 *start = GetCodePtr(); const u8 *start = GetCodePtr();
@ -398,20 +392,21 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
gpr.Start(js.gpa); gpr.Start(js.gpa);
fpr.Start(js.fpa); fpr.Start(js.fpa);
js.downcountAmount = 0; js.downcountAmount = 0;
if (!Core::g_CoreStartupParameter.bEnableDebugging) if (!Core::g_CoreStartupParameter.bEnableDebugging)
{ js.downcountAmount += PatchEngine::GetSpeedhackCycles(em_address);
for (int i = 0; i < size_of_merged_addresses; ++i)
{
const u32 address = merged_addresses[i];
js.downcountAmount += PatchEngine::GetSpeedhackCycles(address);
}
}
js.skipnext = false; js.skipnext = false;
js.blockSize = size; js.blockSize = code_block.m_instructions;
js.compilerPC = nextPC; js.compilerPC = nextPC;
const int DEBUG_OUTPUT = 0;
if (DEBUG_OUTPUT)
WARN_LOG(DYNA_REC, "-------0x%08x-------", em_address);
// Translate instructions // 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.compilerPC = ops[i].address;
js.op = &ops[i]; 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; const GekkoOPInfo *opinfo = ops[i].opinfo;
js.downcountAmount += opinfo->numCycles; js.downcountAmount += opinfo->numCycles;
if (i == (int)size - 1) if (i == (code_block.m_instructions - 1))
{ {
// WARNING - cmp->branch merging will screw this up. // WARNING - cmp->branch merging will screw this up.
js.isLastInstruction = true; js.isLastInstruction = true;
@ -468,7 +463,7 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
} }
if (!ops[i].skip) if (!ops[i].skip)
{ {
PrintDebug(ops[i].inst, 0); PrintDebug(ops[i].inst, DEBUG_OUTPUT);
if (js.memcheck && (opinfo->flags & FL_USE_FPU)) if (js.memcheck && (opinfo->flags & FL_USE_FPU))
{ {
// Don't do this yet // Don't do this yet
@ -485,7 +480,7 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
} }
if (memory_exception) if (memory_exception)
BKPT(0x500); BKPT(0x500);
if (broken_block) if (code_block.m_broken)
{ {
printf("Broken Block going to 0x%08x\n", nextPC); printf("Broken Block going to 0x%08x\n", nextPC);
WriteExit(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->flags = js.block_flags;
b->codeSize = (u32)(GetCodePtr() - normalEntry); b->codeSize = (u32)(GetCodePtr() - normalEntry);
b->originalSize = size; b->originalSize = code_block.m_instructions;
FlushIcache(); FlushIcache();
return start; return start;
} }

View File

@ -42,6 +42,7 @@ private:
ArmFPRCache fpr; ArmFPRCache fpr;
PPCAnalyst::CodeBuffer code_buffer; PPCAnalyst::CodeBuffer code_buffer;
void DoDownCount(); void DoDownCount();
void PrintDebug(UGeckoInstruction inst, u32 level); void PrintDebug(UGeckoInstruction inst, u32 level);

View File

@ -149,7 +149,6 @@ void JitArm::bcx(UGeckoInstruction inst)
INSTRUCTION_START INSTRUCTION_START
JITDISABLE(bJITBranchOff) JITDISABLE(bJITBranchOff)
// USES_CR // USES_CR
_assert_msg_(DYNA_REC, js.isLastInstruction, "bcx not last instruction of block");
gpr.Flush(); gpr.Flush();
fpr.Flush(); fpr.Flush();
@ -203,7 +202,8 @@ void JitArm::bcx(UGeckoInstruction inst)
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
SetJumpTarget( pCTRDontBranch ); SetJumpTarget( pCTRDontBranch );
WriteExit(js.compilerPC + 4); if (!analyser.HasOption(PPCAnalyst::PPCAnalyser::OPTION_CONDITIONAL_CONTINUE))
WriteExit(js.compilerPC + 4);
} }
void JitArm::bcctrx(UGeckoInstruction inst) void JitArm::bcctrx(UGeckoInstruction inst)
{ {
@ -265,25 +265,16 @@ void JitArm::bcctrx(UGeckoInstruction inst)
WriteExitDestInR(rA); WriteExitDestInR(rA);
SetJumpTarget(b); SetJumpTarget(b);
WriteExit(js.compilerPC + 4);
if (!analyser.HasOption(PPCAnalyst::PPCAnalyser::OPTION_CONDITIONAL_CONTINUE))
WriteExit(js.compilerPC + 4);
} }
} }
void JitArm::bclrx(UGeckoInstruction inst) void JitArm::bclrx(UGeckoInstruction inst)
{ {
INSTRUCTION_START INSTRUCTION_START
JITDISABLE(bJITBranchOff) 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(); gpr.Flush();
fpr.Flush(); fpr.Flush();
@ -342,5 +333,7 @@ void JitArm::bclrx(UGeckoInstruction inst)
SetJumpTarget( pConditionDontBranch ); SetJumpTarget( pConditionDontBranch );
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
SetJumpTarget( pCTRDontBranch ); SetJumpTarget( pCTRDontBranch );
WriteExit(js.compilerPC + 4);
if (!analyser.HasOption(PPCAnalyst::PPCAnalyser::OPTION_CONDITIONAL_CONTINUE))
WriteExit(js.compilerPC + 4);
} }

View File

@ -1014,7 +1014,9 @@ void JitArm::twx(UGeckoInstruction inst)
SetJumpTarget(exit3); SetJumpTarget(exit3);
SetJumpTarget(exit4); SetJumpTarget(exit4);
SetJumpTarget(exit5); SetJumpTarget(exit5);
WriteExit(js.compilerPC + 4);
if (!analyser.HasOption(PPCAnalyst::PPCAnalyser::OPTION_CONDITIONAL_CONTINUE))
WriteExit(js.compilerPC + 4);
gpr.Unlock(RA, RB); gpr.Unlock(RA, RB);
} }

View File

@ -34,6 +34,10 @@ void JitArmIL::Init()
AllocCodeSpace(CODE_SIZE); AllocCodeSpace(CODE_SIZE);
blocks.Init(); blocks.Init();
asm_routines.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() void JitArmIL::ClearCache()
@ -202,14 +206,10 @@ const u8* JitArmIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB
// Memory exception on instruction fetch // Memory exception on instruction fetch
bool memory_exception = false; 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) if (Core::g_CoreStartupParameter.bEnableDebugging)
{ {
// Comment out the following to disable breakpoints (speed-up) // Comment out the following to disable breakpoints (speed-up)
blockSize = 1; blockSize = 1;
broken_block = true;
} }
if (em_address == 0) 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.isLastInstruction = false;
js.blockStart = em_address; js.blockStart = em_address;
js.fifoBytesThisBlock = 0; js.fifoBytesThisBlock = 0;
@ -236,17 +235,12 @@ const u8* JitArmIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB
js.block_flags = 0; js.block_flags = 0;
js.cancel = false; js.cancel = false;
u32 nextPC = em_address;
// Analyze the block, collect all instructions it is made of (including inlining, // 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. // 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 (!memory_exception)
{ nextPC = analyser.Analyse(em_address, &code_block, code_buf, blockSize);
// 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);
}
PPCAnalyst::CodeOp *ops = code_buf->codebuffer; PPCAnalyst::CodeOp *ops = code_buf->codebuffer;
const u8 *start = GetCodePtr(); const u8 *start = GetCodePtr();
@ -271,7 +265,7 @@ const u8* JitArmIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB
u64 codeHash = -1; u64 codeHash = -1;
{ {
// For profiling and IR Writer // 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; const u64 inst = ops[i].inst.hex;
// Ported from boost::hash // Ported from boost::hash
@ -289,19 +283,13 @@ const u8* JitArmIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB
js.downcountAmount = 0; js.downcountAmount = 0;
if (!Core::g_CoreStartupParameter.bEnableDebugging) if (!Core::g_CoreStartupParameter.bEnableDebugging)
{ js.downcountAmount += PatchEngine::GetSpeedhackCycles(em_address);
for (int i = 0; i < size_of_merged_addresses; ++i)
{
const u32 address = merged_addresses[i];
js.downcountAmount += PatchEngine::GetSpeedhackCycles(address);
}
}
js.skipnext = false; js.skipnext = false;
js.blockSize = size; js.blockSize = code_block.m_instructions;
js.compilerPC = nextPC; js.compilerPC = nextPC;
// Translate instructions // 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.compilerPC = ops[i].address;
js.op = &ops[i]; 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; const GekkoOPInfo *opinfo = ops[i].opinfo;
js.downcountAmount += opinfo->numCycles; js.downcountAmount += opinfo->numCycles;
if (i == (int)size - 1) if (i == (code_block.m_instructions - 1))
{ {
// WARNING - cmp->branch merging will screw this up. // WARNING - cmp->branch merging will screw this up.
js.isLastInstruction = true; js.isLastInstruction = true;
@ -348,21 +336,19 @@ const u8* JitArmIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB
} }
if (memory_exception) if (memory_exception)
BKPT(0x500); BKPT(0x500);
if (broken_block)
if (code_block.m_broken)
{ {
printf("Broken Block going to 0x%08x\n", nextPC); printf("Broken Block going to 0x%08x\n", nextPC);
WriteExit(nextPC); WriteExit(nextPC);
} }
// Perform actual code generation // Perform actual code generation
WriteCode(nextPC); WriteCode(nextPC);
b->flags = js.block_flags; b->flags = js.block_flags;
b->codeSize = (u32)(GetCodePtr() - normalEntry); b->codeSize = (u32)(GetCodePtr() - normalEntry);
b->originalSize = size; b->originalSize = code_block.m_instructions;;
{
}
FlushIcache(); FlushIcache();
return start; return start;

View File

@ -83,6 +83,9 @@ protected:
std::unordered_set<u32> fifoWriteAddresses; std::unordered_set<u32> fifoWriteAddresses;
}; };
PPCAnalyst::CodeBlock code_block;
PPCAnalyst::PPCAnalyser analyser;
public: public:
// This should probably be removed from public: // This should probably be removed from public:
JitOptions jo; JitOptions jo;