More JIT work

This commit is contained in:
SimoneN64
2023-08-28 20:12:17 +02:00
parent 92342feeda
commit 28d49812fa
5 changed files with 164 additions and 61 deletions

View File

@@ -34,8 +34,9 @@ Fn JIT::Recompile() {
bool stable = true;
cycles = 0;
prologue();
while(stable) {
mov(rbp, u64(this));
mov(rdi, u64(this) + offsetof(JIT, regs));
while(stable) {
cycles++;
CheckCompareInterrupt();

View File

@@ -23,6 +23,33 @@ private:
void CheckCompareInterrupt() override;
Fn Recompile();
template<class T>
void emitMemberCall(T func, void* thisObj) {
void* funcPtr;
auto thisPtr = reinterpret_cast<uintptr_t>(thisObj);
/*#ifdef ABI_WINDOWS
static_assert(sizeof(T) == 8, "[JIT]: Invalid size for member function pointer");
std::memcpy(&funcPtr, &func, sizeof(T));
#elif defined(ABI_UNIX)
static_assert(sizeof(T) == 16, "[JIT]: Invalid size for member function pointer");
uintptr_t tmpArr[2];
std::memcpy(tmpArr, &func, sizeof(T));
funcPtr = reinterpret_cast<void*>(tmpArr[0]);
thisPtr += tmpArr[1];
#else
Util::panic("Huh?!");
#endif*/
push(rdi);
if(thisPtr == reinterpret_cast<uintptr_t>(this)) {
mov(rdi, rbp);
} else {
mov(rdi, (uintptr_t)thisPtr);
}
call(funcPtr);
pop(rdi);
}
bool isStable(u32 instr) {
u8 mask = (instr >> 26) & 0x3f;
switch(mask) {
@@ -70,6 +97,10 @@ private:
LT, GT, GE, LE, EQ, NE
};
u8 Read8(u64 addr) {
return mem.Read8(regs, addr);
}
void cop2Decode(u32);
void special(u32);
void regimm(u32);
@@ -82,22 +113,22 @@ private:
void and_(u32);
void emitCondition(const std::string&, BranchCond);
template <class T>
void branch(const Xbyak::Operand&, const T&, s64, BranchCond);
void branch(const Xbyak::Reg64&, const T&, s64, BranchCond);
template <class T>
void branch_likely(const Xbyak::Operand&, const T&, s64, BranchCond);
void branch_likely(const Xbyak::Reg64&, const T&, s64, BranchCond);
template <class T>
void b(u32, const Xbyak::Operand&, const T&, BranchCond);
void b(u32, const Xbyak::Reg64&, const T&, BranchCond);
template <class T>
void blink(u32, const Xbyak::Operand&, const T&, BranchCond);
void blink(u32, const Xbyak::Reg64&, const T&, BranchCond);
template <class T>
void bl(u32, const Xbyak::Operand&, const T&, BranchCond);
void bl(u32, const Xbyak::Reg64&, const T&, BranchCond);
template <class T>
void bllink(u32, const Xbyak::Operand&, const T&, BranchCond);
void bllink(u32, const Xbyak::Reg64&, const T&, BranchCond);
void dadd(u32);
void daddu(u32);
void daddi(u32);

View File

@@ -168,10 +168,24 @@ void JIT::Emit(u32 instr) {
case 0x10: regs.cop0.decode(*this, instr); break;
case 0x11: regs.cop1.decode(*this, instr); break;
case 0x12: cop2Decode(instr); break;
case 0x14: bl(instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;
case 0x15: bl(instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); break;
case 0x16: bl(instr, regs.gpr[RS(instr)] <= 0); break;
case 0x17: bl(instr, regs.gpr[RS(instr)] > 0); break;
case 0x14: {
mov(rax, GPR(RS(instr)));
mov(rcx, GPR(RT(instr)));
bl(instr, rax, rcx, EQ);
} break;
case 0x15: {
mov(rax, GPR(RS(instr)));
mov(rcx, GPR(RT(instr)));
bl(instr, rax, rcx, NE);
} break;
case 0x16: {
mov(rax, GPR(RS(instr)));
bl(instr, rax, 0, LE);
} break;
case 0x17: {
mov(rax, GPR(RS(instr)));
bl(instr, rax, 0, GT);
} break;
case 0x18: daddi(instr); break;
case 0x19: daddiu(instr); break;
case 0x1A: ldl(instr); break;

View File

@@ -61,40 +61,40 @@ void JIT::div(u32 instr) {
movsxd(rax, dword[rdi + offsetof(Registers, gpr[RS(instr)])]); // dividend
movsxd(rcx, dword[rdi + offsetof(Registers, gpr[RT(instr)])]); // divisor
cmp(rcx, 0);
je("divisor==0");
je("div_divisor==0");
CodeGenerator::div(rcx);
mov(qword[rdi + offsetof(Registers, lo)], eax);
mov(qword[rdi + offsetof(Registers, hi)], edx);
jmp("exit");
jmp("div_exit");
L("divisor==0");
L("div_divisor==0");
mov(qword[rdi + offsetof(Registers, hi)], rax);
cmp(rax, 0);
jge("dividend>=0");
jge("div_dividend>=0");
mov(qword[rdi + offsetof(Registers, lo)], s64(1));
L("dividend>=0");
L("div_dividend>=0");
mov(qword[rdi + offsetof(Registers, lo)], s64(-1));
L("exit");
L("div_exit");
}
void JIT::divu(u32 instr) {
movsxd(rax, dword[rdi + offsetof(Registers, gpr[RS(instr)])]); // dividend
movsxd(rcx, dword[rdi + offsetof(Registers, gpr[RT(instr)])]); // divisor
cmp(rcx, 0);
je("divisor==0");
je("divu_divisor==0");
CodeGenerator::div(rcx);
mov(qword[rdi + offsetof(Registers, lo)], eax);
mov(qword[rdi + offsetof(Registers, hi)], edx);
jmp("exit");
jmp("divu_exit");
L("divisor==0");
L("divu_divisor==0");
mov(qword[rdi + offsetof(Registers, hi)], rax);
mov(qword[rdi + offsetof(Registers, lo)], -1);
L("exit");
L("divu_exit");
}
void JIT::ddiv(u32 instr) {
@@ -108,39 +108,39 @@ void JIT::ddiv(u32 instr) {
CodeGenerator::xor_(r10, r8);
CodeGenerator::xor_(r9, r10);
cmp(rcx, 0);
je("else if");
je("ddiv_else_if");
cmp(r9, 1);
jne("else");
jne("ddiv_else");
mov(qword[rdi + offsetof(Registers, lo)], rax);
mov(qword[rdi + offsetof(Registers, hi)], 0);
jmp("exit");
L("else if");
jmp("ddiv_exit");
L("ddiv_else_if");
mov(qword[rdi + offsetof(Registers, hi)], rax);
cmp(rax, 0);
jge("dividend>=0");
jge("ddiv_dividend>=0");
mov(qword[rdi + offsetof(Registers, lo)], 1);
L("dividend>=0");
L("ddiv_dividend>=0");
mov(qword[rdi + offsetof(Registers, lo)], -1);
L("else");
L("ddiv_else");
CodeGenerator::div(rcx);
mov(qword[rdi + offsetof(Registers, lo)], rax);
mov(qword[rdi + offsetof(Registers, hi)], rdx);
L("exit");
L("ddiv_exit");
}
void JIT::ddivu(u32 instr) {
mov(rax, GPR(RS(instr)));
mov(rcx, GPR(RT(instr)));
cmp(rcx, 0);
je("divisor==0");
je("ddivu_divisor==0");
CodeGenerator::div(rcx);
mov(qword[rdi + offsetof(Registers, lo)], rax);
mov(qword[rdi + offsetof(Registers, hi)], rdx);
jmp("exit");
L("divisor==0");
jmp("ddivu_exit");
L("ddivu_divisor==0");
mov(qword[rdi + offsetof(Registers, lo)], -1);
mov(qword[rdi + offsetof(Registers, hi)], rax);
L("exit");
L("ddivu_exit");
}
void JIT::emitCondition(const std::string& name, BranchCond cond) {
@@ -167,46 +167,55 @@ void JIT::emitCondition(const std::string& name, BranchCond cond) {
}
template <class T>
void JIT::branch(const Xbyak::Operand& op1, const T& op2, s64 offset, BranchCond cond) {
void JIT::branch(const Xbyak::Reg64& op1, const T& op2, s64 offset, BranchCond cond) {
cmp(op1, op2);
emitCondition("false", cond);
emitCondition("branch_false", cond);
mov(byte[rdi + offsetof(Registers, delaySlot)], 1);
mov(rax, qword[rdi + offsetof(Registers, pc)]);
CodeGenerator::add(rax, offset);
mov(qword[rdi + offsetof(Registers, nextPC)], rax);
L("false");
L("branch_false");
}
template void JIT::branch<Xbyak::Operand>(const Xbyak::Operand& op1, const Xbyak::Operand& op2, s64 offset, BranchCond cond);
template void JIT::branch<int>(const Xbyak::Operand& op1, const int& op2, s64 offset, BranchCond cond);
template void JIT::branch<Xbyak::Reg64>(const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, s64 offset, BranchCond cond);
template void JIT::branch<int>(const Xbyak::Reg64& op1, const int& op2, s64 offset, BranchCond cond);
void JIT::branch_likely(const Xbyak::Operand& op1, const Xbyak::Operand& op2, s64 offset, BranchCond cond) {
template <class T>
void JIT::branch_likely(const Xbyak::Reg64& op1, const T& op2, s64 offset, BranchCond cond) {
mov(rax, qword[rdi + offsetof(Registers, pc)]);
cmp(op1, op2);
emitCondition("false", cond);
emitCondition("branch_likely_false", cond);
mov(byte[rdi + offsetof(Registers, delaySlot)], 1);
CodeGenerator::add(rax, offset);
mov(qword[rdi + offsetof(Registers, nextPC)], rax);
jmp("exit");
jmp("branch_likely_exit");
L("false");
L("branch_likely_false");
mov(qword[rdi + offsetof(Registers, oldPC)], rax);
mov(rcx, qword[rdi + offsetof(Registers, nextPC)]);
mov(qword[rdi + offsetof(Registers, pc)], rcx);
CodeGenerator::add(rcx, 4);
mov(qword[rdi + offsetof(Registers, nextPC)], rcx);
L("exit");
L("branch_likely_exit");
}
void JIT::b(u32 instr, const Xbyak::Operand& op1, const Xbyak::Operand& op2, BranchCond cond) {
template void JIT::branch_likely<Xbyak::Reg64>(const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, s64 offset, BranchCond cond);
template void JIT::branch_likely<int>(const Xbyak::Reg64& op1, const int& op2, s64 offset, BranchCond cond);
template <class T>
void JIT::b(u32 instr, const Xbyak::Reg64& op1, const T& op2, BranchCond cond) {
s16 imm = instr;
s64 offset = u64((s64)imm) << 2;
branch(op1, op2, offset, cond);
}
void JIT::blink(u32 instr, const Xbyak::Operand& op1, const Xbyak::Operand& op2, BranchCond cond) {
template void JIT::b<Xbyak::Reg64>(u32, const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, BranchCond cond);
template void JIT::b<int>(u32, const Xbyak::Reg64& op1, const int& op2, BranchCond cond);
template <class T>
void JIT::blink(u32 instr, const Xbyak::Reg64& op1, const T& op2, BranchCond cond) {
s16 imm = instr;
s64 offset = u64((s64)imm) << 2;
mov(rcx, qword[rdi + offsetof(Registers, nextPC)]);
@@ -214,13 +223,21 @@ void JIT::blink(u32 instr, const Xbyak::Operand& op1, const Xbyak::Operand& op2,
branch(op1, op2, offset, cond);
}
void JIT::bl(u32 instr, const Xbyak::Operand& op1, const Xbyak::Operand& op2, BranchCond cond) {
template void JIT::blink<Xbyak::Reg64>(u32, const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, BranchCond cond);
template void JIT::blink<int>(u32, const Xbyak::Reg64& op1, const int& op2, BranchCond cond);
template <class T>
void JIT::bl(u32 instr, const Xbyak::Reg64& op1, const T& op2, BranchCond cond) {
s16 imm = instr;
s64 offset = u64((s64)imm) << 2;
branch_likely(op1, op2, offset, cond);
}
void JIT::bllink(u32 instr, const Xbyak::Operand& op1, const Xbyak::Operand& op2, BranchCond cond) {
template void JIT::bl<Xbyak::Reg64>(u32, const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, BranchCond cond);
template void JIT::bl<int>(u32, const Xbyak::Reg64& op1, const int& op2, BranchCond cond);
template <class T>
void JIT::bllink(u32 instr, const Xbyak::Reg64& op1, const T& op2, BranchCond cond) {
mov(rcx, qword[rdi + offsetof(Registers, nextPC)]);
mov(GPR(31), rcx);
s16 imm = instr;
@@ -228,6 +245,9 @@ void JIT::bllink(u32 instr, const Xbyak::Operand& op1, const Xbyak::Operand& op2
branch_likely(op1, op2, offset, cond);
}
template void JIT::bllink<Xbyak::Reg64>(u32, const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, BranchCond cond);
template void JIT::bllink<int>(u32, const Xbyak::Reg64& op1, const int& op2, BranchCond cond);
void JIT::lui(u32 instr) {
u64 val = s64(s16(instr));
val <<= 16;
@@ -235,14 +255,36 @@ void JIT::lui(u32 instr) {
}
void JIT::lb(u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr = 0;
if(!MapVAddr(regs, LOAD, address, paddr)) {
HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else {
regs.gpr[RT(instr)] = (s8)mem.Read8(regs, paddr);
}
mov(rdx, GPR(RS(instr)));
CodeGenerator::add(rdx, s64(s16(instr)));
mov(rsi, LOAD);
push(rcx);
lea(rcx, dword[rbp-4]);
call(MapVAddr);
pop(rcx);
cmp(rax, 0);
je("lb_exception");
mov(rsi, dword[rbp-4]);
push(rcx);
emitMemberCall(&JIT::Read8, this);
pop(rcx);
mov(GPR(RT(instr)), rax.cvt8());
L("lb_exception");
mov(rsi, rdx);
push(rax);
call(HandleTLBException);
pop(rax);
push(rsi);
mov(rdi, REG(byte, cop0.tlbError));
mov(rsi, LOAD);
call(GetTLBExceptionCode);
pop(rsi);
mov(rsi, rax);
mov(rdx, 0);
mov(rcx, 1);
push(rax);
call(FireException);
pop(rax);
}
void JIT::lh(u32 instr) {

View File

@@ -5,6 +5,7 @@
#include <log.hpp>
namespace n64 {
using namespace Xbyak;
Cop1::Cop1() {
Reset();
}
@@ -176,6 +177,11 @@ void Cop1::decodeInterp(Interpreter &cpu, u32 instr) {
}
}
#ifdef REG
#undef REG
#define REG(ptr, member) cpu.ptr[cpu.rdi + offsetof(Registers, member)]
#endif
void Cop1::decodeJIT(JIT &cpu, u32 instr) {
Registers &regs = cpu.regs;
if(!regs.cop0.status.cu1) {
@@ -197,13 +203,22 @@ void Cop1::decodeJIT(JIT &cpu, u32 instr) {
case 0x06: ctc1(regs, instr); break;
case 0x07: FireException(regs, ExceptionCode::ReservedInstruction, 1, true); break;
case 0x08:
switch(mask_branch) {
case 0: cpu.b(instr, !regs.cop1.fcr31.compare); break;
case 1: cpu.b(instr, regs.cop1.fcr31.compare); break;
case 2: cpu.bl(instr, !regs.cop1.fcr31.compare); break;
case 3: cpu.bl(instr, regs.cop1.fcr31.compare); break;
/*switch(mask_branch) {
case 0: {
cpu.mov(cpu.rax, REG(byte, cop1.fcr31.compare));
cpu.b(instr, !regs.cop1.fcr31.compare);
} break;
case 1: {
cpu.b(instr, regs.cop1.fcr31.compare);
} break;
case 2: {
cpu.bl(instr, !regs.cop1.fcr31.compare);
} break;
case 3: {
cpu.bl(instr, regs.cop1.fcr31.compare);
} break;
default: Util::panic("Undefined BC COP1 {:02X}", mask_branch);
}
}*/
break;
case 0x10: // s
switch(mask_fun) {