Remove profiled re-JIT support in JitIL.
It's extremely unsafe, unused (not exposed in the GUI and not present in any gameconfigs), and mostly obviated by fastmem. Although this type of thing could theoretically be useful someday for fastmem support with MMU, it's probably not the best way to do it, the existing implementation is way too simplistic, and it can always be dug up to provide support for a new implementation if needed. Not like it's a big deal to keep it working, but it really seems pointless.
This commit is contained in:
parent
3b0c0e2500
commit
a53dc6f981
|
@ -409,7 +409,6 @@ void SConfig::LoadSettings()
|
||||||
ini.Get("Core", "SlotB", (int*)&m_EXIDevice[1], EXIDEVICE_NONE);
|
ini.Get("Core", "SlotB", (int*)&m_EXIDevice[1], EXIDEVICE_NONE);
|
||||||
ini.Get("Core", "SerialPort1", (int*)&m_EXIDevice[2], EXIDEVICE_NONE);
|
ini.Get("Core", "SerialPort1", (int*)&m_EXIDevice[2], EXIDEVICE_NONE);
|
||||||
ini.Get("Core", "BBA_MAC", &m_bba_mac);
|
ini.Get("Core", "BBA_MAC", &m_bba_mac);
|
||||||
ini.Get("Core", "ProfiledReJIT",&m_LocalCoreStartupParameter.bJITProfiledReJIT, false);
|
|
||||||
ini.Get("Core", "TimeProfiling",&m_LocalCoreStartupParameter.bJITILTimeProfiling, false);
|
ini.Get("Core", "TimeProfiling",&m_LocalCoreStartupParameter.bJITILTimeProfiling, false);
|
||||||
ini.Get("Core", "OutputIR", &m_LocalCoreStartupParameter.bJITILOutputIR, false);
|
ini.Get("Core", "OutputIR", &m_LocalCoreStartupParameter.bJITILOutputIR, false);
|
||||||
char sidevicenum[16];
|
char sidevicenum[16];
|
||||||
|
|
|
@ -28,7 +28,7 @@ SCoreStartupParameter::SCoreStartupParameter()
|
||||||
bJITLoadStoreFloatingOff(false), bJITLoadStorePairedOff(false),
|
bJITLoadStoreFloatingOff(false), bJITLoadStorePairedOff(false),
|
||||||
bJITFloatingPointOff(false), bJITIntegerOff(false),
|
bJITFloatingPointOff(false), bJITIntegerOff(false),
|
||||||
bJITPairedOff(false), bJITSystemRegistersOff(false),
|
bJITPairedOff(false), bJITSystemRegistersOff(false),
|
||||||
bJITBranchOff(false), bJITProfiledReJIT(false),
|
bJITBranchOff(false),
|
||||||
bJITILTimeProfiling(false), bJITILOutputIR(false),
|
bJITILTimeProfiling(false), bJITILOutputIR(false),
|
||||||
bEnableFPRF(false),
|
bEnableFPRF(false),
|
||||||
bCPUThread(true), bDSPThread(false), bDSPHLE(true),
|
bCPUThread(true), bDSPThread(false), bDSPHLE(true),
|
||||||
|
|
|
@ -111,7 +111,6 @@ struct SCoreStartupParameter
|
||||||
bool bJITPairedOff;
|
bool bJITPairedOff;
|
||||||
bool bJITSystemRegistersOff;
|
bool bJITSystemRegistersOff;
|
||||||
bool bJITBranchOff;
|
bool bJITBranchOff;
|
||||||
bool bJITProfiledReJIT;
|
|
||||||
bool bJITILTimeProfiling;
|
bool bJITILTimeProfiling;
|
||||||
bool bJITILOutputIR;
|
bool bJITILOutputIR;
|
||||||
|
|
||||||
|
|
|
@ -234,6 +234,4 @@ public:
|
||||||
void icbi(UGeckoInstruction inst);
|
void icbi(UGeckoInstruction inst);
|
||||||
};
|
};
|
||||||
|
|
||||||
void ProfiledReJit();
|
|
||||||
|
|
||||||
#endif // _JIT64_H
|
#endif // _JIT64_H
|
||||||
|
|
|
@ -56,9 +56,6 @@ struct RegInfo {
|
||||||
InstLoc fregs[MAX_NUMBER_OF_REGS];
|
InstLoc fregs[MAX_NUMBER_OF_REGS];
|
||||||
unsigned numSpills;
|
unsigned numSpills;
|
||||||
unsigned numFSpills;
|
unsigned numFSpills;
|
||||||
bool MakeProfile;
|
|
||||||
bool UseProfile;
|
|
||||||
unsigned numProfiledLoads;
|
|
||||||
unsigned exitNumber;
|
unsigned exitNumber;
|
||||||
|
|
||||||
RegInfo(JitIL* j, InstLoc f, unsigned insts) : Jit(j), FirstI(f), IInfo(insts), lastUsed(insts) {
|
RegInfo(JitIL* j, InstLoc f, unsigned insts) : Jit(j), FirstI(f), IInfo(insts), lastUsed(insts) {
|
||||||
|
@ -68,9 +65,7 @@ struct RegInfo {
|
||||||
}
|
}
|
||||||
numSpills = 0;
|
numSpills = 0;
|
||||||
numFSpills = 0;
|
numFSpills = 0;
|
||||||
numProfiledLoads = 0;
|
|
||||||
exitNumber = 0;
|
exitNumber = 0;
|
||||||
MakeProfile = UseProfile = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -106,7 +101,6 @@ static unsigned regReadUse(RegInfo& R, InstLoc I) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned SlotSet[1000];
|
static unsigned SlotSet[1000];
|
||||||
static unsigned ProfiledLoads[1000];
|
|
||||||
static u8 GC_ALIGNED16(FSlotSet[16*1000]);
|
static u8 GC_ALIGNED16(FSlotSet[16*1000]);
|
||||||
|
|
||||||
static OpArg regLocForSlot(RegInfo& RI, unsigned slot) {
|
static OpArg regLocForSlot(RegInfo& RI, unsigned slot) {
|
||||||
|
@ -440,47 +434,14 @@ static void regMarkMemAddress(RegInfo& RI, InstLoc I, InstLoc AI, unsigned OpNum
|
||||||
regMarkUse(RI, I, AI, OpNum);
|
regMarkUse(RI, I, AI, OpNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void regClearDeadMemAddress(RegInfo& RI, InstLoc I, InstLoc AI, unsigned OpNum) {
|
|
||||||
if (!(RI.IInfo[I - RI.FirstI] & (2 << OpNum)))
|
|
||||||
return;
|
|
||||||
if (isImm(*AI)) {
|
|
||||||
unsigned addr = RI.Build->GetImmValue(AI);
|
|
||||||
if (Memory::IsRAMAddress(addr)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InstLoc AddrBase;
|
|
||||||
if (getOpcode(*AI) == Add && isImm(*getOp2(AI))) {
|
|
||||||
AddrBase = getOp1(AI);
|
|
||||||
} else {
|
|
||||||
AddrBase = AI;
|
|
||||||
}
|
|
||||||
regClearInst(RI, AddrBase);
|
|
||||||
}
|
|
||||||
|
|
||||||
// in 64-bit build, this returns a completely bizarre address sometimes!
|
// in 64-bit build, this returns a completely bizarre address sometimes!
|
||||||
static OpArg regBuildMemAddress(RegInfo& RI, InstLoc I, InstLoc AI,
|
static OpArg regBuildMemAddress(RegInfo& RI, InstLoc I, InstLoc AI,
|
||||||
unsigned OpNum, unsigned Size, X64Reg* dest,
|
unsigned OpNum, unsigned Size, X64Reg* dest) {
|
||||||
bool Profiled,
|
|
||||||
unsigned ProfileOffset = 0) {
|
|
||||||
if (isImm(*AI)) {
|
if (isImm(*AI)) {
|
||||||
unsigned addr = RI.Build->GetImmValue(AI);
|
unsigned addr = RI.Build->GetImmValue(AI);
|
||||||
if (Memory::IsRAMAddress(addr)) {
|
if (Memory::IsRAMAddress(addr)) {
|
||||||
if (dest)
|
if (dest)
|
||||||
*dest = regFindFreeReg(RI);
|
*dest = regFindFreeReg(RI);
|
||||||
#ifdef _M_IX86
|
|
||||||
// 32-bit
|
|
||||||
if (Profiled)
|
|
||||||
return M((void*)((u8*)Memory::base + (addr & Memory::MEMVIEW32_MASK)));
|
|
||||||
return M((void*)addr);
|
|
||||||
#else
|
|
||||||
// 64-bit
|
|
||||||
if (Profiled) {
|
|
||||||
RI.Jit->LEA(32, EAX, M((void*)(u64)addr));
|
|
||||||
return MComplex(RBX, EAX, SCALE_1, 0);
|
|
||||||
}
|
|
||||||
return M((void*)(u64)addr);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsigned offset;
|
unsigned offset;
|
||||||
|
@ -512,44 +473,12 @@ static OpArg regBuildMemAddress(RegInfo& RI, InstLoc I, InstLoc AI,
|
||||||
} else {
|
} else {
|
||||||
baseReg = regEnsureInReg(RI, AddrBase);
|
baseReg = regEnsureInReg(RI, AddrBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Profiled) {
|
|
||||||
// (Profiled mode isn't the default, at least for the moment)
|
|
||||||
#ifdef _M_IX86
|
|
||||||
return MDisp(baseReg, (u32)Memory::base + offset + ProfileOffset);
|
|
||||||
#else
|
|
||||||
RI.Jit->LEA(32, EAX, MDisp(baseReg, offset));
|
|
||||||
return MComplex(RBX, EAX, SCALE_1, 0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return MDisp(baseReg, offset);
|
return MDisp(baseReg, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void regEmitMemLoad(RegInfo& RI, InstLoc I, unsigned Size) {
|
static void regEmitMemLoad(RegInfo& RI, InstLoc I, unsigned Size) {
|
||||||
if (RI.UseProfile) {
|
|
||||||
unsigned curLoad = ProfiledLoads[RI.numProfiledLoads++];
|
|
||||||
if (!(curLoad & 0x0C000000)) {
|
|
||||||
X64Reg reg;
|
|
||||||
OpArg addr = regBuildMemAddress(RI, I, getOp1(I), 1,
|
|
||||||
Size, ®, true,
|
|
||||||
-(curLoad & 0xC0000000));
|
|
||||||
RI.Jit->MOVZX(32, Size, reg, addr);
|
|
||||||
RI.Jit->BSWAP(Size, reg);
|
|
||||||
if (regReadUse(RI, I))
|
|
||||||
RI.regs[reg] = I;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
X64Reg reg;
|
X64Reg reg;
|
||||||
OpArg addr = regBuildMemAddress(RI, I, getOp1(I), 1, Size, ®, false);
|
OpArg addr = regBuildMemAddress(RI, I, getOp1(I), 1, Size, ®);
|
||||||
RI.Jit->LEA(32, ECX, addr);
|
|
||||||
if (RI.MakeProfile) {
|
|
||||||
RI.Jit->MOV(32, M(&ProfiledLoads[RI.numProfiledLoads++]), R(ECX));
|
|
||||||
}
|
|
||||||
u32 mem_mask = 0;
|
|
||||||
|
|
||||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU || SConfig::GetInstance().m_LocalCoreStartupParameter.bTLBHack)
|
|
||||||
mem_mask = 0x20000000;
|
|
||||||
|
|
||||||
RI.Jit->TEST(32, R(ECX), Imm32(0x0C000000 | mem_mask));
|
RI.Jit->TEST(32, R(ECX), Imm32(0x0C000000 | mem_mask));
|
||||||
FixupBranch argh = RI.Jit->J_CC(CC_Z);
|
FixupBranch argh = RI.Jit->J_CC(CC_Z);
|
||||||
|
@ -580,19 +509,6 @@ static void regEmitMemLoad(RegInfo& RI, InstLoc I, unsigned Size) {
|
||||||
RI.regs[reg] = I;
|
RI.regs[reg] = I;
|
||||||
}
|
}
|
||||||
|
|
||||||
static OpArg regSwappedImmForConst(RegInfo& RI, InstLoc I, unsigned Size) {
|
|
||||||
unsigned imm = RI.Build->GetImmValue(I);
|
|
||||||
if (Size == 32) {
|
|
||||||
imm = Common::swap32(imm);
|
|
||||||
return Imm32(imm);
|
|
||||||
} else if (Size == 16) {
|
|
||||||
imm = Common::swap16(imm);
|
|
||||||
return Imm16(imm);
|
|
||||||
} else {
|
|
||||||
return Imm8(imm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static OpArg regImmForConst(RegInfo& RI, InstLoc I, unsigned Size) {
|
static OpArg regImmForConst(RegInfo& RI, InstLoc I, unsigned Size) {
|
||||||
unsigned imm = RI.Build->GetImmValue(I);
|
unsigned imm = RI.Build->GetImmValue(I);
|
||||||
if (Size == 32) {
|
if (Size == 32) {
|
||||||
|
@ -605,42 +521,7 @@ static OpArg regImmForConst(RegInfo& RI, InstLoc I, unsigned Size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void regEmitMemStore(RegInfo& RI, InstLoc I, unsigned Size) {
|
static void regEmitMemStore(RegInfo& RI, InstLoc I, unsigned Size) {
|
||||||
if (RI.UseProfile) {
|
OpArg addr = regBuildMemAddress(RI, I, getOp2(I), 2, Size, 0);
|
||||||
unsigned curStore = ProfiledLoads[RI.numProfiledLoads++];
|
|
||||||
if (!(curStore & 0x0C000000)) {
|
|
||||||
OpArg addr = regBuildMemAddress(RI, I, getOp2(I), 2,
|
|
||||||
Size, 0, true,
|
|
||||||
-(curStore & 0xC0000000));
|
|
||||||
if (isImm(*getOp1(I))) {
|
|
||||||
RI.Jit->MOV(Size, addr, regSwappedImmForConst(RI, getOp1(I), Size));
|
|
||||||
} else {
|
|
||||||
RI.Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I)));
|
|
||||||
RI.Jit->BSWAP(Size, ECX);
|
|
||||||
RI.Jit->MOV(Size, addr, R(ECX));
|
|
||||||
}
|
|
||||||
if (RI.IInfo[I - RI.FirstI] & 4)
|
|
||||||
regClearInst(RI, getOp1(I));
|
|
||||||
return;
|
|
||||||
} else if ((curStore & 0xFFFFF000) == 0xCC008000) {
|
|
||||||
regSpill(RI, EAX);
|
|
||||||
if (isImm(*getOp1(I))) {
|
|
||||||
RI.Jit->MOV(Size, R(ECX), regSwappedImmForConst(RI, getOp1(I), Size));
|
|
||||||
} else {
|
|
||||||
RI.Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I)));
|
|
||||||
RI.Jit->BSWAP(Size, ECX);
|
|
||||||
}
|
|
||||||
RI.Jit->MOV(32, R(EAX), M(&GPFifo::m_gatherPipeCount));
|
|
||||||
RI.Jit->MOV(Size, MDisp(EAX, (u32)(u64)GPFifo::m_gatherPipe), R(ECX));
|
|
||||||
RI.Jit->ADD(32, R(EAX), Imm8(Size >> 3));
|
|
||||||
RI.Jit->MOV(32, M(&GPFifo::m_gatherPipeCount), R(EAX));
|
|
||||||
RI.Jit->js.fifoBytesThisBlock += Size >> 3;
|
|
||||||
if (RI.IInfo[I - RI.FirstI] & 4)
|
|
||||||
regClearInst(RI, getOp1(I));
|
|
||||||
regClearDeadMemAddress(RI, I, getOp2(I), 2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OpArg addr = regBuildMemAddress(RI, I, getOp2(I), 2, Size, 0, false);
|
|
||||||
RI.Jit->LEA(32, ECX, addr);
|
RI.Jit->LEA(32, ECX, addr);
|
||||||
regSpill(RI, EAX);
|
regSpill(RI, EAX);
|
||||||
if (isImm(*getOp1(I))) {
|
if (isImm(*getOp1(I))) {
|
||||||
|
@ -648,9 +529,6 @@ static void regEmitMemStore(RegInfo& RI, InstLoc I, unsigned Size) {
|
||||||
} else {
|
} else {
|
||||||
RI.Jit->MOV(32, R(EAX), regLocForInst(RI, getOp1(I)));
|
RI.Jit->MOV(32, R(EAX), regLocForInst(RI, getOp1(I)));
|
||||||
}
|
}
|
||||||
if (RI.MakeProfile) {
|
|
||||||
RI.Jit->MOV(32, M(&ProfiledLoads[RI.numProfiledLoads++]), R(ECX));
|
|
||||||
}
|
|
||||||
RI.Jit->SafeWriteRegToReg(EAX, ECX, Size, 0, regsInUse(RI));
|
RI.Jit->SafeWriteRegToReg(EAX, ECX, Size, 0, regsInUse(RI));
|
||||||
if (RI.IInfo[I - RI.FirstI] & 4)
|
if (RI.IInfo[I - RI.FirstI] & 4)
|
||||||
regClearInst(RI, getOp1(I));
|
regClearInst(RI, getOp1(I));
|
||||||
|
@ -704,18 +582,6 @@ static void regEmitICmpInst(RegInfo& RI, InstLoc I, CCFlags flag) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void regWriteExit(RegInfo& RI, InstLoc dest) {
|
static void regWriteExit(RegInfo& RI, InstLoc dest) {
|
||||||
if (RI.MakeProfile) {
|
|
||||||
if (isImm(*dest)) {
|
|
||||||
RI.Jit->MOV(32, M(&PC), Imm32(RI.Build->GetImmValue(dest)));
|
|
||||||
} else {
|
|
||||||
RI.Jit->MOV(32, R(EAX), regLocForInst(RI, dest));
|
|
||||||
RI.Jit->MOV(32, M(&PC), R(EAX));
|
|
||||||
}
|
|
||||||
RI.Jit->Cleanup();
|
|
||||||
RI.Jit->SUB(32, M(&CoreTiming::downcount), Imm32(RI.Jit->js.downcountAmount));
|
|
||||||
RI.Jit->JMP(((JitIL *)jit)->asm_routines.doReJit, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isImm(*dest)) {
|
if (isImm(*dest)) {
|
||||||
RI.Jit->WriteExit(RI.Build->GetImmValue(dest), RI.exitNumber++);
|
RI.Jit->WriteExit(RI.Build->GetImmValue(dest), RI.exitNumber++);
|
||||||
} else {
|
} else {
|
||||||
|
@ -729,12 +595,10 @@ static bool checkIsSNAN() {
|
||||||
return MathUtil::IsSNAN(isSNANTemp[0][0]) || MathUtil::IsSNAN(isSNANTemp[1][0]);
|
return MathUtil::IsSNAN(isSNANTemp[0][0]) || MathUtil::IsSNAN(isSNANTemp[1][0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool MakeProfile) {
|
static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit) {
|
||||||
//printf("Writing block: %x\n", js.blockStart);
|
//printf("Writing block: %x\n", js.blockStart);
|
||||||
RegInfo RI(Jit, ibuild->getFirstInst(), ibuild->getNumInsts());
|
RegInfo RI(Jit, ibuild->getFirstInst(), ibuild->getNumInsts());
|
||||||
RI.Build = ibuild;
|
RI.Build = ibuild;
|
||||||
RI.UseProfile = UseProfile;
|
|
||||||
RI.MakeProfile = MakeProfile;
|
|
||||||
// Pass to compute liveness
|
// Pass to compute liveness
|
||||||
ibuild->StartBackPass();
|
ibuild->StartBackPass();
|
||||||
for (unsigned int index = (unsigned int)RI.IInfo.size() - 1; index != -1U; --index) {
|
for (unsigned int index = (unsigned int)RI.IInfo.size() - 1; index != -1U; --index) {
|
||||||
|
@ -1997,22 +1861,10 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (!RI.MakeProfile && RI.numSpills)
|
|
||||||
// printf("Block: %x, numspills %d\n", Jit->js.blockStart, RI.numSpills);
|
|
||||||
|
|
||||||
Jit->WriteExit(jit->js.curBlock->exitAddress[0], 0);
|
Jit->WriteExit(jit->js.curBlock->exitAddress[0], 0);
|
||||||
Jit->UD2();
|
Jit->UD2();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitIL::WriteCode() {
|
void JitIL::WriteCode() {
|
||||||
DoWriteCode(&ibuild, this, false, SConfig::GetInstance().m_LocalCoreStartupParameter.bJITProfiledReJIT);
|
DoWriteCode(&ibuild, this);
|
||||||
}
|
|
||||||
|
|
||||||
void ProfiledReJit() {
|
|
||||||
JitIL *jitil = (JitIL *)jit;
|
|
||||||
jitil->SetCodePtr(jitil->js.rewriteStart);
|
|
||||||
DoWriteCode(&jitil->ibuild, jitil, true, false);
|
|
||||||
jitil->js.curBlock->codeSize = (int)(jitil->GetCodePtr() - jitil->js.rewriteStart);
|
|
||||||
jitil->GetBlockCache()->FinalizeBlock(jitil->js.curBlock->blockNum, jitil->jo.enableBlocklink,
|
|
||||||
jitil->js.curBlock->normalEntry);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,6 +221,4 @@ public:
|
||||||
|
|
||||||
void Jit(u32 em_address);
|
void Jit(u32 em_address);
|
||||||
|
|
||||||
void ProfiledReJit();
|
|
||||||
|
|
||||||
#endif // _JITIL_H
|
#endif // _JITIL_H
|
||||||
|
|
|
@ -233,13 +233,6 @@ void JitILAsmRoutineManager::GenerateCommon()
|
||||||
fifoDirectWriteXmm64 = AlignCode4();
|
fifoDirectWriteXmm64 = AlignCode4();
|
||||||
GenFifoXmm64Write();
|
GenFifoXmm64Write();
|
||||||
|
|
||||||
doReJit = AlignCode4();
|
|
||||||
ABI_AlignStack(0);
|
|
||||||
CALL(reinterpret_cast<void *>(&ProfiledReJit));
|
|
||||||
ABI_RestoreStack(0);
|
|
||||||
SUB(32, M(&CoreTiming::downcount), Imm8(0));
|
|
||||||
JMP(dispatcher, true);
|
|
||||||
|
|
||||||
GenQuantizedLoads();
|
GenQuantizedLoads();
|
||||||
GenQuantizedStores();
|
GenQuantizedStores();
|
||||||
GenQuantizedSingleStores();
|
GenQuantizedSingleStores();
|
||||||
|
|
|
@ -38,8 +38,6 @@ public:
|
||||||
void Shutdown() {
|
void Shutdown() {
|
||||||
FreeCodeSpace();
|
FreeCodeSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8 *doReJit;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern JitILAsmRoutineManager jitil_asm_routines;
|
extern JitILAsmRoutineManager jitil_asm_routines;
|
||||||
|
|
Loading…
Reference in New Issue