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:
Ryan Houdek 2013-10-09 23:16:07 +00:00
commit 715d5ae8a7
32 changed files with 2387 additions and 314 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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)
{

View File

@ -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);

View File

@ -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)

View File

@ -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>

View File

@ -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"

View File

@ -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);

View 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);
}

View File

@ -0,0 +1 @@

View 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;
}

View 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

View 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();
}

View 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

View File

@ -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);
}

View 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

View 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

View File

@ -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;

View File

@ -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;

View 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

View 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);
}

View File

@ -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)

View File

@ -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)

View File

@ -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));

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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:
{

View File

@ -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)
{

View File

@ -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")},