[clang] [llvm] [AArch64] Add aarch64-unknown-uefi target support (PR #213275)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 31 08:25:08 PDT 2026
https://github.com/paulober updated https://github.com/llvm/llvm-project/pull/213275
>From a5d76397a8d4e30cde988a04b4caa9dff48e9703 Mon Sep 17 00:00:00 2001
From: paulober <44974737+paulober at users.noreply.github.com>
Date: Fri, 31 Jul 2026 14:39:08 +0200
Subject: [PATCH] [AArch64] Add aarch64-unknown-uefi target support
Add a clang AArch64 UEFI target (PE/COFF, Microsoft ARM64 ABI, LLP64) with a COFF data layout, route the triple to it in the target and driver, mirroring the existing x86_64 UEFI target.
In the AArch64 backend, allow COFF on UEFI in addition to Windows: add Subtarget::isTargetUEFI(), relax the MCInstLower Windows-only COFF assertion, and treat UEFI like Windows for frame-record layout and Windows CFI. This answers the existing TODO in AArch64FrameLowering's isTargetWindows() and keeps getCalleeSavedRegs() aligned so the (FP,LR) pairing stays consistent.
---
clang/lib/Basic/Targets.cpp | 2 +
clang/lib/Basic/Targets/AArch64.cpp | 37 +++++++++++++++++++
clang/lib/Basic/Targets/AArch64.h | 11 ++++++
clang/lib/Driver/Driver.cpp | 6 ++-
.../Target/AArch64/AArch64FrameLowering.cpp | 11 +++---
.../lib/Target/AArch64/AArch64MCInstLower.cpp | 4 +-
.../Target/AArch64/AArch64RegisterInfo.cpp | 6 ++-
llvm/lib/Target/AArch64/AArch64Subtarget.h | 1 +
8 files changed, 68 insertions(+), 10 deletions(-)
diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp
index 8c01cfca8ccb4..823a2f08943ff 100644
--- a/clang/lib/Basic/Targets.cpp
+++ b/clang/lib/Basic/Targets.cpp
@@ -190,6 +190,8 @@ std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
default: // Assume MSVC for unknown environments
return std::make_unique<MicrosoftARM64TargetInfo>(Triple, Opts);
}
+ case llvm::Triple::UEFI:
+ return std::make_unique<UEFIAArch64TargetInfo>(Triple, Opts);
default:
return std::make_unique<AArch64leTargetInfo>(Triple, Opts);
}
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index d531e26ade84a..126791d725cd2 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -1859,6 +1859,43 @@ MinGWARM64TargetInfo::MinGWARM64TargetInfo(const llvm::Triple &Triple,
TheCXXABI.set(TargetCXXABI::GenericAArch64);
}
+UEFIAArch64TargetInfo::UEFIAArch64TargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : UEFITargetInfo<AArch64leTargetInfo>(Triple, Opts) {
+ // UEFI images are PE/COFF and follow the Microsoft ARM64 ABI. The UEFI spec
+ // does not mandate a specific C++ ABI or integer model, so we match the
+ // Windows ARM64 target -- the only supported way to produce AArch64 EFI
+ // binaries with Clang/LLVM today.
+ TheCXXABI.set(TargetCXXABI::Microsoft);
+
+ // LLP64 data model: int:4, long:4, long long:8, long double:8.
+ IntWidth = IntAlign = 32;
+ LongWidth = LongAlign = 32;
+ DoubleAlign = LongLongAlign = 64;
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+ IntMaxType = SignedLongLong;
+ Int64Type = SignedLongLong;
+ SizeType = UnsignedLongLong;
+ PtrDiffType = SignedLongLong;
+ IntPtrType = SignedLongLong;
+}
+
+void UEFIAArch64TargetInfo::setDataLayout() {
+ // PE/COFF image: use the same data layout the LLVM AArch64 TargetMachine
+ // computes for COFF. This must be an override (not just a ctor call) because
+ // handleTargetFeatures() re-invokes setDataLayout() after construction, and
+ // the AArch64le base only knows MachO/ELF -- it would otherwise revert to an
+ // ELF layout that mismatches the backend.
+ resetDataLayout("e-m:w-p270:32:32-p271:32:32-p272:64:64-p:64:64-i32:32-"
+ "i64:64-i128:128-n32:64-S128-Fn32");
+}
+
+AArch64TargetInfo::BuiltinVaListKind
+UEFIAArch64TargetInfo::getBuiltinVaListKind() const {
+ return TargetInfo::CharPtrBuiltinVaList;
+}
+
AppleMachOAArch64TargetInfo::AppleMachOAArch64TargetInfo(
const llvm::Triple &Triple, const TargetOptions &Opts)
: AppleMachOTargetInfo<AArch64leTargetInfo>(Triple, Opts) {}
diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h
index 3ccfa265399be..046713668bb1e 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -316,6 +316,17 @@ class LLVM_LIBRARY_VISIBILITY MinGWARM64TargetInfo
MinGWARM64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
};
+// ARM64 UEFI target (PE/COFF image, Microsoft ARM64 ABI)
+class LLVM_LIBRARY_VISIBILITY UEFIAArch64TargetInfo
+ : public UEFITargetInfo<AArch64leTargetInfo> {
+public:
+ UEFIAArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
+
+ void setDataLayout() override;
+
+ BuiltinVaListKind getBuiltinVaListKind() const override;
+};
+
class LLVM_LIBRARY_VISIBILITY AArch64beTargetInfo : public AArch64TargetInfo {
public:
AArch64beTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 38795f7c2ae7a..5bb1716902f1c 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -714,8 +714,10 @@ static llvm::Triple computeTargetTriple(const Driver &D, StringRef TargetTriple,
}
#endif
- // Currently the only architecture supported by *-uefi triples are x86_64.
- if (Target.isUEFI() && Target.getArch() != llvm::Triple::x86_64)
+ // The architectures currently supported by *-uefi triples are x86_64 and
+ // aarch64 (both emit PE/COFF images under the Microsoft ABI).
+ if (Target.isUEFI() && Target.getArch() != llvm::Triple::x86_64 &&
+ Target.getArch() != llvm::Triple::aarch64)
D.Diag(diag::err_target_unknown_triple) << Target.str();
// The `-maix[32|64]` flags are only valid for AIX targets.
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 6ef64b06932ab..3eeea74c98453 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -384,12 +384,13 @@ static bool isLikelyToHaveSVEStack(const AArch64FrameLowering &AFL,
}
static bool isTargetWindows(const MachineFunction &MF) {
- // TODO: Should this include targets like UEFI (which use Windows CFI)?
- // Note: Currently, there is not AArch64 support for UEFI. The value returned
- // here must align with the predicate used for returning the list of callee
- // saved regs in AArch64RegisterInfo::getCalleeSavedRegs(), so that we use
+ // UEFI images are PE/COFF and use Windows CFI, so for frame-record layout and
+ // unwind they behave like Windows. This value must align with the predicate
+ // used for returning the list of callee saved regs in
+ // AArch64RegisterInfo::getCalleeSavedRegs(), so that we use
// invalidateWindowsRegisterPairing() where appropriate.
- return MF.getSubtarget<AArch64Subtarget>().isTargetWindows();
+ const AArch64Subtarget &STI = MF.getSubtarget<AArch64Subtarget>();
+ return STI.isTargetWindows() || STI.isTargetUEFI();
}
bool AArch64FrameLowering::hasSVECalleeSavesAboveFrameRecord(
diff --git a/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp b/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp
index d3a38624488e8..ce0e0ef39ad0e 100644
--- a/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp
+++ b/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp
@@ -49,8 +49,8 @@ MCSymbol *AArch64MCInstLower::GetGlobalValueSymbol(const GlobalValue *GV,
if (!TheTriple.isOSBinFormatCOFF())
return Printer.getSymbolPreferLocal(*GV);
- assert(TheTriple.isOSWindows() &&
- "Windows is the only supported COFF target");
+ assert((TheTriple.isOSWindows() || TheTriple.isUEFI()) &&
+ "COFF is only supported on Windows and UEFI targets");
bool IsIndirect =
(TargetFlags & (AArch64II::MO_DLLIMPORT | AArch64II::MO_COFFSTUB));
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
index 502c91fe3e531..920c1bf29963c 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
@@ -76,7 +76,11 @@ AArch64RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
const auto &F = MF->getFunction();
const auto *TLI = MF->getSubtarget<AArch64Subtarget>().getTargetLowering();
const bool Darwin = MF->getSubtarget<AArch64Subtarget>().isTargetDarwin();
- const bool Windows = MF->getSubtarget<AArch64Subtarget>().isTargetWindows();
+ // UEFI uses the Windows PE/COFF ABI, so it takes the same callee-saved
+ // register lists (this must align with isTargetWindows() in
+ // AArch64FrameLowering, which drives invalidateWindowsRegisterPairing()).
+ const bool Windows = MF->getSubtarget<AArch64Subtarget>().isTargetWindows() ||
+ MF->getSubtarget<AArch64Subtarget>().isTargetUEFI();
if (TLI->supportSwiftError() &&
F.getAttributes().hasAttrSomewhere(Attribute::SwiftError)) {
diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.h b/llvm/lib/Target/AArch64/AArch64Subtarget.h
index 380c3e11fcbf2..68a9947e8e88d 100644
--- a/llvm/lib/Target/AArch64/AArch64Subtarget.h
+++ b/llvm/lib/Target/AArch64/AArch64Subtarget.h
@@ -312,6 +312,7 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
bool isTargetIOS() const { return TargetTriple.isiOS(); }
bool isTargetLinux() const { return TargetTriple.isOSLinux(); }
bool isTargetWindows() const { return TargetTriple.isOSWindows(); }
+ bool isTargetUEFI() const { return TargetTriple.isUEFI(); }
bool isTargetAndroid() const { return TargetTriple.isAndroid(); }
bool isTargetFuchsia() const { return TargetTriple.isOSFuchsia(); }
bool isWindowsArm64EC() const { return TargetTriple.isWindowsArm64EC(); }
More information about the cfe-commits
mailing list