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 \