x86/x64: Don't use a separate code block for pregenerated functions, just like on ARM

This commit is contained in:
Henrik Rydgard 2015-10-08 22:15:28 +02:00
parent c41baab747
commit 7fee5abf9f
10 changed files with 84 additions and 136 deletions

View file

@ -1091,7 +1091,6 @@ elseif(ARM64)
elseif(X86)
set(CoreExtra ${CoreExtra}
Core/MIPS/x86/Asm.cpp
Core/MIPS/x86/Asm.h
Core/MIPS/x86/CompALU.cpp
Core/MIPS/x86/CompBranch.cpp
Core/MIPS/x86/CompFPU.cpp

View file

@ -679,7 +679,6 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="MIPS\x86\Asm.h" />
<ClInclude Include="MIPS\x86\JitSafeMem.h" />
<ClInclude Include="MIPS\x86\RegCacheFPU.h" />
<ClInclude Include="MIPS\x86\Jit.h" />

View file

@ -666,9 +666,6 @@
<ClInclude Include="MIPS\x86\Jit.h">
<Filter>MIPS\x86</Filter>
</ClInclude>
<ClInclude Include="MIPS\x86\Asm.h">
<Filter>MIPS\x86</Filter>
</ClInclude>
<ClInclude Include="MIPS\x86\RegCache.h">
<Filter>MIPS\x86</Filter>
</ClInclude>

View file

@ -46,7 +46,6 @@
#if defined(_M_IX86) || defined(_M_X64)
#include "Common/x64Analyzer.h"
#include "Core/MIPS/x86/Asm.h"
#endif
// #include "JitBase.h"
@ -593,7 +592,7 @@ void JitBlockCache::DestroyBlock(int block_num, bool invalidate) {
// Spurious entrances from previously linked blocks can only come through checkedEntry
XEmitter emit((u8 *)b->checkedEntry);
emit.MOV(32, M(&mips_->pc), Imm32(b->originalAddress));
emit.JMP(MIPSComp::jit->Asm().dispatcher, true);
emit.JMP(MIPSComp::jit->GetDispatcher(), true);
#elif defined(ARM64)

View file

@ -154,15 +154,12 @@ const char *ppsspp_resolver(struct ud*,
*offset = addr - (uint64_t)(&currentMIPS->v[0]);
return "mips.v";
}
// But these do.
if (MIPSComp::jit->IsInSpace((u8 *)(intptr_t)addr)) {
*offset = addr - (uint64_t)MIPSComp::jit->GetBasePtr();
return "jitcode";
}
if (MIPSComp::jit->Asm().IsInSpace((u8 *)(intptr_t)addr)) {
*offset = addr - (uint64_t)MIPSComp::jit->Asm().GetBasePtr();
return "dispatcher";
}
return NULL;
}

View file

@ -28,12 +28,16 @@
#include "Common/MemoryUtil.h"
#include "Core/MIPS/JitCommon/JitCommon.h"
#include "Core/MIPS/x86/Asm.h"
#include "Core/MIPS/x86/Jit.h"
using namespace Gen;
using namespace X64JitConstants;
extern volatile CoreState coreState;
namespace MIPSComp
{
//TODO - make an option
//#if _DEBUG
static bool enableDebug = false;
@ -54,25 +58,23 @@ static bool enableDebug = false;
//R14 - Pointer to fpr/gpr regs
//R15 - Pointer to array of block pointers
extern volatile CoreState coreState;
void ImHere() {
DEBUG_LOG(CPU, "JIT Here: %08x", currentMIPS->pc);
}
void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit, MIPSComp::JitOptions *jo) {
void Jit::GenerateFixedCode(JitOptions &jo) {
const u8 *start = AlignCode16();
restoreRoundingMode = AlignCode16(); {
STMXCSR(M(&mips->temp));
STMXCSR(M(&mips_->temp));
// Clear the rounding mode and flush-to-zero bits back to 0.
AND(32, M(&mips->temp), Imm32(~(7 << 13)));
LDMXCSR(M(&mips->temp));
AND(32, M(&mips_->temp), Imm32(~(7 << 13)));
LDMXCSR(M(&mips_->temp));
RET();
}
applyRoundingMode = AlignCode16(); {
MOV(32, R(EAX), M(&mips->fcr31));
MOV(32, R(EAX), M(&mips_->fcr31));
AND(32, R(EAX), Imm32(0x1000003));
// If it's 0, we don't actually bother setting. This is the most common.
@ -80,7 +82,7 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit, MIPSComp::
// flush-to-zero disabled.
FixupBranch skip = J_CC(CC_Z);
STMXCSR(M(&mips->temp));
STMXCSR(M(&mips_->temp));
// The MIPS bits don't correspond exactly, so we have to adjust.
// 0 -> 0 (skip2), 1 -> 3, 2 -> 2 (skip2), 3 -> 1
@ -90,14 +92,14 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit, MIPSComp::
SetJumpTarget(skip2);
SHL(32, R(EAX), Imm8(13));
OR(32, M(&mips->temp), R(EAX));
OR(32, M(&mips_->temp), R(EAX));
TEST(32, M(&mips->fcr31), Imm32(1 << 24));
TEST(32, M(&mips_->fcr31), Imm32(1 << 24));
FixupBranch skip3 = J_CC(CC_Z);
OR(32, M(&mips->temp), Imm32(1 << 15));
OR(32, M(&mips_->temp), Imm32(1 << 15));
SetJumpTarget(skip3);
LDMXCSR(M(&mips->temp));
LDMXCSR(M(&mips_->temp));
SetJumpTarget(skip);
RET();
}
@ -105,14 +107,14 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit, MIPSComp::
updateRoundingMode = AlignCode16(); {
// If it's only ever 0, we don't actually bother applying or restoring it.
// This is the most common situation.
TEST(32, M(&mips->fcr31), Imm32(0x01000003));
TEST(32, M(&mips_->fcr31), Imm32(0x01000003));
FixupBranch skip = J_CC(CC_Z);
#ifdef _M_X64
// TODO: Move the hasSetRounding flag somewhere we can reach it through the context pointer, or something.
MOV(64, R(RAX), Imm64((uintptr_t)&jit->js.hasSetRounding));
MOV(64, R(RAX), Imm64((uintptr_t)&js.hasSetRounding));
MOV(8, MatR(RAX), Imm8(1));
#else
MOV(8, M(&jit->js.hasSetRounding), Imm8(1));
MOV(8, M(&js.hasSetRounding), Imm8(1));
#endif
SetJumpTarget(skip);
@ -124,20 +126,19 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit, MIPSComp::
#ifdef _M_X64
// Two statically allocated registers.
MOV(64, R(MEMBASEREG), ImmPtr(Memory::base));
uintptr_t jitbase = (uintptr_t)jit->GetBasePtr();
if (jitbase > 0x7FFFFFFFULL)
{
MOV(64, R(JITBASEREG), ImmPtr(jit->GetBasePtr()));
jo->reserveR15ForAsm = true;
uintptr_t jitbase = (uintptr_t)GetBasePtr();
if (jitbase > 0x7FFFFFFFULL) {
MOV(64, R(JITBASEREG), ImmPtr(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]));
MOV(PTRBITS, R(CTXREG), ImmPtr(&mips_->f[0]));
outerLoop = GetCodePtr();
jit->RestoreRoundingMode(true, this);
RestoreRoundingMode(true);
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
jit->ApplyRoundingMode(true, this);
ApplyRoundingMode(true);
FixupBranch skipToRealDispatch = J(); //skip the sync and compare first time
dispatcherCheckCoreState = GetCodePtr();
@ -161,7 +162,7 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit, MIPSComp::
dispatcherNoCheck = GetCodePtr();
MOV(32, R(EAX), M(&mips->pc));
MOV(32, R(EAX), M(&mips_->pc));
dispatcherInEAXNoCheck = GetCodePtr();
#ifdef _M_IX86
@ -178,14 +179,14 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit, MIPSComp::
FixupBranch notfound = J_CC(CC_NE);
if (enableDebug)
{
ADD(32, M(&mips->debugCount), Imm8(1));
ADD(32, M(&mips_->debugCount), Imm8(1));
}
//grab from list and jump to it
AND(32, R(EAX), Imm32(MIPS_EMUHACK_VALUE_MASK));
#ifdef _M_IX86
ADD(32, R(EAX), ImmPtr(jit->GetBasePtr()));
ADD(32, R(EAX), ImmPtr(GetBasePtr()));
#elif _M_X64
if (jo->reserveR15ForAsm)
if (jo.reserveR15ForAsm)
ADD(64, R(RAX), R(JITBASEREG));
else
ADD(64, R(EAX), Imm32(jitbase));
@ -194,9 +195,9 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit, MIPSComp::
SetJumpTarget(notfound);
//Ok, no block, let's jit
jit->RestoreRoundingMode(true, this);
RestoreRoundingMode(true);
ABI_CallFunction(&MIPSComp::JitAt);
jit->ApplyRoundingMode(true, this);
ApplyRoundingMode(true);
JMP(dispatcherNoCheck, true); // Let's just dispatch again, we'll enter the block since we know it's there.
SetJumpTarget(bail);
@ -206,12 +207,14 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit, MIPSComp::
J_CC(CC_Z, outerLoop, true);
SetJumpTarget(badCoreState);
jit->RestoreRoundingMode(true, this);
RestoreRoundingMode(true);
ABI_PopAllCalleeSavedRegsAndAdjustStack();
RET();
breakpointBailout = GetCodePtr();
jit->RestoreRoundingMode(true, this);
RestoreRoundingMode(true);
ABI_PopAllCalleeSavedRegsAndAdjustStack();
RET();
}
} // namespace

View file

@ -1,54 +0,0 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once
#include "Common/x64Emitter.h"
#include "Core/MIPS/MIPS.h"
// Runtime generated assembly routines, like the Dispatcher.
namespace MIPSComp {
class Jit;
struct JitOptions;
}
class AsmRoutineManager : public Gen::XCodeBlock {
private:
void Generate(MIPSState *mips, MIPSComp::Jit *jit, MIPSComp::JitOptions *jo);
public:
void Init(MIPSState *mips, MIPSComp::Jit *jit, MIPSComp::JitOptions *jo) {
AllocCodeSpace(8192);
Generate(mips, jit, jo);
WriteProtect();
}
const u8 *enterDispatcher;
const u8 *outerLoop;
const u8 *dispatcher;
const u8 *dispatcherCheckCoreState;
const u8 *dispatcherNoCheck;
const u8 *dispatcherInEAXNoCheck;
const u8 *breakpointBailout;
const u8 *restoreRoundingMode;
const u8 *applyRoundingMode;
const u8 *updateRoundingMode;
};

View file

@ -119,13 +119,13 @@ static void JitLogMiss(MIPSOpcode op)
// JitBlockCache doesn't use this, just stores it.
#pragma warning(disable:4355)
#endif
Jit::Jit(MIPSState *mips) : blocks(mips, this), mips_(mips)
{
Jit::Jit(MIPSState *mips)
: blocks(mips, this), mips_(mips) {
blocks.Init();
gpr.SetEmitter(this);
fpr.SetEmitter(this);
AllocCodeSpace(1024 * 1024 * 16);
asm_.Init(mips, this, &jo);
GenerateFixedCode(jo);
safeMemFuncs.Init(&thunks);
js.startDefaultPrefix = mips_->HasDefaultPrefix();
@ -220,34 +220,29 @@ void Jit::WriteDowncount(int offset)
SUB(32, M(&mips_->downcount), downcount > 127 ? Imm32(downcount) : Imm8(downcount));
}
void Jit::RestoreRoundingMode(bool force, XEmitter *emitter) {
void Jit::RestoreRoundingMode(bool force) {
// If the game has never set an interesting rounding mode, we can safely skip this.
if (force || js.hasSetRounding) {
if (emitter == NULL)
emitter = this;
emitter->CALL(asm_.restoreRoundingMode);
CALL(restoreRoundingMode);
}
}
void Jit::ApplyRoundingMode(bool force, XEmitter *emitter) {
void Jit::ApplyRoundingMode(bool force) {
// If the game has never set an interesting rounding mode, we can safely skip this.
if (force || js.hasSetRounding) {
if (emitter == NULL)
emitter = this;
emitter->CALL(asm_.applyRoundingMode);
CALL(applyRoundingMode);
}
}
void Jit::UpdateRoundingMode(XEmitter *emitter) {
if (emitter == NULL)
emitter = this;
emitter->CALL(asm_.updateRoundingMode);
void Jit::UpdateRoundingMode() {
CALL(updateRoundingMode);
}
void Jit::ClearCache()
{
blocks.Clear();
ClearCodeSpace();
GenerateFixedCode(jo);
}
void Jit::InvalidateCache()
@ -337,7 +332,7 @@ void Jit::Compile(u32 em_address)
void Jit::RunLoopUntil(u64 globalticks)
{
PROFILE_THIS_SCOPE("jit");
((void (*)())asm_.enterDispatcher)();
((void (*)())enterDispatcher)();
}
u32 Jit::GetCompilerPC() {
@ -367,7 +362,7 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b)
// Downcount flag check. The last block decremented downcounter, and the flag should still be available.
FixupBranch skip = J_CC(CC_NS);
MOV(32, M(&mips_->pc), Imm32(js.blockStart));
JMP(asm_.outerLoop, true); // downcount hit zero - go advance.
JMP(outerLoop, true); // downcount hit zero - go advance.
SetJumpTarget(skip);
b->normalEntry = GetCodePtr();
@ -445,15 +440,13 @@ void Jit::AddContinuedBlock(u32 dest)
js.lastContinuedPC = dest;
}
bool Jit::DescribeCodePtr(const u8 *ptr, std::string &name)
{
bool Jit::DescribeCodePtr(const u8 *ptr, std::string &name) {
u32 jitAddr = blocks.GetAddressFromBlockPtr(ptr);
// Returns 0 when it's valid, but unknown.
if (jitAddr == 0)
name = "UnknownOrDeletedBlock";
else if (jitAddr != (u32)-1)
{
else if (jitAddr != (u32)-1) {
char temp[1024];
const std::string label = symbolMap.GetDescription(jitAddr);
if (!label.empty())
@ -462,7 +455,7 @@ bool Jit::DescribeCodePtr(const u8 *ptr, std::string &name)
snprintf(temp, sizeof(temp), "%08x", jitAddr);
name = temp;
}
else if (asm_.IsInSpace(ptr))
else if (IsInSpace(ptr))
name = "RunLoopUntil";
else if (thunks.IsInSpace(ptr))
name = "Thunk";
@ -660,7 +653,7 @@ void Jit::WriteExit(u32 destination, int exit_num)
} else {
// No blocklinking.
MOV(32, M(&mips_->pc), Imm32(destination));
JMP(asm_.dispatcher, true);
JMP(dispatcher, true);
// Normally, exits are 15 bytes (MOV + &pc + dest + JMP + dest) on 64 or 32 bit.
// But just in case we somehow optimized, pad.
@ -699,8 +692,8 @@ void Jit::WriteExitDestInReg(X64Reg reg)
// Need to set neg flag again.
SUB(32, M(&mips_->downcount), Imm8(0));
if (reg == EAX)
J_CC(CC_NS, asm_.dispatcherInEAXNoCheck, true);
JMP(asm_.dispatcher, true);
J_CC(CC_NS, dispatcherInEAXNoCheck, true);
JMP(dispatcher, true);
SetJumpTarget(tooLow);
SetJumpTarget(tooHigh);
@ -717,15 +710,15 @@ void Jit::WriteExitDestInReg(X64Reg reg)
}
SUB(32, M(&mips_->downcount), Imm8(0));
JMP(asm_.dispatcherCheckCoreState, true);
JMP(dispatcherCheckCoreState, true);
}
else if (reg == EAX)
{
J_CC(CC_NS, asm_.dispatcherInEAXNoCheck, true);
JMP(asm_.dispatcher, true);
J_CC(CC_NS, dispatcherInEAXNoCheck, true);
JMP(dispatcher, true);
}
else
JMP(asm_.dispatcher, true);
JMP(dispatcher, true);
}
void Jit::WriteSyscallExit()
@ -736,7 +729,7 @@ void Jit::WriteSyscallExit()
ABI_CallFunction(&JitMemCheckCleanup);
ApplyRoundingMode();
}
JMP(asm_.dispatcherCheckCoreState, true);
JMP(dispatcherCheckCoreState, true);
}
bool Jit::CheckJitBreakpoint(u32 addr, int downcountOffset)
@ -756,7 +749,7 @@ bool Jit::CheckJitBreakpoint(u32 addr, int downcountOffset)
ApplyRoundingMode();
// Just to fix the stack.
LOAD_FLAGS;
JMP(asm_.dispatcherCheckCoreState, true);
JMP(dispatcherCheckCoreState, true);
SetJumpTarget(skip);
ApplyRoundingMode();

View file

@ -20,7 +20,6 @@
#include "Common/CommonTypes.h"
#include "Common/Thunk.h"
#include "Common/x64Emitter.h"
#include "Core/MIPS/x86/Asm.h"
#if defined(ARM)
#error DO NOT BUILD X86 JIT ON ARM
@ -156,12 +155,11 @@ public:
void GetVectorRegsPrefixD(u8 *regs, VectorSize sz, int vectorReg);
void EatPrefix() { js.EatPrefix(); }
void RestoreRoundingMode(bool force = false, XEmitter *emitter = NULL);
void ApplyRoundingMode(bool force = false, XEmitter *emitter = NULL);
void UpdateRoundingMode(XEmitter *emitter = NULL);
void RestoreRoundingMode(bool force = false);
void ApplyRoundingMode(bool force = false);
void UpdateRoundingMode();
JitBlockCache *GetBlockCache() { return &blocks; }
AsmRoutineManager &Asm() { return asm_; }
void ClearCache();
void InvalidateCache();
@ -171,7 +169,12 @@ public:
}
}
const u8 *GetDispatcher() const {
return dispatcher;
}
private:
void GenerateFixedCode(JitOptions &jo);
void GetStateAndFlushAll(RegCacheState &state);
void RestoreState(const RegCacheState& state);
void FlushAll();
@ -295,15 +298,28 @@ private:
GPRRegCache gpr;
FPURegCache fpr;
AsmRoutineManager asm_;
ThunkManager thunks;
JitSafeMemFuncs safeMemFuncs;
MIPSState *mips_;
const u8 *enterDispatcher;
const u8 *outerLoop;
const u8 *dispatcher;
const u8 *dispatcherCheckCoreState;
const u8 *dispatcherNoCheck;
const u8 *dispatcherInEAXNoCheck;
const u8 *breakpointBailout;
const u8 *restoreRoundingMode;
const u8 *applyRoundingMode;
const u8 *updateRoundingMode;
friend class JitSafeMem;
friend class JitSafeMemFuncs;
friend class AsmRoutineManager;
};
} // namespace MIPSComp

View file

@ -23,7 +23,6 @@
#include "Core/MIPS/MIPSTables.h"
#include "Core/MIPS/MIPSAnalyst.h"
#include "Core/MIPS/x86/Jit.h"
#include "Core/MIPS/x86/Asm.h"
#include "Core/MIPS/x86/RegCache.h"
using namespace Gen;