Merge pull request #10505 from hrydgard/ir-disasm-jit-compare

Show IR disassembly in JIT Compare screen
This commit is contained in:
Henrik Rydgård 2018-01-05 01:20:49 +01:00 committed by GitHub
commit 8c3a50d089
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 140 additions and 41 deletions

View File

@ -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); }

View File

@ -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); }

View File

@ -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_;

View File

@ -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(); }

View File

@ -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;
}

View File

@ -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,
};

View File

@ -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;

View File

@ -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); }

View File

@ -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(); }

View File

@ -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;