github FEX-Emu/FEX FEX-2611
FEX Release FEX-2611

4 hours ago

Read the blog post at FEX-Emu's Site!

You know the drill, it's been around a month so that means we have a new release landing. A smattering of changes all over the codebase this time.
Let's see what's interesting!

CPU core index through TPIDRRO_EL0

This is a fun feature that has come about primarily because Windows on ARM mandates this feature. The TPIDRRO_EL0 register
is an ARM system register that is readable by userspace that the kernel can set to whatever 64-bit value it wants. In particular under Windows it is
part of their ABI that this register must
contain the current CPU core index once read. This gives ARM64/ARM64ec applications a really quick way to read what core it is executing on. This is
kind of a funny thing that needs to exist because technically the MPIDR_EL1 register is supposed to accomplish the same task. Although this
register is kernel-mode only, through their CPU feature register emulation
you can read this register on Linux with a bit of overhead. The problem with this register is that many vendors messed it up, and also it's not just
an index from zero to the number of cores in the system. So in the end the kernel actually only ever returns zero. On Linux, FEX will use the
getcpu syscall instead to get the CPU core index.

So what are we to do? ARM64 WINE applications need this register to be ABI compliant and FEX would like to use it for faster emulation of
RDPID/RDTSCP/CPUID. What does Linux do for this register? Turns out in the 15 years since ARM64 was introduced, the Linux kernel has hardcoded this
register to always be zero and be reserved for future work. Simple enough then would be to send a patch
upstream
to set the register to the core index just like Windows.

While that's working through the system, we have a downstream patch (That we failed to push before this release, sorry!) that adds a PRCTL so FEX can
query if the kernel supports the register to contain the CPU index or not. Once your kernel lands this patch then ARM64 Windows games will get
correct results and FEX will automatically pick it up.

In particular this register is required for when FEX is running under WINE because we can't use Linux syscalls properly there so we couldn't safely or
easily emulate RDPID/RDTSC, so we just disabled those instructions. Problem is that games are starting to mandate these instructions so we were stuck
in a bit of a hard spot. This ends up being a combination of correctness and performance improvements! Win-win!

All the JIT things

This month we have a bunch of JIT fixes, features, and optimizations. Let's try and walk through some of these.

Enable preserve_all on mingw

This will give a decent performance improvement for anything using x87 under full 80-bit precision

SHA256 peephole optimization

ARM64 and x86 SHA256 instructions don't quite behave the same. x86 operates on two rounds where ARM operates on four rounds.
Which is an easy way to think about how typically we throw away half the data on the instruction. We now do a peephole optimization for common SHA256
code patterns so we can stop throwing away half the computation. This gives around a 1.9x perf improvement for heavy SHA code which some games use
heavily.

Inline 128-bit division

Previously FEX would jump out to a C handler for 128-bit division when it was detected as mandatory. This is required because ARM doesn't have an
equivalent divide and can only go up to 64-bit. We now inline the code generation when a 128-bit divide is necessary, resulting in around a 5x
performance uplift. Luckily these are fairly uncommon so most games aren't affected by this slow path.

Wire up SERIALIZE and AVX-NE-Convert

Following last month's VNNI implementation, we are spending a bit more time implementing some new extension. The serialize instruction is fairly
trivial since it's x86's new instruction and memory barrier instruction. Before this games actually needed to abuse the cpuid instruction of all
things because it was the only guaranteed instruction serialization instruction.

AVX-NE-Convert is a funny little extension that basically maps directly for ARM64 instructions for converting FP16 and BF16 floats to FP32 and back.
It was simple to implement and complements the remaining new AVX-VNNI instructions.

While not landing this month, we're also planning on the AVX-VNNI-Int8/16 and SHA512 extensions in the coming months. So look forward to that.

Wire up support for X87 FIP

X87 is kind of a funny little thing, there's always new bits of information to learn about it. Most people know that x87 is a monster 80-bit float
stack machine. But did you know that for most every x87 ALU operation, the co-processor actually records every RIP where that code executed and
also which RIP has accessed memory? Turns out some versions of SecuROM actually check to ensure that the
Floating point RIP is being set correctly for some form of anti-tamper. Once we wired up support for this, it fixed a little known game
Split/Second. Requires the setting the environment variable
FEX_JITFEATURES=enablex87fip

Partial debug register support

Under Windows, applications are allowed to touch the x86 debug registers fairly easily. On Linux this is protected by everything going through the
ptrace interface. WINE implements these debug registers by having the wineserver ptrace the process to be able to pass these through on a real x86
environment. Under FEX we don't have that luxury because we need to translate what these registers represent.

So today FEX emulates the debug registers on wow64 under WINE only. Also we only support instruction breakpoints today, no data breakpoints. This
requires some JIT interaction to punch this through wine which is why it is tricky. For ARM64EC this is also quirky because we need some form of WINE
implementation coordination because the boundary between Arm64 and x86-64 code is a lot closer. We'll get there eventually because games need this to
work.

As for the Linux side...We need to implement ptrace first which is its own nightmare.

Smattering of changes

Let's just slam through a bunch of the other random JIT changes

  • Fix 0x82 instruction aliases.
    • Apparenty Crysis 2 abuses this.
  • Fix performance regression on syscall instruction
  • Support partial instruction faulting information
    • Used by anti-tampers
  • Fix 0xBX instructions with prefixes
  • Fix XSETBV, SWAGGS, SLDT
  • Fix DCE accidentally removing memory accesses
    • Affected Java Hotspot JIT.
  • Have arm64ec skip double-faulting when not required
    • Makes Arxan protected games run slightly faster

Raw Changes

FEX Release FEX-2611

  • ALUOps

    • Inline 128 bit division (24987be)
  • ARM64EC

    • Fix the NtDllRedirectionLUT bounds check in CheckCall (94ff2b0)
  • Allocator

    • Commit rpmalloc memory on demand due to RLIMIT_DATA (5285020)
  • CMake

    • Disable async unwind tables on mingw+preserve_all (d6ec067)
    • too-long-line fixes, options reorg, and some cleanups (1e4dab5)
    • Don't install ThunksDB for mingw (2b4145a)
  • CPUID

    • Add new Apple Silicon names (805f44b)
  • Config

    • Fixes typo in man page. NFC (24da3ae)
  • Crypto

  • Decoder

    • Fix alias issue with 0x82 opcode (89713ba)
  • Dependabot

  • DiskCache

    • Fixes a race condition on the data blob (eef303f)
  • Dispatcher

    • Optimize syscall return with L1 lookup (9eb5d92)
  • Externals

  • FEXCore

    • Support partial instruction fault decoding (1e463b0)
    • Fixes two-byte instruction decode of 0xBX operations (8a3764e)
    • Wire up support for SERIALIZE (d7b8e14)
  • FEXMingwTests

    • Adds the ability to run the mingw tests (75df0f8)
  • FEXServerManager

    • Stop leaving stale FEXServer sockets around (eff9f45)
  • HostFeatures

    • Make a stronger distinction between CPU features and Process features (4e2b509)
    • clang-format (eeb9902)
  • InstcountCI

    • Disable tpidrro in rdpid/rdtsc files. (b1f27cf)
  • JIT

    • Rename CompileCode to EmitJITCode (abc9334)
  • Linux

    • Track main stack usage more accurately in VmData (dab12ae)

    • Return EFAULT for stat() of a null path (e3c1c1e)

    • SignalDelegator

  • OpcodeDispatcher

    • Make sure xsetbv works correctly (a8c9016)
    • Fixes swapgs on 32-bit (5c81797)
    • Add undefined flags acid test (fd8a601)
  • Tests

    • Reduce wall clock time spent in "ninja tests" (e9c1034)
  • Thunks

  • Tools

    • Fixes a couple throws that leaked (a81762c)
  • Misc

    • Feature flag fixes and alignment between targets (effbda6)
    • Implement _wsetlocale and _wcsdup for libc++ 24 (fb68b0e)
    • fix(CMakeLists): Fix build flags when LIBCXX is enabled (4a4669a)
    • Debug register instruction breakpoint support (2b10820)
    • Wire up support for using TPIDRRO as CPU core index on Linux (eae8d21)
    • Ir keep unused guest loads (fixes Necesse) (46acbde)
    • Implement support for x87 FIP (1c4f04b)
    • Add the various new extensions that we may care about to the the various tool (2e537bd)
    • Another missed clang-format (3da673e)
    • Emulate SLDT (e3e8304)
    • code-format-helper: More dependabot things (80e28a1)
    • Implement support for AVX_NE_Convert (3b7daa5)
    • Add another function stub for libc++ 24 on Windows (a36ca80)
  • arm64ec

    • Have synchronous faults skip fault overhead (741e146)
  • unittests

    • Adds new Mingw tests that are only build-tested (7816573)

    • Also fix LLVM 23 (7780a43)

    • ASM

      • Fixes results in new tests (02e24ca)
      • New RNG tests for all the new instructions (d321f49)
      • Fixes AVX-NE-convert tests (fb48e2d)
      • Test SAR sign extension for 8 and 16 bit (d1d772c)
    • FEXMingwTests

      • Adds breakpoint unittest (a6ba3e2)
  • x87

Don't miss a new FEX release

NewReleases is sending notifications on new releases.