AUDIT-059 round 15 — diagnostic. New cvar `audit_jit_prolog_r3_bytes`
(default 64 = existing behaviour, capped at 256, rounded up to 16B
multiple) controls how many bytes are dumped at host(r3) when the
audit_jit_prolog_pc probe fires. Set to 80 to capture audit-051's
stack-local struct at sub_82452DC0's r31+96.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Round-14 of AUDIT-2BF (singleton-dump). Pairs with xenia-rs'
--audit-mem-read-hex to emit one comparable XELOGKERNEL line resolving
the bctrl target at sub_822F1AA8+0x90 (PC 0x822F1B4C):
[0x828E1F08] -> singleton instance ptr
[singleton+0] -> vtable
[vtable+0] -> vtable[0] (= first virtual method, bctrl tgt)
[vtable+24] -> vtable[24] (= slot 6, silph chain target)
Two complementary hooks:
1. src/xenia/cpu/backend/x64/x64_emitter.cc: extend
AuditLogJitPrologArgs. New cvar `audit_jit_prolog_mem_dump` (uint32).
When non-zero and an `audit_jit_prolog_pc` fire happens, the host
side dereferences the VA 3 levels deep and emits one
AUDIT-MEM-READ line in the same format ours emits. Defensive
per-level null + VA-range checks.
2. src/xenia/kernel/kernel_state.cc: one-shot dump in
EmulateCPInterruptDPC of the same chain (hard-coded to
0x828E1F08). Useful when audit_jit_prolog_pc isn't set; fires the
first time the CP interrupt path runs (after the singleton ctor
has had time to populate).
Read-only. Both gates default-off; no impact when cvars unset.
~65 LOC total across the two files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the round-7 hardcoded `current_guest_function_ == 0x824F7800`
gate with a runtime cvar `audit_jit_prolog_pc` (uint32, 0 = disabled).
The cvar names the guest entry PC at which the x64 emitter inserts a
CallNative to the prolog probe; the probe now dumps the active PC in
each log line so multiple instrumentation campaigns can share output.
Renames `audit_log_sub824F7800_args` (cvar) and `AuditLogSub824F7800Args`
(host function) — the round-7 sub_824F7800-specific cvar and function
are deleted, not left dormant. The `audit_handle_lifecycle` cvar and
its existing AUDIT-HLC probe sites in xboxkrnl_threading.cc /
kernel_state.cc are untouched.
Validated by audit-059 round 9: with `--audit_jit_prolog_pc=0x821B55D8`
the silph WorkerCtx-init chain entry fires 1× in canary at tid=6
lr=0x82172D8C (call site at sub_82172BA0+0x1E8 `bctrl`, the virtual
dispatch through vtable slot 6 that statically-blind xref-walkers
cannot enumerate).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds cvar audit_log_sub824F7800_args (off by default). When set, the x64
JIT emits one CallNative to AuditLogSub824F7800Args at the start of the
JIT-compiled body of guest function 0x824F7800 (silph::WorkerCtx ctor's
immediate caller per audit-058). The hook reads r3..r10, LR, and 64
bytes at host(r3) from PPCContext and writes them to XELOGKERNEL.
The hook is placed *after* the JIT prolog (stack push, GUEST_RET_ADDR /
GUEST_CALL_RET_ADDR setup, optional trace-functions block) and *before*
the first HIR body instruction, so r3..r10 and lr in PPCContext still
reflect the caller's args (no LOAD/STORE_CONTEXT has executed yet inside
the callee). The compile-time gate `current_guest_function_ == 0x824F7800`
makes this a zero-cost no-op for all other functions and a single extra
CallNative for the one target.
Audit-059 round 7 probe captures r3..r10 + LR for a-prime synthetic
replay of sub_824F7800 from a host hook in xenia-rs. Run with:
--audit_handle_lifecycle=true --audit_log_sub824F7800_args=true
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the x64 STVL/STVR lowering with explicit byte stores that preserve the
guest-visible vector byte order.
The previous vector shuffle/blend path could write incorrect bytes for partial
vector stores, which broke optimized guest memcpy implementations using
stvlx/stvrx for unaligned heads and tails. In 4156081C this corrupted skinned
model render command data and eventually caused render-thread crashes.
Add regression coverage for StoreVectorLeft/StoreVectorRight across common
unaligned offsets, plus a memcpy-head style case matching the affected guest
instruction pattern.
Detect dependent `AND` and `NOT` IR sequences and combine them into a
singular `AND_NOT` opcode. The later dead-code-elimination-pass will
get rid of the left-over `NOT` opcode if nothing else uses it.
This gets quite a good amount of hits in some of the titles I've tested.
Also updates unit tests with additional data-types and ensures that
`And(..., Not())` returns the same result as `AndNot(...)`
- DIV_I32/I64 and MUL_HI_I64: use source registers directly in
sdiv/udiv/umulh/smulh instead of copying to scratch first
- SWIZZLE: fast paths for identity (no-op), broadcast (dup), and
pair-swap (rev64) before falling back to general TBL
- LOAD_VECTOR_SHL/SHR: build base index vector with fmov+ins
instead of stp+ldr stack round-trip
Replace per-op save/restore of FPCR in EmitWithVmxFpcr with tracked
lazy switching via ChangeFpcrMode. Consecutive VMX float ops in the
same basic block now emit a single FPCR switch instead of one per op.
ChangeFpcrMode loads pre-computed values from the backend context
(fpcr_fpu/fpcr_vmx) instead of MRS + read-modify-write, eliminating
an expensive system register read per switch.
FPU mode is restored at block boundaries and calls via ForgetFpcrMode.
Scalar FP sequences guard with ChangeFpcrMode(Fpu) which is a no-op
when already in FPU mode.
The LSE paths in RESERVED_STORE_I32/I64 returned early from Emit,
leaving forward-referenced no_reserve/done labels unbound. Xbyak
encodes these as offset-zero branches (branch-to-self), causing
infinite loops when the reservation check fails on LSE hardware.
Replace early return with branch-to-done inside an if/else so
labels are always bound regardless of the LSE path taken.
Adds tests for RESERVED_STORE I64 success path and I32/I64
no-reservation failure path with timeout-based hang detection.
* Add unit tests
* Use `dc zva` to zero out entire cache-lines worth of data, when possible
* Special instruction that zaps an entire cache-line into being zero-values, typically 64-bytes at a time
* Statically read and initialize the `DCZID_EL0` register value since reading registers with `mrs` can be kinda slow and isn't worth doing redundantly at JIT-time when it never changes.
* Update store-instructions to use inline post-increments to avoid an additional `add` instruction and keep encoded instruction immediates small
Pretty much every arm processor has a cache line size of 64 bytes, so a typical `dcbz128` to clear 128-bytes of data now results in:
```
dc zva, x0
add x0, x0, 64
dc zva, x0
```
rather than a sequence of 8 `stp xzr, xzr, ...` instructions
Pack(1) causes unaligned pointer errors on ARM64 with Apple's linker.
These are static read-only tables where the ~9KB size savings from
packing is negligible. Removing the pack may also marginally improve
access speed on x86 by avoiding unaligned loads.
Most non-Windows code paths use standard POSIX APIs (sockets, signals,
dlopen, threading) that work on any POSIX platform. Change Linux-specific
guards to !WIN32 or #else where the code is portable. Linux-specific
APIs (SIGRTMIN, Vulkan/X11, fontconfig/GTK) remain Linux-guarded.
Optimize `LoadV128Const` to detect even more opportunities
to use `movi`, `mvni`, and `fmov` and such for 16-bit, 32-bit
and 64-bit splats.
Update some `mov`+`dup` idioms into `LoadV128Const` as well
to catch more opportunities to optimize these const-loads when
possible.
Adds `platform_arm64` similar to `platform_arm64` to populate a 64-bit feature-flag value and creates a `a64_extension_mask` configuration-mask for the detection and utilization of certain arm ISA features. The first feature being `FEAT_LSE` which maps to `XBYAK_AARCH64_HWCAP_ATOMIC`.
Just like the x64 backend, implements `IsFeatureEnabled` to the emitter for checking if the host processor supports a certain subset of feature flag(s) at once.
Optimizes `OPCODE_ATOMIC_EXCHANGE`, `OPCODE_ATOMIC_COMPARE_EXCHANGE`,
and `OPCODE_RESERVED_STORE` with `FEAT_LSE` instructions.
Replace CallNativeSafe round-trips with fcvtl/fcvtl2 for half-to-float
conversion. A rev64 fixup corrects the PPC word-pair ordering. FLOAT16_2
uses ext to rotate the two source halfs into position and sets the
constant {0.0, 1.0} tail lanes. PACK_FLOAT16 kept as C helpers since
fcvtn doesn't match Xenos overflow saturation semantics.
Replace CallNativeSafe round-trips with inline TBL shuffles. LVL uses
a single-register TBL where out-of-range indices naturally produce
zero. LVR uses a 2-register TBL over {zeros, mem} so indices 0-15 map
to zeros and 16-31 map to memory bytes.
Add sentinel bits after the left-shift so clz stops at the correct
count (8 or 16) instead of counting through all 32 bits of the
widened register. Unlikely to hit in practice since PPC only has
cntlzw/cntlzd, but corrects existing sub-word variants.
Expands the vector register allocator from 20 to 28 registers by
including v8-v15. The HostToGuestThunk now saves/restores full Q8-Q15
(128-bit) instead of just D8-D15, and the GuestToHostThunk adds Q8-Q15
to its save/restore set since AAPCS64 only preserves their lower 64
bits across C calls.
Reduces register pressure for VMX-heavy guest code at the cost of
slightly larger thunk stack frames.
Reserves x19 to permanently hold the A64BackendContext pointer
(x20 - sizeof(A64BackendContext)), set once in the HostToGuestThunk.
Since x19 is AAPCS64 callee-saved, it survives all host calls for free.
Eliminates repeated 2-instruction mov+sub sequences in stackpoint
push/pop, stack synchronization, FPCR management, and reserved
load/store paths.
Reduces allocatable GPRs from 8 to 7 (like on x64).
Use the provided scratch register-index, defaults to W0/X0, and insert 64-bit elements directly into the vector-register rather than writing/reading to scratch memory.