It's kind of starting to run

This commit is contained in:
Henrik Rydgard 2016-05-07 17:37:19 +02:00
parent d399c4a470
commit 4acf85aa06
17 changed files with 309 additions and 80 deletions

View file

@ -189,6 +189,7 @@
<ClCompile Include="MIPS\IR\IRCompVFPU.cpp" />
<ClCompile Include="MIPS\IR\IRInst.cpp" />
<ClCompile Include="MIPS\IR\IRJit.cpp" />
<ClCompile Include="MIPS\IR\IRPassSimplify.cpp" />
<ClCompile Include="MIPS\IR\IRRegCache.cpp" />
<ClCompile Include="TextureReplacer.cpp" />
<ClCompile Include="Compatibility.cpp" />
@ -518,6 +519,7 @@
<ClInclude Include="..\ext\udis86\udis86.h" />
<ClInclude Include="MIPS\IR\IRInst.h" />
<ClInclude Include="MIPS\IR\IRJit.h" />
<ClInclude Include="MIPS\IR\IRPassSimplify.h" />
<ClInclude Include="MIPS\IR\IRRegCache.h" />
<ClInclude Include="TextureReplacer.h" />
<ClInclude Include="Compatibility.h" />

View file

@ -664,6 +664,9 @@
<ClCompile Include="MIPS\IR\IRInst.cpp">
<Filter>MIPS\IR</Filter>
</ClCompile>
<ClCompile Include="MIPS\IR\IRPassSimplify.cpp">
<Filter>MIPS\IR</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
@ -1218,6 +1221,9 @@
<ClInclude Include="MIPS\IR\IRInst.h">
<Filter>MIPS\IR</Filter>
</ClInclude>
<ClInclude Include="MIPS\IR\IRPassSimplify.h">
<Filter>MIPS\IR</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />

View file

@ -49,15 +49,15 @@ namespace MIPSComp {
void IRJit::CompImmLogic(MIPSGPReg rs, MIPSGPReg rt, u32 uimm, IROp OP) {
if (gpr.IsImm(rs)) {
switch (OP) {
case IROp::AddConst: gpr.SetImm(rt, rs + uimm); break;
case IROp::SubConst: gpr.SetImm(rt, rs - uimm); break;
case IROp::AndConst: gpr.SetImm(rt, rs & uimm); break;
case IROp::OrConst: gpr.SetImm(rt, rs | uimm); break;
case IROp::XorConst: gpr.SetImm(rt, rs ^ uimm); break;
case IROp::AddConst: gpr.SetImm(rt, gpr.GetImm(rs) + uimm); break;
case IROp::SubConst: gpr.SetImm(rt, gpr.GetImm(rs) - uimm); break;
case IROp::AndConst: gpr.SetImm(rt, gpr.GetImm(rs) & uimm); break;
case IROp::OrConst: gpr.SetImm(rt, gpr.GetImm(rs) | uimm); break;
case IROp::XorConst: gpr.SetImm(rt, gpr.GetImm(rs) ^ uimm); break;
}
} else {
gpr.MapDirtyIn(rt, rs);
ir.Write(OP, rt, ir.AddConstant(uimm));
ir.Write(OP, rt, rs, ir.AddConstant(uimm));
}
}
@ -95,8 +95,7 @@ void IRJit::Comp_IType(MIPSOpcode op) {
break;
}
gpr.MapDirtyIn(rt, rs);
// Grab the sign bit (< 0) as 1/0. Slightly faster than a shift.
ir.Write(IROp::Slt, rt, rs, ir.AddConstant(simm));
ir.Write(IROp::SltConst, rt, rs, ir.AddConstant(simm));
break;
case 11: // R(rt) = R(rs) < suimm; break; //sltiu
@ -105,7 +104,7 @@ void IRJit::Comp_IType(MIPSOpcode op) {
break;
}
gpr.MapDirtyIn(rt, rs);
ir.Write(IROp::SltU, rt, rs, ir.AddConstant(suimm));
ir.Write(IROp::SltUConst, rt, rs, ir.AddConstant(suimm));
break;
case 15: // R(rt) = uimm << 16; //lui
@ -167,6 +166,7 @@ void IRJit::CompType3(MIPSGPReg rd, MIPSGPReg rs, MIPSGPReg rt, IROp op, IROp co
// Luckily, it was just an imm.
gpr.SetImm(rhs, rhsImm);
}
return;
}
// Can't do the RSB optimization on ARM64 - no RSB!
@ -220,10 +220,17 @@ void IRJit::Comp_RType3(MIPSOpcode op) {
case 39: // R(rd) = ~(R(rs) | R(rt)); break; //nor
if (gpr.IsImm(rs) && gpr.IsImm(rt)) {
gpr.SetImm(rd, ~(gpr.GetImm(rs) | gpr.GetImm(rt)));
}
ir.Write(IROp::Or, IRTEMP_0, rs, rt);
ir.Write(IROp::Not, rd, IRTEMP_0);
} else {
gpr.MapDirtyInIn(rd, rs, rt);
if (rs == 0) {
ir.Write(IROp::Not, rd, rt);
} else if (rt == 0) {
ir.Write(IROp::Not, rd, rs);
} else {
ir.Write(IROp::Or, IRTEMP_0, rs, rt);
ir.Write(IROp::Not, rd, IRTEMP_0);
}
}
break;
case 42: //R(rd) = (int)R(rs) < (int)R(rt); break; //slt
@ -323,9 +330,9 @@ void IRJit::Comp_ShiftType(MIPSOpcode op) {
// WARNING : ROTR
switch (op & 0x3f) {
case 0: CompShiftImm(op, IROp::Shl, sa); break; //sll
case 2: CompShiftImm(op, rs == 1 ? IROp::Ror : IROp::Shr, sa); break; //srl
case 3: CompShiftImm(op, IROp::Sar, sa); break; //sra
case 0: CompShiftImm(op, IROp::ShlImm, sa); break; //sll
case 2: CompShiftImm(op, (rs == 1 ? IROp::RorImm : IROp::ShrImm), sa); break; //srl
case 3: CompShiftImm(op, IROp::SarImm, sa); break; //sra
case 4: CompShiftVar(op, IROp::Shl, IROp::ShlImm); break; //sllv
case 6: CompShiftVar(op, (fd == 1 ? IROp::Ror : IROp::Shr), (fd == 1 ? IROp::RorImm : IROp::ShrImm)); break; //srlv
case 7: CompShiftVar(op, IROp::Sar, IROp::SarImm); break; //srav

View file

@ -72,22 +72,28 @@ void IRJit::BranchRSRTComp(MIPSOpcode op, IRComparison cc, bool likely)
MIPSGPReg lhs = rs;
MIPSGPReg rhs = rt;
if (!delaySlotIsNice) {
ir.Write(IROp::Mov, IRTEMP_0, rs);
ir.Write(IROp::Mov, IRTEMP_1, rt);
lhs = (MIPSGPReg)IRTEMP_0;
rhs = (MIPSGPReg)IRTEMP_1;
if (!delaySlotIsNice && !likely) { // if likely, we don't need this
if (rs != 0) {
ir.Write(IROp::Mov, IRTEMP_0, rs);
lhs = (MIPSGPReg)IRTEMP_0;
}
if (rt != 0) {
ir.Write(IROp::Mov, IRTEMP_1, rt);
rhs = (MIPSGPReg)IRTEMP_1;
}
}
if (!likely)
CompileDelaySlot();
gpr.MapInIn(lhs, rhs);
FlushAll();
ir.Write(ComparisonToExit(cc), ir.AddConstant(GetCompilerPC() + 8), lhs, rhs);
// This makes the block "impure" :(
if (likely)
CompileDelaySlot();
FlushAll();
ir.Write(IROp::ExitToConst, ir.AddConstant(targetAddr));
js.compiling = false;
@ -105,19 +111,25 @@ void IRJit::BranchRSZeroComp(MIPSOpcode op, IRComparison cc, bool andLink, bool
MIPSOpcode delaySlotOp = GetOffsetInstruction(1);
bool delaySlotIsNice = IsDelaySlotNiceReg(op, delaySlotOp, rs);
ir.Write(IROp::Downcount, 0, js.downcountAmount & 0xFF, js.downcountAmount >> 8);
if (!likely && delaySlotIsNice)
CompileDelaySlot();
int lhs = rs;
gpr.MapIn(rs);
if (!delaySlotIsNice) {
if (!delaySlotIsNice && !likely) { // if likely, we don't need this
ir.Write(IROp::Mov, IRTEMP_0, rs);
lhs = IRTEMP_0;
}
if (andLink)
gpr.SetImm(MIPS_REG_RA, GetCompilerPC() + 8);
FlushAll();
ir.Write(ComparisonToExit(cc), ir.AddConstant(GetCompilerPC() + 8), lhs);
if (likely) {
CompileDelaySlot();
}
// Taken
FlushAll();
ir.Write(IROp::ExitToConst, ir.AddConstant(targetAddr));
js.compiling = false;
}
@ -173,12 +185,15 @@ void IRJit::BranchFPFlag(MIPSOpcode op, IRComparison cc, bool likely) {
if (!likely)
CompileDelaySlot();
ir.Write(IROp::Downcount, 0, js.downcountAmount & 0xFF, js.downcountAmount >> 8);
FlushAll();
// Not taken
ir.Write(ComparisonToExit(cc), ir.AddConstant(GetCompilerPC() + 8), IRTEMP_0, 0);
// Taken
if (likely)
CompileDelaySlot();
FlushAll();
ir.Write(IROp::ExitToConst, ir.AddConstant(targetAddr));
js.compiling = false;
}
@ -208,6 +223,8 @@ void IRJit::BranchVFPUFlag(MIPSOpcode op, IRComparison cc, bool likely) {
ir.Write(IROp::VfpCondToReg, IRTEMP_0);
ir.Write(IROp::Downcount, 0, js.downcountAmount & 0xFF, js.downcountAmount >> 8);
// Sometimes there's a VFPU branch in a delay slot (Disgaea 2: Dark Hero Days, Zettai Hero Project, La Pucelle)
// The behavior is undefined - the CPU may take the second branch even if the first one passes.
// However, it does consistently try each branch, which these games seem to expect.
@ -223,12 +240,14 @@ void IRJit::BranchVFPUFlag(MIPSOpcode op, IRComparison cc, bool likely) {
u32 notTakenTarget = GetCompilerPC() + (delaySlotIsBranch ? 4 : 8);
ir.Write(IROp::AndConst, IRTEMP_0, IRTEMP_0, ir.AddConstant(imm3));
FlushAll();
ir.Write(ComparisonToExit(cc), ir.AddConstant(notTakenTarget), IRTEMP_0, 0);
if (likely)
CompileDelaySlot();
// Taken
FlushAll();
ir.Write(IROp::ExitToConst, ir.AddConstant(targetAddr));
js.compiling = false;
}
@ -251,6 +270,8 @@ void IRJit::Comp_Jump(MIPSOpcode op) {
u32 off = _IMM26 << 2;
u32 targetAddr = (GetCompilerPC() & 0xF0000000) | off;
ir.Write(IROp::Downcount, 0, js.downcountAmount & 0xFF, js.downcountAmount >> 8);
// Might be a stubbed address or something?
if (!Memory::IsValidAddress(targetAddr)) {
if (js.nextExit == 0) {
@ -270,8 +291,6 @@ void IRJit::Comp_Jump(MIPSOpcode op) {
break;
case 3: //jal
if (ReplaceJalTo(targetAddr))
return;
gpr.SetImm(MIPS_REG_RA, GetCompilerPC() + 8);
CompileDelaySlot();
FlushAll();
@ -299,6 +318,8 @@ void IRJit::Comp_JumpReg(MIPSOpcode op) {
if (andLink && rs == rd)
delaySlotIsNice = false;
ir.Write(IROp::Downcount, 0, js.downcountAmount & 0xFF, js.downcountAmount >> 8);
int destReg;
if (IsSyscall(delaySlotOp)) {
gpr.MapDirty(rs);
@ -336,7 +357,7 @@ void IRJit::Comp_JumpReg(MIPSOpcode op) {
break;
}
ir.Write(IROp::ExitToReg, ir.AddConstant(js.downcountAmount), rs, 0);
ir.Write(IROp::ExitToReg, destReg, 0, 0);
js.compiling = false;
}
@ -354,8 +375,7 @@ void IRJit::Comp_Syscall(MIPSOpcode op) {
js.compiling = false;
}
void IRJit::Comp_Break(MIPSOpcode op)
{
void IRJit::Comp_Break(MIPSOpcode op) {
Comp_Generic(op);
js.compiling = false;
}

View file

@ -82,7 +82,7 @@ void IRJit::Comp_FPUComp(MIPSOpcode op) {
int opc = op & 0xF;
if (opc >= 8) opc -= 8; // alias
if (opc == 0) { // f, sf (signalling false)
gpr.SetImm(MIPS_REG_FPCOND, 0);
gpr.SetImm((MIPSGPReg)IRREG_FPCOND, 0);
return;
}

View file

@ -82,7 +82,8 @@ namespace MIPSComp {
return;
}
u32 iaddr = gpr.IsImm(rs) ? offset + gpr.GetImm(rs) : 0xFFFFFFFF;
gpr.MapIn(rs);
gpr.MapDirty(rt);
int addrReg = IRTEMP_0;
switch (o) {
// Load

View file

@ -1,8 +1,13 @@
#include "Core/MIPS/IR/IRInst.h"
#include "Core/MIPS/IR/IRPassSimplify.h"
#include "Core/MIPS/MIPSDebugInterface.h"
#include "Core/MIPS/MIPSTables.h"
#include "Core/MemMap.h"
#include "Core/HLE/HLE.h"
IRMeta meta[] = {
{ IROp::SetConst, "SetConst", "GC" },
{ IROp::SetConst, "SetConst", "GC_" },
{ IROp::Mov, "Mov", "GG" },
{ IROp::Add, "Add", "GGG" },
{ IROp::Sub, "Sub", "GGG" },
{ IROp::Neg, "Neg", "GG" },
@ -23,9 +28,9 @@ IRMeta meta[] = {
{ IROp::ShrImm, "ShrImm", "GGI" },
{ IROp::SarImm, "SarImm", "GGI" },
{ IROp::RorImm, "RorImm", "GGI" },
{ IROp::Slt, "Slt","GGC" },
{ IROp::SltConst, "SltConst","GGC" },
{ IROp::SltU, "SltU", "GGC" },
{ IROp::Slt, "Slt", "GGG" },
{ IROp::SltConst, "SltConst", "GGC" },
{ IROp::SltU, "SltU", "GGG" },
{ IROp::SltUConst, "SltUConst", "GGC" },
{ IROp::Clz, "Clz", "GG" },
{ IROp::MovZ, "MovZ", "GGG" },
@ -37,6 +42,14 @@ IRMeta meta[] = {
{ IROp::Mul, "Mul", "_GG" },
{ IROp::Ext8to32, "Ext8to32", "GG" },
{ IROp::Ext16to32, "Ext16to32", "GG" },
{ IROp::Load8, "Load8", "GGC" },
{ IROp::Load8Ext, "Load8", "GGC" },
{ IROp::Load16, "Load16", "GGC" },
{ IROp::Load16Ext, "Load16Ext", "GGC" },
{ IROp::Load32, "Load32", "GGC" },
{ IROp::Store8, "Store8", "GGC" },
{ IROp::Store16, "Store16", "GGC" },
{ IROp::Store32, "Store32", "GGC" },
{ IROp::FAdd, "FAdd", "FFF" },
{ IROp::FSub, "FSub", "FFF" },
{ IROp::FMul, "FMul", "FFF" },
@ -57,8 +70,16 @@ IRMeta meta[] = {
{ IROp::SetCtrlVFPU, "SetCtrlVFPU", "T" },
{ IROp::Interpret, "Interpret", "_C" },
{ IROp::Downcount, "Downcount", "_II" },
{ IROp::ExitToConst, "Exit", "C" },
{ IROp::ExitToConstIfEq, "ExitIfEq", "CGG" },
{ IROp::ExitToConstIfNeq, "ExitIfNeq", "CGG" },
{ IROp::ExitToConstIfGtZ, "ExitIfGtZ", "CG" },
{ IROp::ExitToConstIfGeZ, "ExitIfGeZ", "CG" },
{ IROp::ExitToConstIfLeZ, "ExitIfLeZ", "CG" },
{ IROp::ExitToConstIfLtZ, "ExitIfLtZ", "CG" },
{ IROp::ExitToReg, "ExitToReg", "G" },
{ IROp::Syscall, "Syscall", "_C"},
{ IROp::SetPC, "SetPC", "_C"},
{ IROp::SetPC, "SetPC", "_G"},
};
const IRMeta *metaIndex[256];
@ -82,9 +103,39 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int c
case IROp::Sub:
mips->r[inst->dest] = mips->r[inst->src1] - mips->r[inst->src2];
break;
case IROp::And:
mips->r[inst->dest] = mips->r[inst->src1] & mips->r[inst->src2];
break;
case IROp::Or:
mips->r[inst->dest] = mips->r[inst->src1] | mips->r[inst->src2];
break;
case IROp::Xor:
mips->r[inst->dest] = mips->r[inst->src1] ^ mips->r[inst->src2];
break;
case IROp::Mov:
mips->r[inst->dest] = mips->r[inst->src1];
break;
case IROp::AddConst:
mips->r[inst->dest] = mips->r[inst->src1] + constPool[inst->src2];
break;
case IROp::SubConst:
mips->r[inst->dest] = mips->r[inst->src1] - constPool[inst->src2];
break;
case IROp::AndConst:
mips->r[inst->dest] = mips->r[inst->src1] & constPool[inst->src2];
break;
case IROp::OrConst:
mips->r[inst->dest] = mips->r[inst->src1] | constPool[inst->src2];
break;
case IROp::XorConst:
mips->r[inst->dest] = mips->r[inst->src1] ^ constPool[inst->src2];
break;
case IROp::Neg:
mips->r[inst->dest] = -(s32)mips->r[inst->src1];
break;
case IROp::Not:
mips->r[inst->dest] = ~mips->r[inst->src1];
break;
case IROp::Ext8to32:
mips->r[inst->dest] = (s32)(s8)mips->r[inst->src1];
break;
@ -152,6 +203,22 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int c
}
break;
case IROp::Slt:
mips->r[inst->dest] = (s32)mips->r[inst->src1] < (s32)mips->r[inst->src2];
break;
case IROp::SltU:
mips->r[inst->dest] = mips->r[inst->src1] < mips->r[inst->src2];
break;
case IROp::SltConst:
mips->r[inst->dest] = (s32)mips->r[inst->src1] < (s32)constPool[inst->src2];
break;
case IROp::SltUConst:
mips->r[inst->dest] = mips->r[inst->src1] < constPool[inst->src2];
break;
case IROp::MovZ:
if (mips->r[inst->src1] == 0)
mips->r[inst->dest] = mips->r[inst->src2];
@ -208,10 +275,10 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int c
break;
case IROp::ExitToConst:
return constPool[inst->src1];
return constPool[inst->dest];
case IROp::ExitToReg:
return mips->r[inst->src1];
return mips->r[inst->dest];
case IROp::ExitToConstIfEq:
if (mips->r[inst->src1] == mips->r[inst->src2])
@ -238,8 +305,28 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int c
return constPool[inst->dest];
break;
case IROp::Downcount:
mips->downcount -= (inst->src1) | ((inst->src2) << 8);
break;
case IROp::SetPC:
return mips->pc = mips->r[inst->src1];
mips->pc = mips->r[inst->src1];
break;
case IROp::Syscall:
// SetPC was executed before.
{
MIPSOpcode op(constPool[inst->src1]);
CallSyscall(op);
return mips->pc;
}
case IROp::Interpret: // SLOW fallback. Can be made faster.
{
MIPSOpcode op(constPool[inst->src1]);
MIPSInterpret(op);
break;
}
default:
Crash();
@ -262,14 +349,13 @@ void IRWriter::Write(IROp op, u8 dst, u8 src1, u8 src2) {
}
void IRWriter::WriteSetConstant(u8 dst, u32 value) {
// TODO: Check for the fixed ones first.
Write(IROp::SetConstImm, AddConstant(value));
Write(IROp::SetConst, dst, AddConstant(value));
}
int IRWriter::AddConstant(u32 value) {
for (size_t i = 0; i < constPool_.size(); i++) {
if (constPool_[i] == value)
return i;
return (int)i;
}
constPool_.push_back(value);
return (int)constPool_.size() - 1;
@ -281,10 +367,25 @@ int IRWriter::AddConstantFloat(float value) {
return AddConstant(val);
}
void IRWriter::Simplify() {
SimplifyInPlace(&insts_[0], insts_.size(), constPool_.data());
}
const char *GetGPRName(int r) {
if (r < 32) {
return currentDebugMIPS->GetRegName(0, r);
}
switch (r) {
case IRTEMP_0: return "irtemp0";
case IRTEMP_1: return "irtemp1";
default: return "(unk)";
}
}
void DisassembleParam(char *buf, int bufSize, u8 param, char type, const u32 *constPool) {
switch (type) {
case 'G':
snprintf(buf, bufSize, "r%d", param);
snprintf(buf, bufSize, "%s", GetGPRName(param));
break;
case 'F':
snprintf(buf, bufSize, "r%d", param);
@ -292,6 +393,13 @@ void DisassembleParam(char *buf, int bufSize, u8 param, char type, const u32 *co
case 'C':
snprintf(buf, bufSize, "%08x", constPool[param]);
break;
case 'I':
snprintf(buf, bufSize, "%02x", param);
break;
case '_':
case '\0':
buf[0] = 0;
break;
default:
snprintf(buf, bufSize, "?");
break;
@ -300,17 +408,21 @@ void DisassembleParam(char *buf, int bufSize, u8 param, char type, const u32 *co
void DisassembleIR(char *buf, size_t bufsize, IRInst inst, const u32 *constPool) {
const IRMeta *meta = metaIndex[(int)inst.op];
if (!meta) {
snprintf(buf, bufsize, "Unknown %d", (int)inst.op);
return;
}
char bufDst[16];
char bufSrc1[16];
char bufSrc2[16];
DisassembleParam(bufDst, sizeof(bufDst) - 2, inst.dest, meta->types[0], constPool);
DisassembleParam(bufSrc1, sizeof(bufSrc1) - 2, inst.dest, meta->types[1], constPool);
DisassembleParam(bufSrc2, sizeof(bufSrc2), inst.dest, meta->types[2], constPool);
if (meta->types[1]) {
DisassembleParam(bufSrc1, sizeof(bufSrc1) - 2, inst.src1, meta->types[1], constPool);
DisassembleParam(bufSrc2, sizeof(bufSrc2), inst.src2, meta->types[2], constPool);
if (meta->types[1] && meta->types[0] != '_') {
strcat(bufDst, ", ");
}
if (meta->types[2]) {
if (meta->types[2] && meta->types[1] != '_') {
strcat(bufSrc1, ", ");
}
snprintf(buf, bufsize, "%s %s%s%s", meta->name, bufDst, bufSrc1, bufSrc2);
}
}

View file

@ -17,7 +17,6 @@
enum class IROp : u8 {
SetConst,
SetConstImm,
FSetConst,
Mov,
@ -202,6 +201,8 @@ enum {
// Hacky way to get to other state
IRREG_LO = 226, // offset of lo in MIPSState / 4
IRREG_HI = 227,
IRREG_FCR31 = 228,
IRREG_FPCOND = 229
};
enum class IRParam {
@ -249,6 +250,8 @@ public:
constPool_.clear();
}
void Simplify();
const std::vector<IRInst> &GetInstructions() { return insts_; }
const std::vector<u32> &GetConstants() { return constPool_; }
@ -258,3 +261,4 @@ private:
};
void DisassembleIR(char *buf, size_t bufsize, IRInst inst, const u32 *constPool);
void InitIR();

View file

@ -38,32 +38,18 @@
#include "Core/MIPS/IR/IRJit.h"
#include "Core/MIPS/JitCommon/JitCommon.h"
void DisassembleArm64Print(const u8 *data, int size) {
std::vector<std::string> lines = DisassembleArm64(data, size);
for (auto s : lines) {
ILOG("%s", s.c_str());
}
/*
ILOG("+++");
// A format friendly to Online Disassembler which gets endianness wrong
for (size_t i = 0; i < lines.size(); i++) {
uint32_t opcode = ((const uint32_t *)data)[i];
ILOG("%d/%d: %08x", (int)(i+1), (int)lines.size(), swap32(opcode));
}
ILOG("===");
ILOG("===");*/
}
namespace MIPSComp
{
IRJit::IRJit(MIPSState *mips) : gpr(), mips_(mips) {
logBlocks = 0;
dontLogBlocks = 0;
js.startDefaultPrefix = mips_->HasDefaultPrefix();
js.startDefaultPrefix = true;
js.currentRoundingFunc = convertS0ToSCRATCH1[0];
u32 size = 128 * 1024;
blTrampolines_ = kernelMemory.Alloc(size, true, "trampoline");
logBlocks = 100;
InitIR();
}
IRJit::~IRJit() {
@ -102,7 +88,8 @@ void IRJit::DoDummyState(PointerWrap &p) {
}
void IRJit::FlushAll() {
FlushPrefixV();
gpr.FlushAll();
// FlushPrefixV();
}
void IRJit::FlushPrefixV() {
@ -162,6 +149,7 @@ void IRJit::Compile(u32 em_address) {
int block_num = blocks_.AllocateBlock(em_address);
IRBlock *b = blocks_.GetBlock(block_num);
DoJit(em_address, b);
b->Finalize(block_num); // Overwrites the first instruction
bool cleanSlate = false;
@ -192,7 +180,35 @@ void IRJit::Compile(u32 em_address) {
void IRJit::RunLoopUntil(u64 globalticks) {
PROFILE_THIS_SCOPE("jit");
((void (*)())enterDispatcher)();
// ApplyRoundingMode(true);
// IR Dispatcher
while (true) {
// RestoreRoundingMode(true);
CoreTiming::Advance();
// ApplyRoundingMode(true);
if (coreState != 0) {
break;
}
while (mips_->downcount >= 0) {
u32 inst = Memory::ReadUnchecked_U32(mips_->pc);
u32 opcode = inst >> 24;
u32 data = inst & 0xFFFFFF;
if (opcode == (MIPS_EMUHACK_OPCODE >> 24)) {
IRBlock *block = blocks_.GetBlock(data);
ILOG("Run block at %08x : v1=%08x a0=%08x", mips_->pc, mips_->r[MIPS_REG_V1], mips_->r[MIPS_REG_A0]);
mips_->pc = IRInterpret(mips_, block->GetInstructions(), block->GetConstants(), block->GetNumInstructions());
} else {
// RestoreRoundingMode(true);
ILOG("Compile block at %08x : v1=%08x a0=%08x", mips_->pc, mips_->r[MIPS_REG_V1], mips_->r[MIPS_REG_A0]);
Compile(mips_->pc);
// ApplyRoundingMode(true);
}
}
}
// RestoreRoundingMode(true);
}
u32 IRJit::GetCompilerPC() {
@ -230,24 +246,28 @@ void IRJit::DoJit(u32 em_address, IRBlock *b) {
js.numInstructions++;
}
ir.Simplify();
b->SetInstructions(ir.GetInstructions(), ir.GetConstants());
char temp[256];
if (logBlocks > 0 && dontLogBlocks == 0) {
char temp2[256];
ILOG("=============== mips %d ===============", blocks_.GetNumBlocks());
for (u32 cpc = em_address; cpc != GetCompilerPC() + 4; cpc += 4) {
MIPSDisAsm(Memory::Read_Opcode_JIT(cpc), cpc, temp, true);
ILOG("M: %08x %s", cpc, temp);
temp2[0] = 0;
MIPSDisAsm(Memory::Read_Opcode_JIT(cpc), cpc, temp2, true);
ILOG("M: %08x %s", cpc, temp2);
}
}
if (logBlocks > 0 && dontLogBlocks == 0) {
ILOG("=============== IR (%d instructions) ===============", js.numInstructions);
for (int i = 0; i < js.numInstructions; i++) {
for (int i = 0; i < ir.GetInstructions().size(); i++) {
char buf[256];
DisassembleIR(buf, sizeof(buf), ir.GetInstructions()[i], ir.GetConstants().data());
ILOG("%s", buf);
}
ILOG("=============== end =================");
}
if (logBlocks > 0)
@ -330,4 +350,15 @@ void IRBlockCache::InvalidateICache(u32 addess, u32 length) {
// TODO
}
void IRBlock::Finalize(int number) {
origFirstOpcode_= Memory::Read_Opcode_JIT(origAddr_);
MIPSOpcode opcode = MIPSOpcode(MIPS_EMUHACK_OPCODE | number);
Memory::Write_Opcode_JIT(origAddr_, opcode);
}
MIPSOpcode IRJit::GetOriginalOp(MIPSOpcode op) {
IRBlock *b = blocks_.GetBlock(op.encoding & 0xFFFFFF);
return b->GetOriginalFirstOp();
}
} // namespace MIPSComp

View file

@ -34,8 +34,18 @@ namespace MIPSComp {
// TODO : Use arena allocators. For now let's just malloc.
class IRBlock {
public:
IRBlock() {}
IRBlock() : instr_(nullptr), const_(nullptr), numInstructions_(0), numConstants_(0), origAddr_(0) {}
IRBlock(u32 emAddr) : instr_(nullptr), const_(nullptr), origAddr_(emAddr), numInstructions_(0) {}
IRBlock(IRBlock &&b) {
instr_ = b.instr_;
const_ = b.const_;
numInstructions_ = b.numInstructions_;
numConstants_ = b.numConstants_;
origAddr_ = b.origAddr_;
b.instr_ = nullptr;
b.const_ = nullptr;
}
~IRBlock() {
delete[] instr_;
delete[] const_;
@ -50,12 +60,20 @@ public:
memcpy(const_, constants.data(), sizeof(u32) * constants.size());
}
const IRInst *GetInstructions() const { return instr_; }
const u32 *GetConstants() const { return const_; }
int GetNumInstructions() const { return numInstructions_; }
MIPSOpcode GetOriginalFirstOp() const { return origFirstOpcode_; }
void Finalize(int number);
private:
IRInst *instr_;
u32 *const_;
u16 numInstructions_;
u16 numConstants_;
u32 origAddr_;
MIPSOpcode origFirstOpcode_;
};
class IRBlockCache {
@ -170,7 +188,8 @@ public:
int Replace_fabsf();
// Not using a regular block cache.
JitBlockCache *GetBlockCache() { return nullptr; }
JitBlockCache *GetBlockCache() override { return nullptr; }
MIPSOpcode GetOriginalOp(MIPSOpcode op) override;
void ClearCache();
void InvalidateCache();

View file

@ -0,0 +1,14 @@
#include "Core/MIPS/IR/IRPassSimplify.h"
void SimplifyInPlace(IRInst *inst, int count, const u32 *constPool) {
for (int i = 0; i < count; i++) {
switch (inst[i].op) {
case IROp::AddConst:
if (constPool[inst[i].src2] == 0)
inst[i].op = IROp::Mov;
break;
default:
break;
}
}
}

View file

@ -0,0 +1,5 @@
#pragma once
#include "Core/MIPS/IR/IRInst.h"
void SimplifyInPlace(IRInst *inst, int count, const u32 *constPool);

View file

@ -42,5 +42,7 @@ void IRRegCache::Start(IRWriter *ir) {
}
void IRRegCache::FlushAll() {
for (int i = 0; i < TOTAL_MAPPABLE_MIPSREGS; i++) {
Dirty((MIPSGPReg)i);
}
}

View file

@ -57,6 +57,7 @@ namespace MIPSComp {
virtual void Compile(u32 em_address) = 0;
virtual void ClearCache() = 0;
virtual void EatPrefix() = 0;
virtual MIPSOpcode GetOriginalOp(MIPSOpcode op) = 0;
// Block linking. This may need to work differently for whole-function JITs and stuff
// like that.

View file

@ -839,4 +839,14 @@ void Jit::CallProtectedFunction(const void *func, const OpArg &arg1, const u32 a
void Jit::Comp_DoNothing(MIPSOpcode op) { }
MIPSOpcode Jit::GetOriginalOp(MIPSOpcode op) {
JitBlockCache *bc = GetBlockCache();
int block_num = bc->GetBlockNumberFromEmuHackOp(op, true);
if (block_num >= 0) {
return bc->GetOriginalFirstOp(block_num);
} else {
return op;
}
}
} // namespace

View file

@ -161,6 +161,7 @@ public:
void UpdateRoundingMode();
JitBlockCache *GetBlockCache() { return &blocks; }
MIPSOpcode GetOriginalOp(MIPSOpcode op) override;
void ClearCache();
void InvalidateCache() override;

View file

@ -479,13 +479,7 @@ Opcode Read_Opcode_JIT(u32 address)
{
Opcode inst = Opcode(Read_U32(address));
if (MIPS_IS_RUNBLOCK(inst.encoding) && MIPSComp::jit) {
JitBlockCache *bc = MIPSComp::jit->GetBlockCache();
int block_num = bc->GetBlockNumberFromEmuHackOp(inst, true);
if (block_num >= 0) {
return bc->GetOriginalFirstOp(block_num);
} else {
return inst;
}
return MIPSComp::jit->GetOriginalOp(inst);
} else {
return inst;
}