Skip to content

Commit d1335fb

Browse files
authored
[Driver] Add toolchain for X86_64 UEFI target (#76838)
Introduce changes necessary for UEFI X86_64 target Clang driver. Addressed the review comments originally suggested in Phabricator. Differential Revision: https://reviews.llvm.org/D159541
1 parent ccfe7d4 commit d1335fb

File tree

10 files changed

+244
-0
lines changed

10 files changed

+244
-0
lines changed

clang/lib/Basic/Targets.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,9 @@ std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
613613
case llvm::Triple::Solaris:
614614
return std::make_unique<SolarisTargetInfo<X86_64TargetInfo>>(Triple,
615615
Opts);
616+
case llvm::Triple::UEFI:
617+
return std::make_unique<UEFIX86_64TargetInfo>(Triple, Opts);
618+
616619
case llvm::Triple::Win32: {
617620
switch (Triple.getEnvironment()) {
618621
case llvm::Triple::Cygnus:

clang/lib/Basic/Targets/OSTargets.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,21 @@ class LLVM_LIBRARY_VISIBILITY ZOSTargetInfo : public OSTargetInfo<Target> {
778778
}
779779
};
780780

781+
// UEFI target
782+
template <typename Target>
783+
class LLVM_LIBRARY_VISIBILITY UEFITargetInfo : public OSTargetInfo<Target> {
784+
protected:
785+
void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
786+
MacroBuilder &Builder) const override {}
787+
788+
public:
789+
UEFITargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
790+
: OSTargetInfo<Target>(Triple, Opts) {
791+
this->WCharType = TargetInfo::UnsignedShort;
792+
this->WIntType = TargetInfo::UnsignedShort;
793+
}
794+
};
795+
781796
void addWindowsDefines(const llvm::Triple &Triple, const LangOptions &Opts,
782797
MacroBuilder &Builder);
783798

clang/lib/Basic/Targets/X86.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,43 @@ class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo {
814814
}
815815
};
816816

817+
// x86-64 UEFI target
818+
class LLVM_LIBRARY_VISIBILITY UEFIX86_64TargetInfo
819+
: public UEFITargetInfo<X86_64TargetInfo> {
820+
public:
821+
UEFIX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
822+
: UEFITargetInfo<X86_64TargetInfo>(Triple, Opts) {
823+
this->TheCXXABI.set(TargetCXXABI::Microsoft);
824+
this->MaxTLSAlign = 8192u * this->getCharWidth();
825+
this->resetDataLayout("e-m:w-p270:32:32-p271:32:32-p272:64:64-"
826+
"i64:64-i128:128-f80:128-n8:16:32:64-S128");
827+
}
828+
829+
void getTargetDefines(const LangOptions &Opts,
830+
MacroBuilder &Builder) const override {
831+
getOSDefines(Opts, X86TargetInfo::getTriple(), Builder);
832+
}
833+
834+
BuiltinVaListKind getBuiltinVaListKind() const override {
835+
return TargetInfo::CharPtrBuiltinVaList;
836+
}
837+
838+
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
839+
switch (CC) {
840+
case CC_C:
841+
case CC_Win64:
842+
return CCCR_OK;
843+
default:
844+
return CCCR_Warning;
845+
}
846+
}
847+
848+
TargetInfo::CallingConvKind
849+
getCallingConvKind(bool ClangABICompat4) const override {
850+
return CCK_MicrosoftWin64;
851+
}
852+
};
853+
817854
// x86-64 Windows target
818855
class LLVM_LIBRARY_VISIBILITY WindowsX86_64TargetInfo
819856
: public WindowsTargetInfo<X86_64TargetInfo> {

clang/lib/Driver/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ add_clang_library(clangDriver
7878
ToolChains/Solaris.cpp
7979
ToolChains/SPIRV.cpp
8080
ToolChains/TCE.cpp
81+
ToolChains/UEFI.cpp
8182
ToolChains/VEToolchain.cpp
8283
ToolChains/WebAssembly.cpp
8384
ToolChains/XCore.cpp

clang/lib/Driver/Driver.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "ToolChains/SPIRV.h"
4646
#include "ToolChains/Solaris.h"
4747
#include "ToolChains/TCE.h"
48+
#include "ToolChains/UEFI.h"
4849
#include "ToolChains/VEToolchain.h"
4950
#include "ToolChains/WebAssembly.h"
5051
#include "ToolChains/XCore.h"
@@ -6416,6 +6417,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
64166417
case llvm::Triple::Mesa3D:
64176418
TC = std::make_unique<toolchains::AMDGPUToolChain>(*this, Target, Args);
64186419
break;
6420+
case llvm::Triple::UEFI:
6421+
TC = std::make_unique<toolchains::UEFI>(*this, Target, Args);
6422+
break;
64196423
case llvm::Triple::Win32:
64206424
switch (Target.getEnvironment()) {
64216425
default:

clang/lib/Driver/ToolChains/UEFI.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//===--- UEFI.cpp - UEFI ToolChain Implementations -----------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "UEFI.h"
10+
#include "CommonArgs.h"
11+
#include "Darwin.h"
12+
#include "clang/Basic/CharInfo.h"
13+
#include "clang/Basic/Version.h"
14+
#include "clang/Config/config.h"
15+
#include "clang/Driver/Compilation.h"
16+
#include "clang/Driver/Driver.h"
17+
#include "clang/Driver/Options.h"
18+
#include "clang/Driver/SanitizerArgs.h"
19+
#include "llvm/ADT/StringExtras.h"
20+
#include "llvm/ADT/StringSwitch.h"
21+
#include "llvm/Option/Arg.h"
22+
#include "llvm/Option/ArgList.h"
23+
#include "llvm/Support/FileSystem.h"
24+
#include "llvm/Support/MemoryBuffer.h"
25+
#include "llvm/Support/VirtualFileSystem.h"
26+
#include "llvm/TargetParser/Host.h"
27+
28+
using namespace clang::driver;
29+
using namespace clang::driver::toolchains;
30+
using namespace clang;
31+
using namespace llvm::opt;
32+
33+
UEFI::UEFI(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
34+
: ToolChain(D, Triple, Args) {}
35+
36+
Tool *UEFI::buildLinker() const { return new tools::uefi::Linker(*this); }
37+
38+
void tools::uefi::Linker::ConstructJob(Compilation &C, const JobAction &JA,
39+
const InputInfo &Output,
40+
const InputInfoList &Inputs,
41+
const ArgList &Args,
42+
const char *LinkingOutput) const {
43+
ArgStringList CmdArgs;
44+
auto &TC = static_cast<const toolchains::UEFI &>(getToolChain());
45+
46+
assert((Output.isFilename() || Output.isNothing()) && "invalid output");
47+
if (Output.isFilename())
48+
CmdArgs.push_back(
49+
Args.MakeArgString(std::string("-out:") + Output.getFilename()));
50+
51+
CmdArgs.push_back("-nologo");
52+
53+
// TODO: Other UEFI binary subsystems that are currently unsupported:
54+
// efi_boot_service_driver, efi_rom, efi_runtime_driver.
55+
CmdArgs.push_back("-subsystem:efi_application");
56+
57+
// Default entry function name according to the TianoCore reference
58+
// implementation is EfiMain.
59+
// TODO: Provide a flag to override the entry function name.
60+
CmdArgs.push_back("-entry:EfiMain");
61+
62+
// "Terminal Service Aware" flag is not needed for UEFI applications.
63+
CmdArgs.push_back("-tsaware:no");
64+
65+
// EFI_APPLICATION to be linked as DLL by default.
66+
CmdArgs.push_back("-dll");
67+
68+
if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7))
69+
CmdArgs.push_back("-debug");
70+
71+
Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
72+
73+
AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
74+
75+
// This should ideally be handled by ToolChain::GetLinkerPath but we need
76+
// to special case some linker paths. In the case of lld, we need to
77+
// translate 'lld' into 'lld-link'.
78+
StringRef Linker =
79+
Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER);
80+
if (Linker.empty() || Linker == "lld")
81+
Linker = "lld-link";
82+
83+
auto LinkerPath = TC.GetProgramPath(Linker.str().c_str());
84+
auto LinkCmd = std::make_unique<Command>(
85+
JA, *this, ResponseFileSupport::AtFileUTF16(),
86+
Args.MakeArgString(LinkerPath), CmdArgs, Inputs, Output);
87+
C.addCommand(std::move(LinkCmd));
88+
}

clang/lib/Driver/ToolChains/UEFI.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//===--- UEFI.h - UEFI ToolChain Implementations ----------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_UEFI_H
10+
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_UEFI_H
11+
12+
#include "clang/Driver/Tool.h"
13+
#include "clang/Driver/ToolChain.h"
14+
15+
namespace clang::driver {
16+
namespace tools {
17+
namespace uefi {
18+
class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
19+
public:
20+
Linker(const ToolChain &TC) : Tool("uefi::Linker", "lld-link", TC) {}
21+
22+
bool hasIntegratedCPP() const override { return false; }
23+
bool isLinkJob() const override { return true; }
24+
25+
void ConstructJob(Compilation &C, const JobAction &JA,
26+
const InputInfo &Output, const InputInfoList &Inputs,
27+
const llvm::opt::ArgList &TCArgs,
28+
const char *LinkingOutput) const override;
29+
};
30+
} // end namespace uefi
31+
} // end namespace tools
32+
33+
namespace toolchains {
34+
35+
class LLVM_LIBRARY_VISIBILITY UEFI : public ToolChain {
36+
public:
37+
UEFI(const Driver &D, const llvm::Triple &Triple,
38+
const llvm::opt::ArgList &Args);
39+
40+
protected:
41+
Tool *buildLinker() const override;
42+
43+
public:
44+
bool HasNativeLLVMSupport() const override { return true; }
45+
UnwindTableLevel
46+
getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override {
47+
return UnwindTableLevel::Asynchronous;
48+
}
49+
bool isPICDefault() const override { return true; }
50+
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
51+
return false;
52+
}
53+
bool isPICDefaultForced() const override { return true; }
54+
};
55+
56+
} // namespace toolchains
57+
} // namespace clang::driver
58+
59+
#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_UEFI_H
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// RUN: %clang -target x86_64-unknown-uefi -S -emit-llvm -o - %s | \
2+
// RUN: FileCheck --check-prefix=X86_64_UEFI %s
3+
// 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"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_cl -### %s --target=x86_64-unknown-uefi \
2+
// RUN: --sysroot=%S/platform -fuse-ld=lld -g 2>&1 \
3+
// RUN: | FileCheck -check-prefixes=CHECK %s
4+
// CHECK: "-cc1"
5+
// CHECK-SAME: "-triple" "x86_64-unknown-uefi"
6+
// CHECK-SAME: "-mrelocation-model" "pic" "-pic-level" "2"
7+
// CHECK-SAME: "-mframe-pointer=all"
8+
// CHECK-NEXT: "-nologo"
9+
// CHECK-SAME: "-subsystem:efi_application"
10+
// CHECK-SAME: "-entry:EfiMain"
11+
// CHECK-SAME: "-tsaware:no"
12+
// CHECK-SAME: "-dll"
13+
// CHECK-SAME: "-debug"

clang/unittests/Driver/ToolChainTest.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "clang/Basic/DiagnosticIDs.h"
1515
#include "clang/Basic/DiagnosticOptions.h"
1616
#include "clang/Basic/LLVM.h"
17+
#include "clang/Basic/TargetInfo.h"
1718
#include "clang/Basic/TargetOptions.h"
1819
#include "clang/Driver/Compilation.h"
1920
#include "clang/Driver/Driver.h"
@@ -574,6 +575,26 @@ TEST(CompilerInvocation, SplitSwarfSingleCrash) {
574575
EXPECT_TRUE(CI); // no-crash
575576
}
576577

578+
TEST(ToolChainTest, UEFICallingConventionTest) {
579+
clang::CompilerInstance compiler;
580+
compiler.createDiagnostics();
581+
582+
std::string TrStr = "x86_64-unknown-uefi";
583+
llvm::Triple Tr(TrStr);
584+
Tr.setOS(llvm::Triple::OSType::UEFI);
585+
Tr.setVendor(llvm::Triple::VendorType::UnknownVendor);
586+
Tr.setEnvironment(llvm::Triple::EnvironmentType::UnknownEnvironment);
587+
Tr.setArch(llvm::Triple::ArchType::x86_64);
588+
589+
compiler.getTargetOpts().Triple = Tr.getTriple();
590+
compiler.setTarget(clang::TargetInfo::CreateTargetInfo(
591+
compiler.getDiagnostics(),
592+
std::make_shared<clang::TargetOptions>(compiler.getTargetOpts())));
593+
594+
EXPECT_EQ(compiler.getTarget().getCallingConvKind(true),
595+
TargetInfo::CallingConvKind::CCK_MicrosoftWin64);
596+
}
597+
577598
TEST(GetDriverMode, PrefersLastDriverMode) {
578599
static constexpr const char *Args[] = {"clang-cl", "--driver-mode=foo",
579600
"--driver-mode=bar", "foo.cpp"};

0 commit comments

Comments
 (0)