diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2d137ba551..655d8f7e13 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1077,6 +1077,25 @@ include_directories(ext/xxhash)
set(CoreExtra)
set(CoreExtraLibs)
+
+set(CoreExtra ${CoreExtra}
+ Core/MIPS/IR/IRCompALU.cpp
+ Core/MIPS/IR/IRCompBranch.cpp
+ Core/MIPS/IR/IRCompFPU.cpp
+ Core/MIPS/IR/IRCompLoadStore.cpp
+ Core/MIPS/IR/IRCompVFPU.cpp
+ Core/MIPS/IR/IRInst.cpp
+ Core/MIPS/IR/IRInst.h
+ Core/MIPS/IR/IRInterpreter.cpp
+ Core/MIPS/IR/IRInterpreter.h
+ Core/MIPS/IR/IRJit.cpp
+ Core/MIPS/IR/IRJit.h
+ Core/MIPS/IR/IRPassSimplify.cpp
+ Core/MIPS/IR/IRPassSimplify.h
+ Core/MIPS/IR/IRRegCache.cpp
+ Core/MIPS/IR/IRRegCache.h
+ )
+
if(ARM)
set(CoreExtra ${CoreExtra}
Core/MIPS/ARM/ArmAsm.cpp
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index e902adf733..561d83d2d3 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -188,6 +188,7 @@
+
@@ -518,6 +519,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 5905d62de1..0fc92ec2fa 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -667,6 +667,9 @@
MIPS\IR
+
+ MIPS\IR
+
@@ -1224,6 +1227,9 @@
MIPS\IR
+
+ MIPS\IR
+
diff --git a/Core/MIPS/ARM/ArmJit.cpp b/Core/MIPS/ARM/ArmJit.cpp
index eaf0a97411..508a6c3b1f 100644
--- a/Core/MIPS/ARM/ArmJit.cpp
+++ b/Core/MIPS/ARM/ArmJit.cpp
@@ -677,4 +677,14 @@ void ArmJit::WriteSyscallExit()
void ArmJit::Comp_DoNothing(MIPSOpcode op) { }
+MIPSOpcode ArmJit::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
diff --git a/Core/MIPS/ARM/ArmJit.h b/Core/MIPS/ARM/ArmJit.h
index 07b70af968..efdde624bf 100644
--- a/Core/MIPS/ARM/ArmJit.h
+++ b/Core/MIPS/ARM/ArmJit.h
@@ -53,6 +53,7 @@ public:
void Compile(u32 em_address) override; // Compiles a block at current MIPS PC
bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
+ MIPSOpcode GetOriginalOp(MIPSOpcode op) override;
void Comp_RunBlock(MIPSOpcode op) override;
void Comp_ReplacementFunc(MIPSOpcode op) override;
diff --git a/Core/MIPS/ARM64/Arm64Jit.cpp b/Core/MIPS/ARM64/Arm64Jit.cpp
index 83c7ec6b97..a3f032ea5a 100644
--- a/Core/MIPS/ARM64/Arm64Jit.cpp
+++ b/Core/MIPS/ARM64/Arm64Jit.cpp
@@ -634,4 +634,14 @@ void Arm64Jit::WriteSyscallExit() {
void Arm64Jit::Comp_DoNothing(MIPSOpcode op) { }
+MIPSOpcode Arm64Jit::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
diff --git a/Core/MIPS/ARM64/Arm64Jit.h b/Core/MIPS/ARM64/Arm64Jit.h
index e1c9cf5dec..e341df3e79 100644
--- a/Core/MIPS/ARM64/Arm64Jit.h
+++ b/Core/MIPS/ARM64/Arm64Jit.h
@@ -54,6 +54,7 @@ public:
const u8 *DoJit(u32 em_address, JitBlock *b);
bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
+ MIPSOpcode GetOriginalOp(MIPSOpcode op) override;
void Comp_RunBlock(MIPSOpcode op) override;
void Comp_ReplacementFunc(MIPSOpcode op) override;
diff --git a/Core/MIPS/IR/IRInst.cpp b/Core/MIPS/IR/IRInst.cpp
index 45902a4485..66ee7561f2 100644
--- a/Core/MIPS/IR/IRInst.cpp
+++ b/Core/MIPS/IR/IRInst.cpp
@@ -1,12 +1,7 @@
+#include "Common/CommonFuncs.h"
#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"
-#include "Core/HLE/ReplaceTables.h"
-
-#include "math/math_util.h"
static const IRMeta irMeta[] = {
{ IROp::SetConst, "SetConst", "GC" },
@@ -116,406 +111,6 @@ void InitIR() {
}
}
-u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int count) {
- const IRInst *end = inst + count;
- while (inst != end) {
- switch (inst->op) {
- case IROp::SetConst:
- mips->r[inst->dest] = constPool[inst->src1];
- break;
- case IROp::SetConstF:
- memcpy(&mips->f[inst->dest], &constPool[inst->src1], 4);
- break;
- case IROp::SetConstV:
- memcpy(&mips->f[inst->dest], &constPool[inst->src1], 4);
- break;
- case IROp::Add:
- mips->r[inst->dest] = mips->r[inst->src1] + mips->r[inst->src2];
- break;
- 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;
- case IROp::Ext16to32:
- mips->r[inst->dest] = (s32)(s16)mips->r[inst->src1];
- break;
-
- case IROp::Load8:
- mips->r[inst->dest] = Memory::ReadUnchecked_U8(mips->r[inst->src1] + constPool[inst->src2]);
- break;
- case IROp::Load8Ext:
- mips->r[inst->dest] = (s32)(s8)Memory::ReadUnchecked_U8(mips->r[inst->src1] + constPool[inst->src2]);
- break;
- case IROp::Load16:
- mips->r[inst->dest] = Memory::ReadUnchecked_U16(mips->r[inst->src1] + constPool[inst->src2]);
- break;
- case IROp::Load16Ext:
- mips->r[inst->dest] = (s32)(s16)Memory::ReadUnchecked_U16(mips->r[inst->src1] + constPool[inst->src2]);
- break;
- case IROp::Load32:
- mips->r[inst->dest] = Memory::ReadUnchecked_U32(mips->r[inst->src1] + constPool[inst->src2]);
- break;
- case IROp::LoadFloat:
- mips->f[inst->dest] = Memory::ReadUnchecked_Float(mips->r[inst->src1] + constPool[inst->src2]);
- break;
- case IROp::LoadFloatV:
- mips->v[voffset[inst->dest]] = Memory::ReadUnchecked_Float(mips->r[inst->src1] + constPool[inst->src2]);
- break;
-
- case IROp::Store8:
- Memory::WriteUnchecked_U8(mips->r[inst->src3], mips->r[inst->src1] + constPool[inst->src2]);
- break;
- case IROp::Store16:
- Memory::WriteUnchecked_U16(mips->r[inst->src3], mips->r[inst->src1] + constPool[inst->src2]);
- break;
- case IROp::Store32:
- Memory::WriteUnchecked_U32(mips->r[inst->src3], mips->r[inst->src1] + constPool[inst->src2]);
- break;
- case IROp::StoreFloat:
- Memory::WriteUnchecked_Float(mips->f[inst->src3], mips->r[inst->src1] + constPool[inst->src2]);
- break;
- case IROp::StoreFloatV:
- Memory::WriteUnchecked_Float(mips->v[voffset[inst->src3]], mips->r[inst->src1] + constPool[inst->src2]);
- break;
-
- case IROp::ShlImm:
- mips->r[inst->dest] = mips->r[inst->src1] << (int)inst->src2;
- break;
- case IROp::ShrImm:
- mips->r[inst->dest] = mips->r[inst->src1] >> (int)inst->src2;
- break;
- case IROp::SarImm:
- mips->r[inst->dest] = (s32)mips->r[inst->src1] >> (int)inst->src2;
- break;
- case IROp::RorImm:
- {
- u32 x = mips->r[inst->src1];
- int sa = inst->src2;
- mips->r[inst->dest] = (x >> sa) | (x << (32 - sa));
- }
- break;
-
- case IROp::Shl:
- mips->r[inst->dest] = mips->r[inst->src1] << (mips->r[inst->src2] & 31);
- break;
- case IROp::Shr:
- mips->r[inst->dest] = mips->r[inst->src1] >> (mips->r[inst->src2] & 31);
- break;
- case IROp::Sar:
- mips->r[inst->dest] = (s32)mips->r[inst->src1] >> (mips->r[inst->src2] & 31);
- break;
- case IROp::Ror:
- {
- u32 x = mips->r[inst->src1];
- int sa = mips->r[inst->src2] & 31;
- mips->r[inst->dest] = (x >> sa) | (x << (32 - sa));
- }
- break;
-
- case IROp::Clz:
- {
- int x = 31;
- int count = 0;
- int value = mips->r[inst->src1];
- while (x >= 0 && !(value & (1 << x))) {
- count++;
- x--;
- }
- mips->r[inst->dest] = count;
- 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];
- break;
- case IROp::MovNZ:
- if (mips->r[inst->src1] != 0)
- mips->r[inst->dest] = mips->r[inst->src2];
- break;
-
- case IROp::Max:
- mips->r[inst->dest] = (s32)mips->r[inst->src1] > (s32)mips->r[inst->src2] ? mips->r[inst->src1] : mips->r[inst->src2];
- break;
- case IROp::Min:
- mips->r[inst->dest] = (s32)mips->r[inst->src1] < (s32)mips->r[inst->src2] ? mips->r[inst->src1] : mips->r[inst->src2];
- break;
-
- case IROp::MtLo:
- mips->lo = mips->r[inst->src1];
- break;
- case IROp::MtHi:
- mips->hi = mips->r[inst->src1];
- break;
- case IROp::MfLo:
- mips->r[inst->dest] = mips->lo;
- break;
- case IROp::MfHi:
- mips->r[inst->dest] = mips->hi;
- break;
-
- case IROp::Mult:
- {
- s64 result = (s64)(s32)mips->r[inst->src1] * (s64)(s32)mips->r[inst->src2];
- memcpy(&mips->lo, &result, 8);
- break;
- }
- case IROp::MultU:
- {
- u64 result = (u64)mips->r[inst->src1] * (u64)mips->r[inst->src2];
- memcpy(&mips->lo, &result, 8);
- break;
- }
-
- case IROp::BSwap16:
- {
- u32 x = mips->r[inst->src1];
- mips->r[inst->dest] = ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8);
- break;
- }
- case IROp::BSwap32:
- {
- u32 x = mips->r[inst->src1];
- mips->r[inst->dest] = ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | ((x & 0x000000FF) << 24);
- break;
- }
-
- case IROp::FAdd:
- mips->f[inst->dest] = mips->f[inst->src1] + mips->f[inst->src2];
- break;
- case IROp::FSub:
- mips->f[inst->dest] = mips->f[inst->src1] - mips->f[inst->src2];
- break;
- case IROp::FMul:
- mips->f[inst->dest] = mips->f[inst->src1] * mips->f[inst->src2];
- break;
- case IROp::FDiv:
- mips->f[inst->dest] = mips->f[inst->src1] / mips->f[inst->src2];
- break;
-
- case IROp::FMov:
- mips->f[inst->dest] = mips->f[inst->src1];
- break;
- case IROp::FAbs:
- mips->f[inst->dest] = fabsf(mips->f[inst->src1]);
- break;
- case IROp::FSqrt:
- mips->f[inst->dest] = sqrtf(mips->f[inst->src1]);
- break;
- case IROp::FNeg:
- mips->f[inst->dest] = -mips->f[inst->src1];
- break;
- case IROp::FpCondToReg:
- mips->r[inst->dest] = mips->fpcond;
- break;
- case IROp::VfpuCtrlToReg:
- mips->r[inst->dest] = mips->vfpuCtrl[inst->src1];
- break;
- case IROp::FRound:
- mips->fs[inst->dest] = (int)floorf(mips->f[inst->src1] + 0.5f);
- break;
- case IROp::FTrunc:
- {
- float src = mips->f[inst->src1];
- if (src >= 0.0f) {
- mips->fs[inst->dest] = (int)floorf(src);
- // Overflow, but it was positive.
- if (mips->fs[inst->dest] == -2147483648LL) {
- mips->fs[inst->dest] = 2147483647LL;
- }
- } else {
- // Overflow happens to be the right value anyway.
- mips->fs[inst->dest] = (int)ceilf(src);
- }
- break;
- }
- case IROp::FCeil:
- mips->fs[inst->dest] = (int)ceilf(mips->f[inst->src1]);
- break;
- case IROp::FFloor:
- mips->fs[inst->dest] = (int)floorf(mips->f[inst->src1]);
- break;
-
- case IROp::FCvtSW:
- mips->f[inst->dest] = (float)mips->fs[inst->src1];
- break;
- case IROp::FCvtWS:
- {
- float src = mips->f[inst->src1];
- if (my_isnanorinf(src))
- {
- mips->fs[inst->dest] = my_isinf(src) && src < 0.0f ? -2147483648LL : 2147483647LL;
- break;
- }
- switch (mips->fcr31 & 3)
- {
- case 0: mips->fs[inst->dest] = (int)round_ieee_754(src); break; // RINT_0
- case 1: mips->fs[inst->dest] = (int)src; break; // CAST_1
- case 2: mips->fs[inst->dest] = (int)ceilf(src); break; // CEIL_2
- case 3: mips->fs[inst->dest] = (int)floorf(src); break; // FLOOR_3
- }
- break; //cvt.w.s
- }
-
- case IROp::ZeroFpCond:
- mips->fpcond = 0;
- break;
-
- case IROp::FMovFromGPR:
- memcpy(&mips->f[inst->dest], &mips->r[inst->src1], 4);
- break;
- case IROp::FMovToGPR:
- memcpy(&mips->r[inst->dest], &mips->f[inst->src1], 4);
- break;
-
- case IROp::VMovFromGPR:
- memcpy(&mips->v[voffset[inst->dest]], &mips->r[inst->src1], 4);
- break;
- case IROp::VMovToGPR:
- memcpy(&mips->r[inst->dest], &mips->v[voffset[inst->src1]], 4);
- break;
-
- case IROp::ExitToConst:
- return constPool[inst->dest];
-
- case IROp::ExitToReg:
- return mips->r[inst->dest];
-
- case IROp::ExitToConstIfEq:
- if (mips->r[inst->src1] == mips->r[inst->src2])
- return constPool[inst->dest];
- break;
- case IROp::ExitToConstIfNeq:
- if (mips->r[inst->src1] != mips->r[inst->src2])
- return constPool[inst->dest];
- break;
- case IROp::ExitToConstIfGtZ:
- if ((s32)mips->r[inst->src1] > 0)
- return constPool[inst->dest];
- break;
- case IROp::ExitToConstIfGeZ:
- if ((s32)mips->r[inst->src1] >= 0)
- return constPool[inst->dest];
- break;
- case IROp::ExitToConstIfLtZ:
- if ((s32)mips->r[inst->src1] < 0)
- return constPool[inst->dest];
- break;
- case IROp::ExitToConstIfLeZ:
- if ((s32)mips->r[inst->src1] <= 0)
- return constPool[inst->dest];
- break;
-
- case IROp::Downcount:
- mips->downcount -= (inst->src1) | ((inst->src2) << 8);
- break;
-
- case IROp::SetPC:
- mips->pc = mips->r[inst->src1];
- break;
-
- case IROp::SetPCConst:
- mips->pc = constPool[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;
- }
-
- case IROp::CallReplacement:
- {
- int funcIndex = constPool[inst->src1];
- const ReplacementTableEntry *f = GetReplacementFunc(funcIndex);
- int cycles = f->replaceFunc();
- mips->downcount -= cycles;
- return mips->r[MIPS_REG_RA];
- }
-
- case IROp::Break:
- Crash();
- break;
-
- case IROp::SetCtrlVFPU:
- mips->vfpuCtrl[inst->dest] = constPool[inst->src1];
- break;
-
- default:
- Crash();
- }
-#ifdef _DEBUG
- if (mips->r[0] != 0)
- Crash();
-#endif
- inst++;
- }
-
- // If we got here, the block was badly constructed.
- Crash();
- return 0;
-}
-
void IRWriter::Write(IROp op, u8 dst, u8 src1, u8 src2) {
IRInst inst;
inst.op = op;
diff --git a/Core/MIPS/IR/IRInterpreter.cpp b/Core/MIPS/IR/IRInterpreter.cpp
new file mode 100644
index 0000000000..0c3c66188c
--- /dev/null
+++ b/Core/MIPS/IR/IRInterpreter.cpp
@@ -0,0 +1,411 @@
+#include "Core/MemMap.h"
+#include "Core/HLE/HLE.h"
+#include "Core/HLE/ReplaceTables.h"
+#include "Core/MIPS/MIPSTables.h"
+
+#include "math/math_util.h"
+#include "Common/CommonTypes.h"
+#include "Core/MemMap.h"
+#include "Core/MIPS/MIPS.h"
+#include "Core/MIPS/IR/IRInst.h"
+#include "Core/MIPS/IR/IRInterpreter.h"
+
+u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int count) {
+ const IRInst *end = inst + count;
+ while (inst != end) {
+ switch (inst->op) {
+ case IROp::SetConst:
+ mips->r[inst->dest] = constPool[inst->src1];
+ break;
+ case IROp::SetConstF:
+ memcpy(&mips->f[inst->dest], &constPool[inst->src1], 4);
+ break;
+ case IROp::SetConstV:
+ memcpy(&mips->f[inst->dest], &constPool[inst->src1], 4);
+ break;
+ case IROp::Add:
+ mips->r[inst->dest] = mips->r[inst->src1] + mips->r[inst->src2];
+ break;
+ 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;
+ case IROp::Ext16to32:
+ mips->r[inst->dest] = (s32)(s16)mips->r[inst->src1];
+ break;
+
+ case IROp::Load8:
+ mips->r[inst->dest] = Memory::ReadUnchecked_U8(mips->r[inst->src1] + constPool[inst->src2]);
+ break;
+ case IROp::Load8Ext:
+ mips->r[inst->dest] = (s32)(s8)Memory::ReadUnchecked_U8(mips->r[inst->src1] + constPool[inst->src2]);
+ break;
+ case IROp::Load16:
+ mips->r[inst->dest] = Memory::ReadUnchecked_U16(mips->r[inst->src1] + constPool[inst->src2]);
+ break;
+ case IROp::Load16Ext:
+ mips->r[inst->dest] = (s32)(s16)Memory::ReadUnchecked_U16(mips->r[inst->src1] + constPool[inst->src2]);
+ break;
+ case IROp::Load32:
+ mips->r[inst->dest] = Memory::ReadUnchecked_U32(mips->r[inst->src1] + constPool[inst->src2]);
+ break;
+ case IROp::LoadFloat:
+ mips->f[inst->dest] = Memory::ReadUnchecked_Float(mips->r[inst->src1] + constPool[inst->src2]);
+ break;
+ case IROp::LoadFloatV:
+ mips->v[voffset[inst->dest]] = Memory::ReadUnchecked_Float(mips->r[inst->src1] + constPool[inst->src2]);
+ break;
+
+ case IROp::Store8:
+ Memory::WriteUnchecked_U8(mips->r[inst->src3], mips->r[inst->src1] + constPool[inst->src2]);
+ break;
+ case IROp::Store16:
+ Memory::WriteUnchecked_U16(mips->r[inst->src3], mips->r[inst->src1] + constPool[inst->src2]);
+ break;
+ case IROp::Store32:
+ Memory::WriteUnchecked_U32(mips->r[inst->src3], mips->r[inst->src1] + constPool[inst->src2]);
+ break;
+ case IROp::StoreFloat:
+ Memory::WriteUnchecked_Float(mips->f[inst->src3], mips->r[inst->src1] + constPool[inst->src2]);
+ break;
+ case IROp::StoreFloatV:
+ Memory::WriteUnchecked_Float(mips->v[voffset[inst->src3]], mips->r[inst->src1] + constPool[inst->src2]);
+ break;
+
+ case IROp::ShlImm:
+ mips->r[inst->dest] = mips->r[inst->src1] << (int)inst->src2;
+ break;
+ case IROp::ShrImm:
+ mips->r[inst->dest] = mips->r[inst->src1] >> (int)inst->src2;
+ break;
+ case IROp::SarImm:
+ mips->r[inst->dest] = (s32)mips->r[inst->src1] >> (int)inst->src2;
+ break;
+ case IROp::RorImm:
+ {
+ u32 x = mips->r[inst->src1];
+ int sa = inst->src2;
+ mips->r[inst->dest] = (x >> sa) | (x << (32 - sa));
+ }
+ break;
+
+ case IROp::Shl:
+ mips->r[inst->dest] = mips->r[inst->src1] << (mips->r[inst->src2] & 31);
+ break;
+ case IROp::Shr:
+ mips->r[inst->dest] = mips->r[inst->src1] >> (mips->r[inst->src2] & 31);
+ break;
+ case IROp::Sar:
+ mips->r[inst->dest] = (s32)mips->r[inst->src1] >> (mips->r[inst->src2] & 31);
+ break;
+ case IROp::Ror:
+ {
+ u32 x = mips->r[inst->src1];
+ int sa = mips->r[inst->src2] & 31;
+ mips->r[inst->dest] = (x >> sa) | (x << (32 - sa));
+ }
+ break;
+
+ case IROp::Clz:
+ {
+ int x = 31;
+ int count = 0;
+ int value = mips->r[inst->src1];
+ while (x >= 0 && !(value & (1 << x))) {
+ count++;
+ x--;
+ }
+ mips->r[inst->dest] = count;
+ 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];
+ break;
+ case IROp::MovNZ:
+ if (mips->r[inst->src1] != 0)
+ mips->r[inst->dest] = mips->r[inst->src2];
+ break;
+
+ case IROp::Max:
+ mips->r[inst->dest] = (s32)mips->r[inst->src1] > (s32)mips->r[inst->src2] ? mips->r[inst->src1] : mips->r[inst->src2];
+ break;
+ case IROp::Min:
+ mips->r[inst->dest] = (s32)mips->r[inst->src1] < (s32)mips->r[inst->src2] ? mips->r[inst->src1] : mips->r[inst->src2];
+ break;
+
+ case IROp::MtLo:
+ mips->lo = mips->r[inst->src1];
+ break;
+ case IROp::MtHi:
+ mips->hi = mips->r[inst->src1];
+ break;
+ case IROp::MfLo:
+ mips->r[inst->dest] = mips->lo;
+ break;
+ case IROp::MfHi:
+ mips->r[inst->dest] = mips->hi;
+ break;
+
+ case IROp::Mult:
+ {
+ s64 result = (s64)(s32)mips->r[inst->src1] * (s64)(s32)mips->r[inst->src2];
+ memcpy(&mips->lo, &result, 8);
+ break;
+ }
+ case IROp::MultU:
+ {
+ u64 result = (u64)mips->r[inst->src1] * (u64)mips->r[inst->src2];
+ memcpy(&mips->lo, &result, 8);
+ break;
+ }
+
+ case IROp::BSwap16:
+ {
+ u32 x = mips->r[inst->src1];
+ mips->r[inst->dest] = ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8);
+ break;
+ }
+ case IROp::BSwap32:
+ {
+ u32 x = mips->r[inst->src1];
+ mips->r[inst->dest] = ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | ((x & 0x000000FF) << 24);
+ break;
+ }
+
+ case IROp::FAdd:
+ mips->f[inst->dest] = mips->f[inst->src1] + mips->f[inst->src2];
+ break;
+ case IROp::FSub:
+ mips->f[inst->dest] = mips->f[inst->src1] - mips->f[inst->src2];
+ break;
+ case IROp::FMul:
+ mips->f[inst->dest] = mips->f[inst->src1] * mips->f[inst->src2];
+ break;
+ case IROp::FDiv:
+ mips->f[inst->dest] = mips->f[inst->src1] / mips->f[inst->src2];
+ break;
+
+ case IROp::FMov:
+ mips->f[inst->dest] = mips->f[inst->src1];
+ break;
+ case IROp::FAbs:
+ mips->f[inst->dest] = fabsf(mips->f[inst->src1]);
+ break;
+ case IROp::FSqrt:
+ mips->f[inst->dest] = sqrtf(mips->f[inst->src1]);
+ break;
+ case IROp::FNeg:
+ mips->f[inst->dest] = -mips->f[inst->src1];
+ break;
+ case IROp::FpCondToReg:
+ mips->r[inst->dest] = mips->fpcond;
+ break;
+ case IROp::VfpuCtrlToReg:
+ mips->r[inst->dest] = mips->vfpuCtrl[inst->src1];
+ break;
+ case IROp::FRound:
+ mips->fs[inst->dest] = (int)floorf(mips->f[inst->src1] + 0.5f);
+ break;
+ case IROp::FTrunc:
+ {
+ float src = mips->f[inst->src1];
+ if (src >= 0.0f) {
+ mips->fs[inst->dest] = (int)floorf(src);
+ // Overflow, but it was positive.
+ if (mips->fs[inst->dest] == -2147483648LL) {
+ mips->fs[inst->dest] = 2147483647LL;
+ }
+ } else {
+ // Overflow happens to be the right value anyway.
+ mips->fs[inst->dest] = (int)ceilf(src);
+ }
+ break;
+ }
+ case IROp::FCeil:
+ mips->fs[inst->dest] = (int)ceilf(mips->f[inst->src1]);
+ break;
+ case IROp::FFloor:
+ mips->fs[inst->dest] = (int)floorf(mips->f[inst->src1]);
+ break;
+
+ case IROp::FCvtSW:
+ mips->f[inst->dest] = (float)mips->fs[inst->src1];
+ break;
+ case IROp::FCvtWS:
+ {
+ float src = mips->f[inst->src1];
+ if (my_isnanorinf(src))
+ {
+ mips->fs[inst->dest] = my_isinf(src) && src < 0.0f ? -2147483648LL : 2147483647LL;
+ break;
+ }
+ switch (mips->fcr31 & 3)
+ {
+ case 0: mips->fs[inst->dest] = (int)round_ieee_754(src); break; // RINT_0
+ case 1: mips->fs[inst->dest] = (int)src; break; // CAST_1
+ case 2: mips->fs[inst->dest] = (int)ceilf(src); break; // CEIL_2
+ case 3: mips->fs[inst->dest] = (int)floorf(src); break; // FLOOR_3
+ }
+ break; //cvt.w.s
+ }
+
+ case IROp::ZeroFpCond:
+ mips->fpcond = 0;
+ break;
+
+ case IROp::FMovFromGPR:
+ memcpy(&mips->f[inst->dest], &mips->r[inst->src1], 4);
+ break;
+ case IROp::FMovToGPR:
+ memcpy(&mips->r[inst->dest], &mips->f[inst->src1], 4);
+ break;
+
+ case IROp::VMovFromGPR:
+ memcpy(&mips->v[voffset[inst->dest]], &mips->r[inst->src1], 4);
+ break;
+ case IROp::VMovToGPR:
+ memcpy(&mips->r[inst->dest], &mips->v[voffset[inst->src1]], 4);
+ break;
+
+ case IROp::ExitToConst:
+ return constPool[inst->dest];
+
+ case IROp::ExitToReg:
+ return mips->r[inst->dest];
+
+ case IROp::ExitToConstIfEq:
+ if (mips->r[inst->src1] == mips->r[inst->src2])
+ return constPool[inst->dest];
+ break;
+ case IROp::ExitToConstIfNeq:
+ if (mips->r[inst->src1] != mips->r[inst->src2])
+ return constPool[inst->dest];
+ break;
+ case IROp::ExitToConstIfGtZ:
+ if ((s32)mips->r[inst->src1] > 0)
+ return constPool[inst->dest];
+ break;
+ case IROp::ExitToConstIfGeZ:
+ if ((s32)mips->r[inst->src1] >= 0)
+ return constPool[inst->dest];
+ break;
+ case IROp::ExitToConstIfLtZ:
+ if ((s32)mips->r[inst->src1] < 0)
+ return constPool[inst->dest];
+ break;
+ case IROp::ExitToConstIfLeZ:
+ if ((s32)mips->r[inst->src1] <= 0)
+ return constPool[inst->dest];
+ break;
+
+ case IROp::Downcount:
+ mips->downcount -= (inst->src1) | ((inst->src2) << 8);
+ break;
+
+ case IROp::SetPC:
+ mips->pc = mips->r[inst->src1];
+ break;
+
+ case IROp::SetPCConst:
+ mips->pc = constPool[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;
+ }
+
+ case IROp::CallReplacement:
+ {
+ int funcIndex = constPool[inst->src1];
+ const ReplacementTableEntry *f = GetReplacementFunc(funcIndex);
+ int cycles = f->replaceFunc();
+ mips->downcount -= cycles;
+ return mips->r[MIPS_REG_RA];
+ }
+
+ case IROp::Break:
+ Crash();
+ break;
+
+ case IROp::SetCtrlVFPU:
+ mips->vfpuCtrl[inst->dest] = constPool[inst->src1];
+ break;
+
+ default:
+ Crash();
+ }
+#ifdef _DEBUG
+ if (mips->r[0] != 0)
+ Crash();
+#endif
+ inst++;
+ }
+
+ // If we got here, the block was badly constructed.
+ Crash();
+ return 0;
+}
diff --git a/Core/MIPS/IR/IRInterpreter.h b/Core/MIPS/IR/IRInterpreter.h
new file mode 100644
index 0000000000..fe9f8e4ba9
--- /dev/null
+++ b/Core/MIPS/IR/IRInterpreter.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "Common/CommonTypes.h"
+
+class MIPSState;
+struct IRInst;
+
+u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int count);
diff --git a/Core/MIPS/IR/IRJit.cpp b/Core/MIPS/IR/IRJit.cpp
index b9522c6b88..668da61a36 100644
--- a/Core/MIPS/IR/IRJit.cpp
+++ b/Core/MIPS/IR/IRJit.cpp
@@ -37,6 +37,7 @@
#include "Core/MIPS/IR/IRRegCache.h"
#include "Core/MIPS/IR/IRJit.h"
#include "Core/MIPS/IR/IRPassSimplify.h"
+#include "Core/MIPS/IR/IRInterpreter.h"
#include "Core/MIPS/JitCommon/JitCommon.h"
namespace MIPSComp {
diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp
index 1b41243b61..42712bc111 100644
--- a/UI/DevScreens.cpp
+++ b/UI/DevScreens.cpp
@@ -669,6 +669,8 @@ UI::EventReturn JitCompareScreen::OnAddressChange(UI::EventParams &e) {
return UI::EVENT_DONE;
}
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
+ if (!blockCache)
+ return UI::EVENT_DONE;
u32 addr;
if (blockAddr_->GetText().size() > 8)
return UI::EVENT_DONE;
@@ -731,6 +733,9 @@ UI::EventReturn JitCompareScreen::OnBlockAddress(UI::EventParams &e) {
}
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
+ if (!blockCache)
+ return UI::EVENT_DONE;
+
if (Memory::IsValidAddress(e.a)) {
currentBlock_ = blockCache->GetBlockNumberFromStartAddress(e.a);
} else {
@@ -746,6 +751,9 @@ UI::EventReturn JitCompareScreen::OnRandomBlock(UI::EventParams &e) {
}
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
+ if (!blockCache)
+ return UI::EVENT_DONE;
+
int numBlocks = blockCache->GetNumBlocks();
if (numBlocks > 0) {
currentBlock_ = rand() % numBlocks;
@@ -769,6 +777,9 @@ void JitCompareScreen::OnRandomBlock(int flag) {
return;
}
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
+ if (!blockCache)
+ return;
+
int numBlocks = blockCache->GetNumBlocks();
if (numBlocks > 0) {
bool anyWanted = false;
@@ -797,6 +808,8 @@ UI::EventReturn JitCompareScreen::OnCurrentBlock(UI::EventParams &e) {
return UI::EVENT_DONE;
}
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
+ if (!blockCache)
+ return UI::EVENT_DONE;
std::vector blockNum;
blockCache->GetBlockNumbersFromAddress(currentMIPS->pc, &blockNum);
if (blockNum.size() > 0) {
diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp
index 1ade2a4303..32c4a1f93b 100644
--- a/UI/GameSettingsScreen.cpp
+++ b/UI/GameSettingsScreen.cpp
@@ -1060,7 +1060,7 @@ void DeveloperToolsScreen::CreateViews() {
}
#endif
- static const char *cpuCores[] = { "Interpreter", "Dynarec (JIT)", "IRJit" };
+ static const char *cpuCores[] = { "Interpreter", "Dynarec (JIT)", "IR Interpreter" };
PopupMultiChoice *core = list->Add(new PopupMultiChoice(&g_Config.iCpuCore, gr->T("CPU Core"), cpuCores, 0, ARRAY_SIZE(cpuCores), sy->GetName(), screenManager()));
if (!canUseJit) {
core->HideChoice(1);
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 1cda4ed095..92a10e800c 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -157,6 +157,16 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Core/MIPS/MIPSVFPUUtils.cpp.arm \
$(SRC)/Core/MIPS/MIPSCodeUtils.cpp.arm \
$(SRC)/Core/MIPS/MIPSDebugInterface.cpp \
+ $(SRC)/Core/MIPS/IR/IRJit.cpp \
+ $(SRC)/Core/MIPS/IR/IRCompALU.cpp \
+ $(SRC)/Core/MIPS/IR/IRCompBranch.cpp \
+ $(SRC)/Core/MIPS/IR/IRCompFPU.cpp \
+ $(SRC)/Core/MIPS/IR/IRCompLoadStore.cpp \
+ $(SRC)/Core/MIPS/IR/IRCompVFPU.cpp \
+ $(SRC)/Core/MIPS/IR/IRInst.cpp \
+ $(SRC)/Core/MIPS/IR/IRInterpreter.cpp \
+ $(SRC)/Core/MIPS/IR/IRPassSimplify.cpp \
+ $(SRC)/Core/MIPS/IR/IRRegCache.cpp \
$(SRC)/UI/ui_atlas.cpp \
$(SRC)/UI/OnScreenDisplay.cpp \
$(SRC)/ext/libkirk/AES.c \