https://github.com/paulober updated https://github.com/llvm/llvm-project/pull/213275
>From a5d76397a8d4e30cde988a04b4caa9dff48e9703 Mon Sep 17 00:00:00 2001 From: paulober <[email protected]> Date: Fri, 31 Jul 2026 14:39:08 +0200 Subject: [PATCH 1/2] [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(); } >From 3008dabcabd392556ecefeba46408a8ea3e3fa8f Mon Sep 17 00:00:00 2001 From: paulober <[email protected]> Date: Thu, 6 Aug 2026 09:57:51 +0200 Subject: [PATCH 2/2] [AArch64] Use the LP64 data model for aarch64-unknown-uefi LLP64 exported Swift's Int (via @c/@_cdecl) as a 32-bit C long, mismatching swift_allocObject's i64 size params and crashing IRGen for every heap allocation (Array/String/Set/Dictionary). LP64 keeps long == word size; the COFF object format and Windows-style CFI are unchanged. Signed-off-by: paulober <[email protected]> --- clang/lib/Basic/Targets/AArch64.cpp | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 126791d725cd2..acac2e3cfe8f9 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -1862,23 +1862,13 @@ MinGWARM64TargetInfo::MinGWARM64TargetInfo(const llvm::Triple &Triple, 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; + // UEFI images are PE/COFF, but we keep the AArch64 LP64 data model (inherited + // from the freestanding ELF base) rather than the Windows LLP64 model. The + // UEFI spec does not mandate a C integer model, a freestanding Swift firmware + // does not interop with UEFI/Windows C `long`, and LP64 keeps `long` == word + // size, which is what higher-level toolchains (e.g. Swift's Int <-> C integer + // mapping) assume. Only the object format and CFI are Windows-like -- see + // setDataLayout() below and the AArch64 frame lowering. } void UEFIAArch64TargetInfo::setDataLayout() { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
