[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