mirror of
https://github.com/libretro/ppsspp.git
synced 2024-12-09 09:23:53 +00:00
Merge pull request #7192 from unknownbrackets/jit-minor
x86jit: Free up a reg and cut some bytes from asm
This commit is contained in:
commit
9f86148792
@ -60,14 +60,19 @@ void ImHere()
|
||||
DEBUG_LOG(CPU, "JIT Here: %08x", currentMIPS->pc);
|
||||
}
|
||||
|
||||
void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit)
|
||||
void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit, MIPSComp::JitOptions *jo)
|
||||
{
|
||||
enterCode = AlignCode16();
|
||||
ABI_PushAllCalleeSavedRegsAndAdjustStack();
|
||||
#ifdef _M_X64
|
||||
// Two statically allocated registers.
|
||||
MOV(64, R(MEMBASEREG), ImmPtr(Memory::base));
|
||||
MOV(64, R(JITBASEREG), ImmPtr(jit->GetBasePtr())); //It's below 2GB so 32 bits are good enough
|
||||
uintptr_t jitbase = (uintptr_t)jit->GetBasePtr();
|
||||
if (jitbase > 0x7FFFFFFFULL)
|
||||
{
|
||||
MOV(64, R(JITBASEREG), ImmPtr(jit->GetBasePtr()));
|
||||
jo->reserveR15ForAsm = true;
|
||||
}
|
||||
#endif
|
||||
// From the start of the FP reg, a single byte offset can reach all GPR + all FPR (but no VFPUR)
|
||||
MOV(PTRBITS, R(CTXREG), ImmPtr(&mips->f[0]));
|
||||
@ -110,9 +115,10 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit)
|
||||
MOV(32, R(EAX), MComplex(MEMBASEREG, RAX, SCALE_1, 0));
|
||||
#endif
|
||||
MOV(32, R(EDX), R(EAX));
|
||||
AND(32, R(EDX), Imm32(MIPS_JITBLOCK_MASK));
|
||||
CMP(32, R(EDX), Imm32(MIPS_EMUHACK_OPCODE));
|
||||
FixupBranch notfound = J_CC(CC_NZ);
|
||||
_assert_msg_(JIT, MIPS_JITBLOCK_MASK == 0xFF000000, "Hardcoded assumption of emuhack mask");
|
||||
SHR(32, R(EDX), Imm8(24));
|
||||
CMP(32, R(EDX), Imm8(MIPS_EMUHACK_OPCODE >> 24));
|
||||
FixupBranch notfound = J_CC(CC_NE);
|
||||
if (enableDebug)
|
||||
{
|
||||
ADD(32, M(&mips->debugCount), Imm8(1));
|
||||
@ -122,7 +128,10 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit)
|
||||
#ifdef _M_IX86
|
||||
ADD(32, R(EAX), ImmPtr(jit->GetBasePtr()));
|
||||
#elif _M_X64
|
||||
ADD(64, R(RAX), R(JITBASEREG));
|
||||
if (jo->reserveR15ForAsm)
|
||||
ADD(64, R(RAX), R(JITBASEREG));
|
||||
else
|
||||
ADD(64, R(EAX), Imm32(jitbase));
|
||||
#endif
|
||||
JMPptr(R(EAX));
|
||||
SetJumpTarget(notfound);
|
||||
|
@ -18,35 +18,31 @@
|
||||
#ifndef _JIT64ASM_H
|
||||
#define _JIT64ASM_H
|
||||
|
||||
#include "x64Emitter.h"
|
||||
#include "../MIPS.h"
|
||||
#include "Common/x64Emitter.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
|
||||
// Runtime generated assembly routines, like the Dispatcher.
|
||||
|
||||
namespace MIPSComp
|
||||
{
|
||||
namespace MIPSComp {
|
||||
class Jit;
|
||||
struct JitOptions;
|
||||
}
|
||||
|
||||
class AsmRoutineManager : public Gen::XCodeBlock
|
||||
{
|
||||
class AsmRoutineManager : public Gen::XCodeBlock {
|
||||
private:
|
||||
void Generate(MIPSState *mips, MIPSComp::Jit *jit);
|
||||
void Generate(MIPSState *mips, MIPSComp::Jit *jit, MIPSComp::JitOptions *jo);
|
||||
void GenerateCommon();
|
||||
|
||||
public:
|
||||
AsmRoutineManager()
|
||||
{
|
||||
AsmRoutineManager() {
|
||||
}
|
||||
~AsmRoutineManager()
|
||||
{
|
||||
~AsmRoutineManager() {
|
||||
FreeCodeSpace();
|
||||
}
|
||||
|
||||
void Init(MIPSState *mips, MIPSComp::Jit *jit)
|
||||
{
|
||||
void Init(MIPSState *mips, MIPSComp::Jit *jit, MIPSComp::JitOptions *jo) {
|
||||
AllocCodeSpace(8192);
|
||||
Generate(mips, jit);
|
||||
Generate(mips, jit, jo);
|
||||
WriteProtect();
|
||||
}
|
||||
|
||||
|
@ -325,10 +325,18 @@ void Jit::Comp_SVQ(MIPSOpcode op)
|
||||
CMP(32, R(EAX), Imm32(0));
|
||||
FixupBranch next = J_CC(CC_NE);
|
||||
|
||||
auto PSPMemAddr = [](X64Reg scaled, int offset) {
|
||||
#ifdef _M_IX86
|
||||
return MDisp(scaled, (u32)Memory::base + offset);
|
||||
#else
|
||||
return MComplex(MEMBASEREG, scaled, 1, offset);
|
||||
#endif
|
||||
};
|
||||
|
||||
fpr.MapRegsV(vregs, V_Quad, MAP_DIRTY);
|
||||
|
||||
// Offset = 0
|
||||
MOVSS(fpr.RX(vregs[3]), MRegSum(MEMBASEREG, RAX));
|
||||
MOVSS(fpr.RX(vregs[3]), PSPMemAddr(EAX, 0));
|
||||
|
||||
FixupBranch skip0 = J();
|
||||
SetJumpTarget(next);
|
||||
@ -336,8 +344,8 @@ void Jit::Comp_SVQ(MIPSOpcode op)
|
||||
next = J_CC(CC_NE);
|
||||
|
||||
// Offset = 1
|
||||
MOVSS(fpr.RX(vregs[3]), MComplex(MEMBASEREG, RAX, 1, 4));
|
||||
MOVSS(fpr.RX(vregs[2]), MComplex(MEMBASEREG, RAX, 1, 0));
|
||||
MOVSS(fpr.RX(vregs[3]), PSPMemAddr(EAX, 4));
|
||||
MOVSS(fpr.RX(vregs[2]), PSPMemAddr(EAX, 0));
|
||||
|
||||
FixupBranch skip1 = J();
|
||||
SetJumpTarget(next);
|
||||
@ -345,9 +353,9 @@ void Jit::Comp_SVQ(MIPSOpcode op)
|
||||
next = J_CC(CC_NE);
|
||||
|
||||
// Offset = 2
|
||||
MOVSS(fpr.RX(vregs[3]), MComplex(MEMBASEREG, RAX, 1, 8));
|
||||
MOVSS(fpr.RX(vregs[2]), MComplex(MEMBASEREG, RAX, 1, 4));
|
||||
MOVSS(fpr.RX(vregs[1]), MComplex(MEMBASEREG, RAX, 1, 0));
|
||||
MOVSS(fpr.RX(vregs[3]), PSPMemAddr(EAX, 8));
|
||||
MOVSS(fpr.RX(vregs[2]), PSPMemAddr(EAX, 4));
|
||||
MOVSS(fpr.RX(vregs[1]), PSPMemAddr(EAX, 0));
|
||||
|
||||
FixupBranch skip2 = J();
|
||||
SetJumpTarget(next);
|
||||
@ -355,10 +363,10 @@ void Jit::Comp_SVQ(MIPSOpcode op)
|
||||
next = J_CC(CC_NE);
|
||||
|
||||
// Offset = 3
|
||||
MOVSS(fpr.RX(vregs[3]), MComplex(MEMBASEREG, RAX, 1, 12));
|
||||
MOVSS(fpr.RX(vregs[2]), MComplex(MEMBASEREG, RAX, 1, 8));
|
||||
MOVSS(fpr.RX(vregs[1]), MComplex(MEMBASEREG, RAX, 1, 4));
|
||||
MOVSS(fpr.RX(vregs[0]), MComplex(MEMBASEREG, RAX, 1, 0));
|
||||
MOVSS(fpr.RX(vregs[3]), PSPMemAddr(EAX, 12));
|
||||
MOVSS(fpr.RX(vregs[2]), PSPMemAddr(EAX, 8));
|
||||
MOVSS(fpr.RX(vregs[1]), PSPMemAddr(EAX, 4));
|
||||
MOVSS(fpr.RX(vregs[0]), PSPMemAddr(EAX, 0));
|
||||
|
||||
SetJumpTarget(next);
|
||||
SetJumpTarget(skip0);
|
||||
|
@ -122,6 +122,8 @@ JitOptions::JitOptions()
|
||||
continueJumps = false;
|
||||
continueMaxInstructions = 300;
|
||||
enableVFPUSIMD = false;
|
||||
// Set by Asm if needed.
|
||||
reserveR15ForAsm = false;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@ -134,7 +136,7 @@ Jit::Jit(MIPSState *mips) : blocks(mips, this), mips_(mips)
|
||||
gpr.SetEmitter(this);
|
||||
fpr.SetEmitter(this);
|
||||
AllocCodeSpace(1024 * 1024 * 16);
|
||||
asm_.Init(mips, this);
|
||||
asm_.Init(mips, this, &jo);
|
||||
safeMemFuncs.Init(&thunks);
|
||||
|
||||
js.startDefaultPrefix = mips_->HasDefaultPrefix();
|
||||
@ -740,14 +742,14 @@ void Jit::WriteExitDestInReg(X64Reg reg)
|
||||
SetJumpTarget(tooLow);
|
||||
SetJumpTarget(tooHigh);
|
||||
|
||||
ABI_CallFunctionA(Memory::GetPointer, R(reg));
|
||||
ABI_CallFunctionA((const void *)&Memory::GetPointer, R(reg));
|
||||
|
||||
// If we're ignoring, coreState didn't trip - so trip it now.
|
||||
if (g_Config.bIgnoreBadMemAccess)
|
||||
{
|
||||
CMP(32, R(EAX), Imm32(0));
|
||||
FixupBranch skip = J_CC(CC_NE);
|
||||
ABI_CallFunctionA(&Core_UpdateState, Imm32(CORE_ERROR));
|
||||
ABI_CallFunctionA((const void *)&Core_UpdateState, Imm32(CORE_ERROR));
|
||||
SetJumpTarget(skip);
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,7 @@ struct JitOptions
|
||||
bool continueJumps;
|
||||
int continueMaxInstructions;
|
||||
bool enableVFPUSIMD;
|
||||
bool reserveR15ForAsm;
|
||||
};
|
||||
|
||||
// TODO: Hmm, humongous.
|
||||
|
@ -29,21 +29,24 @@
|
||||
using namespace Gen;
|
||||
using namespace X64JitConstants;
|
||||
|
||||
static const int allocationOrder[] =
|
||||
{
|
||||
static const X64Reg allocationOrder[] = {
|
||||
// R12, when used as base register, for example in a LEA, can generate bad code! Need to look into this.
|
||||
// On x64, RCX and RDX are the first args. CallProtectedFunction() assumes they're not regcached.
|
||||
#ifdef _M_X64
|
||||
#ifdef _WIN32
|
||||
RSI, RDI, R13, R8, R9, R10, R11, R12,
|
||||
RSI, RDI, R8, R9, R10, R11, R12, R13,
|
||||
#else
|
||||
RBP, R13, R8, R9, R10, R11, R12,
|
||||
RBP, R8, R9, R10, R11, R12, R13,
|
||||
#endif
|
||||
#elif _M_IX86
|
||||
ESI, EDI, EDX, ECX, EBX,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef _M_X64
|
||||
static X64Reg allocationOrderR15[ARRAY_SIZE(allocationOrder) + 1] = {INVALID_REG};
|
||||
#endif
|
||||
|
||||
void GPRRegCache::FlushBeforeCall() {
|
||||
// TODO: Only flush the non-preserved-by-callee registers.
|
||||
Flush();
|
||||
@ -55,6 +58,13 @@ GPRRegCache::GPRRegCache() : mips(0), emit(0) {
|
||||
}
|
||||
|
||||
void GPRRegCache::Start(MIPSState *mips, MIPSComp::JitState *js, MIPSComp::JitOptions *jo, MIPSAnalyst::AnalysisResults &stats) {
|
||||
#ifdef _M_X64
|
||||
if (allocationOrderR15[0] == INVALID_REG) {
|
||||
memcpy(allocationOrderR15, allocationOrder, sizeof(allocationOrder));
|
||||
allocationOrderR15[ARRAY_SIZE(allocationOrderR15) - 1] = R15;
|
||||
}
|
||||
#endif
|
||||
|
||||
this->mips = mips;
|
||||
for (int i = 0; i < NUM_X_REGS; i++) {
|
||||
xregs[i].free = true;
|
||||
@ -126,13 +136,13 @@ void GPRRegCache::UnlockAllX() {
|
||||
|
||||
X64Reg GPRRegCache::FindBestToSpill(bool unusedOnly, bool *clobbered) {
|
||||
int allocCount;
|
||||
const int *allocOrder = GetAllocationOrder(allocCount);
|
||||
const X64Reg *allocOrder = GetAllocationOrder(allocCount);
|
||||
|
||||
static const int UNUSED_LOOKAHEAD_OPS = 30;
|
||||
|
||||
*clobbered = false;
|
||||
for (int i = 0; i < allocCount; i++) {
|
||||
X64Reg reg = (X64Reg)allocOrder[i];
|
||||
X64Reg reg = allocOrder[i];
|
||||
if (xregs[reg].allocLocked)
|
||||
continue;
|
||||
if (xregs[reg].mipsReg != MIPS_REG_INVALID && regs[xregs[reg].mipsReg].locked)
|
||||
@ -158,13 +168,13 @@ X64Reg GPRRegCache::FindBestToSpill(bool unusedOnly, bool *clobbered) {
|
||||
X64Reg GPRRegCache::GetFreeXReg()
|
||||
{
|
||||
int aCount;
|
||||
const int *aOrder = GetAllocationOrder(aCount);
|
||||
const X64Reg *aOrder = GetAllocationOrder(aCount);
|
||||
for (int i = 0; i < aCount; i++)
|
||||
{
|
||||
X64Reg xr = (X64Reg)aOrder[i];
|
||||
X64Reg xr = aOrder[i];
|
||||
if (!xregs[xr].allocLocked && xregs[xr].free)
|
||||
{
|
||||
return (X64Reg)xr;
|
||||
return xr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -255,8 +265,14 @@ u32 GPRRegCache::GetImm(MIPSGPReg preg) const {
|
||||
return regs[preg].location.GetImmValue();
|
||||
}
|
||||
|
||||
const int *GPRRegCache::GetAllocationOrder(int &count) {
|
||||
count = sizeof(allocationOrder) / sizeof(const int);
|
||||
const X64Reg *GPRRegCache::GetAllocationOrder(int &count) {
|
||||
#ifdef _M_X64
|
||||
if (!jo_->reserveR15ForAsm) {
|
||||
count = ARRAY_SIZE(allocationOrderR15);
|
||||
return allocationOrderR15;
|
||||
}
|
||||
#endif
|
||||
count = ARRAY_SIZE(allocationOrder);
|
||||
return allocationOrder;
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ public:
|
||||
private:
|
||||
Gen::X64Reg GetFreeXReg();
|
||||
Gen::X64Reg FindBestToSpill(bool unusedOnly, bool *clobbered);
|
||||
const int *GetAllocationOrder(int &count);
|
||||
const Gen::X64Reg *GetAllocationOrder(int &count);
|
||||
|
||||
MIPSCachedReg regs[X64JitConstants::NUM_MIPS_GPRS];
|
||||
X64CachedReg xregs[X64JitConstants::NUM_X_REGS];
|
||||
|
Loading…
Reference in New Issue
Block a user