mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-01 03:32:58 +00:00
[ARM] Beginning of JitArmIL JIT recompiler. This code is entirely based off of magumagu's work with the JIT64IL. This puts down the base needed for the recompiler. Starfield actually runs quite a few blocks being mysteriously dying while most other games just exit out due to an instruction not being done yet. A lot of this code can be tidied up and actually shared between the two IL recompilers but isn't yet done.
This commit is contained in:
parent
d6f0ecebb4
commit
a4eab75d15
@ -166,12 +166,13 @@ set(SRCS Src/ActionReplay.cpp
|
|||||||
Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp
|
Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp
|
||||||
Src/PowerPC/Interpreter/Interpreter_Tables.cpp
|
Src/PowerPC/Interpreter/Interpreter_Tables.cpp
|
||||||
Src/PowerPC/JitCommon/JitBase.cpp
|
Src/PowerPC/JitCommon/JitBase.cpp
|
||||||
Src/PowerPC/JitCommon/JitCache.cpp)
|
Src/PowerPC/JitCommon/JitCache.cpp
|
||||||
|
Src/PowerPC/JitILCommon/IR.cpp
|
||||||
|
)
|
||||||
|
|
||||||
if(NOT _M_GENERIC)
|
if(NOT _M_GENERIC)
|
||||||
set(SRCS ${SRCS}
|
set(SRCS ${SRCS}
|
||||||
Src/x64MemTools.cpp
|
Src/x64MemTools.cpp
|
||||||
Src/PowerPC/Jit64IL/IR.cpp
|
|
||||||
Src/PowerPC/Jit64IL/IR_X86.cpp
|
Src/PowerPC/Jit64IL/IR_X86.cpp
|
||||||
Src/PowerPC/Jit64IL/JitILAsm.cpp
|
Src/PowerPC/Jit64IL/JitILAsm.cpp
|
||||||
Src/PowerPC/Jit64IL/JitIL_Branch.cpp
|
Src/PowerPC/Jit64IL/JitIL_Branch.cpp
|
||||||
@ -217,7 +218,15 @@ if(_M_ARM)
|
|||||||
Src/PowerPC/JitArm32/JitArm_Paired.cpp
|
Src/PowerPC/JitArm32/JitArm_Paired.cpp
|
||||||
Src/PowerPC/JitArm32/JitArm_LoadStorePaired.cpp
|
Src/PowerPC/JitArm32/JitArm_LoadStorePaired.cpp
|
||||||
Src/PowerPC/JitArm32/JitArm_SystemRegisters.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/JitIL_SystemRegisters.cpp
|
||||||
|
Src/PowerPC/JitArmIL/IR_Arm.cpp
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(LIBS bdisasm inputcommon videosoftware sfml-network)
|
set(LIBS bdisasm inputcommon videosoftware sfml-network)
|
||||||
|
576
Source/Core/Core/Src/PowerPC/JitArmIL/IR_Arm.cpp
Normal file
576
Source/Core/Core/Src/PowerPC/JitArmIL/IR_Arm.cpp
Normal file
@ -0,0 +1,576 @@
|
|||||||
|
// 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 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) {
|
||||||
|
if (width != 32) {
|
||||||
|
PanicAlert("Not implemented!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isImm(*I)) {
|
||||||
|
RI.Jit->MOVI2R(R12, RI.Build->GetImmValue(I));
|
||||||
|
RI.Jit->STR(R12, R9, offset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ARMReg reg = regEnsureInReg(RI, I);
|
||||||
|
RI.Jit->STR(reg, R9, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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_AND(ARMReg reg, Operand2 op2)
|
||||||
|
{
|
||||||
|
AND(reg, reg, op2);
|
||||||
|
}
|
||||||
|
void JitArmIL::BIN_ADD(ARMReg reg, Operand2 op2)
|
||||||
|
{
|
||||||
|
ADD(reg, reg, op2);
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
if (RHS + 128 < 256) {
|
||||||
|
(RI.Jit->*op)(reg, RHS);
|
||||||
|
} else {
|
||||||
|
(RI.Jit->*op)(reg, RHS);
|
||||||
|
}
|
||||||
|
} 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 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)))) {
|
||||||
|
Jit->MOVI2R(R14, RI.Build->GetImmValue(getOp2(getOp1(I))));
|
||||||
|
Jit->CMP(regLocForInst(RI, getOp1(getOp1(I))), R14);
|
||||||
|
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 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 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 And: {
|
||||||
|
if (!thisUsed) break;
|
||||||
|
regEmitBinInst(RI, I, &JitArmIL::BIN_AND, 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;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
PanicAlert("Unknown JIT instruction; aborting!");
|
||||||
|
ibuild->WriteToFile(0);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < MAX_NUMBER_OF_REGS; i++) {
|
||||||
|
if (RI.regs[i]) {
|
||||||
|
// Start a game in Burnout 2 to get this. Or animal crossing.
|
||||||
|
PanicAlert("Incomplete cleanup! (regs)");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (RI.fregs[i]) {
|
||||||
|
PanicAlert("Incomplete cleanup! (fregs)");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Jit->WriteExit(jit->js.curBlock->exitAddress[0], 0);
|
||||||
|
Jit->BKPT(0x111);
|
||||||
|
|
||||||
|
}
|
||||||
|
void JitArmIL::WriteCode() {
|
||||||
|
DoWriteCode(&ibuild, this);
|
||||||
|
}
|
1
Source/Core/Core/Src/PowerPC/JitArmIL/IR_Arm.h
Normal file
1
Source/Core/Core/Src/PowerPC/JitArmIL/IR_Arm.h
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
334
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL.cpp
Normal file
334
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL.cpp
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
// 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::WriteExitDestInReg(ARMReg Reg)
|
||||||
|
{
|
||||||
|
STR(Reg, R9, PPCSTATE_OFF(pc));
|
||||||
|
MOVI2R(Reg, (u32)asm_routines.dispatcher);
|
||||||
|
B(Reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JitArmIL::WriteRfiExitDestInR(ARMReg Reg)
|
||||||
|
{
|
||||||
|
STR(Reg, R9, PPCSTATE_OFF(pc));
|
||||||
|
|
||||||
|
MOVI2R(Reg, (u32)asm_routines.testExceptions);
|
||||||
|
B(Reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JitArmIL::WriteExit(u32 destination, int exit_num)
|
||||||
|
{
|
||||||
|
//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)
|
||||||
|
{
|
||||||
|
printf("Doing a JIT in JITARMIL. Scream and shout.\n");
|
||||||
|
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, 1);
|
||||||
|
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;
|
||||||
|
|
||||||
|
{
|
||||||
|
}
|
||||||
|
printf("Done emitting block. size was 0x%08x\n", size);
|
||||||
|
FlushIcache();
|
||||||
|
return start;
|
||||||
|
|
||||||
|
}
|
104
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL.h
Normal file
104
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL.h
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// 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/IR.h"
|
||||||
|
#include "../JitCommon/JitBase.h"
|
||||||
|
#include "JitILAsm.h"
|
||||||
|
|
||||||
|
#define INSTRUCTION_START
|
||||||
|
|
||||||
|
#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 JitBase, public ArmGen::ARMXCodeBlock
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
JitArmBlockCache blocks;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
JitArmILAsmRoutineManager asm_routines;
|
||||||
|
|
||||||
|
void PrintDebug(UGeckoInstruction inst, u32 level);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Initialization, etc
|
||||||
|
JitArmIL() : code_buffer(32000) {}
|
||||||
|
~JitArmIL() {}
|
||||||
|
|
||||||
|
IREmitter::IRBuilder ibuild;
|
||||||
|
|
||||||
|
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) {}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// OPCODES
|
||||||
|
void unknown_instruction(UGeckoInstruction inst);
|
||||||
|
void Default(UGeckoInstruction inst);
|
||||||
|
void DoNothing(UGeckoInstruction inst);
|
||||||
|
void HLEFunction(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_ADD(ARMReg reg, Operand2 op2);
|
||||||
|
|
||||||
|
// Branches
|
||||||
|
void rfi(UGeckoInstruction inst);
|
||||||
|
void bx(UGeckoInstruction inst);
|
||||||
|
void bcx(UGeckoInstruction inst);
|
||||||
|
void bclrx(UGeckoInstruction inst);
|
||||||
|
// System Registers
|
||||||
|
void mtmsr(UGeckoInstruction inst);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
121
Source/Core/Core/Src/PowerPC/JitArmIL/JitILAsm.cpp
Normal file
121
Source/Core/Core/Src/PowerPC/JitArmIL/JitILAsm.cpp
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
// Copyright 2013 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
#include "../../HW/Memmap.h"
|
||||||
|
|
||||||
|
#include "../PowerPC.h"
|
||||||
|
#include "../../CoreTiming.h"
|
||||||
|
#include "MemoryUtil.h"
|
||||||
|
|
||||||
|
#include "JitIL.h"
|
||||||
|
#include "../JitCommon/JitCache.h"
|
||||||
|
|
||||||
|
#include "../../HW/GPFifo.h"
|
||||||
|
#include "../../Core.h"
|
||||||
|
|
||||||
|
#include "JitILAsm.h"
|
||||||
|
#include "ArmEmitter.h"
|
||||||
|
|
||||||
|
JitArmILAsmRoutineManager armil_asm_routines;
|
||||||
|
void JitArmILAsmRoutineManager::Generate()
|
||||||
|
{
|
||||||
|
enterCode = GetCodePtr();
|
||||||
|
PUSH(9, R4, R5, R6, R7, R8, R9, R10, R11, _LR);
|
||||||
|
// Take care to 8-byte align stack for function calls.
|
||||||
|
// We are misaligned here because of an odd number of args for PUSH.
|
||||||
|
// It's not like x86 where you need to account for an extra 4 bytes
|
||||||
|
// consumed by CALL.
|
||||||
|
SUB(_SP, _SP, 4);
|
||||||
|
|
||||||
|
MOVI2R(R0, (u32)&CoreTiming::downcount);
|
||||||
|
MOVI2R(R9, (u32)&PowerPC::ppcState.spr[0]);
|
||||||
|
|
||||||
|
FixupBranch skipToRealDispatcher = B();
|
||||||
|
dispatcher = GetCodePtr();
|
||||||
|
printf("ILDispatcher is %p\n", dispatcher);
|
||||||
|
|
||||||
|
// Downcount Check
|
||||||
|
// The result of slice decrementation should be in flags if somebody jumped here
|
||||||
|
// IMPORTANT - We jump on negative, not carry!!!
|
||||||
|
FixupBranch bail = B_CC(CC_MI);
|
||||||
|
|
||||||
|
SetJumpTarget(skipToRealDispatcher);
|
||||||
|
dispatcherNoCheck = GetCodePtr();
|
||||||
|
|
||||||
|
// This block of code gets the address of the compiled block of code
|
||||||
|
// It runs though to the compiling portion if it isn't found
|
||||||
|
LDR(R12, R9, PPCSTATE_OFF(pc));// Load the current PC into R12
|
||||||
|
|
||||||
|
Operand2 iCacheMask = Operand2(0xE, 2); // JIT_ICACHE_MASK
|
||||||
|
BIC(R12, R12, iCacheMask); // R12 contains PC & JIT_ICACHE_MASK here.
|
||||||
|
|
||||||
|
MOVI2R(R14, (u32)jit->GetBlockCache()->GetICache());
|
||||||
|
|
||||||
|
LDR(R12, R14, R12); // R12 contains iCache[PC & JIT_ICACHE_MASK] here
|
||||||
|
// R12 Confirmed this is the correct iCache Location loaded.
|
||||||
|
TST(R12, 0xFC); // Test to see if it is a JIT block.
|
||||||
|
|
||||||
|
SetCC(CC_EQ);
|
||||||
|
// Success, it is our Jitblock.
|
||||||
|
MOVI2R(R14, (u32)jit->GetBlockCache()->GetCodePointers());
|
||||||
|
// LDR R14 right here to get CodePointers()[0] pointer.
|
||||||
|
REV(R12, R12); // Reversing this gives us our JITblock.
|
||||||
|
LSL(R12, R12, 2); // Multiply by four because address locations are u32 in size
|
||||||
|
LDR(R14, R14, R12); // Load the block address in to R14
|
||||||
|
|
||||||
|
B(R14);
|
||||||
|
// No need to jump anywhere after here, the block will go back to dispatcher start
|
||||||
|
SetCC();
|
||||||
|
|
||||||
|
// If we get to this point, that means that we don't have the block cached to execute
|
||||||
|
// So call ArmJit to compile the block and then execute it.
|
||||||
|
MOVI2R(R14, (u32)&Jit);
|
||||||
|
BL(R14);
|
||||||
|
|
||||||
|
B(dispatcherNoCheck);
|
||||||
|
|
||||||
|
// fpException()
|
||||||
|
// Floating Point Exception Check, Jumped to if false
|
||||||
|
fpException = GetCodePtr();
|
||||||
|
LDR(R0, R9, PPCSTATE_OFF(Exceptions));
|
||||||
|
ORR(R0, R0, EXCEPTION_FPU_UNAVAILABLE);
|
||||||
|
STR(R0, R9, PPCSTATE_OFF(Exceptions));
|
||||||
|
QuickCallFunction(R14, (void*)&PowerPC::CheckExceptions);
|
||||||
|
LDR(R0, R9, PPCSTATE_OFF(npc));
|
||||||
|
STR(R0, R9, PPCSTATE_OFF(pc));
|
||||||
|
B(dispatcher);
|
||||||
|
|
||||||
|
SetJumpTarget(bail);
|
||||||
|
doTiming = GetCodePtr();
|
||||||
|
// XXX: In JIT64, Advance() gets called /after/ the exception checking
|
||||||
|
// once it jumps back to the start of outerLoop
|
||||||
|
QuickCallFunction(R14, (void*)&CoreTiming::Advance);
|
||||||
|
|
||||||
|
// Does exception checking
|
||||||
|
testExceptions = GetCodePtr();
|
||||||
|
LDR(R0, R9, PPCSTATE_OFF(pc));
|
||||||
|
STR(R0, R9, PPCSTATE_OFF(npc));
|
||||||
|
QuickCallFunction(R14, (void*)&PowerPC::CheckExceptions);
|
||||||
|
LDR(R0, R9, PPCSTATE_OFF(npc));
|
||||||
|
STR(R0, R9, PPCSTATE_OFF(pc));
|
||||||
|
// Check the state pointer to see if we are exiting
|
||||||
|
// Gets checked on every exception check
|
||||||
|
MOVI2R(R0, (u32)PowerPC::GetStatePtr());
|
||||||
|
MVN(R1, 0);
|
||||||
|
LDR(R0, R0);
|
||||||
|
TST(R0, R1);
|
||||||
|
FixupBranch Exit = B_CC(CC_NEQ);
|
||||||
|
|
||||||
|
B(dispatcher);
|
||||||
|
|
||||||
|
SetJumpTarget(Exit);
|
||||||
|
|
||||||
|
ADD(_SP, _SP, 4);
|
||||||
|
|
||||||
|
POP(9, R4, R5, R6, R7, R8, R9, R10, R11, _PC); // Returns
|
||||||
|
|
||||||
|
GenerateCommon();
|
||||||
|
|
||||||
|
FlushIcache();
|
||||||
|
}
|
||||||
|
|
32
Source/Core/Core/Src/PowerPC/JitArmIL/JitILAsm.h
Normal file
32
Source/Core/Core/Src/PowerPC/JitArmIL/JitILAsm.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2013 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#ifndef _JITARMILASM_H
|
||||||
|
#define _JITARMILASM_H
|
||||||
|
#include "ArmEmitter.h"
|
||||||
|
#include "../JitCommon/JitAsmCommon.h"
|
||||||
|
using namespace ArmGen;
|
||||||
|
class JitArmILAsmRoutineManager : public CommonAsmRoutinesBase, public ARMXCodeBlock
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
void Generate();
|
||||||
|
void GenerateCommon() {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
void Init() {
|
||||||
|
AllocCodeSpace(8192);
|
||||||
|
Generate();
|
||||||
|
WriteProtect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shutdown() {
|
||||||
|
FreeCodeSpace();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern JitArmILAsmRoutineManager armil_asm_routines;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
145
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL_Branch.cpp
Normal file
145
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL_Branch.cpp
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
// 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 "../PPCTables.h"
|
||||||
|
|
||||||
|
#include "JitIL.h"
|
||||||
|
|
||||||
|
#include "../../HW/Memmap.h"
|
||||||
|
|
||||||
|
//#define NORMALBRANCH_START Default(inst); ibuild.EmitInterpreterBranch(); return;
|
||||||
|
#define NORMALBRANCH_START
|
||||||
|
|
||||||
|
void JitArmIL::rfi(UGeckoInstruction inst)
|
||||||
|
{
|
||||||
|
ibuild.EmitRFIExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JitArmIL::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 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)
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2013 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
#include "../PowerPC.h"
|
||||||
|
#include "../PPCTables.h"
|
||||||
|
|
||||||
|
#include "JitIL.h"
|
||||||
|
|
||||||
|
#include "../../HW/Memmap.h"
|
||||||
|
|
||||||
|
// =======================================================================================
|
||||||
|
// Don't interpret this, if we do we get thrown out
|
||||||
|
// --------------
|
||||||
|
void JitArmIL::mtmsr(UGeckoInstruction inst)
|
||||||
|
{
|
||||||
|
ibuild.EmitStoreMSR(ibuild.EmitLoadGReg(inst.RS), ibuild.EmitIntConst(js.compilerPC));
|
||||||
|
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||||
|
}
|
489
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL_Tables.cpp
Normal file
489
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL_Tables.cpp
Normal file
@ -0,0 +1,489 @@
|
|||||||
|
// Copyright 2013 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "JitIL.h"
|
||||||
|
#include "../JitInterface.h"
|
||||||
|
#include "JitIL_Tables.h"
|
||||||
|
|
||||||
|
// Should be moved in to the Jit class
|
||||||
|
typedef void (JitArmIL::*_Instruction) (UGeckoInstruction instCode);
|
||||||
|
|
||||||
|
static _Instruction dynaOpTable[64];
|
||||||
|
static _Instruction dynaOpTable4[1024];
|
||||||
|
static _Instruction dynaOpTable19[1024];
|
||||||
|
static _Instruction dynaOpTable31[1024];
|
||||||
|
static _Instruction dynaOpTable59[32];
|
||||||
|
static _Instruction dynaOpTable63[1024];
|
||||||
|
|
||||||
|
void JitArmIL::DynaRunTable4(UGeckoInstruction _inst) {(this->*dynaOpTable4 [_inst.SUBOP10])(_inst);}
|
||||||
|
void JitArmIL::DynaRunTable19(UGeckoInstruction _inst) {(this->*dynaOpTable19[_inst.SUBOP10])(_inst);}
|
||||||
|
void JitArmIL::DynaRunTable31(UGeckoInstruction _inst) {(this->*dynaOpTable31[_inst.SUBOP10])(_inst);}
|
||||||
|
void JitArmIL::DynaRunTable59(UGeckoInstruction _inst) {(this->*dynaOpTable59[_inst.SUBOP5 ])(_inst);}
|
||||||
|
void JitArmIL::DynaRunTable63(UGeckoInstruction _inst) {(this->*dynaOpTable63[_inst.SUBOP10])(_inst);}
|
||||||
|
|
||||||
|
struct GekkoOPTemplate
|
||||||
|
{
|
||||||
|
int opcode;
|
||||||
|
_Instruction Inst;
|
||||||
|
//GekkoOPInfo opinfo; // Doesn't need opinfo, Interpreter fills it out
|
||||||
|
};
|
||||||
|
|
||||||
|
static GekkoOPTemplate primarytable[] =
|
||||||
|
{
|
||||||
|
{4, &JitArmIL::DynaRunTable4}, //"RunTable4", OPTYPE_SUBTABLE | (4<<24), 0}},
|
||||||
|
{19, &JitArmIL::DynaRunTable19}, //"RunTable19", OPTYPE_SUBTABLE | (19<<24), 0}},
|
||||||
|
{31, &JitArmIL::DynaRunTable31}, //"RunTable31", OPTYPE_SUBTABLE | (31<<24), 0}},
|
||||||
|
{59, &JitArmIL::DynaRunTable59}, //"RunTable59", OPTYPE_SUBTABLE | (59<<24), 0}},
|
||||||
|
{63, &JitArmIL::DynaRunTable63}, //"RunTable63", OPTYPE_SUBTABLE | (63<<24), 0}},
|
||||||
|
|
||||||
|
{16, &JitArmIL::bcx}, //"bcx", OPTYPE_SYSTEM, FL_ENDBLOCK}},
|
||||||
|
{18, &JitArmIL::bx}, //"bx", OPTYPE_SYSTEM, FL_ENDBLOCK}},
|
||||||
|
|
||||||
|
{1, &JitArmIL::Default}, //"HLEFunction", OPTYPE_SYSTEM, FL_ENDBLOCK}},
|
||||||
|
{2, &JitArmIL::Default}, //"DynaBlock", OPTYPE_SYSTEM, 0}},
|
||||||
|
{3, &JitArmIL::Default}, //"twi", OPTYPE_SYSTEM, FL_ENDBLOCK}},
|
||||||
|
{17, &JitArmIL::Default}, //"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::Default}, //"cmpli", OPTYPE_INTEGER, FL_IN_A | FL_SET_CRn}},
|
||||||
|
{11, &JitArmIL::Default}, //"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::Default}, //"addi", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}},
|
||||||
|
{15, &JitArmIL::Default}, //"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::Default}, //"ori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}},
|
||||||
|
{25, &JitArmIL::Default}, //"oris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}},
|
||||||
|
{26, &JitArmIL::Default}, //"xori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}},
|
||||||
|
{27, &JitArmIL::Default}, //"xoris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}},
|
||||||
|
{28, &JitArmIL::Default}, //"andi_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}},
|
||||||
|
{29, &JitArmIL::Default}, //"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::Default}, //"bcctrx", OPTYPE_BRANCH, FL_ENDBLOCK}},
|
||||||
|
{16, &JitArmIL::bclrx}, //"bclrx", OPTYPE_BRANCH, FL_ENDBLOCK}},
|
||||||
|
{257, &JitArmIL::Default}, //"crand", OPTYPE_CR, FL_EVIL}},
|
||||||
|
{129, &JitArmIL::Default}, //"crandc", OPTYPE_CR, FL_EVIL}},
|
||||||
|
{289, &JitArmIL::Default}, //"creqv", OPTYPE_CR, FL_EVIL}},
|
||||||
|
{225, &JitArmIL::Default}, //"crnand", OPTYPE_CR, FL_EVIL}},
|
||||||
|
{33, &JitArmIL::Default}, //"crnor", OPTYPE_CR, FL_EVIL}},
|
||||||
|
{449, &JitArmIL::Default}, //"cror", OPTYPE_CR, FL_EVIL}},
|
||||||
|
{417, &JitArmIL::Default}, //"crorc", OPTYPE_CR, FL_EVIL}},
|
||||||
|
{193, &JitArmIL::Default}, //"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::Default}, //"rfid", OPTYPE_SYSTEM, FL_ENDBLOCK | FL_CHECKEXCEPTIONS}}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static GekkoOPTemplate table31[] =
|
||||||
|
{
|
||||||
|
{28, &JitArmIL::Default}, //"andx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||||
|
{60, &JitArmIL::Default}, //"andcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||||
|
{444, &JitArmIL::Default}, //"orx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||||
|
{124, &JitArmIL::Default}, //"norx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||||
|
{316, &JitArmIL::Default}, //"xorx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||||
|
{412, &JitArmIL::Default}, //"orcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||||
|
{476, &JitArmIL::Default}, //"nandx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||||
|
{284, &JitArmIL::Default}, //"eqvx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||||
|
{0, &JitArmIL::Default}, //"cmp", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}},
|
||||||
|
{32, &JitArmIL::Default}, //"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::Default}, //"tw", OPTYPE_SYSTEM, FL_ENDBLOCK, 1}},
|
||||||
|
{598, &JitArmIL::Default}, //"sync", OPTYPE_SYSTEM, 0, 2}},
|
||||||
|
{982, &JitArmIL::Default}, //"icbi", OPTYPE_SYSTEM, FL_ENDBLOCK, 3}},
|
||||||
|
|
||||||
|
// Unused instructions on GC
|
||||||
|
{310, &JitArmIL::Default}, //"eciwx", OPTYPE_INTEGER, FL_RC_BIT}},
|
||||||
|
{438, &JitArmIL::Default}, //"ecowx", OPTYPE_INTEGER, FL_RC_BIT}},
|
||||||
|
{854, &JitArmIL::Default}, //"eieio", OPTYPE_INTEGER, FL_RC_BIT}},
|
||||||
|
{306, &JitArmIL::Default}, //"tlbie", OPTYPE_SYSTEM, 0}},
|
||||||
|
{370, &JitArmIL::Default}, //"tlbia", OPTYPE_SYSTEM, 0}},
|
||||||
|
{566, &JitArmIL::Default}, //"tlbsync", OPTYPE_SYSTEM, 0}},
|
||||||
|
};
|
||||||
|
|
||||||
|
static GekkoOPTemplate table31_2[] =
|
||||||
|
{
|
||||||
|
{266, &JitArmIL::Default}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||||
|
{778, &JitArmIL::Default}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||||
|
{10, &JitArmIL::Default}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
|
||||||
|
{138, &JitArmIL::Default}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||||
|
{234, &JitArmIL::Default}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||||
|
{202, &JitArmIL::Default}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||||
|
{491, &JitArmIL::Default}, //"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
|
||||||
|
{1003, &JitArmIL::Default}, //"divwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
|
||||||
|
{459, &JitArmIL::Default}, //"divwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
|
||||||
|
{971, &JitArmIL::Default}, //"divwuox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
|
||||||
|
{75, &JitArmIL::Default}, //"mulhwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
|
||||||
|
{11, &JitArmIL::Default}, //"mulhwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
|
||||||
|
{235, &JitArmIL::Default}, //"mullwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
|
||||||
|
{747, &JitArmIL::Default}, //"mullwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
|
||||||
|
{104, &JitArmIL::Default}, //"negx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||||
|
{40, &JitArmIL::Default}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||||
|
{552, &JitArmIL::Default}, //"subox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||||
|
{8, &JitArmIL::Default}, //"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
|
||||||
|
{136, &JitArmIL::Default}, //"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||||
|
{232, &JitArmIL::Default}, //"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||||
|
{200, &JitArmIL::Default}, //"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||||
|
};
|
||||||
|
|
||||||
|
static GekkoOPTemplate table59[] =
|
||||||
|
{
|
||||||
|
{18, &JitArmIL::Default}, //{"fdivsx", OPTYPE_FPU, FL_RC_BIT_F, 16}},
|
||||||
|
{20, &JitArmIL::Default}, //"fsubsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{21, &JitArmIL::Default}, //"faddsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
// {22, &JitArmIL::Default}, //"fsqrtsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{24, &JitArmIL::Default}, //"fresx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{25, &JitArmIL::Default}, //"fmulsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{28, &JitArmIL::Default}, //"fmsubsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{29, &JitArmIL::Default}, //"fmaddsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{30, &JitArmIL::Default}, //"fnmsubsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{31, &JitArmIL::Default}, //"fnmaddsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
};
|
||||||
|
|
||||||
|
static GekkoOPTemplate table63[] =
|
||||||
|
{
|
||||||
|
{264, &JitArmIL::Default}, //"fabsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{32, &JitArmIL::Default}, //"fcmpo", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{0, &JitArmIL::Default}, //"fcmpu", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{14, &JitArmIL::Default}, //"fctiwx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{15, &JitArmIL::Default}, //"fctiwzx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{72, &JitArmIL::Default}, //"fmrx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{136, &JitArmIL::Default}, //"fnabsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{40, &JitArmIL::Default}, //"fnegx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{12, &JitArmIL::Default}, //"frspx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
|
||||||
|
{64, &JitArmIL::Default}, //"mcrfs", OPTYPE_SYSTEMFP, 0}},
|
||||||
|
{583, &JitArmIL::Default}, //"mffsx", OPTYPE_SYSTEMFP, 0}},
|
||||||
|
{70, &JitArmIL::Default}, //"mtfsb0x", OPTYPE_SYSTEMFP, 0, 2}},
|
||||||
|
{38, &JitArmIL::Default}, //"mtfsb1x", OPTYPE_SYSTEMFP, 0, 2}},
|
||||||
|
{134, &JitArmIL::Default}, //"mtfsfix", OPTYPE_SYSTEMFP, 0, 2}},
|
||||||
|
{711, &JitArmIL::Default}, //"mtfsfx", OPTYPE_SYSTEMFP, 0, 2}},
|
||||||
|
};
|
||||||
|
|
||||||
|
static GekkoOPTemplate table63_2[] =
|
||||||
|
{
|
||||||
|
{18, &JitArmIL::Default}, //"fdivx", OPTYPE_FPU, FL_RC_BIT_F, 30}},
|
||||||
|
{20, &JitArmIL::Default}, //"fsubx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{21, &JitArmIL::Default}, //"faddx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{22, &JitArmIL::Default}, //"fsqrtx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{23, &JitArmIL::Default}, //"fselx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{25, &JitArmIL::Default}, //"fmulx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{26, &JitArmIL::Default}, //"frsqrtex", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{28, &JitArmIL::Default}, //"fmsubx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{29, &JitArmIL::Default}, //"fmaddx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{30, &JitArmIL::Default}, //"fnmsubx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
{31, &JitArmIL::Default}, //"fnmaddx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
namespace JitArmILTables
|
||||||
|
{
|
||||||
|
|
||||||
|
void CompileInstruction(PPCAnalyst::CodeOp & op)
|
||||||
|
{
|
||||||
|
JitArmIL *jitarm = (JitArmIL *)jit;
|
||||||
|
(jitarm->*dynaOpTable[op.inst.OPCD])(op.inst);
|
||||||
|
GekkoOPInfo *info = op.opinfo;
|
||||||
|
if (info) {
|
||||||
|
#ifdef OPLOG
|
||||||
|
if (!strcmp(info->opname, OP_TO_LOG)){ ///"mcrfs"
|
||||||
|
rsplocations.push_back(jit.js.compilerPC);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
info->compileCount++;
|
||||||
|
info->lastUse = jit->js.compilerPC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitTables()
|
||||||
|
{
|
||||||
|
// once initialized, tables are read-only
|
||||||
|
static bool initialized = false;
|
||||||
|
if (initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//clear
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
dynaOpTable59[i] = &JitArmIL::unknown_instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 1024; i++)
|
||||||
|
{
|
||||||
|
dynaOpTable4 [i] = &JitArmIL::unknown_instruction;
|
||||||
|
dynaOpTable19[i] = &JitArmIL::unknown_instruction;
|
||||||
|
dynaOpTable31[i] = &JitArmIL::unknown_instruction;
|
||||||
|
dynaOpTable63[i] = &JitArmIL::unknown_instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)(sizeof(primarytable) / sizeof(GekkoOPTemplate)); i++)
|
||||||
|
{
|
||||||
|
dynaOpTable[primarytable[i].opcode] = primarytable[i].Inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
int fill = i << 5;
|
||||||
|
for (int j = 0; j < (int)(sizeof(table4_2) / sizeof(GekkoOPTemplate)); j++)
|
||||||
|
{
|
||||||
|
int op = fill+table4_2[j].opcode;
|
||||||
|
dynaOpTable4[op] = table4_2[j].Inst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
int fill = i << 6;
|
||||||
|
for (int j = 0; j < (int)(sizeof(table4_3) / sizeof(GekkoOPTemplate)); j++)
|
||||||
|
{
|
||||||
|
int op = fill+table4_3[j].opcode;
|
||||||
|
dynaOpTable4[op] = table4_3[j].Inst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)(sizeof(table4) / sizeof(GekkoOPTemplate)); i++)
|
||||||
|
{
|
||||||
|
int op = table4[i].opcode;
|
||||||
|
dynaOpTable4[op] = table4[i].Inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)(sizeof(table31) / sizeof(GekkoOPTemplate)); i++)
|
||||||
|
{
|
||||||
|
int op = table31[i].opcode;
|
||||||
|
dynaOpTable31[op] = table31[i].Inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 1; i++)
|
||||||
|
{
|
||||||
|
int fill = i << 9;
|
||||||
|
for (int j = 0; j < (int)(sizeof(table31_2) / sizeof(GekkoOPTemplate)); j++)
|
||||||
|
{
|
||||||
|
int op = fill + table31_2[j].opcode;
|
||||||
|
dynaOpTable31[op] = table31_2[j].Inst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)(sizeof(table19) / sizeof(GekkoOPTemplate)); i++)
|
||||||
|
{
|
||||||
|
int op = table19[i].opcode;
|
||||||
|
dynaOpTable19[op] = table19[i].Inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)(sizeof(table59) / sizeof(GekkoOPTemplate)); i++)
|
||||||
|
{
|
||||||
|
int op = table59[i].opcode;
|
||||||
|
dynaOpTable59[op] = table59[i].Inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)(sizeof(table63) / sizeof(GekkoOPTemplate)); i++)
|
||||||
|
{
|
||||||
|
int op = table63[i].opcode;
|
||||||
|
dynaOpTable63[op] = table63[i].Inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
int fill = i << 5;
|
||||||
|
for (int j = 0; j < (int)(sizeof(table63_2) / sizeof(GekkoOPTemplate)); j++)
|
||||||
|
{
|
||||||
|
int op = fill + table63_2[j].opcode;
|
||||||
|
dynaOpTable63[op] = table63_2[j].Inst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
16
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL_Tables.h
Normal file
16
Source/Core/Core/Src/PowerPC/JitArmIL/JitIL_Tables.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2013 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#ifndef JITARMIL_TABLES_H
|
||||||
|
#define JITARMIL_TABLES_H
|
||||||
|
|
||||||
|
#include "../Gekko.h"
|
||||||
|
#include "../PPCTables.h"
|
||||||
|
|
||||||
|
namespace JitArmILTables
|
||||||
|
{
|
||||||
|
void CompileInstruction(PPCAnalyst::CodeOp & op);
|
||||||
|
void InitTables();
|
||||||
|
}
|
||||||
|
#endif
|
@ -124,8 +124,6 @@ Fix profiled loads/stores to work safely. On 32-bit, one solution is to
|
|||||||
#include "../PPCTables.h"
|
#include "../PPCTables.h"
|
||||||
#include "../../CoreTiming.h"
|
#include "../../CoreTiming.h"
|
||||||
#include "../../HW/Memmap.h"
|
#include "../../HW/Memmap.h"
|
||||||
#include "JitILAsm.h"
|
|
||||||
#include "JitIL.h"
|
|
||||||
#include "../../HW/GPFifo.h"
|
#include "../../HW/GPFifo.h"
|
||||||
#include "../../Core.h"
|
#include "../../Core.h"
|
||||||
using namespace Gen;
|
using namespace Gen;
|
@ -21,6 +21,8 @@
|
|||||||
#ifdef _M_ARM
|
#ifdef _M_ARM
|
||||||
#include "JitArm32/Jit.h"
|
#include "JitArm32/Jit.h"
|
||||||
#include "JitArm32/JitArm_Tables.h"
|
#include "JitArm32/JitArm_Tables.h"
|
||||||
|
#include "JitArmIL/JitIL.h"
|
||||||
|
#include "JitArmIL/JitIL_Tables.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Profiler.h"
|
#include "Profiler.h"
|
||||||
@ -64,6 +66,11 @@ namespace JitInterface
|
|||||||
ptr = new JitArm();
|
ptr = new JitArm();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
ptr = new JitArmIL();
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@ -99,6 +106,11 @@ namespace JitInterface
|
|||||||
JitArmTables::InitTables();
|
JitArmTables::InitTables();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
JitArmILTables::InitTables();
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user