UI::EventReturn JitCompareScreen::OnShowStats(UI::EventParams &e) { if (!MIPSComp::jit) { return UI::EVENT_DONE; } JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache(); BlockCacheStats bcStats; blockCache->ComputeStats(bcStats); NOTICE_LOG(JIT, "Num blocks: %i", bcStats.numBlocks); NOTICE_LOG(JIT, "Average Bloat: %0.2f%%", 100 * bcStats.avgBloat); NOTICE_LOG(JIT, "Min Bloat: %0.2f%% (%08x)", 100 * bcStats.minBloat, bcStats.minBloatBlock); NOTICE_LOG(JIT, "Max Bloat: %0.2f%% (%08x)", 100 * bcStats.maxBloat, bcStats.maxBloatBlock); int ctr = 0, sz = (int)bcStats.bloatMap.size(); for (auto iter : bcStats.bloatMap) { if (ctr < 10 || ctr > sz - 10) { NOTICE_LOG(JIT, "%08x: %f", iter.second, iter.first); } else if (ctr == 10) { NOTICE_LOG(JIT, "..."); } ctr++; } return UI::EVENT_DONE; }
void JitCompareScreen::OnRandomBlock(int flag) { if (!MIPSComp::jit) { return; } JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache(); int numBlocks = blockCache->GetNumBlocks(); if (numBlocks > 0) { bool anyWanted = false; int tries = 0; while (!anyWanted && tries < 10000) { currentBlock_ = rand() % numBlocks; const JitBlock *b = blockCache->GetBlock(currentBlock_); for (u32 addr = b->originalAddress; addr <= b->originalAddress + b->originalSize; addr += 4) { MIPSOpcode opcode = Memory::Read_Instruction(addr); if (MIPSGetInfo(opcode) & flag) { char temp[256]; MIPSDisAsm(opcode, addr, temp); // INFO_LOG(HLE, "Stopping VFPU instruction: %s", temp); anyWanted = true; break; } } tries++; } } UpdateDisasm(); }
MIPSOpcode Arm64Jit::GetOriginalOp(MIPSOpcode op) { JitBlockCache *bc = GetBlockCache(); int block_num = bc->GetBlockNumberFromEmuHackOp(op, true); if (block_num >= 0) { return bc->GetOriginalFirstOp(block_num); } else { return op; } }
void JitCompareScreen::UpdateDisasm() { leftDisasm_->Clear(); rightDisasm_->Clear(); using namespace UI; I18NCategory *dev = GetI18NCategory("Developer"); JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache(); char temp[256]; snprintf(temp, sizeof(temp), "%i/%i", currentBlock_, blockCache->GetNumBlocks()); blockName_->SetText(temp); if (currentBlock_ < 0 || currentBlock_ >= blockCache->GetNumBlocks()) { leftDisasm_->Add(new TextView(dev->T("No block"))); rightDisasm_->Add(new TextView(dev->T("No block"))); blockStats_->SetText(""); return; } JitBlock *block = blockCache->GetBlock(currentBlock_); snprintf(temp, sizeof(temp), "%08x", block->originalAddress); blockAddr_->SetText(temp); // Alright. First generate the MIPS disassembly. // TODO: Need a way to communicate branch continuing. for (u32 addr = block->originalAddress; addr <= block->originalAddress + block->originalSize * 4; addr += 4) { char temp[256]; MIPSDisAsm(Memory::Read_Instruction(addr), addr, temp, true); std::string mipsDis = temp; leftDisasm_->Add(new TextView(mipsDis))->SetFocusable(true); } #if defined(ARM) std::vector<std::string> targetDis = DisassembleArm2(block->normalEntry, block->codeSize); #elif defined(ARM64) std::vector<std::string> targetDis = DisassembleArm64(block->normalEntry, block->codeSize); #elif defined(_M_IX86) || defined(_M_X64) std::vector<std::string> targetDis = DisassembleX86(block->normalEntry, block->codeSize); #endif #if defined(ARM) || defined(ARM64) || defined(_M_IX86) || defined(_M_X64) for (size_t i = 0; i < targetDis.size(); i++) { rightDisasm_->Add(new TextView(targetDis[i]))->SetFocusable(true); } #endif int numMips = leftDisasm_->GetNumSubviews(); int numHost = rightDisasm_->GetNumSubviews(); snprintf(temp, sizeof(temp), "%d to %d : %d%%", numMips, numHost, 100 * numHost / numMips); blockStats_->SetText(temp); }
UI::EventReturn JitCompareScreen::OnRandomBlock(UI::EventParams &e) { if (!MIPSComp::jit) { return UI::EVENT_DONE; } JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache(); int numBlocks = blockCache->GetNumBlocks(); if (numBlocks > 0) { currentBlock_ = rand() % numBlocks; } UpdateDisasm(); return UI::EVENT_DONE; }
UI::EventReturn JitCompareScreen::OnBlockAddress(UI::EventParams &e) { if (!MIPSComp::jit) { return UI::EVENT_DONE; } JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache(); if (Memory::IsValidAddress(e.a)) { currentBlock_ = blockCache->GetBlockNumberFromStartAddress(e.a); } else { currentBlock_ = -1; } UpdateDisasm(); return UI::EVENT_DONE; }
UI::EventReturn JitCompareScreen::OnCurrentBlock(UI::EventParams &e) { if (!MIPSComp::jit) { return UI::EVENT_DONE; } JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache(); std::vector<int> blockNum; blockCache->GetBlockNumbersFromAddress(currentMIPS->pc, &blockNum); if (blockNum.size() > 0) { currentBlock_ = blockNum[0]; } else { currentBlock_ = -1; } UpdateDisasm(); return UI::EVENT_DONE; }
Opcode Read_Opcode_JIT(u32 address) { Opcode inst = Opcode(Read_U32(address)); if (MIPS_IS_RUNBLOCK(inst.encoding) && MIPSComp::jit) { JitBlockCache *bc = MIPSComp::jit->GetBlockCache(); int block_num = bc->GetBlockNumberFromEmuHackOp(inst, true); if (block_num >= 0) { return bc->GetOriginalFirstOp(block_num); } else { return inst; } } else { return inst; } }
UI::EventReturn JitCompareScreen::OnAddressChange(UI::EventParams &e) { if (!MIPSComp::jit) { return UI::EVENT_DONE; } JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache(); u32 addr; if (blockAddr_->GetText().size() > 8) return UI::EVENT_DONE; if (1 == sscanf(blockAddr_->GetText().c_str(), "%08x", &addr)) { if (Memory::IsValidAddress(addr)) { currentBlock_ = blockCache->GetBlockNumberFromStartAddress(addr); UpdateDisasm(); } } return UI::EVENT_DONE; }
Opcode Read_Instruction(u32 address) { Opcode inst = Opcode(Read_U32(address)); if (MIPS_IS_EMUHACK(inst) && MIPSComp::jit) { JitBlockCache *bc = MIPSComp::jit->GetBlockCache(); int block_num = bc->GetBlockNumberFromEmuHackOp(inst); if (block_num >= 0) { return bc->GetOriginalFirstOp(block_num); } else { return inst; } } else { return inst; } }
static Opcode Read_Instruction(u32 address, bool resolveReplacements, Opcode inst) { if (!MIPS_IS_EMUHACK(inst.encoding)) { return inst; } if (MIPS_IS_RUNBLOCK(inst.encoding) && MIPSComp::jit) { JitBlockCache *bc = MIPSComp::jit->GetBlockCache(); int block_num = bc->GetBlockNumberFromEmuHackOp(inst, true); if (block_num >= 0) { inst = bc->GetOriginalFirstOp(block_num); if (resolveReplacements && MIPS_IS_REPLACEMENT(inst)) { u32 op; if (GetReplacedOpAt(address, &op)) { if (MIPS_IS_EMUHACK(op)) { ERROR_LOG(HLE,"WTF 1"); return Opcode(op); } else { return Opcode(op); } } else { ERROR_LOG(HLE, "Replacement, but no replacement op? %08x", inst.encoding); } } return inst; } else { return inst; } } else if (resolveReplacements && MIPS_IS_REPLACEMENT(inst.encoding)) { u32 op; if (GetReplacedOpAt(address, &op)) { if (MIPS_IS_EMUHACK(op)) { ERROR_LOG(HLE,"WTF 2"); return Opcode(op); } else { return Opcode(op); } } else { return inst; } } else { return inst; } }
bool TestJit() { SetupJitHarness(); currentMIPS->pc = PSP_GetUserMemoryBase(); u32 *p = (u32 *)Memory::GetPointer(currentMIPS->pc); // TODO: Smarter way of seeding in the code sequence. static const char *lines[] = { //"vcrsp.t C000, C100, C200", //"vdot.q C000, C100, C200", //"vmmul.q M000, M100, M200", "lui r1, 0x8910", "vmmul.q M000, M100, M200", "sv.q C000, 0(r1)", "sv.q C000, 16(r1)", "sv.q C000, 32(r1)", "sv.q C000, 48(r1)", /* "abs.s f1, f1", "cvt.w.s f1, f1", "cvt.w.s f3, f1", "cvt.w.s f0, f2", "cvt.w.s f5, f1", "cvt.w.s f6, f5", */ }; bool compileSuccess = true; u32 addr = currentMIPS->pc; DebugInterface *dbg = currentDebugMIPS; for (int i = 0; i < 100; ++i) { /* // VFPU ops aren't supported by MIPSAsm yet. *p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8); *p++ = 0xD03C0000 | (1 << 7) | (1 << 15); *p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8); *p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8); *p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8); *p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8); *p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8); */ for (size_t j = 0; j < ARRAY_SIZE(lines); ++j) { p++; if (!MIPSAsm::MipsAssembleOpcode(lines[j], currentDebugMIPS, addr)) { printf("ERROR: %ls\n", MIPSAsm::GetAssembleError().c_str()); compileSuccess = false; } addr += 4; } } *p++ = MIPS_MAKE_SYSCALL("UnitTestFakeSyscalls", "UnitTestTerminator"); *p++ = MIPS_MAKE_BREAK(1); // Dogfood. addr = currentMIPS->pc; for (size_t j = 0; j < ARRAY_SIZE(lines); ++j) { char line[512]; MIPSDisAsm(Memory::Read_Instruction(addr), addr, line, true); addr += 4; printf("%s\n", line); } printf("\n"); double jit_speed = 0.0, interp_speed = 0.0; if (compileSuccess) { interp_speed = ExecCPUTest(); mipsr4k.UpdateCore(CPUCore::JIT); jit_speed = ExecCPUTest(); // Disassemble JitBlockCache *cache = MIPSComp::jit->GetBlockCache(); JitBlock *block = cache->GetBlock(0); // Should only be one block. #if defined(ARM) std::vector<std::string> lines = DisassembleArm2(block->normalEntry, block->codeSize); #elif defined(ARM64) std::vector<std::string> lines = DisassembleArm64(block->normalEntry, block->codeSize); #else std::vector<std::string> lines = DisassembleX86(block->normalEntry, block->codeSize); #endif // Cut off at 25 due to the repetition above. Might need tweaking for large instructions. const int cutoff = 25; for (int i = 0; i < std::min((int)lines.size(), cutoff); i++) { printf("%s\n", lines[i].c_str()); } if (lines.size() > cutoff) printf("...\n"); printf("Jit was %fx faster than interp.\n\n", jit_speed / interp_speed); } printf("\n"); DestroyJitHarness(); return jit_speed >= interp_speed; }