From b0c94a47f97e4233cd12574db0b5f9680a588b26 Mon Sep 17 00:00:00 2001 From: nodchip Date: Tue, 23 Nov 2010 13:35:44 +0000 Subject: [PATCH] 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 --- Source/Core/Core/Src/ConfigManager.cpp | 3 +- Source/Core/Core/Src/CoreParameter.cpp | 2 +- Source/Core/Core/Src/CoreParameter.h | 1 + Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp | 155 ++++++++++++++++++ Source/Core/Core/Src/PowerPC/Jit64IL/IR.h | 9 +- .../Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp | 5 + .../Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp | 17 +- 7 files changed, 185 insertions(+), 7 deletions(-) diff --git a/Source/Core/Core/Src/ConfigManager.cpp b/Source/Core/Core/Src/ConfigManager.cpp index 3b8f5d2643..483730e882 100644 --- a/Source/Core/Core/Src/ConfigManager.cpp +++ b/Source/Core/Core/Src/ConfigManager.cpp @@ -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) { diff --git a/Source/Core/Core/Src/CoreParameter.cpp b/Source/Core/Core/Src/CoreParameter.cpp index 6a043a9e3f..f1f9ae9372 100644 --- a/Source/Core/Core/Src/CoreParameter.cpp +++ b/Source/Core/Core/Src/CoreParameter.cpp @@ -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), diff --git a/Source/Core/Core/Src/CoreParameter.h b/Source/Core/Core/Src/CoreParameter.h index 4630c63f7a..10f27f1b0f 100644 --- a/Source/Core/Core/Src/CoreParameter.h +++ b/Source/Core/Core/Src/CoreParameter.h @@ -63,6 +63,7 @@ struct SCoreStartupParameter bool bJITBranchOff; bool bJITProfiledReJIT; bool bJITILTimeProfiling; + bool bJITILOutputIR; bool bEnableFPRF; diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp index a0cb2d91b4..faf8f4da4e 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp @@ -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; + +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 alwaysUseds(alwaysUsedList, alwaysUsedList + sizeof(alwaysUsedList) / sizeof(alwaysUsedList[0])); +static const std::set extra8Regs(extra8RegList, extra8RegList + sizeof(extra8RegList) / sizeof(extra8RegList[0])); +static const std::set extra16Regs(extra16RegList, extra16RegList + sizeof(extra16RegList) / sizeof(extra16RegList[0])); +static const std::set 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(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; +} + } diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h index c18bfeddc2..7d94661053 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h @@ -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 InstList; // FIXME: We must ensure this is - // continuous! + std::vector InstList; // FIXME: We must ensure this is continuous! + std::vector MarkUsed; // Used for IRWriter std::vector ConstList; InstLoc curReadPtr; InstLoc GRegCache[32]; diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp index 371d1c69f4..7af2405488 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp @@ -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)); diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp index bf586f04ea..1f6ae83486 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp @@ -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; }