From 28d49812fa092fbe3a321ffb91f4dfc8daa18a78 Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Mon, 28 Aug 2023 20:12:17 +0200 Subject: [PATCH] More JIT work --- src/backend/core/JIT.cpp | 3 +- src/backend/core/JIT.hpp | 43 +++++++-- src/backend/core/JIT/decode.cpp | 22 ++++- src/backend/core/JIT/instructions.cpp | 130 +++++++++++++++++--------- src/backend/core/registers/Cop1.cpp | 27 ++++-- 5 files changed, 164 insertions(+), 61 deletions(-) diff --git a/src/backend/core/JIT.cpp b/src/backend/core/JIT.cpp index c861ea98..3c6adbd9 100644 --- a/src/backend/core/JIT.cpp +++ b/src/backend/core/JIT.cpp @@ -34,8 +34,9 @@ Fn JIT::Recompile() { bool stable = true; cycles = 0; prologue(); + mov(rbp, u64(this)); + mov(rdi, u64(this) + offsetof(JIT, regs)); while(stable) { - mov(rdi, u64(this) + offsetof(JIT, regs)); cycles++; CheckCompareInterrupt(); diff --git a/src/backend/core/JIT.hpp b/src/backend/core/JIT.hpp index 71159fe1..452e8857 100644 --- a/src/backend/core/JIT.hpp +++ b/src/backend/core/JIT.hpp @@ -23,6 +23,33 @@ private: void CheckCompareInterrupt() override; Fn Recompile(); + template + void emitMemberCall(T func, void* thisObj) { + void* funcPtr; + auto thisPtr = reinterpret_cast(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(tmpArr[0]); + thisPtr += tmpArr[1]; +#else + Util::panic("Huh?!"); +#endif*/ + + push(rdi); + if(thisPtr == reinterpret_cast(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 - void branch(const Xbyak::Operand&, const T&, s64, BranchCond); + void branch(const Xbyak::Reg64&, const T&, s64, BranchCond); template - void branch_likely(const Xbyak::Operand&, const T&, s64, BranchCond); + void branch_likely(const Xbyak::Reg64&, const T&, s64, BranchCond); template - void b(u32, const Xbyak::Operand&, const T&, BranchCond); + void b(u32, const Xbyak::Reg64&, const T&, BranchCond); template - void blink(u32, const Xbyak::Operand&, const T&, BranchCond); + void blink(u32, const Xbyak::Reg64&, const T&, BranchCond); template - void bl(u32, const Xbyak::Operand&, const T&, BranchCond); + void bl(u32, const Xbyak::Reg64&, const T&, BranchCond); template - 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); diff --git a/src/backend/core/JIT/decode.cpp b/src/backend/core/JIT/decode.cpp index f43e5ae5..63beee59 100644 --- a/src/backend/core/JIT/decode.cpp +++ b/src/backend/core/JIT/decode.cpp @@ -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; diff --git a/src/backend/core/JIT/instructions.cpp b/src/backend/core/JIT/instructions.cpp index 064c71a5..04b9d541 100644 --- a/src/backend/core/JIT/instructions.cpp +++ b/src/backend/core/JIT/instructions.cpp @@ -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 -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(const Xbyak::Operand& op1, const Xbyak::Operand& op2, s64 offset, BranchCond cond); -template void JIT::branch(const Xbyak::Operand& op1, const int& op2, s64 offset, BranchCond cond); +template void JIT::branch(const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, s64 offset, BranchCond cond); +template void JIT::branch(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 +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(const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, s64 offset, BranchCond cond); +template void JIT::branch_likely(const Xbyak::Reg64& op1, const int& op2, s64 offset, BranchCond cond); + +template +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(u32, const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, BranchCond cond); +template void JIT::b(u32, const Xbyak::Reg64& op1, const int& op2, BranchCond cond); + +template +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(u32, const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, BranchCond cond); +template void JIT::blink(u32, const Xbyak::Reg64& op1, const int& op2, BranchCond cond); + +template +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(u32, const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, BranchCond cond); +template void JIT::bl(u32, const Xbyak::Reg64& op1, const int& op2, BranchCond cond); + +template +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(u32, const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, BranchCond cond); +template void JIT::bllink(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) { diff --git a/src/backend/core/registers/Cop1.cpp b/src/backend/core/registers/Cop1.cpp index e82598ff..35e3c330 100644 --- a/src/backend/core/registers/Cop1.cpp +++ b/src/backend/core/registers/Cop1.cpp @@ -5,6 +5,7 @@ #include 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 ®s = 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) {