[llvm-branch-commits] [llvm] release/23.x: [AArch64][GISel][FastISel] Fix Windows "sret inreg". (#225190) (PR #225548)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Sep 22 15:55:10 PDT 2026
https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/225548
Backport 8890be35705834c5af8e21424d7900639be03180
Requested by: @efriedma-quic
>From 6dd1f43032d3bfe880b4ea96c49dc4bcb1d1dde8 Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at qti.qualcomm.com>
Date: Tue, 22 Sep 2026 15:45:53 -0700
Subject: [PATCH] [AArch64][GISel][FastISel] Fix Windows "sret inreg".
(#225190)
5dc8aeb26d2896c65cbea0d3b87f090241444bb6 added a special case to
SelectionDAG ISel for "sret inreg" parameters: they are copied to x0 on
return. There was a review comment suggesting that GISel and FastISel
also needed fixes, but through some mixup the followup never happened.
Fixes #225060
(cherry picked from commit 8890be35705834c5af8e21424d7900639be03180)
---
llvm/lib/Target/AArch64/AArch64FastISel.cpp | 3 +
.../AArch64/GISel/AArch64CallLowering.cpp | 11 +-
.../CodeGen/AArch64/arm64-windows-calls.ll | 652 +++++++++++++++---
.../CodeGen/AArch64/arm64-windows-tailcall.ll | 62 +-
4 files changed, 616 insertions(+), 112 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64FastISel.cpp b/llvm/lib/Target/AArch64/AArch64FastISel.cpp
index b6deb703893fdb..caa0983ca5fb15 100644
--- a/llvm/lib/Target/AArch64/AArch64FastISel.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FastISel.cpp
@@ -3851,6 +3851,9 @@ bool AArch64FastISel::selectRet(const Instruction *I) {
if (!FuncInfo.CanLowerReturn)
return false;
+ if (FuncInfo.MF->getInfo<AArch64FunctionInfo>()->getSRetReturnReg())
+ return false;
+
if (F.isVarArg())
return false;
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp
index b0a409d153fd21..76439176474749 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp
@@ -715,9 +715,14 @@ bool AArch64CallLowering::lowerFormalArguments(
F.getCallingConv() == CallingConv::ARM64EC_Thunk_X64)
return false;
- bool IsWin64 =
- Subtarget.isCallingConvWin64(F.getCallingConv(), F.isVarArg()) &&
- !Subtarget.isWindowsArm64EC();
+ bool IsWin64 = Subtarget.isCallingConvWin64(F.getCallingConv(), F.isVarArg());
+
+ // If an argument is marked "sret" and "inreg", it must be returned in x0.
+ // Bail for now.
+ if (IsWin64 && any_of(F.args(), [](const Argument &A) {
+ return A.hasStructRetAttr() && A.hasInRegAttr();
+ }))
+ return false;
SmallVector<ArgInfo, 8> SplitArgs;
SmallVector<std::pair<Register, Register>> BoolArgs;
diff --git a/llvm/test/CodeGen/AArch64/arm64-windows-calls.ll b/llvm/test/CodeGen/AArch64/arm64-windows-calls.ll
index 41f00a6c41b3b9..3305a6dce3029e 100644
--- a/llvm/test/CodeGen/AArch64/arm64-windows-calls.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-windows-calls.ll
@@ -1,15 +1,95 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
-; FIXME: Add tests for global-isel/fast-isel.
-; RUN: llc < %s -mtriple=arm64-windows | FileCheck %s
+; RUN: llc < %s -mtriple=arm64-windows | FileCheck -check-prefixes=CHECK,CHECK-NOTGISEL,CHECK-SD %s
+; RUN: llc < %s -mtriple=arm64ec-windows-msvc -arm64ec-generate-thunks=false | FileCheck -check-prefixes=CHECK,CHECK-NOTGISEL,CHECK-EC-SD %s
+; RUN: llc < %s -mtriple=arm64-windows -fast-isel=0 -global-isel=1 -global-isel-abort=0 | FileCheck -check-prefixes=CHECK,CHECK-GI %s
+; RUN: llc < %s -mtriple=arm64-windows -fast-isel=1 -global-isel=0 | FileCheck -check-prefixes=CHECK,CHECK-NOTGISEL,CHECK-FAST %s
+; RUN: llc < %s -mtriple=arm64ec-windows-msvc -arm64ec-generate-thunks=false -fast-isel=0 -global-isel=1 -global-isel-abort=0 | FileCheck -check-prefixes=CHECK,CHECK-EC-GI %s
; Returns <= 8 bytes should be in X0.
%struct.S1 = type { i32, i32 }
-define dso_local i64 @"?f1"() {
+define dso_local i64 @f1() {
+; CHECK-SD-LABEL: f1:
+; CHECK-SD: .seh_proc f1
+; CHECK-SD-NEXT: // %bb.0: // %entry
+; CHECK-SD-NEXT: sub sp, sp, #16
+; CHECK-SD-NEXT: .seh_stackalloc 16
+; CHECK-SD-NEXT: .seh_endprologue
+; CHECK-SD-NEXT: mov x0, xzr
+; CHECK-SD-NEXT: str xzr, [sp, #8]
+; CHECK-SD-NEXT: .seh_startepilogue
+; CHECK-SD-NEXT: add sp, sp, #16
+; CHECK-SD-NEXT: .seh_stackalloc 16
+; CHECK-SD-NEXT: .seh_endepilogue
+; CHECK-SD-NEXT: ret
+; CHECK-SD-NEXT: .seh_endfunclet
+; CHECK-SD-NEXT: .seh_endproc
+;
+; CHECK-EC-SD-LABEL: f1:
+; CHECK-EC-SD: .seh_proc f1
+; CHECK-EC-SD-NEXT: // %bb.0: // %entry
+; CHECK-EC-SD-NEXT: sub sp, sp, #16
+; CHECK-EC-SD-NEXT: .seh_stackalloc 16
+; CHECK-EC-SD-NEXT: .seh_endprologue
+; CHECK-EC-SD-NEXT: mov x0, xzr
+; CHECK-EC-SD-NEXT: str xzr, [sp, #8]
+; CHECK-EC-SD-NEXT: .seh_startepilogue
+; CHECK-EC-SD-NEXT: add sp, sp, #16
+; CHECK-EC-SD-NEXT: .seh_stackalloc 16
+; CHECK-EC-SD-NEXT: .seh_endepilogue
+; CHECK-EC-SD-NEXT: ret
+; CHECK-EC-SD-NEXT: .seh_endfunclet
+; CHECK-EC-SD-NEXT: .seh_endproc
+;
+; CHECK-GI-LABEL: f1:
+; CHECK-GI: .seh_proc f1
+; CHECK-GI-NEXT: // %bb.0: // %entry
+; CHECK-GI-NEXT: sub sp, sp, #16
+; CHECK-GI-NEXT: .seh_stackalloc 16
+; CHECK-GI-NEXT: .seh_endprologue
+; CHECK-GI-NEXT: str xzr, [sp, #8]
+; CHECK-GI-NEXT: mov x0, xzr
+; CHECK-GI-NEXT: .seh_startepilogue
+; CHECK-GI-NEXT: add sp, sp, #16
+; CHECK-GI-NEXT: .seh_stackalloc 16
+; CHECK-GI-NEXT: .seh_endepilogue
+; CHECK-GI-NEXT: ret
+; CHECK-GI-NEXT: .seh_endfunclet
+; CHECK-GI-NEXT: .seh_endproc
+;
+; CHECK-FAST-LABEL: f1:
+; CHECK-FAST: .seh_proc f1
+; CHECK-FAST-NEXT: // %bb.0: // %entry
+; CHECK-FAST-NEXT: sub sp, sp, #16
+; CHECK-FAST-NEXT: .seh_stackalloc 16
+; CHECK-FAST-NEXT: .seh_endprologue
+; CHECK-FAST-NEXT: str xzr, [sp, #8]
+; CHECK-FAST-NEXT: ldr x0, [sp, #8]
+; CHECK-FAST-NEXT: .seh_startepilogue
+; CHECK-FAST-NEXT: add sp, sp, #16
+; CHECK-FAST-NEXT: .seh_stackalloc 16
+; CHECK-FAST-NEXT: .seh_endepilogue
+; CHECK-FAST-NEXT: ret
+; CHECK-FAST-NEXT: .seh_endfunclet
+; CHECK-FAST-NEXT: .seh_endproc
+;
+; CHECK-EC-GI-LABEL: f1:
+; CHECK-EC-GI: .seh_proc f1
+; CHECK-EC-GI-NEXT: // %bb.0: // %entry
+; CHECK-EC-GI-NEXT: sub sp, sp, #16
+; CHECK-EC-GI-NEXT: .seh_stackalloc 16
+; CHECK-EC-GI-NEXT: .seh_endprologue
+; CHECK-EC-GI-NEXT: str xzr, [sp, #8]
+; CHECK-EC-GI-NEXT: mov x0, xzr
+; CHECK-EC-GI-NEXT: .seh_startepilogue
+; CHECK-EC-GI-NEXT: add sp, sp, #16
+; CHECK-EC-GI-NEXT: .seh_stackalloc 16
+; CHECK-EC-GI-NEXT: .seh_endepilogue
+; CHECK-EC-GI-NEXT: ret
+; CHECK-EC-GI-NEXT: .seh_endfunclet
+; CHECK-EC-GI-NEXT: .seh_endproc
+
entry:
-; CHECK-LABEL: f1
-; CHECK-DAG: str xzr, [sp, #8]
-; CHECK-DAG: mov x0, xzr
%retval = alloca %struct.S1, align 4
store i32 0, ptr %retval, align 4
@@ -21,18 +101,60 @@ entry:
; Returns <= 16 bytes should be in X0/X1.
%struct.S2 = type { i32, i32, i32, i32 }
-define dso_local [2 x i64] @"?f2"() {
+define dso_local [2 x i64] @f2() {
+; CHECK-NOTGISEL-LABEL: f2:
+; CHECK-NOTGISEL: .seh_proc f2
+; CHECK-NOTGISEL-NEXT: // %bb.0: // %entry
+; CHECK-NOTGISEL-NEXT: sub sp, sp, #16
+; CHECK-NOTGISEL-NEXT: .seh_stackalloc 16
+; CHECK-NOTGISEL-NEXT: .seh_endprologue
+; CHECK-NOTGISEL-NEXT: mov x0, xzr
+; CHECK-NOTGISEL-NEXT: mov x1, xzr
+; CHECK-NOTGISEL-NEXT: stp xzr, xzr, [sp]
+; CHECK-NOTGISEL-NEXT: .seh_startepilogue
+; CHECK-NOTGISEL-NEXT: add sp, sp, #16
+; CHECK-NOTGISEL-NEXT: .seh_stackalloc 16
+; CHECK-NOTGISEL-NEXT: .seh_endepilogue
+; CHECK-NOTGISEL-NEXT: ret
+; CHECK-NOTGISEL-NEXT: .seh_endfunclet
+; CHECK-NOTGISEL-NEXT: .seh_endproc
+;
+; CHECK-GI-LABEL: f2:
+; CHECK-GI: .seh_proc f2
+; CHECK-GI-NEXT: // %bb.0: // %entry
+; CHECK-GI-NEXT: sub sp, sp, #16
+; CHECK-GI-NEXT: .seh_stackalloc 16
+; CHECK-GI-NEXT: .seh_endprologue
+; CHECK-GI-NEXT: stp xzr, xzr, [sp]
+; CHECK-GI-NEXT: mov x0, xzr
+; CHECK-GI-NEXT: mov x1, xzr
+; CHECK-GI-NEXT: .seh_startepilogue
+; CHECK-GI-NEXT: add sp, sp, #16
+; CHECK-GI-NEXT: .seh_stackalloc 16
+; CHECK-GI-NEXT: .seh_endepilogue
+; CHECK-GI-NEXT: ret
+; CHECK-GI-NEXT: .seh_endfunclet
+; CHECK-GI-NEXT: .seh_endproc
+;
+; CHECK-EC-GI-LABEL: f2:
+; CHECK-EC-GI: .seh_proc f2
+; CHECK-EC-GI-NEXT: // %bb.0: // %entry
+; CHECK-EC-GI-NEXT: sub sp, sp, #16
+; CHECK-EC-GI-NEXT: .seh_stackalloc 16
+; CHECK-EC-GI-NEXT: .seh_endprologue
+; CHECK-EC-GI-NEXT: stp xzr, xzr, [sp]
+; CHECK-EC-GI-NEXT: mov x0, xzr
+; CHECK-EC-GI-NEXT: mov x1, xzr
+; CHECK-EC-GI-NEXT: .seh_startepilogue
+; CHECK-EC-GI-NEXT: add sp, sp, #16
+; CHECK-EC-GI-NEXT: .seh_stackalloc 16
+; CHECK-EC-GI-NEXT: .seh_endepilogue
+; CHECK-EC-GI-NEXT: ret
+; CHECK-EC-GI-NEXT: .seh_endfunclet
+; CHECK-EC-GI-NEXT: .seh_endproc
+
entry:
; FIXME: Missed optimization, the entire SP push/pop could be removed
-; CHECK-LABEL: f2
-; CHECK: sub sp, sp, #16
-; CHECK-NEXT: .seh_stackalloc 16
-; CHECK-NEXT: .seh_endprologue
-; CHECK-DAG: stp xzr, xzr, [sp]
-; CHECK-DAG: mov x0, xzr
-; CHECK-DAG: mov x1, xzr
-; CHECK: .seh_startepilogue
-; CHECK-NEXT: add sp, sp, #16
%retval = alloca %struct.S2, align 4
store i32 0, ptr %retval, align 4
@@ -48,11 +170,13 @@ entry:
; Arguments > 16 bytes should be passed in X8.
%struct.S3 = type { i32, i32, i32, i32, i32 }
-define dso_local void @"?f3"(ptr noalias sret(%struct.S3) %agg.result) {
+define dso_local void @f3(ptr noalias sret(%struct.S3) %agg.result) {
+; CHECK-LABEL: f3:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: stp xzr, xzr, [x8]
+; CHECK-NEXT: str wzr, [x8, #16]
+; CHECK-NEXT: ret
entry:
-; CHECK-LABEL: f3
-; CHECK: stp xzr, xzr, [x8]
-; CHECK: str wzr, [x8, #16]
store i32 0, ptr %agg.result, align 4
%b = getelementptr inbounds %struct.S3, ptr %agg.result, i32 0, i32 1
@@ -69,11 +193,13 @@ entry:
; InReg arguments to non-instance methods must be passed in X0 and returns in
; X0.
%class.B = type { i32 }
-define dso_local void @"?f4"(ptr inreg noalias nocapture sret(%class.B) %agg.result) {
+define dso_local void @f4(ptr inreg noalias nocapture sret(%class.B) %agg.result) {
+; CHECK-LABEL: f4:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: mov w8, #1 // =0x1
+; CHECK-NEXT: str w8, [x0]
+; CHECK-NEXT: ret
entry:
-; CHECK-LABEL: f4
-; CHECK: mov w8, #1
-; CHECK: str w8, [x0]
store i32 1, ptr %agg.result, align 4
ret void
}
@@ -82,11 +208,24 @@ entry:
%class.C = type { i8 }
%class.A = type { i8 }
-define dso_local void @"?inst at C"(ptr %this, ptr inreg noalias sret(%class.A) %agg.result) {
+define dso_local void @inst(ptr %this, ptr inreg noalias sret(%class.A) %agg.result) {
+; CHECK-LABEL: inst:
+; CHECK: .seh_proc inst
+; CHECK-NEXT: // %bb.0: // %entry
+; CHECK-NEXT: sub sp, sp, #16
+; CHECK-NEXT: .seh_stackalloc 16
+; CHECK-NEXT: .seh_endprologue
+; CHECK-NEXT: mov x8, x0
+; CHECK-NEXT: mov x0, x1
+; CHECK-NEXT: str x8, [sp, #8]
+; CHECK-NEXT: .seh_startepilogue
+; CHECK-NEXT: add sp, sp, #16
+; CHECK-NEXT: .seh_stackalloc 16
+; CHECK-NEXT: .seh_endepilogue
+; CHECK-NEXT: ret
+; CHECK-NEXT: .seh_endfunclet
+; CHECK-NEXT: .seh_endproc
entry:
-; CHECK-LABEL: inst at C
-; CHECK-DAG: mov x0, x1
-; CHECK-DAG: str x8, [sp, #8]
%this.addr = alloca ptr, align 8
store ptr %this, ptr %this.addr, align 8
@@ -140,28 +279,131 @@ define dso_local [2 x i64] @copy_notpod(ptr %x) {
@Pod = external global %struct.Pod
define void @call_copy_pod() {
-; CHECK-LABEL: call_copy_pod:
-; CHECK: .seh_proc call_copy_pod
-; CHECK-NEXT: // %bb.0:
-; CHECK-NEXT: sub sp, sp, #16
-; CHECK-NEXT: .seh_stackalloc 16
-; CHECK-NEXT: stp x19, x30, [sp] // 16-byte Folded Spill
-; CHECK-NEXT: .seh_save_lrpair x19, 0
-; CHECK-NEXT: .seh_endprologue
-; CHECK-NEXT: adrp x19, Pod
-; CHECK-NEXT: add x19, x19, :lo12:Pod
-; CHECK-NEXT: mov x0, x19
-; CHECK-NEXT: bl copy_pod
-; CHECK-NEXT: stp d0, d1, [x19]
-; CHECK-NEXT: .seh_startepilogue
-; CHECK-NEXT: ldp x19, x30, [sp] // 16-byte Folded Reload
-; CHECK-NEXT: .seh_save_lrpair x19, 0
-; CHECK-NEXT: add sp, sp, #16
-; CHECK-NEXT: .seh_stackalloc 16
-; CHECK-NEXT: .seh_endepilogue
-; CHECK-NEXT: ret
-; CHECK-NEXT: .seh_endfunclet
-; CHECK-NEXT: .seh_endproc
+; CHECK-SD-LABEL: call_copy_pod:
+; CHECK-SD: .seh_proc call_copy_pod
+; CHECK-SD-NEXT: // %bb.0:
+; CHECK-SD-NEXT: sub sp, sp, #16
+; CHECK-SD-NEXT: .seh_stackalloc 16
+; CHECK-SD-NEXT: stp x19, x30, [sp] // 16-byte Folded Spill
+; CHECK-SD-NEXT: .seh_save_lrpair x19, 0
+; CHECK-SD-NEXT: .seh_endprologue
+; CHECK-SD-NEXT: adrp x19, Pod
+; CHECK-SD-NEXT: add x19, x19, :lo12:Pod
+; CHECK-SD-NEXT: mov x0, x19
+; CHECK-SD-NEXT: bl copy_pod
+; CHECK-SD-NEXT: stp d0, d1, [x19]
+; CHECK-SD-NEXT: .seh_startepilogue
+; CHECK-SD-NEXT: ldp x19, x30, [sp] // 16-byte Folded Reload
+; CHECK-SD-NEXT: .seh_save_lrpair x19, 0
+; CHECK-SD-NEXT: add sp, sp, #16
+; CHECK-SD-NEXT: .seh_stackalloc 16
+; CHECK-SD-NEXT: .seh_endepilogue
+; CHECK-SD-NEXT: ret
+; CHECK-SD-NEXT: .seh_endfunclet
+; CHECK-SD-NEXT: .seh_endproc
+;
+; CHECK-EC-SD-LABEL: call_copy_pod:
+; CHECK-EC-SD: .seh_proc call_copy_pod
+; CHECK-EC-SD-NEXT: // %bb.0:
+; CHECK-EC-SD-NEXT: sub sp, sp, #16
+; CHECK-EC-SD-NEXT: .seh_stackalloc 16
+; CHECK-EC-SD-NEXT: stp x19, x30, [sp] // 16-byte Folded Spill
+; CHECK-EC-SD-NEXT: .seh_save_lrpair x19, 0
+; CHECK-EC-SD-NEXT: .seh_endprologue
+; CHECK-EC-SD-NEXT: adrp x19, Pod
+; CHECK-EC-SD-NEXT: add x19, x19, :lo12:Pod
+; CHECK-EC-SD-NEXT: mov x0, x19
+; CHECK-EC-SD-NEXT: .weak_anti_dep copy_pod
+; CHECK-EC-SD-NEXT: copy_pod = "#copy_pod"
+; CHECK-EC-SD-NEXT: .weak_anti_dep "#copy_pod"
+; CHECK-EC-SD-NEXT: "#copy_pod" = copy_pod
+; CHECK-EC-SD-NEXT: bl "#copy_pod"
+; CHECK-EC-SD-NEXT: stp d0, d1, [x19]
+; CHECK-EC-SD-NEXT: .seh_startepilogue
+; CHECK-EC-SD-NEXT: ldp x19, x30, [sp] // 16-byte Folded Reload
+; CHECK-EC-SD-NEXT: .seh_save_lrpair x19, 0
+; CHECK-EC-SD-NEXT: add sp, sp, #16
+; CHECK-EC-SD-NEXT: .seh_stackalloc 16
+; CHECK-EC-SD-NEXT: .seh_endepilogue
+; CHECK-EC-SD-NEXT: ret
+; CHECK-EC-SD-NEXT: .seh_endfunclet
+; CHECK-EC-SD-NEXT: .seh_endproc
+;
+; CHECK-GI-LABEL: call_copy_pod:
+; CHECK-GI: .seh_proc call_copy_pod
+; CHECK-GI-NEXT: // %bb.0:
+; CHECK-GI-NEXT: stp x19, x20, [sp, #-32]! // 16-byte Folded Spill
+; CHECK-GI-NEXT: .seh_save_regp_x x19, 32
+; CHECK-GI-NEXT: str x30, [sp, #16] // 8-byte Spill
+; CHECK-GI-NEXT: .seh_save_reg x30, 16
+; CHECK-GI-NEXT: .seh_endprologue
+; CHECK-GI-NEXT: adrp x19, Pod
+; CHECK-GI-NEXT: add x19, x19, :lo12:Pod
+; CHECK-GI-NEXT: adrp x20, Pod
+; CHECK-GI-NEXT: mov x0, x19
+; CHECK-GI-NEXT: bl copy_pod
+; CHECK-GI-NEXT: str d0, [x20, :lo12:Pod]
+; CHECK-GI-NEXT: str d1, [x19, #8]
+; CHECK-GI-NEXT: .seh_startepilogue
+; CHECK-GI-NEXT: ldr x30, [sp, #16] // 8-byte Reload
+; CHECK-GI-NEXT: .seh_save_reg x30, 16
+; CHECK-GI-NEXT: ldp x19, x20, [sp], #32 // 16-byte Folded Reload
+; CHECK-GI-NEXT: .seh_save_regp_x x19, 32
+; CHECK-GI-NEXT: .seh_endepilogue
+; CHECK-GI-NEXT: ret
+; CHECK-GI-NEXT: .seh_endfunclet
+; CHECK-GI-NEXT: .seh_endproc
+;
+; CHECK-FAST-LABEL: call_copy_pod:
+; CHECK-FAST: .seh_proc call_copy_pod
+; CHECK-FAST-NEXT: // %bb.0:
+; CHECK-FAST-NEXT: sub sp, sp, #16
+; CHECK-FAST-NEXT: .seh_stackalloc 16
+; CHECK-FAST-NEXT: stp x19, x30, [sp] // 16-byte Folded Spill
+; CHECK-FAST-NEXT: .seh_save_lrpair x19, 0
+; CHECK-FAST-NEXT: .seh_endprologue
+; CHECK-FAST-NEXT: adrp x19, Pod
+; CHECK-FAST-NEXT: add x19, x19, :lo12:Pod
+; CHECK-FAST-NEXT: mov x0, x19
+; CHECK-FAST-NEXT: bl copy_pod
+; CHECK-FAST-NEXT: stp d0, d1, [x19]
+; CHECK-FAST-NEXT: .seh_startepilogue
+; CHECK-FAST-NEXT: ldp x19, x30, [sp] // 16-byte Folded Reload
+; CHECK-FAST-NEXT: .seh_save_lrpair x19, 0
+; CHECK-FAST-NEXT: add sp, sp, #16
+; CHECK-FAST-NEXT: .seh_stackalloc 16
+; CHECK-FAST-NEXT: .seh_endepilogue
+; CHECK-FAST-NEXT: ret
+; CHECK-FAST-NEXT: .seh_endfunclet
+; CHECK-FAST-NEXT: .seh_endproc
+;
+; CHECK-EC-GI-LABEL: call_copy_pod:
+; CHECK-EC-GI: .seh_proc call_copy_pod
+; CHECK-EC-GI-NEXT: // %bb.0:
+; CHECK-EC-GI-NEXT: sub sp, sp, #16
+; CHECK-EC-GI-NEXT: .seh_stackalloc 16
+; CHECK-EC-GI-NEXT: stp x19, x30, [sp] // 16-byte Folded Spill
+; CHECK-EC-GI-NEXT: .seh_save_lrpair x19, 0
+; CHECK-EC-GI-NEXT: .seh_endprologue
+; CHECK-EC-GI-NEXT: adrp x19, Pod
+; CHECK-EC-GI-NEXT: add x19, x19, :lo12:Pod
+; CHECK-EC-GI-NEXT: mov x0, x19
+; CHECK-EC-GI-NEXT: .weak_anti_dep copy_pod
+; CHECK-EC-GI-NEXT: copy_pod = "#copy_pod"
+; CHECK-EC-GI-NEXT: .weak_anti_dep "#copy_pod"
+; CHECK-EC-GI-NEXT: "#copy_pod" = copy_pod
+; CHECK-EC-GI-NEXT: bl "#copy_pod"
+; CHECK-EC-GI-NEXT: stp d0, d1, [x19]
+; CHECK-EC-GI-NEXT: .seh_startepilogue
+; CHECK-EC-GI-NEXT: ldp x19, x30, [sp] // 16-byte Folded Reload
+; CHECK-EC-GI-NEXT: .seh_save_lrpair x19, 0
+; CHECK-EC-GI-NEXT: add sp, sp, #16
+; CHECK-EC-GI-NEXT: .seh_stackalloc 16
+; CHECK-EC-GI-NEXT: .seh_endepilogue
+; CHECK-EC-GI-NEXT: ret
+; CHECK-EC-GI-NEXT: .seh_endfunclet
+; CHECK-EC-GI-NEXT: .seh_endproc
+
%x = call %struct.Pod @copy_pod(ptr @Pod)
store %struct.Pod %x, ptr @Pod
ret void
@@ -170,30 +412,145 @@ define void @call_copy_pod() {
@NotCXX14Aggregate = external global %struct.NotCXX14Aggregate
define void @call_copy_notcxx14aggregate() {
-; CHECK-LABEL: call_copy_notcxx14aggregate:
-; CHECK: .seh_proc call_copy_notcxx14aggregate
-; CHECK-NEXT: // %bb.0:
-; CHECK-NEXT: sub sp, sp, #32
-; CHECK-NEXT: .seh_stackalloc 32
-; CHECK-NEXT: stp x19, x30, [sp, #16] // 16-byte Folded Spill
-; CHECK-NEXT: .seh_save_lrpair x19, 16
-; CHECK-NEXT: .seh_endprologue
-; CHECK-NEXT: adrp x19, NotCXX14Aggregate
-; CHECK-NEXT: add x19, x19, :lo12:NotCXX14Aggregate
-; CHECK-NEXT: mov x0, sp
-; CHECK-NEXT: mov x1, x19
-; CHECK-NEXT: bl copy_notcxx14aggregate
-; CHECK-NEXT: ldp d0, d1, [sp]
-; CHECK-NEXT: stp d0, d1, [x19]
-; CHECK-NEXT: .seh_startepilogue
-; CHECK-NEXT: ldp x19, x30, [sp, #16] // 16-byte Folded Reload
-; CHECK-NEXT: .seh_save_lrpair x19, 16
-; CHECK-NEXT: add sp, sp, #32
-; CHECK-NEXT: .seh_stackalloc 32
-; CHECK-NEXT: .seh_endepilogue
-; CHECK-NEXT: ret
-; CHECK-NEXT: .seh_endfunclet
-; CHECK-NEXT: .seh_endproc
+; CHECK-SD-LABEL: call_copy_notcxx14aggregate:
+; CHECK-SD: .seh_proc call_copy_notcxx14aggregate
+; CHECK-SD-NEXT: // %bb.0:
+; CHECK-SD-NEXT: sub sp, sp, #32
+; CHECK-SD-NEXT: .seh_stackalloc 32
+; CHECK-SD-NEXT: stp x19, x30, [sp, #16] // 16-byte Folded Spill
+; CHECK-SD-NEXT: .seh_save_lrpair x19, 16
+; CHECK-SD-NEXT: .seh_endprologue
+; CHECK-SD-NEXT: adrp x19, NotCXX14Aggregate
+; CHECK-SD-NEXT: add x19, x19, :lo12:NotCXX14Aggregate
+; CHECK-SD-NEXT: mov x0, sp
+; CHECK-SD-NEXT: mov x1, x19
+; CHECK-SD-NEXT: bl copy_notcxx14aggregate
+; CHECK-SD-NEXT: ldp d0, d1, [sp]
+; CHECK-SD-NEXT: stp d0, d1, [x19]
+; CHECK-SD-NEXT: .seh_startepilogue
+; CHECK-SD-NEXT: ldp x19, x30, [sp, #16] // 16-byte Folded Reload
+; CHECK-SD-NEXT: .seh_save_lrpair x19, 16
+; CHECK-SD-NEXT: add sp, sp, #32
+; CHECK-SD-NEXT: .seh_stackalloc 32
+; CHECK-SD-NEXT: .seh_endepilogue
+; CHECK-SD-NEXT: ret
+; CHECK-SD-NEXT: .seh_endfunclet
+; CHECK-SD-NEXT: .seh_endproc
+;
+; CHECK-EC-SD-LABEL: call_copy_notcxx14aggregate:
+; CHECK-EC-SD: .seh_proc call_copy_notcxx14aggregate
+; CHECK-EC-SD-NEXT: // %bb.0:
+; CHECK-EC-SD-NEXT: sub sp, sp, #32
+; CHECK-EC-SD-NEXT: .seh_stackalloc 32
+; CHECK-EC-SD-NEXT: stp x19, x30, [sp, #16] // 16-byte Folded Spill
+; CHECK-EC-SD-NEXT: .seh_save_lrpair x19, 16
+; CHECK-EC-SD-NEXT: .seh_endprologue
+; CHECK-EC-SD-NEXT: adrp x19, NotCXX14Aggregate
+; CHECK-EC-SD-NEXT: add x19, x19, :lo12:NotCXX14Aggregate
+; CHECK-EC-SD-NEXT: mov x0, sp
+; CHECK-EC-SD-NEXT: mov x1, x19
+; CHECK-EC-SD-NEXT: .weak_anti_dep copy_notcxx14aggregate
+; CHECK-EC-SD-NEXT: copy_notcxx14aggregate = "#copy_notcxx14aggregate"
+; CHECK-EC-SD-NEXT: .weak_anti_dep "#copy_notcxx14aggregate"
+; CHECK-EC-SD-NEXT: "#copy_notcxx14aggregate" = copy_notcxx14aggregate
+; CHECK-EC-SD-NEXT: bl "#copy_notcxx14aggregate"
+; CHECK-EC-SD-NEXT: ldp d0, d1, [sp]
+; CHECK-EC-SD-NEXT: stp d0, d1, [x19]
+; CHECK-EC-SD-NEXT: .seh_startepilogue
+; CHECK-EC-SD-NEXT: ldp x19, x30, [sp, #16] // 16-byte Folded Reload
+; CHECK-EC-SD-NEXT: .seh_save_lrpair x19, 16
+; CHECK-EC-SD-NEXT: add sp, sp, #32
+; CHECK-EC-SD-NEXT: .seh_stackalloc 32
+; CHECK-EC-SD-NEXT: .seh_endepilogue
+; CHECK-EC-SD-NEXT: ret
+; CHECK-EC-SD-NEXT: .seh_endfunclet
+; CHECK-EC-SD-NEXT: .seh_endproc
+;
+; CHECK-GI-LABEL: call_copy_notcxx14aggregate:
+; CHECK-GI: .seh_proc call_copy_notcxx14aggregate
+; CHECK-GI-NEXT: // %bb.0:
+; CHECK-GI-NEXT: sub sp, sp, #48
+; CHECK-GI-NEXT: .seh_stackalloc 48
+; CHECK-GI-NEXT: stp x19, x20, [sp, #16] // 16-byte Folded Spill
+; CHECK-GI-NEXT: .seh_save_regp x19, 16
+; CHECK-GI-NEXT: str x30, [sp, #32] // 8-byte Spill
+; CHECK-GI-NEXT: .seh_save_reg x30, 32
+; CHECK-GI-NEXT: .seh_endprologue
+; CHECK-GI-NEXT: adrp x19, NotCXX14Aggregate
+; CHECK-GI-NEXT: add x19, x19, :lo12:NotCXX14Aggregate
+; CHECK-GI-NEXT: mov x0, sp
+; CHECK-GI-NEXT: mov x1, x19
+; CHECK-GI-NEXT: adrp x20, NotCXX14Aggregate
+; CHECK-GI-NEXT: bl copy_notcxx14aggregate
+; CHECK-GI-NEXT: ldp x8, x9, [sp]
+; CHECK-GI-NEXT: str x8, [x20, :lo12:NotCXX14Aggregate]
+; CHECK-GI-NEXT: str x9, [x19, #8]
+; CHECK-GI-NEXT: .seh_startepilogue
+; CHECK-GI-NEXT: ldr x30, [sp, #32] // 8-byte Reload
+; CHECK-GI-NEXT: .seh_save_reg x30, 32
+; CHECK-GI-NEXT: ldp x19, x20, [sp, #16] // 16-byte Folded Reload
+; CHECK-GI-NEXT: .seh_save_regp x19, 16
+; CHECK-GI-NEXT: add sp, sp, #48
+; CHECK-GI-NEXT: .seh_stackalloc 48
+; CHECK-GI-NEXT: .seh_endepilogue
+; CHECK-GI-NEXT: ret
+; CHECK-GI-NEXT: .seh_endfunclet
+; CHECK-GI-NEXT: .seh_endproc
+;
+; CHECK-FAST-LABEL: call_copy_notcxx14aggregate:
+; CHECK-FAST: .seh_proc call_copy_notcxx14aggregate
+; CHECK-FAST-NEXT: // %bb.0:
+; CHECK-FAST-NEXT: sub sp, sp, #32
+; CHECK-FAST-NEXT: .seh_stackalloc 32
+; CHECK-FAST-NEXT: stp x19, x30, [sp, #16] // 16-byte Folded Spill
+; CHECK-FAST-NEXT: .seh_save_lrpair x19, 16
+; CHECK-FAST-NEXT: .seh_endprologue
+; CHECK-FAST-NEXT: adrp x19, NotCXX14Aggregate
+; CHECK-FAST-NEXT: add x19, x19, :lo12:NotCXX14Aggregate
+; CHECK-FAST-NEXT: mov x0, sp
+; CHECK-FAST-NEXT: mov x1, x19
+; CHECK-FAST-NEXT: bl copy_notcxx14aggregate
+; CHECK-FAST-NEXT: ldp d0, d1, [sp]
+; CHECK-FAST-NEXT: stp d0, d1, [x19]
+; CHECK-FAST-NEXT: .seh_startepilogue
+; CHECK-FAST-NEXT: ldp x19, x30, [sp, #16] // 16-byte Folded Reload
+; CHECK-FAST-NEXT: .seh_save_lrpair x19, 16
+; CHECK-FAST-NEXT: add sp, sp, #32
+; CHECK-FAST-NEXT: .seh_stackalloc 32
+; CHECK-FAST-NEXT: .seh_endepilogue
+; CHECK-FAST-NEXT: ret
+; CHECK-FAST-NEXT: .seh_endfunclet
+; CHECK-FAST-NEXT: .seh_endproc
+;
+; CHECK-EC-GI-LABEL: call_copy_notcxx14aggregate:
+; CHECK-EC-GI: .seh_proc call_copy_notcxx14aggregate
+; CHECK-EC-GI-NEXT: // %bb.0:
+; CHECK-EC-GI-NEXT: sub sp, sp, #32
+; CHECK-EC-GI-NEXT: .seh_stackalloc 32
+; CHECK-EC-GI-NEXT: stp x19, x30, [sp, #16] // 16-byte Folded Spill
+; CHECK-EC-GI-NEXT: .seh_save_lrpair x19, 16
+; CHECK-EC-GI-NEXT: .seh_endprologue
+; CHECK-EC-GI-NEXT: adrp x19, NotCXX14Aggregate
+; CHECK-EC-GI-NEXT: add x19, x19, :lo12:NotCXX14Aggregate
+; CHECK-EC-GI-NEXT: mov x0, sp
+; CHECK-EC-GI-NEXT: mov x1, x19
+; CHECK-EC-GI-NEXT: .weak_anti_dep copy_notcxx14aggregate
+; CHECK-EC-GI-NEXT: copy_notcxx14aggregate = "#copy_notcxx14aggregate"
+; CHECK-EC-GI-NEXT: .weak_anti_dep "#copy_notcxx14aggregate"
+; CHECK-EC-GI-NEXT: "#copy_notcxx14aggregate" = copy_notcxx14aggregate
+; CHECK-EC-GI-NEXT: bl "#copy_notcxx14aggregate"
+; CHECK-EC-GI-NEXT: ldp d0, d1, [sp]
+; CHECK-EC-GI-NEXT: stp d0, d1, [x19]
+; CHECK-EC-GI-NEXT: .seh_startepilogue
+; CHECK-EC-GI-NEXT: ldp x19, x30, [sp, #16] // 16-byte Folded Reload
+; CHECK-EC-GI-NEXT: .seh_save_lrpair x19, 16
+; CHECK-EC-GI-NEXT: add sp, sp, #32
+; CHECK-EC-GI-NEXT: .seh_stackalloc 32
+; CHECK-EC-GI-NEXT: .seh_endepilogue
+; CHECK-EC-GI-NEXT: ret
+; CHECK-EC-GI-NEXT: .seh_endfunclet
+; CHECK-EC-GI-NEXT: .seh_endproc
+
%x = alloca %struct.NotCXX14Aggregate
call void @copy_notcxx14aggregate(ptr %x, ptr @NotCXX14Aggregate)
%x1 = load %struct.NotCXX14Aggregate, ptr %x
@@ -204,28 +561,131 @@ define void @call_copy_notcxx14aggregate() {
@NotPod = external global %struct.NotPod
define void @call_copy_notpod() {
-; CHECK-LABEL: call_copy_notpod:
-; CHECK: .seh_proc call_copy_notpod
-; CHECK-NEXT: // %bb.0:
-; CHECK-NEXT: sub sp, sp, #16
-; CHECK-NEXT: .seh_stackalloc 16
-; CHECK-NEXT: stp x19, x30, [sp] // 16-byte Folded Spill
-; CHECK-NEXT: .seh_save_lrpair x19, 0
-; CHECK-NEXT: .seh_endprologue
-; CHECK-NEXT: adrp x19, NotPod
-; CHECK-NEXT: add x19, x19, :lo12:NotPod
-; CHECK-NEXT: mov x0, x19
-; CHECK-NEXT: bl copy_notpod
-; CHECK-NEXT: stp x0, x1, [x19]
-; CHECK-NEXT: .seh_startepilogue
-; CHECK-NEXT: ldp x19, x30, [sp] // 16-byte Folded Reload
-; CHECK-NEXT: .seh_save_lrpair x19, 0
-; CHECK-NEXT: add sp, sp, #16
-; CHECK-NEXT: .seh_stackalloc 16
-; CHECK-NEXT: .seh_endepilogue
-; CHECK-NEXT: ret
-; CHECK-NEXT: .seh_endfunclet
-; CHECK-NEXT: .seh_endproc
+; CHECK-SD-LABEL: call_copy_notpod:
+; CHECK-SD: .seh_proc call_copy_notpod
+; CHECK-SD-NEXT: // %bb.0:
+; CHECK-SD-NEXT: sub sp, sp, #16
+; CHECK-SD-NEXT: .seh_stackalloc 16
+; CHECK-SD-NEXT: stp x19, x30, [sp] // 16-byte Folded Spill
+; CHECK-SD-NEXT: .seh_save_lrpair x19, 0
+; CHECK-SD-NEXT: .seh_endprologue
+; CHECK-SD-NEXT: adrp x19, NotPod
+; CHECK-SD-NEXT: add x19, x19, :lo12:NotPod
+; CHECK-SD-NEXT: mov x0, x19
+; CHECK-SD-NEXT: bl copy_notpod
+; CHECK-SD-NEXT: stp x0, x1, [x19]
+; CHECK-SD-NEXT: .seh_startepilogue
+; CHECK-SD-NEXT: ldp x19, x30, [sp] // 16-byte Folded Reload
+; CHECK-SD-NEXT: .seh_save_lrpair x19, 0
+; CHECK-SD-NEXT: add sp, sp, #16
+; CHECK-SD-NEXT: .seh_stackalloc 16
+; CHECK-SD-NEXT: .seh_endepilogue
+; CHECK-SD-NEXT: ret
+; CHECK-SD-NEXT: .seh_endfunclet
+; CHECK-SD-NEXT: .seh_endproc
+;
+; CHECK-EC-SD-LABEL: call_copy_notpod:
+; CHECK-EC-SD: .seh_proc call_copy_notpod
+; CHECK-EC-SD-NEXT: // %bb.0:
+; CHECK-EC-SD-NEXT: sub sp, sp, #16
+; CHECK-EC-SD-NEXT: .seh_stackalloc 16
+; CHECK-EC-SD-NEXT: stp x19, x30, [sp] // 16-byte Folded Spill
+; CHECK-EC-SD-NEXT: .seh_save_lrpair x19, 0
+; CHECK-EC-SD-NEXT: .seh_endprologue
+; CHECK-EC-SD-NEXT: adrp x19, NotPod
+; CHECK-EC-SD-NEXT: add x19, x19, :lo12:NotPod
+; CHECK-EC-SD-NEXT: mov x0, x19
+; CHECK-EC-SD-NEXT: .weak_anti_dep copy_notpod
+; CHECK-EC-SD-NEXT: copy_notpod = "#copy_notpod"
+; CHECK-EC-SD-NEXT: .weak_anti_dep "#copy_notpod"
+; CHECK-EC-SD-NEXT: "#copy_notpod" = copy_notpod
+; CHECK-EC-SD-NEXT: bl "#copy_notpod"
+; CHECK-EC-SD-NEXT: stp x0, x1, [x19]
+; CHECK-EC-SD-NEXT: .seh_startepilogue
+; CHECK-EC-SD-NEXT: ldp x19, x30, [sp] // 16-byte Folded Reload
+; CHECK-EC-SD-NEXT: .seh_save_lrpair x19, 0
+; CHECK-EC-SD-NEXT: add sp, sp, #16
+; CHECK-EC-SD-NEXT: .seh_stackalloc 16
+; CHECK-EC-SD-NEXT: .seh_endepilogue
+; CHECK-EC-SD-NEXT: ret
+; CHECK-EC-SD-NEXT: .seh_endfunclet
+; CHECK-EC-SD-NEXT: .seh_endproc
+;
+; CHECK-GI-LABEL: call_copy_notpod:
+; CHECK-GI: .seh_proc call_copy_notpod
+; CHECK-GI-NEXT: // %bb.0:
+; CHECK-GI-NEXT: stp x19, x20, [sp, #-32]! // 16-byte Folded Spill
+; CHECK-GI-NEXT: .seh_save_regp_x x19, 32
+; CHECK-GI-NEXT: str x30, [sp, #16] // 8-byte Spill
+; CHECK-GI-NEXT: .seh_save_reg x30, 16
+; CHECK-GI-NEXT: .seh_endprologue
+; CHECK-GI-NEXT: adrp x19, NotPod
+; CHECK-GI-NEXT: add x19, x19, :lo12:NotPod
+; CHECK-GI-NEXT: adrp x20, NotPod
+; CHECK-GI-NEXT: mov x0, x19
+; CHECK-GI-NEXT: bl copy_notpod
+; CHECK-GI-NEXT: str x0, [x20, :lo12:NotPod]
+; CHECK-GI-NEXT: str x1, [x19, #8]
+; CHECK-GI-NEXT: .seh_startepilogue
+; CHECK-GI-NEXT: ldr x30, [sp, #16] // 8-byte Reload
+; CHECK-GI-NEXT: .seh_save_reg x30, 16
+; CHECK-GI-NEXT: ldp x19, x20, [sp], #32 // 16-byte Folded Reload
+; CHECK-GI-NEXT: .seh_save_regp_x x19, 32
+; CHECK-GI-NEXT: .seh_endepilogue
+; CHECK-GI-NEXT: ret
+; CHECK-GI-NEXT: .seh_endfunclet
+; CHECK-GI-NEXT: .seh_endproc
+;
+; CHECK-FAST-LABEL: call_copy_notpod:
+; CHECK-FAST: .seh_proc call_copy_notpod
+; CHECK-FAST-NEXT: // %bb.0:
+; CHECK-FAST-NEXT: sub sp, sp, #16
+; CHECK-FAST-NEXT: .seh_stackalloc 16
+; CHECK-FAST-NEXT: stp x19, x30, [sp] // 16-byte Folded Spill
+; CHECK-FAST-NEXT: .seh_save_lrpair x19, 0
+; CHECK-FAST-NEXT: .seh_endprologue
+; CHECK-FAST-NEXT: adrp x19, NotPod
+; CHECK-FAST-NEXT: add x19, x19, :lo12:NotPod
+; CHECK-FAST-NEXT: mov x0, x19
+; CHECK-FAST-NEXT: bl copy_notpod
+; CHECK-FAST-NEXT: stp x0, x1, [x19]
+; CHECK-FAST-NEXT: .seh_startepilogue
+; CHECK-FAST-NEXT: ldp x19, x30, [sp] // 16-byte Folded Reload
+; CHECK-FAST-NEXT: .seh_save_lrpair x19, 0
+; CHECK-FAST-NEXT: add sp, sp, #16
+; CHECK-FAST-NEXT: .seh_stackalloc 16
+; CHECK-FAST-NEXT: .seh_endepilogue
+; CHECK-FAST-NEXT: ret
+; CHECK-FAST-NEXT: .seh_endfunclet
+; CHECK-FAST-NEXT: .seh_endproc
+;
+; CHECK-EC-GI-LABEL: call_copy_notpod:
+; CHECK-EC-GI: .seh_proc call_copy_notpod
+; CHECK-EC-GI-NEXT: // %bb.0:
+; CHECK-EC-GI-NEXT: sub sp, sp, #16
+; CHECK-EC-GI-NEXT: .seh_stackalloc 16
+; CHECK-EC-GI-NEXT: stp x19, x30, [sp] // 16-byte Folded Spill
+; CHECK-EC-GI-NEXT: .seh_save_lrpair x19, 0
+; CHECK-EC-GI-NEXT: .seh_endprologue
+; CHECK-EC-GI-NEXT: adrp x19, NotPod
+; CHECK-EC-GI-NEXT: add x19, x19, :lo12:NotPod
+; CHECK-EC-GI-NEXT: mov x0, x19
+; CHECK-EC-GI-NEXT: .weak_anti_dep copy_notpod
+; CHECK-EC-GI-NEXT: copy_notpod = "#copy_notpod"
+; CHECK-EC-GI-NEXT: .weak_anti_dep "#copy_notpod"
+; CHECK-EC-GI-NEXT: "#copy_notpod" = copy_notpod
+; CHECK-EC-GI-NEXT: bl "#copy_notpod"
+; CHECK-EC-GI-NEXT: stp x0, x1, [x19]
+; CHECK-EC-GI-NEXT: .seh_startepilogue
+; CHECK-EC-GI-NEXT: ldp x19, x30, [sp] // 16-byte Folded Reload
+; CHECK-EC-GI-NEXT: .seh_save_lrpair x19, 0
+; CHECK-EC-GI-NEXT: add sp, sp, #16
+; CHECK-EC-GI-NEXT: .seh_stackalloc 16
+; CHECK-EC-GI-NEXT: .seh_endepilogue
+; CHECK-EC-GI-NEXT: ret
+; CHECK-EC-GI-NEXT: .seh_endfunclet
+; CHECK-EC-GI-NEXT: .seh_endproc
+
%x = call [2 x i64] @copy_notpod(ptr @NotPod)
store [2 x i64] %x, ptr @NotPod
ret void
diff --git a/llvm/test/CodeGen/AArch64/arm64-windows-tailcall.ll b/llvm/test/CodeGen/AArch64/arm64-windows-tailcall.ll
index cd0a77a280aec2..e81bcd07badc09 100644
--- a/llvm/test/CodeGen/AArch64/arm64-windows-tailcall.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-windows-tailcall.ll
@@ -1,15 +1,32 @@
-; FIXME: Add tests for global-isel/fast-isel.
-
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc < %s -mtriple=arm64-windows | FileCheck %s
+; RUN: llc < %s -mtriple=arm64-windows -fast-isel=1 -global-isel=0 | FileCheck %s
+; RUN: llc < %s -mtriple=arm64-windows -fast-isel=0 -global-isel=1 -global-isel-abort=0 | FileCheck %s
%class.C = type { [1 x i32] }
-define dso_local void @"?bar"(ptr inreg noalias sret(%class.C) %agg.result) {
+define dso_local void @bar(ptr inreg noalias sret(%class.C) %agg.result) {
+; CHECK-LABEL: bar:
+; CHECK: .seh_proc bar
+; CHECK-NEXT: // %bb.0: // %entry
+; CHECK-NEXT: sub sp, sp, #16
+; CHECK-NEXT: .seh_stackalloc 16
+; CHECK-NEXT: stp x19, x30, [sp] // 16-byte Folded Spill
+; CHECK-NEXT: .seh_save_lrpair x19, 0
+; CHECK-NEXT: .seh_endprologue
+; CHECK-NEXT: mov x19, x0
+; CHECK-NEXT: bl "?foo"
+; CHECK-NEXT: mov x0, x19
+; CHECK-NEXT: .seh_startepilogue
+; CHECK-NEXT: ldp x19, x30, [sp] // 16-byte Folded Reload
+; CHECK-NEXT: .seh_save_lrpair x19, 0
+; CHECK-NEXT: add sp, sp, #16
+; CHECK-NEXT: .seh_stackalloc 16
+; CHECK-NEXT: .seh_endepilogue
+; CHECK-NEXT: ret
+; CHECK-NEXT: .seh_endfunclet
+; CHECK-NEXT: .seh_endproc
entry:
-; CHECK-LABEL: bar
-; CHECK: mov x19, x0
-; CHECK: bl "?foo"
-; CHECK: mov x0, x19
tail call void @"?foo"(ptr dereferenceable(4) %agg.result)
ret void
@@ -22,10 +39,28 @@ declare void @inreg_callee(ptr, ptr inreg sret(%class.C))
define void @inreg_caller_1(ptr %a, ptr inreg sret(%class.C) %b) {
; A different value is passed to the inreg parameter, so tail call is not possible.
-; CHECK-LABEL: inreg_caller_1
-; CHECK: mov x19, x1
-; CHECK: bl inreg_callee
-; CHECK: mov x0, x19
+; CHECK-LABEL: inreg_caller_1:
+; CHECK: .seh_proc inreg_caller_1
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #16
+; CHECK-NEXT: .seh_stackalloc 16
+; CHECK-NEXT: stp x19, x30, [sp] // 16-byte Folded Spill
+; CHECK-NEXT: .seh_save_lrpair x19, 0
+; CHECK-NEXT: .seh_endprologue
+; CHECK-NEXT: mov x19, x1
+; CHECK-NEXT: mov x1, x0
+; CHECK-NEXT: mov x0, x19
+; CHECK-NEXT: bl inreg_callee
+; CHECK-NEXT: mov x0, x19
+; CHECK-NEXT: .seh_startepilogue
+; CHECK-NEXT: ldp x19, x30, [sp] // 16-byte Folded Reload
+; CHECK-NEXT: .seh_save_lrpair x19, 0
+; CHECK-NEXT: add sp, sp, #16
+; CHECK-NEXT: .seh_stackalloc 16
+; CHECK-NEXT: .seh_endepilogue
+; CHECK-NEXT: ret
+; CHECK-NEXT: .seh_endfunclet
+; CHECK-NEXT: .seh_endproc
tail call void @inreg_callee(ptr %b, ptr inreg sret(%class.C) %a)
ret void
@@ -34,8 +69,9 @@ define void @inreg_caller_1(ptr %a, ptr inreg sret(%class.C) %b) {
define void @inreg_caller_2(ptr %a, ptr inreg sret(%class.C) %b) {
; The inreg attribute and value line up between caller and callee, so it can
; be tail called.
-; CHECK-LABEL: inreg_caller_2
-; CHECK: b inreg_callee
+; CHECK-LABEL: inreg_caller_2:
+; CHECK: // %bb.0:
+; CHECK-NEXT: b inreg_callee
tail call void @inreg_callee(ptr %a, ptr inreg sret(%class.C) %b)
ret void
More information about the llvm-branch-commits
mailing list