Skip to content

Commit 58b4951

Browse files
authored
Aarch64: Emit a minimal SEH prologue when needed (#158173)
In some cases, with very simple thunks, it is possible that the `.seh_endprologue` is not emitted. This causes issues in the assembler because the epilogue ends up starting before the prologue has ended. Bug: swiftlang#11377
1 parent 8b445ab commit 58b4951

File tree

3 files changed

+63
-2
lines changed

3 files changed

+63
-2
lines changed

llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,13 @@ void AArch64PrologueEmitter::emitPrologue() {
541541
// to determine the end of the prologue.
542542
DebugLoc DL;
543543

544+
// In some cases, particularly with CallingConv::SwiftTail, it is possible to
545+
// have a tail-call where the caller only needs to adjust the stack pointer in
546+
// the epilogue. In this case, we still need to emit a SEH prologue sequence.
547+
// See `seh-minimal-prologue-epilogue.ll` test cases.
548+
if (AFI->getArgumentStackToRestore())
549+
HasWinCFI = true;
550+
544551
if (AFI->shouldSignReturnAddress(MF)) {
545552
// If pac-ret+leaf is in effect, PAUTH_PROLOGUE pseudo instructions
546553
// are inserted by emitPacRetPlusLeafHardening().
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
; RUN: llc -mtriple=aarch64-windows %s -o - | FileCheck %s
2+
3+
; This test verifies that functions requiring Windows CFI that have minimal
4+
; or no prologue instructions still emit proper SEH directives, specifically
5+
; ensuring .seh_endprologue is emitted before .seh_startepilogue.
6+
;
7+
; This reproduces the issue where Swift async functions with swifttailcc
8+
; calling convention would fail with:
9+
; "error: starting epilogue (.seh_startepilogue) before prologue has ended (.seh_endprologue)"
10+
11+
; Test 1: Swift-style tail call function with minimal prologue
12+
define swifttailcc void @test_swifttailcc_minimal(ptr %async_ctx, ptr %arg1, ptr %arg2) {
13+
; CHECK-LABEL: test_swifttailcc_minimal:
14+
; CHECK-NOT: .seh_proc test_swifttailcc_minimal
15+
; CHECK-NOT: .seh_endprologue
16+
; CHECK-NOT: .seh_startepilogue
17+
; CHECK-NOT: .seh_endepilogue
18+
; CHECK-NOT: .seh_endproc
19+
entry:
20+
%ptr1 = getelementptr inbounds i8, ptr %async_ctx, i64 16
21+
%ptr2 = getelementptr inbounds i8, ptr %async_ctx, i64 24
22+
store ptr %arg1, ptr %ptr1, align 8
23+
store ptr %arg2, ptr %ptr2, align 8
24+
musttail call swifttailcc void @external_swift_function(ptr %async_ctx, ptr %arg1)
25+
ret void
26+
}
27+
28+
; Test 2: Function similar to the original failing case
29+
define linkonce_odr hidden swifttailcc void @test_linkonce_swifttailcc(ptr swiftasync %async_ctx, ptr %arg1, ptr noalias dereferenceable(40) %arg2, ptr %arg3, i64 %value, ptr %arg4, ptr %arg5, ptr %arg6, i1 %flag, ptr %arg7, ptr noalias dereferenceable(40) %arg8) {
30+
; CHECK-LABEL: test_linkonce_swifttailcc:
31+
; CHECK-NEXT: .seh_proc
32+
; CHECK: .seh_endprologue
33+
; CHECK: .seh_startepilogue
34+
; CHECK: .seh_endepilogue
35+
; CHECK: .seh_endproc
36+
entry:
37+
%frame_ptr = getelementptr inbounds nuw i8, ptr %async_ctx, i64 16
38+
%ctx1 = getelementptr inbounds nuw i8, ptr %async_ctx, i64 400
39+
%ctx2 = getelementptr inbounds nuw i8, ptr %async_ctx, i64 1168
40+
%spill1 = getelementptr inbounds nuw i8, ptr %async_ctx, i64 2392
41+
store ptr %arg8, ptr %spill1, align 8
42+
%spill2 = getelementptr inbounds nuw i8, ptr %async_ctx, i64 2384
43+
store ptr %arg7, ptr %spill2, align 8
44+
%spill3 = getelementptr inbounds nuw i8, ptr %async_ctx, i64 2225
45+
store i1 %flag, ptr %spill3, align 1
46+
%spill4 = getelementptr inbounds nuw i8, ptr %async_ctx, i64 2376
47+
store ptr %arg6, ptr %spill4, align 8
48+
musttail call swifttailcc void @external_swift_continuation(ptr swiftasync %async_ctx, i64 0, i64 0)
49+
ret void
50+
}
51+
52+
declare swifttailcc void @external_swift_function(ptr, ptr)
53+
declare swifttailcc void @external_swift_continuation(ptr swiftasync, i64, i64)

llvm/test/CodeGen/AArch64/wincfi-seh-only-in-epilogue.ll renamed to llvm/test/CodeGen/AArch64/wincfi-minimal-seh-prologue.ll

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ entry:
55
ret void
66
}
77

8-
; Check that there is no .seh_endprologue but there is seh_startepilogue/seh_endepilogue.
9-
; CHECK-NOT: .seh_endprologue
8+
; Check that there is a minimal SEH prologue with seh_startepilogue/seh_endepilogue.
9+
; CHECK: .seh_proc test
10+
; CHECK: .seh_endprologue
1011
; CHECK: .seh_startepilogue
1112
; CHECK: add sp, sp, #48
1213
; CHECK: .seh_stackalloc 48

0 commit comments

Comments
 (0)