llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-backend-aarch64 Author: Paul (paulober) <details> <summary>Changes</summary> Adds `aarch64-unknown-uefi` as a target, mirroring the existing `x86_64-unknown-uefi` support so Clang/LLVM can emit PE/COFF `.efi` binaries for AArch64 UEFI firmware. UEFI on AArch64 uses PE/COFF images and the Microsoft ARM64 ABI, so it reuses the Windows COFF paths rather than the ELF ones. **Clang** - New `UEFIAArch64TargetInfo` (PE/COFF, Microsoft ARM64 ABI, LLP64) with the COFF data layout; the AArch64 triple maps to it. - Allow `aarch64` in the driver's UEFI arch guard (previously x86_64-only). **AArch64 backend** - Add `AArch64Subtarget::isTargetUEFI()`. - Relax the `AArch64MCInstLower` "Windows is the only supported COFF target" assertion to also accept UEFI. - Treat UEFI like Windows for frame-record layout and Windows CFI (`AArch64FrameLowering::isTargetWindows`, `AArch64RegisterInfo::getCalleeSavedRegs`), keeping the callee-saved register lists aligned so the (FP, LR) pairing stays consistent. This answers the pre-existing `// TODO: Should this include targets like UEFI (which use Windows CFI)?` in `isTargetWindows()`. ### Motivation Enabling Embedded Swift to target AArch64 UEFI firmware; companion `swiftlang/swift` and `swiftlang/swift-driver` changes add the Swift-side support. This PR is the canonical upstream home for the change. A downstream cherry-pick exists at swiftlang/llvm-project#<!-- -->13596 purely to unblock that Swift work ahead of the upstream→downstream merge, and will be dropped once this lands. ### Status / testing Initial patch — it does **not yet include lit tests**, and I'd welcome guidance on the preferred coverage (a Clang `-target` data-layout test plus an AArch64 CodeGen COFF test seem natural). In an out-of-tree build, freestanding C and Embedded Swift compile for `aarch64-unknown-uefi` to valid `coff-arm64` objects with a correct frame record. --- Full diff: https://github.com/llvm/llvm-project/pull/213275.diff 8 Files Affected: - (modified) clang/lib/Basic/Targets.cpp (+2) - (modified) clang/lib/Basic/Targets/AArch64.cpp (+37) - (modified) clang/lib/Basic/Targets/AArch64.h (+11) - (modified) clang/lib/Driver/Driver.cpp (+4-2) - (modified) llvm/lib/Target/AArch64/AArch64FrameLowering.cpp (+6-5) - (modified) llvm/lib/Target/AArch64/AArch64MCInstLower.cpp (+2-2) - (modified) llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp (+5-1) - (modified) llvm/lib/Target/AArch64/AArch64Subtarget.h (+1) ``````````diff 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(); } `````````` </details> https://github.com/llvm/llvm-project/pull/213275 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
