[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