[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