Skip to content

Commit 1cca0e2

Browse files
authored
Merge pull request #2855 from compnerd/compnerd/async-frame-lowering
X86: enable proper frame lowering for swift async on Win64
2 parents 2c9ec0c + c0f2dad commit 1cca0e2

File tree

3 files changed

+198
-0
lines changed

3 files changed

+198
-0
lines changed

llvm/lib/Target/X86/X86FrameLowering.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1518,6 +1518,48 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
15181518
.setMIFlag(MachineInstr::FrameSetup);
15191519
}
15201520
}
1521+
1522+
if (IsWin64Prologue && !IsFunclet) {
1523+
if (X86FI->hasSwiftAsyncContext()) {
1524+
// Before we update the live frame pointer we have to ensure there's a
1525+
// valid (or null) asynchronous context in its slot just before FP in
1526+
// the frame record, so store it now.
1527+
const auto &Attrs = MF.getFunction().getAttributes();
1528+
1529+
if (Attrs.hasAttrSomewhere(Attribute::SwiftAsync)) {
1530+
// We have an initial context in r14, store it just before the frame
1531+
// pointer.
1532+
BuildMI(MBB, MBBI, DL, TII.get(X86::PUSH64r))
1533+
.addReg(X86::R14)
1534+
.setMIFlag(MachineInstr::FrameSetup);
1535+
} else {
1536+
// No initial context, store null so that there's no pointer that
1537+
// could be misused.
1538+
BuildMI(MBB, MBBI, DL, TII.get(X86::PUSH64i8))
1539+
.addImm(0)
1540+
.setMIFlag(MachineInstr::FrameSetup);
1541+
}
1542+
1543+
if (NeedsWinCFI) {
1544+
HasWinCFI = true;
1545+
BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_PushReg))
1546+
.addImm(X86::R14)
1547+
.setMIFlag(MachineInstr::FrameSetup);
1548+
}
1549+
1550+
BuildMI(MBB, MBBI, DL, TII.get(X86::LEA64r), FramePtr)
1551+
.addUse(X86::RSP)
1552+
.addImm(1)
1553+
.addUse(X86::NoRegister)
1554+
.addImm(8)
1555+
.addUse(X86::NoRegister)
1556+
.setMIFlag(MachineInstr::FrameSetup);
1557+
BuildMI(MBB, MBBI, DL, TII.get(X86::SUB64ri8), X86::RSP)
1558+
.addUse(X86::RSP)
1559+
.addImm(8)
1560+
.setMIFlag(MachineInstr::FrameSetup);
1561+
}
1562+
}
15211563
} else {
15221564
assert(!IsFunclet && "funclets without FPs not yet implemented");
15231565
NumBytes = StackSize - X86FI->getCalleeSavedFrameSize();
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
; RUN: llc -mtriple=x86_64-unknown-windows-msvc %s -o - | FileCheck %s
2+
; RUN: llc -mtriple=i686-windows-msvc %s -o - | FileCheck %s --check-prefix=CHECK-32
3+
4+
define void @simple(i8* swiftasync %ctx) "frame-pointer"="all" {
5+
; CHECK-LABEL: simple:
6+
; CHECK: btsq $60, %rbp
7+
; CHECK: pushq %rbp
8+
; CHECK: pushq %r14
9+
; CHECK: leaq 8(%rsp), %rbp
10+
11+
; [...]
12+
13+
; CHECK: addq $16, %rsp
14+
; CHECK: popq %rbp
15+
; CHECK: btrq $60, %rbp
16+
; CHECK: retq
17+
18+
; CHECK-32-LABEL: simple:
19+
; CHECK-32: movl 8(%ebp), [[TMP:%.*]]
20+
; CHECK-32: movl [[TMP]], {{.*}}(%ebp)
21+
22+
ret void
23+
}
24+
25+
define void @more_csrs(i8* swiftasync %ctx) "frame-pointer"="all" {
26+
; CHECK-LABEL: more_csrs:
27+
; CHECK: btsq $60, %rbp
28+
; CHECK: pushq %rbp
29+
; CHECK: .seh_pushreg %rbp
30+
; CHECK: pushq %r14
31+
; CHECK: .seh_pushreg %r14
32+
; CHECK: leaq 8(%rsp), %rbp
33+
; CHECK: subq $8, %rsp
34+
; CHECK: pushq %r15
35+
; CHECK: .seh_pushreg %r15
36+
37+
; [...]
38+
39+
; CHECK: popq %r15
40+
; CHECK: addq $16, %rsp
41+
; CHECK: popq %rbp
42+
; CHECK: btrq $60, %rbp
43+
; CHECK: retq
44+
call void asm sideeffect "", "~{r15}"()
45+
ret void
46+
}
47+
48+
define void @locals(i8* swiftasync %ctx) "frame-pointer"="all" {
49+
; CHECK-LABEL: locals:
50+
; CHECK: btsq $60, %rbp
51+
; CHECK: pushq %rbp
52+
; CHECK: .seh_pushreg %rbp
53+
; CHECK: pushq %r14
54+
; CHECK: .seh_pushreg %r14
55+
; CHECK: leaq 8(%rsp), %rbp
56+
; CHECK: subq $88, %rsp
57+
58+
; CHECK: leaq -48(%rbp), %rcx
59+
; CHECK: callq bar
60+
61+
; CHECK: addq $80, %rsp
62+
; CHECK: addq $16, %rsp
63+
; CHECK: popq %rbp
64+
; CHECK: btrq $60, %rbp
65+
; CHECK: retq
66+
67+
%var = alloca i32, i32 10
68+
call void @bar(i32* %var)
69+
ret void
70+
}
71+
72+
define void @use_input_context(i8* swiftasync %ctx, i8** %ptr) "frame-pointer"="all" {
73+
; CHECK-LABEL: use_input_context:
74+
; CHECK: movq %r14, (%rcx)
75+
76+
store i8* %ctx, i8** %ptr
77+
ret void
78+
}
79+
80+
define i8** @context_in_func() "frame-pointer"="non-leaf" {
81+
; CHECK-LABEL: context_in_func:
82+
; CHECK: leaq -8(%rbp), %rax
83+
84+
; CHECK-32-LABEL: context_in_func
85+
; CHECK-32: movl %esp, %eax
86+
87+
%ptr = call i8** @llvm.swift.async.context.addr()
88+
ret i8** %ptr
89+
}
90+
91+
define void @write_frame_context(i8* swiftasync %ctx, i8* %newctx) "frame-pointer"="non-leaf" {
92+
; CHECK-LABEL: write_frame_context:
93+
; CHECK: movq %rbp, [[TMP:%.*]]
94+
; CHECK: subq $8, [[TMP]]
95+
; CHECK: movq %rcx, ([[TMP]])
96+
97+
%ptr = call i8** @llvm.swift.async.context.addr()
98+
store i8* %newctx, i8** %ptr
99+
ret void
100+
}
101+
102+
define void @simple_fp_elim(i8* swiftasync %ctx) "frame-pointer"="non-leaf" {
103+
; CHECK-LABEL: simple_fp_elim:
104+
; CHECK-NOT: btsq
105+
106+
ret void
107+
}
108+
109+
declare void @bar(i32*)
110+
declare i8** @llvm.swift.async.context.addr()
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
; RUN: llc -mtriple x86_64-unknown-windows-msvc %s -o - | FileCheck %s
2+
3+
4+
declare swifttailcc void @swifttail_callee()
5+
define swifttailcc void @swifttail() {
6+
; CHECK-LABEL: swifttail:
7+
; CHECK-NOT: popq %r14
8+
call void asm "","~{r14}"()
9+
tail call swifttailcc void @swifttail_callee()
10+
ret void
11+
}
12+
13+
define void @has_swiftasync(i8* swiftasync %in) {
14+
; CHECK-LABEL: has_swiftasync:
15+
; CHECK: popq %r14
16+
call void asm "","~{r14}"()
17+
ret void
18+
}
19+
20+
; It's impossible to get a tail call from a function without a swiftasync
21+
; parameter to one with unless the CC is swifttailcc. So it doesn't matter
22+
; whether r14 is callee-saved in this case.
23+
define void @calls_swiftasync() {
24+
; CHECK-LABEL: calls_swiftasync:
25+
; CHECK-NOT: jmpq _has_swiftasync
26+
call void asm "","~{r14}"()
27+
tail call void @has_swiftasync(i8* swiftasync null)
28+
ret void
29+
}
30+
31+
define swifttailcc void @no_preserve_swiftself() {
32+
; CHECK-LABEL: no_preserve_swiftself:
33+
; CHECK-NOT: popq %r13
34+
call void asm "","~{r13}"()
35+
ret void
36+
}
37+
38+
declare swifttailcc i8* @SwiftSelf(i8 * swiftasync %context, i8* swiftself %closure)
39+
define swiftcc i8* @CallSwiftSelf(i8* swiftself %closure, i8* %context) {
40+
; CHECK-LABEL: CallSwiftSelf:
41+
; CHECK: pushq %r13
42+
;call void asm "","~{r13}"() ; We get a push r13 but why not with the call
43+
; below?
44+
%res = call swifttailcc i8* @SwiftSelf(i8 * swiftasync %context, i8* swiftself %closure)
45+
ret i8* %res
46+
}

0 commit comments

Comments
 (0)