Merge pull request #842 from lioncash/jit
Coding style clean up for the Jit, JitARM and JitIL
This commit is contained in:
commit
25e29c323d
|
@ -162,7 +162,9 @@ void Jit64::Init()
|
||||||
jo.enableBlocklink = false;
|
jo.enableBlocklink = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
jo.enableBlocklink = !Core::g_CoreStartupParameter.bMMU;
|
jo.enableBlocklink = !Core::g_CoreStartupParameter.bMMU;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
jo.fpAccurateFcmp = Core::g_CoreStartupParameter.bEnableFPRF;
|
jo.fpAccurateFcmp = Core::g_CoreStartupParameter.bEnableFPRF;
|
||||||
jo.optimizeGatherPipe = true;
|
jo.optimizeGatherPipe = true;
|
||||||
|
@ -435,7 +437,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||||
ABI_CallFunction((void *)&ImHere); //Used to get a trace of the last few blocks before a crash, sometimes VERY useful
|
ABI_CallFunction((void *)&ImHere); //Used to get a trace of the last few blocks before a crash, sometimes VERY useful
|
||||||
|
|
||||||
// Conditionally add profiling code.
|
// Conditionally add profiling code.
|
||||||
if (Profiler::g_ProfileBlocks) {
|
if (Profiler::g_ProfileBlocks)
|
||||||
|
{
|
||||||
ADD(32, M(&b->runCount), Imm8(1));
|
ADD(32, M(&b->runCount), Imm8(1));
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
b->ticCounter = 0;
|
b->ticCounter = 0;
|
||||||
|
@ -617,7 +620,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||||
//NOTICE_LOG(DYNA_REC, "Unflushed register: %s", ppc_inst.c_str());
|
//NOTICE_LOG(DYNA_REC, "Unflushed register: %s", ppc_inst.c_str());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (js.skipnext) {
|
if (js.skipnext)
|
||||||
|
{
|
||||||
js.skipnext = false;
|
js.skipnext = false;
|
||||||
i++; // Skip next instruction
|
i++; // Skip next instruction
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,18 +68,22 @@ public:
|
||||||
|
|
||||||
void ClearCache() override;
|
void ClearCache() override;
|
||||||
|
|
||||||
const u8 *GetDispatcher() {
|
const u8 *GetDispatcher()
|
||||||
|
{
|
||||||
return asm_routines.dispatcher;
|
return asm_routines.dispatcher;
|
||||||
}
|
}
|
||||||
const CommonAsmRoutines *GetAsmRoutines() override {
|
|
||||||
|
const CommonAsmRoutines *GetAsmRoutines() override
|
||||||
|
{
|
||||||
return &asm_routines;
|
return &asm_routines;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *GetName() override {
|
const char *GetName() override
|
||||||
|
{
|
||||||
return "JIT64";
|
return "JIT64";
|
||||||
}
|
}
|
||||||
// Run!
|
|
||||||
|
|
||||||
|
// Run!
|
||||||
void Run() override;
|
void Run() override;
|
||||||
void SingleStep() override;
|
void SingleStep() override;
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,15 @@ private:
|
||||||
void GenerateCommon();
|
void GenerateCommon();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void Init() {
|
void Init()
|
||||||
|
{
|
||||||
AllocCodeSpace(8192);
|
AllocCodeSpace(8192);
|
||||||
Generate();
|
Generate();
|
||||||
WriteProtect();
|
WriteProtect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown() {
|
void Shutdown()
|
||||||
|
{
|
||||||
FreeCodeSpace();
|
FreeCodeSpace();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -52,21 +52,35 @@ void RegCache::Start()
|
||||||
void RegCache::Lock(int p1, int p2, int p3, int p4)
|
void RegCache::Lock(int p1, int p2, int p3, int p4)
|
||||||
{
|
{
|
||||||
regs[p1].locked = true;
|
regs[p1].locked = true;
|
||||||
if (p2 != 0xFF) regs[p2].locked = true;
|
|
||||||
if (p3 != 0xFF) regs[p3].locked = true;
|
if (p2 != 0xFF)
|
||||||
if (p4 != 0xFF) regs[p4].locked = true;
|
regs[p2].locked = true;
|
||||||
|
|
||||||
|
if (p3 != 0xFF)
|
||||||
|
regs[p3].locked = true;
|
||||||
|
|
||||||
|
if (p4 != 0xFF)
|
||||||
|
regs[p4].locked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// these are x64 reg indices
|
// these are x64 reg indices
|
||||||
void RegCache::LockX(int x1, int x2, int x3, int x4)
|
void RegCache::LockX(int x1, int x2, int x3, int x4)
|
||||||
{
|
{
|
||||||
if (xregs[x1].locked) {
|
if (xregs[x1].locked)
|
||||||
|
{
|
||||||
PanicAlert("RegCache: x %i already locked!", x1);
|
PanicAlert("RegCache: x %i already locked!", x1);
|
||||||
}
|
}
|
||||||
|
|
||||||
xregs[x1].locked = true;
|
xregs[x1].locked = true;
|
||||||
if (x2 != 0xFF) xregs[x2].locked = true;
|
|
||||||
if (x3 != 0xFF) xregs[x3].locked = true;
|
if (x2 != 0xFF)
|
||||||
if (x4 != 0xFF) xregs[x4].locked = true;
|
xregs[x2].locked = true;
|
||||||
|
|
||||||
|
if (x3 != 0xFF)
|
||||||
|
xregs[x3].locked = true;
|
||||||
|
|
||||||
|
if (x4 != 0xFF)
|
||||||
|
xregs[x4].locked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::UnlockAll()
|
void RegCache::UnlockAll()
|
||||||
|
@ -321,6 +335,7 @@ void RegCache::Flush(FlushMode mode)
|
||||||
{
|
{
|
||||||
PanicAlert("Someone forgot to unlock PPC reg %" PRIx64 " (X64 reg %i).", i, RX(i));
|
PanicAlert("Someone forgot to unlock PPC reg %" PRIx64 " (X64 reg %i).", i, RX(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (regs[i].away)
|
if (regs[i].away)
|
||||||
{
|
{
|
||||||
if (regs[i].location.IsSimpleReg() || regs[i].location.IsImm())
|
if (regs[i].location.IsSimpleReg() || regs[i].location.IsImm())
|
||||||
|
|
|
@ -47,23 +47,34 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RegCache();
|
RegCache();
|
||||||
|
|
||||||
virtual ~RegCache() {}
|
virtual ~RegCache() {}
|
||||||
|
|
||||||
void Start();
|
void Start();
|
||||||
|
|
||||||
void DiscardRegContentsIfCached(size_t preg);
|
void DiscardRegContentsIfCached(size_t preg);
|
||||||
void SetEmitter(Gen::XEmitter *emitter) {emit = emitter;}
|
void SetEmitter(Gen::XEmitter *emitter)
|
||||||
|
{
|
||||||
|
emit = emitter;
|
||||||
|
}
|
||||||
|
|
||||||
void FlushR(Gen::X64Reg reg);
|
void FlushR(Gen::X64Reg reg);
|
||||||
void FlushR(Gen::X64Reg reg, Gen::X64Reg reg2) {FlushR(reg); FlushR(reg2);}
|
void FlushR(Gen::X64Reg reg, Gen::X64Reg reg2)
|
||||||
void FlushLockX(Gen::X64Reg reg) {
|
{
|
||||||
|
FlushR(reg);
|
||||||
|
FlushR(reg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlushLockX(Gen::X64Reg reg)
|
||||||
|
{
|
||||||
FlushR(reg);
|
FlushR(reg);
|
||||||
LockX(reg);
|
LockX(reg);
|
||||||
}
|
}
|
||||||
void FlushLockX(Gen::X64Reg reg1, Gen::X64Reg reg2) {
|
void FlushLockX(Gen::X64Reg reg1, Gen::X64Reg reg2)
|
||||||
|
{
|
||||||
FlushR(reg1); FlushR(reg2);
|
FlushR(reg1); FlushR(reg2);
|
||||||
LockX(reg1); LockX(reg2);
|
LockX(reg1); LockX(reg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Flush(FlushMode mode = FLUSH_ALL);
|
void Flush(FlushMode mode = FLUSH_ALL);
|
||||||
void Flush(PPCAnalyst::CodeOp *op) {Flush();}
|
void Flush(PPCAnalyst::CodeOp *op) {Flush();}
|
||||||
int SanityCheck() const;
|
int SanityCheck() const;
|
||||||
|
@ -76,7 +87,11 @@ public:
|
||||||
virtual void StoreRegister(size_t preg, Gen::OpArg newLoc) = 0;
|
virtual void StoreRegister(size_t preg, Gen::OpArg newLoc) = 0;
|
||||||
virtual void LoadRegister(size_t preg, Gen::X64Reg newLoc) = 0;
|
virtual void LoadRegister(size_t preg, Gen::X64Reg newLoc) = 0;
|
||||||
|
|
||||||
const Gen::OpArg &R(size_t preg) const {return regs[preg].location;}
|
const Gen::OpArg &R(size_t preg) const
|
||||||
|
{
|
||||||
|
return regs[preg].location;
|
||||||
|
}
|
||||||
|
|
||||||
Gen::X64Reg RX(size_t preg) const
|
Gen::X64Reg RX(size_t preg) const
|
||||||
{
|
{
|
||||||
if (IsBound(preg))
|
if (IsBound(preg))
|
||||||
|
|
|
@ -67,7 +67,8 @@ void Jit64::bx(UGeckoInstruction inst)
|
||||||
// If this is not the last instruction of a block,
|
// If this is not the last instruction of a block,
|
||||||
// we will skip the rest process.
|
// we will skip the rest process.
|
||||||
// Because PPCAnalyst::Flatten() merged the blocks.
|
// Because PPCAnalyst::Flatten() merged the blocks.
|
||||||
if (!js.isLastInstruction) {
|
if (!js.isLastInstruction)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,10 +136,13 @@ void Jit64::fmaddXX(UGeckoInstruction inst)
|
||||||
fpr.BindToRegister(d, false);
|
fpr.BindToRegister(d, false);
|
||||||
//YES it is necessary to dupe the result :(
|
//YES it is necessary to dupe the result :(
|
||||||
//TODO : analysis - does the top reg get used? If so, dupe, if not, don't.
|
//TODO : analysis - does the top reg get used? If so, dupe, if not, don't.
|
||||||
if (single_precision) {
|
if (single_precision)
|
||||||
|
{
|
||||||
ForceSinglePrecisionS(XMM0);
|
ForceSinglePrecisionS(XMM0);
|
||||||
MOVDDUP(fpr.RX(d), R(XMM0));
|
MOVDDUP(fpr.RX(d), R(XMM0));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
MOVSD(fpr.RX(d), R(XMM0));
|
MOVSD(fpr.RX(d), R(XMM0));
|
||||||
}
|
}
|
||||||
// SMB checks flags after this op. Let's lie.
|
// SMB checks flags after this op. Let's lie.
|
||||||
|
@ -159,7 +162,8 @@ void Jit64::fsign(UGeckoInstruction inst)
|
||||||
fpr.Lock(b, d);
|
fpr.Lock(b, d);
|
||||||
fpr.BindToRegister(d, true, true);
|
fpr.BindToRegister(d, true, true);
|
||||||
MOVSD(XMM0, fpr.R(b));
|
MOVSD(XMM0, fpr.R(b));
|
||||||
switch (inst.SUBOP10) {
|
switch (inst.SUBOP10)
|
||||||
|
{
|
||||||
case 40: // fnegx
|
case 40: // fnegx
|
||||||
PXOR(XMM0, M((void*)&psSignBits2));
|
PXOR(XMM0, M((void*)&psSignBits2));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -137,10 +137,26 @@ void Jit64::ComputeRC(const Gen::OpArg & arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 Add(u32 a, u32 b) {return a + b;}
|
// Following static functions are used in conjunction with regimmop
|
||||||
static u32 Or (u32 a, u32 b) {return a | b;}
|
static u32 Add(u32 a, u32 b)
|
||||||
static u32 And(u32 a, u32 b) {return a & b;}
|
{
|
||||||
static u32 Xor(u32 a, u32 b) {return a ^ b;}
|
return a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 Or(u32 a, u32 b)
|
||||||
|
{
|
||||||
|
return a | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 And(u32 a, u32 b)
|
||||||
|
{
|
||||||
|
return a & b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 Xor(u32 a, u32 b)
|
||||||
|
{
|
||||||
|
return a ^ b;
|
||||||
|
}
|
||||||
|
|
||||||
void Jit64::regimmop(int d, int a, bool binary, u32 value, Operation doop, void (XEmitter::*op)(int, const Gen::OpArg&, const Gen::OpArg&), bool Rc, bool carry)
|
void Jit64::regimmop(int d, int a, bool binary, u32 value, Operation doop, void (XEmitter::*op)(int, const Gen::OpArg&, const Gen::OpArg&), bool Rc, bool carry)
|
||||||
{
|
{
|
||||||
|
@ -196,7 +212,7 @@ void Jit64::reg_imm(UGeckoInstruction inst)
|
||||||
u32 d = inst.RD, a = inst.RA, s = inst.RS;
|
u32 d = inst.RD, a = inst.RA, s = inst.RS;
|
||||||
switch (inst.OPCD)
|
switch (inst.OPCD)
|
||||||
{
|
{
|
||||||
case 14: // addi
|
case 14: // addi
|
||||||
// occasionally used as MOV - emulate, with immediate propagation
|
// occasionally used as MOV - emulate, with immediate propagation
|
||||||
if (gpr.R(a).IsImm() && d != a && a != 0)
|
if (gpr.R(a).IsImm() && d != a && a != 0)
|
||||||
{
|
{
|
||||||
|
@ -244,18 +260,36 @@ void Jit64::reg_imm(UGeckoInstruction inst)
|
||||||
regimmop(d, a, false, (u32)inst.SIMM_16 << 16, Add, &XEmitter::ADD);
|
regimmop(d, a, false, (u32)inst.SIMM_16 << 16, Add, &XEmitter::ADD);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 24:
|
case 24: // ori
|
||||||
if (a == 0 && s == 0 && inst.UIMM == 0 && !inst.Rc) //check for nop
|
if (a == 0 && s == 0 && inst.UIMM == 0 && !inst.Rc) //check for nop
|
||||||
{NOP(); return;} //make the nop visible in the generated code. not much use but interesting if we see one.
|
{
|
||||||
|
// Make the nop visible in the generated code. not much use but interesting if we see one.
|
||||||
|
NOP();
|
||||||
|
return;
|
||||||
|
}
|
||||||
regimmop(a, s, true, inst.UIMM, Or, &XEmitter::OR);
|
regimmop(a, s, true, inst.UIMM, Or, &XEmitter::OR);
|
||||||
break; //ori
|
break;
|
||||||
case 25: regimmop(a, s, true, inst.UIMM << 16, Or, &XEmitter::OR, false); break;//oris
|
case 25: // oris
|
||||||
case 28: regimmop(a, s, true, inst.UIMM, And, &XEmitter::AND, true); break;
|
regimmop(a, s, true, inst.UIMM << 16, Or, &XEmitter::OR, false);
|
||||||
case 29: regimmop(a, s, true, inst.UIMM << 16, And, &XEmitter::AND, true); break;
|
break;
|
||||||
case 26: regimmop(a, s, true, inst.UIMM, Xor, &XEmitter::XOR, false); break; //xori
|
case 28: // andi
|
||||||
case 27: regimmop(a, s, true, inst.UIMM << 16, Xor, &XEmitter::XOR, false); break; //xoris
|
regimmop(a, s, true, inst.UIMM, And, &XEmitter::AND, true);
|
||||||
case 12: regimmop(d, a, false, (u32)(s32)inst.SIMM_16, Add, &XEmitter::ADD, false, true); break; //addic
|
break;
|
||||||
case 13: regimmop(d, a, true, (u32)(s32)inst.SIMM_16, Add, &XEmitter::ADD, true, true); break; //addic_rc
|
case 29: // andis
|
||||||
|
regimmop(a, s, true, inst.UIMM << 16, And, &XEmitter::AND, true);
|
||||||
|
break;
|
||||||
|
case 26: // xori
|
||||||
|
regimmop(a, s, true, inst.UIMM, Xor, &XEmitter::XOR, false);
|
||||||
|
break;
|
||||||
|
case 27: // xoris
|
||||||
|
regimmop(a, s, true, inst.UIMM << 16, Xor, &XEmitter::XOR, false);
|
||||||
|
break;
|
||||||
|
case 12: // addic
|
||||||
|
regimmop(d, a, false, (u32)(s32)inst.SIMM_16, Add, &XEmitter::ADD, false, true);
|
||||||
|
break;
|
||||||
|
case 13: // addic_rc
|
||||||
|
regimmop(d, a, true, (u32)(s32)inst.SIMM_16, Add, &XEmitter::ADD, true, true);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
FALLBACK_IF(true);
|
FALLBACK_IF(true);
|
||||||
}
|
}
|
||||||
|
@ -274,20 +308,23 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
||||||
int test_crf = js.next_inst.BI >> 2;
|
int test_crf = js.next_inst.BI >> 2;
|
||||||
// Check if the next instruction is a branch - if it is, merge the two.
|
// Check if the next instruction is a branch - if it is, merge the two.
|
||||||
if (((js.next_inst.OPCD == 16 /* bcx */) ||
|
if (((js.next_inst.OPCD == 16 /* bcx */) ||
|
||||||
((js.next_inst.OPCD == 19) && (js.next_inst.SUBOP10 == 528) /* bcctrx */) ||
|
((js.next_inst.OPCD == 19) && (js.next_inst.SUBOP10 == 528) /* bcctrx */) ||
|
||||||
((js.next_inst.OPCD == 19) && (js.next_inst.SUBOP10 == 16) /* bclrx */)) &&
|
((js.next_inst.OPCD == 19) && (js.next_inst.SUBOP10 == 16) /* bclrx */)) &&
|
||||||
(js.next_inst.BO & BO_DONT_DECREMENT_FLAG) &&
|
(js.next_inst.BO & BO_DONT_DECREMENT_FLAG) &&
|
||||||
!(js.next_inst.BO & BO_DONT_CHECK_CONDITION)) {
|
!(js.next_inst.BO & BO_DONT_CHECK_CONDITION))
|
||||||
|
{
|
||||||
// Looks like a decent conditional branch that we can merge with.
|
// Looks like a decent conditional branch that we can merge with.
|
||||||
// It only test CR, not CTR.
|
// It only test CR, not CTR.
|
||||||
if (test_crf == crf) {
|
if (test_crf == crf)
|
||||||
|
{
|
||||||
merge_branch = true;
|
merge_branch = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OpArg comparand;
|
OpArg comparand;
|
||||||
bool signedCompare;
|
bool signedCompare;
|
||||||
if (inst.OPCD == 31) {
|
if (inst.OPCD == 31)
|
||||||
|
{
|
||||||
// cmp / cmpl
|
// cmp / cmpl
|
||||||
gpr.Lock(a, b);
|
gpr.Lock(a, b);
|
||||||
comparand = gpr.R(b);
|
comparand = gpr.R(b);
|
||||||
|
@ -402,6 +439,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
||||||
MOV(64, R(RAX), Imm32((s32)gpr.R(a).offset));
|
MOV(64, R(RAX), Imm32((s32)gpr.R(a).offset));
|
||||||
else
|
else
|
||||||
MOVSX(64, 32, RAX, gpr.R(a));
|
MOVSX(64, 32, RAX, gpr.R(a));
|
||||||
|
|
||||||
if (!comparand.IsImm())
|
if (!comparand.IsImm())
|
||||||
{
|
{
|
||||||
MOVSX(64, 32, ABI_PARAM1, comparand);
|
MOVSX(64, 32, ABI_PARAM1, comparand);
|
||||||
|
@ -419,6 +457,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
||||||
MOV(32, R(ABI_PARAM1), comparand);
|
MOV(32, R(ABI_PARAM1), comparand);
|
||||||
else
|
else
|
||||||
MOVZX(64, 32, ABI_PARAM1, comparand);
|
MOVZX(64, 32, ABI_PARAM1, comparand);
|
||||||
|
|
||||||
comparand = R(ABI_PARAM1);
|
comparand = R(ABI_PARAM1);
|
||||||
}
|
}
|
||||||
SUB(64, R(RAX), comparand);
|
SUB(64, R(RAX), comparand);
|
||||||
|
@ -466,6 +505,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
if (js.next_inst.LK)
|
if (js.next_inst.LK)
|
||||||
MOV(32, M(&LR), Imm32(js.compilerPC + 4));
|
MOV(32, M(&LR), Imm32(js.compilerPC + 4));
|
||||||
|
|
||||||
MOV(32, R(EAX), M(&CTR));
|
MOV(32, R(EAX), M(&CTR));
|
||||||
AND(32, R(EAX), Imm32(0xFFFFFFFC));
|
AND(32, R(EAX), Imm32(0xFFFFFFFC));
|
||||||
WriteExitDestInEAX();
|
WriteExitDestInEAX();
|
||||||
|
@ -474,8 +514,10 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
MOV(32, R(EAX), M(&LR));
|
MOV(32, R(EAX), M(&LR));
|
||||||
AND(32, R(EAX), Imm32(0xFFFFFFFC));
|
AND(32, R(EAX), Imm32(0xFFFFFFFC));
|
||||||
|
|
||||||
if (js.next_inst.LK)
|
if (js.next_inst.LK)
|
||||||
MOV(32, M(&LR), Imm32(js.compilerPC + 4));
|
MOV(32, M(&LR), Imm32(js.compilerPC + 4));
|
||||||
|
|
||||||
WriteExitDestInEAX();
|
WriteExitDestInEAX();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -506,22 +548,23 @@ void Jit64::boolX(UGeckoInstruction inst)
|
||||||
|
|
||||||
if (gpr.R(s).IsImm() && gpr.R(b).IsImm())
|
if (gpr.R(s).IsImm() && gpr.R(b).IsImm())
|
||||||
{
|
{
|
||||||
if (inst.SUBOP10 == 28) /* andx */
|
if (inst.SUBOP10 == 28) // andx
|
||||||
gpr.SetImmediate32(a, (u32)gpr.R(s).offset & (u32)gpr.R(b).offset);
|
gpr.SetImmediate32(a, (u32)gpr.R(s).offset & (u32)gpr.R(b).offset);
|
||||||
else if (inst.SUBOP10 == 476) /* nandx */
|
else if (inst.SUBOP10 == 476) // nandx
|
||||||
gpr.SetImmediate32(a, ~((u32)gpr.R(s).offset & (u32)gpr.R(b).offset));
|
gpr.SetImmediate32(a, ~((u32)gpr.R(s).offset & (u32)gpr.R(b).offset));
|
||||||
else if (inst.SUBOP10 == 60) /* andcx */
|
else if (inst.SUBOP10 == 60) // andcx
|
||||||
gpr.SetImmediate32(a, (u32)gpr.R(s).offset & (~(u32)gpr.R(b).offset));
|
gpr.SetImmediate32(a, (u32)gpr.R(s).offset & (~(u32)gpr.R(b).offset));
|
||||||
else if (inst.SUBOP10 == 444) /* orx */
|
else if (inst.SUBOP10 == 444) // orx
|
||||||
gpr.SetImmediate32(a, (u32)gpr.R(s).offset | (u32)gpr.R(b).offset);
|
gpr.SetImmediate32(a, (u32)gpr.R(s).offset | (u32)gpr.R(b).offset);
|
||||||
else if (inst.SUBOP10 == 124) /* norx */
|
else if (inst.SUBOP10 == 124) // norx
|
||||||
gpr.SetImmediate32(a, ~((u32)gpr.R(s).offset | (u32)gpr.R(b).offset));
|
gpr.SetImmediate32(a, ~((u32)gpr.R(s).offset | (u32)gpr.R(b).offset));
|
||||||
else if (inst.SUBOP10 == 412) /* orcx */
|
else if (inst.SUBOP10 == 412) // orcx
|
||||||
gpr.SetImmediate32(a, (u32)gpr.R(s).offset | (~(u32)gpr.R(b).offset));
|
gpr.SetImmediate32(a, (u32)gpr.R(s).offset | (~(u32)gpr.R(b).offset));
|
||||||
else if (inst.SUBOP10 == 316) /* xorx */
|
else if (inst.SUBOP10 == 316) // xorx
|
||||||
gpr.SetImmediate32(a, (u32)gpr.R(s).offset ^ (u32)gpr.R(b).offset);
|
gpr.SetImmediate32(a, (u32)gpr.R(s).offset ^ (u32)gpr.R(b).offset);
|
||||||
else if (inst.SUBOP10 == 284) /* eqvx */
|
else if (inst.SUBOP10 == 284) // eqvx
|
||||||
gpr.SetImmediate32(a, ~((u32)gpr.R(s).offset ^ (u32)gpr.R(b).offset));
|
gpr.SetImmediate32(a, ~((u32)gpr.R(s).offset ^ (u32)gpr.R(b).offset));
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
{
|
{
|
||||||
ComputeRC(gpr.R(a));
|
ComputeRC(gpr.R(a));
|
||||||
|
@ -575,16 +618,16 @@ void Jit64::boolX(UGeckoInstruction inst)
|
||||||
OpArg operand = ((a == s) ? gpr.R(b) : gpr.R(s));
|
OpArg operand = ((a == s) ? gpr.R(b) : gpr.R(s));
|
||||||
gpr.BindToRegister(a, true, true);
|
gpr.BindToRegister(a, true, true);
|
||||||
|
|
||||||
if (inst.SUBOP10 == 28) /* andx */
|
if (inst.SUBOP10 == 28) // andx
|
||||||
{
|
{
|
||||||
AND(32, gpr.R(a), operand);
|
AND(32, gpr.R(a), operand);
|
||||||
}
|
}
|
||||||
else if (inst.SUBOP10 == 476) /* nandx */
|
else if (inst.SUBOP10 == 476) // nandx
|
||||||
{
|
{
|
||||||
AND(32, gpr.R(a), operand);
|
AND(32, gpr.R(a), operand);
|
||||||
NOT(32, gpr.R(a));
|
NOT(32, gpr.R(a));
|
||||||
}
|
}
|
||||||
else if (inst.SUBOP10 == 60) /* andcx */
|
else if (inst.SUBOP10 == 60) // andcx
|
||||||
{
|
{
|
||||||
if (a == b)
|
if (a == b)
|
||||||
{
|
{
|
||||||
|
@ -598,16 +641,16 @@ void Jit64::boolX(UGeckoInstruction inst)
|
||||||
AND(32, gpr.R(a), R(EAX));
|
AND(32, gpr.R(a), R(EAX));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (inst.SUBOP10 == 444) /* orx */
|
else if (inst.SUBOP10 == 444) // orx
|
||||||
{
|
{
|
||||||
OR(32, gpr.R(a), operand);
|
OR(32, gpr.R(a), operand);
|
||||||
}
|
}
|
||||||
else if (inst.SUBOP10 == 124) /* norx */
|
else if (inst.SUBOP10 == 124) // norx
|
||||||
{
|
{
|
||||||
OR(32, gpr.R(a), operand);
|
OR(32, gpr.R(a), operand);
|
||||||
NOT(32, gpr.R(a));
|
NOT(32, gpr.R(a));
|
||||||
}
|
}
|
||||||
else if (inst.SUBOP10 == 412) /* orcx */
|
else if (inst.SUBOP10 == 412) // orcx
|
||||||
{
|
{
|
||||||
if (a == b)
|
if (a == b)
|
||||||
{
|
{
|
||||||
|
@ -621,11 +664,11 @@ void Jit64::boolX(UGeckoInstruction inst)
|
||||||
OR(32, gpr.R(a), R(EAX));
|
OR(32, gpr.R(a), R(EAX));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (inst.SUBOP10 == 316) /* xorx */
|
else if (inst.SUBOP10 == 316) // xorx
|
||||||
{
|
{
|
||||||
XOR(32, gpr.R(a), operand);
|
XOR(32, gpr.R(a), operand);
|
||||||
}
|
}
|
||||||
else if (inst.SUBOP10 == 284) /* eqvx */
|
else if (inst.SUBOP10 == 284) // eqvx
|
||||||
{
|
{
|
||||||
NOT(32, gpr.R(a));
|
NOT(32, gpr.R(a));
|
||||||
XOR(32, gpr.R(a), operand);
|
XOR(32, gpr.R(a), operand);
|
||||||
|
@ -643,46 +686,46 @@ void Jit64::boolX(UGeckoInstruction inst)
|
||||||
gpr.Lock(a,s,b);
|
gpr.Lock(a,s,b);
|
||||||
gpr.BindToRegister(a, false, true);
|
gpr.BindToRegister(a, false, true);
|
||||||
|
|
||||||
if (inst.SUBOP10 == 28) /* andx */
|
if (inst.SUBOP10 == 28) // andx
|
||||||
{
|
{
|
||||||
MOV(32, gpr.R(a), gpr.R(s));
|
MOV(32, gpr.R(a), gpr.R(s));
|
||||||
AND(32, gpr.R(a), gpr.R(b));
|
AND(32, gpr.R(a), gpr.R(b));
|
||||||
}
|
}
|
||||||
else if (inst.SUBOP10 == 476) /* nandx */
|
else if (inst.SUBOP10 == 476) // nandx
|
||||||
{
|
{
|
||||||
MOV(32, gpr.R(a), gpr.R(s));
|
MOV(32, gpr.R(a), gpr.R(s));
|
||||||
AND(32, gpr.R(a), gpr.R(b));
|
AND(32, gpr.R(a), gpr.R(b));
|
||||||
NOT(32, gpr.R(a));
|
NOT(32, gpr.R(a));
|
||||||
}
|
}
|
||||||
else if (inst.SUBOP10 == 60) /* andcx */
|
else if (inst.SUBOP10 == 60) // andcx
|
||||||
{
|
{
|
||||||
MOV(32, gpr.R(a), gpr.R(b));
|
MOV(32, gpr.R(a), gpr.R(b));
|
||||||
NOT(32, gpr.R(a));
|
NOT(32, gpr.R(a));
|
||||||
AND(32, gpr.R(a), gpr.R(s));
|
AND(32, gpr.R(a), gpr.R(s));
|
||||||
}
|
}
|
||||||
else if (inst.SUBOP10 == 444) /* orx */
|
else if (inst.SUBOP10 == 444) // orx
|
||||||
{
|
{
|
||||||
MOV(32, gpr.R(a), gpr.R(s));
|
MOV(32, gpr.R(a), gpr.R(s));
|
||||||
OR(32, gpr.R(a), gpr.R(b));
|
OR(32, gpr.R(a), gpr.R(b));
|
||||||
}
|
}
|
||||||
else if (inst.SUBOP10 == 124) /* norx */
|
else if (inst.SUBOP10 == 124) // norx
|
||||||
{
|
{
|
||||||
MOV(32, gpr.R(a), gpr.R(s));
|
MOV(32, gpr.R(a), gpr.R(s));
|
||||||
OR(32, gpr.R(a), gpr.R(b));
|
OR(32, gpr.R(a), gpr.R(b));
|
||||||
NOT(32, gpr.R(a));
|
NOT(32, gpr.R(a));
|
||||||
}
|
}
|
||||||
else if (inst.SUBOP10 == 412) /* orcx */
|
else if (inst.SUBOP10 == 412) // orcx
|
||||||
{
|
{
|
||||||
MOV(32, gpr.R(a), gpr.R(b));
|
MOV(32, gpr.R(a), gpr.R(b));
|
||||||
NOT(32, gpr.R(a));
|
NOT(32, gpr.R(a));
|
||||||
OR(32, gpr.R(a), gpr.R(s));
|
OR(32, gpr.R(a), gpr.R(s));
|
||||||
}
|
}
|
||||||
else if (inst.SUBOP10 == 316) /* xorx */
|
else if (inst.SUBOP10 == 316) // xorx
|
||||||
{
|
{
|
||||||
MOV(32, gpr.R(a), gpr.R(s));
|
MOV(32, gpr.R(a), gpr.R(s));
|
||||||
XOR(32, gpr.R(a), gpr.R(b));
|
XOR(32, gpr.R(a), gpr.R(b));
|
||||||
}
|
}
|
||||||
else if (inst.SUBOP10 == 284) /* eqvx */
|
else if (inst.SUBOP10 == 284) // eqvx
|
||||||
{
|
{
|
||||||
MOV(32, gpr.R(a), gpr.R(s));
|
MOV(32, gpr.R(a), gpr.R(s));
|
||||||
NOT(32, gpr.R(a));
|
NOT(32, gpr.R(a));
|
||||||
|
@ -992,13 +1035,25 @@ void Jit64::mulli(UGeckoInstruction inst)
|
||||||
else if ((imm & (imm - 1)) == 0)
|
else if ((imm & (imm - 1)) == 0)
|
||||||
{
|
{
|
||||||
u32 shift = 0;
|
u32 shift = 0;
|
||||||
if (imm & 0xFFFF0000) shift |= 16;
|
|
||||||
if (imm & 0xFF00FF00) shift |= 8;
|
if (imm & 0xFFFF0000)
|
||||||
if (imm & 0xF0F0F0F0) shift |= 4;
|
shift |= 16;
|
||||||
if (imm & 0xCCCCCCCC) shift |= 2;
|
|
||||||
if (imm & 0xAAAAAAAA) shift |= 1;
|
if (imm & 0xFF00FF00)
|
||||||
|
shift |= 8;
|
||||||
|
|
||||||
|
if (imm & 0xF0F0F0F0)
|
||||||
|
shift |= 4;
|
||||||
|
|
||||||
|
if (imm & 0xCCCCCCCC)
|
||||||
|
shift |= 2;
|
||||||
|
|
||||||
|
if (imm & 0xAAAAAAAA)
|
||||||
|
shift |= 1;
|
||||||
|
|
||||||
if (d != a)
|
if (d != a)
|
||||||
MOV(32, gpr.R(d), gpr.R(a));
|
MOV(32, gpr.R(d), gpr.R(a));
|
||||||
|
|
||||||
if (shift)
|
if (shift)
|
||||||
SHL(32, gpr.R(d), Imm8(shift));
|
SHL(32, gpr.R(d), Imm8(shift));
|
||||||
}
|
}
|
||||||
|
@ -1047,13 +1102,25 @@ void Jit64::mullwx(UGeckoInstruction inst)
|
||||||
else if ((imm & (imm - 1)) == 0 && !inst.OE)
|
else if ((imm & (imm - 1)) == 0 && !inst.OE)
|
||||||
{
|
{
|
||||||
u32 shift = 0;
|
u32 shift = 0;
|
||||||
if (imm & 0xFFFF0000) shift |= 16;
|
|
||||||
if (imm & 0xFF00FF00) shift |= 8;
|
if (imm & 0xFFFF0000)
|
||||||
if (imm & 0xF0F0F0F0) shift |= 4;
|
shift |= 16;
|
||||||
if (imm & 0xCCCCCCCC) shift |= 2;
|
|
||||||
if (imm & 0xAAAAAAAA) shift |= 1;
|
if (imm & 0xFF00FF00)
|
||||||
|
shift |= 8;
|
||||||
|
|
||||||
|
if (imm & 0xF0F0F0F0)
|
||||||
|
shift |= 4;
|
||||||
|
|
||||||
|
if (imm & 0xCCCCCCCC)
|
||||||
|
shift |= 2;
|
||||||
|
|
||||||
|
if (imm & 0xAAAAAAAA)
|
||||||
|
shift |= 1;
|
||||||
|
|
||||||
if (d != src)
|
if (d != src)
|
||||||
MOV(32, gpr.R(d), gpr.R(src));
|
MOV(32, gpr.R(d), gpr.R(src));
|
||||||
|
|
||||||
if (shift)
|
if (shift)
|
||||||
SHL(32, gpr.R(d), Imm8(shift));
|
SHL(32, gpr.R(d), Imm8(shift));
|
||||||
}
|
}
|
||||||
|
@ -1517,7 +1584,7 @@ void Jit64::rlwinmx(UGeckoInstruction inst)
|
||||||
int s = inst.RS;
|
int s = inst.RS;
|
||||||
if (gpr.R(s).IsImm())
|
if (gpr.R(s).IsImm())
|
||||||
{
|
{
|
||||||
unsigned result = (int)gpr.R(s).offset;
|
u32 result = (int)gpr.R(s).offset;
|
||||||
if (inst.SH != 0)
|
if (inst.SH != 0)
|
||||||
result = _rotl(result, inst.SH);
|
result = _rotl(result, inst.SH);
|
||||||
result &= Helper_Mask(inst.MB, inst.ME);
|
result &= Helper_Mask(inst.MB, inst.ME);
|
||||||
|
@ -1554,6 +1621,7 @@ void Jit64::rlwinmx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
ROL(32, gpr.R(a), Imm8(inst.SH));
|
ROL(32, gpr.R(a), Imm8(inst.SH));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(inst.MB==0 && inst.ME==31))
|
if (!(inst.MB==0 && inst.ME==31))
|
||||||
{
|
{
|
||||||
AND(32, gpr.R(a), Imm32(Helper_Mask(inst.MB, inst.ME)));
|
AND(32, gpr.R(a), Imm32(Helper_Mask(inst.MB, inst.ME)));
|
||||||
|
@ -1604,10 +1672,12 @@ void Jit64::rlwimix(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
MOV(32, gpr.R(a), gpr.R(s));
|
MOV(32, gpr.R(a), gpr.R(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.SH)
|
if (inst.SH)
|
||||||
{
|
{
|
||||||
ROL(32, gpr.R(a), Imm8(inst.SH));
|
ROL(32, gpr.R(a), Imm8(inst.SH));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
{
|
{
|
||||||
ComputeRC(gpr.R(a));
|
ComputeRC(gpr.R(a));
|
||||||
|
@ -1637,6 +1707,7 @@ void Jit64::rlwimix(UGeckoInstruction inst)
|
||||||
AND(32, R(EAX), Imm32(mask));
|
AND(32, R(EAX), Imm32(mask));
|
||||||
XOR(32, gpr.R(a), R(EAX));
|
XOR(32, gpr.R(a), R(EAX));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(gpr.R(a));
|
ComputeRC(gpr.R(a));
|
||||||
}
|
}
|
||||||
|
@ -1700,6 +1771,7 @@ void Jit64::negx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
ComputeRC(gpr.R(d));
|
ComputeRC(gpr.R(d));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.OE)
|
if (inst.OE)
|
||||||
{
|
{
|
||||||
GenerateConstantOverflow(gpr.R(d).offset == 0x80000000);
|
GenerateConstantOverflow(gpr.R(d).offset == 0x80000000);
|
||||||
|
@ -1821,7 +1893,9 @@ void Jit64::srawx(UGeckoInstruction inst)
|
||||||
SetJumpTarget(nocarry);
|
SetJumpTarget(nocarry);
|
||||||
gpr.UnlockAll();
|
gpr.UnlockAll();
|
||||||
gpr.UnlockAllX();
|
gpr.UnlockAllX();
|
||||||
if (inst.Rc) {
|
|
||||||
|
if (inst.Rc)
|
||||||
|
{
|
||||||
ComputeRC(gpr.R(a));
|
ComputeRC(gpr.R(a));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1888,8 +1962,10 @@ void Jit64::cntlzwx(UGeckoInstruction inst)
|
||||||
u32 mask = 0x80000000;
|
u32 mask = 0x80000000;
|
||||||
u32 i = 0;
|
u32 i = 0;
|
||||||
for (; i < 32; i++, mask >>= 1)
|
for (; i < 32; i++, mask >>= 1)
|
||||||
|
{
|
||||||
if ((u32)gpr.R(s).offset & mask)
|
if ((u32)gpr.R(s).offset & mask)
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
gpr.SetImmediate32(a, i);
|
gpr.SetImmediate32(a, i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -30,26 +30,26 @@ void Jit64::lXXx(UGeckoInstruction inst)
|
||||||
bool signExtend = false;
|
bool signExtend = false;
|
||||||
switch (inst.OPCD)
|
switch (inst.OPCD)
|
||||||
{
|
{
|
||||||
case 32: /* lwz */
|
case 32: // lwz
|
||||||
case 33: /* lwzu */
|
case 33: // lwzu
|
||||||
accessSize = 32;
|
accessSize = 32;
|
||||||
signExtend = false;
|
signExtend = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 34: /* lbz */
|
case 34: // lbz
|
||||||
case 35: /* lbzu */
|
case 35: // lbzu
|
||||||
accessSize = 8;
|
accessSize = 8;
|
||||||
signExtend = false;
|
signExtend = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 40: /* lhz */
|
case 40: // lhz
|
||||||
case 41: /* lhzu */
|
case 41: // lhzu
|
||||||
accessSize = 16;
|
accessSize = 16;
|
||||||
signExtend = false;
|
signExtend = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 42: /* lha */
|
case 42: // lha
|
||||||
case 43: /* lhau */
|
case 43: // lhau
|
||||||
accessSize = 16;
|
accessSize = 16;
|
||||||
signExtend = true;
|
signExtend = true;
|
||||||
break;
|
break;
|
||||||
|
@ -57,25 +57,25 @@ void Jit64::lXXx(UGeckoInstruction inst)
|
||||||
case 31:
|
case 31:
|
||||||
switch (inst.SUBOP10)
|
switch (inst.SUBOP10)
|
||||||
{
|
{
|
||||||
case 23: /* lwzx */
|
case 23: // lwzx
|
||||||
case 55: /* lwzux */
|
case 55: // lwzux
|
||||||
accessSize = 32;
|
accessSize = 32;
|
||||||
signExtend = false;
|
signExtend = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 87: /* lbzx */
|
case 87: // lbzx
|
||||||
case 119: /* lbzux */
|
case 119: // lbzux
|
||||||
accessSize = 8;
|
accessSize = 8;
|
||||||
signExtend = false;
|
signExtend = false;
|
||||||
break;
|
break;
|
||||||
case 279: /* lhzx */
|
case 279: // lhzx
|
||||||
case 311: /* lhzux */
|
case 311: // lhzux
|
||||||
accessSize = 16;
|
accessSize = 16;
|
||||||
signExtend = false;
|
signExtend = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 343: /* lhax */
|
case 343: // lhax
|
||||||
case 375: /* lhaux */
|
case 375: // lhaux
|
||||||
accessSize = 16;
|
accessSize = 16;
|
||||||
signExtend = true;
|
signExtend = true;
|
||||||
break;
|
break;
|
||||||
|
@ -96,11 +96,11 @@ void Jit64::lXXx(UGeckoInstruction inst)
|
||||||
// ... maybe the throttle one already do that :p
|
// ... maybe the throttle one already do that :p
|
||||||
// if (CommandProcessor::AllowIdleSkipping() && PixelEngine::AllowIdleSkipping())
|
// if (CommandProcessor::AllowIdleSkipping() && PixelEngine::AllowIdleSkipping())
|
||||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle &&
|
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle &&
|
||||||
inst.OPCD == 32 &&
|
inst.OPCD == 32 &&
|
||||||
(inst.hex & 0xFFFF0000) == 0x800D0000 &&
|
(inst.hex & 0xFFFF0000) == 0x800D0000 &&
|
||||||
(Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x28000000 ||
|
(Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x28000000 ||
|
||||||
(SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x2C000000)) &&
|
(SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x2C000000)) &&
|
||||||
Memory::ReadUnchecked_U32(js.compilerPC + 8) == 0x4182fff8)
|
Memory::ReadUnchecked_U32(js.compilerPC + 8) == 0x4182fff8)
|
||||||
{
|
{
|
||||||
// TODO(LinesPrower):
|
// TODO(LinesPrower):
|
||||||
// - Rewrite this!
|
// - Rewrite this!
|
||||||
|
@ -259,10 +259,18 @@ void Jit64::stX(UGeckoInstruction inst)
|
||||||
int accessSize;
|
int accessSize;
|
||||||
switch (inst.OPCD & ~1)
|
switch (inst.OPCD & ~1)
|
||||||
{
|
{
|
||||||
case 36: accessSize = 32; break; //stw
|
case 36: // stw
|
||||||
case 44: accessSize = 16; break; //sth
|
accessSize = 32;
|
||||||
case 38: accessSize = 8; break; //stb
|
break;
|
||||||
default: _assert_msg_(DYNA_REC, 0, "AWETKLJASDLKF"); return;
|
case 44: // sth
|
||||||
|
accessSize = 16;
|
||||||
|
break;
|
||||||
|
case 38: // stb
|
||||||
|
accessSize = 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_assert_msg_(DYNA_REC, 0, "stX: Invalid access size.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((a == 0) || gpr.R(a).IsImm())
|
if ((a == 0) || gpr.R(a).IsImm())
|
||||||
|
@ -273,18 +281,27 @@ void Jit64::stX(UGeckoInstruction inst)
|
||||||
addr += offset;
|
addr += offset;
|
||||||
if ((addr & 0xFFFFF000) == 0xCC008000 && jo.optimizeGatherPipe)
|
if ((addr & 0xFFFFF000) == 0xCC008000 && jo.optimizeGatherPipe)
|
||||||
{
|
{
|
||||||
MOV(32, M(&PC), Imm32(jit->js.compilerPC)); // Helps external systems know which instruction triggered the write
|
// Helps external systems know which instruction triggered the write
|
||||||
|
MOV(32, M(&PC), Imm32(jit->js.compilerPC));
|
||||||
|
|
||||||
gpr.FlushLockX(ABI_PARAM1);
|
gpr.FlushLockX(ABI_PARAM1);
|
||||||
MOV(32, R(ABI_PARAM1), gpr.R(s));
|
MOV(32, R(ABI_PARAM1), gpr.R(s));
|
||||||
if (update)
|
if (update)
|
||||||
gpr.SetImmediate32(a, addr);
|
gpr.SetImmediate32(a, addr);
|
||||||
|
|
||||||
|
// No need to protect these, they don't touch any state
|
||||||
|
// question - should we inline them instead? Pro: Lose a CALL Con: Code bloat
|
||||||
switch (accessSize)
|
switch (accessSize)
|
||||||
{
|
{
|
||||||
// No need to protect these, they don't touch any state
|
case 8:
|
||||||
// question - should we inline them instead? Pro: Lose a CALL Con: Code bloat
|
CALL((void *)asm_routines.fifoDirectWrite8);
|
||||||
case 8: CALL((void *)asm_routines.fifoDirectWrite8); break;
|
break;
|
||||||
case 16: CALL((void *)asm_routines.fifoDirectWrite16); break;
|
case 16:
|
||||||
case 32: CALL((void *)asm_routines.fifoDirectWrite32); break;
|
CALL((void *)asm_routines.fifoDirectWrite16);
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
CALL((void *)asm_routines.fifoDirectWrite32);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
js.fifoBytesThisBlock += accessSize >> 3;
|
js.fifoBytesThisBlock += accessSize >> 3;
|
||||||
gpr.UnlockAllX();
|
gpr.UnlockAllX();
|
||||||
|
@ -300,14 +317,22 @@ void Jit64::stX(UGeckoInstruction inst)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MOV(32, M(&PC), Imm32(jit->js.compilerPC)); // Helps external systems know which instruction triggered the write
|
// Helps external systems know which instruction triggered the write
|
||||||
|
MOV(32, M(&PC), Imm32(jit->js.compilerPC));
|
||||||
|
|
||||||
u32 registersInUse = RegistersInUse();
|
u32 registersInUse = RegistersInUse();
|
||||||
ABI_PushRegistersAndAdjustStack(registersInUse, false);
|
ABI_PushRegistersAndAdjustStack(registersInUse, false);
|
||||||
switch (accessSize)
|
switch (accessSize)
|
||||||
{
|
{
|
||||||
case 32: ABI_CallFunctionAC(true ? ((void *)&Memory::Write_U32) : ((void *)&Memory::Write_U32_Swap), gpr.R(s), addr); break;
|
case 32:
|
||||||
case 16: ABI_CallFunctionAC(true ? ((void *)&Memory::Write_U16) : ((void *)&Memory::Write_U16_Swap), gpr.R(s), addr); break;
|
ABI_CallFunctionAC(true ? ((void *)&Memory::Write_U32) : ((void *)&Memory::Write_U32_Swap), gpr.R(s), addr);
|
||||||
case 8: ABI_CallFunctionAC((void *)&Memory::Write_U8, gpr.R(s), addr); break;
|
break;
|
||||||
|
case 16:
|
||||||
|
ABI_CallFunctionAC(true ? ((void *)&Memory::Write_U16) : ((void *)&Memory::Write_U16_Swap), gpr.R(s), addr);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
ABI_CallFunctionAC((void *)&Memory::Write_U8, gpr.R(s), addr);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
ABI_PopRegistersAndAdjustStack(registersInUse, false);
|
ABI_PopRegistersAndAdjustStack(registersInUse, false);
|
||||||
if (update)
|
if (update)
|
||||||
|
@ -359,17 +384,29 @@ void Jit64::stXx(UGeckoInstruction inst)
|
||||||
ADD(32, gpr.R(a), gpr.R(b));
|
ADD(32, gpr.R(a), gpr.R(b));
|
||||||
MOV(32, R(EDX), gpr.R(a));
|
MOV(32, R(EDX), gpr.R(a));
|
||||||
MEMCHECK_END
|
MEMCHECK_END
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
MOV(32, R(EDX), gpr.R(a));
|
MOV(32, R(EDX), gpr.R(a));
|
||||||
ADD(32, R(EDX), gpr.R(b));
|
ADD(32, R(EDX), gpr.R(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
int accessSize;
|
int accessSize;
|
||||||
switch (inst.SUBOP10 & ~32) {
|
switch (inst.SUBOP10 & ~32)
|
||||||
case 151: accessSize = 32; break;
|
{
|
||||||
case 407: accessSize = 16; break;
|
case 151:
|
||||||
case 215: accessSize = 8; break;
|
accessSize = 32;
|
||||||
default: PanicAlert("stXx: invalid access size");
|
break;
|
||||||
accessSize = 0; break;
|
case 407:
|
||||||
|
accessSize = 16;
|
||||||
|
break;
|
||||||
|
case 215:
|
||||||
|
accessSize = 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PanicAlert("stXx: invalid access size");
|
||||||
|
accessSize = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
MOV(32, R(ECX), gpr.R(s));
|
MOV(32, R(ECX), gpr.R(s));
|
||||||
|
|
|
@ -47,12 +47,15 @@ void Jit64::psq_st(UGeckoInstruction inst)
|
||||||
MOVZX(32, 8, EDX, R(AL));
|
MOVZX(32, 8, EDX, R(AL));
|
||||||
|
|
||||||
// FIXME: Fix ModR/M encoding to allow [EDX*4+disp32] without a base register!
|
// FIXME: Fix ModR/M encoding to allow [EDX*4+disp32] without a base register!
|
||||||
if (inst.W) {
|
if (inst.W)
|
||||||
|
{
|
||||||
// One value
|
// One value
|
||||||
PXOR(XMM0, R(XMM0)); // TODO: See if we can get rid of this cheaply by tweaking the code in the singleStore* functions.
|
PXOR(XMM0, R(XMM0)); // TODO: See if we can get rid of this cheaply by tweaking the code in the singleStore* functions.
|
||||||
CVTSD2SS(XMM0, fpr.R(s));
|
CVTSD2SS(XMM0, fpr.R(s));
|
||||||
CALLptr(MScaled(EDX, SCALE_8, (u32)(u64)asm_routines.singleStoreQuantized));
|
CALLptr(MScaled(EDX, SCALE_8, (u32)(u64)asm_routines.singleStoreQuantized));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Pair of values
|
// Pair of values
|
||||||
CVTPD2PS(XMM0, fpr.R(s));
|
CVTPD2PS(XMM0, fpr.R(s));
|
||||||
CALLptr(MScaled(EDX, SCALE_8, (u32)(u64)asm_routines.pairedStoreQuantized));
|
CALLptr(MScaled(EDX, SCALE_8, (u32)(u64)asm_routines.pairedStoreQuantized));
|
||||||
|
|
|
@ -156,12 +156,21 @@ void Jit64::ps_arith(UGeckoInstruction inst)
|
||||||
|
|
||||||
switch (inst.SUBOP5)
|
switch (inst.SUBOP5)
|
||||||
{
|
{
|
||||||
case 18: tri_op(inst.FD, inst.FA, inst.FB, false, &XEmitter::DIVPD); break; //div
|
case 18: // div
|
||||||
case 20: tri_op(inst.FD, inst.FA, inst.FB, false, &XEmitter::SUBPD); break; //sub
|
tri_op(inst.FD, inst.FA, inst.FB, false, &XEmitter::DIVPD);
|
||||||
case 21: tri_op(inst.FD, inst.FA, inst.FB, true, &XEmitter::ADDPD); break; //add
|
break;
|
||||||
case 25: tri_op(inst.FD, inst.FA, inst.FC, true, &XEmitter::MULPD); break; //mul
|
case 20: // sub
|
||||||
|
tri_op(inst.FD, inst.FA, inst.FB, false, &XEmitter::SUBPD);
|
||||||
|
break;
|
||||||
|
case 21: // add
|
||||||
|
tri_op(inst.FD, inst.FA, inst.FB, true, &XEmitter::ADDPD);
|
||||||
|
break;
|
||||||
|
case 25: // mul
|
||||||
|
tri_op(inst.FD, inst.FA, inst.FC, true, &XEmitter::MULPD);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
_assert_msg_(DYNA_REC, 0, "ps_arith WTF!!!");
|
_assert_msg_(DYNA_REC, 0, "ps_arith WTF!!!");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -174,8 +174,12 @@ namespace JitILProfiler
|
||||||
u64 codeHash;
|
u64 codeHash;
|
||||||
u64 totalElapsed;
|
u64 totalElapsed;
|
||||||
u64 numberOfCalls;
|
u64 numberOfCalls;
|
||||||
Block() : index(0), codeHash(0), totalElapsed(0), numberOfCalls(0) { }
|
|
||||||
|
Block() : index(0), codeHash(0), totalElapsed(0), numberOfCalls(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::vector<Block> blocks;
|
static std::vector<Block> blocks;
|
||||||
static u32 blockIndex;
|
static u32 blockIndex;
|
||||||
static u64 beginTime;
|
static u64 beginTime;
|
||||||
|
@ -188,6 +192,7 @@ namespace JitILProfiler
|
||||||
block.codeHash = codeHash;
|
block.codeHash = codeHash;
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
// These functions need to be static because they are called with
|
// These functions need to be static because they are called with
|
||||||
// ABI_CallFunction().
|
// ABI_CallFunction().
|
||||||
static void Begin(u32 index)
|
static void Begin(u32 index)
|
||||||
|
@ -195,6 +200,7 @@ namespace JitILProfiler
|
||||||
blockIndex = index;
|
blockIndex = index;
|
||||||
beginTime = __rdtsc();
|
beginTime = __rdtsc();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void End()
|
static void End()
|
||||||
{
|
{
|
||||||
const u64 endTime = __rdtsc();
|
const u64 endTime = __rdtsc();
|
||||||
|
@ -203,6 +209,7 @@ namespace JitILProfiler
|
||||||
block.totalElapsed += duration;
|
block.totalElapsed += duration;
|
||||||
++block.numberOfCalls;
|
++block.numberOfCalls;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct JitILProfilerFinalizer
|
struct JitILProfilerFinalizer
|
||||||
{
|
{
|
||||||
virtual ~JitILProfilerFinalizer()
|
virtual ~JitILProfilerFinalizer()
|
||||||
|
@ -221,11 +228,13 @@ namespace JitILProfiler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::unique_ptr<JitILProfilerFinalizer> finalizer;
|
static std::unique_ptr<JitILProfilerFinalizer> finalizer;
|
||||||
static void Init()
|
static void Init()
|
||||||
{
|
{
|
||||||
finalizer = std::make_unique<JitILProfilerFinalizer>();
|
finalizer = std::make_unique<JitILProfilerFinalizer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Shutdown()
|
static void Shutdown()
|
||||||
{
|
{
|
||||||
finalizer.reset();
|
finalizer.reset();
|
||||||
|
@ -246,10 +255,14 @@ void JitIL::Init()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!Core::g_CoreStartupParameter.bJITBlockLinking)
|
if (!Core::g_CoreStartupParameter.bJITBlockLinking)
|
||||||
|
{
|
||||||
jo.enableBlocklink = false;
|
jo.enableBlocklink = false;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
// Speed boost, but not 100% safe
|
// Speed boost, but not 100% safe
|
||||||
jo.enableBlocklink = !Core::g_CoreStartupParameter.bMMU;
|
jo.enableBlocklink = !Core::g_CoreStartupParameter.bMMU;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jo.fpAccurateFcmp = false;
|
jo.fpAccurateFcmp = false;
|
||||||
|
@ -268,7 +281,8 @@ void JitIL::Init()
|
||||||
code_block.m_gpa = &js.gpa;
|
code_block.m_gpa = &js.gpa;
|
||||||
code_block.m_fpa = &js.fpa;
|
code_block.m_fpa = &js.fpa;
|
||||||
|
|
||||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling) {
|
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling)
|
||||||
|
{
|
||||||
JitILProfiler::Init();
|
JitILProfiler::Init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,7 +296,8 @@ void JitIL::ClearCache()
|
||||||
|
|
||||||
void JitIL::Shutdown()
|
void JitIL::Shutdown()
|
||||||
{
|
{
|
||||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling) {
|
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling)
|
||||||
|
{
|
||||||
JitILProfiler::Shutdown();
|
JitILProfiler::Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,11 +367,14 @@ static void ImHere()
|
||||||
PowerPC::ppcState.gpr[5], PowerPC::ppcState.gpr[6]);
|
PowerPC::ppcState.gpr[5], PowerPC::ppcState.gpr[6]);
|
||||||
f.Flush();
|
f.Flush();
|
||||||
}
|
}
|
||||||
if (been_here.find(PC) != been_here.end()) {
|
|
||||||
|
if (been_here.find(PC) != been_here.end())
|
||||||
|
{
|
||||||
been_here.find(PC)->second++;
|
been_here.find(PC)->second++;
|
||||||
if ((been_here.find(PC)->second) & 1023)
|
if ((been_here.find(PC)->second) & 1023)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_LOG(DYNA_REC, "I'm here - PC = %08x , LR = %08x", PC, LR);
|
DEBUG_LOG(DYNA_REC, "I'm here - PC = %08x , LR = %08x", PC, LR);
|
||||||
been_here[PC] = 1;
|
been_here[PC] = 1;
|
||||||
}
|
}
|
||||||
|
@ -376,7 +394,8 @@ void JitIL::Cleanup()
|
||||||
void JitIL::WriteExit(u32 destination)
|
void JitIL::WriteExit(u32 destination)
|
||||||
{
|
{
|
||||||
Cleanup();
|
Cleanup();
|
||||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling) {
|
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling)
|
||||||
|
{
|
||||||
ABI_CallFunction((void *)JitILProfiler::End);
|
ABI_CallFunction((void *)JitILProfiler::End);
|
||||||
}
|
}
|
||||||
SUB(32, M(&PowerPC::ppcState.downcount), Imm32(js.downcountAmount));
|
SUB(32, M(&PowerPC::ppcState.downcount), Imm32(js.downcountAmount));
|
||||||
|
@ -408,7 +427,8 @@ void JitIL::WriteExitDestInOpArg(const Gen::OpArg& arg)
|
||||||
{
|
{
|
||||||
MOV(32, M(&PC), arg);
|
MOV(32, M(&PC), arg);
|
||||||
Cleanup();
|
Cleanup();
|
||||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling) {
|
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling)
|
||||||
|
{
|
||||||
ABI_CallFunction((void *)JitILProfiler::End);
|
ABI_CallFunction((void *)JitILProfiler::End);
|
||||||
}
|
}
|
||||||
SUB(32, M(&PowerPC::ppcState.downcount), Imm32(js.downcountAmount));
|
SUB(32, M(&PowerPC::ppcState.downcount), Imm32(js.downcountAmount));
|
||||||
|
@ -420,7 +440,8 @@ void JitIL::WriteRfiExitDestInOpArg(const Gen::OpArg& arg)
|
||||||
MOV(32, M(&PC), arg);
|
MOV(32, M(&PC), arg);
|
||||||
MOV(32, M(&NPC), arg);
|
MOV(32, M(&NPC), arg);
|
||||||
Cleanup();
|
Cleanup();
|
||||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling) {
|
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling)
|
||||||
|
{
|
||||||
ABI_CallFunction((void *)JitILProfiler::End);
|
ABI_CallFunction((void *)JitILProfiler::End);
|
||||||
}
|
}
|
||||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
||||||
|
@ -431,7 +452,8 @@ void JitIL::WriteRfiExitDestInOpArg(const Gen::OpArg& arg)
|
||||||
void JitIL::WriteExceptionExit()
|
void JitIL::WriteExceptionExit()
|
||||||
{
|
{
|
||||||
Cleanup();
|
Cleanup();
|
||||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling) {
|
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling)
|
||||||
|
{
|
||||||
ABI_CallFunction((void *)JitILProfiler::End);
|
ABI_CallFunction((void *)JitILProfiler::End);
|
||||||
}
|
}
|
||||||
MOV(32, R(EAX), M(&PC));
|
MOV(32, R(EAX), M(&PC));
|
||||||
|
@ -554,7 +576,7 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||||
|
|
||||||
u64 codeHash = -1;
|
u64 codeHash = -1;
|
||||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling ||
|
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling ||
|
||||||
SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILOutputIR)
|
SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILOutputIR)
|
||||||
{
|
{
|
||||||
// For profiling and IR Writer
|
// For profiling and IR Writer
|
||||||
for (u32 i = 0; i < code_block.m_num_instructions; i++)
|
for (u32 i = 0; i < code_block.m_num_instructions; i++)
|
||||||
|
@ -577,7 +599,7 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||||
|
|
||||||
js.downcountAmount = 0;
|
js.downcountAmount = 0;
|
||||||
if (!Core::g_CoreStartupParameter.bEnableDebugging)
|
if (!Core::g_CoreStartupParameter.bEnableDebugging)
|
||||||
js.downcountAmount += PatchEngine::GetSpeedhackCycles(code_block.m_address);
|
js.downcountAmount += PatchEngine::GetSpeedhackCycles(code_block.m_address);
|
||||||
|
|
||||||
// Translate instructions
|
// Translate instructions
|
||||||
for (u32 i = 0; i < code_block.m_num_instructions; i++)
|
for (u32 i = 0; i < code_block.m_num_instructions; i++)
|
||||||
|
|
|
@ -67,19 +67,22 @@ public:
|
||||||
bool IsInCodeSpace(u8 *ptr) override { return IsInSpace(ptr); }
|
bool IsInCodeSpace(u8 *ptr) override { return IsInSpace(ptr); }
|
||||||
|
|
||||||
void ClearCache() override;
|
void ClearCache() override;
|
||||||
const u8 *GetDispatcher() {
|
const u8 *GetDispatcher()
|
||||||
|
{
|
||||||
return asm_routines.dispatcher; // asm_routines.dispatcher
|
return asm_routines.dispatcher; // asm_routines.dispatcher
|
||||||
}
|
}
|
||||||
const CommonAsmRoutines *GetAsmRoutines() override {
|
|
||||||
|
const CommonAsmRoutines *GetAsmRoutines() override
|
||||||
|
{
|
||||||
return &asm_routines;
|
return &asm_routines;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *GetName() override {
|
const char *GetName() override
|
||||||
|
{
|
||||||
return "JIT64IL";
|
return "JIT64IL";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run!
|
// Run!
|
||||||
|
|
||||||
void Run() override;
|
void Run() override;
|
||||||
void SingleStep() override;
|
void SingleStep() override;
|
||||||
|
|
||||||
|
|
|
@ -376,15 +376,19 @@ void CompileInstruction(PPCAnalyst::CodeOp & op)
|
||||||
JitIL *jitil = (JitIL *)jit;
|
JitIL *jitil = (JitIL *)jit;
|
||||||
(jitil->*dynaOpTable[op.inst.OPCD])(op.inst);
|
(jitil->*dynaOpTable[op.inst.OPCD])(op.inst);
|
||||||
GekkoOPInfo *info = op.opinfo;
|
GekkoOPInfo *info = op.opinfo;
|
||||||
if (info) {
|
if (info)
|
||||||
|
{
|
||||||
#ifdef OPLOG
|
#ifdef OPLOG
|
||||||
if (!strcmp(info->opname, OP_TO_LOG)){ ///"mcrfs"
|
if (!strcmp(info->opname, OP_TO_LOG)) // "mcrfs"
|
||||||
|
{
|
||||||
rsplocations.push_back(jit.js.compilerPC);
|
rsplocations.push_back(jit.js.compilerPC);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
info->compileCount++;
|
info->compileCount++;
|
||||||
info->lastUse = jit->js.compilerPC;
|
info->lastUse = jit->js.compilerPC;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
PanicAlert("Tried to compile illegal (or unknown) instruction %08x, at %08x", op.inst.hex, jit->js.compilerPC);
|
PanicAlert("Tried to compile illegal (or unknown) instruction %08x, at %08x", op.inst.hex, jit->js.compilerPC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,12 +108,14 @@ static void ImHere()
|
||||||
}
|
}
|
||||||
fprintf(f.GetHandle(), "%08x\n", PC);
|
fprintf(f.GetHandle(), "%08x\n", PC);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (been_here.find(PC) != been_here.end())
|
if (been_here.find(PC) != been_here.end())
|
||||||
{
|
{
|
||||||
been_here.find(PC)->second++;
|
been_here.find(PC)->second++;
|
||||||
if ((been_here.find(PC)->second) & 1023)
|
if ((been_here.find(PC)->second) & 1023)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_LOG(DYNA_REC, "I'm here - PC = %08x , LR = %08x", PC, LR);
|
DEBUG_LOG(DYNA_REC, "I'm here - PC = %08x , LR = %08x", PC, LR);
|
||||||
been_here[PC] = 1;
|
been_here[PC] = 1;
|
||||||
}
|
}
|
||||||
|
@ -374,8 +376,10 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
|
||||||
SetCC();
|
SetCC();
|
||||||
gpr.Unlock(A, C);
|
gpr.Unlock(A, C);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conditionally add profiling code.
|
// Conditionally add profiling code.
|
||||||
if (Profiler::g_ProfileBlocks) {
|
if (Profiler::g_ProfileBlocks)
|
||||||
|
{
|
||||||
ARMReg rA = gpr.GetReg();
|
ARMReg rA = gpr.GetReg();
|
||||||
ARMReg rB = gpr.GetReg();
|
ARMReg rB = gpr.GetReg();
|
||||||
MOVI2R(rA, (u32)&b->runCount); // Load in to register
|
MOVI2R(rA, (u32)&b->runCount); // Load in to register
|
||||||
|
@ -415,7 +419,8 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
|
||||||
// WARNING - cmp->branch merging will screw this up.
|
// WARNING - cmp->branch merging will screw this up.
|
||||||
js.isLastInstruction = true;
|
js.isLastInstruction = true;
|
||||||
js.next_inst = 0;
|
js.next_inst = 0;
|
||||||
if (Profiler::g_ProfileBlocks) {
|
if (Profiler::g_ProfileBlocks)
|
||||||
|
{
|
||||||
// CAUTION!!! push on stack regs you use, do your stuff, then pop
|
// CAUTION!!! push on stack regs you use, do your stuff, then pop
|
||||||
PROFILER_VPUSH;
|
PROFILER_VPUSH;
|
||||||
// get end tic
|
// get end tic
|
||||||
|
@ -431,6 +436,7 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
|
||||||
js.next_inst = ops[i + 1].inst;
|
js.next_inst = ops[i + 1].inst;
|
||||||
js.next_compilerPC = ops[i + 1].address;
|
js.next_compilerPC = ops[i + 1].address;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock >= 32)
|
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock >= 32)
|
||||||
{
|
{
|
||||||
js.fifoBytesThisBlock -= 32;
|
js.fifoBytesThisBlock -= 32;
|
||||||
|
@ -438,6 +444,7 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
|
||||||
QuickCallFunction(R14, (void*)&GPFifo::CheckGatherPipe);
|
QuickCallFunction(R14, (void*)&GPFifo::CheckGatherPipe);
|
||||||
POP(4, R0, R1, R2, R3);
|
POP(4, R0, R1, R2, R3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Core::g_CoreStartupParameter.bEnableDebugging)
|
if (Core::g_CoreStartupParameter.bEnableDebugging)
|
||||||
{
|
{
|
||||||
// Add run count
|
// Add run count
|
||||||
|
@ -457,6 +464,7 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
|
||||||
fpr.Unlock(VA);
|
fpr.Unlock(VA);
|
||||||
fpr.Unlock(VB);
|
fpr.Unlock(VB);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ops[i].skip)
|
if (!ops[i].skip)
|
||||||
{
|
{
|
||||||
PrintDebug(ops[i].inst, DEBUG_OUTPUT);
|
PrintDebug(ops[i].inst, DEBUG_OUTPUT);
|
||||||
|
@ -474,6 +482,7 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (code_block.m_memory_exception)
|
if (code_block.m_memory_exception)
|
||||||
BKPT(0x500);
|
BKPT(0x500);
|
||||||
|
|
||||||
|
|
|
@ -74,18 +74,22 @@ public:
|
||||||
|
|
||||||
void ClearCache();
|
void ClearCache();
|
||||||
|
|
||||||
const u8 *GetDispatcher() {
|
const u8 *GetDispatcher()
|
||||||
|
{
|
||||||
return asm_routines.dispatcher;
|
return asm_routines.dispatcher;
|
||||||
}
|
}
|
||||||
CommonAsmRoutinesBase *GetAsmRoutines() {
|
|
||||||
|
CommonAsmRoutinesBase *GetAsmRoutines()
|
||||||
|
{
|
||||||
return &asm_routines;
|
return &asm_routines;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *GetName() {
|
const char *GetName()
|
||||||
|
{
|
||||||
return "JITARM";
|
return "JITARM";
|
||||||
}
|
}
|
||||||
// Run!
|
|
||||||
|
|
||||||
|
// Run!
|
||||||
void Run();
|
void Run();
|
||||||
void SingleStep();
|
void SingleStep();
|
||||||
|
|
||||||
|
|
|
@ -16,20 +16,21 @@
|
||||||
|
|
||||||
using namespace ArmGen;
|
using namespace ArmGen;
|
||||||
|
|
||||||
void JitArmBlockCache::WriteLinkBlock(u8* location, const u8* address)
|
void JitArmBlockCache::WriteLinkBlock(u8* location, const u8* address)
|
||||||
{
|
{
|
||||||
ARMXEmitter emit(location);
|
ARMXEmitter emit(location);
|
||||||
emit.B(address);
|
emit.B(address);
|
||||||
emit.FlushIcache();
|
emit.FlushIcache();
|
||||||
}
|
}
|
||||||
void JitArmBlockCache::WriteDestroyBlock(const u8* location, u32 address)
|
|
||||||
{
|
void JitArmBlockCache::WriteDestroyBlock(const u8* location, u32 address)
|
||||||
ARMXEmitter emit((u8 *)location);
|
{
|
||||||
emit.MOVI2R(R11, address);
|
ARMXEmitter emit((u8 *)location);
|
||||||
emit.MOVI2R(R12, (u32)jit->GetAsmRoutines()->dispatcher);
|
emit.MOVI2R(R11, address);
|
||||||
emit.STR(R11, R9, PPCSTATE_OFF(pc));
|
emit.MOVI2R(R12, (u32)jit->GetAsmRoutines()->dispatcher);
|
||||||
emit.B(R12);
|
emit.STR(R11, R9, PPCSTATE_OFF(pc));
|
||||||
emit.FlushIcache();
|
emit.B(R12);
|
||||||
}
|
emit.FlushIcache();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -97,10 +97,12 @@ void JitArm::bx(UGeckoInstruction inst)
|
||||||
STR(rA, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
STR(rA, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||||
//ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4);
|
//ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is not the last instruction of a block,
|
// If this is not the last instruction of a block,
|
||||||
// we will skip the rest process.
|
// we will skip the rest process.
|
||||||
// Because PPCAnalyst::Flatten() merged the blocks.
|
// Because PPCAnalyst::Flatten() merged the blocks.
|
||||||
if (!js.isLastInstruction) {
|
if (!js.isLastInstruction)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,7 +233,8 @@ void JitArm::bcctrx(UGeckoInstruction inst)
|
||||||
LDR(rA, R9, PPCSTATE_OFF(spr[SPR_CTR]));
|
LDR(rA, R9, PPCSTATE_OFF(spr[SPR_CTR]));
|
||||||
BIC(rA, rA, 0x3);
|
BIC(rA, rA, 0x3);
|
||||||
|
|
||||||
if (inst.LK_3){
|
if (inst.LK_3)
|
||||||
|
{
|
||||||
u32 Jumpto = js.compilerPC + 4;
|
u32 Jumpto = js.compilerPC + 4;
|
||||||
MOVI2R(rB, Jumpto);
|
MOVI2R(rB, Jumpto);
|
||||||
STR(rB, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
STR(rB, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||||
|
@ -285,7 +288,8 @@ void JitArm::bclrx(UGeckoInstruction inst)
|
||||||
//AND(32, R(EAX), Imm32(0xFFFFFFFC));
|
//AND(32, R(EAX), Imm32(0xFFFFFFFC));
|
||||||
LDR(rA, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
LDR(rA, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||||
BIC(rA, rA, 0x3);
|
BIC(rA, rA, 0x3);
|
||||||
if (inst.LK){
|
if (inst.LK)
|
||||||
|
{
|
||||||
u32 Jumpto = js.compilerPC + 4;
|
u32 Jumpto = js.compilerPC + 4;
|
||||||
MOVI2R(rB, Jumpto);
|
MOVI2R(rB, Jumpto);
|
||||||
STR(rB, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
STR(rB, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||||
|
|
|
@ -117,7 +117,8 @@ void JitArm::fctiwx(UGeckoInstruction inst)
|
||||||
NEONXEmitter nemit(this);
|
NEONXEmitter nemit(this);
|
||||||
nemit.VORR(vD, vD, V0);
|
nemit.VORR(vD, vD, V0);
|
||||||
|
|
||||||
if (inst.Rc) Helper_UpdateCR1(fpscrReg, rA);
|
if (inst.Rc)
|
||||||
|
Helper_UpdateCR1(fpscrReg, rA);
|
||||||
|
|
||||||
STR(fpscrReg, R9, PPCSTATE_OFF(fpscr));
|
STR(fpscrReg, R9, PPCSTATE_OFF(fpscr));
|
||||||
gpr.Unlock(rA);
|
gpr.Unlock(rA);
|
||||||
|
@ -197,7 +198,8 @@ void JitArm::fctiwzx(UGeckoInstruction inst)
|
||||||
NEONXEmitter nemit(this);
|
NEONXEmitter nemit(this);
|
||||||
nemit.VORR(vD, vD, V0);
|
nemit.VORR(vD, vD, V0);
|
||||||
|
|
||||||
if (inst.Rc) Helper_UpdateCR1(fpscrReg, rA);
|
if (inst.Rc)
|
||||||
|
Helper_UpdateCR1(fpscrReg, rA);
|
||||||
|
|
||||||
STR(fpscrReg, R9, PPCSTATE_OFF(fpscr));
|
STR(fpscrReg, R9, PPCSTATE_OFF(fpscr));
|
||||||
gpr.Unlock(rA);
|
gpr.Unlock(rA);
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
#include "Core/PowerPC/JitArm32/JitAsm.h"
|
#include "Core/PowerPC/JitArm32/JitAsm.h"
|
||||||
#include "Core/PowerPC/JitArm32/JitRegCache.h"
|
#include "Core/PowerPC/JitArm32/JitRegCache.h"
|
||||||
|
|
||||||
void JitArm::ComputeRC(ARMReg value, int cr) {
|
void JitArm::ComputeRC(ARMReg value, int cr)
|
||||||
|
{
|
||||||
ARMReg rB = gpr.GetReg();
|
ARMReg rB = gpr.GetReg();
|
||||||
|
|
||||||
Operand2 ASRReg(value, ST_ASR, 31);
|
Operand2 ASRReg(value, ST_ASR, 31);
|
||||||
|
@ -25,7 +26,9 @@ void JitArm::ComputeRC(ARMReg value, int cr) {
|
||||||
|
|
||||||
gpr.Unlock(rB);
|
gpr.Unlock(rB);
|
||||||
}
|
}
|
||||||
void JitArm::ComputeRC(s32 value, int cr) {
|
|
||||||
|
void JitArm::ComputeRC(s32 value, int cr)
|
||||||
|
{
|
||||||
ARMReg rB = gpr.GetReg();
|
ARMReg rB = gpr.GetReg();
|
||||||
|
|
||||||
Operand2 ASRReg(rB, ST_ASR, 31);
|
Operand2 ASRReg(rB, ST_ASR, 31);
|
||||||
|
@ -51,6 +54,7 @@ void JitArm::ComputeCarry()
|
||||||
STR(tmp, R9, PPCSTATE_OFF(spr[SPR_XER]));
|
STR(tmp, R9, PPCSTATE_OFF(spr[SPR_XER]));
|
||||||
gpr.Unlock(tmp);
|
gpr.Unlock(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitArm::ComputeCarry(bool Carry)
|
void JitArm::ComputeCarry(bool Carry)
|
||||||
{
|
{
|
||||||
ARMReg tmp = gpr.GetReg();
|
ARMReg tmp = gpr.GetReg();
|
||||||
|
@ -162,12 +166,35 @@ void JitArm::subfic(UGeckoInstruction inst)
|
||||||
// This instruction has no RC flag
|
// This instruction has no RC flag
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Add(u32 a, u32 b) {return a + b;}
|
u32 Add(u32 a, u32 b)
|
||||||
u32 Sub(u32 a, u32 b) {return a - b;}
|
{
|
||||||
u32 Mul(u32 a, u32 b) {return a * b;}
|
return a + b;
|
||||||
u32 Or (u32 a, u32 b) {return a | b;}
|
}
|
||||||
u32 And(u32 a, u32 b) {return a & b;}
|
|
||||||
u32 Xor(u32 a, u32 b) {return a ^ b;}
|
u32 Sub(u32 a, u32 b)
|
||||||
|
{
|
||||||
|
return a - b;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 Mul(u32 a, u32 b)
|
||||||
|
{
|
||||||
|
return a * b;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 Or (u32 a, u32 b)
|
||||||
|
{
|
||||||
|
return a | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 And(u32 a, u32 b)
|
||||||
|
{
|
||||||
|
return a & b;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 Xor(u32 a, u32 b)
|
||||||
|
{
|
||||||
|
return a ^ b;
|
||||||
|
}
|
||||||
|
|
||||||
void JitArm::arith(UGeckoInstruction inst)
|
void JitArm::arith(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
|
@ -410,8 +437,13 @@ void JitArm::arith(UGeckoInstruction inst)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (carry) ComputeCarry(hasCarry);
|
|
||||||
if (Rc) ComputeRC(gpr.GetImm(dest), 0);
|
if (carry)
|
||||||
|
ComputeCarry(hasCarry);
|
||||||
|
|
||||||
|
if (Rc)
|
||||||
|
ComputeRC(gpr.GetImm(dest), 0);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,7 +484,9 @@ void JitArm::arith(UGeckoInstruction inst)
|
||||||
gpr.Unlock(rA);
|
gpr.Unlock(rA);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
gpr.SetImmediate(d, Imm[1]);
|
gpr.SetImmediate(d, Imm[1]);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 24:
|
case 24:
|
||||||
case 25:
|
case 25:
|
||||||
|
@ -603,8 +637,12 @@ void JitArm::arith(UGeckoInstruction inst)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (carry) ComputeCarry();
|
|
||||||
if (Rc) ComputeRC(gpr.R(dest));
|
if (carry)
|
||||||
|
ComputeCarry();
|
||||||
|
|
||||||
|
if (Rc)
|
||||||
|
ComputeRC(gpr.R(dest));
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitArm::addex(UGeckoInstruction inst)
|
void JitArm::addex(UGeckoInstruction inst)
|
||||||
|
@ -623,7 +661,10 @@ void JitArm::addex(UGeckoInstruction inst)
|
||||||
GetCarryAndClear(rA);
|
GetCarryAndClear(rA);
|
||||||
ADDS(RD, RA, RB);
|
ADDS(RD, RA, RB);
|
||||||
FinalizeCarry(rA);
|
FinalizeCarry(rA);
|
||||||
if (inst.Rc) ComputeRC(RD);
|
|
||||||
|
if (inst.Rc)
|
||||||
|
ComputeRC(RD);
|
||||||
|
|
||||||
gpr.Unlock(rA);
|
gpr.Unlock(rA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,7 +693,9 @@ void JitArm::mulhwux(UGeckoInstruction inst)
|
||||||
ARMReg RD = gpr.R(d);
|
ARMReg RD = gpr.R(d);
|
||||||
ARMReg rA = gpr.GetReg(false);
|
ARMReg rA = gpr.GetReg(false);
|
||||||
UMULL(rA, RD, RA, RB);
|
UMULL(rA, RD, RA, RB);
|
||||||
if (inst.Rc) ComputeRC(RD);
|
|
||||||
|
if (inst.Rc)
|
||||||
|
ComputeRC(RD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitArm::extshx(UGeckoInstruction inst)
|
void JitArm::extshx(UGeckoInstruction inst)
|
||||||
|
@ -664,7 +707,10 @@ void JitArm::extshx(UGeckoInstruction inst)
|
||||||
if (gpr.IsImm(s))
|
if (gpr.IsImm(s))
|
||||||
{
|
{
|
||||||
gpr.SetImmediate(a, (u32)(s32)(s16)gpr.GetImm(s));
|
gpr.SetImmediate(a, (u32)(s32)(s16)gpr.GetImm(s));
|
||||||
if (inst.Rc) ComputeRC(gpr.GetImm(a), 0);
|
|
||||||
|
if (inst.Rc)
|
||||||
|
ComputeRC(gpr.GetImm(a), 0);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ARMReg rA = gpr.R(a);
|
ARMReg rA = gpr.R(a);
|
||||||
|
@ -682,7 +728,10 @@ void JitArm::extsbx(UGeckoInstruction inst)
|
||||||
if (gpr.IsImm(s))
|
if (gpr.IsImm(s))
|
||||||
{
|
{
|
||||||
gpr.SetImmediate(a, (u32)(s32)(s8)gpr.GetImm(s));
|
gpr.SetImmediate(a, (u32)(s32)(s8)gpr.GetImm(s));
|
||||||
if (inst.Rc) ComputeRC(gpr.GetImm(a), 0);
|
|
||||||
|
if (inst.Rc)
|
||||||
|
ComputeRC(gpr.GetImm(a), 0);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ARMReg rA = gpr.R(a);
|
ARMReg rA = gpr.R(a);
|
||||||
|
@ -865,7 +914,9 @@ void JitArm::twx(UGeckoInstruction inst)
|
||||||
MOV(RA, inst.TO);
|
MOV(RA, inst.TO);
|
||||||
|
|
||||||
if (inst.OPCD == 3) // twi
|
if (inst.OPCD == 3) // twi
|
||||||
|
{
|
||||||
CMP(gpr.R(a), gpr.R(inst.RB));
|
CMP(gpr.R(a), gpr.R(inst.RB));
|
||||||
|
}
|
||||||
else // tw
|
else // tw
|
||||||
{
|
{
|
||||||
MOVI2R(RB, (s32)(s16)inst.SIMM_16);
|
MOVI2R(RB, (s32)(s16)inst.SIMM_16);
|
||||||
|
|
|
@ -68,7 +68,9 @@ void JitArm::SafeStoreFromReg(bool fastmem, s32 dest, u32 value, s32 regOffset,
|
||||||
NOP(1);
|
NOP(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
MOVI2R(R10, (u32)offset, false);
|
MOVI2R(R10, (u32)offset, false);
|
||||||
|
}
|
||||||
|
|
||||||
if (dest != -1)
|
if (dest != -1)
|
||||||
ADD(R10, R10, RA);
|
ADD(R10, R10, RA);
|
||||||
|
@ -439,11 +441,11 @@ void JitArm::lXX(UGeckoInstruction inst)
|
||||||
|
|
||||||
// LWZ idle skipping
|
// LWZ idle skipping
|
||||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle &&
|
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle &&
|
||||||
inst.OPCD == 32 &&
|
inst.OPCD == 32 &&
|
||||||
(inst.hex & 0xFFFF0000) == 0x800D0000 &&
|
(inst.hex & 0xFFFF0000) == 0x800D0000 &&
|
||||||
(Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x28000000 ||
|
(Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x28000000 ||
|
||||||
(SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x2C000000)) &&
|
(SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x2C000000)) &&
|
||||||
Memory::ReadUnchecked_U32(js.compilerPC + 8) == 0x4182fff8)
|
Memory::ReadUnchecked_U32(js.compilerPC + 8) == 0x4182fff8)
|
||||||
{
|
{
|
||||||
ARMReg RD = gpr.R(d);
|
ARMReg RD = gpr.R(d);
|
||||||
|
|
||||||
|
|
|
@ -89,11 +89,12 @@ void JitArm::lfXX(UGeckoInstruction inst)
|
||||||
ADD(rB, rB, RA);
|
ADD(rB, rB, RA);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
ADD(rB, gpr.R(offsetReg), RA);
|
ADD(rB, gpr.R(offsetReg), RA);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
if (zeroA)
|
if (zeroA)
|
||||||
{
|
{
|
||||||
if (offsetReg == -1)
|
if (offsetReg == -1)
|
||||||
|
@ -105,7 +106,9 @@ void JitArm::lfXX(UGeckoInstruction inst)
|
||||||
ADD(rB, rB, RA);
|
ADD(rB, rB, RA);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
MOVI2R(rB, (u32)offset);
|
MOVI2R(rB, (u32)offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -116,7 +119,9 @@ void JitArm::lfXX(UGeckoInstruction inst)
|
||||||
ADD(rB, RB, RA);
|
ADD(rB, RB, RA);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
MOV(rB, RB);
|
MOV(rB, RB);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,11 +253,12 @@ void JitArm::stfXX(UGeckoInstruction inst)
|
||||||
ADD(rB, rB, RA);
|
ADD(rB, rB, RA);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
ADD(rB, gpr.R(offsetReg), RA);
|
ADD(rB, gpr.R(offsetReg), RA);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
if (zeroA)
|
if (zeroA)
|
||||||
{
|
{
|
||||||
if (offsetReg == -1)
|
if (offsetReg == -1)
|
||||||
|
@ -264,7 +270,9 @@ void JitArm::stfXX(UGeckoInstruction inst)
|
||||||
ADD(rB, rB, RA);
|
ADD(rB, rB, RA);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
MOVI2R(rB, (u32)offset);
|
MOVI2R(rB, (u32)offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -275,7 +283,9 @@ void JitArm::stfXX(UGeckoInstruction inst)
|
||||||
ADD(rB, RB, RA);
|
ADD(rB, RB, RA);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
MOV(rB, RB);
|
MOV(rB, RB);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -320,7 +330,6 @@ void JitArm::stfXX(UGeckoInstruction inst)
|
||||||
MOV(R1, rB);
|
MOV(R1, rB);
|
||||||
|
|
||||||
BL(rA);
|
BL(rA);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -332,7 +341,6 @@ void JitArm::stfXX(UGeckoInstruction inst)
|
||||||
VMOV(D0, v0);
|
VMOV(D0, v0);
|
||||||
MOV(R0, rB);
|
MOV(R0, rB);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
BL(rA);
|
BL(rA);
|
||||||
}
|
}
|
||||||
POP(4, R0, R1, R2, R3);
|
POP(4, R0, R1, R2, R3);
|
||||||
|
@ -361,8 +369,9 @@ void JitArm::stfs(UGeckoInstruction inst)
|
||||||
ADD(rB, rB, RA);
|
ADD(rB, rB, RA);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
MOVI2R(rB, (u32)inst.SIMM_16);
|
MOVI2R(rB, (u32)inst.SIMM_16);
|
||||||
|
}
|
||||||
|
|
||||||
MOVI2R(rA, (u32)&Memory::Write_U32);
|
MOVI2R(rA, (u32)&Memory::Write_U32);
|
||||||
PUSH(4, R0, R1, R2, R3);
|
PUSH(4, R0, R1, R2, R3);
|
||||||
|
|
|
@ -77,7 +77,9 @@ void JitArm::psq_lx(UGeckoInstruction inst)
|
||||||
ADD(R10, gpr.R(inst.RB), gpr.R(inst.RA));
|
ADD(R10, gpr.R(inst.RB), gpr.R(inst.RA));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
MOV(R10, gpr.R(inst.RB));
|
MOV(R10, gpr.R(inst.RB));
|
||||||
|
}
|
||||||
|
|
||||||
if (update)
|
if (update)
|
||||||
MOV(gpr.R(inst.RA), R10);
|
MOV(gpr.R(inst.RA), R10);
|
||||||
|
@ -128,7 +130,9 @@ void JitArm::psq_st(UGeckoInstruction inst)
|
||||||
ADD(R10, gpr.R(inst.RA), R14);
|
ADD(R10, gpr.R(inst.RA), R14);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
MOVI2R(R10, (u32)offset);
|
MOVI2R(R10, (u32)offset);
|
||||||
|
}
|
||||||
|
|
||||||
if (update)
|
if (update)
|
||||||
MOV(gpr.R(inst.RA), R10);
|
MOV(gpr.R(inst.RA), R10);
|
||||||
|
@ -171,7 +175,9 @@ void JitArm::psq_stx(UGeckoInstruction inst)
|
||||||
ADD(R10, gpr.R(inst.RA), gpr.R(inst.RB));
|
ADD(R10, gpr.R(inst.RA), gpr.R(inst.RB));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
MOV(R10, gpr.R(inst.RB));
|
MOV(R10, gpr.R(inst.RB));
|
||||||
|
}
|
||||||
|
|
||||||
if (update)
|
if (update)
|
||||||
MOV(gpr.R(inst.RA), R10);
|
MOV(gpr.R(inst.RA), R10);
|
||||||
|
|
|
@ -98,12 +98,14 @@ void JitArm::mtspr(UGeckoInstruction inst)
|
||||||
ARMReg RD = gpr.R(inst.RD);
|
ARMReg RD = gpr.R(inst.RD);
|
||||||
STR(RD, R9, PPCSTATE_OFF(spr) + iIndex * 4);
|
STR(RD, R9, PPCSTATE_OFF(spr) + iIndex * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitArm::mftb(UGeckoInstruction inst)
|
void JitArm::mftb(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(bJITSystemRegistersOff);
|
JITDISABLE(bJITSystemRegistersOff);
|
||||||
mfspr(inst);
|
mfspr(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitArm::mfspr(UGeckoInstruction inst)
|
void JitArm::mfspr(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
|
|
@ -378,9 +378,12 @@ void CompileInstruction(PPCAnalyst::CodeOp & op)
|
||||||
JitArm *jitarm = (JitArm *)jit;
|
JitArm *jitarm = (JitArm *)jit;
|
||||||
(jitarm->*dynaOpTable[op.inst.OPCD])(op.inst);
|
(jitarm->*dynaOpTable[op.inst.OPCD])(op.inst);
|
||||||
GekkoOPInfo *info = op.opinfo;
|
GekkoOPInfo *info = op.opinfo;
|
||||||
if (info) {
|
|
||||||
|
if (info)
|
||||||
|
{
|
||||||
#ifdef OPLOG
|
#ifdef OPLOG
|
||||||
if (!strcmp(info->opname, OP_TO_LOG)){ ///"mcrfs"
|
if (!strcmp(info->opname, OP_TO_LOG)) // "mcrfs"
|
||||||
|
{
|
||||||
rsplocations.push_back(jit.js.compilerPC);
|
rsplocations.push_back(jit.js.compilerPC);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,13 +14,15 @@ private:
|
||||||
void GenerateCommon();
|
void GenerateCommon();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void Init() {
|
void Init()
|
||||||
|
{
|
||||||
AllocCodeSpace(8192);
|
AllocCodeSpace(8192);
|
||||||
Generate();
|
Generate();
|
||||||
WriteProtect();
|
WriteProtect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown() {
|
void Shutdown()
|
||||||
|
{
|
||||||
FreeCodeSpace();
|
FreeCodeSpace();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -83,6 +83,7 @@ ARMReg *ArmFPRCache::GetAllocationOrder(int &count)
|
||||||
ARMReg ArmFPRCache::GetReg(bool AutoLock)
|
ARMReg ArmFPRCache::GetReg(bool AutoLock)
|
||||||
{
|
{
|
||||||
for (u8 a = 0; a < NUMARMREG; ++a)
|
for (u8 a = 0; a < NUMARMREG; ++a)
|
||||||
|
{
|
||||||
if (ArmRegs[a].free)
|
if (ArmRegs[a].free)
|
||||||
{
|
{
|
||||||
// Alright, this one is free
|
// Alright, this one is free
|
||||||
|
@ -90,6 +91,8 @@ ARMReg ArmFPRCache::GetReg(bool AutoLock)
|
||||||
ArmRegs[a].free = false;
|
ArmRegs[a].free = false;
|
||||||
return ArmRegs[a].Reg;
|
return ArmRegs[a].Reg;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Uh Oh, we have all them locked....
|
// Uh Oh, we have all them locked....
|
||||||
_assert_msg_(_DYNA_REC_, false, "All available registers are locked dumb dumb");
|
_assert_msg_(_DYNA_REC_, false, "All available registers are locked dumb dumb");
|
||||||
return D31;
|
return D31;
|
||||||
|
@ -109,9 +112,11 @@ u32 ArmFPRCache::GetLeastUsedRegister(bool increment)
|
||||||
{
|
{
|
||||||
u32 HighestUsed = 0;
|
u32 HighestUsed = 0;
|
||||||
u8 lastRegIndex = 0;
|
u8 lastRegIndex = 0;
|
||||||
for (u8 a = 0; a < NUMPPCREG; ++a){
|
for (u8 a = 0; a < NUMPPCREG; ++a)
|
||||||
|
{
|
||||||
if (increment)
|
if (increment)
|
||||||
++ArmCRegs[a].LastLoad;
|
++ArmCRegs[a].LastLoad;
|
||||||
|
|
||||||
if (ArmCRegs[a].LastLoad > HighestUsed)
|
if (ArmCRegs[a].LastLoad > HighestUsed)
|
||||||
{
|
{
|
||||||
HighestUsed = ArmCRegs[a].LastLoad;
|
HighestUsed = ArmCRegs[a].LastLoad;
|
||||||
|
@ -123,11 +128,13 @@ u32 ArmFPRCache::GetLeastUsedRegister(bool increment)
|
||||||
bool ArmFPRCache::FindFreeRegister(u32 ®index)
|
bool ArmFPRCache::FindFreeRegister(u32 ®index)
|
||||||
{
|
{
|
||||||
for (u8 a = 0; a < NUMPPCREG; ++a)
|
for (u8 a = 0; a < NUMPPCREG; ++a)
|
||||||
|
{
|
||||||
if (ArmCRegs[a].PPCReg == 33)
|
if (ArmCRegs[a].PPCReg == 33)
|
||||||
{
|
{
|
||||||
regindex = a;
|
regindex = a;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ void ArmRegCache::Init(ARMXEmitter *emitter)
|
||||||
ArmRegs[a].free = true;
|
ArmRegs[a].free = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArmRegCache::Start(PPCAnalyst::BlockRegStats &stats)
|
void ArmRegCache::Start(PPCAnalyst::BlockRegStats &stats)
|
||||||
{
|
{
|
||||||
// Make sure the state is wiped on Start
|
// Make sure the state is wiped on Start
|
||||||
|
@ -71,6 +72,7 @@ ARMReg *ArmRegCache::GetAllocationOrder(int &count)
|
||||||
ARMReg ArmRegCache::GetReg(bool AutoLock)
|
ARMReg ArmRegCache::GetReg(bool AutoLock)
|
||||||
{
|
{
|
||||||
for (u8 a = 0; a < NUMARMREG; ++a)
|
for (u8 a = 0; a < NUMARMREG; ++a)
|
||||||
|
{
|
||||||
if (ArmRegs[a].free)
|
if (ArmRegs[a].free)
|
||||||
{
|
{
|
||||||
// Alright, this one is free
|
// Alright, this one is free
|
||||||
|
@ -78,6 +80,8 @@ ARMReg ArmRegCache::GetReg(bool AutoLock)
|
||||||
ArmRegs[a].free = false;
|
ArmRegs[a].free = false;
|
||||||
return ArmRegs[a].Reg;
|
return ArmRegs[a].Reg;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Uh Oh, we have all them locked....
|
// Uh Oh, we have all them locked....
|
||||||
_assert_msg_(_DYNA_REC_, false, "All available registers are locked dumb dumb");
|
_assert_msg_(_DYNA_REC_, false, "All available registers are locked dumb dumb");
|
||||||
return R0;
|
return R0;
|
||||||
|
@ -92,11 +96,18 @@ void ArmRegCache::Unlock(ARMReg R0, ARMReg R1, ARMReg R2, ARMReg R3)
|
||||||
_assert_msg_(_DYNA_REC, !ArmRegs[RegNum].free, "This register is already unlocked");
|
_assert_msg_(_DYNA_REC, !ArmRegs[RegNum].free, "This register is already unlocked");
|
||||||
ArmRegs[RegNum].free = true;
|
ArmRegs[RegNum].free = true;
|
||||||
}
|
}
|
||||||
if ( R1 != INVALID_REG && ArmRegs[RegNum].Reg == R1) ArmRegs[RegNum].free = true;
|
|
||||||
if ( R2 != INVALID_REG && ArmRegs[RegNum].Reg == R2) ArmRegs[RegNum].free = true;
|
if (R1 != INVALID_REG && ArmRegs[RegNum].Reg == R1)
|
||||||
if ( R3 != INVALID_REG && ArmRegs[RegNum].Reg == R3) ArmRegs[RegNum].free = true;
|
ArmRegs[RegNum].free = true;
|
||||||
|
|
||||||
|
if (R2 != INVALID_REG && ArmRegs[RegNum].Reg == R2)
|
||||||
|
ArmRegs[RegNum].free = true;
|
||||||
|
|
||||||
|
if (R3 != INVALID_REG && ArmRegs[RegNum].Reg == R3)
|
||||||
|
ArmRegs[RegNum].free = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ArmRegCache::GetLeastUsedRegister(bool increment)
|
u32 ArmRegCache::GetLeastUsedRegister(bool increment)
|
||||||
{
|
{
|
||||||
u32 HighestUsed = 0;
|
u32 HighestUsed = 0;
|
||||||
|
@ -113,14 +124,17 @@ u32 ArmRegCache::GetLeastUsedRegister(bool increment)
|
||||||
}
|
}
|
||||||
return lastRegIndex;
|
return lastRegIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArmRegCache::FindFreeRegister(u32 ®index)
|
bool ArmRegCache::FindFreeRegister(u32 ®index)
|
||||||
{
|
{
|
||||||
for (u8 a = 0; a < NUMPPCREG; ++a)
|
for (u8 a = 0; a < NUMPPCREG; ++a)
|
||||||
|
{
|
||||||
if (ArmCRegs[a].PPCReg == 33)
|
if (ArmCRegs[a].PPCReg == 33)
|
||||||
{
|
{
|
||||||
regindex = a;
|
regindex = a;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -247,13 +247,16 @@ void CommonAsmRoutines::GenQuantizedSingleStores()
|
||||||
SafeWriteF32ToReg(XMM0, ECX, 0, QUANTIZED_REGS_TO_SAVE, SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM);
|
SafeWriteF32ToReg(XMM0, ECX, 0, QUANTIZED_REGS_TO_SAVE, SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM);
|
||||||
RET();
|
RET();
|
||||||
/*
|
/*
|
||||||
if (cpu_info.bSSSE3) {
|
if (cpu_info.bSSSE3)
|
||||||
|
{
|
||||||
PSHUFB(XMM0, M((void *)pbswapShuffle2x4));
|
PSHUFB(XMM0, M((void *)pbswapShuffle2x4));
|
||||||
// TODO: SafeWriteFloat
|
// TODO: SafeWriteFloat
|
||||||
MOVSS(M(&psTemp[0]), XMM0);
|
MOVSS(M(&psTemp[0]), XMM0);
|
||||||
MOV(32, R(EAX), M(&psTemp[0]));
|
MOV(32, R(EAX), M(&psTemp[0]));
|
||||||
SafeWriteRegToReg(EAX, ECX, 32, 0, SAFE_LOADSTORE_NO_SWAP | SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM);
|
SafeWriteRegToReg(EAX, ECX, 32, 0, SAFE_LOADSTORE_NO_SWAP | SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
MOVSS(M(&psTemp[0]), XMM0);
|
MOVSS(M(&psTemp[0]), XMM0);
|
||||||
MOV(32, R(EAX), M(&psTemp[0]));
|
MOV(32, R(EAX), M(&psTemp[0]));
|
||||||
SafeWriteRegToReg(EAX, ECX, 32, 0, SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM);
|
SafeWriteRegToReg(EAX, ECX, 32, 0, SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM);
|
||||||
|
@ -320,10 +323,13 @@ void CommonAsmRoutines::GenQuantizedLoads()
|
||||||
UD2();
|
UD2();
|
||||||
|
|
||||||
const u8* loadPairedFloatTwo = AlignCode4();
|
const u8* loadPairedFloatTwo = AlignCode4();
|
||||||
if (cpu_info.bSSSE3) {
|
if (cpu_info.bSSSE3)
|
||||||
|
{
|
||||||
MOVQ_xmm(XMM0, MComplex(RBX, RCX, 1, 0));
|
MOVQ_xmm(XMM0, MComplex(RBX, RCX, 1, 0));
|
||||||
PSHUFB(XMM0, M((void *)pbswapShuffle2x4));
|
PSHUFB(XMM0, M((void *)pbswapShuffle2x4));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LoadAndSwap(64, RCX, MComplex(RBX, RCX, 1, 0));
|
LoadAndSwap(64, RCX, MComplex(RBX, RCX, 1, 0));
|
||||||
ROL(64, R(RCX), Imm8(32));
|
ROL(64, R(RCX), Imm8(32));
|
||||||
MOVQ_xmm(XMM0, R(RCX));
|
MOVQ_xmm(XMM0, R(RCX));
|
||||||
|
@ -331,11 +337,14 @@ void CommonAsmRoutines::GenQuantizedLoads()
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
const u8* loadPairedFloatOne = AlignCode4();
|
const u8* loadPairedFloatOne = AlignCode4();
|
||||||
if (cpu_info.bSSSE3) {
|
if (cpu_info.bSSSE3)
|
||||||
|
{
|
||||||
MOVD_xmm(XMM0, MComplex(RBX, RCX, 1, 0));
|
MOVD_xmm(XMM0, MComplex(RBX, RCX, 1, 0));
|
||||||
PSHUFB(XMM0, M((void *)pbswapShuffle1x4));
|
PSHUFB(XMM0, M((void *)pbswapShuffle1x4));
|
||||||
UNPCKLPS(XMM0, M((void*)m_one));
|
UNPCKLPS(XMM0, M((void*)m_one));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LoadAndSwap(32, RCX, MComplex(RBX, RCX, 1, 0));
|
LoadAndSwap(32, RCX, MComplex(RBX, RCX, 1, 0));
|
||||||
MOVD_xmm(XMM0, R(RCX));
|
MOVD_xmm(XMM0, R(RCX));
|
||||||
UNPCKLPS(XMM0, M((void*)m_one));
|
UNPCKLPS(XMM0, M((void*)m_one));
|
||||||
|
|
|
@ -21,7 +21,8 @@ using namespace Gen;
|
||||||
|
|
||||||
extern u8 *trampolineCodePtr;
|
extern u8 *trampolineCodePtr;
|
||||||
|
|
||||||
static void BackPatchError(const std::string &text, u8 *codePtr, u32 emAddress) {
|
static void BackPatchError(const std::string &text, u8 *codePtr, u32 emAddress)
|
||||||
|
{
|
||||||
u64 code_addr = (u64)codePtr;
|
u64 code_addr = (u64)codePtr;
|
||||||
disassembler disasm;
|
disassembler disasm;
|
||||||
char disbuf[256];
|
char disbuf[256];
|
||||||
|
@ -61,9 +62,10 @@ const u8 *TrampolineCache::GetReadTrampoline(const InstructionInfo &info, u32 re
|
||||||
|
|
||||||
if (addrReg != ABI_PARAM1)
|
if (addrReg != ABI_PARAM1)
|
||||||
MOV(32, R(ABI_PARAM1), R((X64Reg)addrReg));
|
MOV(32, R(ABI_PARAM1), R((X64Reg)addrReg));
|
||||||
if (info.displacement) {
|
|
||||||
|
if (info.displacement)
|
||||||
ADD(32, R(ABI_PARAM1), Imm32(info.displacement));
|
ADD(32, R(ABI_PARAM1), Imm32(info.displacement));
|
||||||
}
|
|
||||||
ABI_PushRegistersAndAdjustStack(registersInUse, true);
|
ABI_PushRegistersAndAdjustStack(registersInUse, true);
|
||||||
switch (info.operandSize)
|
switch (info.operandSize)
|
||||||
{
|
{
|
||||||
|
|
|
@ -135,9 +135,9 @@ using namespace Gen;
|
||||||
{
|
{
|
||||||
// check if any endpoint is inside the other range
|
// check if any endpoint is inside the other range
|
||||||
if ((s1 >= s2 && s1 <= e2) ||
|
if ((s1 >= s2 && s1 <= e2) ||
|
||||||
(e1 >= s2 && e1 <= e2) ||
|
(e1 >= s2 && e1 <= e2) ||
|
||||||
(s2 >= s1 && s2 <= e1) ||
|
(s2 >= s1 && s2 <= e1) ||
|
||||||
(e2 >= s1 && e2 <= e1))
|
(e2 >= s1 && e2 <= e1))
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
@ -360,11 +360,13 @@ using namespace Gen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitBlockCache::WriteLinkBlock(u8* location, const u8* address)
|
void JitBlockCache::WriteLinkBlock(u8* location, const u8* address)
|
||||||
{
|
{
|
||||||
XEmitter emit(location);
|
XEmitter emit(location);
|
||||||
emit.JMP(address, true);
|
emit.JMP(address, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitBlockCache::WriteDestroyBlock(const u8* location, u32 address)
|
void JitBlockCache::WriteDestroyBlock(const u8* location, u32 address)
|
||||||
{
|
{
|
||||||
XEmitter emit((u8 *)location);
|
XEmitter emit((u8 *)location);
|
||||||
|
|
|
@ -42,7 +42,8 @@ struct JitBlock
|
||||||
|
|
||||||
bool invalid;
|
bool invalid;
|
||||||
|
|
||||||
struct LinkData {
|
struct LinkData
|
||||||
|
{
|
||||||
u8 *exitPtrs; // to be able to rewrite the exit jum
|
u8 *exitPtrs; // to be able to rewrite the exit jum
|
||||||
u32 exitAddress;
|
u32 exitAddress;
|
||||||
bool linkStatus; // is it already linked?
|
bool linkStatus; // is it already linked?
|
||||||
|
@ -81,18 +82,22 @@ public:
|
||||||
m_valid_block.reset(new u32[VALID_BLOCK_ALLOC_ELEMENTS]);
|
m_valid_block.reset(new u32[VALID_BLOCK_ALLOC_ELEMENTS]);
|
||||||
ClearAll();
|
ClearAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Set(u32 bit)
|
void Set(u32 bit)
|
||||||
{
|
{
|
||||||
m_valid_block[bit / 32] |= 1u << (bit % 32);
|
m_valid_block[bit / 32] |= 1u << (bit % 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clear(u32 bit)
|
void Clear(u32 bit)
|
||||||
{
|
{
|
||||||
m_valid_block[bit / 32] &= ~(1u << (bit % 32));
|
m_valid_block[bit / 32] &= ~(1u << (bit % 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearAll()
|
void ClearAll()
|
||||||
{
|
{
|
||||||
memset(m_valid_block.get(), 0, sizeof(u32) * VALID_BLOCK_ALLOC_ELEMENTS);
|
memset(m_valid_block.get(), 0, sizeof(u32) * VALID_BLOCK_ALLOC_ELEMENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Test(u32 bit)
|
bool Test(u32 bit)
|
||||||
{
|
{
|
||||||
return (m_valid_block[bit / 32] & (1u << (bit % 32))) != 0;
|
return (m_valid_block[bit / 32] & (1u << (bit % 32))) != 0;
|
||||||
|
@ -125,7 +130,10 @@ class JitBaseBlockCache
|
||||||
public:
|
public:
|
||||||
JitBaseBlockCache() :
|
JitBaseBlockCache() :
|
||||||
blockCodePointers(nullptr), blocks(nullptr), num_blocks(0),
|
blockCodePointers(nullptr), blocks(nullptr), num_blocks(0),
|
||||||
iCache(nullptr), iCacheEx(nullptr), iCacheVMEM(nullptr) {}
|
iCache(nullptr), iCacheEx(nullptr), iCacheVMEM(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
int AllocateBlock(u32 em_address);
|
int AllocateBlock(u32 em_address);
|
||||||
void FinalizeBlock(int block_num, bool block_link, const u8 *code_ptr);
|
void FinalizeBlock(int block_num, bool block_link, const u8 *code_ptr);
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,8 @@ u8 *EmuCodeBlock::UnsafeLoadToReg(X64Reg reg_value, Gen::OpArg opAddress, int ac
|
||||||
// offsets with the wrong sign, so whatever. Since the original code
|
// offsets with the wrong sign, so whatever. Since the original code
|
||||||
// *could* try to wrap an address around, however, this is the correct
|
// *could* try to wrap an address around, however, this is the correct
|
||||||
// place to address the issue.)
|
// place to address the issue.)
|
||||||
if ((u32) offset >= 0x1000) {
|
if ((u32) offset >= 0x1000)
|
||||||
|
{
|
||||||
LEA(32, reg_value, MDisp(opAddress.GetSimpleReg(), offset));
|
LEA(32, reg_value, MDisp(opAddress.GetSimpleReg(), offset));
|
||||||
opAddress = R(reg_value);
|
opAddress = R(reg_value);
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
@ -186,7 +187,9 @@ private:
|
||||||
// then mask, then sign extend if needed (1 instr vs. 2/3).
|
// then mask, then sign extend if needed (1 instr vs. 2/3).
|
||||||
u32 all_ones = (1ULL << sbits) - 1;
|
u32 all_ones = (1ULL << sbits) - 1;
|
||||||
if ((all_ones & mask) == all_ones)
|
if ((all_ones & mask) == all_ones)
|
||||||
|
{
|
||||||
MoveOpArgToReg(sbits, MDisp(EAX, 0));
|
MoveOpArgToReg(sbits, MDisp(EAX, 0));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_code->MOVZX(32, sbits, m_dst_reg, MDisp(EAX, 0));
|
m_code->MOVZX(32, sbits, m_dst_reg, MDisp(EAX, 0));
|
||||||
|
@ -342,10 +345,18 @@ void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg & opAddress,
|
||||||
ABI_PushRegistersAndAdjustStack(registersInUse, false);
|
ABI_PushRegistersAndAdjustStack(registersInUse, false);
|
||||||
switch (accessSize)
|
switch (accessSize)
|
||||||
{
|
{
|
||||||
case 64: ABI_CallFunctionA((void *)&Memory::Read_U64, addr_loc); break;
|
case 64:
|
||||||
case 32: ABI_CallFunctionA((void *)&Memory::Read_U32, addr_loc); break;
|
ABI_CallFunctionA((void *)&Memory::Read_U64, addr_loc);
|
||||||
case 16: ABI_CallFunctionA((void *)&Memory::Read_U16_ZX, addr_loc); break;
|
break;
|
||||||
case 8: ABI_CallFunctionA((void *)&Memory::Read_U8_ZX, addr_loc); break;
|
case 32:
|
||||||
|
ABI_CallFunctionA((void *)&Memory::Read_U32, addr_loc);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
ABI_CallFunctionA((void *)&Memory::Read_U16_ZX, addr_loc);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
ABI_CallFunctionA((void *)&Memory::Read_U8_ZX, addr_loc);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
ABI_PopRegistersAndAdjustStack(registersInUse, false);
|
ABI_PopRegistersAndAdjustStack(registersInUse, false);
|
||||||
|
|
||||||
|
@ -373,11 +384,12 @@ void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg & opAddress,
|
||||||
|
|
||||||
u8 *EmuCodeBlock::UnsafeWriteRegToReg(X64Reg reg_value, X64Reg reg_addr, int accessSize, s32 offset, bool swap)
|
u8 *EmuCodeBlock::UnsafeWriteRegToReg(X64Reg reg_value, X64Reg reg_addr, int accessSize, s32 offset, bool swap)
|
||||||
{
|
{
|
||||||
u8 *result;
|
if (accessSize == 8 && reg_value >= 4)
|
||||||
if (accessSize == 8 && reg_value >= 4) {
|
{
|
||||||
PanicAlert("WARNING: likely incorrect use of UnsafeWriteRegToReg!");
|
PanicAlert("WARNING: likely incorrect use of UnsafeWriteRegToReg!");
|
||||||
}
|
}
|
||||||
result = GetWritableCodePtr();
|
|
||||||
|
u8* result = GetWritableCodePtr();
|
||||||
OpArg dest = MComplex(RBX, reg_addr, SCALE_1, offset);
|
OpArg dest = MComplex(RBX, reg_addr, SCALE_1, offset);
|
||||||
if (swap)
|
if (swap)
|
||||||
{
|
{
|
||||||
|
@ -396,6 +408,7 @@ u8 *EmuCodeBlock::UnsafeWriteRegToReg(X64Reg reg_value, X64Reg reg_addr, int acc
|
||||||
{
|
{
|
||||||
MOV(accessSize, dest, R(reg_value));
|
MOV(accessSize, dest, R(reg_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,10 +463,18 @@ void EmuCodeBlock::SafeWriteRegToReg(X64Reg reg_value, X64Reg reg_addr, int acce
|
||||||
ABI_PushRegistersAndAdjustStack(registersInUse, noProlog);
|
ABI_PushRegistersAndAdjustStack(registersInUse, noProlog);
|
||||||
switch (accessSize)
|
switch (accessSize)
|
||||||
{
|
{
|
||||||
case 64: ABI_CallFunctionRR(swap ? ((void *)&Memory::Write_U64) : ((void *)&Memory::Write_U64_Swap), reg_value, reg_addr, false); break;
|
case 64:
|
||||||
case 32: ABI_CallFunctionRR(swap ? ((void *)&Memory::Write_U32) : ((void *)&Memory::Write_U32_Swap), reg_value, reg_addr, false); break;
|
ABI_CallFunctionRR(swap ? ((void *)&Memory::Write_U64) : ((void *)&Memory::Write_U64_Swap), reg_value, reg_addr, false);
|
||||||
case 16: ABI_CallFunctionRR(swap ? ((void *)&Memory::Write_U16) : ((void *)&Memory::Write_U16_Swap), reg_value, reg_addr, false); break;
|
break;
|
||||||
case 8: ABI_CallFunctionRR((void *)&Memory::Write_U8, reg_value, reg_addr, false); break;
|
case 32:
|
||||||
|
ABI_CallFunctionRR(swap ? ((void *)&Memory::Write_U32) : ((void *)&Memory::Write_U32_Swap), reg_value, reg_addr, false);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
ABI_CallFunctionRR(swap ? ((void *)&Memory::Write_U16) : ((void *)&Memory::Write_U16_Swap), reg_value, reg_addr, false);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
ABI_CallFunctionRR((void *)&Memory::Write_U8, reg_value, reg_addr, false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
ABI_PopRegistersAndAdjustStack(registersInUse, noProlog);
|
ABI_PopRegistersAndAdjustStack(registersInUse, noProlog);
|
||||||
FixupBranch exit = J();
|
FixupBranch exit = J();
|
||||||
|
@ -478,7 +499,8 @@ void EmuCodeBlock::WriteToConstRamAddress(int accessSize, Gen::X64Reg arg, u32 a
|
||||||
MOV(accessSize, MDisp(RBX, address & 0x3FFFFFFF), R(arg));
|
MOV(accessSize, MDisp(RBX, address & 0x3FFFFFFF), R(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuCodeBlock::ForceSinglePrecisionS(X64Reg xmm) {
|
void EmuCodeBlock::ForceSinglePrecisionS(X64Reg xmm)
|
||||||
|
{
|
||||||
// Most games don't need these. Zelda requires it though - some platforms get stuck without them.
|
// Most games don't need these. Zelda requires it though - some platforms get stuck without them.
|
||||||
if (jit->jo.accurateSinglePrecision)
|
if (jit->jo.accurateSinglePrecision)
|
||||||
{
|
{
|
||||||
|
@ -487,7 +509,8 @@ void EmuCodeBlock::ForceSinglePrecisionS(X64Reg xmm) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuCodeBlock::ForceSinglePrecisionP(X64Reg xmm) {
|
void EmuCodeBlock::ForceSinglePrecisionP(X64Reg xmm)
|
||||||
|
{
|
||||||
// Most games don't need these. Zelda requires it though - some platforms get stuck without them.
|
// Most games don't need these. Zelda requires it though - some platforms get stuck without them.
|
||||||
if (jit->jo.accurateSinglePrecision)
|
if (jit->jo.accurateSinglePrecision)
|
||||||
{
|
{
|
||||||
|
@ -600,10 +623,13 @@ void EmuCodeBlock::ConvertDoubleToSingle(X64Reg dst, X64Reg src)
|
||||||
MOVSD(XMM1, R(src));
|
MOVSD(XMM1, R(src));
|
||||||
FLD(64, M(&temp64));
|
FLD(64, M(&temp64));
|
||||||
CCFlags cond;
|
CCFlags cond;
|
||||||
if (cpu_info.bSSE4_1) {
|
if (cpu_info.bSSE4_1)
|
||||||
|
{
|
||||||
PTEST(XMM1, M((void *)&double_exponent));
|
PTEST(XMM1, M((void *)&double_exponent));
|
||||||
cond = CC_NC;
|
cond = CC_NC;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// emulate PTEST; checking FPU flags is incorrect because the NaN bits
|
// emulate PTEST; checking FPU flags is incorrect because the NaN bits
|
||||||
// are sticky (persist between instructions)
|
// are sticky (persist between instructions)
|
||||||
MOVSD(XMM0, M((void *)&double_exponent));
|
MOVSD(XMM0, M((void *)&double_exponent));
|
||||||
|
@ -619,9 +645,12 @@ void EmuCodeBlock::ConvertDoubleToSingle(X64Reg dst, X64Reg src)
|
||||||
|
|
||||||
PANDN(XMM1, M((void *)&double_qnan_bit));
|
PANDN(XMM1, M((void *)&double_qnan_bit));
|
||||||
PSRLQ(XMM1, 29);
|
PSRLQ(XMM1, 29);
|
||||||
if (cpu_info.bAVX) {
|
if (cpu_info.bAVX)
|
||||||
|
{
|
||||||
VPANDN(XMM0, XMM1, R(XMM0));
|
VPANDN(XMM0, XMM1, R(XMM0));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
PANDN(XMM1, R(XMM0));
|
PANDN(XMM1, R(XMM0));
|
||||||
MOVSS(XMM0, R(XMM1));
|
MOVSS(XMM0, R(XMM1));
|
||||||
}
|
}
|
||||||
|
@ -633,19 +662,26 @@ void EmuCodeBlock::ConvertDoubleToSingle(X64Reg dst, X64Reg src)
|
||||||
|
|
||||||
void EmuCodeBlock::ConvertSingleToDouble(X64Reg dst, X64Reg src, bool src_is_gpr)
|
void EmuCodeBlock::ConvertSingleToDouble(X64Reg dst, X64Reg src, bool src_is_gpr)
|
||||||
{
|
{
|
||||||
if (src_is_gpr) {
|
if (src_is_gpr)
|
||||||
|
{
|
||||||
MOV(32, M(&temp32), R(src));
|
MOV(32, M(&temp32), R(src));
|
||||||
MOVD_xmm(XMM1, R(src));
|
MOVD_xmm(XMM1, R(src));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
MOVSS(M(&temp32), src);
|
MOVSS(M(&temp32), src);
|
||||||
MOVSS(R(XMM1), src);
|
MOVSS(R(XMM1), src);
|
||||||
}
|
}
|
||||||
|
|
||||||
FLD(32, M(&temp32));
|
FLD(32, M(&temp32));
|
||||||
CCFlags cond;
|
CCFlags cond;
|
||||||
if (cpu_info.bSSE4_1) {
|
if (cpu_info.bSSE4_1)
|
||||||
|
{
|
||||||
PTEST(XMM1, M((void *)&single_exponent));
|
PTEST(XMM1, M((void *)&single_exponent));
|
||||||
cond = CC_NC;
|
cond = CC_NC;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// emulate PTEST; checking FPU flags is incorrect because the NaN bits
|
// emulate PTEST; checking FPU flags is incorrect because the NaN bits
|
||||||
// are sticky (persist between instructions)
|
// are sticky (persist between instructions)
|
||||||
MOVSS(XMM0, M((void *)&single_exponent));
|
MOVSS(XMM0, M((void *)&single_exponent));
|
||||||
|
@ -661,9 +697,12 @@ void EmuCodeBlock::ConvertSingleToDouble(X64Reg dst, X64Reg src, bool src_is_gpr
|
||||||
|
|
||||||
PANDN(XMM1, M((void *)&single_qnan_bit));
|
PANDN(XMM1, M((void *)&single_qnan_bit));
|
||||||
PSLLQ(XMM1, 29);
|
PSLLQ(XMM1, 29);
|
||||||
if (cpu_info.bAVX) {
|
if (cpu_info.bAVX)
|
||||||
|
{
|
||||||
VPANDN(dst, XMM1, R(dst));
|
VPANDN(dst, XMM1, R(dst));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
PANDN(XMM1, R(dst));
|
PANDN(XMM1, R(dst));
|
||||||
MOVSD(dst, R(XMM1));
|
MOVSD(dst, R(XMM1));
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,8 +8,11 @@
|
||||||
|
|
||||||
#include "Common/x64Emitter.h"
|
#include "Common/x64Emitter.h"
|
||||||
|
|
||||||
namespace IREmitter {
|
namespace IREmitter
|
||||||
enum Opcode {
|
{
|
||||||
|
|
||||||
|
enum Opcode
|
||||||
|
{
|
||||||
Nop = 0,
|
Nop = 0,
|
||||||
|
|
||||||
// "Zero-operand" operators
|
// "Zero-operand" operators
|
||||||
|
@ -177,46 +180,57 @@ enum Opcode {
|
||||||
typedef unsigned Inst;
|
typedef unsigned Inst;
|
||||||
typedef Inst* InstLoc;
|
typedef Inst* InstLoc;
|
||||||
|
|
||||||
unsigned inline getOpcode(Inst i) {
|
unsigned inline getOpcode(Inst i)
|
||||||
|
{
|
||||||
return i & 255;
|
return i & 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned inline isImm(Inst i) {
|
unsigned inline isImm(Inst i)
|
||||||
|
{
|
||||||
return getOpcode(i) >= CInt16 && getOpcode(i) <= CInt32;
|
return getOpcode(i) >= CInt16 && getOpcode(i) <= CInt32;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned inline isICmp(Inst i) {
|
unsigned inline isICmp(Inst i)
|
||||||
|
{
|
||||||
return getOpcode(i) >= ICmpEq && getOpcode(i) <= ICmpSle;
|
return getOpcode(i) >= ICmpEq && getOpcode(i) <= ICmpSle;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned inline isFResult(Inst i) {
|
unsigned inline isFResult(Inst i)
|
||||||
|
{
|
||||||
return getOpcode(i) > FResult_Start &&
|
return getOpcode(i) > FResult_Start &&
|
||||||
getOpcode(i) < FResult_End;
|
getOpcode(i) < FResult_End;
|
||||||
}
|
}
|
||||||
|
|
||||||
InstLoc inline getOp1(InstLoc i) {
|
InstLoc inline getOp1(InstLoc i)
|
||||||
|
{
|
||||||
i = i - 1 - ((*i >> 8) & 255);
|
i = i - 1 - ((*i >> 8) & 255);
|
||||||
if (getOpcode(*i) == Tramp) {
|
|
||||||
|
if (getOpcode(*i) == Tramp)
|
||||||
|
{
|
||||||
i = i - 1 - (*i >> 8);
|
i = i - 1 - (*i >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
InstLoc inline getOp2(InstLoc i) {
|
InstLoc inline getOp2(InstLoc i)
|
||||||
|
{
|
||||||
i = i - 1 - ((*i >> 16) & 255);
|
i = i - 1 - ((*i >> 16) & 255);
|
||||||
if (getOpcode(*i) == Tramp) {
|
|
||||||
|
if (getOpcode(*i) == Tramp)
|
||||||
|
{
|
||||||
i = i - 1 - (*i >> 8);
|
i = i - 1 - (*i >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
class IRBuilder {
|
class IRBuilder
|
||||||
|
{
|
||||||
private:
|
private:
|
||||||
InstLoc EmitZeroOp(unsigned Opcode, unsigned extra);
|
InstLoc EmitZeroOp(unsigned Opcode, unsigned extra);
|
||||||
InstLoc EmitUOp(unsigned OpCode, InstLoc Op1,
|
InstLoc EmitUOp(unsigned OpCode, InstLoc Op1, unsigned extra = 0);
|
||||||
unsigned extra = 0);
|
InstLoc EmitBiOp(unsigned OpCode, InstLoc Op1, InstLoc Op2, unsigned extra = 0);
|
||||||
InstLoc EmitBiOp(unsigned OpCode, InstLoc Op1, InstLoc Op2,
|
|
||||||
unsigned extra = 0);
|
|
||||||
|
|
||||||
InstLoc FoldAdd(InstLoc Op1, InstLoc Op2);
|
InstLoc FoldAdd(InstLoc Op1, InstLoc Op2);
|
||||||
InstLoc FoldSub(InstLoc Op1, InstLoc Op2);
|
InstLoc FoldSub(InstLoc Op1, InstLoc Op2);
|
||||||
|
@ -238,316 +252,515 @@ private:
|
||||||
InstLoc FoldFallBackToInterpreter(InstLoc Op1, InstLoc Op2);
|
InstLoc FoldFallBackToInterpreter(InstLoc Op1, InstLoc Op2);
|
||||||
|
|
||||||
InstLoc FoldZeroOp(unsigned Opcode, unsigned extra);
|
InstLoc FoldZeroOp(unsigned Opcode, unsigned extra);
|
||||||
InstLoc FoldUOp(unsigned OpCode, InstLoc Op1,
|
InstLoc FoldUOp(unsigned OpCode, InstLoc Op1, unsigned extra = 0);
|
||||||
unsigned extra = 0);
|
InstLoc FoldBiOp(unsigned OpCode, InstLoc Op1, InstLoc Op2, unsigned extra = 0);
|
||||||
InstLoc FoldBiOp(unsigned OpCode, InstLoc Op1, InstLoc Op2,
|
|
||||||
unsigned extra = 0);
|
|
||||||
|
|
||||||
unsigned ComputeKnownZeroBits(InstLoc I) const;
|
unsigned ComputeKnownZeroBits(InstLoc I) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InstLoc EmitIntConst(unsigned value) { return EmitIntConst64(value); }
|
InstLoc EmitIntConst(unsigned value) { return EmitIntConst64(value); }
|
||||||
InstLoc EmitIntConst64(u64 value);
|
InstLoc EmitIntConst64(u64 value);
|
||||||
InstLoc EmitStoreLink(InstLoc val) {
|
|
||||||
|
InstLoc EmitStoreLink(InstLoc val)
|
||||||
|
{
|
||||||
return FoldUOp(StoreLink, val);
|
return FoldUOp(StoreLink, val);
|
||||||
}
|
}
|
||||||
InstLoc EmitBranchUncond(InstLoc val) {
|
|
||||||
|
InstLoc EmitBranchUncond(InstLoc val)
|
||||||
|
{
|
||||||
return FoldUOp(BranchUncond, val);
|
return FoldUOp(BranchUncond, val);
|
||||||
}
|
}
|
||||||
InstLoc EmitBranchCond(InstLoc check, InstLoc dest) {
|
|
||||||
|
InstLoc EmitBranchCond(InstLoc check, InstLoc dest)
|
||||||
|
{
|
||||||
return FoldBiOp(BranchCond, check, dest);
|
return FoldBiOp(BranchCond, check, dest);
|
||||||
}
|
}
|
||||||
InstLoc EmitIdleBranch(InstLoc check, InstLoc dest) {
|
|
||||||
|
InstLoc EmitIdleBranch(InstLoc check, InstLoc dest)
|
||||||
|
{
|
||||||
return FoldBiOp(IdleBranch, check, dest);
|
return FoldBiOp(IdleBranch, check, dest);
|
||||||
}
|
}
|
||||||
InstLoc EmitLoadCR(unsigned crreg) {
|
|
||||||
|
InstLoc EmitLoadCR(unsigned crreg)
|
||||||
|
{
|
||||||
return FoldZeroOp(LoadCR, crreg);
|
return FoldZeroOp(LoadCR, crreg);
|
||||||
}
|
}
|
||||||
InstLoc EmitStoreCR(InstLoc value, unsigned crreg) {
|
|
||||||
|
InstLoc EmitStoreCR(InstLoc value, unsigned crreg)
|
||||||
|
{
|
||||||
return FoldUOp(StoreCR, value, crreg);
|
return FoldUOp(StoreCR, value, crreg);
|
||||||
}
|
}
|
||||||
InstLoc EmitLoadLink() {
|
|
||||||
|
InstLoc EmitLoadLink()
|
||||||
|
{
|
||||||
return FoldZeroOp(LoadLink, 0);
|
return FoldZeroOp(LoadLink, 0);
|
||||||
}
|
}
|
||||||
InstLoc EmitLoadMSR() {
|
|
||||||
|
InstLoc EmitLoadMSR()
|
||||||
|
{
|
||||||
return FoldZeroOp(LoadMSR, 0);
|
return FoldZeroOp(LoadMSR, 0);
|
||||||
}
|
}
|
||||||
InstLoc EmitStoreMSR(InstLoc val, InstLoc pc) {
|
|
||||||
|
InstLoc EmitStoreMSR(InstLoc val, InstLoc pc)
|
||||||
|
{
|
||||||
return FoldBiOp(StoreMSR, val, pc);
|
return FoldBiOp(StoreMSR, val, pc);
|
||||||
}
|
}
|
||||||
InstLoc EmitStoreFPRF(InstLoc value) {
|
|
||||||
|
InstLoc EmitStoreFPRF(InstLoc value)
|
||||||
|
{
|
||||||
return FoldUOp(StoreFPRF, value);
|
return FoldUOp(StoreFPRF, value);
|
||||||
}
|
}
|
||||||
InstLoc EmitLoadGReg(unsigned reg) {
|
|
||||||
|
InstLoc EmitLoadGReg(unsigned reg)
|
||||||
|
{
|
||||||
return FoldZeroOp(LoadGReg, reg);
|
return FoldZeroOp(LoadGReg, reg);
|
||||||
}
|
}
|
||||||
InstLoc EmitStoreGReg(InstLoc value, unsigned reg) {
|
|
||||||
|
InstLoc EmitStoreGReg(InstLoc value, unsigned reg)
|
||||||
|
{
|
||||||
return FoldUOp(StoreGReg, value, reg);
|
return FoldUOp(StoreGReg, value, reg);
|
||||||
}
|
}
|
||||||
InstLoc EmitNot(InstLoc op1) {
|
|
||||||
|
InstLoc EmitNot(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(Not, op1);
|
return FoldUOp(Not, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitAnd(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitAnd(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(And, op1, op2);
|
return FoldBiOp(And, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitXor(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitXor(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(Xor, op1, op2);
|
return FoldBiOp(Xor, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitSub(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitSub(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(Sub, op1, op2);
|
return FoldBiOp(Sub, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitOr(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitOr(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(Or, op1, op2);
|
return FoldBiOp(Or, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitAdd(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitAdd(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(Add, op1, op2);
|
return FoldBiOp(Add, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitMul(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitMul(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(Mul, op1, op2);
|
return FoldBiOp(Mul, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitMulHighUnsigned(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitMulHighUnsigned(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(MulHighUnsigned, op1, op2);
|
return FoldBiOp(MulHighUnsigned, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitRol(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitRol(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(Rol, op1, op2);
|
return FoldBiOp(Rol, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitShl(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitShl(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(Shl, op1, op2);
|
return FoldBiOp(Shl, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitShrl(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitShrl(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(Shrl, op1, op2);
|
return FoldBiOp(Shrl, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitSarl(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitSarl(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(Sarl, op1, op2);
|
return FoldBiOp(Sarl, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitLoadCTR() {
|
|
||||||
|
InstLoc EmitLoadCTR()
|
||||||
|
{
|
||||||
return FoldZeroOp(LoadCTR, 0);
|
return FoldZeroOp(LoadCTR, 0);
|
||||||
}
|
}
|
||||||
InstLoc EmitStoreCTR(InstLoc op1) {
|
|
||||||
|
InstLoc EmitStoreCTR(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(StoreCTR, op1);
|
return FoldUOp(StoreCTR, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitICmpEq(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitICmpEq(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(ICmpEq, op1, op2);
|
return FoldBiOp(ICmpEq, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitICmpNe(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitICmpNe(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(ICmpNe, op1, op2);
|
return FoldBiOp(ICmpNe, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitICmpUgt(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitICmpUgt(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(ICmpUgt, op1, op2);
|
return FoldBiOp(ICmpUgt, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitICmpUlt(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitICmpUlt(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(ICmpUlt, op1, op2);
|
return FoldBiOp(ICmpUlt, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitICmpSgt(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitICmpSgt(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(ICmpSgt, op1, op2);
|
return FoldBiOp(ICmpSgt, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitICmpSlt(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitICmpSlt(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(ICmpSlt, op1, op2);
|
return FoldBiOp(ICmpSlt, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitICmpSge(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitICmpSge(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(ICmpSge, op1, op2);
|
return FoldBiOp(ICmpSge, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitICmpSle(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitICmpSle(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(ICmpSle, op1, op2);
|
return FoldBiOp(ICmpSle, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitLoad8(InstLoc op1) {
|
|
||||||
|
InstLoc EmitLoad8(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(Load8, op1);
|
return FoldUOp(Load8, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitLoad16(InstLoc op1) {
|
|
||||||
|
InstLoc EmitLoad16(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(Load16, op1);
|
return FoldUOp(Load16, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitLoad32(InstLoc op1) {
|
|
||||||
|
InstLoc EmitLoad32(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(Load32, op1);
|
return FoldUOp(Load32, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitStore8(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitStore8(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(Store8, op1, op2);
|
return FoldBiOp(Store8, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitStore16(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitStore16(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(Store16, op1, op2);
|
return FoldBiOp(Store16, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitStore32(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitStore32(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(Store32, op1, op2);
|
return FoldBiOp(Store32, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitSExt16(InstLoc op1) {
|
|
||||||
|
InstLoc EmitSExt16(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(SExt16, op1);
|
return FoldUOp(SExt16, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitSExt8(InstLoc op1) {
|
|
||||||
|
InstLoc EmitSExt8(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(SExt8, op1);
|
return FoldUOp(SExt8, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitCntlzw(InstLoc op1) {
|
|
||||||
|
InstLoc EmitCntlzw(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(Cntlzw, op1);
|
return FoldUOp(Cntlzw, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitICmpCRSigned(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitICmpCRSigned(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(ICmpCRSigned, op1, op2);
|
return FoldBiOp(ICmpCRSigned, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitICmpCRUnsigned(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitICmpCRUnsigned(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(ICmpCRUnsigned, op1, op2);
|
return FoldBiOp(ICmpCRUnsigned, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitConvertFromFastCR(InstLoc op1) {
|
|
||||||
|
InstLoc EmitConvertFromFastCR(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(ConvertFromFastCR, op1);
|
return FoldUOp(ConvertFromFastCR, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitConvertToFastCR(InstLoc op1) {
|
|
||||||
|
InstLoc EmitConvertToFastCR(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(ConvertToFastCR, op1);
|
return FoldUOp(ConvertToFastCR, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitFastCRSOSet(InstLoc op1) {
|
|
||||||
|
InstLoc EmitFastCRSOSet(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(FastCRSOSet, op1);
|
return FoldUOp(FastCRSOSet, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitFastCREQSet(InstLoc op1) {
|
|
||||||
|
InstLoc EmitFastCREQSet(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(FastCREQSet, op1);
|
return FoldUOp(FastCREQSet, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitFastCRLTSet(InstLoc op1) {
|
|
||||||
|
InstLoc EmitFastCRLTSet(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(FastCRLTSet, op1);
|
return FoldUOp(FastCRLTSet, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitFastCRGTSet(InstLoc op1) {
|
|
||||||
|
InstLoc EmitFastCRGTSet(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(FastCRGTSet, op1);
|
return FoldUOp(FastCRGTSet, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitFallBackToInterpreter(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitFallBackToInterpreter(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(FallBackToInterpreter, op1, op2);
|
return FoldBiOp(FallBackToInterpreter, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitInterpreterBranch() {
|
|
||||||
|
InstLoc EmitInterpreterBranch()
|
||||||
|
{
|
||||||
return FoldZeroOp(InterpreterBranch, 0);
|
return FoldZeroOp(InterpreterBranch, 0);
|
||||||
}
|
}
|
||||||
InstLoc EmitLoadCarry() {
|
|
||||||
|
InstLoc EmitLoadCarry()
|
||||||
|
{
|
||||||
return FoldZeroOp(LoadCarry, 0);
|
return FoldZeroOp(LoadCarry, 0);
|
||||||
}
|
}
|
||||||
InstLoc EmitStoreCarry(InstLoc op1) {
|
|
||||||
|
InstLoc EmitStoreCarry(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(StoreCarry, op1);
|
return FoldUOp(StoreCarry, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitSystemCall(InstLoc pc) {
|
|
||||||
|
InstLoc EmitSystemCall(InstLoc pc)
|
||||||
|
{
|
||||||
return FoldUOp(SystemCall, pc);
|
return FoldUOp(SystemCall, pc);
|
||||||
}
|
}
|
||||||
InstLoc EmitFPExceptionCheck(InstLoc pc) {
|
|
||||||
|
InstLoc EmitFPExceptionCheck(InstLoc pc)
|
||||||
|
{
|
||||||
return EmitUOp(FPExceptionCheck, pc);
|
return EmitUOp(FPExceptionCheck, pc);
|
||||||
}
|
}
|
||||||
InstLoc EmitDSIExceptionCheck(InstLoc pc) {
|
|
||||||
|
InstLoc EmitDSIExceptionCheck(InstLoc pc)
|
||||||
|
{
|
||||||
return EmitUOp(DSIExceptionCheck, pc);
|
return EmitUOp(DSIExceptionCheck, pc);
|
||||||
}
|
}
|
||||||
InstLoc EmitISIException(InstLoc dest) {
|
|
||||||
|
InstLoc EmitISIException(InstLoc dest)
|
||||||
|
{
|
||||||
return EmitUOp(ISIException, dest);
|
return EmitUOp(ISIException, dest);
|
||||||
}
|
}
|
||||||
InstLoc EmitExtExceptionCheck(InstLoc pc) {
|
|
||||||
|
InstLoc EmitExtExceptionCheck(InstLoc pc)
|
||||||
|
{
|
||||||
return EmitUOp(ExtExceptionCheck, pc);
|
return EmitUOp(ExtExceptionCheck, pc);
|
||||||
}
|
}
|
||||||
InstLoc EmitBreakPointCheck(InstLoc pc) {
|
|
||||||
|
InstLoc EmitBreakPointCheck(InstLoc pc)
|
||||||
|
{
|
||||||
return EmitUOp(BreakPointCheck, pc);
|
return EmitUOp(BreakPointCheck, pc);
|
||||||
}
|
}
|
||||||
InstLoc EmitRFIExit() {
|
|
||||||
|
InstLoc EmitRFIExit()
|
||||||
|
{
|
||||||
return FoldZeroOp(RFIExit, 0);
|
return FoldZeroOp(RFIExit, 0);
|
||||||
}
|
}
|
||||||
InstLoc EmitShortIdleLoop(InstLoc pc) {
|
|
||||||
|
InstLoc EmitShortIdleLoop(InstLoc pc)
|
||||||
|
{
|
||||||
return FoldUOp(ShortIdleLoop, pc);
|
return FoldUOp(ShortIdleLoop, pc);
|
||||||
}
|
}
|
||||||
InstLoc EmitLoadSingle(InstLoc addr) {
|
|
||||||
|
InstLoc EmitLoadSingle(InstLoc addr)
|
||||||
|
{
|
||||||
return FoldUOp(LoadSingle, addr);
|
return FoldUOp(LoadSingle, addr);
|
||||||
}
|
}
|
||||||
InstLoc EmitLoadDouble(InstLoc addr) {
|
|
||||||
|
InstLoc EmitLoadDouble(InstLoc addr)
|
||||||
|
{
|
||||||
return FoldUOp(LoadDouble, addr);
|
return FoldUOp(LoadDouble, addr);
|
||||||
}
|
}
|
||||||
InstLoc EmitLoadPaired(InstLoc addr, unsigned quantReg) {
|
|
||||||
|
InstLoc EmitLoadPaired(InstLoc addr, unsigned quantReg)
|
||||||
|
{
|
||||||
return FoldUOp(LoadPaired, addr, quantReg);
|
return FoldUOp(LoadPaired, addr, quantReg);
|
||||||
}
|
}
|
||||||
InstLoc EmitStoreSingle(InstLoc value, InstLoc addr) {
|
|
||||||
|
InstLoc EmitStoreSingle(InstLoc value, InstLoc addr)
|
||||||
|
{
|
||||||
return FoldBiOp(StoreSingle, value, addr);
|
return FoldBiOp(StoreSingle, value, addr);
|
||||||
}
|
}
|
||||||
InstLoc EmitStoreDouble(InstLoc value, InstLoc addr) {
|
|
||||||
|
InstLoc EmitStoreDouble(InstLoc value, InstLoc addr)
|
||||||
|
{
|
||||||
return FoldBiOp(StoreDouble, value, addr);
|
return FoldBiOp(StoreDouble, value, addr);
|
||||||
}
|
}
|
||||||
InstLoc EmitStorePaired(InstLoc value, InstLoc addr, unsigned quantReg) {
|
|
||||||
|
InstLoc EmitStorePaired(InstLoc value, InstLoc addr, unsigned quantReg)
|
||||||
|
{
|
||||||
return FoldBiOp(StorePaired, value, addr, quantReg);
|
return FoldBiOp(StorePaired, value, addr, quantReg);
|
||||||
}
|
}
|
||||||
InstLoc EmitLoadFReg(unsigned freg) {
|
|
||||||
|
InstLoc EmitLoadFReg(unsigned freg)
|
||||||
|
{
|
||||||
return FoldZeroOp(LoadFReg, freg);
|
return FoldZeroOp(LoadFReg, freg);
|
||||||
}
|
}
|
||||||
InstLoc EmitLoadFRegDENToZero(unsigned freg) {
|
|
||||||
|
InstLoc EmitLoadFRegDENToZero(unsigned freg)
|
||||||
|
{
|
||||||
return FoldZeroOp(LoadFRegDENToZero, freg);
|
return FoldZeroOp(LoadFRegDENToZero, freg);
|
||||||
}
|
}
|
||||||
InstLoc EmitStoreFReg(InstLoc val, unsigned freg) {
|
|
||||||
|
InstLoc EmitStoreFReg(InstLoc val, unsigned freg)
|
||||||
|
{
|
||||||
return FoldUOp(StoreFReg, val, freg);
|
return FoldUOp(StoreFReg, val, freg);
|
||||||
}
|
}
|
||||||
InstLoc EmitDupSingleToMReg(InstLoc val) {
|
|
||||||
|
InstLoc EmitDupSingleToMReg(InstLoc val)
|
||||||
|
{
|
||||||
return FoldUOp(DupSingleToMReg, val);
|
return FoldUOp(DupSingleToMReg, val);
|
||||||
}
|
}
|
||||||
InstLoc EmitDupSingleToPacked(InstLoc val) {
|
|
||||||
|
InstLoc EmitDupSingleToPacked(InstLoc val)
|
||||||
|
{
|
||||||
return FoldUOp(DupSingleToPacked, val);
|
return FoldUOp(DupSingleToPacked, val);
|
||||||
}
|
}
|
||||||
InstLoc EmitInsertDoubleInMReg(InstLoc val, InstLoc reg) {
|
|
||||||
|
InstLoc EmitInsertDoubleInMReg(InstLoc val, InstLoc reg)
|
||||||
|
{
|
||||||
return FoldBiOp(InsertDoubleInMReg, val, reg);
|
return FoldBiOp(InsertDoubleInMReg, val, reg);
|
||||||
}
|
}
|
||||||
InstLoc EmitExpandPackedToMReg(InstLoc val) {
|
|
||||||
|
InstLoc EmitExpandPackedToMReg(InstLoc val)
|
||||||
|
{
|
||||||
return FoldUOp(ExpandPackedToMReg, val);
|
return FoldUOp(ExpandPackedToMReg, val);
|
||||||
}
|
}
|
||||||
InstLoc EmitCompactMRegToPacked(InstLoc val) {
|
|
||||||
|
InstLoc EmitCompactMRegToPacked(InstLoc val)
|
||||||
|
{
|
||||||
return FoldUOp(CompactMRegToPacked, val);
|
return FoldUOp(CompactMRegToPacked, val);
|
||||||
}
|
}
|
||||||
InstLoc EmitFSMul(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitFSMul(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(FSMul, op1, op2);
|
return FoldBiOp(FSMul, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitFSAdd(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitFSAdd(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(FSAdd, op1, op2);
|
return FoldBiOp(FSAdd, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitFSSub(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitFSSub(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(FSSub, op1, op2);
|
return FoldBiOp(FSSub, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitFSNeg(InstLoc op1) {
|
|
||||||
|
InstLoc EmitFSNeg(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(FSNeg, op1);
|
return FoldUOp(FSNeg, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitFDMul(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitFDMul(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(FDMul, op1, op2);
|
return FoldBiOp(FDMul, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitFDAdd(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitFDAdd(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(FDAdd, op1, op2);
|
return FoldBiOp(FDAdd, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitFDSub(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitFDSub(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(FDSub, op1, op2);
|
return FoldBiOp(FDSub, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitFDNeg(InstLoc op1) {
|
|
||||||
|
InstLoc EmitFDNeg(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(FDNeg, op1);
|
return FoldUOp(FDNeg, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitFPAdd(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitFPAdd(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(FPAdd, op1, op2);
|
return FoldBiOp(FPAdd, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitFPMul(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitFPMul(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(FPMul, op1, op2);
|
return FoldBiOp(FPMul, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitFPSub(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitFPSub(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(FPSub, op1, op2);
|
return FoldBiOp(FPSub, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitFPMerge00(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitFPMerge00(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(FPMerge00, op1, op2);
|
return FoldBiOp(FPMerge00, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitFPMerge01(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitFPMerge01(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(FPMerge01, op1, op2);
|
return FoldBiOp(FPMerge01, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitFPMerge10(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitFPMerge10(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(FPMerge10, op1, op2);
|
return FoldBiOp(FPMerge10, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitFPMerge11(InstLoc op1, InstLoc op2) {
|
|
||||||
|
InstLoc EmitFPMerge11(InstLoc op1, InstLoc op2)
|
||||||
|
{
|
||||||
return FoldBiOp(FPMerge11, op1, op2);
|
return FoldBiOp(FPMerge11, op1, op2);
|
||||||
}
|
}
|
||||||
InstLoc EmitFPDup0(InstLoc op1) {
|
|
||||||
|
InstLoc EmitFPDup0(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(FPDup0, op1);
|
return FoldUOp(FPDup0, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitFPDup1(InstLoc op1) {
|
|
||||||
|
InstLoc EmitFPDup1(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(FPDup1, op1);
|
return FoldUOp(FPDup1, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitFPNeg(InstLoc op1) {
|
|
||||||
|
InstLoc EmitFPNeg(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(FPNeg, op1);
|
return FoldUOp(FPNeg, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitDoubleToSingle(InstLoc op1) {
|
|
||||||
|
InstLoc EmitDoubleToSingle(InstLoc op1)
|
||||||
|
{
|
||||||
return FoldUOp(DoubleToSingle, op1);
|
return FoldUOp(DoubleToSingle, op1);
|
||||||
}
|
}
|
||||||
InstLoc EmitFDCmpCR(InstLoc op1, InstLoc op2, int ordered) {
|
|
||||||
|
InstLoc EmitFDCmpCR(InstLoc op1, InstLoc op2, int ordered)
|
||||||
|
{
|
||||||
return FoldBiOp(FDCmpCR, op1, op2, ordered);
|
return FoldBiOp(FDCmpCR, op1, op2, ordered);
|
||||||
}
|
}
|
||||||
InstLoc EmitLoadGQR(unsigned gqr) {
|
|
||||||
|
InstLoc EmitLoadGQR(unsigned gqr)
|
||||||
|
{
|
||||||
return FoldZeroOp(LoadGQR, gqr);
|
return FoldZeroOp(LoadGQR, gqr);
|
||||||
}
|
}
|
||||||
InstLoc EmitStoreGQR(InstLoc op1, unsigned gqr) {
|
|
||||||
|
InstLoc EmitStoreGQR(InstLoc op1, unsigned gqr)
|
||||||
|
{
|
||||||
return FoldUOp(StoreGQR, op1, gqr);
|
return FoldUOp(StoreGQR, op1, gqr);
|
||||||
}
|
}
|
||||||
InstLoc EmitStoreSRR(InstLoc op1, unsigned srr) {
|
|
||||||
|
InstLoc EmitStoreSRR(InstLoc op1, unsigned srr)
|
||||||
|
{
|
||||||
return FoldUOp(StoreSRR, op1, srr);
|
return FoldUOp(StoreSRR, op1, srr);
|
||||||
}
|
}
|
||||||
|
|
||||||
InstLoc EmitINT3()
|
InstLoc EmitINT3()
|
||||||
{
|
{
|
||||||
return FoldZeroOp(Int3, 0);
|
return FoldZeroOp(Int3, 0);
|
||||||
|
@ -566,28 +779,38 @@ public:
|
||||||
bool IsMarkUsed(InstLoc I) const;
|
bool IsMarkUsed(InstLoc I) const;
|
||||||
void WriteToFile(u64 codeHash);
|
void WriteToFile(u64 codeHash);
|
||||||
|
|
||||||
void Reset() {
|
void Reset()
|
||||||
|
{
|
||||||
InstList.clear();
|
InstList.clear();
|
||||||
InstList.reserve(100000);
|
InstList.reserve(100000);
|
||||||
MarkUsed.clear();
|
MarkUsed.clear();
|
||||||
MarkUsed.reserve(100000);
|
MarkUsed.reserve(100000);
|
||||||
for (unsigned i = 0; i < 32; i++) {
|
|
||||||
|
for (unsigned i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
GRegCache[i] = nullptr;
|
GRegCache[i] = nullptr;
|
||||||
GRegCacheStore[i] = nullptr;
|
GRegCacheStore[i] = nullptr;
|
||||||
FRegCache[i] = nullptr;
|
FRegCache[i] = nullptr;
|
||||||
FRegCacheStore[i] = nullptr;
|
FRegCacheStore[i] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CarryCache = nullptr;
|
CarryCache = nullptr;
|
||||||
CarryCacheStore = nullptr;
|
CarryCacheStore = nullptr;
|
||||||
for (unsigned i = 0; i < 8; i++) {
|
|
||||||
|
for (unsigned i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
CRCache[i] = nullptr;
|
CRCache[i] = nullptr;
|
||||||
CRCacheStore[i] = nullptr;
|
CRCacheStore[i] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CTRCache = nullptr;
|
CTRCache = nullptr;
|
||||||
CTRCacheStore = nullptr;
|
CTRCacheStore = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
IRBuilder() { Reset(); }
|
IRBuilder()
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IRBuilder(IRBuilder&); // DO NOT IMPLEMENT
|
IRBuilder(IRBuilder&); // DO NOT IMPLEMENT
|
||||||
|
|
|
@ -43,7 +43,8 @@ void JitILBase::bx(UGeckoInstruction inst)
|
||||||
// If this is not the last instruction of a block,
|
// If this is not the last instruction of a block,
|
||||||
// we will skip the rest process.
|
// we will skip the rest process.
|
||||||
// Because PPCAnalyst::Flatten() merged the blocks.
|
// Because PPCAnalyst::Flatten() merged the blocks.
|
||||||
if (!js.isLastInstruction) {
|
if (!js.isLastInstruction)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +54,8 @@ void JitILBase::bx(UGeckoInstruction inst)
|
||||||
else
|
else
|
||||||
destination = js.compilerPC + SignExt26(inst.LI << 2);
|
destination = js.compilerPC + SignExt26(inst.LI << 2);
|
||||||
|
|
||||||
if (destination == js.compilerPC) {
|
if (destination == js.compilerPC)
|
||||||
|
{
|
||||||
ibuild.EmitShortIdleLoop(ibuild.EmitIntConst(js.compilerPC));
|
ibuild.EmitShortIdleLoop(ibuild.EmitIntConst(js.compilerPC));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -85,36 +87,40 @@ static IREmitter::InstLoc EmitCRTest(IREmitter::IRBuilder& ibuild, UGeckoInstruc
|
||||||
return CRTest;
|
return CRTest;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IREmitter::InstLoc TestBranch(IREmitter::IRBuilder& ibuild, UGeckoInstruction inst) {
|
static IREmitter::InstLoc TestBranch(IREmitter::IRBuilder& ibuild, UGeckoInstruction inst)
|
||||||
|
{
|
||||||
IREmitter::InstLoc CRTest = nullptr, CTRTest = nullptr;
|
IREmitter::InstLoc CRTest = nullptr, CTRTest = nullptr;
|
||||||
if ((inst.BO & 16) == 0) // Test a CR bit
|
if ((inst.BO & 16) == 0) // Test a CR bit
|
||||||
{
|
{
|
||||||
CRTest = EmitCRTest(ibuild, inst);
|
CRTest = EmitCRTest(ibuild, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((inst.BO & 4) == 0) {
|
if ((inst.BO & 4) == 0)
|
||||||
|
{
|
||||||
IREmitter::InstLoc c = ibuild.EmitLoadCTR();
|
IREmitter::InstLoc c = ibuild.EmitLoadCTR();
|
||||||
c = ibuild.EmitSub(c, ibuild.EmitIntConst(1));
|
c = ibuild.EmitSub(c, ibuild.EmitIntConst(1));
|
||||||
ibuild.EmitStoreCTR(c);
|
ibuild.EmitStoreCTR(c);
|
||||||
if (inst.BO & 2) {
|
|
||||||
CTRTest = ibuild.EmitICmpEq(c,
|
if (inst.BO & 2)
|
||||||
ibuild.EmitIntConst(0));
|
CTRTest = ibuild.EmitICmpEq(c, ibuild.EmitIntConst(0));
|
||||||
} else {
|
else
|
||||||
CTRTest = c;
|
CTRTest = c;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::InstLoc Test = CRTest;
|
IREmitter::InstLoc Test = CRTest;
|
||||||
if (CTRTest) {
|
if (CTRTest)
|
||||||
|
{
|
||||||
if (Test)
|
if (Test)
|
||||||
Test = ibuild.EmitAnd(Test, CTRTest);
|
Test = ibuild.EmitAnd(Test, CTRTest);
|
||||||
else
|
else
|
||||||
Test = CTRTest;
|
Test = CTRTest;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Test) {
|
if (!Test)
|
||||||
|
{
|
||||||
Test = ibuild.EmitIntConst(1);
|
Test = ibuild.EmitIntConst(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Test;
|
return Test;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,8 +128,7 @@ void JitILBase::bcx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
NORMALBRANCH_START
|
NORMALBRANCH_START
|
||||||
if (inst.LK)
|
if (inst.LK)
|
||||||
ibuild.EmitStoreLink(
|
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||||
ibuild.EmitIntConst(js.compilerPC + 4));
|
|
||||||
|
|
||||||
IREmitter::InstLoc Test = TestBranch(ibuild, inst);
|
IREmitter::InstLoc Test = TestBranch(ibuild, inst);
|
||||||
|
|
||||||
|
@ -134,11 +139,11 @@ void JitILBase::bcx(UGeckoInstruction inst)
|
||||||
destination = js.compilerPC + SignExt16(inst.BD << 2);
|
destination = js.compilerPC + SignExt16(inst.BD << 2);
|
||||||
|
|
||||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle &&
|
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle &&
|
||||||
inst.hex == 0x4182fff8 &&
|
inst.hex == 0x4182fff8 &&
|
||||||
(Memory::ReadUnchecked_U32(js.compilerPC - 8) & 0xFFFF0000) == 0x800D0000 &&
|
(Memory::ReadUnchecked_U32(js.compilerPC - 8) & 0xFFFF0000) == 0x800D0000 &&
|
||||||
(Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x28000000 ||
|
(Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x28000000 ||
|
||||||
(SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x2C000000))
|
(SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x2C000000))
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
ibuild.EmitIdleBranch(Test, ibuild.EmitIntConst(destination));
|
ibuild.EmitIdleBranch(Test, ibuild.EmitIntConst(destination));
|
||||||
}
|
}
|
||||||
|
@ -152,11 +157,13 @@ void JitILBase::bcx(UGeckoInstruction inst)
|
||||||
void JitILBase::bcctrx(UGeckoInstruction inst)
|
void JitILBase::bcctrx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
NORMALBRANCH_START
|
NORMALBRANCH_START
|
||||||
if ((inst.BO & 4) == 0) {
|
if ((inst.BO & 4) == 0)
|
||||||
|
{
|
||||||
IREmitter::InstLoc c = ibuild.EmitLoadCTR();
|
IREmitter::InstLoc c = ibuild.EmitLoadCTR();
|
||||||
c = ibuild.EmitSub(c, ibuild.EmitIntConst(1));
|
c = ibuild.EmitSub(c, ibuild.EmitIntConst(1));
|
||||||
ibuild.EmitStoreCTR(c);
|
ibuild.EmitStoreCTR(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::InstLoc test;
|
IREmitter::InstLoc test;
|
||||||
if ((inst.BO & 16) == 0) // Test a CR bit
|
if ((inst.BO & 16) == 0) // Test a CR bit
|
||||||
{
|
{
|
||||||
|
@ -181,16 +188,19 @@ void JitILBase::bclrx(UGeckoInstruction inst)
|
||||||
NORMALBRANCH_START
|
NORMALBRANCH_START
|
||||||
|
|
||||||
if (!js.isLastInstruction &&
|
if (!js.isLastInstruction &&
|
||||||
(inst.BO & (1 << 4)) && (inst.BO & (1 << 2))) {
|
(inst.BO & (1 << 4)) && (inst.BO & (1 << 2)))
|
||||||
|
{
|
||||||
if (inst.LK)
|
if (inst.LK)
|
||||||
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.hex == 0x4e800020) {
|
if (inst.hex == 0x4e800020)
|
||||||
|
{
|
||||||
ibuild.EmitBranchUncond(ibuild.EmitLoadLink());
|
ibuild.EmitBranchUncond(ibuild.EmitLoadLink());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::InstLoc test = TestBranch(ibuild, inst);
|
IREmitter::InstLoc test = TestBranch(ibuild, inst);
|
||||||
test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0));
|
test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0));
|
||||||
ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4));
|
ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4));
|
||||||
|
|
|
@ -30,10 +30,13 @@ void JitILBase::fp_arith_s(UGeckoInstruction inst)
|
||||||
_assert_msg_(DYNA_REC, 0, "fp_arith_s WTF!!!");
|
_assert_msg_(DYNA_REC, 0, "fp_arith_s WTF!!!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.OPCD == 59) {
|
if (inst.OPCD == 59)
|
||||||
|
{
|
||||||
val = ibuild.EmitDoubleToSingle(val);
|
val = ibuild.EmitDoubleToSingle(val);
|
||||||
val = ibuild.EmitDupSingleToMReg(val);
|
val = ibuild.EmitDupSingleToMReg(val);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD));
|
val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD));
|
||||||
}
|
}
|
||||||
ibuild.EmitStoreFReg(val, inst.FD);
|
ibuild.EmitStoreFReg(val, inst.FD);
|
||||||
|
@ -50,18 +53,25 @@ void JitILBase::fmaddXX(UGeckoInstruction inst)
|
||||||
|
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA);
|
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA);
|
||||||
val = ibuild.EmitFDMul(val, ibuild.EmitLoadFReg(inst.FC));
|
val = ibuild.EmitFDMul(val, ibuild.EmitLoadFReg(inst.FC));
|
||||||
|
|
||||||
if (inst.SUBOP5 & 1)
|
if (inst.SUBOP5 & 1)
|
||||||
val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB));
|
val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB));
|
||||||
else
|
else
|
||||||
val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB));
|
val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB));
|
||||||
|
|
||||||
if (inst.SUBOP5 & 2)
|
if (inst.SUBOP5 & 2)
|
||||||
val = ibuild.EmitFDNeg(val);
|
val = ibuild.EmitFDNeg(val);
|
||||||
if (inst.OPCD == 59) {
|
|
||||||
|
if (inst.OPCD == 59)
|
||||||
|
{
|
||||||
val = ibuild.EmitDoubleToSingle(val);
|
val = ibuild.EmitDoubleToSingle(val);
|
||||||
val = ibuild.EmitDupSingleToMReg(val);
|
val = ibuild.EmitDupSingleToMReg(val);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD));
|
val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD));
|
||||||
}
|
}
|
||||||
|
|
||||||
ibuild.EmitStoreFReg(val, inst.FD);
|
ibuild.EmitStoreFReg(val, inst.FD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +107,8 @@ void JitILBase::fsign(UGeckoInstruction inst)
|
||||||
FALLBACK_IF(true);
|
FALLBACK_IF(true);
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
switch (inst.SUBOP10) {
|
switch (inst.SUBOP10)
|
||||||
|
{
|
||||||
case 40: // fnegx
|
case 40: // fnegx
|
||||||
break;
|
break;
|
||||||
case 264: // fabsx
|
case 264: // fabsx
|
||||||
|
|
|
@ -198,7 +198,7 @@ void JitILBase::subfic(UGeckoInstruction inst)
|
||||||
JITDISABLE(bJITIntegerOff);
|
JITDISABLE(bJITIntegerOff);
|
||||||
IREmitter::InstLoc nota, lhs, val, test;
|
IREmitter::InstLoc nota, lhs, val, test;
|
||||||
nota = ibuild.EmitXor(ibuild.EmitLoadGReg(inst.RA),
|
nota = ibuild.EmitXor(ibuild.EmitLoadGReg(inst.RA),
|
||||||
ibuild.EmitIntConst(-1));
|
ibuild.EmitIntConst(-1));
|
||||||
|
|
||||||
if (inst.SIMM_16 == -1)
|
if (inst.SIMM_16 == -1)
|
||||||
{
|
{
|
||||||
|
@ -220,7 +220,10 @@ void JitILBase::subfcx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(bJITIntegerOff);
|
JITDISABLE(bJITIntegerOff);
|
||||||
if (inst.OE) PanicAlert("OE: subfcx");
|
|
||||||
|
if (inst.OE)
|
||||||
|
PanicAlert("OE: subfcx");
|
||||||
|
|
||||||
IREmitter::InstLoc val, test, lhs, rhs;
|
IREmitter::InstLoc val, test, lhs, rhs;
|
||||||
lhs = ibuild.EmitLoadGReg(inst.RB);
|
lhs = ibuild.EmitLoadGReg(inst.RB);
|
||||||
rhs = ibuild.EmitLoadGReg(inst.RA);
|
rhs = ibuild.EmitLoadGReg(inst.RA);
|
||||||
|
@ -229,6 +232,7 @@ void JitILBase::subfcx(UGeckoInstruction inst)
|
||||||
test = ibuild.EmitICmpEq(rhs, ibuild.EmitIntConst(0));
|
test = ibuild.EmitICmpEq(rhs, ibuild.EmitIntConst(0));
|
||||||
test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val));
|
test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val));
|
||||||
ibuild.EmitStoreCarry(test);
|
ibuild.EmitStoreCarry(test);
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
@ -237,7 +241,10 @@ void JitILBase::subfex(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(bJITIntegerOff);
|
JITDISABLE(bJITIntegerOff);
|
||||||
if (inst.OE) PanicAlert("OE: subfex");
|
|
||||||
|
if (inst.OE)
|
||||||
|
PanicAlert("OE: subfex");
|
||||||
|
|
||||||
IREmitter::InstLoc val, test, lhs, rhs, carry;
|
IREmitter::InstLoc val, test, lhs, rhs, carry;
|
||||||
rhs = ibuild.EmitLoadGReg(inst.RA);
|
rhs = ibuild.EmitLoadGReg(inst.RA);
|
||||||
carry = ibuild.EmitLoadCarry();
|
carry = ibuild.EmitLoadCarry();
|
||||||
|
@ -250,6 +257,7 @@ void JitILBase::subfex(UGeckoInstruction inst)
|
||||||
ibuild.EmitStoreGReg(val, inst.RD);
|
ibuild.EmitStoreGReg(val, inst.RD);
|
||||||
test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val));
|
test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val));
|
||||||
ibuild.EmitStoreCarry(test);
|
ibuild.EmitStoreCarry(test);
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
@ -258,10 +266,14 @@ void JitILBase::subfx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(bJITIntegerOff);
|
JITDISABLE(bJITIntegerOff);
|
||||||
if (inst.OE) PanicAlert("OE: subfx");
|
|
||||||
|
if (inst.OE)
|
||||||
|
PanicAlert("OE: subfx");
|
||||||
|
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
||||||
val = ibuild.EmitSub(val, ibuild.EmitLoadGReg(inst.RA));
|
val = ibuild.EmitSub(val, ibuild.EmitLoadGReg(inst.RA));
|
||||||
ibuild.EmitStoreGReg(val, inst.RD);
|
ibuild.EmitStoreGReg(val, inst.RD);
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
@ -282,6 +294,7 @@ void JitILBase::mullwx(UGeckoInstruction inst)
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
||||||
val = ibuild.EmitMul(ibuild.EmitLoadGReg(inst.RA), val);
|
val = ibuild.EmitMul(ibuild.EmitLoadGReg(inst.RA), val);
|
||||||
ibuild.EmitStoreGReg(val, inst.RD);
|
ibuild.EmitStoreGReg(val, inst.RD);
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
@ -295,6 +308,7 @@ void JitILBase::mulhwux(UGeckoInstruction inst)
|
||||||
IREmitter::InstLoc b = ibuild.EmitLoadGReg(inst.RB);
|
IREmitter::InstLoc b = ibuild.EmitLoadGReg(inst.RB);
|
||||||
IREmitter::InstLoc d = ibuild.EmitMulHighUnsigned(a, b);
|
IREmitter::InstLoc d = ibuild.EmitMulHighUnsigned(a, b);
|
||||||
ibuild.EmitStoreGReg(d, inst.RD);
|
ibuild.EmitStoreGReg(d, inst.RD);
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, d);
|
ComputeRC(ibuild, d);
|
||||||
}
|
}
|
||||||
|
@ -326,7 +340,9 @@ void JitILBase::divwux(UGeckoInstruction inst)
|
||||||
MOV(32, gpr.R(d), R(EAX));
|
MOV(32, gpr.R(d), R(EAX));
|
||||||
gpr.UnlockAll();
|
gpr.UnlockAll();
|
||||||
gpr.UnlockAllX();
|
gpr.UnlockAllX();
|
||||||
if (inst.Rc) {
|
|
||||||
|
if (inst.Rc)
|
||||||
|
{
|
||||||
CALL((u8*)asm_routines.computeRc);
|
CALL((u8*)asm_routines.computeRc);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -339,6 +355,7 @@ void JitILBase::addx(UGeckoInstruction inst)
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
||||||
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), val);
|
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), val);
|
||||||
ibuild.EmitStoreGReg(val, inst.RD);
|
ibuild.EmitStoreGReg(val, inst.RD);
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
@ -347,12 +364,12 @@ void JitILBase::addzex(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(bJITIntegerOff);
|
JITDISABLE(bJITIntegerOff);
|
||||||
IREmitter::InstLoc lhs = ibuild.EmitLoadGReg(inst.RA),
|
IREmitter::InstLoc lhs = ibuild.EmitLoadGReg(inst.RA), val, newcarry;
|
||||||
val, newcarry;
|
|
||||||
val = ibuild.EmitAdd(lhs, ibuild.EmitLoadCarry());
|
val = ibuild.EmitAdd(lhs, ibuild.EmitLoadCarry());
|
||||||
ibuild.EmitStoreGReg(val, inst.RD);
|
ibuild.EmitStoreGReg(val, inst.RD);
|
||||||
newcarry = ibuild.EmitICmpUlt(val, lhs);
|
newcarry = ibuild.EmitICmpUlt(val, lhs);
|
||||||
ibuild.EmitStoreCarry(newcarry);
|
ibuild.EmitStoreCarry(newcarry);
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
@ -375,7 +392,9 @@ void JitILBase::addex(UGeckoInstruction inst)
|
||||||
ibuild.EmitStoreGReg(abc, inst.RD);
|
ibuild.EmitStoreGReg(abc, inst.RD);
|
||||||
ibuild.EmitStoreCarry(new_carry);
|
ibuild.EmitStoreCarry(new_carry);
|
||||||
|
|
||||||
if (inst.OE) PanicAlert("OE: addex");
|
if (inst.OE)
|
||||||
|
PanicAlert("OE: addex");
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, abc);
|
ComputeRC(ibuild, abc);
|
||||||
}
|
}
|
||||||
|
@ -389,6 +408,7 @@ void JitILBase::rlwinmx(UGeckoInstruction inst)
|
||||||
val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH));
|
val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH));
|
||||||
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
|
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
|
||||||
ibuild.EmitStoreGReg(val, inst.RA);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
@ -406,6 +426,7 @@ void JitILBase::rlwimix(UGeckoInstruction inst)
|
||||||
ival = ibuild.EmitAnd(ival, ibuild.EmitIntConst(~mask));
|
ival = ibuild.EmitAnd(ival, ibuild.EmitIntConst(~mask));
|
||||||
val = ibuild.EmitOr(ival, val);
|
val = ibuild.EmitOr(ival, val);
|
||||||
ibuild.EmitStoreGReg(val, inst.RA);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
@ -419,6 +440,7 @@ void JitILBase::rlwnmx(UGeckoInstruction inst)
|
||||||
val = ibuild.EmitRol(val, ibuild.EmitLoadGReg(inst.RB));
|
val = ibuild.EmitRol(val, ibuild.EmitLoadGReg(inst.RB));
|
||||||
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
|
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
|
||||||
ibuild.EmitStoreGReg(val, inst.RA);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
@ -430,6 +452,7 @@ void JitILBase::negx(UGeckoInstruction inst)
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA);
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA);
|
||||||
val = ibuild.EmitSub(ibuild.EmitIntConst(0), val);
|
val = ibuild.EmitSub(ibuild.EmitIntConst(0), val);
|
||||||
ibuild.EmitStoreGReg(val, inst.RD);
|
ibuild.EmitStoreGReg(val, inst.RD);
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
@ -438,9 +461,11 @@ void JitILBase::srwx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(bJITIntegerOff);
|
JITDISABLE(bJITIntegerOff);
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS),
|
|
||||||
samt = ibuild.EmitLoadGReg(inst.RB),
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||||
corr;
|
IREmitter::InstLoc samt = ibuild.EmitLoadGReg(inst.RB);
|
||||||
|
IREmitter::InstLoc corr;
|
||||||
|
|
||||||
// FIXME: We can do better with a cmov
|
// FIXME: We can do better with a cmov
|
||||||
// FIXME: We can do better on 64-bit
|
// FIXME: We can do better on 64-bit
|
||||||
val = ibuild.EmitShrl(val, samt);
|
val = ibuild.EmitShrl(val, samt);
|
||||||
|
@ -449,6 +474,7 @@ void JitILBase::srwx(UGeckoInstruction inst)
|
||||||
corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1));
|
corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1));
|
||||||
val = ibuild.EmitAnd(corr, val);
|
val = ibuild.EmitAnd(corr, val);
|
||||||
ibuild.EmitStoreGReg(val, inst.RA);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
@ -457,9 +483,11 @@ void JitILBase::slwx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(bJITIntegerOff);
|
JITDISABLE(bJITIntegerOff);
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS),
|
|
||||||
samt = ibuild.EmitLoadGReg(inst.RB),
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||||
corr;
|
IREmitter::InstLoc samt = ibuild.EmitLoadGReg(inst.RB);
|
||||||
|
IREmitter::InstLoc corr;
|
||||||
|
|
||||||
// FIXME: We can do better with a cmov
|
// FIXME: We can do better with a cmov
|
||||||
// FIXME: We can do better on 64-bit
|
// FIXME: We can do better on 64-bit
|
||||||
val = ibuild.EmitShl(val, samt);
|
val = ibuild.EmitShl(val, samt);
|
||||||
|
@ -468,6 +496,7 @@ void JitILBase::slwx(UGeckoInstruction inst)
|
||||||
corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1));
|
corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1));
|
||||||
val = ibuild.EmitAnd(corr, val);
|
val = ibuild.EmitAnd(corr, val);
|
||||||
ibuild.EmitStoreGReg(val, inst.RA);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
@ -524,6 +553,7 @@ void JitILBase::cntlzwx(UGeckoInstruction inst)
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||||
val = ibuild.EmitCntlzw(val);
|
val = ibuild.EmitCntlzw(val);
|
||||||
ibuild.EmitStoreGReg(val, inst.RA);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,11 +35,21 @@ void JitILBase::lXz(UGeckoInstruction inst)
|
||||||
IREmitter::InstLoc val;
|
IREmitter::InstLoc val;
|
||||||
switch (inst.OPCD & ~0x1)
|
switch (inst.OPCD & ~0x1)
|
||||||
{
|
{
|
||||||
case 32: val = ibuild.EmitLoad32(addr); break; //lwz
|
case 32: // lwz
|
||||||
case 40: val = ibuild.EmitLoad16(addr); break; //lhz
|
val = ibuild.EmitLoad32(addr);
|
||||||
case 34: val = ibuild.EmitLoad8(addr); break; //lbz
|
break;
|
||||||
default: PanicAlert("lXz: invalid access size"); val = nullptr; break;
|
case 40: // lhz
|
||||||
|
val = ibuild.EmitLoad16(addr);
|
||||||
|
break;
|
||||||
|
case 34: // lbz
|
||||||
|
val = ibuild.EmitLoad8(addr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PanicAlert("lXz: invalid access size");
|
||||||
|
val = nullptr;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ibuild.EmitStoreGReg(val, inst.RD);
|
ibuild.EmitStoreGReg(val, inst.RD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,10 +97,17 @@ void JitILBase::lXzx(UGeckoInstruction inst)
|
||||||
IREmitter::InstLoc val;
|
IREmitter::InstLoc val;
|
||||||
switch (inst.SUBOP10 & ~32)
|
switch (inst.SUBOP10 & ~32)
|
||||||
{
|
{
|
||||||
default: PanicAlert("lXzx: invalid access size");
|
default:
|
||||||
case 23: val = ibuild.EmitLoad32(addr); break; //lwzx
|
PanicAlert("lXzx: invalid access size");
|
||||||
case 279: val = ibuild.EmitLoad16(addr); break; //lhzx
|
case 23: // lwzx
|
||||||
case 87: val = ibuild.EmitLoad8(addr); break; //lbzx
|
val = ibuild.EmitLoad32(addr);
|
||||||
|
break;
|
||||||
|
case 279: // lhzx
|
||||||
|
val = ibuild.EmitLoad16(addr);
|
||||||
|
break;
|
||||||
|
case 87: // lbzx
|
||||||
|
val = ibuild.EmitLoad8(addr);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
ibuild.EmitStoreGReg(val, inst.RD);
|
ibuild.EmitStoreGReg(val, inst.RD);
|
||||||
}
|
}
|
||||||
|
@ -115,7 +132,10 @@ void JitILBase::dcbz(UGeckoInstruction inst)
|
||||||
// TODO!
|
// TODO!
|
||||||
#if 0
|
#if 0
|
||||||
if (Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITLoadStoreOff)
|
if (Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITLoadStoreOff)
|
||||||
{Default(inst); return;} // turn off from debugger
|
{
|
||||||
|
Default(inst);
|
||||||
|
return;
|
||||||
|
}
|
||||||
INSTRUCTION_START;
|
INSTRUCTION_START;
|
||||||
MOV(32, R(EAX), gpr.R(inst.RB));
|
MOV(32, R(EAX), gpr.R(inst.RB));
|
||||||
if (inst.RA)
|
if (inst.RA)
|
||||||
|
@ -149,10 +169,18 @@ void JitILBase::stX(UGeckoInstruction inst)
|
||||||
|
|
||||||
switch (inst.OPCD & ~1)
|
switch (inst.OPCD & ~1)
|
||||||
{
|
{
|
||||||
case 36: ibuild.EmitStore32(value, addr); break; //stw
|
case 36: // stw
|
||||||
case 44: ibuild.EmitStore16(value, addr); break; //sth
|
ibuild.EmitStore32(value, addr);
|
||||||
case 38: ibuild.EmitStore8(value, addr); break; //stb
|
break;
|
||||||
default: _assert_msg_(DYNA_REC, 0, "AWETKLJASDLKF"); return;
|
case 44: // sth
|
||||||
|
ibuild.EmitStore16(value, addr);
|
||||||
|
break;
|
||||||
|
case 38: // stb
|
||||||
|
ibuild.EmitStore8(value, addr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_assert_msg_(DYNA_REC, 0, "stX: Invalid access size.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,10 +200,18 @@ void JitILBase::stXx(UGeckoInstruction inst)
|
||||||
|
|
||||||
switch (inst.SUBOP10 & ~32)
|
switch (inst.SUBOP10 & ~32)
|
||||||
{
|
{
|
||||||
case 151: ibuild.EmitStore32(value, addr); break; //stw
|
case 151: // stw
|
||||||
case 407: ibuild.EmitStore16(value, addr); break; //sth
|
ibuild.EmitStore32(value, addr);
|
||||||
case 215: ibuild.EmitStore8(value, addr); break; //stb
|
break;
|
||||||
default: _assert_msg_(DYNA_REC, 0, "AWETKLJASDLKF"); return;
|
case 407: // sth
|
||||||
|
ibuild.EmitStore16(value, addr);
|
||||||
|
break;
|
||||||
|
case 215: // stb
|
||||||
|
ibuild.EmitStore8(value, addr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_assert_msg_(DYNA_REC, 0, "stXx: Invalid store size.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,8 @@ void JitILBase::ps_maddXX(UGeckoInstruction inst)
|
||||||
|
|
||||||
switch (inst.SUBOP5)
|
switch (inst.SUBOP5)
|
||||||
{
|
{
|
||||||
case 14: {//madds0
|
case 14: // madds0
|
||||||
|
{
|
||||||
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
||||||
op2 = ibuild.EmitFPDup0(op2);
|
op2 = ibuild.EmitFPDup0(op2);
|
||||||
val = ibuild.EmitFPMul(val, op2);
|
val = ibuild.EmitFPMul(val, op2);
|
||||||
|
@ -137,7 +138,8 @@ void JitILBase::ps_maddXX(UGeckoInstruction inst)
|
||||||
val = ibuild.EmitFPAdd(val, op3);
|
val = ibuild.EmitFPAdd(val, op3);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 15: {//madds1
|
case 15: // madds1
|
||||||
|
{
|
||||||
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
||||||
op2 = ibuild.EmitFPDup1(op2);
|
op2 = ibuild.EmitFPDup1(op2);
|
||||||
val = ibuild.EmitFPMul(val, op2);
|
val = ibuild.EmitFPMul(val, op2);
|
||||||
|
@ -145,21 +147,24 @@ void JitILBase::ps_maddXX(UGeckoInstruction inst)
|
||||||
val = ibuild.EmitFPAdd(val, op3);
|
val = ibuild.EmitFPAdd(val, op3);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 28: {//msub
|
case 28: // msub
|
||||||
|
{
|
||||||
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
||||||
val = ibuild.EmitFPMul(val, op2);
|
val = ibuild.EmitFPMul(val, op2);
|
||||||
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
||||||
val = ibuild.EmitFPSub(val, op3);
|
val = ibuild.EmitFPSub(val, op3);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 29: {//madd
|
case 29: // madd
|
||||||
|
{
|
||||||
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
||||||
val = ibuild.EmitFPMul(val, op2);
|
val = ibuild.EmitFPMul(val, op2);
|
||||||
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
||||||
val = ibuild.EmitFPAdd(val, op3);
|
val = ibuild.EmitFPAdd(val, op3);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 30: {//nmsub
|
case 30: // nmsub
|
||||||
|
{
|
||||||
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
||||||
val = ibuild.EmitFPMul(val, op2);
|
val = ibuild.EmitFPMul(val, op2);
|
||||||
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
||||||
|
@ -167,7 +172,8 @@ void JitILBase::ps_maddXX(UGeckoInstruction inst)
|
||||||
val = ibuild.EmitFPNeg(val);
|
val = ibuild.EmitFPNeg(val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 31: {//nmadd
|
case 31: // nmadd
|
||||||
|
{
|
||||||
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
||||||
val = ibuild.EmitFPMul(val, op2);
|
val = ibuild.EmitFPMul(val, op2);
|
||||||
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
||||||
|
|
|
@ -170,42 +170,35 @@ void JitILBase::crXX(UGeckoInstruction inst)
|
||||||
|
|
||||||
// Compute combined bit
|
// Compute combined bit
|
||||||
const unsigned subop = inst.SUBOP10;
|
const unsigned subop = inst.SUBOP10;
|
||||||
switch (subop) {
|
switch (subop)
|
||||||
case 257:
|
{
|
||||||
// crand
|
case 257: // crand
|
||||||
eax = ibuild.EmitAnd(eax, ecx);
|
eax = ibuild.EmitAnd(eax, ecx);
|
||||||
break;
|
break;
|
||||||
case 129:
|
case 129: // crandc
|
||||||
// crandc
|
|
||||||
ecx = ibuild.EmitNot(ecx);
|
ecx = ibuild.EmitNot(ecx);
|
||||||
eax = ibuild.EmitAnd(eax, ecx);
|
eax = ibuild.EmitAnd(eax, ecx);
|
||||||
break;
|
break;
|
||||||
case 289:
|
case 289: // creqv
|
||||||
// creqv
|
|
||||||
eax = ibuild.EmitXor(eax, ecx);
|
eax = ibuild.EmitXor(eax, ecx);
|
||||||
eax = ibuild.EmitNot(eax);
|
eax = ibuild.EmitNot(eax);
|
||||||
break;
|
break;
|
||||||
case 225:
|
case 225: // crnand
|
||||||
// crnand
|
|
||||||
eax = ibuild.EmitAnd(eax, ecx);
|
eax = ibuild.EmitAnd(eax, ecx);
|
||||||
eax = ibuild.EmitNot(eax);
|
eax = ibuild.EmitNot(eax);
|
||||||
break;
|
break;
|
||||||
case 33:
|
case 33: // crnor
|
||||||
// crnor
|
|
||||||
eax = ibuild.EmitOr(eax, ecx);
|
eax = ibuild.EmitOr(eax, ecx);
|
||||||
eax = ibuild.EmitNot(eax);
|
eax = ibuild.EmitNot(eax);
|
||||||
break;
|
break;
|
||||||
case 449:
|
case 449: // cror
|
||||||
// cror
|
|
||||||
eax = ibuild.EmitOr(eax, ecx);
|
eax = ibuild.EmitOr(eax, ecx);
|
||||||
break;
|
break;
|
||||||
case 417:
|
case 417: // crorc
|
||||||
// crorc
|
|
||||||
ecx = ibuild.EmitNot(ecx);
|
ecx = ibuild.EmitNot(ecx);
|
||||||
eax = ibuild.EmitOr(eax, ecx);
|
eax = ibuild.EmitOr(eax, ecx);
|
||||||
break;
|
break;
|
||||||
case 193:
|
case 193: // crxor
|
||||||
// crxor
|
|
||||||
eax = ibuild.EmitXor(eax, ecx);
|
eax = ibuild.EmitXor(eax, ecx);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Reference in New Issue