mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-26 03:35:26 +00:00
Merge branch 'JitArmIL'
This implements a partial JITIL based off of the JIT64IL. It's enough to run most games, albiet at a slow speed. Implementing instructions for this IL is really simple since it basically is just enabling based on what is already in JIT64IL, and then enabling each individual IL instruction.
This commit is contained in:
commit
715d5ae8a7
@ -19,10 +19,12 @@
|
||||
<string-array name="emuCoreEntriesARM" translatable="false">
|
||||
<item>@string/interpreter</item>
|
||||
<item>@string/jit_arm_recompiler</item>
|
||||
<item>@string/jitil_arm_recompiler</item>
|
||||
</string-array>
|
||||
<string-array name="emuCoreValuesARM" translatable="false">
|
||||
<item>0</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
</string-array>
|
||||
|
||||
<!-- CPU core selection - Other -->
|
||||
@ -137,4 +139,4 @@
|
||||
<item>4</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
</resources>
|
||||
|
@ -69,6 +69,7 @@
|
||||
<string name="jit64_recompiler">JIT64 Recompiler</string>
|
||||
<string name="jitil_recompiler">JITIL Recompiler</string>
|
||||
<string name="jit_arm_recompiler">JIT ARM Recompiler</string>
|
||||
<string name="jitil_arm_recompiler">JITIL ARM Recompiler</string>
|
||||
<string name="cpu_core">CPU Core</string>
|
||||
<string name="cpu_settings">CPU</string>
|
||||
<string name="emu_core_to_use">Emulation core to use</string>
|
||||
|
@ -491,11 +491,10 @@ void ARMXEmitter::POP(const int num, ...)
|
||||
|
||||
void ARMXEmitter::WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, Operand2 op2)
|
||||
{
|
||||
Write32(condition | (13 << 21) | (SetFlags << 20) | (dest << 12) | op2.Imm5() | (op << 4) | src);
|
||||
}
|
||||
void ARMXEmitter::WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, ARMReg op2)
|
||||
{
|
||||
Write32(condition | (13 << 21) | (SetFlags << 20) | (dest << 12) | (op2 << 8) | (op << 4) | src);
|
||||
if (op2.GetType() == TYPE_REG)
|
||||
Write32(condition | (13 << 21) | (SetFlags << 20) | (dest << 12) | (op2.GetData() << 8) | ((op + 1) << 4) | src);
|
||||
else
|
||||
Write32(condition | (13 << 21) | (SetFlags << 20) | (dest << 12) | op2.Imm5() | (op << 4) | src);
|
||||
}
|
||||
|
||||
// IMM, REG, IMMSREG, RSR
|
||||
@ -610,16 +609,10 @@ void ARMXEmitter::SDIV(ARMReg dest, ARMReg dividend, ARMReg divisor)
|
||||
}
|
||||
void ARMXEmitter::LSL (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(0, false, dest, src, op2);}
|
||||
void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(0, true, dest, src, op2);}
|
||||
void ARMXEmitter::LSL (ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(1, false, dest, src, op2);}
|
||||
void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(1, true, dest, src, op2);}
|
||||
void ARMXEmitter::LSR (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(2, false, dest, src, op2);}
|
||||
void ARMXEmitter::LSRS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(2, true, dest, src, op2);}
|
||||
void ARMXEmitter::LSR (ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(3, false, dest, src, op2);}
|
||||
void ARMXEmitter::LSRS(ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(3, true, dest, src, op2);}
|
||||
void ARMXEmitter::ASR (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(4, false, dest, src, op2);}
|
||||
void ARMXEmitter::ASRS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(4, true, dest, src, op2);}
|
||||
void ARMXEmitter::ASR (ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(5, false, dest, src, op2);}
|
||||
void ARMXEmitter::ASRS(ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(5, true, dest, src, op2);}
|
||||
|
||||
void ARMXEmitter::MUL (ARMReg dest, ARMReg src, ARMReg op2)
|
||||
{
|
||||
|
@ -357,7 +357,6 @@ private:
|
||||
|
||||
void WriteStoreOp(u32 Op, ARMReg Rt, ARMReg Rn, Operand2 op2, bool RegAdd);
|
||||
void WriteRegStoreOp(u32 op, ARMReg dest, bool WriteBack, u16 RegList);
|
||||
void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void WriteSignedMultiply(u32 Op, u32 Op2, u32 Op3, ARMReg dest, ARMReg r1, ARMReg r2);
|
||||
|
||||
@ -448,17 +447,11 @@ public:
|
||||
void ADC (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void ADCS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void LSL (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void LSL (ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void LSLS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void LSLS(ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void LSR (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void LSRS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void LSR (ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void LSRS(ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void ASR (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void ASRS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void ASR (ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void ASRS(ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void SBC (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void SBCS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void RBIT(ARMReg dest, ARMReg src);
|
||||
|
@ -166,23 +166,24 @@ set(SRCS Src/ActionReplay.cpp
|
||||
Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp
|
||||
Src/PowerPC/Interpreter/Interpreter_Tables.cpp
|
||||
Src/PowerPC/JitCommon/JitBase.cpp
|
||||
Src/PowerPC/JitCommon/JitCache.cpp)
|
||||
Src/PowerPC/JitCommon/JitCache.cpp
|
||||
Src/PowerPC/JitILCommon/IR.cpp
|
||||
Src/PowerPC/JitILCommon/JitILBase_Branch.cpp
|
||||
Src/PowerPC/JitILCommon/JitILBase_LoadStore.cpp
|
||||
Src/PowerPC/JitILCommon/JitILBase_SystemRegisters.cpp
|
||||
Src/PowerPC/JitILCommon/JitILBase_LoadStoreFloating.cpp
|
||||
Src/PowerPC/JitILCommon/JitILBase_LoadStorePaired.cpp
|
||||
Src/PowerPC/JitILCommon/JitILBase_Paired.cpp
|
||||
Src/PowerPC/JitILCommon/JitILBase_FloatingPoint.cpp
|
||||
Src/PowerPC/JitILCommon/JitILBase_Integer.cpp
|
||||
)
|
||||
|
||||
if(NOT _M_GENERIC)
|
||||
set(SRCS ${SRCS}
|
||||
Src/x64MemTools.cpp
|
||||
Src/PowerPC/Jit64IL/IR.cpp
|
||||
Src/PowerPC/Jit64IL/IR_X86.cpp
|
||||
Src/PowerPC/Jit64IL/JitILAsm.cpp
|
||||
Src/PowerPC/Jit64IL/JitIL_Branch.cpp
|
||||
Src/PowerPC/Jit64IL/JitIL.cpp
|
||||
Src/PowerPC/Jit64IL/JitIL_FloatingPoint.cpp
|
||||
Src/PowerPC/Jit64IL/JitIL_Integer.cpp
|
||||
Src/PowerPC/Jit64IL/JitIL_LoadStore.cpp
|
||||
Src/PowerPC/Jit64IL/JitIL_LoadStoreFloating.cpp
|
||||
Src/PowerPC/Jit64IL/JitIL_LoadStorePaired.cpp
|
||||
Src/PowerPC/Jit64IL/JitIL_Paired.cpp
|
||||
Src/PowerPC/Jit64IL/JitIL_SystemRegisters.cpp
|
||||
Src/PowerPC/Jit64IL/JitIL_Tables.cpp
|
||||
Src/PowerPC/Jit64/Jit64_Tables.cpp
|
||||
Src/PowerPC/Jit64/JitAsm.cpp
|
||||
@ -217,7 +218,14 @@ if(_M_ARM)
|
||||
Src/PowerPC/JitArm32/JitArm_Paired.cpp
|
||||
Src/PowerPC/JitArm32/JitArm_LoadStorePaired.cpp
|
||||
Src/PowerPC/JitArm32/JitArm_SystemRegisters.cpp
|
||||
Src/PowerPC/JitArm32/JitArm_LoadStoreFloating.cpp)
|
||||
Src/PowerPC/JitArm32/JitArm_LoadStoreFloating.cpp
|
||||
#JitArmIL
|
||||
Src/PowerPC/JitArmIL/JitIL.cpp
|
||||
Src/PowerPC/JitArmIL/JitILAsm.cpp
|
||||
Src/PowerPC/JitArmIL/JitIL_Tables.cpp
|
||||
Src/PowerPC/JitArmIL/JitIL_Branch.cpp
|
||||
Src/PowerPC/JitArmIL/IR_Arm.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
set(LIBS bdisasm inputcommon videosoftware sfml-network)
|
||||
|
@ -352,18 +352,18 @@
|
||||
<ClCompile Include="Src\PowerPC\Interpreter\Interpreter_Paired.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Interpreter\Interpreter_SystemRegisters.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Interpreter\Interpreter_Tables.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Jit64IL\IR.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\JitILCommon\IR.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\JitILCommon\JitILBase_Branch.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\JitILCommon\JitILBase_FloatingPoint.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\JitILCommon\JitILBase_Integer.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\JitILCommon\JitILBase_LoadStore.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\JitILCommon\JitILBase_LoadStoreFloating.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\JitILCommon\JitILBase_LoadStorePaired.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\JitILCommon\JitILBase_Paired.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\JitILCommon\JitILBase_SystemRegisters.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Jit64IL\IR_X86.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Jit64IL\JitIL.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Jit64IL\JitILAsm.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Jit64IL\JitIL_Branch.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Jit64IL\JitIL_FloatingPoint.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Jit64IL\JitIL_Integer.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Jit64IL\JitIL_LoadStore.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Jit64IL\JitIL_LoadStoreFloating.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Jit64IL\JitIL_LoadStorePaired.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Jit64IL\JitIL_Paired.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Jit64IL\JitIL_SystemRegisters.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Jit64IL\JitIL_Tables.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Jit64\Jit.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Jit64\Jit64_Tables.cpp" />
|
||||
@ -560,7 +560,6 @@
|
||||
<ClInclude Include="Src\PowerPC\Interpreter\Interpreter.h" />
|
||||
<ClInclude Include="Src\PowerPC\Interpreter\Interpreter_FPUtils.h" />
|
||||
<ClInclude Include="Src\PowerPC\Interpreter\Interpreter_Tables.h" />
|
||||
<ClInclude Include="Src\PowerPC\Jit64IL\IR.h" />
|
||||
<ClInclude Include="Src\PowerPC\Jit64IL\JitIL.h" />
|
||||
<ClInclude Include="Src\PowerPC\Jit64IL\JitILAsm.h" />
|
||||
<ClInclude Include="Src\PowerPC\Jit64IL\JitIL_Tables.h" />
|
||||
@ -568,6 +567,8 @@
|
||||
<ClInclude Include="Src\PowerPC\Jit64\Jit64_Tables.h" />
|
||||
<ClInclude Include="Src\PowerPC\Jit64\JitAsm.h" />
|
||||
<ClInclude Include="Src\PowerPC\Jit64\JitRegCache.h" />
|
||||
<ClInclude Include="Src\PowerPC\JitILCommon\IR.h" />
|
||||
<ClInclude Include="Src\PowerPC\JitILCommon\JitILBase.h" />
|
||||
<ClInclude Include="Src\PowerPC\JitCommon\JitAsmCommon.h" />
|
||||
<ClInclude Include="Src\PowerPC\JitCommon\JitBackpatch.h" />
|
||||
<ClInclude Include="Src\PowerPC\JitCommon\JitBase.h" />
|
||||
@ -611,4 +612,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -24,7 +24,7 @@ The register allocation is linear scan allocation.
|
||||
#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned
|
||||
#endif
|
||||
|
||||
#include "IR.h"
|
||||
#include "../JitILCommon/IR.h"
|
||||
#include "../PPCTables.h"
|
||||
#include "../../CoreTiming.h"
|
||||
#include "../../HW/Memmap.h"
|
||||
|
@ -24,7 +24,8 @@
|
||||
#include "../JitCommon/Jit_Util.h"
|
||||
#include "x64Emitter.h"
|
||||
#include "x64Analyzer.h"
|
||||
#include "IR.h"
|
||||
#include "../JitILCommon/JitILBase.h"
|
||||
#include "../JitILCommon/IR.h"
|
||||
#include "../JitCommon/JitBase.h"
|
||||
#include "JitILAsm.h"
|
||||
|
||||
@ -44,10 +45,11 @@
|
||||
#define DISABLE64
|
||||
#endif
|
||||
|
||||
class JitIL : public Jitx86Base
|
||||
class JitIL : public JitILBase, public EmuCodeBlock
|
||||
{
|
||||
private:
|
||||
|
||||
JitBlockCache blocks;
|
||||
TrampolineCache trampolines;
|
||||
|
||||
// The default code buffer. We keep it around to not have to alloc/dealloc a
|
||||
// large chunk of memory for each recompiled block.
|
||||
@ -73,6 +75,12 @@ public:
|
||||
|
||||
void Trace();
|
||||
|
||||
JitBlockCache *GetBlockCache() { return &blocks; }
|
||||
|
||||
const u8 *BackPatch(u8 *codePtr, u32 em_address, void *ctx) { return NULL; };
|
||||
|
||||
bool IsInCodeSpace(u8 *ptr) { return IsInSpace(ptr); }
|
||||
|
||||
void ClearCache();
|
||||
const u8 *GetDispatcher() {
|
||||
return asm_routines.dispatcher; // asm_routines.dispatcher
|
||||
@ -125,98 +133,6 @@ public:
|
||||
void DynaRunTable31(UGeckoInstruction _inst);
|
||||
void DynaRunTable59(UGeckoInstruction _inst);
|
||||
void DynaRunTable63(UGeckoInstruction _inst);
|
||||
|
||||
void addx(UGeckoInstruction inst);
|
||||
void boolX(UGeckoInstruction inst);
|
||||
void mulli(UGeckoInstruction inst);
|
||||
void mulhwux(UGeckoInstruction inst);
|
||||
void mullwx(UGeckoInstruction inst);
|
||||
void divwux(UGeckoInstruction inst);
|
||||
void srawix(UGeckoInstruction inst);
|
||||
void srawx(UGeckoInstruction inst);
|
||||
void addex(UGeckoInstruction inst);
|
||||
void addzex(UGeckoInstruction inst);
|
||||
|
||||
void extsbx(UGeckoInstruction inst);
|
||||
void extshx(UGeckoInstruction inst);
|
||||
|
||||
void sc(UGeckoInstruction _inst);
|
||||
void rfi(UGeckoInstruction _inst);
|
||||
|
||||
void bx(UGeckoInstruction inst);
|
||||
void bclrx(UGeckoInstruction _inst);
|
||||
void bcctrx(UGeckoInstruction _inst);
|
||||
void bcx(UGeckoInstruction inst);
|
||||
|
||||
void mtspr(UGeckoInstruction inst);
|
||||
void mfspr(UGeckoInstruction inst);
|
||||
void mtmsr(UGeckoInstruction inst);
|
||||
void mfmsr(UGeckoInstruction inst);
|
||||
void mftb(UGeckoInstruction inst);
|
||||
void mtcrf(UGeckoInstruction inst);
|
||||
void mfcr(UGeckoInstruction inst);
|
||||
void mcrf(UGeckoInstruction inst);
|
||||
void crXX(UGeckoInstruction inst);
|
||||
|
||||
void reg_imm(UGeckoInstruction inst);
|
||||
|
||||
void ps_sel(UGeckoInstruction inst);
|
||||
void ps_mr(UGeckoInstruction inst);
|
||||
void ps_sign(UGeckoInstruction inst); //aggregate
|
||||
void ps_arith(UGeckoInstruction inst); //aggregate
|
||||
void ps_mergeXX(UGeckoInstruction inst);
|
||||
void ps_maddXX(UGeckoInstruction inst);
|
||||
void ps_rsqrte(UGeckoInstruction inst);
|
||||
void ps_sum(UGeckoInstruction inst);
|
||||
void ps_muls(UGeckoInstruction inst);
|
||||
|
||||
void fp_arith_s(UGeckoInstruction inst);
|
||||
|
||||
void fcmpx(UGeckoInstruction inst);
|
||||
void fmrx(UGeckoInstruction inst);
|
||||
|
||||
void cmpXX(UGeckoInstruction inst);
|
||||
|
||||
void cntlzwx(UGeckoInstruction inst);
|
||||
|
||||
void lfs(UGeckoInstruction inst);
|
||||
void lfd(UGeckoInstruction inst);
|
||||
void stfd(UGeckoInstruction inst);
|
||||
void stfs(UGeckoInstruction inst);
|
||||
void stfsx(UGeckoInstruction inst);
|
||||
void psq_l(UGeckoInstruction inst);
|
||||
void psq_st(UGeckoInstruction inst);
|
||||
|
||||
void fmaddXX(UGeckoInstruction inst);
|
||||
void fsign(UGeckoInstruction inst);
|
||||
void stX(UGeckoInstruction inst); //stw sth stb
|
||||
void lXz(UGeckoInstruction inst);
|
||||
void lbzu(UGeckoInstruction inst);
|
||||
void lha(UGeckoInstruction inst);
|
||||
void rlwinmx(UGeckoInstruction inst);
|
||||
void rlwimix(UGeckoInstruction inst);
|
||||
void rlwnmx(UGeckoInstruction inst);
|
||||
void negx(UGeckoInstruction inst);
|
||||
void slwx(UGeckoInstruction inst);
|
||||
void srwx(UGeckoInstruction inst);
|
||||
void dcbst(UGeckoInstruction inst);
|
||||
void dcbz(UGeckoInstruction inst);
|
||||
void lfsx(UGeckoInstruction inst);
|
||||
|
||||
void subfic(UGeckoInstruction inst);
|
||||
void subfcx(UGeckoInstruction inst);
|
||||
void subfx(UGeckoInstruction inst);
|
||||
void subfex(UGeckoInstruction inst);
|
||||
|
||||
void lXzx(UGeckoInstruction inst);
|
||||
void lhax(UGeckoInstruction inst);
|
||||
|
||||
void stXx(UGeckoInstruction inst);
|
||||
|
||||
void lmw(UGeckoInstruction inst);
|
||||
void stmw(UGeckoInstruction inst);
|
||||
|
||||
void icbi(UGeckoInstruction inst);
|
||||
};
|
||||
|
||||
void Jit(u32 em_address);
|
||||
|
742
Source/Core/Core/Src/PowerPC/JitArmIL/IR_Arm.cpp
Normal file
742
Source/Core/Core/Src/PowerPC/JitArmIL/IR_Arm.cpp
Normal file
@ -0,0 +1,742 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
#include "../JitILCommon/IR.h"
|
||||
#include "../PPCTables.h"
|
||||
#include "../../CoreTiming.h"
|
||||
#include "../../HW/Memmap.h"
|
||||
#include "JitILAsm.h"
|
||||
#include "JitIL.h"
|
||||
#include "ArmEmitter.h"
|
||||
#include "../../Core.h"
|
||||
|
||||
using namespace IREmitter;
|
||||
using namespace ArmGen;
|
||||
static const unsigned int MAX_NUMBER_OF_REGS = 32;
|
||||
|
||||
struct RegInfo {
|
||||
JitArmIL *Jit;
|
||||
IRBuilder* Build;
|
||||
InstLoc FirstI;
|
||||
std::vector<unsigned> IInfo;
|
||||
std::vector<InstLoc> lastUsed;
|
||||
InstLoc regs[MAX_NUMBER_OF_REGS];
|
||||
InstLoc fregs[MAX_NUMBER_OF_REGS];
|
||||
unsigned numSpills;
|
||||
unsigned numFSpills;
|
||||
unsigned exitNumber;
|
||||
|
||||
RegInfo(JitArmIL* j, InstLoc f, unsigned insts) : Jit(j), FirstI(f), IInfo(insts), lastUsed(insts) {
|
||||
for (unsigned i = 0; i < MAX_NUMBER_OF_REGS; i++) {
|
||||
regs[i] = 0;
|
||||
fregs[i] = 0;
|
||||
}
|
||||
numSpills = 0;
|
||||
numFSpills = 0;
|
||||
exitNumber = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
RegInfo(RegInfo&); // DO NOT IMPLEMENT
|
||||
};
|
||||
|
||||
static const ARMReg RegAllocOrder[] = {R0, R1, R2, R3, R4, R5, R6, R7, R8};
|
||||
static const int RegAllocSize = sizeof(RegAllocOrder) / sizeof(ARMReg);
|
||||
|
||||
static unsigned SlotSet[1000];
|
||||
|
||||
static void regMarkUse(RegInfo& R, InstLoc I, InstLoc Op, unsigned OpNum) {
|
||||
unsigned& info = R.IInfo[Op - R.FirstI];
|
||||
if (info == 0) R.IInfo[I - R.FirstI] |= 1 << (OpNum + 1);
|
||||
if (info < 2) info++;
|
||||
R.lastUsed[Op - R.FirstI] = max(R.lastUsed[Op - R.FirstI], I);
|
||||
}
|
||||
static void regClearInst(RegInfo& RI, InstLoc I) {
|
||||
for (int i = 0; i < RegAllocSize; i++)
|
||||
if (RI.regs[RegAllocOrder[i]] == I)
|
||||
RI.regs[RegAllocOrder[i]] = 0;
|
||||
}
|
||||
static void regNormalRegClear(RegInfo& RI, InstLoc I) {
|
||||
if (RI.IInfo[I - RI.FirstI] & 4)
|
||||
regClearInst(RI, getOp1(I));
|
||||
if (RI.IInfo[I - RI.FirstI] & 8)
|
||||
regClearInst(RI, getOp2(I));
|
||||
}
|
||||
|
||||
static unsigned regReadUse(RegInfo& R, InstLoc I) {
|
||||
return R.IInfo[I - R.FirstI] & 3;
|
||||
}
|
||||
|
||||
static u32 regLocForSlot(RegInfo& RI, unsigned slot) {
|
||||
return (u32)&SlotSet[slot - 1];
|
||||
}
|
||||
|
||||
static unsigned regCreateSpill(RegInfo& RI, InstLoc I) {
|
||||
unsigned newSpill = ++RI.numSpills;
|
||||
RI.IInfo[I - RI.FirstI] |= newSpill << 16;
|
||||
return newSpill;
|
||||
}
|
||||
|
||||
static unsigned regGetSpill(RegInfo& RI, InstLoc I) {
|
||||
return RI.IInfo[I - RI.FirstI] >> 16;
|
||||
}
|
||||
|
||||
static void regSpill(RegInfo& RI, ARMReg reg) {
|
||||
if (!RI.regs[reg]) return;
|
||||
unsigned slot = regGetSpill(RI, RI.regs[reg]);
|
||||
if (!slot) {
|
||||
slot = regCreateSpill(RI, RI.regs[reg]);
|
||||
RI.Jit->MOVI2R(R14, regLocForSlot(RI, slot));
|
||||
RI.Jit->STR(reg, R14, 0);
|
||||
}
|
||||
RI.regs[reg] = 0;
|
||||
}
|
||||
|
||||
static ARMReg regFindFreeReg(RegInfo& RI) {
|
||||
for (int i = 0; i < RegAllocSize; i++)
|
||||
if (RI.regs[RegAllocOrder[i]] == 0)
|
||||
return RegAllocOrder[i];
|
||||
|
||||
int bestIndex = -1;
|
||||
InstLoc bestEnd = 0;
|
||||
for (int i = 0; i < RegAllocSize; ++i) {
|
||||
const InstLoc start = RI.regs[RegAllocOrder[i]];
|
||||
const InstLoc end = RI.lastUsed[start - RI.FirstI];
|
||||
if (bestEnd < end) {
|
||||
bestEnd = end;
|
||||
bestIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
ARMReg reg = RegAllocOrder[bestIndex];
|
||||
regSpill(RI, reg);
|
||||
return reg;
|
||||
}
|
||||
static ARMReg regLocForInst(RegInfo& RI, InstLoc I) {
|
||||
for (int i = 0; i < RegAllocSize; i++)
|
||||
if (RI.regs[RegAllocOrder[i]] == I)
|
||||
return RegAllocOrder[i];
|
||||
|
||||
if (regGetSpill(RI, I) == 0)
|
||||
PanicAlert("Retrieving unknown spill slot?!");
|
||||
RI.Jit->MOVI2R(R14, regLocForSlot(RI, regGetSpill(RI, I)));
|
||||
ARMReg reg = regFindFreeReg(RI);
|
||||
RI.Jit->LDR(reg, R14, 0);
|
||||
return reg;
|
||||
}
|
||||
static ARMReg regBinLHSReg(RegInfo& RI, InstLoc I) {
|
||||
ARMReg reg = regFindFreeReg(RI);
|
||||
RI.Jit->MOV(reg, regLocForInst(RI, getOp1(I)));
|
||||
return reg;
|
||||
}
|
||||
|
||||
// If the lifetime of the register used by an operand ends at I,
|
||||
// return the register. Otherwise return a free register.
|
||||
static ARMReg regBinReg(RegInfo& RI, InstLoc I) {
|
||||
// FIXME: When regLocForInst() is extracted as a local variable,
|
||||
// "Retrieving unknown spill slot?!" is shown.
|
||||
if (RI.IInfo[I - RI.FirstI] & 4)
|
||||
return regLocForInst(RI, getOp1(I));
|
||||
else if (RI.IInfo[I - RI.FirstI] & 8)
|
||||
return regLocForInst(RI, getOp2(I));
|
||||
|
||||
return regFindFreeReg(RI);
|
||||
}
|
||||
|
||||
static void regSpillCallerSaved(RegInfo& RI) {
|
||||
regSpill(RI, R0);
|
||||
regSpill(RI, R1);
|
||||
regSpill(RI, R2);
|
||||
regSpill(RI, R3);
|
||||
}
|
||||
|
||||
static ARMReg regEnsureInReg(RegInfo& RI, InstLoc I) {
|
||||
return regLocForInst(RI, I);
|
||||
}
|
||||
|
||||
static void regWriteExit(RegInfo& RI, InstLoc dest) {
|
||||
if (isImm(*dest)) {
|
||||
RI.Jit->WriteExit(RI.Build->GetImmValue(dest), RI.exitNumber++);
|
||||
} else {
|
||||
RI.Jit->WriteExitDestInReg(regLocForInst(RI, dest));
|
||||
}
|
||||
}
|
||||
static void regStoreInstToPPCState(RegInfo& RI, unsigned width, InstLoc I, s32 offset) {
|
||||
void (JitArmIL::*op)(ARMReg, ARMReg, Operand2, bool);
|
||||
switch(width)
|
||||
{
|
||||
case 32:
|
||||
op = &JitArmIL::STR;
|
||||
break;
|
||||
case 8:
|
||||
op = &JitArmIL::STRB;
|
||||
break;
|
||||
default:
|
||||
PanicAlert("Not implemented!");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isImm(*I)) {
|
||||
RI.Jit->MOVI2R(R12, RI.Build->GetImmValue(I));
|
||||
(RI.Jit->*op)(R12, R9, offset, true);
|
||||
return;
|
||||
}
|
||||
ARMReg reg = regEnsureInReg(RI, I);
|
||||
(RI.Jit->*op)(reg, R9, offset, true);
|
||||
}
|
||||
|
||||
//
|
||||
// Mark and calculation routines for profiled load/store addresses
|
||||
// Could be extended to unprofiled addresses.
|
||||
static void regMarkMemAddress(RegInfo& RI, InstLoc I, InstLoc AI, unsigned OpNum) {
|
||||
if (isImm(*AI)) {
|
||||
unsigned addr = RI.Build->GetImmValue(AI);
|
||||
if (Memory::IsRAMAddress(addr))
|
||||
return;
|
||||
}
|
||||
if (getOpcode(*AI) == Add && isImm(*getOp2(AI))) {
|
||||
regMarkUse(RI, I, getOp1(AI), OpNum);
|
||||
return;
|
||||
}
|
||||
regMarkUse(RI, I, AI, OpNum);
|
||||
}
|
||||
// Binary ops
|
||||
void JitArmIL::BIN_XOR(ARMReg reg, Operand2 op2)
|
||||
{
|
||||
EOR(reg, reg, op2);
|
||||
}
|
||||
void JitArmIL::BIN_OR(ARMReg reg, Operand2 op2)
|
||||
{
|
||||
ORR(reg, reg, op2);
|
||||
}
|
||||
void JitArmIL::BIN_AND(ARMReg reg, Operand2 op2)
|
||||
{
|
||||
AND(reg, reg, op2);
|
||||
}
|
||||
void JitArmIL::BIN_ADD(ARMReg reg, Operand2 op2)
|
||||
{
|
||||
ADD(reg, reg, op2);
|
||||
}
|
||||
static void regEmitShiftInst(RegInfo& RI, InstLoc I, void (JitArmIL::*op)(ARMReg, ARMReg, Operand2))
|
||||
{
|
||||
ARMReg reg = regBinLHSReg(RI, I);
|
||||
if (isImm(*getOp2(I))) {
|
||||
unsigned RHS = RI.Build->GetImmValue(getOp2(I));
|
||||
(RI.Jit->*op)(reg, reg, RHS);
|
||||
RI.regs[reg] = I;
|
||||
return;
|
||||
}
|
||||
(RI.Jit->*op)(reg, reg, regLocForInst(RI, getOp2(I)));
|
||||
RI.regs[reg] = I;
|
||||
regNormalRegClear(RI, I);
|
||||
}
|
||||
|
||||
static void regEmitBinInst(RegInfo& RI, InstLoc I,
|
||||
void (JitArmIL::*op)(ARMReg, Operand2),
|
||||
bool commutable = false) {
|
||||
ARMReg reg;
|
||||
bool commuted = false;
|
||||
if (RI.IInfo[I - RI.FirstI] & 4) {
|
||||
reg = regEnsureInReg(RI, getOp1(I));
|
||||
} else if (commutable && (RI.IInfo[I - RI.FirstI] & 8)) {
|
||||
reg = regEnsureInReg(RI, getOp2(I));
|
||||
commuted = true;
|
||||
} else {
|
||||
reg = regFindFreeReg(RI);
|
||||
RI.Jit->MOV(reg, regLocForInst(RI, getOp1(I)));
|
||||
}
|
||||
if (isImm(*getOp2(I))) {
|
||||
unsigned RHS = RI.Build->GetImmValue(getOp2(I));
|
||||
Operand2 RHSop;
|
||||
if (TryMakeOperand2(RHS, RHSop))
|
||||
(RI.Jit->*op)(reg, RHSop);
|
||||
else
|
||||
{
|
||||
RI.Jit->MOVI2R(R12, RHS);
|
||||
(RI.Jit->*op)(reg, R12);
|
||||
}
|
||||
} else if (commuted) {
|
||||
(RI.Jit->*op)(reg, regLocForInst(RI, getOp1(I)));
|
||||
} else {
|
||||
(RI.Jit->*op)(reg, regLocForInst(RI, getOp2(I)));
|
||||
}
|
||||
RI.regs[reg] = I;
|
||||
regNormalRegClear(RI, I);
|
||||
}
|
||||
static void regEmitCmp(RegInfo& RI, InstLoc I) {
|
||||
if (isImm(*getOp2(I))) {
|
||||
unsigned RHS = RI.Build->GetImmValue(getOp2(I));
|
||||
Operand2 op;
|
||||
if (TryMakeOperand2(RHS, op))
|
||||
RI.Jit->CMP(regLocForInst(RI, getOp1(I)), op);
|
||||
else
|
||||
{
|
||||
RI.Jit->MOVI2R(R12, RHS);
|
||||
RI.Jit->CMP(regLocForInst(RI, getOp1(I)), R12);
|
||||
}
|
||||
} else {
|
||||
ARMReg reg = regEnsureInReg(RI, getOp1(I));
|
||||
RI.Jit->CMP(reg, regLocForInst(RI, getOp2(I)));
|
||||
}
|
||||
}
|
||||
|
||||
static void DoWriteCode(IRBuilder* ibuild, JitArmIL* Jit) {
|
||||
RegInfo RI(Jit, ibuild->getFirstInst(), ibuild->getNumInsts());
|
||||
RI.Build = ibuild;
|
||||
|
||||
// Pass to compute liveness
|
||||
ibuild->StartBackPass();
|
||||
for (unsigned int index = (unsigned int)RI.IInfo.size() - 1; index != -1U; --index) {
|
||||
InstLoc I = ibuild->ReadBackward();
|
||||
unsigned int op = getOpcode(*I);
|
||||
bool thisUsed = regReadUse(RI, I) ? true : false;
|
||||
switch (op) {
|
||||
default:
|
||||
PanicAlert("Unexpected inst!");
|
||||
case Nop:
|
||||
case CInt16:
|
||||
case CInt32:
|
||||
case LoadGReg:
|
||||
case LoadLink:
|
||||
case LoadCR:
|
||||
case LoadCarry:
|
||||
case LoadCTR:
|
||||
case LoadMSR:
|
||||
case LoadFReg:
|
||||
case LoadFRegDENToZero:
|
||||
case LoadGQR:
|
||||
case BlockEnd:
|
||||
case BlockStart:
|
||||
case InterpreterFallback:
|
||||
case SystemCall:
|
||||
case RFIExit:
|
||||
case InterpreterBranch:
|
||||
case ShortIdleLoop:
|
||||
case FPExceptionCheck:
|
||||
case DSIExceptionCheck:
|
||||
case ISIException:
|
||||
case ExtExceptionCheck:
|
||||
case BreakPointCheck:
|
||||
case Int3:
|
||||
case Tramp:
|
||||
// No liveness effects
|
||||
break;
|
||||
case SExt8:
|
||||
case SExt16:
|
||||
case BSwap32:
|
||||
case BSwap16:
|
||||
case Cntlzw:
|
||||
case Not:
|
||||
case DupSingleToMReg:
|
||||
case DoubleToSingle:
|
||||
case ExpandPackedToMReg:
|
||||
case CompactMRegToPacked:
|
||||
case FPNeg:
|
||||
case FPDup0:
|
||||
case FPDup1:
|
||||
case FSNeg:
|
||||
case FDNeg:
|
||||
if (thisUsed)
|
||||
regMarkUse(RI, I, getOp1(I), 1);
|
||||
break;
|
||||
case Load8:
|
||||
case Load16:
|
||||
case Load32:
|
||||
regMarkMemAddress(RI, I, getOp1(I), 1);
|
||||
break;
|
||||
case LoadDouble:
|
||||
case LoadSingle:
|
||||
case LoadPaired:
|
||||
if (thisUsed)
|
||||
regMarkUse(RI, I, getOp1(I), 1);
|
||||
break;
|
||||
case StoreCR:
|
||||
case StoreCarry:
|
||||
case StoreFPRF:
|
||||
regMarkUse(RI, I, getOp1(I), 1);
|
||||
break;
|
||||
case StoreGReg:
|
||||
case StoreLink:
|
||||
case StoreCTR:
|
||||
case StoreMSR:
|
||||
case StoreGQR:
|
||||
case StoreSRR:
|
||||
case StoreFReg:
|
||||
if (!isImm(*getOp1(I)))
|
||||
regMarkUse(RI, I, getOp1(I), 1);
|
||||
break;
|
||||
case Add:
|
||||
case Sub:
|
||||
case And:
|
||||
case Or:
|
||||
case Xor:
|
||||
case Mul:
|
||||
case MulHighUnsigned:
|
||||
case Rol:
|
||||
case Shl:
|
||||
case Shrl:
|
||||
case Sarl:
|
||||
case ICmpCRUnsigned:
|
||||
case ICmpCRSigned:
|
||||
case ICmpEq:
|
||||
case ICmpNe:
|
||||
case ICmpUgt:
|
||||
case ICmpUlt:
|
||||
case ICmpUge:
|
||||
case ICmpUle:
|
||||
case ICmpSgt:
|
||||
case ICmpSlt:
|
||||
case ICmpSge:
|
||||
case ICmpSle:
|
||||
case FSMul:
|
||||
case FSAdd:
|
||||
case FSSub:
|
||||
case FSRSqrt:
|
||||
case FDMul:
|
||||
case FDAdd:
|
||||
case FDSub:
|
||||
case FPAdd:
|
||||
case FPMul:
|
||||
case FPSub:
|
||||
case FPMerge00:
|
||||
case FPMerge01:
|
||||
case FPMerge10:
|
||||
case FPMerge11:
|
||||
case FDCmpCR:
|
||||
case InsertDoubleInMReg:
|
||||
if (thisUsed) {
|
||||
regMarkUse(RI, I, getOp1(I), 1);
|
||||
if (!isImm(*getOp2(I)))
|
||||
regMarkUse(RI, I, getOp2(I), 2);
|
||||
}
|
||||
break;
|
||||
case Store8:
|
||||
case Store16:
|
||||
case Store32:
|
||||
if (!isImm(*getOp1(I)))
|
||||
regMarkUse(RI, I, getOp1(I), 1);
|
||||
regMarkMemAddress(RI, I, getOp2(I), 2);
|
||||
break;
|
||||
case StoreSingle:
|
||||
case StoreDouble:
|
||||
case StorePaired:
|
||||
regMarkUse(RI, I, getOp1(I), 1);
|
||||
regMarkUse(RI, I, getOp2(I), 2);
|
||||
break;
|
||||
case BranchUncond:
|
||||
if (!isImm(*getOp1(I)))
|
||||
regMarkUse(RI, I, getOp1(I), 1);
|
||||
break;
|
||||
case IdleBranch:
|
||||
regMarkUse(RI, I, getOp1(getOp1(I)), 1);
|
||||
break;
|
||||
case BranchCond: {
|
||||
if (isICmp(*getOp1(I)) &&
|
||||
isImm(*getOp2(getOp1(I)))) {
|
||||
regMarkUse(RI, I, getOp1(getOp1(I)), 1);
|
||||
} else {
|
||||
regMarkUse(RI, I, getOp1(I), 1);
|
||||
}
|
||||
if (!isImm(*getOp2(I)))
|
||||
regMarkUse(RI, I, getOp2(I), 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ibuild->StartForwardPass();
|
||||
for (unsigned i = 0; i != RI.IInfo.size(); i++) {
|
||||
InstLoc I = ibuild->ReadForward();
|
||||
|
||||
bool thisUsed = regReadUse(RI, I) ? true : false;
|
||||
if (thisUsed) {
|
||||
// Needed for IR Writer
|
||||
ibuild->SetMarkUsed(I);
|
||||
}
|
||||
|
||||
switch (getOpcode(*I)) {
|
||||
case CInt32:
|
||||
case CInt16: {
|
||||
if (!thisUsed) break;
|
||||
ARMReg reg = regFindFreeReg(RI);
|
||||
Jit->MOVI2R(reg, ibuild->GetImmValue(I));
|
||||
RI.regs[reg] = I;
|
||||
break;
|
||||
}
|
||||
case BranchUncond: {
|
||||
regWriteExit(RI, getOp1(I));
|
||||
regNormalRegClear(RI, I);
|
||||
break;
|
||||
}
|
||||
case BranchCond: {
|
||||
if (isICmp(*getOp1(I)) &&
|
||||
isImm(*getOp2(getOp1(I)))) {
|
||||
unsigned imm = RI.Build->GetImmValue(getOp2(getOp1(I)));
|
||||
if (imm > 255)
|
||||
{
|
||||
Jit->MOVI2R(R14, imm);
|
||||
Jit->CMP(regLocForInst(RI, getOp1(getOp1(I))), R14);
|
||||
}
|
||||
else
|
||||
Jit->CMP(regLocForInst(RI, getOp1(getOp1(I))), imm);
|
||||
CCFlags flag;
|
||||
switch (getOpcode(*getOp1(I))) {
|
||||
case ICmpEq: flag = CC_NEQ; break;
|
||||
case ICmpNe: flag = CC_EQ; break;
|
||||
case ICmpUgt: flag = CC_LS; break;
|
||||
case ICmpUlt: flag = CC_HI; break;
|
||||
case ICmpUge: flag = CC_HS; break;
|
||||
case ICmpUle: flag = CC_LO; break;
|
||||
case ICmpSgt: flag = CC_LT; break;
|
||||
case ICmpSlt: flag = CC_GT; break;
|
||||
case ICmpSge: flag = CC_LE; break;
|
||||
case ICmpSle: flag = CC_GE; break;
|
||||
default: PanicAlert("cmpXX"); flag = CC_AL; break;
|
||||
}
|
||||
FixupBranch cont = Jit->B_CC(flag);
|
||||
regWriteExit(RI, getOp2(I));
|
||||
Jit->SetJumpTarget(cont);
|
||||
if (RI.IInfo[I - RI.FirstI] & 4)
|
||||
regClearInst(RI, getOp1(getOp1(I)));
|
||||
} else {
|
||||
Jit->CMP(regLocForInst(RI, getOp1(I)), 0);
|
||||
FixupBranch cont = Jit->B_CC(CC_EQ);
|
||||
regWriteExit(RI, getOp2(I));
|
||||
Jit->SetJumpTarget(cont);
|
||||
if (RI.IInfo[I - RI.FirstI] & 4)
|
||||
regClearInst(RI, getOp1(I));
|
||||
}
|
||||
if (RI.IInfo[I - RI.FirstI] & 8)
|
||||
regClearInst(RI, getOp2(I));
|
||||
break;
|
||||
}
|
||||
|
||||
case StoreGReg: {
|
||||
unsigned ppcreg = *I >> 16;
|
||||
regStoreInstToPPCState(RI, 32, getOp1(I), PPCSTATE_OFF(gpr[ppcreg]));
|
||||
regNormalRegClear(RI, I);
|
||||
break;
|
||||
}
|
||||
case StoreCR: {
|
||||
unsigned ppcreg = *I >> 16;
|
||||
regStoreInstToPPCState(RI, 8, getOp1(I), PPCSTATE_OFF(cr_fast[ppcreg]));
|
||||
regNormalRegClear(RI, I);
|
||||
break;
|
||||
}
|
||||
case StoreLink: {
|
||||
regStoreInstToPPCState(RI, 32, getOp1(I), PPCSTATE_OFF(spr[SPR_LR]));
|
||||
regNormalRegClear(RI, I);
|
||||
break;
|
||||
}
|
||||
case StoreCTR: {
|
||||
regStoreInstToPPCState(RI, 32, getOp1(I), PPCSTATE_OFF(spr[SPR_CTR]));
|
||||
regNormalRegClear(RI, I);
|
||||
break;
|
||||
}
|
||||
case StoreMSR: {
|
||||
regStoreInstToPPCState(RI, 32, getOp1(I), PPCSTATE_OFF(msr));
|
||||
regNormalRegClear(RI, I);
|
||||
break;
|
||||
}
|
||||
case LoadGReg: {
|
||||
if (!thisUsed) break;
|
||||
ARMReg reg = regFindFreeReg(RI);
|
||||
unsigned ppcreg = *I >> 8;
|
||||
Jit->LDR(reg, R9, PPCSTATE_OFF(gpr[ppcreg]));
|
||||
RI.regs[reg] = I;
|
||||
break;
|
||||
}
|
||||
case LoadCR: {
|
||||
if (!thisUsed) break;
|
||||
ARMReg reg = regFindFreeReg(RI);
|
||||
unsigned ppcreg = *I >> 8;
|
||||
Jit->LDRB(reg, R9, PPCSTATE_OFF(cr_fast[ppcreg]));
|
||||
RI.regs[reg] = I;
|
||||
break;
|
||||
}
|
||||
case LoadCTR: {
|
||||
if (!thisUsed) break;
|
||||
ARMReg reg = regFindFreeReg(RI);
|
||||
Jit->LDR(reg, R9, PPCSTATE_OFF(spr[SPR_CTR]));
|
||||
RI.regs[reg] = I;
|
||||
break;
|
||||
}
|
||||
case LoadLink: {
|
||||
if (!thisUsed) break;
|
||||
ARMReg reg = regFindFreeReg(RI);
|
||||
Jit->LDR(reg, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
RI.regs[reg] = I;
|
||||
break;
|
||||
}
|
||||
case InterpreterFallback: {
|
||||
unsigned InstCode = ibuild->GetImmValue(getOp1(I));
|
||||
unsigned InstLoc = ibuild->GetImmValue(getOp2(I));
|
||||
// There really shouldn't be anything live across an
|
||||
// interpreter call at the moment, but optimizing interpreter
|
||||
// calls isn't completely out of the question...
|
||||
regSpillCallerSaved(RI);
|
||||
Jit->MOVI2R(R14, InstLoc);
|
||||
Jit->STR(R14, R9, PPCSTATE_OFF(pc));
|
||||
Jit->MOVI2R(R14, InstLoc + 4);
|
||||
Jit->STR(R14, R9, PPCSTATE_OFF(npc));
|
||||
|
||||
Jit->MOVI2R(R0, InstCode);
|
||||
Jit->MOVI2R(R14, (u32)GetInterpreterOp(InstCode));
|
||||
Jit->BL(R14);
|
||||
break;
|
||||
}
|
||||
case SystemCall: {
|
||||
unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
|
||||
Jit->MOVI2R(R14, InstLoc + 4);
|
||||
Jit->STR(R14, R9, PPCSTATE_OFF(pc));
|
||||
Jit->LDR(R14, R9, PPCSTATE_OFF(Exceptions));
|
||||
Jit->ORR(R14, R14, EXCEPTION_SYSCALL);
|
||||
Jit->STR(R14, R9, PPCSTATE_OFF(Exceptions));
|
||||
Jit->WriteExceptionExit();
|
||||
break;
|
||||
}
|
||||
case ShortIdleLoop: {
|
||||
unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
|
||||
Jit->MOVI2R(R14, (u32)&CoreTiming::Idle);
|
||||
Jit->BL(R14);
|
||||
Jit->MOVI2R(R14, InstLoc);
|
||||
Jit->STR(R14, R9, PPCSTATE_OFF(pc));
|
||||
Jit->MOVI2R(R14, (u32)Jit->GetAsmRoutines()->testExceptions);
|
||||
Jit->B(R14);
|
||||
break;
|
||||
}
|
||||
case InterpreterBranch: {
|
||||
Jit->LDR(R14, R9, PPCSTATE_OFF(npc));
|
||||
Jit->WriteExitDestInReg(R14);
|
||||
break;
|
||||
}
|
||||
case RFIExit: {
|
||||
const u32 mask = 0x87C0FFFF;
|
||||
const u32 clearMSR13 = 0xFFFBFFFF; // Mask used to clear the bit MSR[13]
|
||||
// MSR = ((MSR & ~mask) | (SRR1 & mask)) & clearMSR13;
|
||||
// R0 = MSR location
|
||||
// R1 = MSR contents
|
||||
// R2 = Mask
|
||||
// R3 = Mask
|
||||
ARMReg rA = R14;
|
||||
ARMReg rB = R12;
|
||||
ARMReg rC = R11;
|
||||
ARMReg rD = R10;
|
||||
Jit->MOVI2R(rB, (~mask) & clearMSR13);
|
||||
Jit->MOVI2R(rC, mask & clearMSR13);
|
||||
|
||||
Jit->LDR(rD, R9, PPCSTATE_OFF(msr));
|
||||
|
||||
Jit->AND(rD, rD, rB); // rD = Masked MSR
|
||||
|
||||
Jit->LDR(rB, R9, PPCSTATE_OFF(spr[SPR_SRR1])); // rB contains SRR1 here
|
||||
|
||||
Jit->AND(rB, rB, rC); // rB contains masked SRR1 here
|
||||
Jit->ORR(rB, rD, rB); // rB = Masked MSR OR masked SRR1
|
||||
|
||||
Jit->STR(rB, R9, PPCSTATE_OFF(msr)); // STR rB in to rA
|
||||
|
||||
Jit->LDR(rA, R9, PPCSTATE_OFF(spr[SPR_SRR0]));
|
||||
|
||||
Jit->WriteRfiExitDestInR(rA); // rA gets unlocked here
|
||||
break;
|
||||
}
|
||||
case Shl: {
|
||||
if (!thisUsed) break;
|
||||
regEmitShiftInst(RI, I, &JitArmIL::LSL);
|
||||
break;
|
||||
}
|
||||
case Shrl: {
|
||||
if (!thisUsed) break;
|
||||
regEmitShiftInst(RI, I, &JitArmIL::LSR);
|
||||
break;
|
||||
}
|
||||
case Sarl: {
|
||||
if (!thisUsed) break;
|
||||
regEmitShiftInst(RI, I, &JitArmIL::ASR);
|
||||
break;
|
||||
}
|
||||
case And: {
|
||||
if (!thisUsed) break;
|
||||
regEmitBinInst(RI, I, &JitArmIL::BIN_AND, true);
|
||||
break;
|
||||
}
|
||||
case Not: {
|
||||
if (!thisUsed) break;
|
||||
ARMReg reg = regBinLHSReg(RI, I);
|
||||
Jit->MVN(reg, reg);
|
||||
RI.regs[reg] = I;
|
||||
regNormalRegClear(RI, I);
|
||||
break;
|
||||
}
|
||||
case Or: {
|
||||
if (!thisUsed) break;
|
||||
regEmitBinInst(RI, I, &JitArmIL::BIN_OR, true);
|
||||
break;
|
||||
}
|
||||
case Xor: {
|
||||
if (!thisUsed) break;
|
||||
regEmitBinInst(RI, I, &JitArmIL::BIN_XOR, true);
|
||||
break;
|
||||
}
|
||||
case Add: {
|
||||
if (!thisUsed) break;
|
||||
regEmitBinInst(RI, I, &JitArmIL::BIN_ADD, true);
|
||||
break;
|
||||
}
|
||||
case ICmpCRUnsigned: {
|
||||
if (!thisUsed) break;
|
||||
regEmitCmp(RI, I);
|
||||
ARMReg reg = regBinReg(RI, I);
|
||||
Jit->MOV(reg, 0x2); // Result == 0
|
||||
Jit->SetCC(CC_LO); Jit->MOV(reg, 0x8); // Result < 0
|
||||
Jit->SetCC(CC_HI); Jit->MOV(reg, 0x4); // Result > 0
|
||||
Jit->SetCC();
|
||||
RI.regs[reg] = I;
|
||||
regNormalRegClear(RI, I);
|
||||
break;
|
||||
}
|
||||
|
||||
case ICmpCRSigned: {
|
||||
if (!thisUsed) break;
|
||||
regEmitCmp(RI, I);
|
||||
ARMReg reg = regBinReg(RI, I);
|
||||
Jit->MOV(reg, 0x2); // Result == 0
|
||||
Jit->SetCC(CC_LT); Jit->MOV(reg, 0x8); // Result < 0
|
||||
Jit->SetCC(CC_GT); Jit->MOV(reg, 0x4); // Result > 0
|
||||
Jit->SetCC();
|
||||
RI.regs[reg] = I;
|
||||
regNormalRegClear(RI, I);
|
||||
break;
|
||||
}
|
||||
case Int3:
|
||||
Jit->BKPT(0x321);
|
||||
break;
|
||||
case Tramp: break;
|
||||
case Nop: break;
|
||||
default:
|
||||
PanicAlert("Unknown JIT instruction; aborting!");
|
||||
ibuild->WriteToFile(0);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < MAX_NUMBER_OF_REGS; i++) {
|
||||
if (RI.regs[i]) {
|
||||
// Start a game in Burnout 2 to get this. Or animal crossing.
|
||||
PanicAlert("Incomplete cleanup! (regs)");
|
||||
exit(1);
|
||||
}
|
||||
if (RI.fregs[i]) {
|
||||
PanicAlert("Incomplete cleanup! (fregs)");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Jit->WriteExit(jit->js.curBlock->exitAddress[0], 0);
|
||||
Jit->BKPT(0x111);
|
||||
|
||||
}
|
||||
void JitArmIL::WriteCode() {
|
||||
DoWriteCode(&ibuild, this);
|
||||
}
|
1
Source/Core/Core/Src/PowerPC/JitArmIL/IR_Arm.h
Normal file
1
Source/Core/Core/Src/PowerPC/JitArmIL/IR_Arm.h
Normal file
@ -0,0 +1 @@
|
||||
|
365
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL.cpp
Normal file
365
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL.cpp
Normal file
@ -0,0 +1,365 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "Common.h"
|
||||
#include "../../HLE/HLE.h"
|
||||
#include "../../Core.h"
|
||||
#include "../../PatchEngine.h"
|
||||
#include "../../CoreTiming.h"
|
||||
#include "../../ConfigManager.h"
|
||||
#include "../PowerPC.h"
|
||||
#include "../Profiler.h"
|
||||
#include "../PPCTables.h"
|
||||
#include "../PPCAnalyst.h"
|
||||
#include "../../HW/Memmap.h"
|
||||
#include "../../HW/GPFifo.h"
|
||||
#include "JitIL.h"
|
||||
#include "JitIL_Tables.h"
|
||||
#include "ArmEmitter.h"
|
||||
#include "../JitInterface.h"
|
||||
|
||||
using namespace ArmGen;
|
||||
using namespace PowerPC;
|
||||
|
||||
static int CODE_SIZE = 1024*1024*32;
|
||||
namespace CPUCompare
|
||||
{
|
||||
extern u32 m_BlockStart;
|
||||
}
|
||||
void JitArmIL::Init()
|
||||
{
|
||||
AllocCodeSpace(CODE_SIZE);
|
||||
blocks.Init();
|
||||
asm_routines.Init();
|
||||
}
|
||||
|
||||
void JitArmIL::ClearCache()
|
||||
{
|
||||
ClearCodeSpace();
|
||||
blocks.Clear();
|
||||
}
|
||||
|
||||
void JitArmIL::Shutdown()
|
||||
{
|
||||
FreeCodeSpace();
|
||||
blocks.Shutdown();
|
||||
asm_routines.Shutdown();
|
||||
}
|
||||
void JitArmIL::unknown_instruction(UGeckoInstruction inst)
|
||||
{
|
||||
// CCPU::Break();
|
||||
PanicAlert("unknown_instruction %08x - Fix me ;)", inst.hex);
|
||||
}
|
||||
|
||||
void JitArmIL::Default(UGeckoInstruction _inst)
|
||||
{
|
||||
ibuild.EmitInterpreterFallback(
|
||||
ibuild.EmitIntConst(_inst.hex),
|
||||
ibuild.EmitIntConst(js.compilerPC));
|
||||
}
|
||||
|
||||
void JitArmIL::HLEFunction(UGeckoInstruction _inst)
|
||||
{
|
||||
// XXX
|
||||
}
|
||||
|
||||
void JitArmIL::DoNothing(UGeckoInstruction _inst)
|
||||
{
|
||||
// Yup, just don't do anything.
|
||||
}
|
||||
void JitArmIL::Break(UGeckoInstruction _inst)
|
||||
{
|
||||
ibuild.EmitINT3();
|
||||
}
|
||||
|
||||
void JitArmIL::DoDownCount()
|
||||
{
|
||||
ARMReg rA = R14;
|
||||
ARMReg rB = R12;
|
||||
MOVI2R(rA, (u32)&CoreTiming::downcount);
|
||||
LDR(rB, rA);
|
||||
if(js.downcountAmount < 255) // We can enlarge this if we used rotations
|
||||
{
|
||||
SUBS(rB, rB, js.downcountAmount);
|
||||
STR(rB, rA);
|
||||
}
|
||||
else
|
||||
{
|
||||
ARMReg rC = R11;
|
||||
MOVI2R(rC, js.downcountAmount);
|
||||
SUBS(rB, rB, rC);
|
||||
STR(rB, rA);
|
||||
}
|
||||
}
|
||||
|
||||
void JitArmIL::WriteExitDestInReg(ARMReg Reg)
|
||||
{
|
||||
STR(Reg, R9, PPCSTATE_OFF(pc));
|
||||
DoDownCount();
|
||||
MOVI2R(Reg, (u32)asm_routines.dispatcher);
|
||||
B(Reg);
|
||||
}
|
||||
|
||||
void JitArmIL::WriteRfiExitDestInR(ARMReg Reg)
|
||||
{
|
||||
STR(Reg, R9, PPCSTATE_OFF(pc));
|
||||
DoDownCount();
|
||||
MOVI2R(Reg, (u32)asm_routines.testExceptions);
|
||||
B(Reg);
|
||||
}
|
||||
void JitArmIL::WriteExceptionExit()
|
||||
{
|
||||
DoDownCount();
|
||||
|
||||
MOVI2R(R14, (u32)asm_routines.testExceptions);
|
||||
B(R14);
|
||||
}
|
||||
void JitArmIL::WriteExit(u32 destination, int exit_num)
|
||||
{
|
||||
DoDownCount();
|
||||
//If nobody has taken care of this yet (this can be removed when all branches are done)
|
||||
JitBlock *b = js.curBlock;
|
||||
b->exitAddress[exit_num] = destination;
|
||||
b->exitPtrs[exit_num] = GetWritableCodePtr();
|
||||
|
||||
// Link opportunity!
|
||||
int block = blocks.GetBlockNumberFromStartAddress(destination);
|
||||
if (block >= 0 && jo.enableBlocklink)
|
||||
{
|
||||
// It exists! Joy of joy!
|
||||
B(blocks.GetBlock(block)->checkedEntry);
|
||||
b->linkStatus[exit_num] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
MOVI2R(R14, destination);
|
||||
STR(R14, R9, PPCSTATE_OFF(pc));
|
||||
MOVI2R(R14, (u32)asm_routines.dispatcher);
|
||||
B(R14);
|
||||
}
|
||||
}
|
||||
void JitArmIL::PrintDebug(UGeckoInstruction inst, u32 level)
|
||||
{
|
||||
if (level > 0)
|
||||
printf("Start: %08x OP '%s' Info\n", (u32)GetCodePtr(), PPCTables::GetInstructionName(inst));
|
||||
if (level > 1)
|
||||
{
|
||||
GekkoOPInfo* Info = GetOpInfo(inst.hex);
|
||||
printf("\tOuts\n");
|
||||
if (Info->flags & FL_OUT_A)
|
||||
printf("\t-OUT_A: %x\n", inst.RA);
|
||||
if(Info->flags & FL_OUT_D)
|
||||
printf("\t-OUT_D: %x\n", inst.RD);
|
||||
printf("\tIns\n");
|
||||
// A, AO, B, C, S
|
||||
if(Info->flags & FL_IN_A)
|
||||
printf("\t-IN_A: %x\n", inst.RA);
|
||||
if(Info->flags & FL_IN_A0)
|
||||
printf("\t-IN_A0: %x\n", inst.RA);
|
||||
if(Info->flags & FL_IN_B)
|
||||
printf("\t-IN_B: %x\n", inst.RB);
|
||||
if(Info->flags & FL_IN_C)
|
||||
printf("\t-IN_C: %x\n", inst.RC);
|
||||
if(Info->flags & FL_IN_S)
|
||||
printf("\t-IN_S: %x\n", inst.RS);
|
||||
}
|
||||
}
|
||||
|
||||
void STACKALIGN JitArmIL::Run()
|
||||
{
|
||||
CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode;
|
||||
pExecAddr();
|
||||
}
|
||||
|
||||
void JitArmIL::SingleStep()
|
||||
{
|
||||
CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode;
|
||||
pExecAddr();
|
||||
}
|
||||
void STACKALIGN JitArmIL::Jit(u32 em_address)
|
||||
{
|
||||
if (GetSpaceLeft() < 0x10000 || blocks.IsFull() || Core::g_CoreStartupParameter.bJITNoBlockCache)
|
||||
{
|
||||
ClearCache();
|
||||
}
|
||||
|
||||
int block_num = blocks.AllocateBlock(PowerPC::ppcState.pc);
|
||||
JitBlock *b = blocks.GetBlock(block_num);
|
||||
const u8* BlockPtr = DoJit(PowerPC::ppcState.pc, &code_buffer, b);
|
||||
blocks.FinalizeBlock(block_num, jo.enableBlocklink, BlockPtr);
|
||||
}
|
||||
|
||||
const u8* JitArmIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b)
|
||||
{
|
||||
int blockSize = code_buf->GetSize();
|
||||
// Memory exception on instruction fetch
|
||||
bool memory_exception = false;
|
||||
|
||||
// A broken block is a block that does not end in a branch
|
||||
bool broken_block = false;
|
||||
|
||||
if (Core::g_CoreStartupParameter.bEnableDebugging)
|
||||
{
|
||||
// Comment out the following to disable breakpoints (speed-up)
|
||||
blockSize = 1;
|
||||
broken_block = true;
|
||||
}
|
||||
|
||||
if (em_address == 0)
|
||||
{
|
||||
Core::SetState(Core::CORE_PAUSE);
|
||||
PanicAlert("ERROR: Compiling at 0. LR=%08x CTR=%08x", LR, CTR);
|
||||
}
|
||||
|
||||
if (Core::g_CoreStartupParameter.bMMU && (em_address & JIT_ICACHE_VMEM_BIT))
|
||||
{
|
||||
if (!Memory::TranslateAddress(em_address, Memory::FLAG_OPCODE))
|
||||
{
|
||||
// Memory exception occurred during instruction fetch
|
||||
memory_exception = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int size = 0;
|
||||
js.isLastInstruction = false;
|
||||
js.blockStart = em_address;
|
||||
js.fifoBytesThisBlock = 0;
|
||||
js.curBlock = b;
|
||||
js.block_flags = 0;
|
||||
js.cancel = false;
|
||||
|
||||
// Analyze the block, collect all instructions it is made of (including inlining,
|
||||
// if that is enabled), reorder instructions for optimal performance, and join joinable instructions.
|
||||
u32 nextPC = em_address;
|
||||
u32 merged_addresses[32];
|
||||
const int capacity_of_merged_addresses = sizeof(merged_addresses) / sizeof(merged_addresses[0]);
|
||||
int size_of_merged_addresses = 0;
|
||||
if (!memory_exception)
|
||||
{
|
||||
// If there is a memory exception inside a block (broken_block==true), compile up to that instruction.
|
||||
nextPC = PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, broken_block, code_buf, blockSize, merged_addresses, capacity_of_merged_addresses, size_of_merged_addresses);
|
||||
}
|
||||
PPCAnalyst::CodeOp *ops = code_buf->codebuffer;
|
||||
|
||||
const u8 *start = GetCodePtr();
|
||||
b->checkedEntry = start;
|
||||
b->runCount = 0;
|
||||
|
||||
// Downcount flag check, Only valid for linked blocks
|
||||
{
|
||||
// XXX
|
||||
}
|
||||
|
||||
const u8 *normalEntry = GetCodePtr();
|
||||
b->normalEntry = normalEntry;
|
||||
|
||||
if (js.fpa.any)
|
||||
{
|
||||
// XXX
|
||||
// This block uses FPU - needs to add FP exception bailout
|
||||
}
|
||||
js.rewriteStart = (u8*)GetCodePtr();
|
||||
|
||||
u64 codeHash = -1;
|
||||
{
|
||||
// For profiling and IR Writer
|
||||
for (int i = 0; i < (int)size; i++)
|
||||
{
|
||||
const u64 inst = ops[i].inst.hex;
|
||||
// Ported from boost::hash
|
||||
codeHash ^= inst + (codeHash << 6) + (codeHash >> 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Conditionally add profiling code.
|
||||
if (Profiler::g_ProfileBlocks) {
|
||||
// XXX
|
||||
}
|
||||
// Start up IR builder (structure that collects the
|
||||
// instruction processed by the JIT routines)
|
||||
ibuild.Reset();
|
||||
|
||||
js.downcountAmount = 0;
|
||||
if (!Core::g_CoreStartupParameter.bEnableDebugging)
|
||||
{
|
||||
for (int i = 0; i < size_of_merged_addresses; ++i)
|
||||
{
|
||||
const u32 address = merged_addresses[i];
|
||||
js.downcountAmount += PatchEngine::GetSpeedhackCycles(address);
|
||||
}
|
||||
}
|
||||
|
||||
js.skipnext = false;
|
||||
js.blockSize = size;
|
||||
js.compilerPC = nextPC;
|
||||
// Translate instructions
|
||||
for (int i = 0; i < (int)size; i++)
|
||||
{
|
||||
js.compilerPC = ops[i].address;
|
||||
js.op = &ops[i];
|
||||
js.instructionNumber = i;
|
||||
const GekkoOPInfo *opinfo = ops[i].opinfo;
|
||||
js.downcountAmount += (opinfo->numCyclesMinusOne + 1);
|
||||
|
||||
if (i == (int)size - 1)
|
||||
{
|
||||
// WARNING - cmp->branch merging will screw this up.
|
||||
js.isLastInstruction = true;
|
||||
js.next_inst = 0;
|
||||
if (Profiler::g_ProfileBlocks) {
|
||||
// CAUTION!!! push on stack regs you use, do your stuff, then pop
|
||||
PROFILER_VPUSH;
|
||||
// get end tic
|
||||
PROFILER_QUERY_PERFORMANCE_COUNTER(&b->ticStop);
|
||||
// tic counter += (end tic - start tic)
|
||||
PROFILER_ADD_DIFF_LARGE_INTEGER(&b->ticCounter, &b->ticStop, &b->ticStart);
|
||||
PROFILER_VPOP;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// help peephole optimizations
|
||||
js.next_inst = ops[i + 1].inst;
|
||||
js.next_compilerPC = ops[i + 1].address;
|
||||
}
|
||||
if (!ops[i].skip)
|
||||
{
|
||||
PrintDebug(ops[i].inst, 0);
|
||||
if (js.memcheck && (opinfo->flags & FL_USE_FPU))
|
||||
{
|
||||
// Don't do this yet
|
||||
BKPT(0x7777);
|
||||
}
|
||||
JitArmILTables::CompileInstruction(ops[i]);
|
||||
if (js.memcheck && (opinfo->flags & FL_LOADSTORE))
|
||||
{
|
||||
// Don't do this yet
|
||||
BKPT(0x666);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (memory_exception)
|
||||
BKPT(0x500);
|
||||
if (broken_block)
|
||||
{
|
||||
printf("Broken Block going to 0x%08x\n", nextPC);
|
||||
WriteExit(nextPC, 0);
|
||||
}
|
||||
|
||||
// Perform actual code generation
|
||||
|
||||
WriteCode();
|
||||
b->flags = js.block_flags;
|
||||
b->codeSize = (u32)(GetCodePtr() - normalEntry);
|
||||
b->originalSize = size;
|
||||
|
||||
{
|
||||
}
|
||||
FlushIcache();
|
||||
return start;
|
||||
|
||||
}
|
99
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL.h
Normal file
99
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL.h
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _JITARMIL_H
|
||||
#define _JITARMIL_H
|
||||
|
||||
#include "../PPCAnalyst.h"
|
||||
#include "ArmEmitter.h"
|
||||
#include "../JitArm32/JitArmCache.h"
|
||||
#include "../JitILCommon/JitILBase.h"
|
||||
#include "../JitILCommon/IR.h"
|
||||
#include "../JitCommon/JitBase.h"
|
||||
#include "JitILAsm.h"
|
||||
|
||||
#define JITDISABLE(setting) \
|
||||
if (Core::g_CoreStartupParameter.bJITOff || \
|
||||
Core::g_CoreStartupParameter.setting) \
|
||||
{Default(inst); return;}
|
||||
|
||||
#define PPCSTATE_OFF(elem) ((s32)STRUCT_OFF(PowerPC::ppcState, elem) - (s32)STRUCT_OFF(PowerPC::ppcState, spr[0]))
|
||||
class JitArmIL : public JitILBase, public ArmGen::ARMXCodeBlock
|
||||
{
|
||||
private:
|
||||
JitArmBlockCache blocks;
|
||||
JitArmILAsmRoutineManager asm_routines;
|
||||
|
||||
void PrintDebug(UGeckoInstruction inst, u32 level);
|
||||
void DoDownCount();
|
||||
|
||||
public:
|
||||
// Initialization, etc
|
||||
JitArmIL() {}
|
||||
~JitArmIL() {}
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
// Jit!
|
||||
|
||||
void Jit(u32 em_address);
|
||||
const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buffer, JitBlock *b);
|
||||
|
||||
JitBaseBlockCache *GetBlockCache() { return &blocks; }
|
||||
|
||||
const u8 *BackPatch(u8 *codePtr, u32 em_address, void *ctx) { return NULL; }
|
||||
|
||||
bool IsInCodeSpace(u8 *ptr) { return IsInSpace(ptr); }
|
||||
|
||||
void ClearCache();
|
||||
const u8 *GetDispatcher() {
|
||||
return asm_routines.dispatcher; // asm_routines.dispatcher
|
||||
}
|
||||
const CommonAsmRoutinesBase *GetAsmRoutines() {
|
||||
return &asm_routines;
|
||||
}
|
||||
|
||||
const char *GetName() {
|
||||
return "JITARMIL";
|
||||
}
|
||||
|
||||
// Run!
|
||||
|
||||
void Run();
|
||||
void SingleStep();
|
||||
//
|
||||
void WriteCode();
|
||||
void WriteExit(u32 destination, int exit_num);
|
||||
void WriteExitDestInReg(ARMReg Reg);
|
||||
void WriteRfiExitDestInR(ARMReg Reg);
|
||||
void WriteExceptionExit();
|
||||
|
||||
// OPCODES
|
||||
void unknown_instruction(UGeckoInstruction inst);
|
||||
void Default(UGeckoInstruction inst);
|
||||
void DoNothing(UGeckoInstruction inst);
|
||||
void HLEFunction(UGeckoInstruction inst);
|
||||
void Break(UGeckoInstruction inst);
|
||||
|
||||
void DynaRunTable4(UGeckoInstruction inst);
|
||||
void DynaRunTable19(UGeckoInstruction inst);
|
||||
void DynaRunTable31(UGeckoInstruction inst);
|
||||
void DynaRunTable59(UGeckoInstruction inst);
|
||||
void DynaRunTable63(UGeckoInstruction inst);
|
||||
|
||||
// Binary ops
|
||||
void BIN_AND(ARMReg reg, Operand2 op2);
|
||||
void BIN_XOR(ARMReg reg, Operand2 op2);
|
||||
void BIN_OR(ARMReg reg, Operand2 op2);
|
||||
void BIN_ADD(ARMReg reg, Operand2 op2);
|
||||
|
||||
// Branches
|
||||
void bx(UGeckoInstruction inst);
|
||||
void bcx(UGeckoInstruction inst);
|
||||
void bclrx(UGeckoInstruction inst);
|
||||
void bcctrx(UGeckoInstruction inst);
|
||||
};
|
||||
|
||||
#endif
|
121
Source/Core/Core/Src/PowerPC/JitArmIL/JitILAsm.cpp
Normal file
121
Source/Core/Core/Src/PowerPC/JitArmIL/JitILAsm.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
#include "../../HW/Memmap.h"
|
||||
|
||||
#include "../PowerPC.h"
|
||||
#include "../../CoreTiming.h"
|
||||
#include "MemoryUtil.h"
|
||||
|
||||
#include "JitIL.h"
|
||||
#include "../JitCommon/JitCache.h"
|
||||
|
||||
#include "../../HW/GPFifo.h"
|
||||
#include "../../Core.h"
|
||||
|
||||
#include "JitILAsm.h"
|
||||
#include "ArmEmitter.h"
|
||||
|
||||
JitArmILAsmRoutineManager armil_asm_routines;
|
||||
void JitArmILAsmRoutineManager::Generate()
|
||||
{
|
||||
enterCode = GetCodePtr();
|
||||
PUSH(9, R4, R5, R6, R7, R8, R9, R10, R11, _LR);
|
||||
// Take care to 8-byte align stack for function calls.
|
||||
// We are misaligned here because of an odd number of args for PUSH.
|
||||
// It's not like x86 where you need to account for an extra 4 bytes
|
||||
// consumed by CALL.
|
||||
SUB(_SP, _SP, 4);
|
||||
|
||||
MOVI2R(R0, (u32)&CoreTiming::downcount);
|
||||
MOVI2R(R9, (u32)&PowerPC::ppcState.spr[0]);
|
||||
|
||||
FixupBranch skipToRealDispatcher = B();
|
||||
dispatcher = GetCodePtr();
|
||||
printf("ILDispatcher is %p\n", dispatcher);
|
||||
|
||||
// Downcount Check
|
||||
// The result of slice decrementation should be in flags if somebody jumped here
|
||||
// IMPORTANT - We jump on negative, not carry!!!
|
||||
FixupBranch bail = B_CC(CC_MI);
|
||||
|
||||
SetJumpTarget(skipToRealDispatcher);
|
||||
dispatcherNoCheck = GetCodePtr();
|
||||
|
||||
// This block of code gets the address of the compiled block of code
|
||||
// It runs though to the compiling portion if it isn't found
|
||||
LDR(R12, R9, PPCSTATE_OFF(pc));// Load the current PC into R12
|
||||
|
||||
Operand2 iCacheMask = Operand2(0xE, 2); // JIT_ICACHE_MASK
|
||||
BIC(R12, R12, iCacheMask); // R12 contains PC & JIT_ICACHE_MASK here.
|
||||
|
||||
MOVI2R(R14, (u32)jit->GetBlockCache()->GetICache());
|
||||
|
||||
LDR(R12, R14, R12); // R12 contains iCache[PC & JIT_ICACHE_MASK] here
|
||||
// R12 Confirmed this is the correct iCache Location loaded.
|
||||
TST(R12, 0xFC); // Test to see if it is a JIT block.
|
||||
|
||||
SetCC(CC_EQ);
|
||||
// Success, it is our Jitblock.
|
||||
MOVI2R(R14, (u32)jit->GetBlockCache()->GetCodePointers());
|
||||
// LDR R14 right here to get CodePointers()[0] pointer.
|
||||
REV(R12, R12); // Reversing this gives us our JITblock.
|
||||
LSL(R12, R12, 2); // Multiply by four because address locations are u32 in size
|
||||
LDR(R14, R14, R12); // Load the block address in to R14
|
||||
|
||||
B(R14);
|
||||
// No need to jump anywhere after here, the block will go back to dispatcher start
|
||||
SetCC();
|
||||
|
||||
// If we get to this point, that means that we don't have the block cached to execute
|
||||
// So call ArmJit to compile the block and then execute it.
|
||||
MOVI2R(R14, (u32)&Jit);
|
||||
BL(R14);
|
||||
|
||||
B(dispatcherNoCheck);
|
||||
|
||||
// fpException()
|
||||
// Floating Point Exception Check, Jumped to if false
|
||||
fpException = GetCodePtr();
|
||||
LDR(R0, R9, PPCSTATE_OFF(Exceptions));
|
||||
ORR(R0, R0, EXCEPTION_FPU_UNAVAILABLE);
|
||||
STR(R0, R9, PPCSTATE_OFF(Exceptions));
|
||||
QuickCallFunction(R14, (void*)&PowerPC::CheckExceptions);
|
||||
LDR(R0, R9, PPCSTATE_OFF(npc));
|
||||
STR(R0, R9, PPCSTATE_OFF(pc));
|
||||
B(dispatcher);
|
||||
|
||||
SetJumpTarget(bail);
|
||||
doTiming = GetCodePtr();
|
||||
// XXX: In JIT64, Advance() gets called /after/ the exception checking
|
||||
// once it jumps back to the start of outerLoop
|
||||
QuickCallFunction(R14, (void*)&CoreTiming::Advance);
|
||||
|
||||
// Does exception checking
|
||||
testExceptions = GetCodePtr();
|
||||
LDR(R0, R9, PPCSTATE_OFF(pc));
|
||||
STR(R0, R9, PPCSTATE_OFF(npc));
|
||||
QuickCallFunction(R14, (void*)&PowerPC::CheckExceptions);
|
||||
LDR(R0, R9, PPCSTATE_OFF(npc));
|
||||
STR(R0, R9, PPCSTATE_OFF(pc));
|
||||
// Check the state pointer to see if we are exiting
|
||||
// Gets checked on every exception check
|
||||
MOVI2R(R0, (u32)PowerPC::GetStatePtr());
|
||||
MVN(R1, 0);
|
||||
LDR(R0, R0);
|
||||
TST(R0, R1);
|
||||
FixupBranch Exit = B_CC(CC_NEQ);
|
||||
|
||||
B(dispatcher);
|
||||
|
||||
SetJumpTarget(Exit);
|
||||
|
||||
ADD(_SP, _SP, 4);
|
||||
|
||||
POP(9, R4, R5, R6, R7, R8, R9, R10, R11, _PC); // Returns
|
||||
|
||||
GenerateCommon();
|
||||
|
||||
FlushIcache();
|
||||
}
|
||||
|
32
Source/Core/Core/Src/PowerPC/JitArmIL/JitILAsm.h
Normal file
32
Source/Core/Core/Src/PowerPC/JitArmIL/JitILAsm.h
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _JITARMILASM_H
|
||||
#define _JITARMILASM_H
|
||||
#include "ArmEmitter.h"
|
||||
#include "../JitCommon/JitAsmCommon.h"
|
||||
using namespace ArmGen;
|
||||
class JitArmILAsmRoutineManager : public CommonAsmRoutinesBase, public ARMXCodeBlock
|
||||
{
|
||||
private:
|
||||
void Generate();
|
||||
void GenerateCommon() {}
|
||||
|
||||
public:
|
||||
void Init() {
|
||||
AllocCodeSpace(8192);
|
||||
Generate();
|
||||
WriteProtect();
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
FreeCodeSpace();
|
||||
}
|
||||
};
|
||||
|
||||
extern JitArmILAsmRoutineManager armil_asm_routines;
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -6,44 +6,18 @@
|
||||
|
||||
#include "../../ConfigManager.h"
|
||||
#include "../PowerPC.h"
|
||||
#include "../../CoreTiming.h"
|
||||
#include "../PPCTables.h"
|
||||
#include "x64Emitter.h"
|
||||
|
||||
#include "JitIL.h"
|
||||
#include "JitILAsm.h"
|
||||
|
||||
#include "../../HW/Memmap.h"
|
||||
|
||||
// The branches are known good, or at least reasonably good.
|
||||
// No need for a disable-mechanism.
|
||||
#define NORMALBRANCH_START Default(inst); ibuild.EmitInterpreterBranch(); return;
|
||||
//#define NORMALBRANCH_START
|
||||
|
||||
// If defined, clears CR0 at blr and bl-s. If the assumption that
|
||||
// flags never carry over between functions holds, then the task for
|
||||
// an optimizer becomes much easier.
|
||||
|
||||
// #define ACID_TEST
|
||||
|
||||
// Zelda and many more games seem to pass the Acid Test.
|
||||
|
||||
//#define NORMALBRANCH_START Default(inst); ibuild.EmitInterpreterBranch(); return;
|
||||
#define NORMALBRANCH_START
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
void JitIL::sc(UGeckoInstruction inst)
|
||||
void JitArmIL::bx(UGeckoInstruction inst)
|
||||
{
|
||||
ibuild.EmitSystemCall(ibuild.EmitIntConst(js.compilerPC));
|
||||
}
|
||||
|
||||
void JitIL::rfi(UGeckoInstruction inst)
|
||||
{
|
||||
ibuild.EmitRFIExit();
|
||||
}
|
||||
|
||||
void JitIL::bx(UGeckoInstruction inst)
|
||||
{
|
||||
NORMALBRANCH_START
|
||||
//NORMALBRANCH_START
|
||||
INSTRUCTION_START;
|
||||
|
||||
// We must always process the following sentence
|
||||
@ -71,7 +45,6 @@ void JitIL::bx(UGeckoInstruction inst)
|
||||
|
||||
ibuild.EmitBranchUncond(ibuild.EmitIntConst(destination));
|
||||
}
|
||||
|
||||
static IREmitter::InstLoc TestBranch(IREmitter::IRBuilder& ibuild, UGeckoInstruction inst) {
|
||||
IREmitter::InstLoc CRTest = 0, CTRTest = 0;
|
||||
if ((inst.BO & 16) == 0) // Test a CR bit
|
||||
@ -109,7 +82,32 @@ static IREmitter::InstLoc TestBranch(IREmitter::IRBuilder& ibuild, UGeckoInstruc
|
||||
return Test;
|
||||
}
|
||||
|
||||
void JitIL::bcx(UGeckoInstruction inst)
|
||||
void JitArmIL::bclrx(UGeckoInstruction inst)
|
||||
{
|
||||
NORMALBRANCH_START
|
||||
|
||||
if (!js.isLastInstruction &&
|
||||
(inst.BO & (1 << 4)) && (inst.BO & (1 << 2))) {
|
||||
if (inst.LK)
|
||||
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
return;
|
||||
}
|
||||
|
||||
if (inst.hex == 0x4e800020) {
|
||||
ibuild.EmitBranchUncond(ibuild.EmitLoadLink());
|
||||
return;
|
||||
}
|
||||
IREmitter::InstLoc test = TestBranch(ibuild, inst);
|
||||
test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0));
|
||||
ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
|
||||
IREmitter::InstLoc destination = ibuild.EmitLoadLink();
|
||||
destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4));
|
||||
if (inst.LK)
|
||||
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
ibuild.EmitBranchUncond(destination);
|
||||
}
|
||||
void JitArmIL::bcx(UGeckoInstruction inst)
|
||||
{
|
||||
NORMALBRANCH_START
|
||||
if (inst.LK)
|
||||
@ -140,7 +138,7 @@ void JitIL::bcx(UGeckoInstruction inst)
|
||||
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
}
|
||||
|
||||
void JitIL::bcctrx(UGeckoInstruction inst)
|
||||
void JitArmIL::bcctrx(UGeckoInstruction inst)
|
||||
{
|
||||
NORMALBRANCH_START
|
||||
if ((inst.BO & 4) == 0) {
|
||||
@ -169,28 +167,3 @@ void JitIL::bcctrx(UGeckoInstruction inst)
|
||||
ibuild.EmitBranchUncond(destination);
|
||||
}
|
||||
|
||||
void JitIL::bclrx(UGeckoInstruction inst)
|
||||
{
|
||||
NORMALBRANCH_START
|
||||
|
||||
if (!js.isLastInstruction &&
|
||||
(inst.BO & (1 << 4)) && (inst.BO & (1 << 2))) {
|
||||
if (inst.LK)
|
||||
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
return;
|
||||
}
|
||||
|
||||
if (inst.hex == 0x4e800020) {
|
||||
ibuild.EmitBranchUncond(ibuild.EmitLoadLink());
|
||||
return;
|
||||
}
|
||||
IREmitter::InstLoc test = TestBranch(ibuild, inst);
|
||||
test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0));
|
||||
ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
|
||||
IREmitter::InstLoc destination = ibuild.EmitLoadLink();
|
||||
destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4));
|
||||
if (inst.LK)
|
||||
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
ibuild.EmitBranchUncond(destination);
|
||||
}
|
489
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL_Tables.cpp
Normal file
489
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL_Tables.cpp
Normal file
@ -0,0 +1,489 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "JitIL.h"
|
||||
#include "../JitInterface.h"
|
||||
#include "JitIL_Tables.h"
|
||||
|
||||
// Should be moved in to the Jit class
|
||||
typedef void (JitArmIL::*_Instruction) (UGeckoInstruction instCode);
|
||||
|
||||
static _Instruction dynaOpTable[64];
|
||||
static _Instruction dynaOpTable4[1024];
|
||||
static _Instruction dynaOpTable19[1024];
|
||||
static _Instruction dynaOpTable31[1024];
|
||||
static _Instruction dynaOpTable59[32];
|
||||
static _Instruction dynaOpTable63[1024];
|
||||
|
||||
void JitArmIL::DynaRunTable4(UGeckoInstruction _inst) {(this->*dynaOpTable4 [_inst.SUBOP10])(_inst);}
|
||||
void JitArmIL::DynaRunTable19(UGeckoInstruction _inst) {(this->*dynaOpTable19[_inst.SUBOP10])(_inst);}
|
||||
void JitArmIL::DynaRunTable31(UGeckoInstruction _inst) {(this->*dynaOpTable31[_inst.SUBOP10])(_inst);}
|
||||
void JitArmIL::DynaRunTable59(UGeckoInstruction _inst) {(this->*dynaOpTable59[_inst.SUBOP5 ])(_inst);}
|
||||
void JitArmIL::DynaRunTable63(UGeckoInstruction _inst) {(this->*dynaOpTable63[_inst.SUBOP10])(_inst);}
|
||||
|
||||
struct GekkoOPTemplate
|
||||
{
|
||||
int opcode;
|
||||
_Instruction Inst;
|
||||
//GekkoOPInfo opinfo; // Doesn't need opinfo, Interpreter fills it out
|
||||
};
|
||||
|
||||
static GekkoOPTemplate primarytable[] =
|
||||
{
|
||||
{4, &JitArmIL::DynaRunTable4}, //"RunTable4", OPTYPE_SUBTABLE | (4<<24), 0}},
|
||||
{19, &JitArmIL::DynaRunTable19}, //"RunTable19", OPTYPE_SUBTABLE | (19<<24), 0}},
|
||||
{31, &JitArmIL::DynaRunTable31}, //"RunTable31", OPTYPE_SUBTABLE | (31<<24), 0}},
|
||||
{59, &JitArmIL::DynaRunTable59}, //"RunTable59", OPTYPE_SUBTABLE | (59<<24), 0}},
|
||||
{63, &JitArmIL::DynaRunTable63}, //"RunTable63", OPTYPE_SUBTABLE | (63<<24), 0}},
|
||||
|
||||
{16, &JitArmIL::bcx}, //"bcx", OPTYPE_SYSTEM, FL_ENDBLOCK}},
|
||||
{18, &JitArmIL::bx}, //"bx", OPTYPE_SYSTEM, FL_ENDBLOCK}},
|
||||
|
||||
{1, &JitArmIL::HLEFunction}, //"HLEFunction", OPTYPE_SYSTEM, FL_ENDBLOCK}},
|
||||
{2, &JitArmIL::Default}, //"DynaBlock", OPTYPE_SYSTEM, 0}},
|
||||
{3, &JitArmIL::Break}, //"twi", OPTYPE_SYSTEM, FL_ENDBLOCK}},
|
||||
{17, &JitArmIL::sc}, //"sc", OPTYPE_SYSTEM, FL_ENDBLOCK, 1}},
|
||||
|
||||
{7, &JitArmIL::Default}, //"mulli", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_RC_BIT, 2}},
|
||||
{8, &JitArmIL::Default}, //"subfic", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CA}},
|
||||
{10, &JitArmIL::cmpXX}, //"cmpli", OPTYPE_INTEGER, FL_IN_A | FL_SET_CRn}},
|
||||
{11, &JitArmIL::cmpXX}, //"cmpi", OPTYPE_INTEGER, FL_IN_A | FL_SET_CRn}},
|
||||
{12, &JitArmIL::Default}, //"addic", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CA}},
|
||||
{13, &JitArmIL::Default}, //"addic_rc", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CR0}},
|
||||
{14, &JitArmIL::reg_imm}, //"addi", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}},
|
||||
{15, &JitArmIL::reg_imm}, //"addis", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}},
|
||||
|
||||
{20, &JitArmIL::Default}, //"rlwimix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_A | FL_IN_S | FL_RC_BIT}},
|
||||
{21, &JitArmIL::Default}, //"rlwinmx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}},
|
||||
{23, &JitArmIL::Default}, //"rlwnmx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_IN_B | FL_RC_BIT}},
|
||||
|
||||
{24, &JitArmIL::reg_imm}, //"ori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}},
|
||||
{25, &JitArmIL::reg_imm}, //"oris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}},
|
||||
{26, &JitArmIL::reg_imm}, //"xori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}},
|
||||
{27, &JitArmIL::reg_imm}, //"xoris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}},
|
||||
{28, &JitArmIL::reg_imm}, //"andi_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}},
|
||||
{29, &JitArmIL::reg_imm}, //"andis_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}},
|
||||
|
||||
{32, &JitArmIL::Default}, //"lwz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
|
||||
{33, &JitArmIL::Default}, //"lwzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
|
||||
{34, &JitArmIL::Default}, //"lbz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
|
||||
{35, &JitArmIL::Default}, //"lbzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
|
||||
{40, &JitArmIL::Default}, //"lhz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
|
||||
{41, &JitArmIL::Default}, //"lhzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
|
||||
{42, &JitArmIL::Default}, //"lha", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
|
||||
{43, &JitArmIL::Default}, //"lhau", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
|
||||
|
||||
{44, &JitArmIL::Default}, //"sth", OPTYPE_STORE, FL_IN_A | FL_IN_S}},
|
||||
{45, &JitArmIL::Default}, //"sthu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}},
|
||||
{36, &JitArmIL::Default}, //"stw", OPTYPE_STORE, FL_IN_A | FL_IN_S}},
|
||||
{37, &JitArmIL::Default}, //"stwu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}},
|
||||
{38, &JitArmIL::Default}, //"stb", OPTYPE_STORE, FL_IN_A | FL_IN_S}},
|
||||
{39, &JitArmIL::Default}, //"stbu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}},
|
||||
|
||||
{46, &JitArmIL::Default}, //"lmw", OPTYPE_SYSTEM, FL_EVIL, 10}},
|
||||
{47, &JitArmIL::Default}, //"stmw", OPTYPE_SYSTEM, FL_EVIL, 10}},
|
||||
|
||||
{48, &JitArmIL::Default}, //"lfs", OPTYPE_LOADFP, FL_IN_A}},
|
||||
{49, &JitArmIL::Default}, //"lfsu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A}},
|
||||
{50, &JitArmIL::Default}, //"lfd", OPTYPE_LOADFP, FL_IN_A}},
|
||||
{51, &JitArmIL::Default}, //"lfdu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A}},
|
||||
|
||||
{52, &JitArmIL::Default}, //"stfs", OPTYPE_STOREFP, FL_IN_A}},
|
||||
{53, &JitArmIL::Default}, //"stfsu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A}},
|
||||
{54, &JitArmIL::Default}, //"stfd", OPTYPE_STOREFP, FL_IN_A}},
|
||||
{55, &JitArmIL::Default}, //"stfdu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A}},
|
||||
|
||||
{56, &JitArmIL::Default}, //"psq_l", OPTYPE_PS, FL_IN_A}},
|
||||
{57, &JitArmIL::Default}, //"psq_lu", OPTYPE_PS, FL_OUT_A | FL_IN_A}},
|
||||
{60, &JitArmIL::Default}, //"psq_st", OPTYPE_PS, FL_IN_A}},
|
||||
{61, &JitArmIL::Default}, //"psq_stu", OPTYPE_PS, FL_OUT_A | FL_IN_A}},
|
||||
|
||||
//missing: 0, 5, 6, 9, 22, 30, 62, 58
|
||||
{0, &JitArmIL::Default}, //"unknown_instruction", OPTYPE_UNKNOWN, 0}},
|
||||
{5, &JitArmIL::Default}, //"unknown_instruction", OPTYPE_UNKNOWN, 0}},
|
||||
{6, &JitArmIL::Default}, //"unknown_instruction", OPTYPE_UNKNOWN, 0}},
|
||||
{9, &JitArmIL::Default}, //"unknown_instruction", OPTYPE_UNKNOWN, 0}},
|
||||
{22, &JitArmIL::Default}, //"unknown_instruction", OPTYPE_UNKNOWN, 0}},
|
||||
{30, &JitArmIL::Default}, //"unknown_instruction", OPTYPE_UNKNOWN, 0}},
|
||||
{62, &JitArmIL::Default}, //"unknown_instruction", OPTYPE_UNKNOWN, 0}},
|
||||
{58, &JitArmIL::Default}, //"unknown_instruction", OPTYPE_UNKNOWN, 0}},
|
||||
};
|
||||
|
||||
static GekkoOPTemplate table4[] =
|
||||
{ //SUBOP10
|
||||
{0, &JitArmIL::Default}, //"ps_cmpu0", OPTYPE_PS, FL_SET_CRn}},
|
||||
{32, &JitArmIL::Default}, //"ps_cmpo0", OPTYPE_PS, FL_SET_CRn}},
|
||||
{40, &JitArmIL::Default}, //"ps_neg", OPTYPE_PS, FL_RC_BIT}},
|
||||
{136, &JitArmIL::Default}, //"ps_nabs", OPTYPE_PS, FL_RC_BIT}},
|
||||
{264, &JitArmIL::Default}, //"ps_abs", OPTYPE_PS, FL_RC_BIT}},
|
||||
{64, &JitArmIL::Default}, //"ps_cmpu1", OPTYPE_PS, FL_RC_BIT}},
|
||||
{72, &JitArmIL::Default}, //"ps_mr", OPTYPE_PS, FL_RC_BIT}},
|
||||
{96, &JitArmIL::Default}, //"ps_cmpo1", OPTYPE_PS, FL_RC_BIT}},
|
||||
{528, &JitArmIL::Default}, //"ps_merge00", OPTYPE_PS, FL_RC_BIT}},
|
||||
{560, &JitArmIL::Default}, //"ps_merge01", OPTYPE_PS, FL_RC_BIT}},
|
||||
{592, &JitArmIL::Default}, //"ps_merge10", OPTYPE_PS, FL_RC_BIT}},
|
||||
{624, &JitArmIL::Default}, //"ps_merge11", OPTYPE_PS, FL_RC_BIT}},
|
||||
|
||||
{1014, &JitArmIL::Default}, //"dcbz_l", OPTYPE_SYSTEM, 0}},
|
||||
};
|
||||
|
||||
static GekkoOPTemplate table4_2[] =
|
||||
{
|
||||
{10, &JitArmIL::Default}, //"ps_sum0", OPTYPE_PS, 0}},
|
||||
{11, &JitArmIL::Default}, //"ps_sum1", OPTYPE_PS, 0}},
|
||||
{12, &JitArmIL::Default}, //"ps_muls0", OPTYPE_PS, 0}},
|
||||
{13, &JitArmIL::Default}, //"ps_muls1", OPTYPE_PS, 0}},
|
||||
{14, &JitArmIL::Default}, //"ps_madds0", OPTYPE_PS, 0}},
|
||||
{15, &JitArmIL::Default}, //"ps_madds1", OPTYPE_PS, 0}},
|
||||
{18, &JitArmIL::Default}, //"ps_div", OPTYPE_PS, 0, 16}},
|
||||
{20, &JitArmIL::Default}, //"ps_sub", OPTYPE_PS, 0}},
|
||||
{21, &JitArmIL::Default}, //"ps_add", OPTYPE_PS, 0}},
|
||||
{23, &JitArmIL::Default}, //"ps_sel", OPTYPE_PS, 0}},
|
||||
{24, &JitArmIL::Default}, //"ps_res", OPTYPE_PS, 0}},
|
||||
{25, &JitArmIL::Default}, //"ps_mul", OPTYPE_PS, 0}},
|
||||
{26, &JitArmIL::Default}, //"ps_rsqrte", OPTYPE_PS, 0, 1}},
|
||||
{28, &JitArmIL::Default}, //"ps_msub", OPTYPE_PS, 0}},
|
||||
{29, &JitArmIL::Default}, //"ps_madd", OPTYPE_PS, 0}},
|
||||
{30, &JitArmIL::Default}, //"ps_nmsub", OPTYPE_PS, 0}},
|
||||
{31, &JitArmIL::Default}, //"ps_nmadd", OPTYPE_PS, 0}},
|
||||
};
|
||||
|
||||
|
||||
static GekkoOPTemplate table4_3[] =
|
||||
{
|
||||
{6, &JitArmIL::Default}, //"psq_lx", OPTYPE_PS, 0}},
|
||||
{7, &JitArmIL::Default}, //"psq_stx", OPTYPE_PS, 0}},
|
||||
{38, &JitArmIL::Default}, //"psq_lux", OPTYPE_PS, 0}},
|
||||
{39, &JitArmIL::Default}, //"psq_stux", OPTYPE_PS, 0}},
|
||||
};
|
||||
|
||||
static GekkoOPTemplate table19[] =
|
||||
{
|
||||
{528, &JitArmIL::bcctrx}, //"bcctrx", OPTYPE_BRANCH, FL_ENDBLOCK}},
|
||||
{16, &JitArmIL::bclrx}, //"bclrx", OPTYPE_BRANCH, FL_ENDBLOCK}},
|
||||
{257, &JitArmIL::crXX}, //"crand", OPTYPE_CR, FL_EVIL}},
|
||||
{129, &JitArmIL::crXX}, //"crandc", OPTYPE_CR, FL_EVIL}},
|
||||
{289, &JitArmIL::crXX}, //"creqv", OPTYPE_CR, FL_EVIL}},
|
||||
{225, &JitArmIL::crXX}, //"crnand", OPTYPE_CR, FL_EVIL}},
|
||||
{33, &JitArmIL::crXX}, //"crnor", OPTYPE_CR, FL_EVIL}},
|
||||
{449, &JitArmIL::crXX}, //"cror", OPTYPE_CR, FL_EVIL}},
|
||||
{417, &JitArmIL::crXX}, //"crorc", OPTYPE_CR, FL_EVIL}},
|
||||
{193, &JitArmIL::crXX}, //"crxor", OPTYPE_CR, FL_EVIL}},
|
||||
|
||||
{150, &JitArmIL::Default}, //"isync", OPTYPE_ICACHE, FL_EVIL}},
|
||||
{0, &JitArmIL::Default}, //"mcrf", OPTYPE_SYSTEM, FL_EVIL}},
|
||||
|
||||
{50, &JitArmIL::rfi}, //"rfi", OPTYPE_SYSTEM, FL_ENDBLOCK | FL_CHECKEXCEPTIONS, 1}},
|
||||
{18, &JitArmIL::Break}, //"rfid", OPTYPE_SYSTEM, FL_ENDBLOCK | FL_CHECKEXCEPTIONS}}
|
||||
};
|
||||
|
||||
|
||||
static GekkoOPTemplate table31[] =
|
||||
{
|
||||
{28, &JitArmIL::boolX}, //"andx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||
{60, &JitArmIL::boolX}, //"andcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||
{444, &JitArmIL::boolX}, //"orx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||
{124, &JitArmIL::boolX}, //"norx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||
{316, &JitArmIL::boolX}, //"xorx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||
{412, &JitArmIL::boolX}, //"orcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||
{476, &JitArmIL::boolX}, //"nandx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||
{284, &JitArmIL::boolX}, //"eqvx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||
{0, &JitArmIL::cmpXX}, //"cmp", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}},
|
||||
{32, &JitArmIL::cmpXX}, //"cmpl", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}},
|
||||
{26, &JitArmIL::Default}, //"cntlzwx",OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}},
|
||||
{922, &JitArmIL::Default}, //"extshx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}},
|
||||
{954, &JitArmIL::Default}, //"extsbx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}},
|
||||
{536, &JitArmIL::Default}, //"srwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
|
||||
{792, &JitArmIL::Default}, //"srawx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
|
||||
{824, &JitArmIL::Default}, //"srawix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
|
||||
{24, &JitArmIL::Default}, //"slwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
|
||||
|
||||
{54, &JitArmIL::Default}, //"dcbst", OPTYPE_DCACHE, 0, 4}},
|
||||
{86, &JitArmIL::Default}, //"dcbf", OPTYPE_DCACHE, 0, 4}},
|
||||
{246, &JitArmIL::Default}, //"dcbtst", OPTYPE_DCACHE, 0, 1}},
|
||||
{278, &JitArmIL::Default}, //"dcbt", OPTYPE_DCACHE, 0, 1}},
|
||||
{470, &JitArmIL::Default}, //"dcbi", OPTYPE_DCACHE, 0, 4}},
|
||||
{758, &JitArmIL::Default}, //"dcba", OPTYPE_DCACHE, 0, 4}},
|
||||
{1014, &JitArmIL::Default}, //"dcbz", OPTYPE_DCACHE, 0, 4}},
|
||||
|
||||
//load word
|
||||
{23, &JitArmIL::Default}, //"lwzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
|
||||
{55, &JitArmIL::Default}, //"lwzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
|
||||
|
||||
//load halfword
|
||||
{279, &JitArmIL::Default}, //"lhzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
|
||||
{311, &JitArmIL::Default}, //"lhzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
|
||||
|
||||
//load halfword signextend
|
||||
{343, &JitArmIL::Default}, //"lhax", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
|
||||
{375, &JitArmIL::Default}, //"lhaux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
|
||||
|
||||
//load byte
|
||||
{87, &JitArmIL::Default}, //"lbzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
|
||||
{119, &JitArmIL::Default}, //"lbzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
|
||||
|
||||
//load byte reverse
|
||||
{534, &JitArmIL::Default}, //"lwbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
|
||||
{790, &JitArmIL::Default}, //"lhbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
|
||||
|
||||
// Conditional load/store (Wii SMP)
|
||||
{150, &JitArmIL::Default}, //"stwcxd", OPTYPE_STORE, FL_EVIL | FL_SET_CR0}},
|
||||
{20, &JitArmIL::Default}, //"lwarx", OPTYPE_LOAD, FL_EVIL | FL_OUT_D | FL_IN_A0B | FL_SET_CR0}},
|
||||
|
||||
//load string (interpret these)
|
||||
{533, &JitArmIL::Default}, //"lswx", OPTYPE_LOAD, FL_EVIL | FL_IN_A | FL_OUT_D}},
|
||||
{597, &JitArmIL::Default}, //"lswi", OPTYPE_LOAD, FL_EVIL | FL_IN_AB | FL_OUT_D}},
|
||||
|
||||
//store word
|
||||
{151, &JitArmIL::Default}, //"stwx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}},
|
||||
{183, &JitArmIL::Default}, //"stwux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}},
|
||||
|
||||
//store halfword
|
||||
{407, &JitArmIL::Default}, //"sthx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}},
|
||||
{439, &JitArmIL::Default}, //"sthux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}},
|
||||
|
||||
//store byte
|
||||
{215, &JitArmIL::Default}, //"stbx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}},
|
||||
{247, &JitArmIL::Default}, //"stbux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}},
|
||||
|
||||
//store bytereverse
|
||||
{662, &JitArmIL::Default}, //"stwbrx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}},
|
||||
{918, &JitArmIL::Default}, //"sthbrx", OPTYPE_STORE, FL_IN_A | FL_IN_B}},
|
||||
|
||||
{661, &JitArmIL::Default}, //"stswx", OPTYPE_STORE, FL_EVIL}},
|
||||
{725, &JitArmIL::Default}, //"stswi", OPTYPE_STORE, FL_EVIL}},
|
||||
|
||||
// fp load/store
|
||||
{535, &JitArmIL::Default}, //"lfsx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B}},
|
||||
{567, &JitArmIL::Default}, //"lfsux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B}},
|
||||
{599, &JitArmIL::Default}, //"lfdx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B}},
|
||||
{631, &JitArmIL::Default}, //"lfdux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B}},
|
||||
|
||||
{663, &JitArmIL::Default}, //"stfsx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}},
|
||||
{695, &JitArmIL::Default}, //"stfsux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B}},
|
||||
{727, &JitArmIL::Default}, //"stfdx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}},
|
||||
{759, &JitArmIL::Default}, //"stfdux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B}},
|
||||
{983, &JitArmIL::Default}, //"stfiwx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}},
|
||||
|
||||
{19, &JitArmIL::Default}, //"mfcr", OPTYPE_SYSTEM, FL_OUT_D}},
|
||||
{83, &JitArmIL::Default}, //"mfmsr", OPTYPE_SYSTEM, FL_OUT_D}},
|
||||
{144, &JitArmIL::Default}, //"mtcrf", OPTYPE_SYSTEM, 0}},
|
||||
{146, &JitArmIL::mtmsr}, //"mtmsr", OPTYPE_SYSTEM, FL_ENDBLOCK}},
|
||||
{210, &JitArmIL::Default}, //"mtsr", OPTYPE_SYSTEM, 0}},
|
||||
{242, &JitArmIL::Default}, //"mtsrin", OPTYPE_SYSTEM, 0}},
|
||||
{339, &JitArmIL::Default}, //"mfspr", OPTYPE_SPR, FL_OUT_D}},
|
||||
{467, &JitArmIL::Default}, //"mtspr", OPTYPE_SPR, 0, 2}},
|
||||
{371, &JitArmIL::Default}, //"mftb", OPTYPE_SYSTEM, FL_OUT_D | FL_TIMER}},
|
||||
{512, &JitArmIL::Default}, //"mcrxr", OPTYPE_SYSTEM, 0}},
|
||||
{595, &JitArmIL::Default}, //"mfsr", OPTYPE_SYSTEM, FL_OUT_D, 2}},
|
||||
{659, &JitArmIL::Default}, //"mfsrin", OPTYPE_SYSTEM, FL_OUT_D, 2}},
|
||||
|
||||
{4, &JitArmIL::Break}, //"tw", OPTYPE_SYSTEM, FL_ENDBLOCK, 1}},
|
||||
{598, &JitArmIL::Default}, //"sync", OPTYPE_SYSTEM, 0, 2}},
|
||||
{982, &JitArmIL::icbi}, //"icbi", OPTYPE_SYSTEM, FL_ENDBLOCK, 3}},
|
||||
|
||||
// Unused instructions on GC
|
||||
{310, &JitArmIL::Default}, //"eciwx", OPTYPE_INTEGER, FL_RC_BIT}},
|
||||
{438, &JitArmIL::Default}, //"ecowx", OPTYPE_INTEGER, FL_RC_BIT}},
|
||||
{854, &JitArmIL::Default}, //"eieio", OPTYPE_INTEGER, FL_RC_BIT}},
|
||||
{306, &JitArmIL::Default}, //"tlbie", OPTYPE_SYSTEM, 0}},
|
||||
{370, &JitArmIL::Default}, //"tlbia", OPTYPE_SYSTEM, 0}},
|
||||
{566, &JitArmIL::Default}, //"tlbsync", OPTYPE_SYSTEM, 0}},
|
||||
};
|
||||
|
||||
static GekkoOPTemplate table31_2[] =
|
||||
{
|
||||
{266, &JitArmIL::Default}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{778, &JitArmIL::Default}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{10, &JitArmIL::Default}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
|
||||
{138, &JitArmIL::Default}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{234, &JitArmIL::Default}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{202, &JitArmIL::Default}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{491, &JitArmIL::Default}, //"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
|
||||
{1003, &JitArmIL::Default}, //"divwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
|
||||
{459, &JitArmIL::Default}, //"divwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
|
||||
{971, &JitArmIL::Default}, //"divwuox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
|
||||
{75, &JitArmIL::Default}, //"mulhwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
|
||||
{11, &JitArmIL::Default}, //"mulhwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
|
||||
{235, &JitArmIL::Default}, //"mullwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
|
||||
{747, &JitArmIL::Default}, //"mullwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
|
||||
{104, &JitArmIL::Default}, //"negx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{40, &JitArmIL::Default}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{552, &JitArmIL::Default}, //"subox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{8, &JitArmIL::Default}, //"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
|
||||
{136, &JitArmIL::Default}, //"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{232, &JitArmIL::Default}, //"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{200, &JitArmIL::Default}, //"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
};
|
||||
|
||||
static GekkoOPTemplate table59[] =
|
||||
{
|
||||
{18, &JitArmIL::Default}, //{"fdivsx", OPTYPE_FPU, FL_RC_BIT_F, 16}},
|
||||
{20, &JitArmIL::Default}, //"fsubsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{21, &JitArmIL::Default}, //"faddsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
// {22, &JitArmIL::Default}, //"fsqrtsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{24, &JitArmIL::Default}, //"fresx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{25, &JitArmIL::Default}, //"fmulsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{28, &JitArmIL::Default}, //"fmsubsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{29, &JitArmIL::Default}, //"fmaddsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{30, &JitArmIL::Default}, //"fnmsubsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{31, &JitArmIL::Default}, //"fnmaddsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
};
|
||||
|
||||
static GekkoOPTemplate table63[] =
|
||||
{
|
||||
{264, &JitArmIL::Default}, //"fabsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{32, &JitArmIL::Default}, //"fcmpo", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{0, &JitArmIL::Default}, //"fcmpu", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{14, &JitArmIL::Default}, //"fctiwx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{15, &JitArmIL::Default}, //"fctiwzx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{72, &JitArmIL::Default}, //"fmrx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{136, &JitArmIL::Default}, //"fnabsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{40, &JitArmIL::Default}, //"fnegx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{12, &JitArmIL::Default}, //"frspx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
|
||||
{64, &JitArmIL::Default}, //"mcrfs", OPTYPE_SYSTEMFP, 0}},
|
||||
{583, &JitArmIL::Default}, //"mffsx", OPTYPE_SYSTEMFP, 0}},
|
||||
{70, &JitArmIL::Default}, //"mtfsb0x", OPTYPE_SYSTEMFP, 0, 2}},
|
||||
{38, &JitArmIL::Default}, //"mtfsb1x", OPTYPE_SYSTEMFP, 0, 2}},
|
||||
{134, &JitArmIL::Default}, //"mtfsfix", OPTYPE_SYSTEMFP, 0, 2}},
|
||||
{711, &JitArmIL::Default}, //"mtfsfx", OPTYPE_SYSTEMFP, 0, 2}},
|
||||
};
|
||||
|
||||
static GekkoOPTemplate table63_2[] =
|
||||
{
|
||||
{18, &JitArmIL::Default}, //"fdivx", OPTYPE_FPU, FL_RC_BIT_F, 30}},
|
||||
{20, &JitArmIL::Default}, //"fsubx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{21, &JitArmIL::Default}, //"faddx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{22, &JitArmIL::Default}, //"fsqrtx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{23, &JitArmIL::Default}, //"fselx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{25, &JitArmIL::Default}, //"fmulx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{26, &JitArmIL::Default}, //"frsqrtex", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{28, &JitArmIL::Default}, //"fmsubx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{29, &JitArmIL::Default}, //"fmaddx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{30, &JitArmIL::Default}, //"fnmsubx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{31, &JitArmIL::Default}, //"fnmaddx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
};
|
||||
|
||||
|
||||
namespace JitArmILTables
|
||||
{
|
||||
|
||||
void CompileInstruction(PPCAnalyst::CodeOp & op)
|
||||
{
|
||||
JitArmIL *jitarm = (JitArmIL *)jit;
|
||||
(jitarm->*dynaOpTable[op.inst.OPCD])(op.inst);
|
||||
GekkoOPInfo *info = op.opinfo;
|
||||
if (info) {
|
||||
#ifdef OPLOG
|
||||
if (!strcmp(info->opname, OP_TO_LOG)){ ///"mcrfs"
|
||||
rsplocations.push_back(jit.js.compilerPC);
|
||||
}
|
||||
#endif
|
||||
info->compileCount++;
|
||||
info->lastUse = jit->js.compilerPC;
|
||||
}
|
||||
}
|
||||
|
||||
void InitTables()
|
||||
{
|
||||
// once initialized, tables are read-only
|
||||
static bool initialized = false;
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
//clear
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
dynaOpTable59[i] = &JitArmIL::unknown_instruction;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1024; i++)
|
||||
{
|
||||
dynaOpTable4 [i] = &JitArmIL::unknown_instruction;
|
||||
dynaOpTable19[i] = &JitArmIL::unknown_instruction;
|
||||
dynaOpTable31[i] = &JitArmIL::unknown_instruction;
|
||||
dynaOpTable63[i] = &JitArmIL::unknown_instruction;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)(sizeof(primarytable) / sizeof(GekkoOPTemplate)); i++)
|
||||
{
|
||||
dynaOpTable[primarytable[i].opcode] = primarytable[i].Inst;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
int fill = i << 5;
|
||||
for (int j = 0; j < (int)(sizeof(table4_2) / sizeof(GekkoOPTemplate)); j++)
|
||||
{
|
||||
int op = fill+table4_2[j].opcode;
|
||||
dynaOpTable4[op] = table4_2[j].Inst;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
int fill = i << 6;
|
||||
for (int j = 0; j < (int)(sizeof(table4_3) / sizeof(GekkoOPTemplate)); j++)
|
||||
{
|
||||
int op = fill+table4_3[j].opcode;
|
||||
dynaOpTable4[op] = table4_3[j].Inst;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)(sizeof(table4) / sizeof(GekkoOPTemplate)); i++)
|
||||
{
|
||||
int op = table4[i].opcode;
|
||||
dynaOpTable4[op] = table4[i].Inst;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)(sizeof(table31) / sizeof(GekkoOPTemplate)); i++)
|
||||
{
|
||||
int op = table31[i].opcode;
|
||||
dynaOpTable31[op] = table31[i].Inst;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1; i++)
|
||||
{
|
||||
int fill = i << 9;
|
||||
for (int j = 0; j < (int)(sizeof(table31_2) / sizeof(GekkoOPTemplate)); j++)
|
||||
{
|
||||
int op = fill + table31_2[j].opcode;
|
||||
dynaOpTable31[op] = table31_2[j].Inst;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)(sizeof(table19) / sizeof(GekkoOPTemplate)); i++)
|
||||
{
|
||||
int op = table19[i].opcode;
|
||||
dynaOpTable19[op] = table19[i].Inst;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)(sizeof(table59) / sizeof(GekkoOPTemplate)); i++)
|
||||
{
|
||||
int op = table59[i].opcode;
|
||||
dynaOpTable59[op] = table59[i].Inst;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)(sizeof(table63) / sizeof(GekkoOPTemplate)); i++)
|
||||
{
|
||||
int op = table63[i].opcode;
|
||||
dynaOpTable63[op] = table63[i].Inst;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
int fill = i << 5;
|
||||
for (int j = 0; j < (int)(sizeof(table63_2) / sizeof(GekkoOPTemplate)); j++)
|
||||
{
|
||||
int op = fill + table63_2[j].opcode;
|
||||
dynaOpTable63[op] = table63_2[j].Inst;
|
||||
}
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
|
||||
}
|
||||
|
||||
} // namespace
|
16
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL_Tables.h
Normal file
16
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL_Tables.h
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef JITARMIL_TABLES_H
|
||||
#define JITARMIL_TABLES_H
|
||||
|
||||
#include "../Gekko.h"
|
||||
#include "../PPCTables.h"
|
||||
|
||||
namespace JitArmILTables
|
||||
{
|
||||
void CompileInstruction(PPCAnalyst::CodeOp & op);
|
||||
void InitTables();
|
||||
}
|
||||
#endif
|
@ -107,6 +107,19 @@
|
||||
#define CTX_R15 gregs[REG_R15]
|
||||
#define CTX_RIP gregs[REG_RIP]
|
||||
#elif defined(_M_IX86)
|
||||
#ifdef ANDROID
|
||||
#include <asm/sigcontext.h>
|
||||
typedef sigcontext SContext;
|
||||
#define CTX_EAX eax
|
||||
#define CTX_EBX ebx
|
||||
#define CTX_ECX ecx
|
||||
#define CTX_EDX edx
|
||||
#define CTX_EDI edi
|
||||
#define CTX_ESI esi
|
||||
#define CTX_EBP ebp
|
||||
#define CTX_ESP esp
|
||||
#define CTX_EIP eip
|
||||
#else
|
||||
#include <ucontext.h>
|
||||
typedef mcontext_t SContext;
|
||||
#define CTX_EAX gregs[REG_EAX]
|
||||
@ -118,6 +131,7 @@
|
||||
#define CTX_EBP gregs[REG_EBP]
|
||||
#define CTX_ESP gregs[REG_ESP]
|
||||
#define CTX_EIP gregs[REG_EIP]
|
||||
#endif
|
||||
#elif defined(_M_ARM)
|
||||
// Add others if required.
|
||||
typedef struct sigcontext SContext;
|
||||
|
@ -124,8 +124,6 @@ Fix profiled loads/stores to work safely. On 32-bit, one solution is to
|
||||
#include "../PPCTables.h"
|
||||
#include "../../CoreTiming.h"
|
||||
#include "../../HW/Memmap.h"
|
||||
#include "JitILAsm.h"
|
||||
#include "JitIL.h"
|
||||
#include "../../HW/GPFifo.h"
|
||||
#include "../../Core.h"
|
||||
using namespace Gen;
|
146
Source/Core/Core/Src/PowerPC/JitILCommon/JitILBase.h
Normal file
146
Source/Core/Core/Src/PowerPC/JitILCommon/JitILBase.h
Normal file
@ -0,0 +1,146 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _JITILBASE_H
|
||||
#define _JITILBASE_H
|
||||
|
||||
#include "../PPCAnalyst.h"
|
||||
#include "IR.h"
|
||||
#include "../JitCommon/JitBase.h"
|
||||
|
||||
#define INSTRUCTION_START
|
||||
|
||||
#define JITDISABLE(setting) \
|
||||
if (Core::g_CoreStartupParameter.bJITOff || \
|
||||
Core::g_CoreStartupParameter.setting) \
|
||||
{Default(inst); return;}
|
||||
|
||||
class JitILBase : public JitBase
|
||||
{
|
||||
protected:
|
||||
// The default code buffer. We keep it around to not have to alloc/dealloc a
|
||||
// large chunk of memory for each recompiled block.
|
||||
PPCAnalyst::CodeBuffer code_buffer;
|
||||
public:
|
||||
JitILBase() : code_buffer(32000) {}
|
||||
~JitILBase() {}
|
||||
|
||||
IREmitter::IRBuilder ibuild;
|
||||
|
||||
virtual JitBaseBlockCache *GetBlockCache() = 0;
|
||||
|
||||
virtual void Jit(u32 em_address) = 0;
|
||||
|
||||
virtual const u8 *BackPatch(u8 *codePtr, u32 em_address, void *ctx) = 0;
|
||||
|
||||
virtual const CommonAsmRoutinesBase *GetAsmRoutines() = 0;
|
||||
|
||||
virtual bool IsInCodeSpace(u8 *ptr) = 0;
|
||||
|
||||
// OPCODES
|
||||
virtual void unknown_instruction(UGeckoInstruction inst) = 0;
|
||||
virtual void Default(UGeckoInstruction inst) = 0;
|
||||
virtual void DoNothing(UGeckoInstruction inst) = 0;
|
||||
virtual void HLEFunction(UGeckoInstruction inst) = 0;
|
||||
|
||||
virtual void DynaRunTable4(UGeckoInstruction _inst) = 0;
|
||||
virtual void DynaRunTable19(UGeckoInstruction _inst) = 0;
|
||||
virtual void DynaRunTable31(UGeckoInstruction _inst) = 0;
|
||||
virtual void DynaRunTable59(UGeckoInstruction _inst) = 0;
|
||||
virtual void DynaRunTable63(UGeckoInstruction _inst) = 0;
|
||||
|
||||
// Branches
|
||||
void sc(UGeckoInstruction inst);
|
||||
void rfi(UGeckoInstruction inst);
|
||||
void bx(UGeckoInstruction inst);
|
||||
void bcx(UGeckoInstruction inst);
|
||||
void bcctrx(UGeckoInstruction inst);
|
||||
void bclrx(UGeckoInstruction inst);
|
||||
|
||||
// LoadStore
|
||||
void lXzx(UGeckoInstruction inst);
|
||||
void lhax(UGeckoInstruction inst);
|
||||
void stXx(UGeckoInstruction inst);
|
||||
void lmw(UGeckoInstruction inst);
|
||||
void stmw(UGeckoInstruction inst);
|
||||
void stX(UGeckoInstruction inst); //stw sth stb
|
||||
void lXz(UGeckoInstruction inst);
|
||||
void lbzu(UGeckoInstruction inst);
|
||||
void lha(UGeckoInstruction inst);
|
||||
|
||||
// System Registers
|
||||
void mtspr(UGeckoInstruction inst);
|
||||
void mfspr(UGeckoInstruction inst);
|
||||
void mtmsr(UGeckoInstruction inst);
|
||||
void mfmsr(UGeckoInstruction inst);
|
||||
void mftb(UGeckoInstruction inst);
|
||||
void mtcrf(UGeckoInstruction inst);
|
||||
void mfcr(UGeckoInstruction inst);
|
||||
void mcrf(UGeckoInstruction inst);
|
||||
void crXX(UGeckoInstruction inst);
|
||||
|
||||
void dcbst(UGeckoInstruction inst);
|
||||
void dcbz(UGeckoInstruction inst);
|
||||
void icbi(UGeckoInstruction inst);
|
||||
|
||||
void addx(UGeckoInstruction inst);
|
||||
void boolX(UGeckoInstruction inst);
|
||||
void mulli(UGeckoInstruction inst);
|
||||
void mulhwux(UGeckoInstruction inst);
|
||||
void mullwx(UGeckoInstruction inst);
|
||||
void divwux(UGeckoInstruction inst);
|
||||
void srawix(UGeckoInstruction inst);
|
||||
void srawx(UGeckoInstruction inst);
|
||||
void addex(UGeckoInstruction inst);
|
||||
void addzex(UGeckoInstruction inst);
|
||||
|
||||
void extsbx(UGeckoInstruction inst);
|
||||
void extshx(UGeckoInstruction inst);
|
||||
|
||||
void reg_imm(UGeckoInstruction inst);
|
||||
|
||||
void ps_sel(UGeckoInstruction inst);
|
||||
void ps_mr(UGeckoInstruction inst);
|
||||
void ps_sign(UGeckoInstruction inst); //aggregate
|
||||
void ps_arith(UGeckoInstruction inst); //aggregate
|
||||
void ps_mergeXX(UGeckoInstruction inst);
|
||||
void ps_maddXX(UGeckoInstruction inst);
|
||||
void ps_rsqrte(UGeckoInstruction inst);
|
||||
void ps_sum(UGeckoInstruction inst);
|
||||
void ps_muls(UGeckoInstruction inst);
|
||||
|
||||
void fp_arith_s(UGeckoInstruction inst);
|
||||
|
||||
void fcmpx(UGeckoInstruction inst);
|
||||
void fmrx(UGeckoInstruction inst);
|
||||
|
||||
void cmpXX(UGeckoInstruction inst);
|
||||
|
||||
void cntlzwx(UGeckoInstruction inst);
|
||||
|
||||
void lfs(UGeckoInstruction inst);
|
||||
void lfd(UGeckoInstruction inst);
|
||||
void stfd(UGeckoInstruction inst);
|
||||
void stfs(UGeckoInstruction inst);
|
||||
void stfsx(UGeckoInstruction inst);
|
||||
void psq_l(UGeckoInstruction inst);
|
||||
void psq_st(UGeckoInstruction inst);
|
||||
|
||||
void fmaddXX(UGeckoInstruction inst);
|
||||
void fsign(UGeckoInstruction inst);
|
||||
void rlwinmx(UGeckoInstruction inst);
|
||||
void rlwimix(UGeckoInstruction inst);
|
||||
void rlwnmx(UGeckoInstruction inst);
|
||||
void negx(UGeckoInstruction inst);
|
||||
void slwx(UGeckoInstruction inst);
|
||||
void srwx(UGeckoInstruction inst);
|
||||
void lfsx(UGeckoInstruction inst);
|
||||
|
||||
void subfic(UGeckoInstruction inst);
|
||||
void subfcx(UGeckoInstruction inst);
|
||||
void subfx(UGeckoInstruction inst);
|
||||
void subfex(UGeckoInstruction inst);
|
||||
|
||||
};
|
||||
#endif
|
191
Source/Core/Core/Src/PowerPC/JitILCommon/JitILBase_Branch.cpp
Normal file
191
Source/Core/Core/Src/PowerPC/JitILCommon/JitILBase_Branch.cpp
Normal file
@ -0,0 +1,191 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "../../ConfigManager.h"
|
||||
#include "../PowerPC.h"
|
||||
#include "../../CoreTiming.h"
|
||||
#include "../PPCTables.h"
|
||||
#include "JitILBase.h"
|
||||
|
||||
#include "../../HW/Memmap.h"
|
||||
|
||||
// The branches are known good, or at least reasonably good.
|
||||
// No need for a disable-mechanism.
|
||||
|
||||
// If defined, clears CR0 at blr and bl-s. If the assumption that
|
||||
// flags never carry over between functions holds, then the task for
|
||||
// an optimizer becomes much easier.
|
||||
|
||||
// #define ACID_TEST
|
||||
|
||||
// Zelda and many more games seem to pass the Acid Test.
|
||||
|
||||
//#define NORMALBRANCH_START Default(inst); ibuild.EmitInterpreterBranch(); return;
|
||||
#define NORMALBRANCH_START
|
||||
|
||||
void JitILBase::sc(UGeckoInstruction inst)
|
||||
{
|
||||
ibuild.EmitSystemCall(ibuild.EmitIntConst(js.compilerPC));
|
||||
}
|
||||
|
||||
void JitILBase::rfi(UGeckoInstruction inst)
|
||||
{
|
||||
ibuild.EmitRFIExit();
|
||||
}
|
||||
|
||||
void JitILBase::bx(UGeckoInstruction inst)
|
||||
{
|
||||
NORMALBRANCH_START
|
||||
INSTRUCTION_START;
|
||||
|
||||
// We must always process the following sentence
|
||||
// even if the blocks are merged by PPCAnalyst::Flatten().
|
||||
if (inst.LK)
|
||||
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
|
||||
// If this is not the last instruction of a block,
|
||||
// we will skip the rest process.
|
||||
// Because PPCAnalyst::Flatten() merged the blocks.
|
||||
if (!js.isLastInstruction) {
|
||||
return;
|
||||
}
|
||||
|
||||
u32 destination;
|
||||
if (inst.AA)
|
||||
destination = SignExt26(inst.LI << 2);
|
||||
else
|
||||
destination = js.compilerPC + SignExt26(inst.LI << 2);
|
||||
|
||||
if (destination == js.compilerPC) {
|
||||
ibuild.EmitShortIdleLoop(ibuild.EmitIntConst(js.compilerPC));
|
||||
return;
|
||||
}
|
||||
|
||||
ibuild.EmitBranchUncond(ibuild.EmitIntConst(destination));
|
||||
}
|
||||
|
||||
static IREmitter::InstLoc TestBranch(IREmitter::IRBuilder& ibuild, UGeckoInstruction inst) {
|
||||
IREmitter::InstLoc CRTest = 0, CTRTest = 0;
|
||||
if ((inst.BO & 16) == 0) // Test a CR bit
|
||||
{
|
||||
IREmitter::InstLoc CRReg = ibuild.EmitLoadCR(inst.BI >> 2);
|
||||
IREmitter::InstLoc CRCmp = ibuild.EmitIntConst(8 >> (inst.BI & 3));
|
||||
CRTest = ibuild.EmitAnd(CRReg, CRCmp);
|
||||
if (!(inst.BO & 8))
|
||||
CRTest = ibuild.EmitXor(CRCmp, CRTest);
|
||||
}
|
||||
|
||||
if ((inst.BO & 4) == 0) {
|
||||
IREmitter::InstLoc c = ibuild.EmitLoadCTR();
|
||||
c = ibuild.EmitSub(c, ibuild.EmitIntConst(1));
|
||||
ibuild.EmitStoreCTR(c);
|
||||
if (inst.BO & 2) {
|
||||
CTRTest = ibuild.EmitICmpEq(c,
|
||||
ibuild.EmitIntConst(0));
|
||||
} else {
|
||||
CTRTest = c;
|
||||
}
|
||||
}
|
||||
|
||||
IREmitter::InstLoc Test = CRTest;
|
||||
if (CTRTest) {
|
||||
if (Test)
|
||||
Test = ibuild.EmitAnd(Test, CTRTest);
|
||||
else
|
||||
Test = CTRTest;
|
||||
}
|
||||
|
||||
if (!Test) {
|
||||
Test = ibuild.EmitIntConst(1);
|
||||
}
|
||||
return Test;
|
||||
}
|
||||
|
||||
void JitILBase::bcx(UGeckoInstruction inst)
|
||||
{
|
||||
NORMALBRANCH_START
|
||||
if (inst.LK)
|
||||
ibuild.EmitStoreLink(
|
||||
ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
|
||||
IREmitter::InstLoc Test = TestBranch(ibuild, inst);
|
||||
|
||||
u32 destination;
|
||||
if(inst.AA)
|
||||
destination = SignExt16(inst.BD << 2);
|
||||
else
|
||||
destination = js.compilerPC + SignExt16(inst.BD << 2);
|
||||
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle &&
|
||||
inst.hex == 0x4182fff8 &&
|
||||
(Memory::ReadUnchecked_U32(js.compilerPC - 8) & 0xFFFF0000) == 0x800D0000 &&
|
||||
(Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x28000000 ||
|
||||
(SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x2C000000))
|
||||
)
|
||||
{
|
||||
ibuild.EmitIdleBranch(Test, ibuild.EmitIntConst(destination));
|
||||
}
|
||||
else
|
||||
{
|
||||
ibuild.EmitBranchCond(Test, ibuild.EmitIntConst(destination));
|
||||
}
|
||||
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
}
|
||||
|
||||
void JitILBase::bcctrx(UGeckoInstruction inst)
|
||||
{
|
||||
NORMALBRANCH_START
|
||||
if ((inst.BO & 4) == 0) {
|
||||
IREmitter::InstLoc c = ibuild.EmitLoadCTR();
|
||||
c = ibuild.EmitSub(c, ibuild.EmitIntConst(1));
|
||||
ibuild.EmitStoreCTR(c);
|
||||
}
|
||||
IREmitter::InstLoc test;
|
||||
if ((inst.BO & 16) == 0) // Test a CR bit
|
||||
{
|
||||
IREmitter::InstLoc CRReg = ibuild.EmitLoadCR(inst.BI >> 2);
|
||||
IREmitter::InstLoc CRCmp = ibuild.EmitIntConst(8 >> (inst.BI & 3));
|
||||
test = ibuild.EmitAnd(CRReg, CRCmp);
|
||||
if (!(inst.BO & 8))
|
||||
test = ibuild.EmitXor(test, CRCmp);
|
||||
} else {
|
||||
test = ibuild.EmitIntConst(1);
|
||||
}
|
||||
test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0));
|
||||
ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
|
||||
IREmitter::InstLoc destination = ibuild.EmitLoadCTR();
|
||||
destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4));
|
||||
if (inst.LK)
|
||||
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
ibuild.EmitBranchUncond(destination);
|
||||
}
|
||||
|
||||
void JitILBase::bclrx(UGeckoInstruction inst)
|
||||
{
|
||||
NORMALBRANCH_START
|
||||
|
||||
if (!js.isLastInstruction &&
|
||||
(inst.BO & (1 << 4)) && (inst.BO & (1 << 2))) {
|
||||
if (inst.LK)
|
||||
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
return;
|
||||
}
|
||||
|
||||
if (inst.hex == 0x4e800020) {
|
||||
ibuild.EmitBranchUncond(ibuild.EmitLoadLink());
|
||||
return;
|
||||
}
|
||||
IREmitter::InstLoc test = TestBranch(ibuild, inst);
|
||||
test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0));
|
||||
ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
|
||||
IREmitter::InstLoc destination = ibuild.EmitLoadLink();
|
||||
destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4));
|
||||
if (inst.LK)
|
||||
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
ibuild.EmitBranchUncond(destination);
|
||||
}
|
@ -7,14 +7,10 @@
|
||||
#include "../../Core.h"
|
||||
#include "../PowerPC.h"
|
||||
#include "../PPCTables.h"
|
||||
#include "x64Emitter.h"
|
||||
|
||||
#include "JitIL.h"
|
||||
#include "JitILBase.h"
|
||||
|
||||
//#define INSTRUCTION_START Default(inst); return;
|
||||
#define INSTRUCTION_START
|
||||
|
||||
void JitIL::fp_arith_s(UGeckoInstruction inst)
|
||||
void JitILBase::fp_arith_s(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITFloatingPointOff)
|
||||
@ -57,7 +53,7 @@ void JitIL::fp_arith_s(UGeckoInstruction inst)
|
||||
ibuild.EmitStoreFReg(val, inst.FD);
|
||||
}
|
||||
|
||||
void JitIL::fmaddXX(UGeckoInstruction inst)
|
||||
void JitILBase::fmaddXX(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITFloatingPointOff)
|
||||
@ -85,7 +81,7 @@ void JitIL::fmaddXX(UGeckoInstruction inst)
|
||||
ibuild.EmitStoreFReg(val, inst.FD);
|
||||
}
|
||||
|
||||
void JitIL::fmrx(UGeckoInstruction inst)
|
||||
void JitILBase::fmrx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITFloatingPointOff)
|
||||
@ -97,7 +93,7 @@ void JitIL::fmrx(UGeckoInstruction inst)
|
||||
ibuild.EmitStoreFReg(val, inst.FD);
|
||||
}
|
||||
|
||||
void JitIL::fcmpx(UGeckoInstruction inst)
|
||||
void JitILBase::fcmpx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITFloatingPointOff)
|
||||
@ -110,7 +106,7 @@ void JitIL::fcmpx(UGeckoInstruction inst)
|
||||
ibuild.EmitStoreCR(res, inst.CRFD);
|
||||
}
|
||||
|
||||
void JitIL::fsign(UGeckoInstruction inst)
|
||||
void JitILBase::fsign(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITFloatingPointOff)
|
@ -9,13 +9,8 @@
|
||||
#include "../../Core.h" // include "Common.h", "CoreParameter.h", SCoreStartupParameter
|
||||
#include "../PowerPC.h"
|
||||
#include "../PPCTables.h"
|
||||
#include "x64Emitter.h"
|
||||
|
||||
#include "JitIL.h"
|
||||
#include "JitILAsm.h"
|
||||
|
||||
//#define INSTRUCTION_START Default(inst); return;
|
||||
#define INSTRUCTION_START
|
||||
#include "JitILBase.h"
|
||||
|
||||
static void ComputeRC(IREmitter::IRBuilder& ibuild,
|
||||
IREmitter::InstLoc val) {
|
||||
@ -24,7 +19,7 @@ static void ComputeRC(IREmitter::IRBuilder& ibuild,
|
||||
ibuild.EmitStoreCR(res, 0);
|
||||
}
|
||||
|
||||
void JitIL::reg_imm(UGeckoInstruction inst)
|
||||
void JitILBase::reg_imm(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -92,7 +87,7 @@ void JitIL::reg_imm(UGeckoInstruction inst)
|
||||
}
|
||||
}
|
||||
|
||||
void JitIL::cmpXX(UGeckoInstruction inst)
|
||||
void JitILBase::cmpXX(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -117,7 +112,7 @@ void JitIL::cmpXX(UGeckoInstruction inst)
|
||||
ibuild.EmitStoreCR(res, inst.CRFD);
|
||||
}
|
||||
|
||||
void JitIL::boolX(UGeckoInstruction inst)
|
||||
void JitILBase::boolX(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -170,7 +165,7 @@ void JitIL::boolX(UGeckoInstruction inst)
|
||||
ComputeRC(ibuild, a);
|
||||
}
|
||||
|
||||
void JitIL::extsbx(UGeckoInstruction inst)
|
||||
void JitILBase::extsbx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -181,7 +176,7 @@ void JitIL::extsbx(UGeckoInstruction inst)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitIL::extshx(UGeckoInstruction inst)
|
||||
void JitILBase::extshx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -192,7 +187,7 @@ void JitIL::extshx(UGeckoInstruction inst)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitIL::subfic(UGeckoInstruction inst)
|
||||
void JitILBase::subfic(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -211,7 +206,7 @@ void JitIL::subfic(UGeckoInstruction inst)
|
||||
ibuild.EmitStoreCarry(test);
|
||||
}
|
||||
|
||||
void JitIL::subfcx(UGeckoInstruction inst)
|
||||
void JitILBase::subfcx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -228,7 +223,7 @@ void JitIL::subfcx(UGeckoInstruction inst)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitIL::subfex(UGeckoInstruction inst)
|
||||
void JitILBase::subfex(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -249,7 +244,7 @@ void JitIL::subfex(UGeckoInstruction inst)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitIL::subfx(UGeckoInstruction inst)
|
||||
void JitILBase::subfx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -261,7 +256,7 @@ void JitIL::subfx(UGeckoInstruction inst)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitIL::mulli(UGeckoInstruction inst)
|
||||
void JitILBase::mulli(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -270,7 +265,7 @@ void JitIL::mulli(UGeckoInstruction inst)
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
}
|
||||
|
||||
void JitIL::mullwx(UGeckoInstruction inst)
|
||||
void JitILBase::mullwx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -281,7 +276,7 @@ void JitIL::mullwx(UGeckoInstruction inst)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitIL::mulhwux(UGeckoInstruction inst)
|
||||
void JitILBase::mulhwux(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -295,7 +290,7 @@ void JitIL::mulhwux(UGeckoInstruction inst)
|
||||
}
|
||||
|
||||
// skipped some of the special handling in here - if we get crashes, let the interpreter handle this op
|
||||
void JitIL::divwux(UGeckoInstruction inst) {
|
||||
void JitILBase::divwux(UGeckoInstruction inst) {
|
||||
Default(inst); return;
|
||||
#if 0
|
||||
int a = inst.RA, b = inst.RB, d = inst.RD;
|
||||
@ -319,7 +314,7 @@ void JitIL::divwux(UGeckoInstruction inst) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void JitIL::addx(UGeckoInstruction inst)
|
||||
void JitILBase::addx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -330,7 +325,7 @@ void JitIL::addx(UGeckoInstruction inst)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitIL::addzex(UGeckoInstruction inst)
|
||||
void JitILBase::addzex(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -344,7 +339,7 @@ void JitIL::addzex(UGeckoInstruction inst)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitIL::addex(UGeckoInstruction inst)
|
||||
void JitILBase::addex(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -367,7 +362,7 @@ void JitIL::addex(UGeckoInstruction inst)
|
||||
ComputeRC(ibuild, abc);
|
||||
}
|
||||
|
||||
void JitIL::rlwinmx(UGeckoInstruction inst)
|
||||
void JitILBase::rlwinmx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -381,7 +376,7 @@ void JitIL::rlwinmx(UGeckoInstruction inst)
|
||||
}
|
||||
|
||||
|
||||
void JitIL::rlwimix(UGeckoInstruction inst)
|
||||
void JitILBase::rlwimix(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -397,7 +392,7 @@ void JitIL::rlwimix(UGeckoInstruction inst)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitIL::rlwnmx(UGeckoInstruction inst)
|
||||
void JitILBase::rlwnmx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -410,7 +405,7 @@ void JitIL::rlwnmx(UGeckoInstruction inst)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitIL::negx(UGeckoInstruction inst)
|
||||
void JitILBase::negx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -421,7 +416,7 @@ void JitIL::negx(UGeckoInstruction inst)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitIL::srwx(UGeckoInstruction inst)
|
||||
void JitILBase::srwx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -440,7 +435,7 @@ void JitIL::srwx(UGeckoInstruction inst)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitIL::slwx(UGeckoInstruction inst)
|
||||
void JitILBase::slwx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -459,7 +454,7 @@ void JitIL::slwx(UGeckoInstruction inst)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitIL::srawx(UGeckoInstruction inst)
|
||||
void JitILBase::srawx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -485,7 +480,7 @@ void JitIL::srawx(UGeckoInstruction inst)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitIL::srawix(UGeckoInstruction inst)
|
||||
void JitILBase::srawix(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
||||
@ -502,7 +497,7 @@ void JitIL::srawix(UGeckoInstruction inst)
|
||||
}
|
||||
|
||||
// count leading zeroes
|
||||
void JitIL::cntlzwx(UGeckoInstruction inst)
|
||||
void JitILBase::cntlzwx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff)
|
@ -2,9 +2,6 @@
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// TODO(ector): Tons of pshufb optimization of the loads/stores, for SSSE3+, possibly SSE4, only.
|
||||
// Should give a very noticable speed boost to paired single heavy code.
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "../PowerPC.h"
|
||||
@ -12,16 +9,10 @@
|
||||
#include "../../HW/GPFifo.h"
|
||||
#include "../../HW/Memmap.h"
|
||||
#include "../PPCTables.h"
|
||||
#include "x64Emitter.h"
|
||||
#include "x64ABI.h"
|
||||
|
||||
#include "JitIL.h"
|
||||
#include "JitILAsm.h"
|
||||
#include "JitILBase.h"
|
||||
|
||||
//#define INSTRUCTION_START Default(inst); return;
|
||||
#define INSTRUCTION_START
|
||||
|
||||
void JitIL::lhax(UGeckoInstruction inst)
|
||||
void JitILBase::lhax(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff)
|
||||
@ -34,7 +25,7 @@ void JitIL::lhax(UGeckoInstruction inst)
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
}
|
||||
|
||||
void JitIL::lXz(UGeckoInstruction inst)
|
||||
void JitILBase::lXz(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff)
|
||||
@ -55,7 +46,7 @@ void JitIL::lXz(UGeckoInstruction inst)
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
}
|
||||
|
||||
void JitIL::lbzu(UGeckoInstruction inst) {
|
||||
void JitILBase::lbzu(UGeckoInstruction inst) {
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff)
|
||||
const IREmitter::InstLoc uAddress = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), ibuild.EmitIntConst((int)inst.SIMM_16));
|
||||
@ -64,7 +55,7 @@ void JitIL::lbzu(UGeckoInstruction inst) {
|
||||
ibuild.EmitStoreGReg(uAddress, inst.RA);
|
||||
}
|
||||
|
||||
void JitIL::lha(UGeckoInstruction inst)
|
||||
void JitILBase::lha(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff)
|
||||
@ -78,7 +69,7 @@ void JitIL::lha(UGeckoInstruction inst)
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
}
|
||||
|
||||
void JitIL::lXzx(UGeckoInstruction inst)
|
||||
void JitILBase::lXzx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff)
|
||||
@ -100,7 +91,7 @@ void JitIL::lXzx(UGeckoInstruction inst)
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
}
|
||||
|
||||
void JitIL::dcbst(UGeckoInstruction inst)
|
||||
void JitILBase::dcbst(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff)
|
||||
@ -116,7 +107,7 @@ void JitIL::dcbst(UGeckoInstruction inst)
|
||||
}
|
||||
|
||||
// Zero cache line.
|
||||
void JitIL::dcbz(UGeckoInstruction inst)
|
||||
void JitILBase::dcbz(UGeckoInstruction inst)
|
||||
{
|
||||
Default(inst); return;
|
||||
|
||||
@ -141,7 +132,7 @@ void JitIL::dcbz(UGeckoInstruction inst)
|
||||
#endif
|
||||
}
|
||||
|
||||
void JitIL::stX(UGeckoInstruction inst)
|
||||
void JitILBase::stX(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff)
|
||||
@ -161,7 +152,7 @@ void JitIL::stX(UGeckoInstruction inst)
|
||||
}
|
||||
}
|
||||
|
||||
void JitIL::stXx(UGeckoInstruction inst)
|
||||
void JitILBase::stXx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff)
|
||||
@ -181,7 +172,7 @@ void JitIL::stXx(UGeckoInstruction inst)
|
||||
}
|
||||
|
||||
// A few games use these heavily in video codecs. (GFZP01 @ 0x80020E18)
|
||||
void JitIL::lmw(UGeckoInstruction inst)
|
||||
void JitILBase::lmw(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff)
|
||||
@ -197,7 +188,7 @@ void JitIL::lmw(UGeckoInstruction inst)
|
||||
}
|
||||
}
|
||||
|
||||
void JitIL::stmw(UGeckoInstruction inst)
|
||||
void JitILBase::stmw(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff)
|
||||
@ -213,7 +204,7 @@ void JitIL::stmw(UGeckoInstruction inst)
|
||||
}
|
||||
}
|
||||
|
||||
void JitIL::icbi(UGeckoInstruction inst)
|
||||
void JitILBase::icbi(UGeckoInstruction inst)
|
||||
{
|
||||
Default(inst);
|
||||
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
|
@ -2,9 +2,6 @@
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// TODO(ector): Tons of pshufb optimization of the loads/stores, for SSSE3+, possibly SSE4, only.
|
||||
// Should give a very noticable speed boost to paired single heavy code.
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "../PowerPC.h"
|
||||
@ -12,21 +9,14 @@
|
||||
#include "../../HW/GPFifo.h"
|
||||
#include "../../HW/Memmap.h"
|
||||
#include "../PPCTables.h"
|
||||
#include "CPUDetect.h"
|
||||
#include "x64Emitter.h"
|
||||
#include "x64ABI.h"
|
||||
|
||||
#include "JitIL.h"
|
||||
#include "JitILAsm.h"
|
||||
|
||||
//#define INSTRUCTION_START Default(inst); return;
|
||||
#define INSTRUCTION_START
|
||||
#include "JitILBase.h"
|
||||
|
||||
// TODO: Add peephole optimizations for multiple consecutive lfd/lfs/stfd/stfs since they are so common,
|
||||
// and pshufb could help a lot.
|
||||
// Also add hacks for things like lfs/stfs the same reg consecutively, that is, simple memory moves.
|
||||
|
||||
void JitIL::lfs(UGeckoInstruction inst)
|
||||
void JitILBase::lfs(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreFloatingOff)
|
||||
@ -40,7 +30,7 @@ void JitIL::lfs(UGeckoInstruction inst)
|
||||
}
|
||||
|
||||
|
||||
void JitIL::lfd(UGeckoInstruction inst)
|
||||
void JitILBase::lfd(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreFloatingOff)
|
||||
@ -55,7 +45,7 @@ void JitIL::lfd(UGeckoInstruction inst)
|
||||
}
|
||||
|
||||
|
||||
void JitIL::stfd(UGeckoInstruction inst)
|
||||
void JitILBase::stfd(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreFloatingOff)
|
||||
@ -71,7 +61,7 @@ void JitIL::stfd(UGeckoInstruction inst)
|
||||
}
|
||||
|
||||
|
||||
void JitIL::stfs(UGeckoInstruction inst)
|
||||
void JitILBase::stfs(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreFloatingOff)
|
||||
@ -88,7 +78,7 @@ void JitIL::stfs(UGeckoInstruction inst)
|
||||
}
|
||||
|
||||
|
||||
void JitIL::stfsx(UGeckoInstruction inst)
|
||||
void JitILBase::stfsx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreFloatingOff)
|
||||
@ -103,7 +93,7 @@ void JitIL::stfsx(UGeckoInstruction inst)
|
||||
}
|
||||
|
||||
|
||||
void JitIL::lfsx(UGeckoInstruction inst)
|
||||
void JitILBase::lfsx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreFloatingOff)
|
@ -9,17 +9,10 @@
|
||||
#include "../../HW/GPFifo.h"
|
||||
#include "../../HW/Memmap.h"
|
||||
#include "../PPCTables.h"
|
||||
#include "CPUDetect.h"
|
||||
#include "x64Emitter.h"
|
||||
#include "x64ABI.h"
|
||||
|
||||
#include "JitIL.h"
|
||||
#include "JitILAsm.h"
|
||||
#include "JitILBase.h"
|
||||
|
||||
//#define INSTRUCTION_START Default(inst); return;
|
||||
#define INSTRUCTION_START
|
||||
|
||||
void JitIL::psq_st(UGeckoInstruction inst)
|
||||
void JitILBase::psq_st(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStorePairedOff)
|
||||
@ -35,7 +28,7 @@ void JitIL::psq_st(UGeckoInstruction inst)
|
||||
ibuild.EmitStorePaired(val, addr, inst.I);
|
||||
}
|
||||
|
||||
void JitIL::psq_l(UGeckoInstruction inst)
|
||||
void JitILBase::psq_l(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStorePairedOff)
|
@ -7,32 +7,31 @@
|
||||
#include "../../Core.h"
|
||||
#include "../PowerPC.h"
|
||||
#include "../PPCTables.h"
|
||||
#include "x64Emitter.h"
|
||||
#include "../../HW/GPFifo.h"
|
||||
|
||||
#include "JitIL.h"
|
||||
#include "JitILBase.h"
|
||||
|
||||
void JitIL::ps_mr(UGeckoInstruction inst)
|
||||
void JitILBase::ps_mr(UGeckoInstruction inst)
|
||||
{
|
||||
Default(inst); return;
|
||||
}
|
||||
|
||||
void JitIL::ps_sel(UGeckoInstruction inst)
|
||||
void JitILBase::ps_sel(UGeckoInstruction inst)
|
||||
{
|
||||
Default(inst); return;
|
||||
}
|
||||
|
||||
void JitIL::ps_sign(UGeckoInstruction inst)
|
||||
void JitILBase::ps_sign(UGeckoInstruction inst)
|
||||
{
|
||||
Default(inst); return;
|
||||
}
|
||||
|
||||
void JitIL::ps_rsqrte(UGeckoInstruction inst)
|
||||
void JitILBase::ps_rsqrte(UGeckoInstruction inst)
|
||||
{
|
||||
Default(inst); return;
|
||||
}
|
||||
|
||||
void JitIL::ps_arith(UGeckoInstruction inst)
|
||||
void JitILBase::ps_arith(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITPairedOff)
|
||||
@ -61,7 +60,7 @@ void JitIL::ps_arith(UGeckoInstruction inst)
|
||||
ibuild.EmitStoreFReg(val, inst.FD);
|
||||
}
|
||||
|
||||
void JitIL::ps_sum(UGeckoInstruction inst)
|
||||
void JitILBase::ps_sum(UGeckoInstruction inst)
|
||||
{
|
||||
// TODO: This operation strikes me as a bit strange...
|
||||
// perhaps we can optimize it depending on the users?
|
||||
@ -84,7 +83,7 @@ void JitIL::ps_sum(UGeckoInstruction inst)
|
||||
}
|
||||
|
||||
|
||||
void JitIL::ps_muls(UGeckoInstruction inst)
|
||||
void JitILBase::ps_muls(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITPairedOff)
|
||||
@ -109,7 +108,7 @@ void JitIL::ps_muls(UGeckoInstruction inst)
|
||||
|
||||
|
||||
//TODO: find easy cases and optimize them, do a breakout like ps_arith
|
||||
void JitIL::ps_mergeXX(UGeckoInstruction inst)
|
||||
void JitILBase::ps_mergeXX(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITPairedOff)
|
||||
@ -142,7 +141,7 @@ void JitIL::ps_mergeXX(UGeckoInstruction inst)
|
||||
}
|
||||
|
||||
|
||||
void JitIL::ps_maddXX(UGeckoInstruction inst)
|
||||
void JitILBase::ps_maddXX(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITPairedOff)
|
@ -9,15 +9,10 @@
|
||||
#include "../../HW/SystemTimers.h"
|
||||
#include "../PowerPC.h"
|
||||
#include "../PPCTables.h"
|
||||
#include "x64Emitter.h"
|
||||
#include "x64ABI.h"
|
||||
|
||||
#include "JitIL.h"
|
||||
#include "JitILBase.h"
|
||||
|
||||
//#define INSTRUCTION_START Default(inst); return;
|
||||
#define INSTRUCTION_START
|
||||
|
||||
void JitIL::mtspr(UGeckoInstruction inst)
|
||||
void JitILBase::mtspr(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITSystemRegistersOff)
|
||||
@ -53,7 +48,7 @@ void JitIL::mtspr(UGeckoInstruction inst)
|
||||
}
|
||||
}
|
||||
|
||||
void JitIL::mfspr(UGeckoInstruction inst)
|
||||
void JitILBase::mfspr(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITSystemRegistersOff)
|
||||
@ -90,7 +85,7 @@ void JitIL::mfspr(UGeckoInstruction inst)
|
||||
// =======================================================================================
|
||||
// Don't interpret this, if we do we get thrown out
|
||||
// --------------
|
||||
void JitIL::mtmsr(UGeckoInstruction inst)
|
||||
void JitILBase::mtmsr(UGeckoInstruction inst)
|
||||
{
|
||||
ibuild.EmitStoreMSR(ibuild.EmitLoadGReg(inst.RS), ibuild.EmitIntConst(js.compilerPC));
|
||||
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
@ -98,21 +93,21 @@ void JitIL::mtmsr(UGeckoInstruction inst)
|
||||
// ==============
|
||||
|
||||
|
||||
void JitIL::mfmsr(UGeckoInstruction inst)
|
||||
void JitILBase::mfmsr(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITSystemRegistersOff)
|
||||
ibuild.EmitStoreGReg(ibuild.EmitLoadMSR(), inst.RD);
|
||||
}
|
||||
|
||||
void JitIL::mftb(UGeckoInstruction inst)
|
||||
void JitILBase::mftb(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START;
|
||||
JITDISABLE(bJITSystemRegistersOff)
|
||||
mfspr(inst);
|
||||
}
|
||||
|
||||
void JitIL::mfcr(UGeckoInstruction inst)
|
||||
void JitILBase::mfcr(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START;
|
||||
JITDISABLE(bJITSystemRegistersOff)
|
||||
@ -126,7 +121,7 @@ void JitIL::mfcr(UGeckoInstruction inst)
|
||||
ibuild.EmitStoreGReg(d, inst.RD);
|
||||
}
|
||||
|
||||
void JitIL::mtcrf(UGeckoInstruction inst)
|
||||
void JitILBase::mtcrf(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START;
|
||||
JITDISABLE(bJITSystemRegistersOff)
|
||||
@ -144,7 +139,7 @@ void JitIL::mtcrf(UGeckoInstruction inst)
|
||||
}
|
||||
}
|
||||
|
||||
void JitIL::mcrf(UGeckoInstruction inst)
|
||||
void JitILBase::mcrf(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITSystemRegistersOff)
|
||||
@ -155,7 +150,7 @@ void JitIL::mcrf(UGeckoInstruction inst)
|
||||
}
|
||||
}
|
||||
|
||||
void JitIL::crXX(UGeckoInstruction inst)
|
||||
void JitILBase::crXX(UGeckoInstruction inst)
|
||||
{
|
||||
// Ported from Jit_SystemRegister.cpp
|
||||
|
@ -21,6 +21,8 @@
|
||||
#ifdef _M_ARM
|
||||
#include "JitArm32/Jit.h"
|
||||
#include "JitArm32/JitArm_Tables.h"
|
||||
#include "JitArmIL/JitIL.h"
|
||||
#include "JitArmIL/JitIL_Tables.h"
|
||||
#endif
|
||||
|
||||
#include "Profiler.h"
|
||||
@ -64,6 +66,11 @@ namespace JitInterface
|
||||
ptr = new JitArm();
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
ptr = new JitArmIL();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
@ -99,6 +106,11 @@ namespace JitInterface
|
||||
JitArmTables::InitTables();
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
JitArmILTables::InitTables();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
|
@ -22,7 +22,7 @@
|
||||
namespace EMM
|
||||
{
|
||||
|
||||
#if defined __APPLE__ || defined __linux__ || defined __FreeBSD__
|
||||
#if (defined __APPLE__ || defined __linux__ || defined __FreeBSD__) && !defined(ANDROID)
|
||||
#include <execinfo.h>
|
||||
void print_trace(const char * msg)
|
||||
{
|
||||
|
@ -43,6 +43,7 @@ const CPUCore CPUCores[] = {
|
||||
{0, wxTRANSLATE("Interpreter (VERY slow)")},
|
||||
#ifdef _M_ARM
|
||||
{3, wxTRANSLATE("Arm JIT (experimental)")},
|
||||
{4, wxTRANSLATE("Arm JITIL (experimental)")},
|
||||
#else
|
||||
{1, wxTRANSLATE("JIT Recompiler (recommended)")},
|
||||
{2, wxTRANSLATE("JITIL experimental recompiler")},
|
||||
|
Loading…
x
Reference in New Issue
Block a user