diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8ca3c64c92..1a91796708 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1539,6 +1539,8 @@ set(CoreExtra)
set(CoreExtraLibs)
set(CoreExtra ${CoreExtra}
+ Core/MIPS/IR/IRAnalysis.cpp
+ Core/MIPS/IR/IRAnalysis.h
Core/MIPS/IR/IRCompALU.cpp
Core/MIPS/IR/IRCompBranch.cpp
Core/MIPS/IR/IRCompFPU.cpp
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index b2ae24174f..9794f02f81 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -580,6 +580,7 @@
+
@@ -1164,6 +1165,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index a4f56f5eb1..e437d0d813 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -1237,6 +1237,9 @@
MIPS\RiscV
+
+ MIPS\IR
+
@@ -1992,6 +1995,9 @@
MIPS\RiscV
+
+ MIPS\IR
+
diff --git a/Core/MIPS/IR/IRAnalysis.cpp b/Core/MIPS/IR/IRAnalysis.cpp
new file mode 100644
index 0000000000..0a8b861b89
--- /dev/null
+++ b/Core/MIPS/IR/IRAnalysis.cpp
@@ -0,0 +1,135 @@
+// Copyright (c) 2016- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#include "Core/MIPS/IR/IRAnalysis.h"
+
+static bool IRReadsFrom(const IRInst &inst, int reg, char type, bool directly = false) {
+ const IRMeta *m = GetIRMeta(inst.op);
+
+ if (m->types[1] == type && inst.src1 == reg) {
+ return true;
+ }
+ if (m->types[2] == type && inst.src2 == reg) {
+ return true;
+ }
+ if ((m->flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && m->types[0] == type && inst.src3 == reg) {
+ return true;
+ }
+ if (!directly) {
+ if (inst.op == IROp::Interpret || inst.op == IROp::CallReplacement || inst.op == IROp::Syscall || inst.op == IROp::Break)
+ return true;
+ if (inst.op == IROp::Breakpoint || inst.op == IROp::MemoryCheck)
+ return true;
+ }
+ return false;
+}
+
+bool IRReadsFromFPR(const IRInst &inst, int reg, bool directly) {
+ if (IRReadsFrom(inst, reg, 'F', directly))
+ return true;
+
+ const IRMeta *m = GetIRMeta(inst.op);
+
+ // We also need to check V and 2. Indirect reads already checked, don't check again.
+ if (m->types[1] == 'V' && reg >= inst.src1 && reg < inst.src1 + 4)
+ return true;
+ if (m->types[1] == '2' && reg >= inst.src1 && reg < inst.src1 + 2)
+ return true;
+ if (m->types[2] == 'V' && reg >= inst.src2 && reg < inst.src2 + 4)
+ return true;
+ if (m->types[2] == '2' && reg >= inst.src2 && reg < inst.src2 + 2)
+ return true;
+ if ((m->flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0) {
+ if (m->types[0] == 'V' && reg >= inst.src3 && reg <= inst.src3 + 4)
+ return true;
+ if (m->types[0] == '2' && reg >= inst.src3 && reg <= inst.src3 + 2)
+ return true;
+ }
+ return false;
+}
+
+bool IRReadsFromGPR(const IRInst &inst, int reg, bool directly) {
+ return IRReadsFrom(inst, reg, 'G', directly);
+}
+
+int IRDestGPR(const IRInst &inst) {
+ const IRMeta *m = GetIRMeta(inst.op);
+
+ if ((m->flags & IRFLAG_SRC3) == 0 && m->types[0] == 'G') {
+ return inst.dest;
+ }
+ return -1;
+}
+
+bool IRWritesToGPR(const IRInst &inst, int reg) {
+ return IRDestGPR(inst) == reg;
+}
+
+bool IRWritesToFPR(const IRInst &inst, int reg) {
+ const IRMeta *m = GetIRMeta(inst.op);
+
+ // Doesn't write to anything.
+ if ((m->flags & IRFLAG_SRC3) != 0)
+ return false;
+
+ if (m->types[0] == 'F' && reg == inst.dest)
+ return true;
+ if (m->types[0] == 'V' && reg >= inst.dest && reg < inst.dest + 4)
+ return true;
+ if (m->types[0] == '2' && reg >= inst.dest && reg < inst.dest + 2)
+ return true;
+ return false;
+}
+
+IRUsage IRNextGPRUsage(int gpr, const IRSituation &info) {
+ // Exclude any "special" regs from this logic for now.
+ if (gpr >= 32)
+ return IRUsage::UNKNOWN;
+
+ int count = std::min(info.numInstructions - info.currentIndex, info.lookaheadCount);
+ for (int i = 0; i < count; ++i) {
+ const IRInst inst = info.instructions[info.currentIndex + i];
+ if (IRReadsFromGPR(inst, gpr))
+ return IRUsage::READ;
+ // We say WRITE when the current instruction writes. It's not useful for spilling.
+ if (IRDestGPR(inst) == gpr)
+ return i == 0 ? IRUsage::WRITE : IRUsage::CLOBBERED;
+ }
+
+ return IRUsage::UNUSED;
+}
+
+IRUsage IRNextFPRUsage(int fpr, const IRSituation &info) {
+ // Let's only pay attention to standard FP regs and temps.
+ // See MIPS.h for these offsets.
+ if (fpr < 0 || (fpr >= 160 && fpr < 192) || fpr >= 208)
+ return IRUsage::UNKNOWN;
+
+ int count = std::min(info.numInstructions - info.currentIndex, info.lookaheadCount);
+ for (int i = 0; i < count; ++i) {
+ const IRInst inst = info.instructions[info.currentIndex + i];
+
+ if (IRReadsFromFPR(inst, fpr))
+ return IRUsage::READ;
+ // We say WRITE when the current instruction writes. It's not useful for spilling.
+ if (IRWritesToFPR(inst, fpr)) {
+ return i == 0 ? IRUsage::WRITE : IRUsage::CLOBBERED;
+ }
+ }
+
+ return IRUsage::UNUSED;
+}
diff --git a/Core/MIPS/IR/IRAnalysis.h b/Core/MIPS/IR/IRAnalysis.h
new file mode 100644
index 0000000000..2b5ff598b4
--- /dev/null
+++ b/Core/MIPS/IR/IRAnalysis.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2016- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#pragma once
+
+#include "Core/MIPS/IR/IRInst.h"
+
+bool IRReadsFromFPR(const IRInst &inst, int reg, bool directly = false);
+bool IRReadsFromGPR(const IRInst &inst, int reg, bool directly = false);
+bool IRWritesToGPR(const IRInst &inst, int reg);
+bool IRWritesToFPR(const IRInst &inst, int reg);
+int IRDestGPR(const IRInst &inst);
+
+struct IRSituation {
+ int lookaheadCount;
+ int currentIndex;
+ const IRInst *instructions;
+ int numInstructions;
+};
+
+enum class IRUsage {
+ UNKNOWN,
+ UNUSED,
+ READ,
+ WRITE,
+ CLOBBERED,
+};
+
+IRUsage IRNextGPRUsage(int gpr, const IRSituation &info);
+IRUsage IRNextFPRUsage(int fpr, const IRSituation &info);
diff --git a/Core/MIPS/IR/IRInst.cpp b/Core/MIPS/IR/IRInst.cpp
index 738b2151f0..ff623776a3 100644
--- a/Core/MIPS/IR/IRInst.cpp
+++ b/Core/MIPS/IR/IRInst.cpp
@@ -1,6 +1,5 @@
#include "Common/CommonFuncs.h"
#include "Core/MIPS/IR/IRInst.h"
-#include "Core/MIPS/IR/IRPassSimplify.h"
#include "Core/MIPS/MIPSDebugInterface.h"
// Legend
diff --git a/Core/MIPS/IR/IRJit.cpp b/Core/MIPS/IR/IRJit.cpp
index 1253ca5061..039b8ee197 100644
--- a/Core/MIPS/IR/IRJit.cpp
+++ b/Core/MIPS/IR/IRJit.cpp
@@ -36,7 +36,6 @@
#include "Core/MIPS/MIPSTables.h"
#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"
#include "Core/Reporting.h"
diff --git a/Core/MIPS/IR/IRPassSimplify.cpp b/Core/MIPS/IR/IRPassSimplify.cpp
index 11b8e5292c..9e0f12c587 100644
--- a/Core/MIPS/IR/IRPassSimplify.cpp
+++ b/Core/MIPS/IR/IRPassSimplify.cpp
@@ -6,6 +6,7 @@
#include "Common/Data/Convert/SmallDataConvert.h"
#include "Common/Log.h"
#include "Core/Config.h"
+#include "Core/MIPS/IR/IRAnalysis.h"
#include "Core/MIPS/IR/IRInterpreter.h"
#include "Core/MIPS/IR/IRPassSimplify.h"
#include "Core/MIPS/IR/IRRegCache.h"
@@ -803,27 +804,6 @@ bool PropagateConstants(const IRWriter &in, IRWriter &out, const IROptions &opts
return logBlocks;
}
-bool IRReadsFromGPR(const IRInst &inst, int reg, bool directly = false) {
- const IRMeta *m = GetIRMeta(inst.op);
-
- if (m->types[1] == 'G' && inst.src1 == reg) {
- return true;
- }
- if (m->types[2] == 'G' && inst.src2 == reg) {
- return true;
- }
- if ((m->flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && m->types[0] == 'G' && inst.src3 == reg) {
- return true;
- }
- if (!directly) {
- if (inst.op == IROp::Interpret || inst.op == IROp::CallReplacement || inst.op == IROp::Syscall || inst.op == IROp::Break)
- return true;
- if (inst.op == IROp::Breakpoint || inst.op == IROp::MemoryCheck)
- return true;
- }
- return false;
-}
-
IRInst IRReplaceSrcGPR(const IRInst &inst, int fromReg, int toReg) {
IRInst newInst = inst;
const IRMeta *m = GetIRMeta(inst.op);
@@ -840,15 +820,6 @@ IRInst IRReplaceSrcGPR(const IRInst &inst, int fromReg, int toReg) {
return newInst;
}
-int IRDestGPR(const IRInst &inst) {
- const IRMeta *m = GetIRMeta(inst.op);
-
- if ((m->flags & IRFLAG_SRC3) == 0 && m->types[0] == 'G') {
- return inst.dest;
- }
- return -1;
-}
-
IRInst IRReplaceDestGPR(const IRInst &inst, int fromReg, int toReg) {
IRInst newInst = inst;
const IRMeta *m = GetIRMeta(inst.op);
diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp
index 4cfe9a2292..1cdeeb00ba 100644
--- a/Core/MIPS/MIPSAnalyst.cpp
+++ b/Core/MIPS/MIPSAnalyst.cpp
@@ -813,7 +813,7 @@ namespace MIPSAnalyst {
break;
}
- if (reg > 32) {
+ if (reg >= 32) {
return USAGE_UNKNOWN;
}
diff --git a/Core/MIPS/RiscV/RiscVJit.cpp b/Core/MIPS/RiscV/RiscVJit.cpp
index bf3bf4e60a..a9724d1045 100644
--- a/Core/MIPS/RiscV/RiscVJit.cpp
+++ b/Core/MIPS/RiscV/RiscVJit.cpp
@@ -111,19 +111,20 @@ bool RiscVJit::CompileTargetBlock(IRBlock *block, int block_num, bool preload) {
// TODO: Block linking, checked entries and such.
- gpr.Start();
- fpr.Start();
+ gpr.Start(block);
+ fpr.Start(block);
for (int i = 0; i < block->GetNumInstructions(); ++i) {
const IRInst &inst = block->GetInstructions()[i];
+ gpr.SetIRIndex(i);
+ fpr.SetIRIndex(i);
+
CompileIRInst(inst);
- if (jo.Disabled(JitDisable::REGALLOC_GPR)) {
+ if (jo.Disabled(JitDisable::REGALLOC_GPR))
gpr.FlushAll();
- }
- if (jo.Disabled(JitDisable::REGALLOC_FPR)) {
+ if (jo.Disabled(JitDisable::REGALLOC_FPR))
fpr.FlushAll();
- }
// Safety check, in case we get a bunch of really large jit ops without a lot of branching.
if (GetSpaceLeft() < 0x800) {
diff --git a/Core/MIPS/RiscV/RiscVRegCache.cpp b/Core/MIPS/RiscV/RiscVRegCache.cpp
index 25f7b5db59..8885905f85 100644
--- a/Core/MIPS/RiscV/RiscVRegCache.cpp
+++ b/Core/MIPS/RiscV/RiscVRegCache.cpp
@@ -21,6 +21,7 @@
#include "Common/CPUDetect.h"
#include "Core/MIPS/IR/IRInst.h"
+#include "Core/MIPS/IR/IRAnalysis.h"
#include "Core/MIPS/RiscV/RiscVRegCache.h"
#include "Core/MIPS/JitCommon/JitState.h"
#include "Core/Reporting.h"
@@ -36,7 +37,7 @@ void RiscVRegCache::Init(RiscVEmitter *emitter) {
emit_ = emitter;
}
-void RiscVRegCache::Start() {
+void RiscVRegCache::Start(MIPSComp::IRBlock *irBlock) {
if (!initialReady_) {
SetupInitialRegs();
initialReady_ = true;
@@ -56,6 +57,9 @@ void RiscVRegCache::Start() {
mr[statics[i].mr].isStatic = true;
mr[statics[i].mr].spillLock = true;
}
+
+ irBlock_ = irBlock;
+ irIndex_ = 0;
}
void RiscVRegCache::SetupInitialRegs() {
@@ -362,8 +366,6 @@ allocate:
}
// Still nothing. Let's spill a reg and goto 10.
- // TODO: Use age or something to choose which register to spill?
- // TODO: Spill dirty regs first? or opposite?
bool clobbered;
RiscVReg bestToSpill = FindBestToSpill(true, &clobbered);
if (bestToSpill == INVALID_REG) {
@@ -392,6 +394,12 @@ RiscVReg RiscVRegCache::FindBestToSpill(bool unusedOnly, bool *clobbered) {
static const int UNUSED_LOOKAHEAD_OPS = 30;
+ IRSituation info;
+ info.lookaheadCount = UNUSED_LOOKAHEAD_OPS;
+ info.currentIndex = irIndex_;
+ info.instructions = irBlock_->GetInstructions();
+ info.numInstructions = irBlock_->GetNumInstructions();
+
*clobbered = false;
for (int i = 0; i < allocCount; i++) {
RiscVReg reg = allocOrder[i];
@@ -401,16 +409,24 @@ RiscVReg RiscVRegCache::FindBestToSpill(bool unusedOnly, bool *clobbered) {
continue;
// As it's in alloc-order, we know it's not static so we don't need to check for that.
+ IRUsage usage = IRNextGPRUsage(ar[reg].mipsReg, info);
- // TODO: Look for clobbering in the IRInst array with index?
-
- // Not awesome. A used reg. Let's try to avoid spilling.
- // TODO: Actually check if we'd be spilling.
- if (unusedOnly) {
- continue;
+ // Awesome, a clobbered reg. Let's use it.
+ if (usage == IRUsage::CLOBBERED) {
+ // TODO: Check HI/LO clobber together if we combine.
+ bool canClobber = true;
+ if (canClobber) {
+ *clobbered = true;
+ return reg;
+ }
}
- return reg;
+ // Not awesome. A used reg. Let's try to avoid spilling.
+ if (!unusedOnly || usage == IRUsage::UNUSED) {
+ // TODO: Use age or something to choose which register to spill?
+ // TODO: Spill dirty regs first? or opposite?
+ return reg;
+ }
}
return INVALID_REG;
diff --git a/Core/MIPS/RiscV/RiscVRegCache.h b/Core/MIPS/RiscV/RiscVRegCache.h
index 10305f5e25..ffe373c639 100644
--- a/Core/MIPS/RiscV/RiscVRegCache.h
+++ b/Core/MIPS/RiscV/RiscVRegCache.h
@@ -19,6 +19,7 @@
#include "Common/RiscVEmitter.h"
#include "Core/MIPS/MIPS.h"
+#include "Core/MIPS/IR/IRJit.h"
namespace RiscVJitConstants {
@@ -101,8 +102,10 @@ public:
~RiscVRegCache() {}
void Init(RiscVGen::RiscVEmitter *emitter);
- // TODO: Maybe pass in IR block and start PC for logging/debugging?
- void Start();
+ void Start(MIPSComp::IRBlock *irBlock);
+ void SetIRIndex(int index) {
+ irIndex_ = index;
+ }
// Protect the arm register containing a MIPS register from spilling, to ensure that
// it's being kept allocated.
@@ -176,6 +179,8 @@ private:
MIPSState *mips_;
RiscVGen::RiscVEmitter *emit_ = nullptr;
MIPSComp::JitOptions *jo_;
+ MIPSComp::IRBlock *irBlock_ = nullptr;
+ int irIndex_ = 0;
enum {
NUM_RVREG = 32, // 31 actual registers, plus the zero/sp register which is not mappable.
diff --git a/Core/MIPS/RiscV/RiscVRegCacheFPU.cpp b/Core/MIPS/RiscV/RiscVRegCacheFPU.cpp
index 48d0400d1d..c99261b9f9 100644
--- a/Core/MIPS/RiscV/RiscVRegCacheFPU.cpp
+++ b/Core/MIPS/RiscV/RiscVRegCacheFPU.cpp
@@ -20,6 +20,8 @@
#endif
#include "Common/CPUDetect.h"
+#include "Core/MIPS/IR/IRInst.h"
+#include "Core/MIPS/IR/IRAnalysis.h"
#include "Core/MIPS/RiscV/RiscVRegCacheFPU.h"
#include "Core/MIPS/JitCommon/JitState.h"
#include "Core/Reporting.h"
@@ -34,7 +36,7 @@ void RiscVRegCacheFPU::Init(RiscVEmitter *emitter) {
emit_ = emitter;
}
-void RiscVRegCacheFPU::Start() {
+void RiscVRegCacheFPU::Start(MIPSComp::IRBlock *irBlock) {
if (!initialReady_) {
SetupInitialRegs();
initialReady_ = true;
@@ -43,6 +45,9 @@ void RiscVRegCacheFPU::Start() {
memcpy(ar, arInitial_, sizeof(ar));
memcpy(mr, mrInitial_, sizeof(mr));
pendingFlush_ = false;
+
+ irBlock_ = irBlock;
+ irIndex_ = 0;
}
void RiscVRegCacheFPU::SetupInitialRegs() {
@@ -130,8 +135,6 @@ allocate:
}
// Still nothing. Let's spill a reg and goto 10.
- // TODO: Use age or something to choose which register to spill?
- // TODO: Spill dirty regs first? or opposite?
bool clobbered;
RiscVReg bestToSpill = FindBestToSpill(true, &clobbered);
if (bestToSpill == INVALID_REG) {
@@ -160,21 +163,33 @@ RiscVReg RiscVRegCacheFPU::FindBestToSpill(bool unusedOnly, bool *clobbered) {
static const int UNUSED_LOOKAHEAD_OPS = 30;
+ IRSituation info;
+ info.lookaheadCount = UNUSED_LOOKAHEAD_OPS;
+ info.currentIndex = irIndex_;
+ info.instructions = irBlock_->GetInstructions();
+ info.numInstructions = irBlock_->GetNumInstructions();
+
*clobbered = false;
for (int i = 0; i < allocCount; i++) {
RiscVReg reg = allocOrder[i];
if (ar[reg - F0].mipsReg != IRREG_INVALID && mr[ar[reg - F0].mipsReg].spillLock)
continue;
- // TODO: Look for clobbering in the IRInst array with index?
+ // As it's in alloc-order, we know it's not static so we don't need to check for that.
+ IRUsage usage = IRNextFPRUsage(ar[reg - F0].mipsReg, info);
- // Not awesome. A used reg. Let's try to avoid spilling.
- // TODO: Actually check if we'd be spilling.
- if (unusedOnly) {
- continue;
+ // Awesome, a clobbered reg. Let's use it.
+ if (usage == IRUsage::CLOBBERED) {
+ *clobbered = true;
+ return reg;
}
- return reg;
+ // Not awesome. A used reg. Let's try to avoid spilling.
+ if (!unusedOnly || usage == IRUsage::UNUSED) {
+ // TODO: Use age or something to choose which register to spill?
+ // TODO: Spill dirty regs first? or opposite?
+ return reg;
+ }
}
return INVALID_REG;
diff --git a/Core/MIPS/RiscV/RiscVRegCacheFPU.h b/Core/MIPS/RiscV/RiscVRegCacheFPU.h
index 30f897d43d..9edda169aa 100644
--- a/Core/MIPS/RiscV/RiscVRegCacheFPU.h
+++ b/Core/MIPS/RiscV/RiscVRegCacheFPU.h
@@ -46,8 +46,10 @@ public:
~RiscVRegCacheFPU() {}
void Init(RiscVGen::RiscVEmitter *emitter);
- // TODO: Maybe pass in IR block and start PC for logging/debugging?
- void Start();
+ void Start(MIPSComp::IRBlock *irBlock);
+ void SetIRIndex(int index) {
+ irIndex_ = index;
+ }
// Protect the RISC-V register containing a MIPS register from spilling, to ensure that
// it's being kept allocated.
@@ -89,6 +91,8 @@ private:
MIPSState *mips_;
RiscVGen::RiscVEmitter *emit_ = nullptr;
MIPSComp::JitOptions *jo_;
+ MIPSComp::IRBlock *irBlock_ = nullptr;
+ int irIndex_ = 0;
enum {
// On RiscV, each of the 32 registers are full 128-bit. No sharing of components!
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj
index ca53e7d496..5af1ee85d0 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj
+++ b/UWP/CoreUWP/CoreUWP.vcxproj
@@ -302,6 +302,7 @@
+
@@ -561,6 +562,7 @@
+
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters
index f6ccb537f0..363504bba7 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj.filters
+++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters
@@ -645,6 +645,9 @@
MIPS\IR
+
+ MIPS\IR
+
MIPS\IR
@@ -1667,6 +1670,9 @@
MIPS\IR
+
+ MIPS\IR
+
MIPS\IR
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 4fe1d0df45..494a4d6316 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -390,6 +390,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Core/MIPS/MIPSVFPUFallbacks.cpp.arm \
$(SRC)/Core/MIPS/MIPSCodeUtils.cpp.arm \
$(SRC)/Core/MIPS/MIPSDebugInterface.cpp \
+ $(SRC)/Core/MIPS/IR/IRAnalysis.cpp \
$(SRC)/Core/MIPS/IR/IRFrontend.cpp \
$(SRC)/Core/MIPS/IR/IRJit.cpp \
$(SRC)/Core/MIPS/IR/IRCompALU.cpp \
diff --git a/libretro/Makefile.common b/libretro/Makefile.common
index 8c6a90ca06..70c00dfee2 100644
--- a/libretro/Makefile.common
+++ b/libretro/Makefile.common
@@ -671,6 +671,7 @@ SOURCES_CXX += \
$(COREDIR)/MIPS/JitCommon/JitCommon.cpp \
$(COREDIR)/MIPS/JitCommon/JitState.cpp \
$(COREDIR)/MIPS/JitCommon/JitBlockCache.cpp \
+ $(COREDIR)/MIPS/IR/IRAnalysis.cpp \
$(COREDIR)/MIPS/IR/IRCompALU.cpp \
$(COREDIR)/MIPS/IR/IRCompBranch.cpp \
$(COREDIR)/MIPS/IR/IRCompFPU.cpp \