JitIL: Implemented JitIL IR Disassembler. If you want to use it, add "OutputIR = True" in the "Core" section of Dolphin.ini.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6462 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
nodchip 2010-11-23 13:35:44 +00:00
parent 1830342d66
commit b0c94a47f9
7 changed files with 185 additions and 7 deletions

View File

@ -282,7 +282,8 @@ void SConfig::LoadSettings()
ini.Get("Core", "SlotB", (int*)&m_EXIDevice[1], EXIDEVICE_MEMORYCARD_B);
ini.Get("Core", "SerialPort1", (int*)&m_EXIDevice[2], EXIDEVICE_NONE);
ini.Get("Core", "ProfiledReJIT",&m_LocalCoreStartupParameter.bJITProfiledReJIT, false);
ini.Get("Core", "TimeProfiling",&m_LocalCoreStartupParameter.bJITILTimeProfiling, false);
ini.Get("Core", "TimeProfiling",&m_LocalCoreStartupParameter.bJITILTimeProfiling, false);
ini.Get("Core", "OutputIR", &m_LocalCoreStartupParameter.bJITILOutputIR, false);
char sidevicenum[16];
for (int i = 0; i < 4; ++i)
{

View File

@ -40,7 +40,7 @@ SCoreStartupParameter::SCoreStartupParameter()
bJITFloatingPointOff(false), bJITIntegerOff(false),
bJITPairedOff(false), bJITSystemRegistersOff(false),
bJITBranchOff(false), bJITProfiledReJIT(false),
bJITILTimeProfiling(false),
bJITILTimeProfiling(false), bJITILOutputIR(false),
bEnableFPRF(false),
bCPUThread(true), bDSPThread(false),
bSkipIdle(true), bNTSC(false), bNTSCJ(false),

View File

@ -63,6 +63,7 @@ struct SCoreStartupParameter
bool bJITBranchOff;
bool bJITProfiledReJIT;
bool bJITILTimeProfiling;
bool bJITILOutputIR;
bool bEnableFPRF;

View File

@ -146,6 +146,7 @@ namespace IREmitter {
InstLoc IRBuilder::EmitZeroOp(unsigned Opcode, unsigned extra = 0) {
InstLoc curIndex = &InstList[InstList.size()];
InstList.push_back(Opcode | (extra << 8));
MarkUsed.push_back(false);
return curIndex;
}
@ -154,10 +155,12 @@ InstLoc IRBuilder::EmitUOp(unsigned Opcode, InstLoc Op1, unsigned extra) {
unsigned backOp1 = (s32)(curIndex - 1 - Op1);
if (backOp1 >= 256) {
InstList.push_back(Tramp | backOp1 << 8);
MarkUsed.push_back(false);
backOp1 = 0;
curIndex++;
}
InstList.push_back(Opcode | (backOp1 << 8) | (extra << 16));
MarkUsed.push_back(false);
return curIndex;
}
@ -166,17 +169,20 @@ InstLoc IRBuilder::EmitBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2, unsigned
unsigned backOp1 = (s32)(curIndex - 1 - Op1);
if (backOp1 >= 255) {
InstList.push_back(Tramp | backOp1 << 8);
MarkUsed.push_back(false);
backOp1 = 0;
curIndex++;
}
unsigned backOp2 = (s32)(curIndex - 1 - Op2);
if (backOp2 >= 256) {
InstList.push_back(Tramp | backOp2 << 8);
MarkUsed.push_back(false);
backOp2 = 0;
backOp1++;
curIndex++;
}
InstList.push_back(Opcode | (backOp1 << 8) | (backOp2 << 16) | (extra << 24));
MarkUsed.push_back(false);
return curIndex;
}
@ -186,12 +192,14 @@ InstLoc IRBuilder::EmitTriOp(unsigned Opcode, InstLoc Op1, InstLoc Op2, InstLoc
unsigned backOp1 = curIndex - 1 - Op1;
if (backOp1 >= 254) {
InstList.push_back(Tramp | backOp1 << 8);
MarkUsed.push_back(false);
backOp1 = 0;
curIndex++;
}
unsigned backOp2 = curIndex - 1 - Op2;
if (backOp2 >= 255) {
InstList.push_back((Tramp | backOp2 << 8));
MarkUsed.push_back(false);
backOp2 = 0;
backOp1++;
curIndex++;
@ -199,12 +207,14 @@ InstLoc IRBuilder::EmitTriOp(unsigned Opcode, InstLoc Op1, InstLoc Op2, InstLoc
unsigned backOp3 = curIndex - 1 - Op3;
if (backOp3 >= 256) {
InstList.push_back(Tramp | (backOp3 << 8));
MarkUsed.push_back(false);
backOp3 = 0;
backOp2++;
backOp1++;
curIndex++;
}
InstList.push_back(Opcode | (backOp1 << 8) | (backOp2 << 16) | (backOp3 << 24));
MarkUsed.push_back(false);
return curIndex;
}
#endif
@ -1054,6 +1064,7 @@ InstLoc IRBuilder::FoldBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2, unsigned
InstLoc IRBuilder::EmitIntConst(unsigned value) {
InstLoc curIndex = &InstList[InstList.size()];
InstList.push_back(CInt32 | ((unsigned int)ConstList.size() << 8));
MarkUsed.push_back(false);
ConstList.push_back(value);
return curIndex;
}
@ -1062,6 +1073,16 @@ unsigned IRBuilder::GetImmValue(InstLoc I) const {
return ConstList[*I >> 8];
}
void IRBuilder::SetMarkUsed(InstLoc I) {
const unsigned i = (unsigned)(I - &InstList[0]);
MarkUsed[i] = true;
}
bool IRBuilder::IsMarkUsed(InstLoc I) const {
const unsigned i = (unsigned)(I - &InstList[0]);
return MarkUsed[i];
}
unsigned IRBuilder::isSameValue(InstLoc Op1, InstLoc Op2) const {
if (Op1 == Op2) {
return true;
@ -1200,4 +1221,138 @@ InstLoc IRBuilder::isNeg(InstLoc I) const {
return NULL;
}
// TODO: Move the following code to a separated file.
struct Writer {
FILE* file;
Writer() : file(NULL) {
char buffer[1024];
sprintf(buffer, "JitIL_IR_%d.txt", time(NULL));
file = fopen(buffer, "w");
setvbuf(file, NULL, _IOFBF, 1024 * 1024);
}
virtual ~Writer() {
if (file) {
fclose(file);
file = NULL;
}
}
};
static std::auto_ptr<Writer> writer;
static const std::string opcodeNames[] = {
"Nop", "LoadGReg", "LoadLink", "LoadCR", "LoadCarry", "LoadCTR",
"LoadMSR", "LoadGQR", "SExt8", "SExt16", "BSwap32", "BSwap16", "Cntlzw",
"Not", "Load8", "Load16", "Load32", "BranchUncond", "StoreGReg",
"StoreCR", "StoreLink", "StoreCarry", "StoreCTR", "StoreMSR", "StoreFPRF",
"StoreGQR", "StoreSRR", "InterpreterFallback", "Add", "Mul", "And", "Or",
"Xor", "MulHighUnsigned", "Sub", "Shl", "Shrl", "Sarl", "Rol",
"ICmpCRSigned", "ICmpCRUnsigned", "ICmpEq", "ICmpNe", "ICmpUgt",
"ICmpUlt", "ICmpUge", "ICmpUle", "ICmpSgt", "ICmpSlt", "ICmpSge",
"ICmpSle", "Store8", "Store16", "Store32", "BranchCond", "FResult_Start",
"LoadSingle", "LoadDouble", "LoadPaired", "DoubleToSingle",
"DupSingleToMReg", "DupSingleToPacked", "InsertDoubleInMReg",
"ExpandPackedToMReg", "CompactMRegToPacked", "LoadFReg",
"LoadFRegDENToZero", "FSMul", "FSAdd", "FSSub", "FSNeg", "FSRSqrt",
"FPAdd", "FPMul", "FPSub", "FPNeg", "FDMul", "FDAdd", "FDSub", "FDNeg",
"FPMerge00", "FPMerge01", "FPMerge10", "FPMerge11", "FPDup0", "FPDup1",
"FResult_End", "StorePaired", "StoreSingle", "StoreDouble", "StoreFReg",
"FDCmpCR", "CInt16", "CInt32", "SystemCall", "RFIExit",
"InterpreterBranch", "IdleBranch", "ShortIdleLoop",
"FPExceptionCheckStart", "FPExceptionCheckEnd", "ISIException", "Tramp",
"BlockStart", "BlockEnd", "Int3",
};
static const unsigned alwaysUsedList[] = {
InterpreterFallback, StoreGReg, StoreCR, StoreLink, StoreCTR, StoreMSR,
StoreGQR, StoreSRR, StoreCarry, StoreFPRF, Load8, Load16, Load32, Store8,
Store16, Store32, StoreSingle, StoreDouble, StorePaired, StoreFReg, FDCmpCR,
BlockStart, BlockEnd, IdleBranch, BranchCond, BranchUncond, ShortIdleLoop,
SystemCall, InterpreterBranch, RFIExit, FPExceptionCheckStart,
FPExceptionCheckEnd, ISIException, Int3, Tramp, Nop
};
static const unsigned extra8RegList[] = {
LoadGReg, LoadCR, LoadGQR, LoadFReg, LoadFRegDENToZero,
};
static const unsigned extra16RegList[] = {
StoreGReg, StoreCR, StoreGQR, StoreSRR, LoadPaired, StoreFReg,
};
static const unsigned extra24RegList[] = {
StorePaired,
};
static const std::set<unsigned> alwaysUseds(alwaysUsedList, alwaysUsedList + sizeof(alwaysUsedList) / sizeof(alwaysUsedList[0]));
static const std::set<unsigned> extra8Regs(extra8RegList, extra8RegList + sizeof(extra8RegList) / sizeof(extra8RegList[0]));
static const std::set<unsigned> extra16Regs(extra16RegList, extra16RegList + sizeof(extra16RegList) / sizeof(extra16RegList[0]));
static const std::set<unsigned> extra24Regs(extra24RegList, extra24RegList + sizeof(extra24RegList) / sizeof(extra24RegList[0]));
void IRBuilder::WriteToFile(u64 codeHash) {
assert(sizeof(opcodeNames) / sizeof(opcodeNames[0]) == Int3 + 1);
if (!writer.get()) {
writer = std::auto_ptr<Writer>(new Writer);
}
FILE* file = writer->file;
fprintf(file, "\ncode hash:%016llx\n", codeHash);
const InstLoc lastCurReadPtr = curReadPtr;
StartForwardPass();
const unsigned numInsts = getNumInsts();
for (int i = 0; i < numInsts; ++i) {
const InstLoc I = ReadForward();
const unsigned opcode = getOpcode(*I);
const bool thisUsed = IsMarkUsed(I) ||
alwaysUseds.find(opcode) != alwaysUseds.end();
// Line number
fprintf(file, "%4d", i);
if (!thisUsed) {
fprintf(file, "%*c", 32, ' ');
}
// Opcode
const std::string& opcodeName = opcodeNames[opcode];
fprintf(file, " %-20s", opcodeName.c_str());
const unsigned numberOfOperands = getNumberOfOperands(I);
// Op1
if (numberOfOperands >= 1) {
const IREmitter::InstLoc inst = getOp1(I);
if (isImm(*inst)) {
fprintf(file, " 0x%08x", GetImmValue(inst));
} else {
fprintf(file, " %10d", i - (I - inst));
}
}
// Op2
if (numberOfOperands >= 2) {
const IREmitter::InstLoc inst = getOp2(I);
if (isImm(*inst)) {
fprintf(file, " 0x%08x", GetImmValue(inst));
} else {
fprintf(file, " %10d", i - (I - inst));
}
}
if (extra8Regs.count(opcode)) {
fprintf(file, " R%d", *I >> 8);
}
if (extra16Regs.count(opcode)) {
fprintf(file, " R%d", *I >> 16);
}
if (extra24Regs.count(opcode)) {
fprintf(file, " R%d", *I >> 24);
}
if (opcode == CInt32 || opcode == CInt16) {
fprintf(file, " 0x%08x", GetImmValue(I));
}
fprintf(file, "\n");
}
curReadPtr = lastCurReadPtr;
}
}

View File

@ -544,10 +544,15 @@ public:
unsigned int getNumInsts() { return (unsigned int)InstList.size(); }
unsigned int ReadInst(InstLoc I) { return *I; }
unsigned int GetImmValue(InstLoc I) const;
void SetMarkUsed(InstLoc I);
bool IsMarkUsed(InstLoc I) const;
void WriteToFile(u64 codeHash);
void Reset() {
InstList.clear();
InstList.reserve(100000);
MarkUsed.clear();
MarkUsed.reserve(100000);
for (unsigned i = 0; i < 32; i++) {
GRegCache[i] = 0;
GRegCacheStore[i] = 0;
@ -576,8 +581,8 @@ private:
bool maskedValueIsZero(InstLoc Op1, InstLoc Op2) const;
InstLoc isNeg(InstLoc I) const;
std::vector<Inst> InstList; // FIXME: We must ensure this is
// continuous!
std::vector<Inst> InstList; // FIXME: We must ensure this is continuous!
std::vector<bool> MarkUsed; // Used for IRWriter
std::vector<unsigned> ConstList;
InstLoc curReadPtr;
InstLoc GRegCache[32];

View File

@ -892,6 +892,11 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
for (unsigned i = 0; i != RI.IInfo.size(); i++) {
InstLoc I = ibuild->ReadForward();
bool thisUsed = regReadUse(RI, I) ? true : false;
if (thisUsed) {
// Needed for IR Writer
ibuild->SetMarkUsed(I);
}
switch (getOpcode(*I)) {
case InterpreterFallback: {
unsigned InstCode = ibuild->GetImmValue(getOp1(I));

View File

@ -582,15 +582,21 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
js.rewriteStart = (u8*)GetCodePtr();
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling) {
// For profiling
u64 codeHash = -1;
u64 codeHash = -1;
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling ||
SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILOutputIR)
{
// For profiling and IR Writer
for (int i = 0; i < (int)size; i++)
{
const u64 inst = ops[i].inst.hex;
// Ported from boost::hash
codeHash ^= inst + (codeHash << 6) + (codeHash >> 2);
}
}
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling)
{
JitILProfiler::Block& block = JitILProfiler::Add(codeHash);
ABI_CallFunctionC((void *)JitILProfiler::Begin, block.index);
}
@ -661,5 +667,10 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
LogGeneratedX86(size, code_buf, normalEntry, b);
#endif
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILOutputIR)
{
ibuild.WriteToFile(codeHash);
}
return normalEntry;
}