From f8ecf79c2f703cbbfe9a95cc4a98869022e510b2 Mon Sep 17 00:00:00 2001 From: Simone Date: Thu, 21 Dec 2023 11:52:35 +0100 Subject: [PATCH] more instructions in IR --- src/backend/core/JIT.hpp | 4 +- src/backend/core/JIT/IR.hpp | 38 ++++- src/backend/core/JIT/instructions.cpp | 198 +++++++++++++++----------- 3 files changed, 153 insertions(+), 87 deletions(-) diff --git a/src/backend/core/JIT.hpp b/src/backend/core/JIT.hpp index f78f600f..d2430bac 100644 --- a/src/backend/core/JIT.hpp +++ b/src/backend/core/JIT.hpp @@ -3,7 +3,8 @@ #include #include #include -#include "CpuDefinitions.hpp" +#include +#include namespace n64 { using Fn = int(*)(); @@ -29,6 +30,7 @@ struct JIT : BaseCPU, Xbyak::CodeGenerator { friend struct Cop1; friend struct Cop0; private: + IR ir{}; int cycles = 0; bool ShouldServiceInterrupt() override; void CheckCompareInterrupt() override; diff --git a/src/backend/core/JIT/IR.hpp b/src/backend/core/JIT/IR.hpp index 2f43e217..b7436d83 100644 --- a/src/backend/core/JIT/IR.hpp +++ b/src/backend/core/JIT/IR.hpp @@ -1,17 +1,47 @@ #pragma once #include #include +#include namespace n64 { struct Entry { - u16 type; + enum : u8 { + LINK = 0x10, + LIKELY = 0x20, + REGISTER = 0x40 + }; + + enum Opcode : u16 { + MOV, ADD, SUB, MUL, DIV, AND, NOR, XOR, OR, SRL, SLL, SRA, + LOAD, STORE, BRANCH, JUMP + } op; + struct Operand { - enum { + enum Type { + NONE, REG_F64, REG_F32, IMM_F64, IMM_F32, REG_S64, REG_S32, REG_U64, REG_U32, REG_U5, IMM_S16, IMM_S32, IMM_S64, IMM_U16, IMM_U32, IMM_U64, IMM_U5, } type; - u8 index; - } dst, op1, op2; + std::optional index_or_imm; + + Operand(Type t, std::optional i = std::nullopt) + : type(t), index_or_imm(i) {} + } dst = Operand::NONE, op1, op2; + + enum BranchCond { + EQ, NE, LT, GT, LE, GE + }; + + std::optional branchCond = std::nullopt; + + Entry(Opcode op, Operand dst, Operand op1, Operand op2) + : op(op), dst(dst), op1(op1), op2(op2) {} + + Entry(Opcode op, Operand op1, Operand op2) + : op(op), op1(op1), op2(op2) {} + + Entry(Opcode op, Operand op1, std::optional bc, Operand op2) + : op(op), op1(op1), branchCond(bc), op2(op2) {} }; struct IR { diff --git a/src/backend/core/JIT/instructions.cpp b/src/backend/core/JIT/instructions.cpp index 7ec1f46c..eebb477b 100644 --- a/src/backend/core/JIT/instructions.cpp +++ b/src/backend/core/JIT/instructions.cpp @@ -6,12 +6,11 @@ namespace n64 { void JIT::add(u32 instr) { - if (RD(instr) != 0) [[likely]] { - movsx(eax, GPR(dword, RS(instr))); // rs - movsx(ecx, GPR(dword, RT(instr))); // rt - CodeGenerator::add(eax, ecx); - mov(GPR(dword, RD(instr)), eax); // rd - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::REG_U32, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_U32, u8(RT(instr)) }; + Entry e(Entry::ADD, dst, op1, op2); + ir.push(e); } void JIT::addu(u32 instr) { @@ -19,12 +18,11 @@ void JIT::addu(u32 instr) { } void JIT::addi(u32 instr) { - if (RT(instr) != 0) [[likely]] { - movsx(eax, GPR(dword, RS(instr))); - mov(ecx, s32(s16(instr))); - CodeGenerator::add(eax, ecx); - mov(GPR(dword, RT(instr)), eax); - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::REG_U32, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::IMM_S16, s16(instr) }; + Entry e(Entry::ADD, dst, op1, op2); + ir.push(e); } void JIT::addiu(u32 instr) { @@ -32,76 +30,133 @@ void JIT::addiu(u32 instr) { } void JIT::dadd(u32 instr) { - if (RD(instr) != 0) [[likely]] { - mov(rax, GPR(qword, RS(instr))); // rs - mov(rcx, GPR(qword, RT(instr))); // rt - CodeGenerator::add(rax, rcx); - mov(GPR(qword, RD(instr)), rax); // rd - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::REG_U64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_U64, u8(RT(instr)) }; + Entry e(Entry::ADD, dst, op1, op2); + ir.push(e); } -void JIT::bltz(u32) { - +void JIT::bltz(u32 instr) { + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; + Entry e(Entry::BRANCH, op1, Entry::BranchCond::LT, op2); + ir.push(e); } -void JIT::bgez(u32) { - +void JIT::bgez(u32 instr) { + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; + Entry e(Entry::BRANCH, op1, Entry::BranchCond::GE, op2); + ir.push(e); } -void JIT::bltzl(u32) { - +void JIT::bltzl(u32 instr) { + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; + auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); + Entry e(opc, op1, Entry::BranchCond::LT, op2); + ir.push(e); } -void JIT::bgezl(u32) { - +void JIT::bgezl(u32 instr) { + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; + auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); + Entry e(opc, op1, Entry::BranchCond::GE, op2); + ir.push(e); } -void JIT::bltzal(u32) { - +void JIT::bltzal(u32 instr) { + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; + auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LINK); + Entry e(opc, op1, Entry::BranchCond::LT, op2); + ir.push(e); } -void JIT::bgezal(u32) { - +void JIT::bgezal(u32 instr) { + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; + auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LINK); + Entry e(opc, op1, Entry::BranchCond::GE, op2); + ir.push(e); } -void JIT::bltzall(u32) { - +void JIT::bltzall(u32 instr) { + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; + auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LINK | Entry::LIKELY); + Entry e(opc, op1, Entry::BranchCond::LT, op2); + ir.push(e); } -void JIT::bgezall(u32) { - +void JIT::bgezall(u32 instr) { + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; + auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LINK | Entry::LIKELY); + Entry e(opc, op1, Entry::BranchCond::GE, op2); + ir.push(e); } -void JIT::beq(u32) { - +void JIT::beq(u32 instr) { + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + Entry e(Entry::BRANCH, op1, Entry::BranchCond::EQ, op2); + ir.push(e); } -void JIT::bne(u32) { - +void JIT::bne(u32 instr) { + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + Entry e(Entry::BRANCH, op1, Entry::BranchCond::NE, op2); + ir.push(e); } -void JIT::blez(u32) { - +void JIT::blez(u32 instr) { + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::IMM_S64, 0 }; + Entry e(Entry::BRANCH, op1, Entry::BranchCond::LE, op2); + ir.push(e); } -void JIT::bgtz(u32) { - +void JIT::bgtz(u32 instr) { + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::IMM_S64, 0 }; + Entry e(Entry::BRANCH, op1, Entry::BranchCond::GT, op2); + ir.push(e); } -void JIT::beql(u32) { - +void JIT::beql(u32 instr) { + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); + Entry e(opc, op1, Entry::BranchCond::EQ, op2); + ir.push(e); } -void JIT::bnel(u32) { - +void JIT::bnel(u32 instr) { + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); + Entry e(opc, op1, Entry::BranchCond::NE, op2); + ir.push(e); } -void JIT::blezl(u32) { - +void JIT::blezl(u32 instr) { + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::IMM_S64, 0 }; + auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); + Entry e(opc, op1, Entry::BranchCond::LE, op2); + ir.push(e); } -void JIT::bgtzl(u32) { - +void JIT::bgtzl(u32 instr) { + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::IMM_S64, 0 }; + auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); + Entry e(opc, op1, Entry::BranchCond::GT, op2); + ir.push(e); } void JIT::daddu(u32 instr) { @@ -109,12 +164,11 @@ void JIT::daddu(u32 instr) { } void JIT::daddi(u32 instr) { - if (RT(instr) != 0) [[likely]] { - mov(rax, GPR(qword, RS(instr))); - mov(rcx, s64(s16(instr))); - CodeGenerator::add(rax, rcx); - mov(GPR(qword, RT(instr)), rax); - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::IMM_S16, s16(instr) }; + Entry e(Entry::ADD, dst, op1, op2); + ir.push(e); } void JIT::daddiu(u32 instr) { @@ -122,25 +176,7 @@ void JIT::daddiu(u32 instr) { } void JIT::div(u32 instr) { - movsxd(rax, GPR(dword, RS(instr))); // dividend - movsxd(rcx, GPR(dword, RT(instr))); // divisor - cmp(rcx, 0); - je("div_divisor==0"); - - CodeGenerator::div(rcx); - mov(qword[rdi + offsetof(Registers, lo)], eax); - mov(qword[rdi + offsetof(Registers, hi)], edx); - jmp("div_exit"); - - L("div_divisor==0"); - mov(qword[rdi + offsetof(Registers, hi)], rax); - cmp(rax, 0); - jge("div_dividend>=0"); - mov(qword[rdi + offsetof(Registers, lo)], s64(1)); - L("div_dividend>=0"); - mov(qword[rdi + offsetof(Registers, lo)], s64(-1)); - - L("div_exit"); + } void JIT::divu(u32 instr) { @@ -731,13 +767,11 @@ void JIT::and_(u32 instr) { } void JIT::sll(u32 instr) { - if (RD(instr) != 0) [[likely]] { - u8 sa = ((instr >> 6) & 0x1f); - mov(rax, GPR(qword, RT(instr))); - sal(rax, sa); - movsxd(rcx, eax); - mov(GPR(qword, RD(instr)), rcx); - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::IMM_U5, std::nullopt }; + Entry e(Entry::SLL, dst, op1, op2); + ir.push(e); } void JIT::sllv(u32 instr) {