[llvm] 16bd5ce - Reland [AArch64] Copy x4/x5 vararg payload into the x64 stack in Arm64EC exit thunks (#208453)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 13 05:34:40 PDT 2026


Author: Alex Bradbury
Date: 2026-07-13T12:34:35Z
New Revision: 16bd5ce1184bb5683ea96290478e5912cf2975b9

URL: https://github.com/llvm/llvm-project/commit/16bd5ce1184bb5683ea96290478e5912cf2975b9
DIFF: https://github.com/llvm/llvm-project/commit/16bd5ce1184bb5683ea96290478e5912cf2975b9.diff

LOG: Reland [AArch64] Copy x4/x5 vararg payload into the x64 stack in Arm64EC exit thunks (#208453)

Reland llvm/llvm-project#190933, which was reverted by
llvm/llvm-project#198540 due to an EXPENSIVE_CHECKS build failure.

The fix relative to the reverted patch is to do the memcpy before the
final CALLSEQ_START for the dispatch call, avoiding nested call-frame
pseudos if memcpy lowers to a call.

Original commit message:
Currently the x4/x5 in a variadic Arm64EC exit thunks are treated by
LLVM like any other outgoing arguments. x4/x5 contain a pointer to the
first stack parameter and the size of the parameters passed on the
stack, and the generated exit thunk must memcpy these to the x86-64
stack. Current MSVC does this correctly.

Rather than introducing a new entry to the CallingConv enum, we mark the
call as vararg in AArch64ArmECCallLowering so that the lowering logic in
AArch64ISelLowering.cpp can recognise this case, perform the necessary
memcpy, and drop the x4/x5 arguments.

LLVM should additionally ensure that x0-x3 are mirrored to f0-f3 in
order to match the Windows x86-64 vararg ABI, but that change is left
for a follow-up patch.

Added: 
    

Modified: 
    llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
    llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
    llvm/test/CodeGen/AArch64/arm64ec-exit-thunks.ll
    llvm/test/CodeGen/AArch64/arm64ec-hybrid-patchable.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp b/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
index fb21d1fd3f7bd..c8db242f5530c 100644
--- a/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
@@ -459,6 +459,14 @@ Function *AArch64Arm64ECCallLowering::buildExitThunk(FunctionType *FT,
   Value *Callee = IRB.CreateLoad(PtrTy, CalleePtr);
   auto &DL = M->getDataLayout();
   SmallVector<Value *> Args;
+  FunctionType *DispatcherCallTy = X64Ty;
+  // If we have a vararg function, the SelectionDAG lowering will need to
+  // recognize this so it can copy the arguments described by x4 (pointer) and
+  // x5 (length) to set up the x86-64 context correctly.
+  if (FT->isVarArg())
+    DispatcherCallTy =
+        FunctionType::get(X64Ty->getReturnType(), X64Ty->params(),
+                          /*isVarArg=*/true);
 
   // Pass the called function in x9.
   auto X64TyOffset = 1;
@@ -510,7 +518,7 @@ Function *AArch64Arm64ECCallLowering::buildExitThunk(FunctionType *FT,
   }
   // FIXME: Transfer necessary attributes? sret? anything else?
 
-  CallInst *Call = IRB.CreateCall(X64Ty, Callee, Args);
+  CallInst *Call = IRB.CreateCall(DispatcherCallTy, Callee, Args);
   Call->setCallingConv(CallingConv::ARM64EC_Thunk_X64);
 
   Value *RetVal = Call;

diff  --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 4192184480e82..fd71b3a2d10d0 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -9716,6 +9716,20 @@ static void analyzeCallOperands(const AArch64TargetLowering &TLI,
     CCInfo.AllocateStack(32, Align(16));
 
   unsigned NumArgs = Outs.size();
+
+  // IsVarArg is only set on an ARM64EC_Thunk_X64 for exit thunks, so if set
+  // we know we have a vararg exit thunk where x4 and x5 must be consumed in
+  // this lowering (copying the data to the stack).
+  bool IsArm64ECVarArgExitThunk = CalleeCC == CallingConv::ARM64EC_Thunk_X64 &&
+                                  IsVarArg &&
+                                  !(CLI.CB && CLI.CB->isMustTailCall());
+  if (IsArm64ECVarArgExitThunk) {
+    if (NumArgs < 2)
+      report_fatal_error("variadic arm64ec_thunk_x64 call is missing the "
+                         "x4/x5 (pointer/length) arguments");
+    NumArgs -= 2;
+  }
+
   for (unsigned i = 0; i != NumArgs; ++i) {
     MVT ArgVT = Outs[i].VT;
     ISD::ArgFlagsTy ArgFlags = Outs[i].Flags;
@@ -10305,6 +10319,50 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
     });
   }
 
+  auto PtrVT = getPointerTy(DAG.getDataLayout());
+  MachineFrameInfo &MFI = MF.getFrameInfo();
+  // If we have a variadic Arm64EC exit thunk, we must lower the x4/x5
+  // parameters (address and length of additional arguments) into an outgoing
+  // stack area.
+  bool IsArm64ECVarArgExitThunk = CallConv == CallingConv::ARM64EC_Thunk_X64 &&
+                                  IsVarArg &&
+                                  !(CLI.CB && CLI.CB->isMustTailCall());
+  if (IsArm64ECVarArgExitThunk) {
+    // Materialize an aligned outgoing stack area now
+    // so the args described by x4 (pointer) and x5 (length) can be copied
+    // into a real x64-style stack layout.
+    if (Outs.size() < 2)
+      report_fatal_error("variadic arm64ec_thunk_x64 call is missing the "
+                         "x4/x5 (pointer/length) arguments");
+    if (IsTailCall)
+      report_fatal_error("tail calls are not supported for variadic "
+                         "arm64ec_thunk_x64 calls");
+
+    SDValue ThunkVarArgSrc = OutVals[Outs.size() - 2];
+    SDValue ThunkVarArgSize =
+        DAG.getZExtOrTrunc(OutVals[Outs.size() - 1], DL, PtrVT);
+    SDValue RoundedThunkVarArgSize = DAG.getNode(
+        ISD::ADD, DL, PtrVT, ThunkVarArgSize, DAG.getConstant(15, DL, PtrVT));
+    RoundedThunkVarArgSize =
+        DAG.getNode(ISD::AND, DL, PtrVT, RoundedThunkVarArgSize,
+                    DAG.getSignedConstant(-16, DL, PtrVT));
+    SDValue ThunkVarArgDst = DAG.getNode(
+        ISD::DYNAMIC_STACKALLOC, DL, DAG.getVTList(PtrVT, MVT::Other),
+        {Chain, RoundedThunkVarArgSize, DAG.getConstant(0, DL, PtrVT)});
+    Chain = ThunkVarArgDst.getValue(1);
+    MFI.CreateVariableSizedObject(Align(16), nullptr);
+
+    // The x64 shadow store for the final thunk call is allocated by the normal
+    // CALLSEQ_START below. Copy the variadic stack arguments before that call
+    // sequence starts so lowering the memcpy libcall cannot create nested
+    // ADJCALLSTACKDOWN/ADJCALLSTACKUP pairs.
+    Chain = DAG.getMemcpy(
+        Chain, DL, ThunkVarArgDst, ThunkVarArgSrc, ThunkVarArgSize, Align(16),
+        Align(1), /*isVol=*/false, /*AlwaysInline=*/false,
+        /*CI=*/nullptr, std::nullopt, MachinePointerInfo::getUnknownStack(MF),
+        MachinePointerInfo());
+  }
+
   // Adjust the stack pointer for the new arguments... and mark ZA uses.
   // These operations are automatically eliminated by the prolog/epilog pass
   assert((!IsSibCall || !ZAMarkerNode) && "ZA markers require CALLSEQ_START");
@@ -10327,7 +10385,6 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
   SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass;
   SmallSet<unsigned, 8> RegsUsed;
   SmallVector<SDValue, 8> MemOpChains;
-  auto PtrVT = getPointerTy(DAG.getDataLayout());
 
   if (IsVarArg && CLI.CB && CLI.CB->isMustTailCall()) {
     const auto &Forwards = FuncInfo->getForwardedMustTailRegParms();
@@ -10339,7 +10396,8 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
 
   // Walk the register/memloc assignments, inserting copies/loads.
   unsigned ExtraArgLocs = 0;
-  for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
+  unsigned NumThunkVarArgOperands = IsArm64ECVarArgExitThunk ? 2 : 0;
+  for (unsigned i = 0, e = Outs.size() - NumThunkVarArgOperands; i != e; ++i) {
     CCValAssign &VA = ArgLocs[i - ExtraArgLocs];
     SDValue Arg = OutVals[i];
     ISD::ArgFlagsTy Flags = Outs[i].Flags;
@@ -10561,7 +10619,7 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
   }
 
   if (IsVarArg && Subtarget->isWindowsArm64EC() &&
-      !(CLI.CB && CLI.CB->isMustTailCall())) {
+      !(CLI.CB && CLI.CB->isMustTailCall()) && !IsArm64ECVarArgExitThunk) {
     SDValue ParamPtr = StackPtr;
     if (IsTailCall) {
       // Create a dummy object at the top of the stack that can be used to get

diff  --git a/llvm/test/CodeGen/AArch64/arm64ec-exit-thunks.ll b/llvm/test/CodeGen/AArch64/arm64ec-exit-thunks.ll
index 991b9c291da09..03ce3ca919a56 100644
--- a/llvm/test/CodeGen/AArch64/arm64ec-exit-thunks.ll
+++ b/llvm/test/CodeGen/AArch64/arm64ec-exit-thunks.ll
@@ -1,4 +1,4 @@
-; RUN: llc -mtriple=arm64ec-pc-windows-msvc < %s | FileCheck %s
+; RUN: llc -mtriple=arm64ec-pc-windows-msvc -verify-machineinstrs < %s | FileCheck %s
 
 declare void @no_op() nounwind;
 ; CHECK-LABEL:    .def    $iexit_thunk$cdecl$v$v;
@@ -286,22 +286,52 @@ declare void @has_varargs(...) nounwind;
 ; CHECK-LABEL:    .def    $iexit_thunk$cdecl$v$varargs;
 ; CHECK:          .section        .wowthk$aa,"xr",discard,$iexit_thunk$cdecl$v$varargs
 ; CHECK:          // %bb.0:
-; CHECK-NEXT:     sub     sp, sp, #64
-; CHECK-NEXT:     .seh_stackalloc 64
+; CHECK-NEXT:     stp     x19, x20, [sp, #-64]!           // 16-byte Folded Spill
+; CHECK-NEXT:     .seh_save_regp_x x19, 64
+; CHECK-NEXT:     stp     x21, x22, [sp, #16]             // 16-byte Folded Spill
+; CHECK-NEXT:     .seh_save_regp x21, 16
+; CHECK-NEXT:     stp     x25, x26, [sp, #32]             // 16-byte Folded Spill
+; CHECK-NEXT:     .seh_save_regp x25, 32
 ; CHECK-NEXT:     stp     x29, x30, [sp, #48]             // 16-byte Folded Spill
 ; CHECK-NEXT:     .seh_save_fplr  48
 ; CHECK-NEXT:     add     x29, sp, #48
 ; CHECK-NEXT:     .seh_add_fp     48
 ; CHECK-NEXT:     .seh_endprologue
 ; CHECK-NEXT:     adrp    x8, __os_arm64x_dispatch_call_no_redirect
-; CHECK-NEXT:     stp     x4, x5, [sp, #32]
-; CHECK-NEXT:     ldr     x16, [x8, :lo12:__os_arm64x_dispatch_call_no_redirect]
+; CHECK-NEXT:     mov     x19, x3
+; CHECK-NEXT:     mov     x20, x2
+; CHECK-NEXT:     ldr     x25, [x8, :lo12:__os_arm64x_dispatch_call_no_redirect]
+; CHECK-NEXT:     add     x8, x5, #15
+; CHECK-NEXT:     mov     x21, x1
+; CHECK-NEXT:     lsr     x15, x8, #4
+; CHECK-NEXT:     mov     x22, x0
+; CHECK-NEXT:     mov     x26, x9
+; CHECK-NEXT:     bl      "#__chkstk_arm64ec"
+; CHECK-NEXT:     sub     x0, sp, x15, lsl #4
+; CHECK-NEXT:     mov     sp, x0
+; CHECK-NEXT:     mov     x1, x4
+; CHECK-NEXT:     mov     x2, x5
+; CHECK-NEXT:     bl      "#memcpy"
+; CHECK-NEXT:     sub     sp, sp, #32
+; CHECK-NEXT:     mov     x9, x26
+; CHECK-NEXT:     mov     x0, x22
+; CHECK-NEXT:     mov     x1, x21
+; CHECK-NEXT:     mov     x2, x20
+; CHECK-NEXT:     mov     x3, x19
+; CHECK-NEXT:     mov     x16, x25
 ; CHECK-NEXT:     blr     x16
+; CHECK-NEXT:     add     sp, sp, #32
 ; CHECK-NEXT:     .seh_startepilogue
+; CHECK-NEXT:     sub     sp, x29, #48
+; CHECK-NEXT:     .seh_add_fp     48
 ; CHECK-NEXT:     ldp     x29, x30, [sp, #48]             // 16-byte Folded Reload
 ; CHECK-NEXT:     .seh_save_fplr  48
-; CHECK-NEXT:     add     sp, sp, #64
-; CHECK-NEXT:     .seh_stackalloc 64
+; CHECK-NEXT:     ldp     x25, x26, [sp, #32]             // 16-byte Folded Reload
+; CHECK-NEXT:     .seh_save_regp x25, 32
+; CHECK-NEXT:     ldp     x21, x22, [sp, #16]             // 16-byte Folded Reload
+; CHECK-NEXT:     .seh_save_regp x21, 16
+; CHECK-NEXT:     ldp     x19, x20, [sp], #64             // 16-byte Folded Reload
+; CHECK-NEXT:     .seh_save_regp_x x19, 64
 ; CHECK-NEXT:     .seh_endepilogue
 ; CHECK-NEXT:     ret
 ; CHECK-NEXT:     .seh_endfunclet
@@ -329,6 +359,87 @@ declare void @has_varargs(...) nounwind;
 ; CHECK-NEXT:     .seh_endfunclet
 ; CHECK-NEXT:     .seh_endproc
 
+declare [2 x i8] @has_varargs_small_struct(...) nounwind;
+; CHECK-LABEL:    .def    $iexit_thunk$cdecl$m2$varargs;
+; CHECK:          .section        .wowthk$aa,"xr",discard,$iexit_thunk$cdecl$m2$varargs
+; CHECK:          // %bb.0:
+; CHECK-NEXT:     stp     x19, x20, [sp, #-64]!           // 16-byte Folded Spill
+; CHECK-NEXT:     .seh_save_regp_x x19, 64
+; CHECK-NEXT:     stp     x21, x22, [sp, #16]             // 16-byte Folded Spill
+; CHECK-NEXT:     .seh_save_regp x21, 16
+; CHECK-NEXT:     stp     x25, x26, [sp, #32]             // 16-byte Folded Spill
+; CHECK-NEXT:     .seh_save_regp x25, 32
+; CHECK-NEXT:     stp     x29, x30, [sp, #48]             // 16-byte Folded Spill
+; CHECK-NEXT:     .seh_save_fplr  48
+; CHECK-NEXT:     add     x29, sp, #48
+; CHECK-NEXT:     .seh_add_fp     48
+; CHECK-NEXT:     .seh_endprologue
+; CHECK-NEXT:     sub     sp, sp, #16
+; CHECK-NEXT:     adrp    x8, __os_arm64x_dispatch_call_no_redirect
+; CHECK-NEXT:     mov     x19, x3
+; CHECK-NEXT:     mov     x20, x2
+; CHECK-NEXT:     ldr     x25, [x8, :lo12:__os_arm64x_dispatch_call_no_redirect]
+; CHECK-NEXT:     add     x8, x5, #15
+; CHECK-NEXT:     mov     x21, x1
+; CHECK-NEXT:     lsr     x15, x8, #4
+; CHECK-NEXT:     mov     x22, x0
+; CHECK-NEXT:     mov     x26, x9
+; CHECK-NEXT:     bl      "#__chkstk_arm64ec"
+; CHECK-NEXT:     sub     x0, sp, x15, lsl #4
+; CHECK-NEXT:     mov     sp, x0
+; CHECK-NEXT:     mov     x1, x4
+; CHECK-NEXT:     mov     x2, x5
+; CHECK-NEXT:     bl      "#memcpy"
+; CHECK-NEXT:     sub     sp, sp, #32
+; CHECK-NEXT:     mov     x9, x26
+; CHECK-NEXT:     mov     x0, x22
+; CHECK-NEXT:     mov     x1, x21
+; CHECK-NEXT:     mov     x2, x20
+; CHECK-NEXT:     mov     x3, x19
+; CHECK-NEXT:     mov     x16, x25
+; CHECK-NEXT:     blr     x16
+; CHECK-NEXT:     add     sp, sp, #32
+; CHECK-NEXT:     mov     w0, w8
+; CHECK-NEXT:     sturh   w8, [x29, #-50]
+; CHECK-NEXT:     ubfx    w1, w8, #8, #8
+; CHECK-NEXT:     .seh_startepilogue
+; CHECK-NEXT:     sub     sp, x29, #48
+; CHECK-NEXT:     .seh_add_fp     48
+; CHECK-NEXT:     ldp     x29, x30, [sp, #48]             // 16-byte Folded Reload
+; CHECK-NEXT:     .seh_save_fplr  48
+; CHECK-NEXT:     ldp     x25, x26, [sp, #32]             // 16-byte Folded Reload
+; CHECK-NEXT:     .seh_save_regp x25, 32
+; CHECK-NEXT:     ldp     x21, x22, [sp, #16]             // 16-byte Folded Reload
+; CHECK-NEXT:     .seh_save_regp x21, 16
+; CHECK-NEXT:     ldp     x19, x20, [sp], #64             // 16-byte Folded Reload
+; CHECK-NEXT:     .seh_save_regp_x x19, 64
+; CHECK-NEXT:     .seh_endepilogue
+; CHECK-NEXT:     ret
+; CHECK-NEXT:     .seh_endfunclet
+; CHECK-NEXT:     .seh_endproc
+; CHECK-LABEL:    .def    "#has_varargs_small_struct$exit_thunk";
+; CHECK:          .section        .wowthk$aa,"xr",discard,"#has_varargs_small_struct$exit_thunk"
+; CHECK:          .weak_anti_dep  has_varargs_small_struct
+; CHECK:          .weak_anti_dep  "#has_varargs_small_struct"
+; CHECK:          // %bb.0:
+; CHECK-NEXT:     str     x30, [sp, #-16]!                // 8-byte Folded Spill
+; CHECK-NEXT:     .seh_save_reg_x x30, 16
+; CHECK-NEXT:     .seh_endprologue
+; CHECK-NEXT:     adrp    x8, __os_arm64x_check_icall
+; CHECK-NEXT:     adrp    x11, has_varargs_small_struct
+; CHECK-NEXT:     add     x11, x11, :lo12:has_varargs_small_struct
+; CHECK-NEXT:     ldr     x8, [x8, :lo12:__os_arm64x_check_icall]
+; CHECK-NEXT:     adrp    x10, $iexit_thunk$cdecl$m2$varargs
+; CHECK-NEXT:     add     x10, x10, :lo12:$iexit_thunk$cdecl$m2$varargs
+; CHECK-NEXT:     blr     x8
+; CHECK-NEXT:     .seh_startepilogue
+; CHECK-NEXT:     ldr     x30, [sp], #16                  // 8-byte Folded Reload
+; CHECK-NEXT:     .seh_save_reg_x x30, 16
+; CHECK-NEXT:     .seh_endepilogue
+; CHECK-NEXT:     br      x11
+; CHECK-NEXT:     .seh_endfunclet
+; CHECK-NEXT:     .seh_endproc
+
 declare void @has_sret(ptr sret([100 x i8])) nounwind;
 ; CHECK-LABEL:    .def    $iexit_thunk$cdecl$m100$v;
 ; CHECK:          .section        .wowthk$aa,"xr",discard,$iexit_thunk$cdecl$m100$v
@@ -424,6 +535,82 @@ declare void @has_aligned_sret(ptr align 32 sret(%TSRet)) nounwind;
 ; CHECK:          .seh_endfunclet
 ; CHECK:          .seh_endproc
 
+declare void @has_varargs_sret(ptr sret([100 x i8]), ...) nounwind;
+; CHECK-LABEL:    .def    $iexit_thunk$cdecl$m100$varargs;
+; CHECK:          .section        .wowthk$aa,"xr",discard,$iexit_thunk$cdecl$m100$varargs
+; CHECK:          // %bb.0:
+; CHECK-NEXT:     stp     x19, x20, [sp, #-64]!           // 16-byte Folded Spill
+; CHECK-NEXT:     .seh_save_regp_x x19, 64
+; CHECK-NEXT:     stp     x21, x22, [sp, #16]             // 16-byte Folded Spill
+; CHECK-NEXT:     .seh_save_regp x21, 16
+; CHECK-NEXT:     stp     x25, x26, [sp, #32]             // 16-byte Folded Spill
+; CHECK-NEXT:     .seh_save_regp x25, 32
+; CHECK-NEXT:     stp     x29, x30, [sp, #48]             // 16-byte Folded Spill
+; CHECK-NEXT:     .seh_save_fplr  48
+; CHECK-NEXT:     add     x29, sp, #48
+; CHECK-NEXT:     .seh_add_fp     48
+; CHECK-NEXT:     .seh_endprologue
+; CHECK-NEXT:     mov     x22, x8
+; CHECK-NEXT:     adrp    x8, __os_arm64x_dispatch_call_no_redirect
+; CHECK-NEXT:     mov     x19, x2
+; CHECK-NEXT:     ldr     x25, [x8, :lo12:__os_arm64x_dispatch_call_no_redirect]
+; CHECK-NEXT:     add     x8, x4, #15
+; CHECK-NEXT:     mov     x20, x1
+; CHECK-NEXT:     lsr     x15, x8, #4
+; CHECK-NEXT:     mov     x21, x0
+; CHECK-NEXT:     mov     x26, x9
+; CHECK-NEXT:     bl      "#__chkstk_arm64ec"
+; CHECK-NEXT:     sub     x0, sp, x15, lsl #4
+; CHECK-NEXT:     mov     sp, x0
+; CHECK-NEXT:     mov     x1, x3
+; CHECK-NEXT:     mov     x2, x4
+; CHECK-NEXT:     bl      "#memcpy"
+; CHECK-NEXT:     sub     sp, sp, #32
+; CHECK-NEXT:     mov     x9, x26
+; CHECK-NEXT:     mov     x0, x22
+; CHECK-NEXT:     mov     x1, x21
+; CHECK-NEXT:     mov     x2, x20
+; CHECK-NEXT:     mov     x3, x19
+; CHECK-NEXT:     mov     x16, x25
+; CHECK-NEXT:     blr     x16
+; CHECK-NEXT:     add     sp, sp, #32
+; CHECK-NEXT:     .seh_startepilogue
+; CHECK-NEXT:     sub     sp, x29, #48
+; CHECK-NEXT:     .seh_add_fp     48
+; CHECK-NEXT:     ldp     x29, x30, [sp, #48]             // 16-byte Folded Reload
+; CHECK-NEXT:     .seh_save_fplr  48
+; CHECK-NEXT:     ldp     x25, x26, [sp, #32]             // 16-byte Folded Reload
+; CHECK-NEXT:     .seh_save_regp x25, 32
+; CHECK-NEXT:     ldp     x21, x22, [sp, #16]             // 16-byte Folded Reload
+; CHECK-NEXT:     .seh_save_regp x21, 16
+; CHECK-NEXT:     ldp     x19, x20, [sp], #64             // 16-byte Folded Reload
+; CHECK-NEXT:     .seh_save_regp_x x19, 64
+; CHECK-NEXT:     .seh_endepilogue
+; CHECK-NEXT:     ret
+; CHECK-NEXT:     .seh_endfunclet
+; CHECK-NEXT:     .seh_endproc
+; CHECK-LABEL:    .def    "#has_varargs_sret$exit_thunk";
+; CHECK:          .section        .wowthk$aa,"xr",discard,"#has_varargs_sret$exit_thunk"
+; CHECK:          .weak_anti_dep  has_varargs_sret
+; CHECK:          .weak_anti_dep  "#has_varargs_sret"
+; CHECK:          // %bb.0:
+; CHECK-NEXT:     str     x30, [sp, #-16]!                // 8-byte Folded Spill
+; CHECK-NEXT:     .seh_save_reg_x x30, 16
+; CHECK-NEXT:     .seh_endprologue
+; CHECK-NEXT:     adrp    x9, __os_arm64x_check_icall
+; CHECK-NEXT:     adrp    x11, has_varargs_sret
+; CHECK-NEXT:     add     x11, x11, :lo12:has_varargs_sret
+; CHECK-NEXT:     ldr     x9, [x9, :lo12:__os_arm64x_check_icall]
+; CHECK-NEXT:     adrp    x10, $iexit_thunk$cdecl$m100$varargs
+; CHECK-NEXT:     add     x10, x10, :lo12:$iexit_thunk$cdecl$m100$varargs
+; CHECK-NEXT:     blr     x9
+; CHECK-NEXT:     .seh_startepilogue
+; CHECK-NEXT:     ldr     x30, [sp], #16                  // 8-byte Folded Reload
+; CHECK-NEXT:     .seh_save_reg_x x30, 16
+; CHECK-NEXT:     .seh_endepilogue
+; CHECK-NEXT:     br      x11
+; CHECK-NEXT:     .seh_endfunclet
+; CHECK-NEXT:     .seh_endproc
 declare [2 x i8] @small_array([2 x i8], [2 x half], [2 x fp128], [2 x float]) nounwind;
 ; CHECK-LABEL:    .def    $iexit_thunk$cdecl$m2$m2__llvm_H__4__llvm_Q__32F8;
 ; CHECK:          .section        .wowthk$aa,"xr",discard,$iexit_thunk$cdecl$m2$m2__llvm_H__4__llvm_Q__32F8
@@ -788,6 +975,12 @@ declare void @"??@md5mangleaaaaaaaaaaaaaaaaaaaaaaa@"()
 ; CHECK-NEXT:     .symidx "#has_varargs$exit_thunk"
 ; CHECK-NEXT:     .symidx has_varargs
 ; CHECK-NEXT:     .word 0
+; CHECK-NEXT:     .symidx has_varargs_small_struct
+; CHECK-NEXT:     .symidx $iexit_thunk$cdecl$m2$varargs
+; CHECK-NEXT:     .word   4
+; CHECK-NEXT:     .symidx "#has_varargs_small_struct$exit_thunk"
+; CHECK-NEXT:     .symidx has_varargs_small_struct
+; CHECK-NEXT:     .word   0
 ; CHECK-NEXT:     .symidx has_sret
 ; CHECK-NEXT:     .symidx $iexit_thunk$cdecl$m100$v
 ; CHECK-NEXT:     .word   4
@@ -800,6 +993,12 @@ declare void @"??@md5mangleaaaaaaaaaaaaaaaaaaaaaaa@"()
 ; CHECK-NEXT:     .symidx "#has_aligned_sret$exit_thunk"
 ; CHECK-NEXT:     .symidx has_aligned_sret
 ; CHECK-NEXT:     .word   0
+; CHECK-NEXT:     .symidx has_varargs_sret
+; CHECK-NEXT:     .symidx $iexit_thunk$cdecl$m100$varargs
+; CHECK-NEXT:     .word   4
+; CHECK-NEXT:     .symidx "#has_varargs_sret$exit_thunk"
+; CHECK-NEXT:     .symidx has_varargs_sret
+; CHECK-NEXT:     .word   0
 ; CHECK-NEXT:     .symidx small_array
 ; CHECK-NEXT:     .symidx $iexit_thunk$cdecl$m2$m2__llvm_H__4__llvm_Q__32F8
 ; CHECK-NEXT:     .word   4
@@ -845,11 +1044,13 @@ define void @func_caller() nounwind {
   call half @return_half()
   call fp128 @return_fp128()
   call void (...) @has_varargs()
+  call [2 x i8] (...) @has_varargs_small_struct()
   %c = alloca i8
   call void @has_sret(ptr sret([100 x i8]) %c)
   %aligned = alloca %TSRet, align 32
   store %TSRet { i64 0, i64 0 }, ptr %aligned, align 32
   call void @has_aligned_sret(ptr align 32 sret(%TSRet) %aligned)
+  call void (ptr, ...) @has_varargs_sret(ptr sret([100 x i8]) %c)
   call [2 x i8] @small_array([2 x i8] [i8 0, i8 0], [2 x half] [half 0.0, half 0.0], [2 x fp128] [fp128 0.0, fp128 0.0], [2 x float] [float 0.0, float 0.0])
   call [3 x i64] @large_array([3 x i64] [i64 0, i64 0, i64 0], [2 x double] [double 0.0, double 0.0], [2 x [2 x i64]] [[2 x i64] [i64 0, i64 0], [2 x i64] [i64 0, i64 0]])
   call %T2 @simple_struct(%T1 { i16 0 }, %T2 { i32 0, float 0.0 }, %T3 { i64 0, double 0.0 }, %T4 { i64 0, double 0.0, i8 0 })

diff  --git a/llvm/test/CodeGen/AArch64/arm64ec-hybrid-patchable.ll b/llvm/test/CodeGen/AArch64/arm64ec-hybrid-patchable.ll
index 7c77832a9d9a5..c60e7b44e4eb0 100644
--- a/llvm/test/CodeGen/AArch64/arm64ec-hybrid-patchable.ll
+++ b/llvm/test/CodeGen/AArch64/arm64ec-hybrid-patchable.ll
@@ -1,5 +1,5 @@
-; RUN: llc -mtriple=arm64ec-pc-windows-msvc < %s | FileCheck %s
-; RUN: llc -mtriple=arm64ec-pc-windows-msvc -filetype=obj -o %t.o < %s
+; RUN: llc -mtriple=arm64ec-pc-windows-msvc -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=arm64ec-pc-windows-msvc -verify-machineinstrs -filetype=obj -o %t.o < %s
 ; RUN: llvm-objdump -t %t.o | FileCheck --check-prefix=SYM %s
 
 define dso_local ptr @func() hybrid_patchable nounwind {
@@ -321,15 +321,17 @@ define dso_local void @caller() nounwind {
 ; SYM:      [122](sec  0)(fl 0x00)(ty   0)(scl  69) (nx 1) 0x00000000 has_varargs
 ; SYM-NEXT: AUX indx 124 srch 3
 ; SYM-NEXT: [124](sec  0)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x00000000 EXP+#has_varargs
-; SYM-NEXT: [125](sec  0)(fl 0x00)(ty   0)(scl  69) (nx 1) 0x00000000 has_sret
-; SYM-NEXT: AUX indx 127 srch 3
-; SYM-NEXT: [127](sec  0)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x00000000 EXP+#has_sret
-; SYM-NEXT: [128](sec  0)(fl 0x00)(ty   0)(scl  69) (nx 1) 0x00000000 exp
-; SYM-NEXT: AUX indx 130 srch 3
-; SYM-NEXT: [130](sec  0)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x00000000 EXP+#exp
-; SYM-NEXT: [131](sec  0)(fl 0x00)(ty   0)(scl  69) (nx 1) 0x00000000 #has_varargs
+; SYM-NEXT: [125](sec  0)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 #__chkstk_arm64ec
+; SYM-NEXT: [126](sec  0)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 #memcpy
+; SYM-NEXT: [127](sec  0)(fl 0x00)(ty   0)(scl  69) (nx 1) 0x00000000 has_sret
+; SYM-NEXT: AUX indx 129 srch 3
+; SYM-NEXT: [129](sec  0)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x00000000 EXP+#has_sret
+; SYM-NEXT: [130](sec  0)(fl 0x00)(ty   0)(scl  69) (nx 1) 0x00000000 exp
+; SYM-NEXT: AUX indx 132 srch 3
+; SYM-NEXT: [132](sec  0)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x00000000 EXP+#exp
+; SYM-NEXT: [133](sec  0)(fl 0x00)(ty   0)(scl  69) (nx 1) 0x00000000 #has_varargs
 ; SYM-NEXT: AUX indx 58 srch 3
-; SYM-NEXT: [133](sec  0)(fl 0x00)(ty   0)(scl  69) (nx 1) 0x00000000 #has_sret
+; SYM-NEXT: [135](sec  0)(fl 0x00)(ty   0)(scl  69) (nx 1) 0x00000000 #has_sret
 ; SYM-NEXT: AUX indx 68 srch 3
-; SYM-NEXT: [135](sec  0)(fl 0x00)(ty   0)(scl  69) (nx 1) 0x00000000 #exp
+; SYM-NEXT: [137](sec  0)(fl 0x00)(ty   0)(scl  69) (nx 1) 0x00000000 #exp
 ; SYM-NEXT: AUX indx 78 srch 3


        


More information about the llvm-commits mailing list