Skip to content

Feature flag fixes and alignment between targets - #6094

Merged
lioncash merged 4 commits into
FEX-Emu:mainfrom
Sonicadvance1:302
Nov 3, 2026
Merged

lioncash merged 4 commits into
FEX-Emu:mainfrom
Sonicadvance1:302

Conversation

@Sonicadvance1

Copy link
Copy Markdown
Member

This gets the HostFeaturesHash matching between Linux and arm64ec.

wow64 is the odd one out as it doesn't support AVX, it's the only flag that differs. We need to get wow64 AVX support wired up.

This check was inverted. We were accidentally disabling cache operations
on Wine, but enabling on Windows when it should be the opposite.
Accidentally changed the host type from arm64ec to wow64 which disabled
AVX.
llvm has supported preserve_all abi on Windows ABI since
llvm/llvm-project#166436.
This has been in a clang release since 22.1. Do a clang version check to
ensure the compiler is >= 22.1 to enabled preserve_all under
wow64/arm64ec.

This will give a performance boost to applications that require x87 full
precision and a couple other minor things.
There's enough of them now that it's kind of annoying to track by
counting.
@Sonicadvance1

Copy link
Copy Markdown
Member Author

A note, on SVE supporting targets the flags will still differ between Linux and wine because SVE is currently hard disabled on Wine due to the inability to save predicates.

@lioncash
lioncash merged commit effbda6 into FEX-Emu:main Nov 3, 2026
13 checks passed
@Sonicadvance1
Sonicadvance1 deleted the 302 branch November 3, 2026 18:30
@mstorsjo

mstorsjo commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

The commit for enabling preserve_all on Windows targets, since llvm/llvm-project#166436, doesn't work fully unfortunately.

While that PR did make it possible to use preserve_all and preserve_most on Windows targets in general, it doesn't seem to work properly if unwind info generation is enabled (as it is by default for such targets). The code generation ends up backing up x9 on the stack, and tries to represent this in unwind info, where it is unrepresentable (only registers >= x19 can be handled there).

The problematic thing is that this only shows up if using a Clang built with asserts enabled. With Clang without asserts, it silently builds an object file, where the unwind info is bogus compared with the function.

Building fails on FEXCore/Source/Interface/Core/Interpreter/Fallbacks/StringCompareFallbacks.cpp, External/SoftFloat-3e/src/s_normRoundPackToExtF80.c and FEXCore/Source/Interface/Core/Interpreter/Fallbacks/InterpreterFallbacks.cpp, with assert failures like this:

clang: ../lib/MC/MCWin64EH.cpp:1429: void ARM64EmitUnwindCode(llvm::MCStreamer&, const llvm::WinEH::Instruction&): Assertion `inst.Register >= 19 && "Saved registers must be >= 19"' failed.

The issue is reproducible with a small reduced test case like this:

long a, b;
int c, e;
char d;
__attribute__((preserve_all)) void f();
__attribute__((preserve_all)) void g() {
  d = a;
  c -= d;
  long h, i = b >> -d;
  h = b << d;
  f(e, 0, i, h, 0);
}
$ clang -target aarch64-windows-msvc -O2 repro.c -c
clang: ../lib/MC/MCWin64EH.cpp:1413: void ARM64EmitUnwindCode(llvm::MCStreamer&, const llvm::WinEH::Instruction&): Assertion `inst.Register >= 19 && "Saved reg must be >= 19"' failed.

The same happens for both aarch64-windows-msvc and aarch64-windows-gnu (aka aarch64-w64-mingw32) targets, and happens the same for both preserve_all and preserve_most. Building these source files with -fno-asynchronous-unwind-tables does avoid hitting the assert though.

If building with a version of Clang without asserts, building succeeds, but the unwind info doesn't match the actual code:

$ llvm-objdump -d repro.o 

repro.o:        file format coff-arm64

Disassembly of section .text:

0000000000000000 <g>:
       0: f81f0fe9      str     x9, [sp, #-0x10]!
       4: 90000008      adrp    x8, 0x0 <g>
       8: 90000011      adrp    x17, 0x0 <g>
       c: 90000006      adrp    x6, 0x0 <g>
      10: b9400108      ldr     w8, [x8]
[...]
$ llvm-readobj --unwind repro.o 

File: repro.o
Format: COFF-ARM64
Arch: aarch64
AddressSize: 64bit
UnwindInformation [
  RuntimeFunction {
    Function: g (0x0)
    ExceptionRecord: .xdata (0x0)
    ExceptionData {
      FunctionLength: 84
      Version: 0
      ExceptionData: No
      EpiloguePacked: Yes
      EpilogueOffset: 0
      ByteCodeLength: 4
      Prologue [
        0xd4c1              ; str x25, [sp, #-16]!
        0xe4                ; end
      ]
    }
  }
]

I posted a note about this at llvm/llvm-project#166436 (comment), but perhaps it would warrant a new issue in llvm of its own.

Sonicadvance1 added a commit to Sonicadvance1/FEX that referenced this pull request Nov 4, 2026
From the comment
[here](FEX-Emu#6094 (comment))
apparently there is a bug where async unwind tables and preserve_all
conflicts under mingw. So...just disable it. Easy.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants