idle skipping seems to work!

This commit is contained in:
2026-06-03 10:07:11 +02:00
parent cb8bb634ae
commit 204f0e13b0
5 changed files with 185 additions and 149 deletions
+42 -3
View File
@@ -116,8 +116,8 @@ u32 Interpreter::CacheBlock(u32 addr) {
break;
}
if (InstrEndsBlock(instr)) {
if (InstrHasDelaySlot(instr) && !fetchDelaySlot) {
if (instr.EndsBlock()) {
if (instr.HasDelaySlot() && !fetchDelaySlot) {
fetchDelaySlot = true;
continue;
}
@@ -129,6 +129,45 @@ u32 Interpreter::CacheBlock(u32 addr) {
}
}
auto delay = line.code[i - 1];
if (i == 2) {
// branch to itself
// _nop
auto branch = line.code[i - 2];
line.idleSkip = branch.IsBranch() && branch.offset() == -4 && delay.instr.raw == 0;
}
if (i == 3) {
// load reg1, [some location]
// bcond reg2
// _andi reg2, reg1, immediate
auto branch = line.code[i - 2];
auto load = line.code[i - 3]; // load
line.idleSkip = (load.opcode() == Instruction::LW || load.opcode() == Instruction::LWU) &&
delay.opcode() == Instruction::ANDI && branch.IsBranch() && branch.offset() == -16 &&
load.rt() == delay.rs() && delay.rt() == branch.rs();
}
if (i == 5) {
// lui reg1
// load reg2, [reg1(offset)]
// andi reg3, reg2, immediate
// bcond reg3
// _nop
auto branch = line.code[i - 2];
auto andi = line.code[i - 3]; // andi
auto load = line.code[i - 4]; // load
line.idleSkip = (load.opcode() == Instruction::LW || load.opcode() == Instruction::LWU) &&
andi.opcode() == Instruction::ANDI && branch.IsBranch() && branch.offset() == -16 &&
load.rt() == andi.rs() && andi.rt() == branch.rs();
}
line.cycles = i;
line.len = i;
cachedState.blocks[CACHE_GET_BLOCK(blockAddr)]->lines[CACHE_GET_LINE(blockAddr)] = new CachedLine(line);
@@ -162,7 +201,7 @@ u32 Interpreter::ExecuteCached() {
return i + 1;
// Branch likely with false condition, it wasn't taken so don't execute the delay slot
if (IsBranchLikely(instr) && !regs.delaySlot)
if (instr.IsBranchLikely() && !regs.delaySlot)
break;
}
+5 -5
View File
@@ -38,7 +38,7 @@ void JIT::InvalidateBlock(const u32 paddr) {
blockCache[index] = {};
}
std::optional<u32> JIT::FetchInstruction(s64 vaddr) {
std::optional<Instruction> JIT::FetchInstruction(s64 vaddr) {
u32 paddr = 0;
if (Core::IsAddressError(0b11, vaddr)) [[unlikely]] {
@@ -62,7 +62,7 @@ std::optional<u32> JIT::FetchInstruction(s64 vaddr) {
return std::nullopt;
}
const u32 instr = Core::GetMem().Read<u32>(paddr);
const Instruction instr = Core::GetMem().Read<u32>(paddr);
info("{}", Disassembler::GetInstance().DisassembleSimple(paddr, instr).full);
@@ -169,12 +169,12 @@ u32 JIT::Step() {
blockPC = blockNextPC;
blockNextPC += 4;
if (InstrEndsBlock(instruction.value())) {
const auto delay_instruction = FetchInstruction(blockPC); // get instruction in delay slot
if (instruction.value().EndsBlock()) {
auto delay_instruction = FetchInstruction(blockPC); // get instruction in delay slot
if (!delay_instruction)
return 0;
if (InstrEndsBlock(delay_instruction.value())) {
if (delay_instruction.value().EndsBlock()) {
Util::Error::GetInstance().Throw({Util::Error::Severity::NON_FATAL},
{Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT}, blockPC, {},
"[JIT]: Unhandled case of branch from delay slot!");
+1 -1
View File
@@ -118,7 +118,7 @@ struct JIT final {
[[nodiscard]] bool ShouldServiceInterrupt() const;
void CheckCompareInterrupt() const;
std::optional<u32> FetchInstruction(s64);
std::optional<Instruction> FetchInstruction(s64);
void Emit(Instruction);
void special(Instruction);
-138
View File
@@ -2,144 +2,6 @@
#include <Instruction.hpp>
namespace n64 {
static bool SpecialEndsBlock(const Instruction instr) {
switch (instr.special()) {
case Instruction::JR:
case Instruction::JALR:
case Instruction::SYSCALL:
case Instruction::BREAK:
case Instruction::TGE:
case Instruction::TGEU:
case Instruction::TLT:
case Instruction::TLTU:
case Instruction::TEQ:
case Instruction::TNE:
return true;
default:
return false;
}
}
static bool InstrHasDelaySlot(const Instruction instr) {
switch (instr.opcode()) {
case Instruction::SPECIAL:
if (instr.special() == Instruction::JR || instr.special() == Instruction::JALR)
return true;
return false;
case Instruction::REGIMM:
case Instruction::J:
case Instruction::JAL:
case Instruction::BEQ:
case Instruction::BNE:
case Instruction::BLEZ:
case Instruction::BGTZ:
case Instruction::BEQL:
case Instruction::BNEL:
case Instruction::BLEZL:
case Instruction::BGTZL:
return true;
case Instruction::COP1:
if (instr.cop_rs() == 8)
return true;
return false;
default:
return false;
}
}
static bool InstrEndsBlock(const Instruction instr) {
switch (instr.opcode()) {
case Instruction::SPECIAL:
return SpecialEndsBlock(instr);
case Instruction::REGIMM:
case Instruction::J:
case Instruction::JAL:
case Instruction::BEQ:
case Instruction::BNE:
case Instruction::BLEZ:
case Instruction::BGTZ:
case Instruction::BEQL:
case Instruction::BNEL:
case Instruction::BLEZL:
case Instruction::BGTZL:
return true;
case Instruction::COP1:
if (instr.cop_rs() == 8)
return true;
return false;
case Instruction::COP0:
switch (instr.cop_rs()) {
case 0x10 ... 0x1F:
switch (instr.cop_funct()) {
case 0x18: // eret
return true;
default:
return false;
}
default:
return false;
}
default:
return false;
}
}
static bool IsBranchLikely(const Instruction instr) {
switch (instr.opcode()) {
case Instruction::BEQL:
case Instruction::BNEL:
case Instruction::BLEZL:
case Instruction::BGTZL:
return true;
case Instruction::REGIMM:
switch (instr.regimm()) {
case Instruction::BLTZL:
case Instruction::BGEZL:
case Instruction::BLTZALL:
case Instruction::BGEZALL:
return true;
default:
return false;
}
case Instruction::COP1:
if (instr.cop_rs() == 8 && (instr.cop_rt() == 2 || instr.cop_rt() == 3))
return true;
return false;
default:
return false;
}
}
static bool IsBranch(const Instruction instr) {
switch (instr.opcode()) {
case Instruction::BEQ:
case Instruction::BNE:
case Instruction::BLEZ:
case Instruction::BGTZ:
return true;
case Instruction::REGIMM:
switch (instr.regimm()) {
case Instruction::BLTZ:
case Instruction::BGEZ:
case Instruction::BLTZAL:
case Instruction::BGEZAL:
return true;
default:
return false;
}
case Instruction::COP1:
if (instr.cop_rs() == 8 && (instr.cop_rt() == 0 || instr.cop_rt() == 1))
return true;
return false;
default:
return false;
}
}
#ifdef _WIN32
#define ARG1 rcx
#define ARG2 rdx