mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-01 20:18:15 +01:00
IR: Compile kernel loads and stores instead of interpreting them
Kernel code's loads and stores may reach hardware registers, which only the interpreter handled, so the IR frontend sent every one of them (in kernel blocks, only run by the VSH boot) to it. They now become LoadKernel*/StoreKernel* IR ops (one per size, like the plain loads and stores), which check at run time whether the address is memory or a hardware register (MMIO). After constant propagation, ResolveKernelMemory turns the ones at a constant address that's plain memory into ordinary loads and stores, so only the hardware registers, and addresses only known at run time, stay checked. The native JITs run the two ops through their IR fallback. They're barriers, since a register access has side effects, but can't change the GPRs, so constants stay known across. The kernel mode check for MMIO moves to the interpreter, the only caller that can run user code there. TestMMIO covers the new paths and which accesses stay checked. Under --vsh, the JIT and the interpreter now make the same unhandled register accesses, in the same numbers. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
79e88a7e0d
commit
53ac2c7c56
12 files changed
+268
-47
No files matched your search
@@ -53,18 +53,28 @@ namespace MIPSComp {
|
||||
|
||||
CheckMemoryBreakpoint(rs, offset);
|
||||
|
||||
if (js.kernelMode) {
|
||||
// Send all memory accesses to the interpreter in kernel mode.
|
||||
// TODO: Do something faster - but it hardly matters, currently this is VSH-only.
|
||||
DISABLE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (((op >> 29) & 1) == 0 && rt == MIPS_REG_ZERO) {
|
||||
// Don't load anything into $zr
|
||||
return;
|
||||
}
|
||||
|
||||
if (js.kernelMode) {
|
||||
// Kernel code may reach hardware registers. ResolveKernelMemory turns the plain memory
|
||||
// accesses back into ordinary ones where it can tell. The rest go to the interpreter.
|
||||
switch (o) {
|
||||
case 32: ir.Write(IROp::LoadKernel8Ext, rt, rs, 0, offset); return;
|
||||
case 33: ir.Write(IROp::LoadKernel16Ext, rt, rs, 0, offset); return;
|
||||
case 35: ir.Write(IROp::LoadKernel32, rt, rs, 0, offset); return;
|
||||
case 36: ir.Write(IROp::LoadKernel8, rt, rs, 0, offset); return;
|
||||
case 37: ir.Write(IROp::LoadKernel16, rt, rs, 0, offset); return;
|
||||
case 40: ir.Write(IROp::StoreKernel8, rt, rs, 0, offset); return;
|
||||
case 41: ir.Write(IROp::StoreKernel16, rt, rs, 0, offset); return;
|
||||
case 43: ir.Write(IROp::StoreKernel32, rt, rs, 0, offset); return;
|
||||
default:
|
||||
DISABLE;
|
||||
}
|
||||
}
|
||||
|
||||
switch (o) {
|
||||
// Load
|
||||
case 35:
|
||||
|
||||
Reference in new issue
Block a user