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:
parent
1830342d66
commit
b0c94a47f9
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -63,6 +63,7 @@ struct SCoreStartupParameter
|
|||
bool bJITBranchOff;
|
||||
bool bJITProfiledReJIT;
|
||||
bool bJITILTimeProfiling;
|
||||
bool bJITILOutputIR;
|
||||
|
||||
bool bEnableFPRF;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue