Skip to content

Commit

Permalink
Reland "[Driver] Add toolchain for X86_64 UEFI target" (llvm#109364)
Browse files Browse the repository at this point in the history
Reverts llvm#109340

Addressing the failed MAC Clang Driver test as part of this reland.
  • Loading branch information
Prabhuk authored Sep 20, 2024
1 parent d497f46 commit fb78495
Show file tree
Hide file tree
Showing 10 changed files with 243 additions and 0 deletions.
3 changes: 3 additions & 0 deletions clang/lib/Basic/Targets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/Basic/Targets/OSTargets.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
37 changes: 37 additions & 0 deletions clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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:
Expand Down
88 changes: 88 additions & 0 deletions clang/lib/Driver/ToolChains/UEFI.cpp
Original file line number Diff line number Diff line change
@@ -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));
}
59 changes: 59 additions & 0 deletions clang/lib/Driver/ToolChains/UEFI.h
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions clang/test/CodeGen/X86/uefi-data-layout.c
Original file line number Diff line number Diff line change
@@ -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"
12 changes: 12 additions & 0 deletions clang/test/Driver/uefi-constructed-args.c
Original file line number Diff line number Diff line change
@@ -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"
21 changes: 21 additions & 0 deletions clang/unittests/Driver/ToolChainTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"};
Expand Down

0 comments on commit fb78495

Please sign in to comment.