Commit Graph

466 Commits

Author SHA1 Message Date
Gliniak
9588ce244d [CPU/X64] Preserve NaN bit during float->double, double->float conversion
Probably this should be moved to ppc_emit_memory level instead of being x86-64 specific

Was AI used in this change: Yes
2026-06-29 22:50:14 +02:00
Michael Oliver
30ac9d7be6 [CPU] fix correct partial vector stores
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.
2026-06-11 21:14:23 +02:00
Guilhem Massol
f3086cfced [Compilation] Fix Clang 23 2026-05-12 22:45:56 +02:00
Gliniak
74f34818e7 [Lint] Added InsertBraces to linter to unify codebase to one standard 2026-05-08 18:54:50 +02:00
Wunkolo
8e1b286578 [x64] Add GFNI and AVX512VBMI optimizations for VECTOR_SHL(Int8)
Uses `{v}gf2p8mulb` as a general int8-multiplication instruction to do
variable Int8 bit-shifts.
Uses `{v}gf2p8affineqb` in the case that all of the shift values are the same.

Based on this original PR I had made to Xenia:
https://github.com/xenia-project/xenia/pull/2247
and this little write-up I did on this method:
https://wunkolo.github.io/post/2020/11/gf2p8affineqb-int8-shifting/
2026-04-23 22:07:39 +02:00
Herman S.
4acda223db [CPU] Remove ATOMIC_EXCHANGE opcode (dead code) 2026-04-08 00:05:29 +09:00
Herman S.
d2c8ca675e [A64] Use ARM64 bitmask immediates for AND/OR/XOR with constants 2026-03-31 18:21:22 +09:00
Herman S.
84b05bd20a [A64] Skip software denormal flushing when FPCR.FZ handles inputs
Depends on hardware support, detected and runtime and controllable
via a64_extension_mask bit 1.
2026-03-31 18:21:21 +09:00
Herman S.
02ea71ed51 [A64] Replace RSQRT CallNativeSafe with direct blr calls 2026-03-31 18:21:21 +09:00
Herman S.
06f56a20ea [A64] Inline V128 bit-shifts with NEON, remove C helper thunks 2026-03-31 18:21:21 +09:00
Herman S.
2fc5aca628 [A64] Optimizations for DIV, MUL_HI, SWIZZLE, LOAD_VECTOR_SHL/SHR
- 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
2026-03-31 18:21:21 +09:00
Herman S.
59f9fb9964 [A64] Optimize FPCR switching with lazy mode tracking
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.
2026-03-31 18:21:21 +09:00
Herman S.
904c6c8b1c [A64] Fix RESERVED_STORE LSE path leaving labels unbound
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.
2026-03-30 11:10:30 +09:00
Herman S.
553aedebb5 [A64] Remove dead code 2026-03-29 17:16:56 +09:00
Herman S.
2d2105cfd8 [A64] Assert OPCODE_MEMSET invariants, remove dead general-case path 2026-03-29 15:14:04 +09:00
Wunkolo
664b77f38e [a64] Optimize OPCODE_MEMSET with zva
* 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
2026-03-29 15:13:45 +09:00
Herman S.
cb12f7fa1e [Build] Generalize POSIX platform guards
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.
2026-03-26 23:10:47 +09:00
Wunkolo
45cf464f63 [a64] Optimize more LoadV128Const splat opportunities
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.
2026-03-26 22:42:01 +09:00
Wunkolo
6a47370219 [a64] Fix ATOMIC_EXCHANGE swp operand order
`swp` is weird and actually writes the first operand into the
memory address into the third operand,
_and puts the old value into the second operand_.
2026-03-26 16:04:36 +09:00
Herman S.
b6ad99ee21 [A64] Add thread-safe atomics to A64Function
Also adds some bounds check to LookupFunction.

Co-Authored-By: Reality <reality@xenios.jp>
2026-03-25 15:31:26 +09:00
Herman S.
0e05b92f85 [A64] Use shifted immediate for 0x1000 add in ComputeMemoryAddress 2026-03-25 15:31:26 +09:00
Herman S.
e54a053eca [A64] Fix epilog label memory leak in ARM64 emitter 2026-03-25 15:31:26 +09:00
Wunkolo
dd3ffeb9cb [a64] Implement FEAT_LSE optimizations
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.
2026-03-25 14:31:53 +09:00
Wunkolo
bf83c4e9f5 [a64] Implement OPCODE_CACHE_CONTROL store 2026-03-25 13:32:21 +09:00
Herman S.
680aeaf52b [A64] Fix ARM64 DWARF/SEH unwind info and add registration test 2026-03-25 12:58:44 +09:00
Herman S.
6e557abb0d [A64] Inline all vector C helpers using NEON/GPR and add some tests 2026-03-25 09:48:47 +09:00
Herman S.
ef13662234 [A64] Fix SET_NJM to update cached fpcr_vmx 2026-03-25 09:48:35 +09:00
Herman S.
8911a3b7d8 [a64] Inline UNPACK_FLOAT16_2/4 using NEON fcvtl
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.
2026-03-24 16:17:13 +09:00
Herman S.
2fe20d8d4f [A64] Inline LVL/LVR using NEON TBL instead of C helpers
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.
2026-03-24 16:17:13 +09:00
Herman S.
a1e333223e [A64] Use 16-byte NEON stores in MEMSET fallback loop
Splat the fill byte into v0.16b and use str q0 (16 bytes/iter) for
the bulk, falling back to a byte loop for the 0-15 byte tail.
2026-03-24 16:17:13 +09:00
Herman S.
bdf64db79e [A64] Fix CNTLZ_I8/I16 returning 32 for zero input
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.
2026-03-24 16:17:13 +09:00
Herman S.
02d2cb5cc4 [A64] Add v8-v15 to allocatable VEC pool
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.
2026-03-24 15:12:10 +09:00
Herman S.
756ae7a558 [A64] Dedicate x19 as backend context pointer
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).
2026-03-24 14:23:31 +09:00
Wunkolo
cfc1e4d069 [a64] Optimize EmitD3DCOLOR constants
`3.0` works with `fmov`
2026-03-24 13:54:57 +09:00
Wunkolo
531c49fbdc [a64] Optimize FlushDenormals_V128 constants
`mov`+`dup` can ve `movi`.

`mov`+dup` sequences for constants like `0x00FFFFFF` in particular can just use `mvni`(bit-inverse of `movi`)
2026-03-24 13:54:57 +09:00
Wunkolo
095bbbbda1 [a64] Optimize OPCODE_RECIP constants
Loading the value `1.0` can be done with a singular `fmov` instruction rather than a generic `mov`+`dup` sequence
2026-03-24 13:54:57 +09:00
Wunkolo
39706a0974 [a64] Avoid LoadV128Const scratch-memory usage
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.
2026-03-24 13:46:28 +09:00
Wunkolo
a045586e8e [a64] Use LoadV128Const for OPCODE_SPLAT(constant)
Should allow certain splats to opportunistically emit the best assembly when possible.
Also use `std::bit_cast` rather than an inline `union` type to directly
cast a `float` into a `uint32_t`.
2026-03-24 13:46:28 +09:00
Wunkolo
33aa579b0c [a64] Add opportunistic LoadV128Const splat optimizations
Try to detect opportunities to use the `movi` instructions for generating 128-bit constants rather than writing and loading scratch memory.
2026-03-24 13:46:28 +09:00
Wunkolo
aff3999876 [a64] Fix debug break trap codes
The `BRK` instruction code needs to be specified correctly so that a debugger can handle it properly(and continue from it). `brk 0xF000` implements a debug-breakpoint that can be continued from, and `brk 0xF001` is implemented an assertion failing. Any other codes like `0` and `F1` will not be able to be continued from or handled correctly by debuggers.

These seem to be standard brk codes:
```
Breakpoint    0xF000
Assert        0xF001
Debug Service 0xF002
Fastfail      0xF003
Divide by 0   0xF004
```
2026-03-24 13:25:30 +09:00
Wunk
f2a90ce86d [a64] Optimize mov+dup idioms into movi (#928)
Rather than using a `mov` and vector-`dup` for vector-splats, just use the `movi` instruction where applicable(8-bit element-splats).
Eventually we might want to detect opportunities to use `FMOV` and the 64-bit form of `MOVI` over in `LoadV128Const`.
2026-03-23 16:11:44 +09:00
Herman S.
be64fb1b70 [CPU/A64] Add PPC FP state handling
Track PPC scalar FP state in the backend context and restore it at
host/guest boundaries so translated FP code has a stable rounding mode.

Convert remaining VMX sequences to scoped EmitWithVmxFpcr. Remove
unnecessary ChangeFpcrMode from sequences that only call native helpers.

Co-Authored-By: Reality <reality@xenios.jp>
2026-03-23 12:06:28 +09:00
Herman S.
3747f5e282 [x64] Restore FP rounding mode after host callbacks
Add MXCSR restore to the x64 GuestToHostThunk so host callbacks can't
leak their rounding state into subsequent guest FP operations.
2026-03-23 12:02:30 +09:00
Reality
ecd7501029 [A64] Add MMIO-aware memory sequences 2026-03-23 10:39:50 +09:00
Reality
3906ff11ef [A64/Vector] Scope VMX FPCR in vector helpers
Save and restore FPCR around each VMX FP operation so vector code
doesn't leak FPCR state into scalar paths. Drop the DN bit so NaN
propagation fixup can inspect original payloads.
2026-03-23 10:39:50 +09:00
Reality
5b0b15676c [CPU/A64] Avoid static init order in A64 sequences
The A64 sequence table is populated by registration statics spread across
multiple translation units. Keeping the backing map as a global object makes
registration depend on cross-TU initialization order and can hit the table
before it has been constructed.

Move the sequence table behind a function-local static so sequence
registration is safe regardless of which unit initializes first.
2026-03-23 00:42:59 +09:00
Herman S.
883c2030d0 [ARM64] Initial commit for arm64 backend
Based entirely off existing xbyak x86 implementation and available
tests. Still needs a lot of optimization and testing on non-Windows
platforms.

So far passes all tests and boots at least some games on Windows.
2026-03-22 15:57:37 +09:00
Herman S.
bc37068f90 [x64] Fix AVX-512 VECTOR_DENORMFLUSH merge-masking & FpRangeSign values
Copy src1 into dest before the masked vrangeps so that unmasked lanes
(normal/inf/NaN values) are preserved via merge-masking. Previously,
when the register allocator assigned different physical registers for
dest and src1, unmasked lanes would retain stale values from dest.

Tested with Intel SDE and AVX-512 cpu to verify.

Also shift unused FpRangeSign constants into bits [3:2] of the vrangeps
immediate, matching the Intel encoding. Only one used in the code was 0
so it was already correct by accident but using the others in the future
would produce incorrect results.
2026-03-21 15:16:59 +09:00
Wunkolo
7801d53842 [x64] Add AVX512 optimization for VECTOR_DENORMFLUSH
Use the `vptestnmd`-instruction to quickly test if the exponent bits of
each element is zero and put these results into a mask register. This
mask register can then be used to write `+0.0` or `-0.0` values
depending on the original value's sign-bit.

A masked `vrangeps` instruction is used to move zero-values into the effected
elements while preserving the sign-bit without having to touch memory.
2026-03-20 22:26:17 +01:00
Wunkolo
b1983bab68 [x64] Add GFNI optimization for single-byte vector splats
Use the `vgf2p8affineqb` instruction to splat byte-values across a whole
register without having to touch memory.
2026-03-20 21:34:35 +01:00