[llvm-branch-commits] [llvm] [AArch64] Apply the Windows SEH and CRT codegen constraints to UEFI (PR #232704)

Prabhu Rajasekaran via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sat Oct 17 23:03:42 PDT 2026


https://github.com/Prabhuk updated https://github.com/llvm/llvm-project/pull/232704

>From 43eb3d3c3a1ddbc6a3c33c813818eeeb13292625 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Fri, 16 Oct 2026 04:49:24 -0700
Subject: [PATCH] [AArch64] Apply the Windows SEH and CRT codegen constraints
 to UEFI

aarch64-unknown-uefi uses SEH unwind information and has no C runtime
library, so the remaining Windows specific codegen decisions that follow
from this apply to it too:

* do not align loops or basic blocks, since SEH unwind info generation
  needs the exact function layout before alignment padding is inserted,
* sign return addresses with the B key by default and reject A key
  signing, matching the pac_sign_lr unwind code used by the unwinder;
  the branch protection parser defaults to the B key for UEFI as well,
  so that -mbranch-protection=pac-ret keeps working,
* do not lower wide shifts to libcalls at -Oz, as those helpers are not
  available.

The corresponding Windows tests gain aarch64-unknown-uefi run lines and
the LLVM release notes announce the new target, which completes the
backend side of aarch64-unknown-uefi support.

Assisted-by: Claude
---
 llvm/docs/ReleaseNotes.md                      |  4 ++++
 .../Target/AArch64/AArch64CodeLayoutOpt.cpp    |  2 +-
 .../lib/Target/AArch64/AArch64ISelLowering.cpp | 10 +++++-----
 .../AArch64/AArch64MachineFunctionInfo.cpp     |  4 ++--
 .../lib/TargetParser/ARMTargetParserCommon.cpp |  4 ++--
 .../AArch64/windows-pac-invalid-a-key.ll       |  1 +
 llvm/test/CodeGen/AArch64/windows-trap.ll      |  1 +
 llvm/test/CodeGen/AArch64/wineh-pac.ll         |  1 +
 .../TargetParser/TargetParserTest.cpp          | 18 ++++++++++++++++++
 9 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 302aa57396105e..0b41fd223d3030 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -271,6 +271,10 @@ Makes programs 10x faster by doing Special New Thing.
 * Assembler/disassembler support has been added for Armv9.8-A (2026)
   architecture extensions.
 
+* Added support for the `aarch64-unknown-uefi` target. It follows the Windows
+  ARM64 ABI (calling convention, callee saved registers, stack probing and SEH
+  unwind information) and produces PE/COFF objects.
+
 ### Changes to the AMDGPU Backend
 
 * Replaced `xnack` and `sramecc` target features with `amdgpu.xnack`
diff --git a/llvm/lib/Target/AArch64/AArch64CodeLayoutOpt.cpp b/llvm/lib/Target/AArch64/AArch64CodeLayoutOpt.cpp
index 73e641da816063..cdbdd0994e77f2 100644
--- a/llvm/lib/Target/AArch64/AArch64CodeLayoutOpt.cpp
+++ b/llvm/lib/Target/AArch64/AArch64CodeLayoutOpt.cpp
@@ -163,7 +163,7 @@ bool AArch64CodeLayoutOpt::runOnMachineFunction(MachineFunction &MF) {
   const auto *Subtarget = &MF.getSubtarget<AArch64Subtarget>();
 
   // Aligning basic blocks currently isn't compatible with Windows unwind info.
-  if (Subtarget->isTargetWindows())
+  if (Subtarget->isTargetWindowsOrUEFI())
     return false;
 
   TII = Subtarget->getInstrInfo();
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 6d6cd21f25be20..8a2677f647aec0 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -1171,10 +1171,10 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
   setMinFunctionAlignment(Align(4));
   // Set preferred alignments.
 
-  // Don't align loops on Windows. The SEH unwind info generation needs to
-  // know the exact length of functions before the alignments have been
-  // expanded.
-  if (!Subtarget->isTargetWindows())
+  // Don't align loops on Windows and UEFI. The SEH unwind info generation
+  // needs to know the exact length of functions before the alignments have
+  // been expanded.
+  if (!Subtarget->isTargetWindowsOrUEFI())
     setPrefLoopAlignment(STI.getPrefLoopAlignment());
   setMaxBytesForAlignment(STI.getMaxBytesForLoopAlignment());
   setPrefFunctionAlignment(STI.getPrefFunctionAlignment());
@@ -33850,7 +33850,7 @@ TargetLowering::ShiftLegalizationStrategy
 AArch64TargetLowering::preferredShiftLegalizationStrategy(
     SelectionDAG &DAG, SDNode *N, unsigned int ExpansionFactor) const {
   if (DAG.getMachineFunction().getFunction().hasMinSize() &&
-      !Subtarget->isTargetWindows() && !Subtarget->isTargetDarwin())
+      !Subtarget->isTargetWindowsOrUEFI() && !Subtarget->isTargetDarwin())
     return ShiftLegalizationStrategy::LowerToLibcall;
   return TargetLowering::preferredShiftLegalizationStrategy(DAG, N,
                                                             ExpansionFactor);
diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
index 07a9230b63dc97..7129e332585fa8 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
@@ -86,7 +86,7 @@ static bool ShouldSignWithBKey(const Function &F, const AArch64Subtarget &STI) {
   if (F.hasFnAttribute("ptrauth-returns"))
     return true;
   if (!F.hasFnAttribute("sign-return-address-key")) {
-    if (STI.getTargetTriple().isOSWindows())
+    if (STI.getTargetTriple().isOSWindowsOrUEFI())
       return true;
     return false;
   }
@@ -94,7 +94,7 @@ static bool ShouldSignWithBKey(const Function &F, const AArch64Subtarget &STI) {
   const StringRef Key =
       F.getFnAttribute("sign-return-address-key").getValueAsString();
   assert(Key == "a_key" || Key == "b_key");
-  if (STI.getTargetTriple().isOSWindows() && Key == "a_key" &&
+  if (STI.getTargetTriple().isOSWindowsOrUEFI() && Key == "a_key" &&
       GetSignReturnAddress(F) != SignReturnAddress::None) {
     F.getContext().diagnose(DiagnosticInfoUnsupported{
         F, "A-key return address signing is unsupported on AArch64 Windows"});
diff --git a/llvm/lib/TargetParser/ARMTargetParserCommon.cpp b/llvm/lib/TargetParser/ARMTargetParserCommon.cpp
index 818fb64d2e10d2..af5c96133abcf4 100644
--- a/llvm/lib/TargetParser/ARMTargetParserCommon.cpp
+++ b/llvm/lib/TargetParser/ARMTargetParserCommon.cpp
@@ -153,7 +153,7 @@ bool ARM::parseBranchProtection(StringRef Spec, ParsedBranchProtection &PBP,
     PBP.BranchTargetEnforcement = true;
     PBP.GuardedControlStack = true;
     PBP.BranchProtectionPAuthLR = EnablePAuthLR;
-    if (Triple.isAArch64() && Triple.isOSWindows())
+    if (Triple.isAArch64() && Triple.isOSWindowsOrUEFI())
       PBP.Key = "b_key";
     return true;
   }
@@ -168,7 +168,7 @@ bool ARM::parseBranchProtection(StringRef Spec, ParsedBranchProtection &PBP,
     }
     if (Opt == "pac-ret") {
       PBP.Scope = "non-leaf";
-      if (Triple.isAArch64() && Triple.isOSWindows())
+      if (Triple.isAArch64() && Triple.isOSWindowsOrUEFI())
         PBP.Key = "b_key";
 
       for (; I + 1 != E; ++I) {
diff --git a/llvm/test/CodeGen/AArch64/windows-pac-invalid-a-key.ll b/llvm/test/CodeGen/AArch64/windows-pac-invalid-a-key.ll
index 7203e10e4b2003..5b8ab7fdf6b15a 100644
--- a/llvm/test/CodeGen/AArch64/windows-pac-invalid-a-key.ll
+++ b/llvm/test/CodeGen/AArch64/windows-pac-invalid-a-key.ll
@@ -1,4 +1,5 @@
 ; RUN: not llc -mtriple=aarch64-windows-msvc -filetype=null %s 2>&1 | FileCheck %s
+; RUN: not llc -mtriple=aarch64-unknown-uefi -filetype=null %s 2>&1 | FileCheck %s
 
 ; CHECK: error:
 ; CHECK-SAME: A-key return address signing is unsupported on AArch64 Windows
diff --git a/llvm/test/CodeGen/AArch64/windows-trap.ll b/llvm/test/CodeGen/AArch64/windows-trap.ll
index 5cf0ece48e97d1..9165fb0d2e7cdb 100644
--- a/llvm/test/CodeGen/AArch64/windows-trap.ll
+++ b/llvm/test/CodeGen/AArch64/windows-trap.ll
@@ -1,4 +1,5 @@
 ; RUN: llc -mtriple=aarch64-win32 %s -o - | FileCheck %s
+; RUN: llc -mtriple=aarch64-unknown-uefi %s -o - | FileCheck %s
 
 declare void @callee() noreturn
 
diff --git a/llvm/test/CodeGen/AArch64/wineh-pac.ll b/llvm/test/CodeGen/AArch64/wineh-pac.ll
index 71dcaa3b826512..13075447eeef41 100644
--- a/llvm/test/CodeGen/AArch64/wineh-pac.ll
+++ b/llvm/test/CodeGen/AArch64/wineh-pac.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc < %s -mtriple=aarch64-windows | FileCheck %s
+; RUN: llc < %s -mtriple=aarch64-unknown-uefi | FileCheck %s
 
 define dso_local i32 @func(ptr %g, i32 %a) "sign-return-address"="non-leaf" "sign-return-address-key"="b_key" {
 ; CHECK-LABEL: func:
diff --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp
index c32ec6a5b4f927..b176aa5ae54c3b 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -1087,6 +1087,24 @@ TEST(TargetParserTest, ARMPrintSupportedExtensions) {
   EXPECT_EQ(std::string::npos, captured.find("xscale"));
 }
 
+TEST(TargetParserTest, ARMParseBranchProtectionDefaultKey) {
+  // AArch64 Windows and UEFI only support B key return address signing, so it
+  // is the default there; everywhere else the A key is.
+  for (const auto &[TripleName, ExpectedKey] :
+       {std::pair{"aarch64-unknown-linux-gnu", "a_key"},
+        std::pair{"aarch64-pc-windows-msvc", "b_key"},
+        std::pair{"aarch64-unknown-uefi", "b_key"}}) {
+    const Triple T(TripleName);
+    for (StringRef Spec : {"standard", "pac-ret", "pac-ret+leaf+bti"}) {
+      ARM::ParsedBranchProtection PBP;
+      StringRef Err;
+      EXPECT_TRUE(ARM::parseBranchProtection(Spec, PBP, Err, T))
+          << TripleName << " " << Spec;
+      EXPECT_EQ(PBP.Key, ExpectedKey) << TripleName << " " << Spec;
+    }
+  }
+}
+
 struct AArch64CPUTestParams
     : public ARMCPUTestParams<AArch64::ExtensionBitset> {
   AArch64CPUTestParams(StringRef CPUName, StringRef ExpectedArch)



More information about the llvm-branch-commits mailing list