Merge pull request #7192 from unknownbrackets/jit-minor

x86jit: Free up a reg and cut some bytes from asm
This commit is contained in:
Henrik Rydgård 2014-12-18 22:21:40 +01:00
commit 9f86148792
7 changed files with 77 additions and 45 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -51,6 +51,7 @@ struct JitOptions
bool continueJumps;
int continueMaxInstructions;
bool enableVFPUSIMD;
bool reserveR15ForAsm;
};
// TODO: Hmm, humongous.

View File

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

View File

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