Index: llvm/lib/Target/AArch64/AArch64FrameLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64FrameLowering.cpp +++ llvm/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -1158,11 +1158,23 @@ // 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 Index: llvm/lib/Target/AArch64/AArch64Subtarget.h =================================================================== --- llvm/lib/Target/AArch64/AArch64Subtarget.h +++ llvm/lib/Target/AArch64/AArch64Subtarget.h @@ -600,6 +600,31 @@ } } + /// 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 Index: llvm/lib/Target/X86/X86FrameLowering.cpp =================================================================== --- llvm/lib/Target/X86/X86FrameLowering.cpp +++ llvm/lib/Target/X86/X86FrameLowering.cpp @@ -1360,11 +1360,23 @@ 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 Index: llvm/lib/Target/X86/X86Subtarget.h =================================================================== --- llvm/lib/Target/X86/X86Subtarget.h +++ llvm/lib/Target/X86/X86Subtarget.h @@ -937,6 +937,31 @@ /// 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 { Index: llvm/test/CodeGen/AArch64/swift-async.ll =================================================================== --- llvm/test/CodeGen/AArch64/swift-async.ll +++ 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 Index: llvm/test/CodeGen/AArch64/swift-dynamic-async-frame.ll =================================================================== --- /dev/null +++ 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@GOTPAGE +; CHECK-DYNAMIC: ldr x16, [x16, _swift_async_extendedFramePointerFlags@GOTPAGEOFF] +; CHECK-DYNAMIC: orr x29, x29, x16 + +; CHECK-DYNAMIC-32-LABEL: foo: +; CHECK-DYNAMIC-32: adrp x16, _swift_async_extendedFramePointerFlags@GOTPAGE +; CHECK-DYNAMIC-32: ldr w16, [x16, _swift_async_extendedFramePointerFlags@GOTPAGEOFF] +; CHECK-DYNAMIC-32: orr x29, x29, x16, lsl #32 + +define void @foo(i8* swiftasync) "frame-pointer"="all" { + ret void +} Index: llvm/test/CodeGen/X86/swift-async.ll =================================================================== --- llvm/test/CodeGen/X86/swift-async.ll +++ 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 Index: llvm/test/CodeGen/X86/swift-dynamic-async-frame.ll =================================================================== --- /dev/null +++ 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@GOTPCREL(%rip), %rbp + +define void @foo(i8* swiftasync) "frame-pointer"="all" { + ret void +}