[llvm] 5d070c8 - SwiftAsync: use runtime-provided flag for extended frame if back-deploying

Tim Northover via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 13 05:54:51 PDT 2021


Author: Tim Northover
Date: 2021-09-13T13:54:46+01:00
New Revision: 5d070c8259ac64355a5b5d3fd28710a335c2a16f

URL: https://github.com/llvm/llvm-project/commit/5d070c8259ac64355a5b5d3fd28710a335c2a16f
DIFF: https://github.com/llvm/llvm-project/commit/5d070c8259ac64355a5b5d3fd28710a335c2a16f.diff

LOG: 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.

Added: 
    llvm/test/CodeGen/AArch64/swift-dynamic-async-frame.ll
    llvm/test/CodeGen/X86/swift-dynamic-async-frame.ll

Modified: 
    llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
    llvm/lib/Target/AArch64/AArch64Subtarget.h
    llvm/lib/Target/X86/X86FrameLowering.cpp
    llvm/lib/Target/X86/X86Subtarget.h
    llvm/test/CodeGen/AArch64/swift-async.ll
    llvm/test/CodeGen/X86/swift-async.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 779a3b0c4ef9b..02421b8f2d877 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -1158,11 +1158,23 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
   // ORR is sufficient, it is assumed a Swift kernel would initialize the TBI
   // bits so that is still true.
   if (HasFP && AFI->hasSwiftAsyncContext()) {
-    // ORR x29, x29, #0x1000_0000_0000_0000
-    BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXri), AArch64::FP)
-        .addUse(AArch64::FP)
-        .addImm(0x1100)
-        .setMIFlag(MachineInstr::FrameSetup);
+    if  (Subtarget.swiftAsyncContextIsDynamicallySet()) {
+      // The special symbol below is absolute and has a *value* that can be
+      // combined with the frame pointer to signal an extended frame.
+      BuildMI(MBB, MBBI, DL, TII->get(AArch64::LOADgot), AArch64::X16)
+          .addExternalSymbol("swift_async_extendedFramePointerFlags",
+                             AArch64II::MO_GOT);
+      BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXrs), AArch64::FP)
+          .addUse(AArch64::FP)
+          .addUse(AArch64::X16)
+          .addImm(Subtarget.isTargetILP32() ? 32 : 0);
+    } else {
+      // ORR x29, x29, #0x1000_0000_0000_0000
+      BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXri), AArch64::FP)
+          .addUse(AArch64::FP)
+          .addImm(0x1100)
+          .setMIFlag(MachineInstr::FrameSetup);
+    }
   }
 
   // All calls are tail calls in GHC calling conv, and functions have no

diff  --git a/llvm/lib/Target/AArch64/AArch64Subtarget.h b/llvm/lib/Target/AArch64/AArch64Subtarget.h
index 3000c7b4f6e09..38e09215fd7da 100644
--- a/llvm/lib/Target/AArch64/AArch64Subtarget.h
+++ b/llvm/lib/Target/AArch64/AArch64Subtarget.h
@@ -598,6 +598,31 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
     }
   }
 
+  /// Return whether FrameLowering should always set the "extended frame
+  /// present" bit in FP, or set it based on a symbol in the runtime.
+  bool swiftAsyncContextIsDynamicallySet() const {
+    // Older OS versions (particularly system unwinders) are confused by the
+    // Swift extended frame, so when building code that might be run on them we
+    // must dynamically query the concurrency library to determine whether
+    // extended frames should be flagged as present.
+    const Triple &TT = getTargetTriple();
+
+    unsigned Major, Minor, Micro;
+    TT.getOSVersion(Major, Minor, Micro);
+    switch(TT.getOS()) {
+    default:
+      return false;
+    case Triple::IOS:
+    case Triple::TvOS:
+      return Major < 15;
+    case Triple::WatchOS:
+      return Major < 8;
+    case Triple::MacOSX:
+    case Triple::Darwin:
+      return Major < 12;
+    }
+  }
+
   void mirFileLoaded(MachineFunction &MF) const override;
 
   // Return the known range for the bit length of SVE data registers. A value

diff  --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp
index a2b81a41e7474..15d5f8b4c9787 100644
--- a/llvm/lib/Target/X86/X86FrameLowering.cpp
+++ b/llvm/lib/Target/X86/X86FrameLowering.cpp
@@ -1364,11 +1364,23 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
   unsigned StackProbeSize = STI.getTargetLowering()->getStackProbeSize(MF);
 
   if (HasFP && X86FI->hasSwiftAsyncContext()) {
-    BuildMI(MBB, MBBI, DL, TII.get(X86::BTS64ri8),
-            MachineFramePtr)
-        .addUse(MachineFramePtr)
-        .addImm(60)
-        .setMIFlag(MachineInstr::FrameSetup);
+    if (STI.swiftAsyncContextIsDynamicallySet()) {
+      // The special symbol below is absolute and has a *value* suitable to be
+      // combined with the frame pointer directly.
+      BuildMI(MBB, MBBI, DL, TII.get(X86::OR64rm), MachineFramePtr)
+          .addUse(MachineFramePtr)
+          .addUse(X86::RIP)
+          .addImm(1)
+          .addUse(X86::NoRegister)
+          .addExternalSymbol("swift_async_extendedFramePointerFlags",
+                             X86II::MO_GOTPCREL)
+          .addUse(X86::NoRegister);
+    } else {
+      BuildMI(MBB, MBBI, DL, TII.get(X86::BTS64ri8), MachineFramePtr)
+          .addUse(MachineFramePtr)
+          .addImm(60)
+          .setMIFlag(MachineInstr::FrameSetup);
+    }
   }
 
   // Re-align the stack on 64-bit if the x86-interrupt calling convention is

diff  --git a/llvm/lib/Target/X86/X86Subtarget.h b/llvm/lib/Target/X86/X86Subtarget.h
index 8021d289d0e55..796bd83f2a273 100644
--- a/llvm/lib/Target/X86/X86Subtarget.h
+++ b/llvm/lib/Target/X86/X86Subtarget.h
@@ -942,6 +942,31 @@ class X86Subtarget final : public X86GenSubtargetInfo {
   /// Return true if the subtarget allows calls to immediate address.
   bool isLegalToCallImmediateAddr() const;
 
+  /// Return whether FrameLowering should always set the "extended frame
+  /// present" bit in FP, or set it based on a symbol in the runtime.
+  bool swiftAsyncContextIsDynamicallySet() const {
+    // Older OS versions (particularly system unwinders) are confused by the
+    // Swift extended frame, so when building code that might be run on them we
+    // must dynamically query the concurrency library to determine whether
+    // extended frames should be flagged as present.
+    const Triple &TT = getTargetTriple();
+
+    unsigned Major, Minor, Micro;
+    TT.getOSVersion(Major, Minor, Micro);
+    switch(TT.getOS()) {
+    default:
+      return false;
+    case Triple::IOS:
+    case Triple::TvOS:
+      return Major < 15;
+    case Triple::WatchOS:
+      return Major < 8;
+    case Triple::MacOSX:
+    case Triple::Darwin:
+      return Major < 12;
+    }
+  }
+
   /// If we are using indirect thunks, we need to expand indirectbr to avoid it
   /// lowering to an actual indirect jump.
   bool enableIndirectBrExpand() const override {

diff  --git a/llvm/test/CodeGen/AArch64/swift-async.ll b/llvm/test/CodeGen/AArch64/swift-async.ll
index 6042e27408ac7..e2d0eb8b480c4 100644
--- a/llvm/test/CodeGen/AArch64/swift-async.ll
+++ b/llvm/test/CodeGen/AArch64/swift-async.ll
@@ -1,6 +1,6 @@
-; RUN: llc -mtriple=arm64-apple-ios %s -o - | FileCheck %s --check-prefixes=CHECK-NOAUTH,CHECK
-; RUN: llc -mtriple=arm64-apple-ios -mcpu=apple-a13 %s -o - | FileCheck %s --check-prefixes=CHECK-NOAUTH,CHECK
-; RUN: llc -mtriple=arm64e-apple-ios %s -o - | FileCheck %s --check-prefixes=CHECK-AUTH,CHECK
+; RUN: llc -mtriple=arm64-apple-ios15 %s -o - | FileCheck %s --check-prefixes=CHECK-NOAUTH,CHECK
+; RUN: llc -mtriple=arm64-apple-ios15 -mcpu=apple-a13 %s -o - | FileCheck %s --check-prefixes=CHECK-NOAUTH,CHECK
+; RUN: llc -mtriple=arm64e-apple-ios15 %s -o - | FileCheck %s --check-prefixes=CHECK-AUTH,CHECK
 
 ; Important details in prologue:
 ;   * x22 is stored just below x29

diff  --git a/llvm/test/CodeGen/AArch64/swift-dynamic-async-frame.ll b/llvm/test/CodeGen/AArch64/swift-dynamic-async-frame.ll
new file mode 100644
index 0000000000000..6b17b49403f2f
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/swift-dynamic-async-frame.ll
@@ -0,0 +1,25 @@
+; RUN: llc -mtriple arm64-apple-ios15.0.0 %s -o - | FileCheck %s --check-prefix=CHECK-STATIC
+; RUN: llc -mtriple arm64-apple-ios14.9.0 %s -o - | FileCheck %s --check-prefix=CHECK-DYNAMIC
+; RUN: llc -mtriple arm64-apple-tvos15.0.0 %s -o - | FileCheck %s --check-prefix=CHECK-STATIC
+; RUN: llc -mtriple arm64-apple-tvos14.9.0 %s -o - | FileCheck %s --check-prefix=CHECK-DYNAMIC
+; RUN: llc -mtriple arm64-apple-macosx12.0.0 %s -o - | FileCheck %s --check-prefix=CHECK-STATIC
+; RUN: llc -mtriple arm64-apple-macosx11.9.0 %s -o - | FileCheck %s --check-prefix=CHECK-DYNAMIC
+; RUN: llc -mtriple arm64_32-apple-watchos8.0.0 %s -o - | FileCheck %s --check-prefix=CHECK-STATIC
+; RUN: llc -mtriple arm64_32-apple-watchos7.9.0 %s -o - | FileCheck %s --check-prefix=CHECK-DYNAMIC-32
+
+; CHECK-STATIC-LABEL: foo:
+; CHECK-STATIC: orr x29, x29, #0x1000000000000000
+
+; CHECK-DYNAMIC-LABEL: foo:
+; CHECK-DYNAMIC: adrp x16, _swift_async_extendedFramePointerFlags at GOTPAGE
+; CHECK-DYNAMIC: ldr x16, [x16, _swift_async_extendedFramePointerFlags at GOTPAGEOFF]
+; CHECK-DYNAMIC: orr x29, x29, x16
+
+; CHECK-DYNAMIC-32-LABEL: foo:
+; CHECK-DYNAMIC-32: adrp x16, _swift_async_extendedFramePointerFlags at GOTPAGE
+; CHECK-DYNAMIC-32: ldr w16, [x16, _swift_async_extendedFramePointerFlags at GOTPAGEOFF]
+; CHECK-DYNAMIC-32: orr x29, x29, x16, lsl #32
+
+define void @foo(i8* swiftasync) "frame-pointer"="all" {
+  ret void
+}

diff  --git a/llvm/test/CodeGen/X86/swift-async.ll b/llvm/test/CodeGen/X86/swift-async.ll
index 9716fe7364896..c671917fd0d4f 100644
--- a/llvm/test/CodeGen/X86/swift-async.ll
+++ b/llvm/test/CodeGen/X86/swift-async.ll
@@ -1,4 +1,4 @@
-; RUN: llc -mtriple=x86_64-apple-darwin %s -o - | FileCheck %s
+; RUN: llc -mtriple=x86_64-apple-macosx12.0 %s -o - | FileCheck %s
 ; RUN: llc -mtriple=i686-apple-darwin %s -o - | FileCheck %s --check-prefix=CHECK-32
 
 

diff  --git a/llvm/test/CodeGen/X86/swift-dynamic-async-frame.ll b/llvm/test/CodeGen/X86/swift-dynamic-async-frame.ll
new file mode 100644
index 0000000000000..8719aee17d53b
--- /dev/null
+++ b/llvm/test/CodeGen/X86/swift-dynamic-async-frame.ll
@@ -0,0 +1,12 @@
+; RUN: llc -mtriple x86_64-apple-macosx12.0.0 %s -o - | FileCheck %s --check-prefix=CHECK-STATIC
+; RUN: llc -mtriple x86_64-apple-macosx11.9.0 %s -o - | FileCheck %s --check-prefix=CHECK-DYNAMIC
+
+; CHECK-STATIC-LABEL: foo:
+; CHECK-STATIC: btsq $60, %rbp
+
+; CHECK-DYNAMIC-LABEL: foo:
+; CHECK-DYNAMIC: orq _swift_async_extendedFramePointerFlags at GOTPCREL(%rip), %rbp
+
+define void @foo(i8* swiftasync) "frame-pointer"="all" {
+  ret void
+}


        


More information about the llvm-commits mailing list