mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
It's kind of starting to run
This commit is contained in:
parent
d399c4a470
commit
4acf85aa06
17 changed files with 309 additions and 80 deletions
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
|
|
14
Core/MIPS/IR/IRPassSimplify.cpp
Normal file
14
Core/MIPS/IR/IRPassSimplify.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
5
Core/MIPS/IR/IRPassSimplify.h
Normal file
5
Core/MIPS/IR/IRPassSimplify.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "Core/MIPS/IR/IRInst.h"
|
||||
|
||||
void SimplifyInPlace(IRInst *inst, int count, const u32 *constPool);
|
|
@ -42,5 +42,7 @@ void IRRegCache::Start(IRWriter *ir) {
|
|||
}
|
||||
|
||||
void IRRegCache::FlushAll() {
|
||||
|
||||
for (int i = 0; i < TOTAL_MAPPABLE_MIPSREGS; i++) {
|
||||
Dirty((MIPSGPReg)i);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -161,6 +161,7 @@ public:
|
|||
void UpdateRoundingMode();
|
||||
|
||||
JitBlockCache *GetBlockCache() { return &blocks; }
|
||||
MIPSOpcode GetOriginalOp(MIPSOpcode op) override;
|
||||
|
||||
void ClearCache();
|
||||
void InvalidateCache() override;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue