ARMJIT Experiment: Keep downcount in a register. Needs benchmarking.

This commit is contained in:
Henrik Rydgard 2013-07-27 17:27:26 +02:00
parent fe090e8d95
commit 76a937f489
6 changed files with 76 additions and 23 deletions

View file

@ -116,12 +116,14 @@ void Jit::GenerateFixedCode()
MOVI2R(R11, (u32)Memory::base);
MOVI2R(R10, (u32)mips_);
MOVI2R(R9, (u32)GetBasePtr());
RestoreDowncount();
MovFromPC(R0);
outerLoopPCInR0 = GetCodePtr();
MovToPC(R0);
outerLoop = GetCodePtr();
SaveDowncount();
QuickCallFunction(R0, (void *)&CoreTiming::Advance);
RestoreDowncount();
FixupBranch skipToRealDispatch = B(); //skip the sync and compare first time
dispatcherCheckCoreState = GetCodePtr();
@ -174,7 +176,9 @@ void Jit::GenerateFixedCode()
SetCC(CC_AL);
//Ok, no block, let's jit
SaveDowncount();
QuickCallFunction(R2, (void *)&JitAt);
RestoreDowncount();
B(dispatcherNoCheck); // no point in special casing this
@ -187,8 +191,8 @@ void Jit::GenerateFixedCode()
B_CC(CC_EQ, outerLoop);
SetJumpTarget(badCoreState);
breakpointBailout = GetCodePtr();
SaveDowncount();
ADD(_SP, _SP, 4);

View file

@ -414,7 +414,9 @@ void Jit::Comp_Syscall(u32 op)
js.downcountAmount = -offset;
MOVI2R(R0, op);
SaveDowncount();
QuickCallFunction(R1, (void *)&CallSyscall);
RestoreDowncount();
WriteSyscallExit();
js.compiling = false;

View file

@ -56,7 +56,7 @@ void DisassembleArm(const u8 *data, int size) {
namespace MIPSComp
{
Jit::Jit(MIPSState *mips) : blocks(mips, this), gpr(mips), fpr(mips), mips_(mips)
Jit::Jit(MIPSState *mips) : blocks(mips, this), gpr(mips, &jo), fpr(mips), mips_(mips)
{
blocks.Init();
gpr.SetEmitter(this);
@ -286,10 +286,12 @@ void Jit::Comp_Generic(u32 op)
MIPSInterpretFunc func = MIPSGetInterpretFunc(op);
if (func)
{
SaveDowncount();
MOVI2R(R0, js.compilerPC);
MovToPC(R0);
MOVI2R(R0, op);
QuickCallFunction(R1, (void *)func);
RestoreDowncount();
}
// Might have eaten prefixes, hard to tell...
@ -305,21 +307,45 @@ void Jit::MovToPC(ARMReg r) {
STR(r, CTXREG, offsetof(MIPSState, pc));
}
void Jit::SaveDowncount() {
if (jo.downcountInRegister)
STR(R7, CTXREG, offsetof(MIPSState, downcount));
}
void Jit::RestoreDowncount() {
if (jo.downcountInRegister)
LDR(R7, CTXREG, offsetof(MIPSState, downcount));
}
void Jit::WriteDownCount(int offset)
{
int theDowncount = js.downcountAmount + offset;
LDR(R1, CTXREG, offsetof(MIPSState, downcount));
Operand2 op2;
if (TryMakeOperand2(theDowncount, op2)) // We can enlarge this if we used rotations
{
SUBS(R1, R1, op2);
STR(R1, CTXREG, offsetof(MIPSState, downcount));
if (jo.downcountInRegister) {
int theDowncount = js.downcountAmount + offset;
Operand2 op2;
if (TryMakeOperand2(theDowncount, op2)) // We can enlarge this if we used rotations
{
SUBS(R7, R7, op2);
} else {
// Should be fine to use R2 here, flushed the regcache anyway.
// If js.downcountAmount can be expressed as an Imm8, we don't need this anyway.
MOVI2R(R2, theDowncount);
SUBS(R7, R7, R2);
}
} else {
// Should be fine to use R2 here, flushed the regcache anyway.
// If js.downcountAmount can be expressed as an Imm8, we don't need this anyway.
MOVI2R(R2, theDowncount);
SUBS(R1, R1, R2);
STR(R1, CTXREG, offsetof(MIPSState, downcount));
int theDowncount = js.downcountAmount + offset;
LDR(R1, CTXREG, offsetof(MIPSState, downcount));
Operand2 op2;
if (TryMakeOperand2(theDowncount, op2)) // We can enlarge this if we used rotations
{
SUBS(R1, R1, op2);
STR(R1, CTXREG, offsetof(MIPSState, downcount));
} else {
// Should be fine to use R2 here, flushed the regcache anyway.
// If js.downcountAmount can be expressed as an Imm8, we don't need this anyway.
MOVI2R(R2, theDowncount);
SUBS(R1, R1, R2);
STR(R1, CTXREG, offsetof(MIPSState, downcount));
}
}
}

View file

@ -36,9 +36,11 @@ struct ArmJitOptions
ArmJitOptions()
{
enableBlocklink = true;
downcountInRegister = true;
}
bool enableBlocklink;
bool downcountInRegister;
};
struct ArmJitState
@ -230,6 +232,9 @@ private:
void MovFromPC(ARMReg r);
void MovToPC(ARMReg r);
void SaveDowncount();
void RestoreDowncount();
void WriteExit(u32 destination, int exit_num);
void WriteExitDestInR(ARMReg Reg);
void WriteSyscallExit();

View file

@ -17,6 +17,7 @@
#include "ArmRegCache.h"
#include "ArmEmitter.h"
#include "ArmJit.h"
#if defined(MAEMO)
#include "stddef.h"
@ -24,7 +25,7 @@
using namespace ArmGen;
ArmRegCache::ArmRegCache(MIPSState *mips) : mips_(mips) {
ArmRegCache::ArmRegCache(MIPSState *mips, MIPSComp::ArmJitOptions *options) : mips_(mips), options_(options) {
}
void ArmRegCache::Init(ARMXEmitter *emitter) {
@ -44,18 +45,26 @@ void ArmRegCache::Start(MIPSAnalyst::AnalysisResults &stats) {
}
}
static const ARMReg *GetMIPSAllocationOrder(int &count) {
const ARMReg *ArmRegCache::GetMIPSAllocationOrder(int &count) {
// Note that R0 is reserved as scratch for now.
// R1 could be used as it's only used for scratch outside "regalloc space" now.
// R12 is also potentially usable.
// R4-R7 are registers we could use for static allocation or downcount.
// R8 is used to preserve flags in nasty branches.
// R9 and upwards are reserved for jit basics.
static const ARMReg allocationOrder[] = {
R2, R3, R4, R5, R6, R7, R12,
};
count = sizeof(allocationOrder) / sizeof(const int);
return allocationOrder;
if (options_->downcountInRegister) {
static const ARMReg allocationOrder[] = {
R2, R3, R4, R5, R6, R12,
};
count = sizeof(allocationOrder) / sizeof(const int);
return allocationOrder;
} else {
static const ARMReg allocationOrder2[] = {
R2, R3, R4, R5, R6, R7, R12,
};
count = sizeof(allocationOrder2) / sizeof(const int);
return allocationOrder2;
}
}
// TODO: Somewhat smarter spilling - currently simply spills the first available, should do

View file

@ -68,10 +68,14 @@ enum {
MAP_NOINIT = 2,
};
namespace MIPSComp {
struct ArmJitOptions;
}
class ArmRegCache
{
public:
ArmRegCache(MIPSState *mips);
ArmRegCache(MIPSState *mips, MIPSComp::ArmJitOptions *options);
~ArmRegCache() {}
void Init(ARMXEmitter *emitter);
@ -107,7 +111,10 @@ public:
int GetMipsRegOffset(MIPSReg r);
private:
const ARMReg *GetMIPSAllocationOrder(int &count);
MIPSState *mips_;
MIPSComp::ArmJitOptions *options_;
ARMXEmitter *emit;
u32 compilerPC_;