[clang] [UEFI] X86_64 UEFI Clang Driver (PR #76838)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 12 13:38:36 PDT 2024
https://github.com/Prabhuk updated https://github.com/llvm/llvm-project/pull/76838
>From 7cc2e01a4a272934861e0d36791985e9604d9794 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Mon, 4 Dec 2023 08:54:14 -0800
Subject: [PATCH 1/2] [UEFI] X86_64 UEFI Clang Driver
Introduce changes necessary for UEFI X86_64 target Clang driver.
Reviewed By: phosek
Differential Revision: https://reviews.llvm.org/D159541
---
clang/lib/Basic/Targets.cpp | 3 +
clang/lib/Basic/Targets/OSTargets.h | 15 ++++
clang/lib/Basic/Targets/X86.h | 37 ++++++++++
clang/lib/Driver/CMakeLists.txt | 1 +
clang/lib/Driver/Driver.cpp | 4 ++
clang/lib/Driver/ToolChains/UEFI.cpp | 88 +++++++++++++++++++++++
clang/lib/Driver/ToolChains/UEFI.h | 61 ++++++++++++++++
clang/test/CodeGen/target-data.c | 4 ++
clang/test/Driver/uefi-constructed-args.c | 13 ++++
clang/test/Driver/uefi-data-layout.c | 3 +
clang/unittests/Driver/ToolChainTest.cpp | 21 ++++++
11 files changed, 250 insertions(+)
create mode 100644 clang/lib/Driver/ToolChains/UEFI.cpp
create mode 100644 clang/lib/Driver/ToolChains/UEFI.h
create mode 100644 clang/test/Driver/uefi-constructed-args.c
create mode 100644 clang/test/Driver/uefi-data-layout.c
diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp
index 0b8e565345b6a4..4917ef015941be 100644
--- a/clang/lib/Basic/Targets.cpp
+++ b/clang/lib/Basic/Targets.cpp
@@ -613,6 +613,9 @@ std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
case llvm::Triple::Solaris:
return std::make_unique<SolarisTargetInfo<X86_64TargetInfo>>(Triple,
Opts);
+ case llvm::Triple::UEFI:
+ return std::make_unique<UEFIX86_64TargetInfo>(Triple, Opts);
+
case llvm::Triple::Win32: {
switch (Triple.getEnvironment()) {
case llvm::Triple::Cygnus:
diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h
index 0a4f06967fff5a..a83d6464e789d6 100644
--- a/clang/lib/Basic/Targets/OSTargets.h
+++ b/clang/lib/Basic/Targets/OSTargets.h
@@ -778,6 +778,21 @@ class LLVM_LIBRARY_VISIBILITY ZOSTargetInfo : public OSTargetInfo<Target> {
}
};
+// UEFI target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY UEFITargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {}
+
+public:
+ UEFITargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {
+ this->WCharType = TargetInfo::UnsignedShort;
+ this->WIntType = TargetInfo::UnsignedShort;
+ }
+};
+
void addWindowsDefines(const llvm::Triple &Triple, const LangOptions &Opts,
MacroBuilder &Builder);
diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h
index 79fd5867cf6673..a99ae62984c7d5 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -814,6 +814,43 @@ class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo {
}
};
+// x86-64 UEFI target
+class LLVM_LIBRARY_VISIBILITY UEFIX86_64TargetInfo
+ : public UEFITargetInfo<X86_64TargetInfo> {
+public:
+ UEFIX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : UEFITargetInfo<X86_64TargetInfo>(Triple, Opts) {
+ this->TheCXXABI.set(TargetCXXABI::Microsoft);
+ this->MaxTLSAlign = 8192u * this->getCharWidth();
+ this->resetDataLayout("e-m:w-p270:32:32-p271:32:32-p272:64:64-"
+ "i64:64-i128:128-f80:128-n8:16:32:64-S128");
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ getOSDefines(Opts, X86TargetInfo::getTriple(), Builder);
+ }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::CharPtrBuiltinVaList;
+ }
+
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
+ switch (CC) {
+ case CC_C:
+ case CC_Win64:
+ return CCCR_OK;
+ default:
+ return CCCR_Warning;
+ }
+ }
+
+ TargetInfo::CallingConvKind
+ getCallingConvKind(bool ClangABICompat4) const override {
+ return CCK_MicrosoftWin64;
+ }
+};
+
// x86-64 Windows target
class LLVM_LIBRARY_VISIBILITY WindowsX86_64TargetInfo
: public WindowsTargetInfo<X86_64TargetInfo> {
diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt
index 32a4378ab499fa..4fd10bf671512f 100644
--- a/clang/lib/Driver/CMakeLists.txt
+++ b/clang/lib/Driver/CMakeLists.txt
@@ -78,6 +78,7 @@ add_clang_library(clangDriver
ToolChains/Solaris.cpp
ToolChains/SPIRV.cpp
ToolChains/TCE.cpp
+ ToolChains/UEFI.cpp
ToolChains/VEToolchain.cpp
ToolChains/WebAssembly.cpp
ToolChains/XCore.cpp
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 5b3783e20eabba..18d5cef79b05c8 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -45,6 +45,7 @@
#include "ToolChains/SPIRV.h"
#include "ToolChains/Solaris.h"
#include "ToolChains/TCE.h"
+#include "ToolChains/UEFI.h"
#include "ToolChains/VEToolchain.h"
#include "ToolChains/WebAssembly.h"
#include "ToolChains/XCore.h"
@@ -6416,6 +6417,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
case llvm::Triple::Mesa3D:
TC = std::make_unique<toolchains::AMDGPUToolChain>(*this, Target, Args);
break;
+ case llvm::Triple::UEFI:
+ TC = std::make_unique<toolchains::UEFI>(*this, Target, Args);
+ break;
case llvm::Triple::Win32:
switch (Target.getEnvironment()) {
default:
diff --git a/clang/lib/Driver/ToolChains/UEFI.cpp b/clang/lib/Driver/ToolChains/UEFI.cpp
new file mode 100644
index 00000000000000..6132c9c20fd64d
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/UEFI.cpp
@@ -0,0 +1,88 @@
+//===--- UEFI.h - UEFI ToolChain Implementations ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "UEFI.h"
+#include "CommonArgs.h"
+#include "Darwin.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/Version.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/TargetParser/Host.h"
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+UEFI::UEFI(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
+ : ToolChain(D, Triple, Args) {}
+
+Tool *UEFI::buildLinker() const { return new tools::uefi::Linker(*this); }
+
+void tools::uefi::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+ auto &TC = static_cast<const toolchains::UEFI &>(getToolChain());
+
+ assert((Output.isFilename() || Output.isNothing()) && "invalid output");
+ if (Output.isFilename())
+ CmdArgs.push_back(
+ Args.MakeArgString(std::string("-out:") + Output.getFilename()));
+
+ CmdArgs.push_back("-nologo");
+
+ // TODO: Other UEFI binary subsystems that are currently unsupported:
+ // efi_boot_service_driver, efi_rom, efi_runtime_driver.
+ CmdArgs.push_back("-subsystem:efi_application");
+
+ // Default entry function name according to the TianoCore reference
+ // implementation is EfiMain.
+ // TODO: Provide a flag to override the entry function name.
+ CmdArgs.push_back("-entry:EfiMain");
+
+ // "Terminal Service Aware" flag is not needed for UEFI applications.
+ CmdArgs.push_back("-tsaware:no");
+
+ // EFI_APPLICATION to be linked as DLL by default.
+ CmdArgs.push_back("-dll");
+
+ if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7))
+ CmdArgs.push_back("-debug");
+
+ Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
+
+ AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
+
+ // This should ideally be handled by ToolChain::GetLinkerPath but we need
+ // to special case some linker paths. In the case of lld, we need to
+ // translate 'lld' into 'lld-link'.
+ StringRef Linker =
+ Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER);
+ if (Linker.empty() || Linker == "lld")
+ Linker = "lld-link";
+
+ auto LinkerPath = TC.GetProgramPath(Linker.str().c_str());
+ auto LinkCmd = std::make_unique<Command>(
+ JA, *this, ResponseFileSupport::AtFileUTF16(),
+ Args.MakeArgString(LinkerPath), CmdArgs, Inputs, Output);
+ C.addCommand(std::move(LinkCmd));
+}
diff --git a/clang/lib/Driver/ToolChains/UEFI.h b/clang/lib/Driver/ToolChains/UEFI.h
new file mode 100644
index 00000000000000..3e1cc558aa7d17
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/UEFI.h
@@ -0,0 +1,61 @@
+//===--- UEFI.h - UEFI ToolChain Implementations ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_UEFI_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_UEFI_H
+
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace uefi {
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+public:
+ Linker(const ToolChain &TC) : Tool("uefi::Linker", "lld-link", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace uefi
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY UEFI : public ToolChain {
+public:
+ UEFI(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+protected:
+ Tool *buildLinker() const override;
+
+public:
+ bool HasNativeLLVMSupport() const override { return true; }
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override {
+ return UnwindTableLevel::Asynchronous;
+ }
+ bool isPICDefault() const override { return true; }
+ bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
+ return false;
+ }
+ bool isPICDefaultForced() const override { return true; }
+};
+
+} // namespace toolchains
+} // namespace driver
+} // namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_UEFI_H
diff --git a/clang/test/CodeGen/target-data.c b/clang/test/CodeGen/target-data.c
index 41cbd5a0219d5e..eaad2adb229bc8 100644
--- a/clang/test/CodeGen/target-data.c
+++ b/clang/test/CodeGen/target-data.c
@@ -22,6 +22,10 @@
// RUN: FileCheck --check-prefix=X86_64 %s
// X86_64: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+// RUN: %clang_cc1 -triple x86_64-unknown-uefi -emit-llvm -o - %s | \
+// RUN: FileCheck --check-prefix=X86_64_UEFI %s
+// X86_64_UEFI: target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+
// RUN: %clang_cc1 -triple xcore-unknown-unknown -emit-llvm -o - %s | \
// RUN: FileCheck --check-prefix=XCORE %s
// XCORE: target datalayout = "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32-f64:32-a:0:32-n32"
diff --git a/clang/test/Driver/uefi-constructed-args.c b/clang/test/Driver/uefi-constructed-args.c
new file mode 100644
index 00000000000000..91de4d7405deeb
--- /dev/null
+++ b/clang/test/Driver/uefi-constructed-args.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cl -### %s --target=x86_64-unknown-uefi \
+// RUN: --sysroot=%S/platform -fuse-ld=lld -g 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHECK %s
+// CHECK: "-cc1"
+// CHECK-SAME: "-triple" "x86_64-unknown-uefi"
+// CHECK-SAME: "-mrelocation-model" "pic" "-pic-level" "2"
+// CHECK-SAME: "-mframe-pointer=all"
+// CHECK-NEXT: "-nologo"
+// CHECK-SAME: "-subsystem:efi_application"
+// CHECK-SAME: "-entry:EfiMain"
+// CHECK-SAME: "-tsaware:no"
+// CHECK-SAME: "-dll"
+// CHECK-SAME: "-debug"
\ No newline at end of file
diff --git a/clang/test/Driver/uefi-data-layout.c b/clang/test/Driver/uefi-data-layout.c
new file mode 100644
index 00000000000000..f0da4603b34669
--- /dev/null
+++ b/clang/test/Driver/uefi-data-layout.c
@@ -0,0 +1,3 @@
+// RUN: %clang -target x86_64-unknown-uefi -S -emit-llvm -o - %s | \
+// RUN: FileCheck --check-prefix=X86_64_UEFI %s
+// X86_64_UEFI: target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
\ No newline at end of file
diff --git a/clang/unittests/Driver/ToolChainTest.cpp b/clang/unittests/Driver/ToolChainTest.cpp
index a9b5f3c700315c..8542a168f93c27 100644
--- a/clang/unittests/Driver/ToolChainTest.cpp
+++ b/clang/unittests/Driver/ToolChainTest.cpp
@@ -14,6 +14,7 @@
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
@@ -574,6 +575,26 @@ TEST(CompilerInvocation, SplitSwarfSingleCrash) {
EXPECT_TRUE(CI); // no-crash
}
+TEST(ToolChainTest, UEFICallingConventionTest) {
+ clang::CompilerInstance compiler;
+ compiler.createDiagnostics();
+
+ std::string TrStr = "x86_64-unknown-uefi";
+ llvm::Triple Tr(TrStr);
+ Tr.setOS(llvm::Triple::OSType::UEFI);
+ Tr.setVendor(llvm::Triple::VendorType::UnknownVendor);
+ Tr.setEnvironment(llvm::Triple::EnvironmentType::UnknownEnvironment);
+ Tr.setArch(llvm::Triple::ArchType::x86_64);
+
+ compiler.getTargetOpts().Triple = Tr.getTriple();
+ compiler.setTarget(clang::TargetInfo::CreateTargetInfo(
+ compiler.getDiagnostics(),
+ std::make_shared<clang::TargetOptions>(compiler.getTargetOpts())));
+
+ EXPECT_EQ(compiler.getTarget().getCallingConvKind(true),
+ TargetInfo::CallingConvKind::CCK_MicrosoftWin64);
+}
+
TEST(GetDriverMode, PrefersLastDriverMode) {
static constexpr const char *Args[] = {"clang-cl", "--driver-mode=foo",
"--driver-mode=bar", "foo.cpp"};
>From 96b5a06298b049b64db3a37e79aa0e0ef37e82c3 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Thu, 12 Sep 2024 13:38:01 -0700
Subject: [PATCH 2/2] Add end of file new lines.
---
clang/test/Driver/uefi-constructed-args.c | 3 ++-
clang/test/Driver/uefi-data-layout.c | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/clang/test/Driver/uefi-constructed-args.c b/clang/test/Driver/uefi-constructed-args.c
index 91de4d7405deeb..7bc64da749ddce 100644
--- a/clang/test/Driver/uefi-constructed-args.c
+++ b/clang/test/Driver/uefi-constructed-args.c
@@ -10,4 +10,5 @@
// CHECK-SAME: "-entry:EfiMain"
// CHECK-SAME: "-tsaware:no"
// CHECK-SAME: "-dll"
-// CHECK-SAME: "-debug"
\ No newline at end of file
+// CHECK-SAME: "-debug"
+
diff --git a/clang/test/Driver/uefi-data-layout.c b/clang/test/Driver/uefi-data-layout.c
index f0da4603b34669..60bb0bff115c64 100644
--- a/clang/test/Driver/uefi-data-layout.c
+++ b/clang/test/Driver/uefi-data-layout.c
@@ -1,3 +1,4 @@
// RUN: %clang -target x86_64-unknown-uefi -S -emit-llvm -o - %s | \
// RUN: FileCheck --check-prefix=X86_64_UEFI %s
-// X86_64_UEFI: target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
\ No newline at end of file
+// X86_64_UEFI: target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+
More information about the cfe-commits
mailing list