mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 21:39:52 +00:00
Merge pull request #10505 from hrydgard/ir-disasm-jit-compare
Show IR disassembly in JIT Compare screen
This commit is contained in:
commit
8c3a50d089
@ -168,6 +168,7 @@ public:
|
||||
int Replace_fabsf() override;
|
||||
|
||||
JitBlockCache *GetBlockCache() override { return &blocks; }
|
||||
JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() override { return &blocks; }
|
||||
|
||||
std::vector<u32> SaveAndClearEmuHackOps() override { return blocks.SaveAndClearEmuHackOps(); }
|
||||
void RestoreSavedEmuHackOps(std::vector<u32> saved) override { blocks.RestoreSavedEmuHackOps(saved); }
|
||||
|
@ -169,6 +169,7 @@ public:
|
||||
int Replace_fabsf() override;
|
||||
|
||||
JitBlockCache *GetBlockCache() override { return &blocks; }
|
||||
JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() override { return &blocks; }
|
||||
|
||||
std::vector<u32> SaveAndClearEmuHackOps() override { return blocks.SaveAndClearEmuHackOps(); }
|
||||
void RestoreSavedEmuHackOps(std::vector<u32> saved) override { blocks.RestoreSavedEmuHackOps(saved); }
|
||||
|
@ -116,7 +116,7 @@ void IRJit::RunLoopUntil(u64 globalticks) {
|
||||
}
|
||||
|
||||
bool IRJit::DescribeCodePtr(const u8 *ptr, std::string &name) {
|
||||
// Used in disassembly viewer.
|
||||
// Used in target disassembly viewer.
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ void IRBlockCache::FinalizeBlock(int i) {
|
||||
}
|
||||
}
|
||||
|
||||
u32 IRBlockCache::AddressToPage(u32 addr) {
|
||||
u32 IRBlockCache::AddressToPage(u32 addr) const {
|
||||
// Use relatively small pages since basic blocks are typically small.
|
||||
return (addr & 0x3FFFFFFF) >> 10;
|
||||
}
|
||||
@ -210,7 +210,54 @@ void IRBlockCache::RestoreSavedEmuHackOps(std::vector<u32> saved) {
|
||||
}
|
||||
}
|
||||
|
||||
bool IRBlock::HasOriginalFirstOp() {
|
||||
JitBlockDebugInfo IRBlockCache::GetBlockDebugInfo(int blockNum) const {
|
||||
const IRBlock &ir = blocks_[blockNum];
|
||||
JitBlockDebugInfo debugInfo{};
|
||||
uint32_t start, size;
|
||||
ir.GetRange(start, size);
|
||||
debugInfo.originalAddress = start; // TODO
|
||||
|
||||
for (u32 addr = start; addr < start + size; addr += 4) {
|
||||
char temp[256];
|
||||
MIPSDisAsm(Memory::Read_Instruction(addr), addr, temp, true);
|
||||
std::string mipsDis = temp;
|
||||
debugInfo.origDisasm.push_back(mipsDis);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ir.GetNumInstructions(); i++) {
|
||||
IRInst inst = ir.GetInstructions()[i];
|
||||
char buffer[256];
|
||||
DisassembleIR(buffer, sizeof(buffer), inst);
|
||||
debugInfo.irDisasm.push_back(buffer);
|
||||
}
|
||||
return debugInfo;
|
||||
}
|
||||
|
||||
void IRBlockCache::ComputeStats(BlockCacheStats &bcStats) const {
|
||||
// TODO: Implement properly
|
||||
memset(&bcStats, 0, sizeof(bcStats));
|
||||
bcStats.numBlocks = (int)blocks_.size();
|
||||
}
|
||||
|
||||
int IRBlockCache::GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly) const {
|
||||
u32 page = AddressToPage(em_address);
|
||||
|
||||
const auto iter = byPage_.find(page);
|
||||
if (iter == byPage_.end())
|
||||
return -1;
|
||||
|
||||
const std::vector<int> &blocksInPage = iter->second;
|
||||
for (int i : blocksInPage) {
|
||||
uint32_t start, size;
|
||||
blocks_[i].GetRange(start, size);
|
||||
if (start == em_address) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool IRBlock::HasOriginalFirstOp() const {
|
||||
return Memory::ReadUnchecked_U32(origAddr_) == origFirstOpcode_.encoding;
|
||||
}
|
||||
|
||||
@ -240,7 +287,7 @@ void IRBlock::Destroy(int number) {
|
||||
}
|
||||
}
|
||||
|
||||
bool IRBlock::OverlapsRange(u32 addr, u32 size) {
|
||||
bool IRBlock::OverlapsRange(u32 addr, u32 size) const {
|
||||
addr &= 0x3FFFFFFF;
|
||||
u32 origAddr = origAddr_ & 0x3FFFFFFF;
|
||||
return addr + size > origAddr && addr < origAddr + origSize_;
|
||||
|
@ -64,15 +64,15 @@ public:
|
||||
const IRInst *GetInstructions() const { return instr_; }
|
||||
int GetNumInstructions() const { return numInstructions_; }
|
||||
MIPSOpcode GetOriginalFirstOp() const { return origFirstOpcode_; }
|
||||
bool HasOriginalFirstOp();
|
||||
bool HasOriginalFirstOp() const;
|
||||
bool RestoreOriginalFirstOp(int number);
|
||||
bool IsValid() const { return origAddr_ != 0; }
|
||||
void SetOriginalSize(u32 size) {
|
||||
origSize_ = size;
|
||||
}
|
||||
bool OverlapsRange(u32 addr, u32 size);
|
||||
bool OverlapsRange(u32 addr, u32 size) const;
|
||||
|
||||
void GetRange(u32 &start, u32 &size) {
|
||||
void GetRange(u32 &start, u32 &size) const {
|
||||
start = origAddr_;
|
||||
size = origSize_;
|
||||
}
|
||||
@ -88,13 +88,13 @@ private:
|
||||
MIPSOpcode origFirstOpcode_;
|
||||
};
|
||||
|
||||
class IRBlockCache {
|
||||
class IRBlockCache : public JitBlockCacheDebugInterface {
|
||||
public:
|
||||
IRBlockCache() {}
|
||||
void Clear();
|
||||
void InvalidateICache(u32 address, u32 length);
|
||||
void FinalizeBlock(int i);
|
||||
int GetNumBlocks() const { return (int)blocks_.size(); }
|
||||
int GetNumBlocks() const override { return (int)blocks_.size(); }
|
||||
int AllocateBlock(int emAddr) {
|
||||
blocks_.push_back(IRBlock(emAddr));
|
||||
return (int)blocks_.size() - 1;
|
||||
@ -110,8 +110,12 @@ public:
|
||||
std::vector<u32> SaveAndClearEmuHackOps();
|
||||
void RestoreSavedEmuHackOps(std::vector<u32> saved);
|
||||
|
||||
JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const override;
|
||||
void ComputeStats(BlockCacheStats &bcStats) const override;
|
||||
int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const override;
|
||||
|
||||
private:
|
||||
u32 AddressToPage(u32 addr);
|
||||
u32 AddressToPage(u32 addr) const;
|
||||
|
||||
std::vector<IRBlock> blocks_;
|
||||
std::unordered_map<u32, std::vector<int>> byPage_;
|
||||
@ -133,6 +137,7 @@ public:
|
||||
bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
|
||||
// Not using a regular block cache.
|
||||
JitBlockCache *GetBlockCache() override { return nullptr; }
|
||||
JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() override { return &blocks_; }
|
||||
MIPSOpcode GetOriginalOp(MIPSOpcode op) override;
|
||||
|
||||
std::vector<u32> SaveAndClearEmuHackOps() override { return blocks_.SaveAndClearEmuHackOps(); }
|
||||
|
@ -123,6 +123,10 @@ JitBlock *JitBlockCache::GetBlock(int no) {
|
||||
return &blocks_[no];
|
||||
}
|
||||
|
||||
const JitBlock *JitBlockCache::GetBlock(int no) const {
|
||||
return &blocks_[no];
|
||||
}
|
||||
|
||||
int JitBlockCache::AllocateBlock(u32 startAddress) {
|
||||
JitBlock &b = blocks_[num_blocks_];
|
||||
|
||||
@ -326,7 +330,7 @@ MIPSOpcode JitBlockCache::GetEmuHackOpForBlock(int blockNum) const {
|
||||
return MIPSOpcode(MIPS_EMUHACK_OPCODE | off);
|
||||
}
|
||||
|
||||
int JitBlockCache::GetBlockNumberFromStartAddress(u32 addr, bool realBlocksOnly) {
|
||||
int JitBlockCache::GetBlockNumberFromStartAddress(u32 addr, bool realBlocksOnly) const {
|
||||
if (!blocks_ || !Memory::IsValidAddress(addr))
|
||||
return -1;
|
||||
|
||||
@ -610,12 +614,12 @@ int JitBlockCache::GetBlockExitSize() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void JitBlockCache::ComputeStats(BlockCacheStats &bcStats) {
|
||||
void JitBlockCache::ComputeStats(BlockCacheStats &bcStats) const {
|
||||
double totalBloat = 0.0;
|
||||
double maxBloat = 0.0;
|
||||
double minBloat = 1000000000.0;
|
||||
for (int i = 0; i < num_blocks_; i++) {
|
||||
JitBlock *b = GetBlock(i);
|
||||
const JitBlock *b = GetBlock(i);
|
||||
double codeSize = (double)b->codeSize;
|
||||
if (codeSize == 0)
|
||||
continue;
|
||||
@ -637,3 +641,25 @@ void JitBlockCache::ComputeStats(BlockCacheStats &bcStats) {
|
||||
bcStats.maxBloat = maxBloat;
|
||||
bcStats.avgBloat = totalBloat / (double)num_blocks_;
|
||||
}
|
||||
|
||||
JitBlockDebugInfo JitBlockCache::GetBlockDebugInfo(int blockNum) const {
|
||||
JitBlockDebugInfo debugInfo{};
|
||||
const JitBlock *block = GetBlock(blockNum);
|
||||
debugInfo.originalAddress = block->originalAddress;
|
||||
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;
|
||||
debugInfo.origDisasm.push_back(mipsDis);
|
||||
}
|
||||
|
||||
#if defined(ARM)
|
||||
debugInfo.targetDisasm = DisassembleArm2(block->normalEntry, block->codeSize);
|
||||
#elif defined(ARM64)
|
||||
debugInfo.targetDisasm = DisassembleArm64(block->normalEntry, block->codeSize);
|
||||
#elif defined(_M_IX86) || defined(_M_X64)
|
||||
debugInfo.targetDisasm = DisassembleX86(block->normalEntry, block->codeSize);
|
||||
#endif
|
||||
|
||||
return debugInfo;
|
||||
}
|
||||
|
@ -93,7 +93,24 @@ struct JitBlock {
|
||||
|
||||
typedef void (*CompiledCode)();
|
||||
|
||||
class JitBlockCache {
|
||||
struct JitBlockDebugInfo {
|
||||
uint32_t originalAddress;
|
||||
std::vector<std::string> origDisasm;
|
||||
std::vector<std::string> irDisasm; // if any
|
||||
std::vector<std::string> targetDisasm;
|
||||
};
|
||||
|
||||
class JitBlockCacheDebugInterface {
|
||||
public:
|
||||
virtual int GetNumBlocks() const = 0;
|
||||
virtual int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const = 0;
|
||||
virtual JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const = 0;
|
||||
virtual void ComputeStats(BlockCacheStats &bcStats) const = 0;
|
||||
|
||||
virtual ~JitBlockCacheDebugInterface() {}
|
||||
};
|
||||
|
||||
class JitBlockCache : public JitBlockCacheDebugInterface {
|
||||
public:
|
||||
JitBlockCache(MIPSState *mips_, CodeBlockCommon *codeBlock);
|
||||
~JitBlockCache();
|
||||
@ -109,13 +126,14 @@ public:
|
||||
void Reset();
|
||||
|
||||
bool IsFull() const;
|
||||
void ComputeStats(BlockCacheStats &bcStats);
|
||||
void ComputeStats(BlockCacheStats &bcStats) const override;
|
||||
|
||||
// Code Cache
|
||||
JitBlock *GetBlock(int block_num);
|
||||
const JitBlock *GetBlock(int block_num) const;
|
||||
|
||||
// Fast way to get a block. Only works on the first source-cpu instruction of a block.
|
||||
int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true);
|
||||
int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const override;
|
||||
|
||||
// slower, but can get numbers from within blocks, not just the first instruction.
|
||||
// WARNING! WILL NOT WORK WITH JIT INLINING ENABLED (not yet a feature but will be soon)
|
||||
@ -140,10 +158,12 @@ public:
|
||||
std::vector<u32> SaveAndClearEmuHackOps();
|
||||
void RestoreSavedEmuHackOps(std::vector<u32> saved);
|
||||
|
||||
int GetNumBlocks() const { return num_blocks_; }
|
||||
int GetNumBlocks() const override { return num_blocks_; }
|
||||
|
||||
static int GetBlockExitSize();
|
||||
|
||||
JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const override;
|
||||
|
||||
enum {
|
||||
MAX_BLOCK_INSTRUCTIONS = 0x4000,
|
||||
};
|
||||
|
@ -31,6 +31,7 @@ std::vector<std::string> DisassembleX86(const u8 *data, int size);
|
||||
|
||||
struct JitBlock;
|
||||
class JitBlockCache;
|
||||
class JitBlockCacheDebugInterface;
|
||||
class PointerWrap;
|
||||
|
||||
#ifdef USING_QT_UI
|
||||
@ -123,6 +124,7 @@ namespace MIPSComp {
|
||||
virtual bool DescribeCodePtr(const u8 *ptr, std::string &name) = 0;
|
||||
virtual const u8 *GetDispatcher() const = 0;
|
||||
virtual JitBlockCache *GetBlockCache() = 0;
|
||||
virtual JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() = 0;
|
||||
virtual void InvalidateCacheAt(u32 em_address, int length = 4) = 0;
|
||||
virtual void DoState(PointerWrap &p) = 0;
|
||||
virtual void RunLoopUntil(u64 globalticks) = 0;
|
||||
|
@ -129,6 +129,7 @@ public:
|
||||
void Comp_Vbfy(MIPSOpcode op) {}
|
||||
|
||||
JitBlockCache *GetBlockCache() override { return &blocks; }
|
||||
JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() override { return &blocks; }
|
||||
|
||||
std::vector<u32> SaveAndClearEmuHackOps() override { return blocks.SaveAndClearEmuHackOps(); }
|
||||
void RestoreSavedEmuHackOps(std::vector<u32> saved) override { blocks.RestoreSavedEmuHackOps(saved); }
|
||||
|
@ -158,6 +158,8 @@ public:
|
||||
void UpdateRoundingMode();
|
||||
|
||||
JitBlockCache *GetBlockCache() override { return &blocks; }
|
||||
JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() override { return &blocks; }
|
||||
|
||||
MIPSOpcode GetOriginalOp(MIPSOpcode op) override;
|
||||
|
||||
std::vector<u32> SaveAndClearEmuHackOps() override { return blocks.SaveAndClearEmuHackOps(); }
|
||||
|
@ -701,46 +701,41 @@ void JitCompareScreen::UpdateDisasm() {
|
||||
|
||||
I18NCategory *dev = GetI18NCategory("Developer");
|
||||
|
||||
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
|
||||
JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface();
|
||||
|
||||
char temp[256];
|
||||
snprintf(temp, sizeof(temp), "%i/%i", currentBlock_, blockCache->GetNumBlocks());
|
||||
snprintf(temp, sizeof(temp), "%i/%i", currentBlock_, blockCacheDebug->GetNumBlocks());
|
||||
blockName_->SetText(temp);
|
||||
|
||||
if (currentBlock_ < 0 || currentBlock_ >= blockCache->GetNumBlocks()) {
|
||||
if (currentBlock_ < 0 || currentBlock_ >= blockCacheDebug->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_);
|
||||
JitBlockDebugInfo debugInfo = blockCacheDebug->GetBlockDebugInfo(currentBlock_);
|
||||
|
||||
snprintf(temp, sizeof(temp), "%08x", block->originalAddress);
|
||||
snprintf(temp, sizeof(temp), "%08x", debugInfo.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);
|
||||
for (auto line : debugInfo.origDisasm) {
|
||||
leftDisasm_->Add(new TextView(line))->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);
|
||||
// TODO : When we have both target and IR, need a third column.
|
||||
if (debugInfo.targetDisasm.size()) {
|
||||
for (auto line : debugInfo.targetDisasm) {
|
||||
rightDisasm_->Add(new TextView(line))->SetFocusable(true);
|
||||
}
|
||||
} else {
|
||||
for (auto line : debugInfo.irDisasm) {
|
||||
rightDisasm_->Add(new TextView(line))->SetFocusable(true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int numMips = leftDisasm_->GetNumSubviews();
|
||||
int numHost = rightDisasm_->GetNumSubviews();
|
||||
@ -773,7 +768,7 @@ UI::EventReturn JitCompareScreen::OnShowStats(UI::EventParams &e) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
|
||||
JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface();
|
||||
BlockCacheStats bcStats;
|
||||
blockCache->ComputeStats(bcStats);
|
||||
NOTICE_LOG(JIT, "Num blocks: %i", bcStats.numBlocks);
|
||||
@ -790,7 +785,6 @@ UI::EventReturn JitCompareScreen::OnShowStats(UI::EventParams &e) {
|
||||
}
|
||||
ctr++;
|
||||
}
|
||||
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
@ -839,7 +833,7 @@ UI::EventReturn JitCompareScreen::OnRandomBlock(UI::EventParams &e) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
|
||||
JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface();
|
||||
if (!blockCache)
|
||||
return UI::EVENT_DONE;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user