[llvm-branch-commits] [llvm] [AArch64] Use Windows style stack probing on UEFI (PR #232702)
Prabhu Rajasekaran via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Oct 16 04:56:47 PDT 2026
https://github.com/Prabhuk created https://github.com/llvm/llvm-project/pull/232702
Like Windows, and like x86_64-unknown-uefi already does, probe large
stack frames and dynamic allocas through the __chkstk helper on
aarch64-unknown-uefi instead of the inline stack probe loop:
* make the __chkstk STACK_PROBE libcall available for AArch64 UEFI,
* select the Windows stack probe paths in frame lowering,
LowerDYNAMIC_STACKALLOC and the SME state buffer allocation, honouring
the "no-stack-arg-probe" attribute as on Windows,
* fall back from GlobalISel to SelectionDAG for dynamic allocas, as is
done for Windows, since the IRTranslator does not implement the probing.
The existing chkstk and alloca tests gain aarch64-unknown-uefi run lines.
Assisted-by: Claude
---
<sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>
>From b12a4adb17b619d2e69b54250089f2caf758bd82 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Fri, 16 Oct 2026 04:48:26 -0700
Subject: [PATCH] [AArch64] Use Windows style stack probing on UEFI
Like Windows, and like x86_64-unknown-uefi already does, probe large
stack frames and dynamic allocas through the __chkstk helper on
aarch64-unknown-uefi instead of the inline stack probe loop:
* make the __chkstk STACK_PROBE libcall available for AArch64 UEFI,
* select the Windows stack probe paths in frame lowering,
LowerDYNAMIC_STACKALLOC and the SME state buffer allocation, honouring
the "no-stack-arg-probe" attribute as on Windows,
* fall back from GlobalISel to SelectionDAG for dynamic allocas, as is
done for Windows, since the IRTranslator does not implement the probing.
The existing chkstk and alloca tests gain aarch64-unknown-uefi run lines.
Assisted-by: Claude
---
llvm/include/llvm/IR/RuntimeLibcalls.td | 5 +++--
llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 4 ++--
llvm/lib/Target/AArch64/AArch64FrameLowering.cpp | 2 +-
llvm/lib/Target/AArch64/AArch64ISelLowering.cpp | 6 +++---
llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp | 2 +-
llvm/lib/Target/AArch64/MachineSMEABIPass.cpp | 2 +-
llvm/test/CodeGen/AArch64/chkstk.ll | 2 ++
llvm/test/CodeGen/AArch64/win-alloca.ll | 1 +
llvm/test/CodeGen/AArch64/win64_vararg.ll | 1 +
9 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td
index d05cd842bdb047..26fae82e95354c 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.td
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.td
@@ -2064,9 +2064,10 @@ defvar SecurityCheckCookieIfWinMSVC =
LibcallImpls<(add __security_check_cookie, __security_cookie),
isWindowsMSVCOrItaniumEnvironment>;
-// The Windows CRT security cookie and stack probes are part of libc.
+// The Windows CRT security cookie and stack probes are part of libc. UEFI
+// follows the Windows ARM64 ABI and uses the same stack probe helper.
def isWindowsAArch64NotArm64EC : RuntimeLibcallAvailability<
- (all_of IsOSWindows, IsAArch64, (not IsWindowsArm64EC))>;
+ (all_of IsOSWindowsOrUEFI, IsAArch64, (not IsWindowsArm64EC))>;
def isWindowsARM : RuntimeLibcallAvailability<
(all_of IsOSWindows, (any_of IsARM, IsThumb))>;
def WindowsCRTLibc : LibcallLibrary<"libc", (add SecurityCheckCookieIfWinMSVC)>;
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index ebf2eb79a64528..2ac7f1f3c2b3bb 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -4031,8 +4031,8 @@ bool IRTranslatorImpl::translateAlloca(const User &U,
return true;
}
- // FIXME: support stack probing for Windows.
- if (MF->getTarget().getTargetTriple().isOSWindows())
+ // FIXME: support stack probing for Windows and UEFI.
+ if (MF->getTarget().getTargetTriple().isOSWindowsOrUEFI())
return false;
// Now we're in the harder dynamic case.
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 4a35ab0b129b77..4873b8cb1b42ba 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -866,7 +866,7 @@ bool AArch64FrameLowering::windowsRequiresStackProbe(
const AArch64FunctionInfo &MFI = *MF.getInfo<AArch64FunctionInfo>();
// TODO: When implementing stack protectors, take that into account
// for the probe threshold.
- return Subtarget.isTargetWindows() && MFI.hasStackProbing() &&
+ return Subtarget.isTargetWindowsOrUEFI() && MFI.hasStackProbing() &&
StackSizeInBytes >= uint64_t(MFI.getStackProbeSize());
}
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 9d47ef0a28c08e..42729b32cd7aa6 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -9729,7 +9729,7 @@ SDValue AArch64TargetLowering::LowerFormalArguments(
if (Subtarget->hasCustomCallingConv())
Subtarget->getRegisterInfo()->UpdateCustomCalleeSavedRegs(MF);
- if (Subtarget->isTargetWindows() || hasInlineStackProbe(MF)) {
+ if (Subtarget->isTargetWindowsOrUEFI() || hasInlineStackProbe(MF)) {
SDValue Size;
if (Attrs.hasZAState()) {
SDValue SVL = DAG.getNode(AArch64ISD::RDSVL, DL, MVT::i64,
@@ -18532,7 +18532,7 @@ AArch64TargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
- if (Subtarget->isTargetWindows())
+ if (Subtarget->isTargetWindowsOrUEFI())
return LowerWindowsDYNAMIC_STACKALLOC(Op, DAG);
else if (hasInlineStackProbe(MF))
return LowerInlineDYNAMIC_STACKALLOC(Op, DAG);
@@ -36572,7 +36572,7 @@ unsigned AArch64TargetLowering::getVectorTypeBreakdownForCallingConv(
bool AArch64TargetLowering::hasInlineStackProbe(
const MachineFunction &MF) const {
- return !Subtarget->isTargetWindows() &&
+ return !Subtarget->isTargetWindowsOrUEFI() &&
MF.getInfo<AArch64FunctionInfo>()->hasStackProbing();
}
diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
index 004315b0251194..07a9230b63dc97 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
@@ -157,7 +157,7 @@ AArch64FunctionInfo::AArch64FunctionInfo(const Function &F,
ProbeSize = PS->getZExtValue();
assert(int64_t(ProbeSize) > 0 && "Invalid stack probe size");
- if (STI->isTargetWindows()) {
+ if (STI->isTargetWindowsOrUEFI()) {
if (!F.hasFnAttribute("no-stack-arg-probe"))
StackProbeSize = ProbeSize;
} else {
diff --git a/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp b/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
index a09a9db6a3ad48..3f62a2ec97cfe9 100644
--- a/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
+++ b/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
@@ -887,7 +887,7 @@ void MachineSMEABI::emitAllocateLazySaveBuffer(
// will always allocate the lazy save buffer (even if the function contains
// no lazy saves). If we want to handle Windows here, we'll need to
// implement something similar to LowerWindowsDYNAMIC_STACKALLOC.
- assert(!Subtarget->isTargetWindows() &&
+ assert(!Subtarget->isTargetWindowsOrUEFI() &&
"Lazy ZA save is not yet supported on Windows");
Buffer = MRI->createVirtualRegister(&AArch64::GPR64RegClass);
// Get original stack pointer.
diff --git a/llvm/test/CodeGen/AArch64/chkstk.ll b/llvm/test/CodeGen/AArch64/chkstk.ll
index 8a3dea9807a785..b1d4fcf39ab5e9 100644
--- a/llvm/test/CodeGen/AArch64/chkstk.ll
+++ b/llvm/test/CodeGen/AArch64/chkstk.ll
@@ -2,6 +2,8 @@
; RUN: | FileCheck -check-prefix CHECK-DEFAULT-CODE-MODEL %s
; RUN: llc -mtriple=aarch64-w64-mingw32 -verify-machineinstrs %s -o - \
; RUN: | FileCheck -check-prefix CHECK-DEFAULT-CODE-MODEL %s
+; RUN: llc -mtriple=aarch64-unknown-uefi -verify-machineinstrs %s -o - \
+; RUN: | FileCheck -check-prefix CHECK-DEFAULT-CODE-MODEL %s
; RUN: llc < %s -mtriple=aarch64-windows -stop-after=prolog-epilog \
; RUN: | FileCheck -check-prefix CHECK-REGSTATE %s
diff --git a/llvm/test/CodeGen/AArch64/win-alloca.ll b/llvm/test/CodeGen/AArch64/win-alloca.ll
index 94c3d884581695..a3592308807757 100644
--- a/llvm/test/CodeGen/AArch64/win-alloca.ll
+++ b/llvm/test/CodeGen/AArch64/win-alloca.ll
@@ -1,5 +1,6 @@
; RUN: llc -mtriple aarch64-windows -verify-machineinstrs -filetype asm -o - %s | FileCheck %s -check-prefixes=CHECK,CHECK-OPT
; RUN: llc -mtriple aarch64-windows -verify-machineinstrs -filetype asm -o - %s -O0 | FileCheck %s
+; RUN: llc -mtriple aarch64-unknown-uefi -verify-machineinstrs -filetype asm -o - %s | FileCheck %s -check-prefixes=CHECK,CHECK-OPT
; RUN: llc -mtriple arm64ec-windows-msvc -verify-machineinstrs -filetype asm -o - %s | FileCheck -check-prefix=CHECK-ARM64EC %s
define void @func(i64 %a) {
diff --git a/llvm/test/CodeGen/AArch64/win64_vararg.ll b/llvm/test/CodeGen/AArch64/win64_vararg.ll
index 0f4cb44a6f73b2..75f27ae97acdc8 100644
--- a/llvm/test/CodeGen/AArch64/win64_vararg.ll
+++ b/llvm/test/CodeGen/AArch64/win64_vararg.ll
@@ -1,5 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=aarch64-pc-win32 | FileCheck %s
+; RUN: llc < %s -mtriple=aarch64-unknown-uefi | FileCheck %s
define void @pass_va(i32 %count, ...) nounwind {
; CHECK-LABEL: pass_va:
More information about the llvm-branch-commits
mailing list