Merge pull request #5800 from Sonicadvance1/195

#5795 but with clang_format
This commit is contained in:
Ryan Houdek authored and GitHub committed 2026-08-03 15:30:14 -07:00
commit 4caad9bf55
5 files changed
+126 -9

No files matched your search

@@ -525,16 +525,18 @@ int main(int argc, char** argv, char** const envp) {
FEXCore::Profiler::Init(Program.ProgramName, Program.ProgramPath);
bool SupportsAVX {};
bool SupportsSVE256 {};
fextl::unique_ptr<FEXCore::Context::Context> CTX;
{
auto HostFeatures = FEX::FetchHostFeatures();
CTX = FEXCore::Context::Context::CreateNewContext(HostFeatures);
SupportsAVX = HostFeatures.SupportsAVX;
SupportsSVE256 = HostFeatures.SupportsSVE256;
}
FEX::Kernel::Init(Loader.Is64BitMode(), CTX.get());
auto SignalDelegation = FEX::HLE::CreateSignalDelegator(CTX.get(), Program.ProgramName, SupportsAVX);
auto SignalDelegation = FEX::HLE::CreateSignalDelegator(CTX.get(), Program.ProgramName, SupportsAVX, SupportsSVE256);
auto ThunkHandler = FEX::HLE::CreateThunkHandler();
auto SyscallHandler = Loader.Is64BitMode() ?
@@ -116,7 +116,7 @@ void SignalDelegator::SpillSRA(FEXCore::Core::InternalThreadState* Thread, void*
Thread->CurrentFrame->State.gregs[i] = ArchHelpers::Context::GetArmReg(ucontext, SRAIdxMap);
}
if (SupportsAVX) {
if (SupportsAVX && SupportsSVE256) {
// TODO: This doesn't save the upper 128-bits of the 256-bit registers.
// This needs to be implemented still.
for (size_t i = 0; i < Config.SRAFPRCount; i++) {
@@ -872,10 +872,11 @@ void SignalDelegator::QueueSignal(pid_t tgid, pid_t tid, int Signal, siginfo_t*
}
}
SignalDelegator::SignalDelegator(FEXCore::Context::Context* _CTX, const std::string_view ApplicationName, bool SupportsAVX)
SignalDelegator::SignalDelegator(FEXCore::Context::Context* _CTX, const std::string_view ApplicationName, bool SupportsAVX, bool SupportsSVE256)
: CTX {_CTX}
, ApplicationName {ApplicationName}
, SupportsAVX {SupportsAVX} {
, SupportsAVX {SupportsAVX}
, SupportsSVE256 {SupportsSVE256} {
// Signal zero isn't real
HostHandlers[0].Installed = true;
@@ -1345,7 +1346,7 @@ uint64_t SignalDelegator::GuestSignalFD(int fd, const uint64_t* set, size_t sigs
}
fextl::unique_ptr<FEX::HLE::SignalDelegator>
CreateSignalDelegator(FEXCore::Context::Context* CTX, const std::string_view ApplicationName, bool SupportsAVX) {
return fextl::make_unique<FEX::HLE::SignalDelegator>(CTX, ApplicationName, SupportsAVX);
CreateSignalDelegator(FEXCore::Context::Context* CTX, const std::string_view ApplicationName, bool SupportsAVX, bool SupportsSVE256) {
return fextl::make_unique<FEX::HLE::SignalDelegator>(CTX, ApplicationName, SupportsAVX, SupportsSVE256);
}
} // namespace FEX::HLE
@@ -54,7 +54,7 @@ public:
// Returns true if the host handled the signal
// Arguments are the same as sigaction handler
SignalDelegator(FEXCore::Context::Context* _CTX, const std::string_view ApplicationName, bool SupportsAVX);
SignalDelegator(FEXCore::Context::Context* _CTX, const std::string_view ApplicationName, bool SupportsAVX, bool SupportsSVE256);
~SignalDelegator() override;
// Called from the signal trampoline function.
@@ -196,6 +196,7 @@ private:
std::mutex HostDelegatorMutex;
std::mutex GuestDelegatorMutex;
bool SupportsAVX;
bool SupportsSVE256;
// Called from the thunk handler to handle the signal
void HandleGuestSignal(FEX::HLE::ThreadStateObject* ThreadObject, int Signal, void* Info, void* UContext);
@@ -294,5 +295,5 @@ private:
};
fextl::unique_ptr<FEX::HLE::SignalDelegator>
CreateSignalDelegator(FEXCore::Context::Context* CTX, const std::string_view ApplicationName, bool SupportsAVX);
CreateSignalDelegator(FEXCore::Context::Context* CTX, const std::string_view ApplicationName, bool SupportsAVX, bool SupportsSVE256);
} // namespace FEX::HLE
@@ -249,7 +249,7 @@ int main(int argc, char** argv, char** const envp) {
auto CTX = FEXCore::Context::Context::CreateNewContext(HostFeatures);
#ifndef _WIN32
auto SignalDelegation = FEX::HLE::CreateSignalDelegator(CTX.get(), {}, HostFeatures.SupportsAVX);
auto SignalDelegation = FEX::HLE::CreateSignalDelegator(CTX.get(), {}, HostFeatures.SupportsAVX, HostFeatures.SupportsSVE256);
#else
// Enable exit on HLT while Wine's longjump is broken.
//
@@ -0,0 +1,113 @@
#include <catch2/catch_test_macros.hpp>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#pragma GCC diagnostic ignored "-Wattributes"
constexpr static uint32_t xmm_values[8][4] = {
{0x00000001, 0x00000002, 0x00000003, 0x00000004}, {0x00000011, 0x00000012, 0x00000013, 0x00000014},
{0x00000021, 0x00000022, 0x00000023, 0x00000024}, {0x00000031, 0x00000032, 0x00000033, 0x00000034},
{0x00000041, 0x00000042, 0x00000043, 0x00000044}, {0x00000051, 0x00000052, 0x00000053, 0x00000054},
{0x00000061, 0x00000062, 0x00000063, 0x00000064}, {0x00000071, 0x00000072, 0x00000073, 0x00000074},
};
// 4 GPR slots (2 used + 2 pad for 16-byte alignment) + 32 XMM slots
static uint32_t results[4 + 32] __attribute__((aligned(16)));
static volatile int alarm_fired = 0;
extern "C" void ContinueAfterSignal();
static void SignalHandler(int signal, siginfo_t* siginfo, void* context) {
ucontext_t* _context = (ucontext_t*)context;
alarm_fired = 1;
#ifdef REG_RIP
#define FEX_IP_REG REG_RIP
#else
#define FEX_IP_REG REG_EIP
#endif
_context->uc_mcontext.gregs[FEX_IP_REG] = reinterpret_cast<greg_t>(ContinueAfterSignal);
#undef FEX_IP_REG
}
// Load GPRs (ECX, EDX) and XMM0-XMM7 with known values, keep them
// live in SRA with a reload loop. SIGALRM fires asynchronously, the
// handler modifies EIP, forcing FEX to spill and reload all register
// state via SpillSRA. After returning, store all registers for comparison.
__attribute__((nocf_check)) static void LoadRegsLoopAndStore() {
__asm volatile(R"(
movaps xmm0, [%[v]]
movaps xmm1, [%[v]+16]
movaps xmm2, [%[v]+32]
movaps xmm3, [%[v]+48]
movaps xmm4, [%[v]+64]
movaps xmm5, [%[v]+80]
movaps xmm6, [%[v]+96]
movaps xmm7, [%[v]+112]
.Lloop:
mov ecx, 0x89ABCDEF
mov edx, 0xFEDCBA98
movaps xmm0, [%[v]]
movaps xmm1, [%[v]+16]
movaps xmm2, [%[v]+32]
movaps xmm3, [%[v]+48]
movaps xmm4, [%[v]+64]
movaps xmm5, [%[v]+80]
movaps xmm6, [%[v]+96]
movaps xmm7, [%[v]+112]
mov eax, %[alarm]
test eax, eax
jz .Lloop
.global ContinueAfterSignal
ContinueAfterSignal:
mov [%[res]], ecx
mov [%[res]+4], edx
movaps [%[res]+16], xmm0
movaps [%[res]+32], xmm1
movaps [%[res]+48], xmm2
movaps [%[res]+64], xmm3
movaps [%[res]+80], xmm4
movaps [%[res]+96], xmm5
movaps [%[res]+112], xmm6
movaps [%[res]+128], xmm7
)" ::[v] "r"(xmm_values),
[alarm] "m"(alarm_fired), [res] "r"(results)
: "memory", "cc", "eax", "ecx", "edx");
}
TEST_CASE("Signals: Register state preserved across async signal with SRA") {
struct sigaction act {};
act.sa_sigaction = SignalHandler;
act.sa_flags = SA_SIGINFO;
sigaction(SIGALRM, &act, nullptr);
alarm_fired = 0;
memset(results, 0, sizeof(results));
alarm(1);
LoadRegsLoopAndStore();
REQUIRE(alarm_fired == 1);
CHECK(results[0] == 0x89ABCDEF);
CHECK(results[1] == 0xFEDCBA98);
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 4; j++) {
uint32_t val = results[4 + i * 4 + j];
if (val != xmm_values[i][j]) {
printf("XMM%d[%d] = 0x%08x, expected 0x%08x\n", i, j, val, xmm_values[i][j]);
}
CHECK(val == xmm_values[i][j]);
}
}
}