Skip to content

Commit 56b171f

Browse files
TNorthoveraschwaighofer
authored andcommitted
SwiftAsync: use runtime-provided flag for extended frame if back-deploying
When back-deploying Swift async code we can't always toggle the flag showing an extended frame is present because it will confuse unwinders on systems released before this feature. So in cases where the code might run there, we `or` in a mask provided by the runtime (as an absolute symbol) telling us whether the unwinders can cope. When deploying only for newer OSs, we can still hard-code the bit-set for greater efficiency. rdar://79357449
1 parent 5852614 commit 56b171f

File tree

8 files changed

+125
-14
lines changed

8 files changed

+125
-14
lines changed

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,11 +1180,23 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
11801180
// ORR is sufficient, it is assumed a Swift kernel would initialize the TBI
11811181
// bits so that is still true.
11821182
if (HasFP && AFI->hasSwiftAsyncContext()) {
1183-
// ORR x29, x29, #0x1000_0000_0000_0000
1184-
BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXri), AArch64::FP)
1185-
.addUse(AArch64::FP)
1186-
.addImm(0x1100)
1187-
.setMIFlag(MachineInstr::FrameSetup);
1183+
if (Subtarget.swiftAsyncContextIsDynamicallySet()) {
1184+
// The special symbol below is absolute and has a *value* that can be
1185+
// combined with the frame pointer to signal an extended frame.
1186+
BuildMI(MBB, MBBI, DL, TII->get(AArch64::LOADgot), AArch64::X16)
1187+
.addExternalSymbol("swift_async_extendedFramePointerFlags",
1188+
AArch64II::MO_GOT);
1189+
BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXrs), AArch64::FP)
1190+
.addUse(AArch64::FP)
1191+
.addUse(AArch64::X16)
1192+
.addImm(Subtarget.isTargetILP32() ? 32 : 0);
1193+
} else {
1194+
// ORR x29, x29, #0x1000_0000_0000_0000
1195+
BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXri), AArch64::FP)
1196+
.addUse(AArch64::FP)
1197+
.addImm(0x1100)
1198+
.setMIFlag(MachineInstr::FrameSetup);
1199+
}
11881200
}
11891201

11901202
// All calls are tail calls in GHC calling conv, and functions have no

llvm/lib/Target/AArch64/AArch64Subtarget.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,31 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
598598
}
599599
}
600600

601+
/// Return whether FrameLowering should always set the "extended frame
602+
/// present" bit in FP, or set it based on a symbol in the runtime.
603+
bool swiftAsyncContextIsDynamicallySet() const {
604+
// Older OS versions (particularly system unwinders) are confused by the
605+
// Swift extended frame, so when building code that might be run on them we
606+
// must dynamically query the concurrency library to determine whether
607+
// extended frames should be flagged as present.
608+
const Triple &TT = getTargetTriple();
609+
610+
unsigned Major, Minor, Micro;
611+
TT.getOSVersion(Major, Minor, Micro);
612+
switch(TT.getOS()) {
613+
default:
614+
return false;
615+
case Triple::IOS:
616+
case Triple::TvOS:
617+
return Major < 15;
618+
case Triple::WatchOS:
619+
return Major < 8;
620+
case Triple::MacOSX:
621+
case Triple::Darwin:
622+
return Major < 12;
623+
}
624+
}
625+
601626
void mirFileLoaded(MachineFunction &MF) const override;
602627

603628
// Return the known range for the bit length of SVE data registers. A value

llvm/lib/Target/X86/X86FrameLowering.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,11 +1363,23 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
13631363
unsigned StackProbeSize = STI.getTargetLowering()->getStackProbeSize(MF);
13641364

13651365
if (HasFP && X86FI->hasSwiftAsyncContext()) {
1366-
BuildMI(MBB, MBBI, DL, TII.get(X86::BTS64ri8),
1367-
MachineFramePtr)
1368-
.addUse(MachineFramePtr)
1369-
.addImm(60)
1370-
.setMIFlag(MachineInstr::FrameSetup);
1366+
if (STI.swiftAsyncContextIsDynamicallySet()) {
1367+
// The special symbol below is absolute and has a *value* suitable to be
1368+
// combined with the frame pointer directly.
1369+
BuildMI(MBB, MBBI, DL, TII.get(X86::OR64rm), MachineFramePtr)
1370+
.addUse(MachineFramePtr)
1371+
.addUse(X86::RIP)
1372+
.addImm(1)
1373+
.addUse(X86::NoRegister)
1374+
.addExternalSymbol("swift_async_extendedFramePointerFlags",
1375+
X86II::MO_GOTPCREL)
1376+
.addUse(X86::NoRegister);
1377+
} else {
1378+
BuildMI(MBB, MBBI, DL, TII.get(X86::BTS64ri8), MachineFramePtr)
1379+
.addUse(MachineFramePtr)
1380+
.addImm(60)
1381+
.setMIFlag(MachineInstr::FrameSetup);
1382+
}
13711383
}
13721384

13731385
// Re-align the stack on 64-bit if the x86-interrupt calling convention is

llvm/lib/Target/X86/X86Subtarget.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,31 @@ class X86Subtarget final : public X86GenSubtargetInfo {
933933
/// Return true if the subtarget allows calls to immediate address.
934934
bool isLegalToCallImmediateAddr() const;
935935

936+
/// Return whether FrameLowering should always set the "extended frame
937+
/// present" bit in FP, or set it based on a symbol in the runtime.
938+
bool swiftAsyncContextIsDynamicallySet() const {
939+
// Older OS versions (particularly system unwinders) are confused by the
940+
// Swift extended frame, so when building code that might be run on them we
941+
// must dynamically query the concurrency library to determine whether
942+
// extended frames should be flagged as present.
943+
const Triple &TT = getTargetTriple();
944+
945+
unsigned Major, Minor, Micro;
946+
TT.getOSVersion(Major, Minor, Micro);
947+
switch(TT.getOS()) {
948+
default:
949+
return false;
950+
case Triple::IOS:
951+
case Triple::TvOS:
952+
return Major < 15;
953+
case Triple::WatchOS:
954+
return Major < 8;
955+
case Triple::MacOSX:
956+
case Triple::Darwin:
957+
return Major < 12;
958+
}
959+
}
960+
936961
/// If we are using indirect thunks, we need to expand indirectbr to avoid it
937962
/// lowering to an actual indirect jump.
938963
bool enableIndirectBrExpand() const override {

llvm/test/CodeGen/AArch64/swift-async.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
; RUN: llc -mtriple=arm64-apple-ios %s -o - | FileCheck %s --check-prefixes=CHECK-NOAUTH,CHECK
2-
; RUN: llc -mtriple=arm64-apple-ios -mcpu=apple-a13 %s -o - | FileCheck %s --check-prefixes=CHECK-NOAUTH,CHECK
3-
; RUN: llc -mtriple=arm64e-apple-ios %s -o - | FileCheck %s --check-prefixes=CHECK-AUTH,CHECK
1+
; RUN: llc -mtriple=arm64-apple-ios15 %s -o - | FileCheck %s --check-prefixes=CHECK-NOAUTH,CHECK
2+
; RUN: llc -mtriple=arm64-apple-ios15 -mcpu=apple-a13 %s -o - | FileCheck %s --check-prefixes=CHECK-NOAUTH,CHECK
3+
; RUN: llc -mtriple=arm64e-apple-ios15 %s -o - | FileCheck %s --check-prefixes=CHECK-AUTH,CHECK
44

55
; Important details in prologue:
66
; * x22 is stored just below x29
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
; RUN: llc -mtriple arm64-apple-ios15.0.0 %s -o - | FileCheck %s --check-prefix=CHECK-STATIC
2+
; RUN: llc -mtriple arm64-apple-ios14.9.0 %s -o - | FileCheck %s --check-prefix=CHECK-DYNAMIC
3+
; RUN: llc -mtriple arm64-apple-tvos15.0.0 %s -o - | FileCheck %s --check-prefix=CHECK-STATIC
4+
; RUN: llc -mtriple arm64-apple-tvos14.9.0 %s -o - | FileCheck %s --check-prefix=CHECK-DYNAMIC
5+
; RUN: llc -mtriple arm64-apple-macosx12.0.0 %s -o - | FileCheck %s --check-prefix=CHECK-STATIC
6+
; RUN: llc -mtriple arm64-apple-macosx11.9.0 %s -o - | FileCheck %s --check-prefix=CHECK-DYNAMIC
7+
; RUN: llc -mtriple arm64_32-apple-watchos8.0.0 %s -o - | FileCheck %s --check-prefix=CHECK-STATIC
8+
; RUN: llc -mtriple arm64_32-apple-watchos7.9.0 %s -o - | FileCheck %s --check-prefix=CHECK-DYNAMIC-32
9+
10+
; CHECK-STATIC-LABEL: foo:
11+
; CHECK-STATIC: orr x29, x29, #0x1000000000000000
12+
13+
; CHECK-DYNAMIC-LABEL: foo:
14+
; CHECK-DYNAMIC: adrp x16, _swift_async_extendedFramePointerFlags@GOTPAGE
15+
; CHECK-DYNAMIC: ldr x16, [x16, _swift_async_extendedFramePointerFlags@GOTPAGEOFF]
16+
; CHECK-DYNAMIC: orr x29, x29, x16
17+
18+
; CHECK-DYNAMIC-32-LABEL: foo:
19+
; CHECK-DYNAMIC-32: adrp x16, _swift_async_extendedFramePointerFlags@GOTPAGE
20+
; CHECK-DYNAMIC-32: ldr w16, [x16, _swift_async_extendedFramePointerFlags@GOTPAGEOFF]
21+
; CHECK-DYNAMIC-32: orr x29, x29, x16, lsl #32
22+
23+
define void @foo(i8* swiftasync) "frame-pointer"="all" {
24+
ret void
25+
}

llvm/test/CodeGen/X86/swift-async.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: llc -mtriple=x86_64-apple-darwin %s -o - | FileCheck %s
1+
; RUN: llc -mtriple=x86_64-apple-macosx12.0 %s -o - | FileCheck %s
22
; RUN: llc -mtriple=i686-apple-darwin %s -o - | FileCheck %s --check-prefix=CHECK-32
33

44

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
; RUN: llc -mtriple x86_64-apple-macosx12.0.0 %s -o - | FileCheck %s --check-prefix=CHECK-STATIC
2+
; RUN: llc -mtriple x86_64-apple-macosx11.9.0 %s -o - | FileCheck %s --check-prefix=CHECK-DYNAMIC
3+
4+
; CHECK-STATIC-LABEL: foo:
5+
; CHECK-STATIC: btsq $60, %rbp
6+
7+
; CHECK-DYNAMIC-LABEL: foo:
8+
; CHECK-DYNAMIC: orq _swift_async_extendedFramePointerFlags@GOTPCREL(%rip), %rbp
9+
10+
define void @foo(i8* swiftasync) "frame-pointer"="all" {
11+
ret void
12+
}

0 commit comments

Comments
 (0)