[iterate-4A] jit: wire compiled-block cache + cover bx/bcx/bclrx (diff-clean, 6.57% native)
Wire the Cranelift block-JIT into execution and add branch coverage. Both
increments validated bit-exact against the interpreter via the in-process
differential harness on a full boot+movie run (movie plays, clean exit):
wiring only (addi/addis): checked 146.8M blocks, 0.01% native, MISMATCHES=0
+ branches (bx/bcx/bclrx): checked 148.5M blocks, 6.57% native (9.76M), MISMATCHES=0
jit.rs
* JitCache: direct-mapped 64K-slot compiled-block cache keyed (start_pc,
page_version) identically to BlockCache, so self-modifying / DMA'd code
invalidates native code the same way. Caches the None ("uncovered") verdict
so an uncovered block is compile-attempted at most once per (pc,version).
Owns the Jit/JITModule (keeps every CompiledFn valid for its lifetime).
* covered(): addi/addis + bx/bcx/bclrx. bcctrx excluded (indirect target +
dispatch_rec diagnostic hook the native path would skip).
* pc-handling refactor: a branch terminator writes pc itself (writes_pc());
the block epilogue stores end_pc only for straight-line (max-len / page-
boundary) blocks. cycle/timebase still += N (covered ops never fault/yield;
a branch is always the last instruction).
* Branch lowering uses immediate targets — the interpreter's ctx.pc equals the
instruction address at emit time, so bx/bcx relative targets are constants.
emit_branch_taken mirrors the interpreter: optional CTR decrement, ctr_ok =
(ctr as u32 vs 0) inverted by BO3, cond_ok = CR-bit BI byte == BO1 (both BO
sub-cases const-fold), combined with select. bclrx reads lr&!3 before the LK
link overwrites lr.
recompiler.rs
* run_block / diff_step take &mut JitCache. run_block runs the native fn when
get_or_compile returns one (else interpreter fallback); diff_step runs it on
the speculative clone/OverlayMemory so every native block is diff-checked.
* report_jit_summary(): native-vs-interpreted block counts (XENIA_JIT / _DIFF).
main.rs
* WorkerCtx owns a JitCache; run_superblock routing passes it to
diff_step/run_block; report_jit_summary() at clean exit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2479,6 +2479,10 @@ struct WorkerCtx {
|
||||
hw_id: u8,
|
||||
block_cache: xenia_cpu::block_cache::BlockCache,
|
||||
decode_cache: xenia_cpu::decoder::DecodeCache,
|
||||
/// Compiled-block cache (Cranelift JIT). Keyed identically to `block_cache`
|
||||
/// on `(start_pc, page_version)`; owns the JIT module and thus the native
|
||||
/// code. Only consulted on the `XENIA_JIT` / `XENIA_JIT_DIFF` paths.
|
||||
jit_cache: xenia_cpu::jit::JitCache,
|
||||
force_per_instr: bool,
|
||||
}
|
||||
|
||||
@@ -2488,6 +2492,7 @@ impl WorkerCtx {
|
||||
hw_id,
|
||||
block_cache: xenia_cpu::block_cache::BlockCache::new(),
|
||||
decode_cache: xenia_cpu::decoder::DecodeCache::new(),
|
||||
jit_cache: xenia_cpu::jit::JitCache::new(),
|
||||
force_per_instr,
|
||||
}
|
||||
}
|
||||
@@ -3145,9 +3150,9 @@ fn run_superblock(
|
||||
// - XENIA_JIT: JIT authoritative (M0 = interpreter fallback),
|
||||
// - else: interpreter directly.
|
||||
if xenia_cpu::recompiler::diff_enabled() {
|
||||
xenia_cpu::recompiler::diff_step(ctx, mem, block)
|
||||
xenia_cpu::recompiler::diff_step(ctx, mem, block, &mut wc.jit_cache)
|
||||
} else if xenia_cpu::recompiler::jit_enabled() {
|
||||
xenia_cpu::recompiler::run_block(ctx, mem, block)
|
||||
xenia_cpu::recompiler::run_block(ctx, mem, block, &mut wc.jit_cache)
|
||||
} else {
|
||||
step_block(ctx, mem, block)
|
||||
}
|
||||
@@ -4396,6 +4401,8 @@ fn dump_thread_diagnostic(
|
||||
}
|
||||
// JIT differential harness: checked/skipped/mismatch tally at clean exit.
|
||||
xenia_cpu::recompiler::report_diff_summary();
|
||||
// JIT native-vs-interpreted block coverage at clean exit.
|
||||
xenia_cpu::recompiler::report_jit_summary();
|
||||
// JIT opcode-frequency histogram (XENIA_JIT_HIST) — drives M1 coverage.
|
||||
xenia_cpu::recompiler::report_histogram();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user