CPU: Add more branch hints to interpreter

Eliminate more bounds checks. This plus the last change can net up to a
20% performance improvement in some games when using the interpreter
(tested on AMD 7950X3D).
pull/3750/head
Stenzek 4 months ago
parent 667e1147a4
commit 2b5baa1b82
No known key found for this signature in database

@ -2557,13 +2557,13 @@ template<PGXPMode pgxp_mode, bool debug>
}
// fetch the next instruction - even if this fails, it'll still refetch on the flush so we can continue
if (!FetchInstruction())
if (!FetchInstruction()) [[unlikely]]
continue;
// trace functionality
if constexpr (debug)
{
if (s_locals.trace_to_log)
if (s_locals.trace_to_log) [[unlikely]]
LogInstruction(g_state.current_instruction.bits, g_state.current_instruction_pc, true);
// handle all mirrors of the syscall trampoline. will catch 200000A0 etc, but those aren't fetchable anyway
@ -2973,6 +2973,9 @@ ALWAYS_INLINE_RELEASE bool CPU::FetchInstruction()
DebugAssert(Common::IsAlignedPow2(g_state.npc, 4));
const PhysicalMemoryAddress address = g_state.npc;
g_state.pc = g_state.npc;
g_state.npc += sizeof(g_state.next_instruction.bits);
switch (address >> 29)
{
case 0x00: // KUSEG 0M-512M
@ -2991,25 +2994,24 @@ ALWAYS_INLINE_RELEASE bool CPU::FetchInstruction()
case 0x05: // KSEG1 - physical memory uncached
{
if (!DoInstructionRead<true, false, 1, true>(address, &g_state.next_instruction.bits))
if (!DoInstructionRead<true, false, 1, true>(address, &g_state.next_instruction.bits)) [[unlikely]]
return false;
}
break;
case 0x01: // KUSEG 512M-1024M
case 0x02: // KUSEG 1024M-1536M
case 0x03: // KUSEG 1536M-2048M
case 0x06: // KSEG2
case 0x07: // KSEG2
default:
[[unlikely]] case 0x01: // KUSEG 512M-1024M
[[unlikely]] case 0x02: // KUSEG 1024M-1536M
[[unlikely]] case 0x03: // KUSEG 1536M-2048M
[[unlikely]] case 0x06: // KSEG2
[[unlikely]] case 0x07: // KSEG2
{
CPU::RaiseException(Cop0Registers::CAUSE::MakeValueForException(Exception::IBE, false, false, 0), address);
return false;
}
DefaultCaseIsUnreachable();
}
g_state.pc = g_state.npc;
g_state.npc += sizeof(g_state.next_instruction.bits);
return true;
}
@ -3024,11 +3026,14 @@ bool CPU::FetchInstructionForInterpreterFallback()
}
const PhysicalMemoryAddress address = g_state.npc;
g_state.pc = g_state.npc;
g_state.npc += sizeof(g_state.next_instruction.bits);
switch (address >> 29)
{
case 0x00: // KUSEG 0M-512M
case 0x04: // KSEG0 - physical memory cached
case 0x05: // KSEG1 - physical memory uncached
[[unlikely]] case 0x00: // KUSEG 0M-512M
[[unlikely]] case 0x04: // KSEG0 - physical memory cached
[[unlikely]] case 0x05: // KSEG1 - physical memory uncached
{
// We don't use the icache when doing interpreter fallbacks, because it's probably stale.
if (!DoInstructionRead<false, false, 1, true>(address, &g_state.next_instruction.bits)) [[unlikely]]
@ -3036,12 +3041,11 @@ bool CPU::FetchInstructionForInterpreterFallback()
}
break;
case 0x01: // KUSEG 512M-1024M
case 0x02: // KUSEG 1024M-1536M
case 0x03: // KUSEG 1536M-2048M
case 0x06: // KSEG2
case 0x07: // KSEG2
default:
[[unlikely]] case 0x01: // KUSEG 512M-1024M
[[unlikely]] case 0x02: // KUSEG 1024M-1536M
[[unlikely]] case 0x03: // KUSEG 1536M-2048M
[[unlikely]] case 0x06: // KSEG2
[[unlikely]] case 0x07: // KSEG2
{
CPU::RaiseException(Cop0Registers::CAUSE::MakeValueForException(Exception::IBE,
g_state.current_instruction_in_branch_delay_slot,
@ -3049,10 +3053,10 @@ bool CPU::FetchInstructionForInterpreterFallback()
address);
return false;
}
DefaultCaseIsUnreachable();
}
g_state.pc = g_state.npc;
g_state.npc += sizeof(g_state.next_instruction.bits);
return true;
}
@ -3068,15 +3072,14 @@ bool CPU::SafeReadInstruction(VirtualMemoryAddress addr, u32* value)
return DoInstructionRead<false, false, 1, false>(addr, value);
}
case 0x01: // KUSEG 512M-1024M
case 0x02: // KUSEG 1024M-1536M
case 0x03: // KUSEG 1536M-2048M
case 0x06: // KSEG2
case 0x07: // KSEG2
default:
{
[[unlikely]] case 0x01: // KUSEG 512M-1024M
[[unlikely]] case 0x02: // KUSEG 1024M-1536M
[[unlikely]] case 0x03: // KUSEG 1536M-2048M
[[unlikely]] case 0x06: // KSEG2
[[unlikely]] case 0x07: // KSEG2
return false;
}
DefaultCaseIsUnreachable();
}
}
@ -3134,11 +3137,11 @@ ALWAYS_INLINE bool CPU::DoSafeMemoryAccess(VirtualMemoryAddress address, u32& va
}
break;
case 0x01: // KUSEG 512M-1024M
case 0x02: // KUSEG 1024M-1536M
case 0x03: // KUSEG 1536M-2048M
case 0x06: // KSEG2
case 0x07: // KSEG2
[[unlikely]] case 0x01: // KUSEG 512M-1024M
[[unlikely]] case 0x02: // KUSEG 1024M-1536M
[[unlikely]] case 0x03: // KUSEG 1536M-2048M
[[unlikely]] case 0x06: // KSEG2
[[unlikely]] case 0x07: // KSEG2
{
// Above 512mb raises an exception.
return false;
@ -3480,12 +3483,12 @@ ALWAYS_INLINE_RELEASE bool CPU::DoAlignmentCheck(VirtualMemoryAddress address)
{
if constexpr (size == MemoryAccessSize::HalfWord)
{
if (Common::IsAlignedPow2(address, 2))
if (Common::IsAlignedPow2(address, 2)) [[likely]]
return true;
}
else if constexpr (size == MemoryAccessSize::Word)
{
if (Common::IsAlignedPow2(address, 4))
if (Common::IsAlignedPow2(address, 4)) [[likely]]
return true;
}
else
@ -3567,7 +3570,7 @@ bool CPU::ReadMemoryByte(VirtualMemoryAddress addr, u8* value)
bool CPU::ReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value)
{
if (!DoAlignmentCheck<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(addr))
if (!DoAlignmentCheck<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(addr)) [[unlikely]]
return false;
*value = Truncate16(GetMemoryReadHandler(addr, MemoryAccessSize::HalfWord)(addr));
@ -3584,7 +3587,7 @@ bool CPU::ReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value)
bool CPU::ReadMemoryWord(VirtualMemoryAddress addr, u32* value)
{
if (!DoAlignmentCheck<MemoryAccessType::Read, MemoryAccessSize::Word>(addr))
if (!DoAlignmentCheck<MemoryAccessType::Read, MemoryAccessSize::Word>(addr)) [[unlikely]]
return false;
*value = GetMemoryReadHandler(addr, MemoryAccessSize::Word)(addr);
@ -3618,7 +3621,7 @@ bool CPU::WriteMemoryHalfWord(VirtualMemoryAddress addr, u32 value)
{
MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::HalfWord, addr, value);
if (!DoAlignmentCheck<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(addr))
if (!DoAlignmentCheck<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(addr)) [[unlikely]]
return false;
GetMemoryWriteHandler(addr, MemoryAccessSize::HalfWord)(addr, value);
@ -3636,7 +3639,7 @@ bool CPU::WriteMemoryWord(VirtualMemoryAddress addr, u32 value)
{
MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::Word, addr, value);
if (!DoAlignmentCheck<MemoryAccessType::Write, MemoryAccessSize::Word>(addr))
if (!DoAlignmentCheck<MemoryAccessType::Write, MemoryAccessSize::Word>(addr)) [[unlikely]]
return false;
GetMemoryWriteHandler(addr, MemoryAccessSize::Word)(addr, value);

Loading…
Cancel
Save