[llvm] [AArch64] Accept __chkstk_darwin stack probes on Darwin (PR #210812)

Karim Alweheshy via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 31 02:30:52 PDT 2026


https://github.com/karim-alweheshy updated https://github.com/llvm/llvm-project/pull/210812

>From 8c867c48d96174566e6c9949a1d15730962f9afe Mon Sep 17 00:00:00 2001
From: Karim Alweheshy <karim.alweheshy at gmail.com>
Date: Mon, 20 Jul 2026 23:22:22 +0200
Subject: [PATCH 1/3] [AArch64] Accept __chkstk_darwin stack probes on Darwin

Apple Swift bitcode uses the __chkstk_darwin probe kind, which the upstream AArch64 backend currently rejects during LTO. Accept that spelling for Darwin targets and lower it through the existing inline stack-probing implementation.
---
 .../AArch64/AArch64MachineFunctionInfo.cpp    |  6 ++++-
 .../AArch64/swift-darwin-stack-probing.ll     | 22 +++++++++++++++++++
 2 files changed, 27 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/AArch64/swift-darwin-stack-probing.ll

diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
index 29aea3694497f..e6ad188eab206 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
@@ -160,7 +160,11 @@ AArch64FunctionInfo::AArch64FunctionInfo(const Function &F,
                  F.getParent()->getModuleFlag("probe-stack")))
       ProbeKind = PS->getString();
     if (ProbeKind.size()) {
-      if (ProbeKind != "inline-asm")
+      // Apple Swift emits __chkstk_darwin for Darwin bitcode. Treat it as a
+      // request for the existing inline probe sequence; this backend does not
+      // provide Apple's out-of-tree helper-based implementation.
+      if (ProbeKind != "inline-asm" &&
+          !(STI->isTargetDarwin() && ProbeKind == "__chkstk_darwin"))
         report_fatal_error("Unsupported stack probing method");
       StackProbeSize = ProbeSize;
     }
diff --git a/llvm/test/CodeGen/AArch64/swift-darwin-stack-probing.ll b/llvm/test/CodeGen/AArch64/swift-darwin-stack-probing.ll
new file mode 100644
index 0000000000000..7fe4a09a6406a
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/swift-darwin-stack-probing.ll
@@ -0,0 +1,22 @@
+; RUN: llc -mtriple=arm64-apple-macosx -verify-machineinstrs < %s | FileCheck %s
+
+; Verify that the stack-probing attribute emitted by Apple Swift is accepted
+; on Darwin and lowered to the existing inline stack-probing sequence.
+
+define void @swift_darwin_stack_probe(ptr %out) #0 {
+; CHECK-LABEL: swift_darwin_stack_probe:
+; CHECK:       sub sp, sp, #1, lsl #12
+; CHECK-NEXT:  ldr xzr, [sp]
+entry:
+  %frame = alloca i8, i64 4096, align 1
+  store ptr %frame, ptr %out, align 8
+  ret void
+}
+
+attributes #0 = {
+  noinline
+  "frame-pointer"="none"
+  "probe-stack"="__chkstk_darwin"
+  "stack-probe-size"="4096"
+  uwtable(async)
+}

>From 5409396cdbe9665ccf3bf7b13427cce34619b6c8 Mon Sep 17 00:00:00 2001
From: Karim Alweheshy <karim.alweheshy at gmail.com>
Date: Tue, 21 Jul 2026 14:26:48 +0200
Subject: [PATCH 2/3] Relax stack-probe assembly adjacency check

---
 llvm/test/CodeGen/AArch64/swift-darwin-stack-probing.ll | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/test/CodeGen/AArch64/swift-darwin-stack-probing.ll b/llvm/test/CodeGen/AArch64/swift-darwin-stack-probing.ll
index 7fe4a09a6406a..f6a749c9a0506 100644
--- a/llvm/test/CodeGen/AArch64/swift-darwin-stack-probing.ll
+++ b/llvm/test/CodeGen/AArch64/swift-darwin-stack-probing.ll
@@ -6,7 +6,7 @@
 define void @swift_darwin_stack_probe(ptr %out) #0 {
 ; CHECK-LABEL: swift_darwin_stack_probe:
 ; CHECK:       sub sp, sp, #1, lsl #12
-; CHECK-NEXT:  ldr xzr, [sp]
+; CHECK:       ldr xzr, [sp]
 entry:
   %frame = alloca i8, i64 4096, align 1
   store ptr %frame, ptr %out, align 8

>From 5c53f122582d212c64643e43be8d1dfe092585cf Mon Sep 17 00:00:00 2001
From: Karim Alweheshy <karim.alweheshy at gmail.com>
Date: Thu, 30 Jul 2026 09:47:36 +0200
Subject: [PATCH 3/3] [AArch64] Lower Darwin stack probes through
 __chkstk_darwin

---
 .../AArch64/AArch64CallingConvention.td       | 10 +++
 .../Target/AArch64/AArch64FrameLowering.cpp   | 17 ++++
 .../lib/Target/AArch64/AArch64FrameLowering.h |  2 +
 .../Target/AArch64/AArch64ISelLowering.cpp    | 49 +++++++++++-
 llvm/lib/Target/AArch64/AArch64ISelLowering.h |  1 +
 .../AArch64/AArch64MachineFunctionInfo.cpp    | 14 ++--
 .../AArch64/AArch64MachineFunctionInfo.h      | 18 ++++-
 .../AArch64/AArch64PrologueEpilogue.cpp       | 39 ++++++++-
 .../Target/AArch64/AArch64PrologueEpilogue.h  |  2 +
 .../Target/AArch64/AArch64RegisterInfo.cpp    |  4 +
 llvm/lib/Target/AArch64/AArch64RegisterInfo.h |  1 +
 .../AArch64/swift-darwin-stack-probing.ll     | 79 +++++++++++++++++--
 12 files changed, 221 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64CallingConvention.td b/llvm/lib/Target/AArch64/AArch64CallingConvention.td
index 4683f166386e7..ecbd83088cc4a 100644
--- a/llvm/lib/Target/AArch64/AArch64CallingConvention.td
+++ b/llvm/lib/Target/AArch64/AArch64CallingConvention.td
@@ -732,6 +732,16 @@ def CSR_AArch64_StackProbe_Windows
                            (sequence "X%u", 18, 28), FP, SP,
                            (sequence "Q%u", 0, 31))>;
 
+// ___chkstk_darwin takes the prospective stack allocation size in X9. The
+// compatibility implementation used by older Darwin versions also uses X10,
+// and its dispatch veneer uses X16.
+def CSR_AArch64_StackProbe_Darwin
+    : CalleeSavedRegs<(add (sequence "X%u", 0, 8),
+                           (sequence "X%u", 11, 15),
+                           (sequence "X%u", 17, 28), FP, SP,
+                           (sequence "Z%u", 0, 31),
+                           (sequence "P%u", 0, 15))>;
+
 // Darwin variants of AAPCS.
 // Darwin puts the frame-record at the top of the callee-save area.
 def CSR_Darwin_AArch64_AAPCS : CalleeSavedRegs<(add LR, FP, X19, X20, X21, X22,
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index a38b9798ac1e5..1d4cab6be9120 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -904,6 +904,13 @@ bool AArch64FrameLowering::windowsRequiresStackProbe(
          StackSizeInBytes >= uint64_t(MFI.getStackProbeSize());
 }
 
+bool AArch64FrameLowering::darwinRequiresStackProbe(
+    const MachineFunction &MF, uint64_t StackSizeInBytes) const {
+  const AArch64FunctionInfo &MFI = *MF.getInfo<AArch64FunctionInfo>();
+  return MFI.hasDarwinStackProbe() &&
+         StackSizeInBytes >= uint64_t(MFI.getStackProbeSize());
+}
+
 static void getLiveRegsForEntryMBB(LivePhysRegs &LiveRegs,
                                    const MachineBasicBlock &MBB) {
   const MachineFunction *MF = MBB.getParent();
@@ -979,6 +986,16 @@ bool AArch64FrameLowering::canUseAsPrologue(
     if (findScratchNonCalleeSaveRegister(TmpMBB) == AArch64::NoRegister)
       return false;
 
+  if (darwinRequiresStackProbe(*MF, std::numeric_limits<uint64_t>::max())) {
+    const AArch64RegisterInfo &TRI = *Subtarget.getRegisterInfo();
+    const MachineRegisterInfo &MRI = MF->getRegInfo();
+    LivePhysRegs LiveRegs(TRI);
+    getLiveRegsForEntryMBB(LiveRegs, MBB);
+    if (!LiveRegs.available(MRI, AArch64::X9) ||
+        !LiveRegs.available(MRI, AArch64::X16))
+      return false;
+  }
+
   // May need a scratch register (for return value) if require making a special
   // call
   if (requiresSaveVG(*MF) ||
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.h b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
index 19cc93d01013d..616f49ff86a8c 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
@@ -233,6 +233,8 @@ class AArch64FrameLowering : public TargetFrameLowering {
 
   bool windowsRequiresStackProbe(const MachineFunction &MF,
                                  uint64_t StackSizeInBytes) const;
+  bool darwinRequiresStackProbe(const MachineFunction &MF,
+                                uint64_t StackSizeInBytes) const;
 
   bool shouldSignReturnAddressEverywhere(const MachineFunction &MF) const;
 
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 9872ec9a4a1fe..a31b7e8bef842 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -18271,6 +18271,50 @@ AArch64TargetLowering::LowerInlineDYNAMIC_STACKALLOC(SDValue Op,
   return DAG.getMergeValues(Ops, DL);
 }
 
+SDValue
+AArch64TargetLowering::LowerDarwinDYNAMIC_STACKALLOC(SDValue Op,
+                                                     SelectionDAG &DAG) const {
+  SDNode *Node = Op.getNode();
+  SDValue Chain = Op.getOperand(0);
+  SDValue Size = Op.getOperand(1);
+  MaybeAlign Align =
+      cast<ConstantSDNode>(Op.getOperand(2))->getMaybeAlignValue();
+  SDLoc DL(Op);
+  EVT VT = Node->getValueType(0);
+
+  SDValue SP = DAG.getCopyFromReg(Chain, DL, AArch64::SP, MVT::i64);
+  Chain = SP.getValue(1);
+  SDValue TargetSP = DAG.getNode(ISD::SUB, DL, MVT::i64, SP, Size);
+  if (Align)
+    TargetSP = DAG.getNode(ISD::AND, DL, VT, TargetSP,
+                           DAG.getSignedConstant(-Align->value(), DL, VT));
+  SDValue ProbeSize = DAG.getNode(ISD::SUB, DL, MVT::i64, SP, TargetSP);
+
+  Chain = DAG.getCALLSEQ_START(Chain, 0, 0, DL);
+
+  EVT PtrVT = getPointerTy(DAG.getDataLayout());
+  SDValue Callee =
+      DAG.getTargetExternalSymbol("__chkstk_darwin", PtrVT, AArch64II::MO_GOT);
+  Callee = DAG.getNode(AArch64ISD::LOADgot, DL, PtrVT, Callee);
+
+  const AArch64RegisterInfo *TRI = Subtarget->getRegisterInfo();
+  const uint32_t *Mask = TRI->getDarwinStackProbePreservedMask();
+  if (Subtarget->hasCustomCallingConv())
+    TRI->UpdateCustomCallPreservedMask(DAG.getMachineFunction(), &Mask);
+
+  Chain = DAG.getCopyToReg(Chain, DL, AArch64::X9, ProbeSize, SDValue());
+  Chain =
+      DAG.getNode(AArch64ISD::CALL, DL, DAG.getVTList(MVT::Other, MVT::Glue),
+                  Chain, Callee, DAG.getRegister(AArch64::X9, MVT::i64),
+                  DAG.getRegisterMask(Mask), Chain.getValue(1));
+
+  Chain = DAG.getCopyToReg(Chain, DL, AArch64::SP, TargetSP);
+  Chain = DAG.getCALLSEQ_END(Chain, 0, 0, SDValue(), DL);
+
+  SDValue Ops[2] = {TargetSP, Chain};
+  return DAG.getMergeValues(Ops, DL);
+}
+
 SDValue
 AArch64TargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
                                                SelectionDAG &DAG) const {
@@ -18278,6 +18322,8 @@ AArch64TargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
 
   if (Subtarget->isTargetWindows())
     return LowerWindowsDYNAMIC_STACKALLOC(Op, DAG);
+  else if (MF.getInfo<AArch64FunctionInfo>()->hasDarwinStackProbe())
+    return LowerDarwinDYNAMIC_STACKALLOC(Op, DAG);
   else if (hasInlineStackProbe(MF))
     return LowerInlineDYNAMIC_STACKALLOC(Op, DAG);
   else
@@ -35574,8 +35620,7 @@ unsigned AArch64TargetLowering::getVectorTypeBreakdownForCallingConv(
 
 bool AArch64TargetLowering::hasInlineStackProbe(
     const MachineFunction &MF) const {
-  return !Subtarget->isTargetWindows() &&
-         MF.getInfo<AArch64FunctionInfo>()->hasStackProbing();
+  return MF.getInfo<AArch64FunctionInfo>()->hasInlineStackProbe();
 }
 
 bool AArch64TargetLowering::isTypeDesirableForOp(unsigned Opc, EVT VT) const {
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index 6827356b7c194..2428d042824d4 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -805,6 +805,7 @@ class AArch64TargetLowering : public TargetLowering {
   SDValue LowerVECREDUCE_MUL(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerATOMIC_LOAD_AND(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerWindowsDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
+  SDValue LowerDarwinDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerInlineDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerMSTORE(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
index e6ad188eab206..52a747b7cf02f 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
@@ -146,8 +146,10 @@ AArch64FunctionInfo::AArch64FunctionInfo(const Function &F,
   assert(int64_t(ProbeSize) > 0 && "Invalid stack probe size");
 
   if (STI->isTargetWindows()) {
-    if (!F.hasFnAttribute("no-stack-arg-probe"))
+    if (!F.hasFnAttribute("no-stack-arg-probe")) {
+      StackProbe = StackProbeKind::Windows;
       StackProbeSize = ProbeSize;
+    }
   } else {
     // Round down to the stack alignment.
     uint64_t StackAlign =
@@ -160,11 +162,11 @@ AArch64FunctionInfo::AArch64FunctionInfo(const Function &F,
                  F.getParent()->getModuleFlag("probe-stack")))
       ProbeKind = PS->getString();
     if (ProbeKind.size()) {
-      // Apple Swift emits __chkstk_darwin for Darwin bitcode. Treat it as a
-      // request for the existing inline probe sequence; this backend does not
-      // provide Apple's out-of-tree helper-based implementation.
-      if (ProbeKind != "inline-asm" &&
-          !(STI->isTargetDarwin() && ProbeKind == "__chkstk_darwin"))
+      if (ProbeKind == "inline-asm")
+        StackProbe = StackProbeKind::Inline;
+      else if (STI->isTargetDarwin() && ProbeKind == "__chkstk_darwin")
+        StackProbe = StackProbeKind::Darwin;
+      else
         report_fatal_error("Unsupported stack probing method");
       StackProbeSize = ProbeSize;
     }
diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
index 60a5a978bb09a..3cdd5d0c68f10 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
@@ -46,6 +46,13 @@ enum class SignReturnAddress {
   All,
 };
 
+enum class StackProbeKind {
+  None,
+  Inline,
+  Darwin,
+  Windows,
+};
+
 /// AArch64FunctionInfo - This class is derived from MachineFunctionInfo and
 /// contains private AArch64-specific information for each MachineFunction.
 class AArch64FunctionInfo final : public MachineFunctionInfo {
@@ -223,6 +230,7 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
   /// True if the function need asynchronous unwind information.
   mutable std::optional<bool> NeedsAsyncDwarfUnwindInfo;
 
+  StackProbeKind StackProbe = StackProbeKind::None;
   int64_t StackProbeSize = 0;
 
   // Holds a register containing pstate.sm. This is set
@@ -603,7 +611,15 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
     HasStreamingModeChanges = HasChanges;
   }
 
-  bool hasStackProbing() const { return StackProbeSize != 0; }
+  bool hasStackProbing() const { return StackProbe != StackProbeKind::None; }
+
+  bool hasInlineStackProbe() const {
+    return StackProbe == StackProbeKind::Inline;
+  }
+
+  bool hasDarwinStackProbe() const {
+    return StackProbe == StackProbeKind::Darwin;
+  }
 
   int64_t getStackProbeSize() const { return StackProbeSize; }
 
diff --git a/llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp b/llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp
index 230ea947c5e54..cea1413b5024b 100644
--- a/llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp
+++ b/llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp
@@ -702,7 +702,8 @@ void AArch64PrologueEmitter::emitPrologue() {
   // function, including the funclet.
   int64_t NumBytes =
       IsFunclet ? AFL.getWinEHFuncletFrameSize(MF) : MFI.getStackSize();
-  if (!AFI->hasStackFrame() && !AFL.windowsRequiresStackProbe(MF, NumBytes))
+  if (!AFI->hasStackFrame() && !AFL.windowsRequiresStackProbe(MF, NumBytes) &&
+      !AFL.darwinRequiresStackProbe(MF, NumBytes))
     return emitEmptyStackFramePrologue(NumBytes, PrologueBeginI, DL);
 
   bool IsWin64 = Subtarget.isCallingConvWin64(F.getCallingConv(), F.isVarArg());
@@ -791,6 +792,8 @@ void AArch64PrologueEmitter::emitPrologue() {
 
   if (AFL.windowsRequiresStackProbe(MF, NumBytes + RealignmentPadding))
     emitWindowsStackProbe(AfterGPRSavesI, DL, NumBytes, RealignmentPadding);
+  else if (AFL.darwinRequiresStackProbe(MF, NumBytes + RealignmentPadding))
+    emitDarwinStackProbe(AfterGPRSavesI, DL, NumBytes + RealignmentPadding);
 
   StackOffset NonSVELocalsSize = StackOffset::getFixed(NumBytes);
   SVEAllocs.AfterZPRs += NonSVELocalsSize;
@@ -1792,4 +1795,38 @@ void AArch64EpilogueEmitter::finalizeEpilogue() const {
   }
 }
 
+void AArch64PrologueEmitter::emitDarwinStackProbe(
+    MachineBasicBlock::iterator MBBI, const DebugLoc &DL,
+    uint64_t NumBytes) const {
+  constexpr StringLiteral ChkStk = "__chkstk_darwin";
+
+  BuildMI(MBB, MBBI, DL, TII->get(AArch64::STRXpre))
+      .addReg(AArch64::SP, RegState::Define)
+      .addReg(AArch64::LR)
+      .addReg(AArch64::SP)
+      .addImm(-16)
+      .setMIFlag(MachineInstr::FrameSetup);
+
+  BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVi64imm), AArch64::X9)
+      .addImm(NumBytes)
+      .setMIFlag(MachineInstr::FrameSetup);
+
+  BuildMI(MBB, MBBI, DL, TII->get(AArch64::LOADgot), AArch64::X16)
+      .addExternalSymbol(ChkStk.data(), AArch64II::MO_GOT)
+      .setMIFlag(MachineInstr::FrameSetup);
+
+  BuildMI(MBB, MBBI, DL, TII->get(getBLRCallOpcode(MF)))
+      .addReg(AArch64::X16, RegState::Kill)
+      .addReg(AArch64::X9, RegState::Implicit)
+      .addRegMask(RegInfo.getDarwinStackProbePreservedMask())
+      .setMIFlag(MachineInstr::FrameSetup);
+
+  BuildMI(MBB, MBBI, DL, TII->get(AArch64::LDRXpost))
+      .addReg(AArch64::SP, RegState::Define)
+      .addReg(AArch64::LR, RegState::Define)
+      .addReg(AArch64::SP)
+      .addImm(16)
+      .setMIFlag(MachineInstr::FrameSetup);
+}
+
 } // namespace llvm
diff --git a/llvm/lib/Target/AArch64/AArch64PrologueEpilogue.h b/llvm/lib/Target/AArch64/AArch64PrologueEpilogue.h
index 326a6ea3e25ee..4d6816ff3d03d 100644
--- a/llvm/lib/Target/AArch64/AArch64PrologueEpilogue.h
+++ b/llvm/lib/Target/AArch64/AArch64PrologueEpilogue.h
@@ -142,6 +142,8 @@ class AArch64PrologueEmitter final : public AArch64PrologueEpilogueCommon {
   void emitWindowsStackProbe(MachineBasicBlock::iterator MBBI,
                              const DebugLoc &DL, int64_t &NumBytes,
                              int64_t RealignmentPadding) const;
+  void emitDarwinStackProbe(MachineBasicBlock::iterator MBBI,
+                            const DebugLoc &DL, uint64_t NumBytes) const;
 
   void emitCalleeSavedGPRLocations(MachineBasicBlock::iterator MBBI) const;
   void emitCalleeSavedSVELocations(MachineBasicBlock::iterator MBBI) const;
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
index edca3e94a0afe..e3c46f9a45347 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
@@ -388,6 +388,10 @@ const uint32_t *AArch64RegisterInfo::getWindowsStackProbePreservedMask() const {
   return CSR_AArch64_StackProbe_Windows_RegMask;
 }
 
+const uint32_t *AArch64RegisterInfo::getDarwinStackProbePreservedMask() const {
+  return CSR_AArch64_StackProbe_Darwin_RegMask;
+}
+
 std::optional<std::string>
 AArch64RegisterInfo::explainReservedReg(const MachineFunction &MF,
                                         MCRegister PhysReg) const {
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.h b/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
index b31104aac6551..e3ee37cf48aed 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
@@ -96,6 +96,7 @@ class AArch64RegisterInfo final : public AArch64GenRegisterInfo {
 
   /// Stack probing calls preserve different CSRs to the normal CC.
   const uint32_t *getWindowsStackProbePreservedMask() const;
+  const uint32_t *getDarwinStackProbePreservedMask() const;
 
   BitVector getStrictlyReservedRegs(const MachineFunction &MF) const;
   BitVector getUserReservedRegs(const MachineFunction &MF) const;
diff --git a/llvm/test/CodeGen/AArch64/swift-darwin-stack-probing.ll b/llvm/test/CodeGen/AArch64/swift-darwin-stack-probing.ll
index f6a749c9a0506..155f6609fedf7 100644
--- a/llvm/test/CodeGen/AArch64/swift-darwin-stack-probing.ll
+++ b/llvm/test/CodeGen/AArch64/swift-darwin-stack-probing.ll
@@ -1,18 +1,85 @@
 ; RUN: llc -mtriple=arm64-apple-macosx -verify-machineinstrs < %s | FileCheck %s
+; RUN: not --crash llc -mtriple=aarch64-unknown-linux < %s 2>&1 | FileCheck %s --check-prefix=ERROR
 
 ; Verify that the stack-probing attribute emitted by Apple Swift is accepted
-; on Darwin and lowered to the existing inline stack-probing sequence.
+; on Darwin and lowered through the Darwin stack-check helper ABI.
 
-define void @swift_darwin_stack_probe(ptr %out) #0 {
-; CHECK-LABEL: swift_darwin_stack_probe:
-; CHECK:       sub sp, sp, #1, lsl #12
-; CHECK:       ldr xzr, [sp]
+define void @below_probe_threshold(ptr %out) #0 {
+; CHECK-LABEL: below_probe_threshold:
+; CHECK-NOT:   ___chkstk_darwin
+; CHECK:       sub sp, sp, #1040
+; CHECK-NOT:   ___chkstk_darwin
+; CHECK:       ret
+entry:
+  %frame = alloca i8, i64 1040, align 1
+  store ptr %frame, ptr %out, align 8
+  ret void
+}
+
+define void @just_below_probe_threshold(ptr %out) #0 {
+; CHECK-LABEL: just_below_probe_threshold:
+; CHECK-NOT:   ___chkstk_darwin
+; CHECK:       sub sp, sp, #4080
+; CHECK-NOT:   ___chkstk_darwin
+; CHECK:       ret
+entry:
+  %frame = alloca i8, i64 4080, align 1
+  store ptr %frame, ptr %out, align 8
+  ret void
+}
+
+define void @fixed_probe(ptr %out) #0 {
+; CHECK-LABEL: fixed_probe:
+; CHECK:       str x30, [sp, #-16]!
+; CHECK-DAG:   mov x9, #4096
+; CHECK-DAG:   adrp x16, ___chkstk_darwin at GOTPAGE
+; CHECK:       ldr x16, [x16, ___chkstk_darwin at GOTPAGEOFF]
+; CHECK-NEXT:  blr x16
+; CHECK-NEXT:  ldr x30, [sp], #16
+; CHECK-NEXT:  sub sp, sp, #1, lsl #12
+; CHECK-NOT:   ldr xzr, [sp]
+; CHECK:       ret
 entry:
   %frame = alloca i8, i64 4096, align 1
   store ptr %frame, ptr %out, align 8
   ret void
 }
 
+define void @large_fixed_probe(ptr %out) #0 {
+; CHECK-LABEL: large_fixed_probe:
+; CHECK:       str x30, [sp, #-16]!
+; CHECK-DAG:   mov x9, #20480
+; CHECK-DAG:   adrp x16, ___chkstk_darwin at GOTPAGE
+; CHECK:       ldr x16, [x16, ___chkstk_darwin at GOTPAGEOFF]
+; CHECK-NEXT:  blr x16
+; CHECK-NEXT:  ldr x30, [sp], #16
+; CHECK-NEXT:  sub sp, sp, #5, lsl #12
+; CHECK-NOT:   ldr xzr, [sp]
+; CHECK:       ret
+entry:
+  %frame = alloca i8, i64 20480, align 1
+  store ptr %frame, ptr %out, align 8
+  ret void
+}
+
+define void @dynamic_probe(ptr %out, i64 %size) #0 {
+; CHECK-LABEL: dynamic_probe:
+; CHECK-DAG:   mov x9, [[SIZE:x[0-9]+]]
+; Keep the old SP in a register preserved by both the current helper and the
+; compatibility implementation, which clobbers x9, x10, and x16.
+; CHECK-DAG:   mov [[OLDSP:x([0-8]|1[1-5]|1[7-9]|2[0-8])]], sp
+; CHECK-DAG:   adrp [[CALLEE:x[0-9]+]], ___chkstk_darwin at GOTPAGE
+; CHECK-DAG:   ldr [[CALLEE]], {{\[}}[[CALLEE]], ___chkstk_darwin at GOTPAGEOFF]
+; CHECK:       blr [[CALLEE]]
+; CHECK:       sub [[TARGETSP:x[0-9]+]], [[OLDSP]], [[SIZE]]
+; CHECK-NEXT:  mov sp, [[TARGETSP]]
+; CHECK:       ret
+entry:
+  %frame = alloca i8, i64 %size, align 16
+  store ptr %frame, ptr %out, align 8
+  ret void
+}
+
 attributes #0 = {
   noinline
   "frame-pointer"="none"
@@ -20,3 +87,5 @@ attributes #0 = {
   "stack-probe-size"="4096"
   uwtable(async)
 }
+
+; ERROR: LLVM ERROR: Unsupported stack probing method



More information about the llvm-commits mailing list