From db4867839c8ec7e7092db54de4a7b7843632b85b Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 3 Apr 2026 20:07:37 -0700 Subject: [PATCH] Arm64EC: Invert suspend doorbell and move out of hot path This was causing a surprisingly high amount of branch mispredicts in Death Stranding. Suspend doorbell is fairly rare so just invert the check and move the target down out of the hot path. Then the doorbell handling code will trampoline to the correct location still. --- Source/Windows/ARM64EC/Module.S | 15 +++++++++------ Source/Windows/ARM64EC/Module.cpp | 3 ++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Source/Windows/ARM64EC/Module.S b/Source/Windows/ARM64EC/Module.S index e182db3de..365931332 100644 --- a/Source/Windows/ARM64EC/Module.S +++ b/Source/Windows/ARM64EC/Module.S @@ -64,12 +64,10 @@ ExitFunctionEC: strb wzr, [x17, #0x0] // ChpeV2CpuAreaInfo->InSimulation ldr x17, [x17, #0x20] // ChpeV2CpuAreaInfo->SuspendDoorbell ldr w17, [x17] - cbz w17, no_suspend -.global ExitFunctionSuspendPoint -ExitFunctionSuspendPoint: - brk #0xCAFE - // Will resume here -no_suspend: + cbnz w17, ExitFunctionSuspendPoint + +.global ExitFunctionSuspendResumePoint +ExitFunctionSuspendResumePoint: // Either return to an exit thunk (return to ARM64EC function) or call an entry thunk (call to ARM64EC function). // It is assumed that a 'blr x16' instruction is only ever used to call into x86 code from an exit thunk, and that all // exported ARM64EC functions have a 4-byte offset to their entry thunk immediately before their first instruction. @@ -99,6 +97,11 @@ ret_sp_misaligned: ldr lr, [lr, #:lo12:X64ReturnInstr] br x17 +.global ExitFunctionSuspendPoint +ExitFunctionSuspendPoint: + brk #0xCAFE + // Resume will jump back to `ExitFunctionSuspendResumePoint` + // Makes a wrapper for calling a system call directly, skipping the usual ntdll thunks #define HASH # #define DIRECT_SYSCALL_WRAPPER(Name, WineIdName, WindowsId) \ diff --git a/Source/Windows/ARM64EC/Module.cpp b/Source/Windows/ARM64EC/Module.cpp index 28c25cfc7..8df18573c 100644 --- a/Source/Windows/ARM64EC/Module.cpp +++ b/Source/Windows/ARM64EC/Module.cpp @@ -69,6 +69,7 @@ extern IMAGE_DOS_HEADER __ImageBase; // Provided by the linker extern void* ExitFunctionEC; extern void* CheckCall; extern void* ExitFunctionSuspendPoint; +extern void* ExitFunctionSuspendResumePoint; void* X64ReturnInstr; // See Module.S uintptr_t NtDllBase; @@ -676,7 +677,7 @@ bool ResetToConsistentStateImpl(const ThreadCPUArea CPUArea, EXCEPTION_RECORD* E // A suspend interrupt can occur in ExitFunctionEC before InSimulation is unset and set SuspendDoorbell. If this // occurs then it is still our duty to cooperatively suspend with an appropriate context. To support this, after // unsetting InSimulation a brk #0xCAFE instruction will be raised that we can handle here. - NativeContext->Pc += 4; // Skip over the brk instruction when we resume + NativeContext->Pc = reinterpret_cast(ExitFunctionSuspendResumePoint); // Jump to the suspend resume point. *CPUArea.Area->SuspendDoorbell = 0; return true; }