Reland "[Driver] Add toolchain for X86_64 UEFI target" (#109364)

Reverts llvm/llvm-project#109340

Addressing the failed MAC Clang Driver test as part of this reland.
This commit is contained in:
Prabhuk
2024-09-20 11:16:36 -07:00
committed by GitHub
parent d497f465df
commit fb78495376
10 changed files with 243 additions and 0 deletions

View File

@@ -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:

View File

@@ -778,6 +778,21 @@ public:
}
};
// 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);

View File

@@ -814,6 +814,43 @@ public:
}
};
// 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> {

View File

@@ -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

View File

@@ -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"
@@ -6422,6 +6423,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:

View File

@@ -0,0 +1,88 @@
//===--- UEFI.cpp - UEFI ToolChain Implementations -----------------------===//
//
// 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));
}

View File

@@ -0,0 +1,59 @@
//===--- 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::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 clang::driver
#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_UEFI_H

View File

@@ -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"

View File

@@ -0,0 +1,12 @@
// RUN: %clang_cl -### --target=x86_64-unknown-uefi -g -- %s 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"

View File

@@ -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"};