[llvm] [arm64ec] Fix missing sret return in Arm64EC entry thunks for large struct returns (PR #185452)

via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 9 09:31:00 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-platform-windows

Author: Daniel Paoliello (dpaoliello)

<details>
<summary>Changes</summary>

When an Arm64EC function returns a struct by value that is too large for x64's `RAX` (>8 bytes), the entry thunk synthesizes a hidden sret pointer parameter for the x64 side. However, this
parameter was never marked with the sret attribute, so ISel did not copy its value into `x8` (the Arm64EC mapping of `RAX`) on return. This caused the x64 caller to see a garbage pointer in `RAX` instead of the return buffer address.

The change adds the sret attribute to the thunk's synthesized pointer parameter, so that `LowerFormalArguments` saves it and `LowerReturn` restores it to `x8` before the tail call to `__os_arm64x_dispatch_ret`.

Fixes #<!-- -->185390

---
Full diff: https://github.com/llvm/llvm-project/pull/185452.diff


2 Files Affected:

- (modified) llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp (+5) 
- (modified) llvm/test/CodeGen/AArch64/arm64ec-entry-thunks.ll (+2) 


``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp b/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
index c27a693ceecc1..866e2f9c4218c 100644
--- a/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
@@ -593,6 +593,11 @@ Function *AArch64Arm64ECCallLowering::buildEntryThunk(Function *F) {
 
   Value *RetVal = Call;
   if (TransformDirectToSRet) {
+    // The x64 side returns this value indirectly via a hidden pointer (sret).
+    // Mark the thunk's pointer arg with sret so that ISel saves it and copies
+    // it into x8 (RAX) on return, matching the x64 calling convention.
+    Thunk->addParamAttr(
+        1, Attribute::getWithStructRetType(M->getContext(), RetTy));
     IRB.CreateStore(RetVal, Thunk->getArg(1));
   } else if (X64RetType != RetTy) {
     Value *CastAlloca = IRB.CreateAlloca(X64RetType);
diff --git a/llvm/test/CodeGen/AArch64/arm64ec-entry-thunks.ll b/llvm/test/CodeGen/AArch64/arm64ec-entry-thunks.ll
index 2c1b735ffe28c..09fe884940c6a 100644
--- a/llvm/test/CodeGen/AArch64/arm64ec-entry-thunks.ll
+++ b/llvm/test/CodeGen/AArch64/arm64ec-entry-thunks.ll
@@ -359,6 +359,7 @@ define [3 x i64] @large_array([3 x i64] %0, [2 x double], [2 x [2 x i64]]) nounw
 ; CHECK-NEXT:     adrp    x8, __os_arm64x_dispatch_ret
 ; CHECK-NEXT:     str     x2, [x19, #16]
 ; CHECK-NEXT:     ldr     x0, [x8, :lo12:__os_arm64x_dispatch_ret]
+; CHECK-NEXT:     mov     x8, x19
 ; CHECK-NEXT:     .seh_startepilogue
 ; CHECK-NEXT:     ldp     x29, x30, [sp, #168]            // 16-byte Folded Reload
 ; CHECK-NEXT:     .seh_save_fplr  168
@@ -568,6 +569,7 @@ define <8 x i16> @large_vector(<8 x i16> %0) {
 ; CHECK-NEXT:     adrp	x8, __os_arm64x_dispatch_ret
 ; CHECK-NEXT:     str	q0, [x19]
 ; CHECK-NEXT:     ldr	x0, [x8, :lo12:__os_arm64x_dispatch_ret]
+; CHECK-NEXT:     mov	x8, x19
 ; CHECK-NEXT:     .seh_startepilogue
 ; CHECK-NEXT:     ldp	x29, x30, [sp, #168]            // 16-byte Folded Reload
 ; CHECK-NEXT:     .seh_save_fplr	168

``````````

</details>


https://github.com/llvm/llvm-project/pull/185452


More information about the llvm-commits mailing list