Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@ -0,0 +1,387 @@
//===--- Action.cpp - Abstract compilation steps --------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Driver/Action.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Regex.h"
#include <cassert>
using namespace clang::driver;
using namespace llvm::opt;
Action::~Action() {}
const char *Action::getClassName(ActionClass AC) {
switch (AC) {
case InputClass: return "input";
case BindArchClass: return "bind-arch";
case OffloadClass:
return "offload";
case PreprocessJobClass: return "preprocessor";
case PrecompileJobClass: return "precompiler";
case AnalyzeJobClass: return "analyzer";
case MigrateJobClass: return "migrator";
case CompileJobClass: return "compiler";
case BackendJobClass: return "backend";
case AssembleJobClass: return "assembler";
case LinkJobClass: return "linker";
case LipoJobClass: return "lipo";
case DsymutilJobClass: return "dsymutil";
case VerifyDebugInfoJobClass: return "verify-debug-info";
case VerifyPCHJobClass: return "verify-pch";
case OffloadBundlingJobClass:
return "clang-offload-bundler";
case OffloadUnbundlingJobClass:
return "clang-offload-unbundler";
}
llvm_unreachable("invalid class");
}
void Action::propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch) {
// Offload action set its own kinds on their dependences.
if (Kind == OffloadClass)
return;
// Unbundling actions use the host kinds.
if (Kind == OffloadUnbundlingJobClass)
return;
assert((OffloadingDeviceKind == OKind || OffloadingDeviceKind == OFK_None) &&
"Setting device kind to a different device??");
assert(!ActiveOffloadKindMask && "Setting a device kind in a host action??");
OffloadingDeviceKind = OKind;
OffloadingArch = OArch;
for (auto *A : Inputs)
A->propagateDeviceOffloadInfo(OffloadingDeviceKind, OArch);
}
void Action::propagateHostOffloadInfo(unsigned OKinds, const char *OArch) {
// Offload action set its own kinds on their dependences.
if (Kind == OffloadClass)
return;
assert(OffloadingDeviceKind == OFK_None &&
"Setting a host kind in a device action.");
ActiveOffloadKindMask |= OKinds;
OffloadingArch = OArch;
for (auto *A : Inputs)
A->propagateHostOffloadInfo(ActiveOffloadKindMask, OArch);
}
void Action::propagateOffloadInfo(const Action *A) {
if (unsigned HK = A->getOffloadingHostActiveKinds())
propagateHostOffloadInfo(HK, A->getOffloadingArch());
else
propagateDeviceOffloadInfo(A->getOffloadingDeviceKind(),
A->getOffloadingArch());
}
std::string Action::getOffloadingKindPrefix() const {
switch (OffloadingDeviceKind) {
case OFK_None:
break;
case OFK_Host:
llvm_unreachable("Host kind is not an offloading device kind.");
break;
case OFK_Cuda:
return "device-cuda";
case OFK_OpenMP:
return "device-openmp";
// TODO: Add other programming models here.
}
if (!ActiveOffloadKindMask)
return "";
std::string Res("host");
if (ActiveOffloadKindMask & OFK_Cuda)
Res += "-cuda";
if (ActiveOffloadKindMask & OFK_OpenMP)
Res += "-openmp";
// TODO: Add other programming models here.
return Res;
}
/// Return a string that can be used as prefix in order to generate unique files
/// for each offloading kind.
std::string
Action::GetOffloadingFileNamePrefix(OffloadKind Kind,
llvm::StringRef NormalizedTriple,
bool CreatePrefixForHost) {
// Don't generate prefix for host actions unless required.
if (!CreatePrefixForHost && (Kind == OFK_None || Kind == OFK_Host))
return "";
std::string Res("-");
Res += GetOffloadKindName(Kind);
Res += "-";
Res += NormalizedTriple;
return Res;
}
/// Return a string with the offload kind name. If that is not defined, we
/// assume 'host'.
llvm::StringRef Action::GetOffloadKindName(OffloadKind Kind) {
switch (Kind) {
case OFK_None:
case OFK_Host:
return "host";
case OFK_Cuda:
return "cuda";
case OFK_OpenMP:
return "openmp";
// TODO: Add other programming models here.
}
llvm_unreachable("invalid offload kind");
}
void InputAction::anchor() {}
InputAction::InputAction(const Arg &_Input, types::ID _Type)
: Action(InputClass, _Type), Input(_Input) {
}
void BindArchAction::anchor() {}
BindArchAction::BindArchAction(Action *Input, llvm::StringRef ArchName)
: Action(BindArchClass, Input), ArchName(ArchName) {}
void OffloadAction::anchor() {}
OffloadAction::OffloadAction(const HostDependence &HDep)
: Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()) {
OffloadingArch = HDep.getBoundArch();
ActiveOffloadKindMask = HDep.getOffloadKinds();
HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(),
HDep.getBoundArch());
}
OffloadAction::OffloadAction(const DeviceDependences &DDeps, types::ID Ty)
: Action(OffloadClass, DDeps.getActions(), Ty),
DevToolChains(DDeps.getToolChains()) {
auto &OKinds = DDeps.getOffloadKinds();
auto &BArchs = DDeps.getBoundArchs();
// If all inputs agree on the same kind, use it also for this action.
if (llvm::all_of(OKinds, [&](OffloadKind K) { return K == OKinds.front(); }))
OffloadingDeviceKind = OKinds.front();
// If we have a single dependency, inherit the architecture from it.
if (OKinds.size() == 1)
OffloadingArch = BArchs.front();
// Propagate info to the dependencies.
for (unsigned i = 0, e = getInputs().size(); i != e; ++i)
getInputs()[i]->propagateDeviceOffloadInfo(OKinds[i], BArchs[i]);
}
OffloadAction::OffloadAction(const HostDependence &HDep,
const DeviceDependences &DDeps)
: Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()),
DevToolChains(DDeps.getToolChains()) {
// We use the kinds of the host dependence for this action.
OffloadingArch = HDep.getBoundArch();
ActiveOffloadKindMask = HDep.getOffloadKinds();
HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(),
HDep.getBoundArch());
// Add device inputs and propagate info to the device actions. Do work only if
// we have dependencies.
for (unsigned i = 0, e = DDeps.getActions().size(); i != e; ++i)
if (auto *A = DDeps.getActions()[i]) {
getInputs().push_back(A);
A->propagateDeviceOffloadInfo(DDeps.getOffloadKinds()[i],
DDeps.getBoundArchs()[i]);
}
}
void OffloadAction::doOnHostDependence(const OffloadActionWorkTy &Work) const {
if (!HostTC)
return;
assert(!getInputs().empty() && "No dependencies for offload action??");
auto *A = getInputs().front();
Work(A, HostTC, A->getOffloadingArch());
}
void OffloadAction::doOnEachDeviceDependence(
const OffloadActionWorkTy &Work) const {
auto I = getInputs().begin();
auto E = getInputs().end();
if (I == E)
return;
// We expect to have the same number of input dependences and device tool
// chains, except if we also have a host dependence. In that case we have one
// more dependence than we have device tool chains.
assert(getInputs().size() == DevToolChains.size() + (HostTC ? 1 : 0) &&
"Sizes of action dependences and toolchains are not consistent!");
// Skip host action
if (HostTC)
++I;
auto TI = DevToolChains.begin();
for (; I != E; ++I, ++TI)
Work(*I, *TI, (*I)->getOffloadingArch());
}
void OffloadAction::doOnEachDependence(const OffloadActionWorkTy &Work) const {
doOnHostDependence(Work);
doOnEachDeviceDependence(Work);
}
void OffloadAction::doOnEachDependence(bool IsHostDependence,
const OffloadActionWorkTy &Work) const {
if (IsHostDependence)
doOnHostDependence(Work);
else
doOnEachDeviceDependence(Work);
}
bool OffloadAction::hasHostDependence() const { return HostTC != nullptr; }
Action *OffloadAction::getHostDependence() const {
assert(hasHostDependence() && "Host dependence does not exist!");
assert(!getInputs().empty() && "No dependencies for offload action??");
return HostTC ? getInputs().front() : nullptr;
}
bool OffloadAction::hasSingleDeviceDependence(
bool DoNotConsiderHostActions) const {
if (DoNotConsiderHostActions)
return getInputs().size() == (HostTC ? 2 : 1);
return !HostTC && getInputs().size() == 1;
}
Action *
OffloadAction::getSingleDeviceDependence(bool DoNotConsiderHostActions) const {
assert(hasSingleDeviceDependence(DoNotConsiderHostActions) &&
"Single device dependence does not exist!");
// The previous assert ensures the number of entries in getInputs() is
// consistent with what we are doing here.
return HostTC ? getInputs()[1] : getInputs().front();
}
void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC,
const char *BoundArch,
OffloadKind OKind) {
DeviceActions.push_back(&A);
DeviceToolChains.push_back(&TC);
DeviceBoundArchs.push_back(BoundArch);
DeviceOffloadKinds.push_back(OKind);
}
OffloadAction::HostDependence::HostDependence(Action &A, const ToolChain &TC,
const char *BoundArch,
const DeviceDependences &DDeps)
: HostAction(A), HostToolChain(TC), HostBoundArch(BoundArch) {
for (auto K : DDeps.getOffloadKinds())
HostOffloadKinds |= K;
}
void JobAction::anchor() {}
JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type)
: Action(Kind, Input, Type) {}
JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
: Action(Kind, Inputs, Type) {
}
void PreprocessJobAction::anchor() {}
PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType)
: JobAction(PreprocessJobClass, Input, OutputType) {}
void PrecompileJobAction::anchor() {}
PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType)
: JobAction(PrecompileJobClass, Input, OutputType) {}
void AnalyzeJobAction::anchor() {}
AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)
: JobAction(AnalyzeJobClass, Input, OutputType) {}
void MigrateJobAction::anchor() {}
MigrateJobAction::MigrateJobAction(Action *Input, types::ID OutputType)
: JobAction(MigrateJobClass, Input, OutputType) {}
void CompileJobAction::anchor() {}
CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType)
: JobAction(CompileJobClass, Input, OutputType) {}
void BackendJobAction::anchor() {}
BackendJobAction::BackendJobAction(Action *Input, types::ID OutputType)
: JobAction(BackendJobClass, Input, OutputType) {}
void AssembleJobAction::anchor() {}
AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)
: JobAction(AssembleJobClass, Input, OutputType) {}
void LinkJobAction::anchor() {}
LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type)
: JobAction(LinkJobClass, Inputs, Type) {
}
void LipoJobAction::anchor() {}
LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type)
: JobAction(LipoJobClass, Inputs, Type) {
}
void DsymutilJobAction::anchor() {}
DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type)
: JobAction(DsymutilJobClass, Inputs, Type) {
}
void VerifyJobAction::anchor() {}
VerifyJobAction::VerifyJobAction(ActionClass Kind, Action *Input,
types::ID Type)
: JobAction(Kind, Input, Type) {
assert((Kind == VerifyDebugInfoJobClass || Kind == VerifyPCHJobClass) &&
"ActionClass is not a valid VerifyJobAction");
}
void VerifyDebugInfoJobAction::anchor() {}
VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(Action *Input,
types::ID Type)
: VerifyJobAction(VerifyDebugInfoJobClass, Input, Type) {}
void VerifyPCHJobAction::anchor() {}
VerifyPCHJobAction::VerifyPCHJobAction(Action *Input, types::ID Type)
: VerifyJobAction(VerifyPCHJobClass, Input, Type) {}
void OffloadBundlingJobAction::anchor() {}
OffloadBundlingJobAction::OffloadBundlingJobAction(ActionList &Inputs)
: JobAction(OffloadBundlingJobClass, Inputs, Inputs.front()->getType()) {}
void OffloadUnbundlingJobAction::anchor() {}
OffloadUnbundlingJobAction::OffloadUnbundlingJobAction(Action *Input)
: JobAction(OffloadUnbundlingJobClass, Input, Input->getType()) {}

View File

@ -0,0 +1,71 @@
set(LLVM_LINK_COMPONENTS
BinaryFormat
Option
Support
)
if(WIN32)
# MSVCToolChain.cpp uses version.dll.
set(system_libs version)
endif()
add_clang_library(clangDriver
Action.cpp
Compilation.cpp
Distro.cpp
Driver.cpp
DriverOptions.cpp
Job.cpp
Multilib.cpp
Phases.cpp
SanitizerArgs.cpp
Tool.cpp
ToolChain.cpp
ToolChains/Arch/AArch64.cpp
ToolChains/Arch/ARM.cpp
ToolChains/Arch/Mips.cpp
ToolChains/Arch/PPC.cpp
ToolChains/Arch/Sparc.cpp
ToolChains/Arch/SystemZ.cpp
ToolChains/Arch/X86.cpp
ToolChains/Ananas.cpp
ToolChains/AMDGPU.cpp
ToolChains/AVR.cpp
ToolChains/BareMetal.cpp
ToolChains/Clang.cpp
ToolChains/CloudABI.cpp
ToolChains/CommonArgs.cpp
ToolChains/Contiki.cpp
ToolChains/CrossWindows.cpp
ToolChains/Cuda.cpp
ToolChains/Darwin.cpp
ToolChains/DragonFly.cpp
ToolChains/FreeBSD.cpp
ToolChains/Fuchsia.cpp
ToolChains/Gnu.cpp
ToolChains/Haiku.cpp
ToolChains/Hexagon.cpp
ToolChains/Linux.cpp
ToolChains/MipsLinux.cpp
ToolChains/MinGW.cpp
ToolChains/Minix.cpp
ToolChains/MSVC.cpp
ToolChains/Myriad.cpp
ToolChains/NaCl.cpp
ToolChains/NetBSD.cpp
ToolChains/OpenBSD.cpp
ToolChains/PS4CPU.cpp
ToolChains/Solaris.cpp
ToolChains/TCE.cpp
ToolChains/WebAssembly.cpp
ToolChains/XCore.cpp
Types.cpp
XRayArgs.cpp
DEPENDS
ClangDriverOptions
LINK_LIBS
clangBasic
${system_libs}
)

View File

@ -0,0 +1,267 @@
//===--- Compilation.cpp - Compilation Task Implementation ----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang::driver;
using namespace clang;
using namespace llvm::opt;
Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
InputArgList *_Args, DerivedArgList *_TranslatedArgs,
bool ContainsError)
: TheDriver(D), DefaultToolChain(_DefaultToolChain), ActiveOffloadMask(0u),
Args(_Args), TranslatedArgs(_TranslatedArgs), ForDiagnostics(false),
ContainsError(ContainsError) {
// The offloading host toolchain is the default toolchain.
OrderedOffloadingToolchains.insert(
std::make_pair(Action::OFK_Host, &DefaultToolChain));
}
Compilation::~Compilation() {
delete TranslatedArgs;
delete Args;
// Free any derived arg lists.
for (auto Arg : TCArgs)
if (Arg.second != TranslatedArgs)
delete Arg.second;
}
const DerivedArgList &
Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch,
Action::OffloadKind DeviceOffloadKind) {
if (!TC)
TC = &DefaultToolChain;
DerivedArgList *&Entry = TCArgs[{TC, BoundArch, DeviceOffloadKind}];
if (!Entry) {
SmallVector<Arg *, 4> AllocatedArgs;
DerivedArgList *OpenMPArgs = nullptr;
// Translate OpenMP toolchain arguments provided via the -Xopenmp-target flags.
if (DeviceOffloadKind == Action::OFK_OpenMP) {
const ToolChain *HostTC = getSingleOffloadToolChain<Action::OFK_Host>();
bool SameTripleAsHost = (TC->getTriple() == HostTC->getTriple());
OpenMPArgs = TC->TranslateOpenMPTargetArgs(
*TranslatedArgs, SameTripleAsHost, AllocatedArgs);
}
if (!OpenMPArgs) {
Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind);
if (!Entry)
Entry = TranslatedArgs;
} else {
Entry = TC->TranslateArgs(*OpenMPArgs, BoundArch, DeviceOffloadKind);
if (!Entry)
Entry = OpenMPArgs;
else
delete OpenMPArgs;
}
// Add allocated arguments to the final DAL.
for (auto ArgPtr : AllocatedArgs) {
Entry->AddSynthesizedArg(ArgPtr);
}
}
return *Entry;
}
bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
// FIXME: Why are we trying to remove files that we have not created? For
// example we should only try to remove a temporary assembly file if
// "clang -cc1" succeed in writing it. Was this a workaround for when
// clang was writing directly to a .s file and sometimes leaving it behind
// during a failure?
// FIXME: If this is necessary, we can still try to split
// llvm::sys::fs::remove into a removeFile and a removeDir and avoid the
// duplicated stat from is_regular_file.
// Don't try to remove files which we don't have write access to (but may be
// able to remove), or non-regular files. Underlying tools may have
// intentionally not overwritten them.
if (!llvm::sys::fs::can_write(File) || !llvm::sys::fs::is_regular_file(File))
return true;
if (std::error_code EC = llvm::sys::fs::remove(File)) {
// Failure is only failure if the file exists and is "regular". We checked
// for it being regular before, and llvm::sys::fs::remove ignores ENOENT,
// so we don't need to check again.
if (IssueErrors)
getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
<< EC.message();
return false;
}
return true;
}
bool Compilation::CleanupFileList(const ArgStringList &Files,
bool IssueErrors) const {
bool Success = true;
for (ArgStringList::const_iterator
it = Files.begin(), ie = Files.end(); it != ie; ++it)
Success &= CleanupFile(*it, IssueErrors);
return Success;
}
bool Compilation::CleanupFileMap(const ArgStringMap &Files,
const JobAction *JA,
bool IssueErrors) const {
bool Success = true;
for (ArgStringMap::const_iterator
it = Files.begin(), ie = Files.end(); it != ie; ++it) {
// If specified, only delete the files associated with the JobAction.
// Otherwise, delete all files in the map.
if (JA && it->first != JA)
continue;
Success &= CleanupFile(it->second, IssueErrors);
}
return Success;
}
int Compilation::ExecuteCommand(const Command &C,
const Command *&FailingCommand) const {
if ((getDriver().CCPrintOptions ||
getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) {
raw_ostream *OS = &llvm::errs();
// Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the
// output stream.
if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) {
std::error_code EC;
OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename, EC,
llvm::sys::fs::F_Append |
llvm::sys::fs::F_Text);
if (EC) {
getDriver().Diag(clang::diag::err_drv_cc_print_options_failure)
<< EC.message();
FailingCommand = &C;
delete OS;
return 1;
}
}
if (getDriver().CCPrintOptions)
*OS << "[Logging clang options]";
C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions);
if (OS != &llvm::errs())
delete OS;
}
std::string Error;
bool ExecutionFailed;
int Res = C.Execute(Redirects, &Error, &ExecutionFailed);
if (!Error.empty()) {
assert(Res && "Error string set with 0 result code!");
getDriver().Diag(clang::diag::err_drv_command_failure) << Error;
}
if (Res)
FailingCommand = &C;
return ExecutionFailed ? 1 : Res;
}
using FailingCommandList = SmallVectorImpl<std::pair<int, const Command *>>;
static bool ActionFailed(const Action *A,
const FailingCommandList &FailingCommands) {
if (FailingCommands.empty())
return false;
// CUDA can have the same input source code compiled multiple times so do not
// compiled again if there are already failures. It is OK to abort the CUDA
// pipeline on errors.
if (A->isOffloading(Action::OFK_Cuda))
return true;
for (const auto &CI : FailingCommands)
if (A == &(CI.second->getSource()))
return true;
for (const Action *AI : A->inputs())
if (ActionFailed(AI, FailingCommands))
return true;
return false;
}
static bool InputsOk(const Command &C,
const FailingCommandList &FailingCommands) {
return !ActionFailed(&C.getSource(), FailingCommands);
}
void Compilation::ExecuteJobs(const JobList &Jobs,
FailingCommandList &FailingCommands) const {
// According to UNIX standard, driver need to continue compiling all the
// inputs on the command line even one of them failed.
// In all but CLMode, execute all the jobs unless the necessary inputs for the
// job is missing due to previous failures.
for (const auto &Job : Jobs) {
if (!InputsOk(Job, FailingCommands))
continue;
const Command *FailingCommand = nullptr;
if (int Res = ExecuteCommand(Job, FailingCommand)) {
FailingCommands.push_back(std::make_pair(Res, FailingCommand));
// Bail as soon as one command fails in cl driver mode.
if (TheDriver.IsCLMode())
return;
}
}
}
void Compilation::initCompilationForDiagnostics() {
ForDiagnostics = true;
// Free actions and jobs.
Actions.clear();
AllActions.clear();
Jobs.clear();
// Clear temporary/results file lists.
TempFiles.clear();
ResultFiles.clear();
FailureResultFiles.clear();
// Remove any user specified output. Claim any unclaimed arguments, so as
// to avoid emitting warnings about unused args.
OptSpecifier OutputOpts[] = { options::OPT_o, options::OPT_MD,
options::OPT_MMD };
for (unsigned i = 0, e = llvm::array_lengthof(OutputOpts); i != e; ++i) {
if (TranslatedArgs->hasArg(OutputOpts[i]))
TranslatedArgs->eraseArg(OutputOpts[i]);
}
TranslatedArgs->ClaimAllArgs();
// Redirect stdout/stderr to /dev/null.
Redirects = {None, {""}, {""}};
}
StringRef Compilation::getSysRoot() const {
return getDriver().SysRoot;
}
void Compilation::Redirect(ArrayRef<Optional<StringRef>> Redirects) {
this->Redirects = Redirects;
}

View File

@ -0,0 +1,141 @@
//===--- Distro.cpp - Linux distribution detection support ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Driver/Distro.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/MemoryBuffer.h"
using namespace clang::driver;
using namespace clang;
static Distro::DistroType DetectDistro(vfs::FileSystem &VFS) {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
VFS.getBufferForFile("/etc/lsb-release");
if (File) {
StringRef Data = File.get()->getBuffer();
SmallVector<StringRef, 16> Lines;
Data.split(Lines, "\n");
Distro::DistroType Version = Distro::UnknownDistro;
for (StringRef Line : Lines)
if (Version == Distro::UnknownDistro && Line.startswith("DISTRIB_CODENAME="))
Version = llvm::StringSwitch<Distro::DistroType>(Line.substr(17))
.Case("hardy", Distro::UbuntuHardy)
.Case("intrepid", Distro::UbuntuIntrepid)
.Case("jaunty", Distro::UbuntuJaunty)
.Case("karmic", Distro::UbuntuKarmic)
.Case("lucid", Distro::UbuntuLucid)
.Case("maverick", Distro::UbuntuMaverick)
.Case("natty", Distro::UbuntuNatty)
.Case("oneiric", Distro::UbuntuOneiric)
.Case("precise", Distro::UbuntuPrecise)
.Case("quantal", Distro::UbuntuQuantal)
.Case("raring", Distro::UbuntuRaring)
.Case("saucy", Distro::UbuntuSaucy)
.Case("trusty", Distro::UbuntuTrusty)
.Case("utopic", Distro::UbuntuUtopic)
.Case("vivid", Distro::UbuntuVivid)
.Case("wily", Distro::UbuntuWily)
.Case("xenial", Distro::UbuntuXenial)
.Case("yakkety", Distro::UbuntuYakkety)
.Case("zesty", Distro::UbuntuZesty)
.Case("artful", Distro::UbuntuArtful)
.Case("bionic", Distro::UbuntuBionic)
.Default(Distro::UnknownDistro);
if (Version != Distro::UnknownDistro)
return Version;
}
File = VFS.getBufferForFile("/etc/redhat-release");
if (File) {
StringRef Data = File.get()->getBuffer();
if (Data.startswith("Fedora release"))
return Distro::Fedora;
if (Data.startswith("Red Hat Enterprise Linux") ||
Data.startswith("CentOS") ||
Data.startswith("Scientific Linux")) {
if (Data.find("release 7") != StringRef::npos)
return Distro::RHEL7;
else if (Data.find("release 6") != StringRef::npos)
return Distro::RHEL6;
else if (Data.find("release 5") != StringRef::npos)
return Distro::RHEL5;
}
return Distro::UnknownDistro;
}
File = VFS.getBufferForFile("/etc/debian_version");
if (File) {
StringRef Data = File.get()->getBuffer();
// Contents: < major.minor > or < codename/sid >
int MajorVersion;
if (!Data.split('.').first.getAsInteger(10, MajorVersion)) {
switch (MajorVersion) {
case 5:
return Distro::DebianLenny;
case 6:
return Distro::DebianSqueeze;
case 7:
return Distro::DebianWheezy;
case 8:
return Distro::DebianJessie;
case 9:
return Distro::DebianStretch;
case 10:
return Distro::DebianBuster;
default:
return Distro::UnknownDistro;
}
}
return llvm::StringSwitch<Distro::DistroType>(Data.split("\n").first)
.Case("squeeze/sid", Distro::DebianSqueeze)
.Case("wheezy/sid", Distro::DebianWheezy)
.Case("jessie/sid", Distro::DebianJessie)
.Case("stretch/sid", Distro::DebianStretch)
.Default(Distro::UnknownDistro);
}
File = VFS.getBufferForFile("/etc/SuSE-release");
if (File) {
StringRef Data = File.get()->getBuffer();
SmallVector<StringRef, 8> Lines;
Data.split(Lines, "\n");
for (const StringRef& Line : Lines) {
if (!Line.trim().startswith("VERSION"))
continue;
std::pair<StringRef, StringRef> SplitLine = Line.split('=');
// Old versions have split VERSION and PATCHLEVEL
// Newer versions use VERSION = x.y
std::pair<StringRef, StringRef> SplitVer = SplitLine.second.trim().split('.');
int Version;
// OpenSUSE/SLES 10 and older are not supported and not compatible
// with our rules, so just treat them as Distro::UnknownDistro.
if (!SplitVer.first.getAsInteger(10, Version) && Version > 10)
return Distro::OpenSUSE;
return Distro::UnknownDistro;
}
return Distro::UnknownDistro;
}
if (VFS.exists("/etc/exherbo-release"))
return Distro::Exherbo;
if (VFS.exists("/etc/alpine-release"))
return Distro::AlpineLinux;
if (VFS.exists("/etc/arch-release"))
return Distro::ArchLinux;
return Distro::UnknownDistro;
}
Distro::Distro(vfs::FileSystem &VFS) : DistroVal(DetectDistro(VFS)) {}

View File

@ -0,0 +1 @@
c890f77415033ad604a979e943ff37e3ccf2735e

View File

@ -0,0 +1,53 @@
//===--- DriverOptions.cpp - Driver Options Table -------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Driver/Options.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Option/Option.h"
#include <cassert>
using namespace clang::driver;
using namespace clang::driver::options;
using namespace llvm::opt;
#define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE;
#include "clang/Driver/Options.inc"
#undef PREFIX
static const OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \
PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES},
#include "clang/Driver/Options.inc"
#undef OPTION
};
namespace {
class DriverOptTable : public OptTable {
public:
DriverOptTable()
: OptTable(InfoTable) {}
};
}
std::unique_ptr<OptTable> clang::driver::createDriverOptTable() {
auto Result = llvm::make_unique<DriverOptTable>();
// Options.inc is included in DriverOptions.cpp, and calls OptTable's
// addValues function.
// Opt is a variable used in the code fragment in Options.inc.
OptTable &Opt = *Result;
#define OPTTABLE_ARG_INIT
#include "clang/Driver/Options.inc"
#undef OPTTABLE_ARG_INIT
return std::move(Result);
}

View File

@ -0,0 +1,108 @@
//===--- InputInfo.h - Input Source & Type Information ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_DRIVER_INPUTINFO_H
#define LLVM_CLANG_LIB_DRIVER_INPUTINFO_H
#include "clang/Driver/Action.h"
#include "clang/Driver/Types.h"
#include "llvm/Option/Arg.h"
#include <cassert>
#include <string>
namespace clang {
namespace driver {
/// InputInfo - Wrapper for information about an input source.
class InputInfo {
// FIXME: The distinction between filenames and inputarg here is
// gross; we should probably drop the idea of a "linker
// input". Doing so means tweaking pipelining to still create link
// steps when it sees linker inputs (but not treat them as
// arguments), and making sure that arguments get rendered
// correctly.
enum Class {
Nothing,
Filename,
InputArg,
Pipe
};
union {
const char *Filename;
const llvm::opt::Arg *InputArg;
} Data;
Class Kind;
const Action* Act;
types::ID Type;
const char *BaseInput;
static types::ID GetActionType(const Action *A) {
return A != nullptr ? A->getType() : types::TY_Nothing;
}
public:
InputInfo() : InputInfo(nullptr, nullptr) {}
InputInfo(const Action *A, const char *_BaseInput)
: Kind(Nothing), Act(A), Type(GetActionType(A)), BaseInput(_BaseInput) {}
InputInfo(types::ID _Type, const char *_Filename, const char *_BaseInput)
: Kind(Filename), Act(nullptr), Type(_Type), BaseInput(_BaseInput) {
Data.Filename = _Filename;
}
InputInfo(const Action *A, const char *_Filename, const char *_BaseInput)
: Kind(Filename), Act(A), Type(GetActionType(A)), BaseInput(_BaseInput) {
Data.Filename = _Filename;
}
InputInfo(types::ID _Type, const llvm::opt::Arg *_InputArg,
const char *_BaseInput)
: Kind(InputArg), Act(nullptr), Type(_Type), BaseInput(_BaseInput) {
Data.InputArg = _InputArg;
}
InputInfo(const Action *A, const llvm::opt::Arg *_InputArg,
const char *_BaseInput)
: Kind(InputArg), Act(A), Type(GetActionType(A)), BaseInput(_BaseInput) {
Data.InputArg = _InputArg;
}
bool isNothing() const { return Kind == Nothing; }
bool isFilename() const { return Kind == Filename; }
bool isInputArg() const { return Kind == InputArg; }
types::ID getType() const { return Type; }
const char *getBaseInput() const { return BaseInput; }
/// The action for which this InputInfo was created. May be null.
const Action *getAction() const { return Act; }
void setAction(const Action *A) { Act = A; }
const char *getFilename() const {
assert(isFilename() && "Invalid accessor.");
return Data.Filename;
}
const llvm::opt::Arg &getInputArg() const {
assert(isInputArg() && "Invalid accessor.");
return *Data.InputArg;
}
/// getAsString - Return a string name for this input, for
/// debugging.
std::string getAsString() const {
if (isFilename())
return std::string("\"") + getFilename() + '"';
else if (isInputArg())
return "(input arg)";
else
return "(nothing)";
}
};
} // end namespace driver
} // end namespace clang
#endif

View File

@ -0,0 +1,430 @@
//===--- Job.cpp - Command to Execute -------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Driver/Job.h"
#include "InputInfo.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
using namespace clang::driver;
using llvm::raw_ostream;
using llvm::StringRef;
using llvm::ArrayRef;
Command::Command(const Action &Source, const Tool &Creator,
const char *Executable, const ArgStringList &Arguments,
ArrayRef<InputInfo> Inputs)
: Source(Source), Creator(Creator), Executable(Executable),
Arguments(Arguments), ResponseFile(nullptr) {
for (const auto &II : Inputs)
if (II.isFilename())
InputFilenames.push_back(II.getFilename());
}
/// @brief Check if the compiler flag in question should be skipped when
/// emitting a reproducer. Also track how many arguments it has and if the
/// option is some kind of include path.
static bool skipArgs(const char *Flag, bool HaveCrashVFS, int &SkipNum,
bool &IsInclude) {
SkipNum = 2;
// These flags are all of the form -Flag <Arg> and are treated as two
// arguments. Therefore, we need to skip the flag and the next argument.
bool ShouldSkip = llvm::StringSwitch<bool>(Flag)
.Cases("-MF", "-MT", "-MQ", "-serialize-diagnostic-file", true)
.Cases("-o", "-dependency-file", true)
.Cases("-fdebug-compilation-dir", "-diagnostic-log-file", true)
.Cases("-dwarf-debug-flags", "-ivfsoverlay", true)
.Default(false);
if (ShouldSkip)
return true;
// Some include flags shouldn't be skipped if we have a crash VFS
IsInclude = llvm::StringSwitch<bool>(Flag)
.Cases("-include", "-header-include-file", true)
.Cases("-idirafter", "-internal-isystem", "-iwithprefix", true)
.Cases("-internal-externc-isystem", "-iprefix", true)
.Cases("-iwithprefixbefore", "-isystem", "-iquote", true)
.Cases("-isysroot", "-I", "-F", "-resource-dir", true)
.Cases("-iframework", "-include-pch", true)
.Default(false);
if (IsInclude)
return HaveCrashVFS ? false : true;
// The remaining flags are treated as a single argument.
// These flags are all of the form -Flag and have no second argument.
ShouldSkip = llvm::StringSwitch<bool>(Flag)
.Cases("-M", "-MM", "-MG", "-MP", "-MD", true)
.Case("-MMD", true)
.Default(false);
// Match found.
SkipNum = 1;
if (ShouldSkip)
return true;
// These flags are treated as a single argument (e.g., -F<Dir>).
StringRef FlagRef(Flag);
IsInclude = FlagRef.startswith("-F") || FlagRef.startswith("-I");
if (IsInclude)
return HaveCrashVFS ? false : true;
if (FlagRef.startswith("-fmodules-cache-path="))
return true;
SkipNum = 0;
return false;
}
void Command::printArg(raw_ostream &OS, StringRef Arg, bool Quote) {
const bool Escape = Arg.find_first_of("\"\\$") != StringRef::npos;
if (!Quote && !Escape) {
OS << Arg;
return;
}
// Quote and escape. This isn't really complete, but good enough.
OS << '"';
for (const char c : Arg) {
if (c == '"' || c == '\\' || c == '$')
OS << '\\';
OS << c;
}
OS << '"';
}
void Command::writeResponseFile(raw_ostream &OS) const {
// In a file list, we only write the set of inputs to the response file
if (Creator.getResponseFilesSupport() == Tool::RF_FileList) {
for (const char *Arg : InputFileList) {
OS << Arg << '\n';
}
return;
}
// In regular response files, we send all arguments to the response file.
// Wrapping all arguments in double quotes ensures that both Unix tools and
// Windows tools understand the response file.
for (const char *Arg : Arguments) {
OS << '"';
for (; *Arg != '\0'; Arg++) {
if (*Arg == '\"' || *Arg == '\\') {
OS << '\\';
}
OS << *Arg;
}
OS << "\" ";
}
}
void Command::buildArgvForResponseFile(
llvm::SmallVectorImpl<const char *> &Out) const {
// When not a file list, all arguments are sent to the response file.
// This leaves us to set the argv to a single parameter, requesting the tool
// to read the response file.
if (Creator.getResponseFilesSupport() != Tool::RF_FileList) {
Out.push_back(Executable);
Out.push_back(ResponseFileFlag.c_str());
return;
}
llvm::StringSet<> Inputs;
for (const char *InputName : InputFileList)
Inputs.insert(InputName);
Out.push_back(Executable);
// In a file list, build args vector ignoring parameters that will go in the
// response file (elements of the InputFileList vector)
bool FirstInput = true;
for (const char *Arg : Arguments) {
if (Inputs.count(Arg) == 0) {
Out.push_back(Arg);
} else if (FirstInput) {
FirstInput = false;
Out.push_back(Creator.getResponseFileFlag());
Out.push_back(ResponseFile);
}
}
}
/// @brief Rewrite relative include-like flag paths to absolute ones.
static void
rewriteIncludes(const llvm::ArrayRef<const char *> &Args, size_t Idx,
size_t NumArgs,
llvm::SmallVectorImpl<llvm::SmallString<128>> &IncFlags) {
using namespace llvm;
using namespace sys;
auto getAbsPath = [](StringRef InInc, SmallVectorImpl<char> &OutInc) -> bool {
if (path::is_absolute(InInc)) // Nothing to do here...
return false;
std::error_code EC = fs::current_path(OutInc);
if (EC)
return false;
path::append(OutInc, InInc);
return true;
};
SmallString<128> NewInc;
if (NumArgs == 1) {
StringRef FlagRef(Args[Idx + NumArgs - 1]);
assert((FlagRef.startswith("-F") || FlagRef.startswith("-I")) &&
"Expecting -I or -F");
StringRef Inc = FlagRef.slice(2, StringRef::npos);
if (getAbsPath(Inc, NewInc)) {
SmallString<128> NewArg(FlagRef.slice(0, 2));
NewArg += NewInc;
IncFlags.push_back(std::move(NewArg));
}
return;
}
assert(NumArgs == 2 && "Not expecting more than two arguments");
StringRef Inc(Args[Idx + NumArgs - 1]);
if (!getAbsPath(Inc, NewInc))
return;
IncFlags.push_back(SmallString<128>(Args[Idx]));
IncFlags.push_back(std::move(NewInc));
}
void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
CrashReportInfo *CrashInfo) const {
// Always quote the exe.
OS << ' ';
printArg(OS, Executable, /*Quote=*/true);
llvm::ArrayRef<const char *> Args = Arguments;
llvm::SmallVector<const char *, 128> ArgsRespFile;
if (ResponseFile != nullptr) {
buildArgvForResponseFile(ArgsRespFile);
Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name
}
bool HaveCrashVFS = CrashInfo && !CrashInfo->VFSPath.empty();
for (size_t i = 0, e = Args.size(); i < e; ++i) {
const char *const Arg = Args[i];
if (CrashInfo) {
int NumArgs = 0;
bool IsInclude = false;
if (skipArgs(Arg, HaveCrashVFS, NumArgs, IsInclude)) {
i += NumArgs - 1;
continue;
}
// Relative includes need to be expanded to absolute paths.
if (HaveCrashVFS && IsInclude) {
SmallVector<SmallString<128>, 2> NewIncFlags;
rewriteIncludes(Args, i, NumArgs, NewIncFlags);
if (!NewIncFlags.empty()) {
for (auto &F : NewIncFlags) {
OS << ' ';
printArg(OS, F.c_str(), Quote);
}
i += NumArgs - 1;
continue;
}
}
auto Found = std::find_if(InputFilenames.begin(), InputFilenames.end(),
[&Arg](StringRef IF) { return IF == Arg; });
if (Found != InputFilenames.end() &&
(i == 0 || StringRef(Args[i - 1]) != "-main-file-name")) {
// Replace the input file name with the crashinfo's file name.
OS << ' ';
StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename);
printArg(OS, ShortName.str(), Quote);
continue;
}
}
OS << ' ';
printArg(OS, Arg, Quote);
}
if (CrashInfo && HaveCrashVFS) {
OS << ' ';
printArg(OS, "-ivfsoverlay", Quote);
OS << ' ';
printArg(OS, CrashInfo->VFSPath.str(), Quote);
// The leftover modules from the crash are stored in
// <name>.cache/vfs/modules
// Leave it untouched for pcm inspection and provide a clean/empty dir
// path to contain the future generated module cache:
// <name>.cache/vfs/repro-modules
SmallString<128> RelModCacheDir = llvm::sys::path::parent_path(
llvm::sys::path::parent_path(CrashInfo->VFSPath));
llvm::sys::path::append(RelModCacheDir, "repro-modules");
std::string ModCachePath = "-fmodules-cache-path=";
ModCachePath.append(RelModCacheDir.c_str());
OS << ' ';
printArg(OS, ModCachePath, Quote);
}
if (ResponseFile != nullptr) {
OS << "\n Arguments passed via response file:\n";
writeResponseFile(OS);
// Avoiding duplicated newline terminator, since FileLists are
// newline-separated.
if (Creator.getResponseFilesSupport() != Tool::RF_FileList)
OS << "\n";
OS << " (end of response file)";
}
OS << Terminator;
}
void Command::setResponseFile(const char *FileName) {
ResponseFile = FileName;
ResponseFileFlag = Creator.getResponseFileFlag();
ResponseFileFlag += FileName;
}
void Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) {
Environment.reserve(NewEnvironment.size() + 1);
Environment.assign(NewEnvironment.begin(), NewEnvironment.end());
Environment.push_back(nullptr);
}
int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
std::string *ErrMsg, bool *ExecutionFailed) const {
SmallVector<const char*, 128> Argv;
const char **Envp;
if (Environment.empty()) {
Envp = nullptr;
} else {
assert(Environment.back() == nullptr &&
"Environment vector should be null-terminated by now");
Envp = const_cast<const char **>(Environment.data());
}
if (ResponseFile == nullptr) {
Argv.push_back(Executable);
Argv.append(Arguments.begin(), Arguments.end());
Argv.push_back(nullptr);
return llvm::sys::ExecuteAndWait(
Executable, Argv.data(), Envp, Redirects, /*secondsToWait*/ 0,
/*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
}
// We need to put arguments in a response file (command is too large)
// Open stream to store the response file contents
std::string RespContents;
llvm::raw_string_ostream SS(RespContents);
// Write file contents and build the Argv vector
writeResponseFile(SS);
buildArgvForResponseFile(Argv);
Argv.push_back(nullptr);
SS.flush();
// Save the response file in the appropriate encoding
if (std::error_code EC = writeFileWithEncoding(
ResponseFile, RespContents, Creator.getResponseFileEncoding())) {
if (ErrMsg)
*ErrMsg = EC.message();
if (ExecutionFailed)
*ExecutionFailed = true;
return -1;
}
return llvm::sys::ExecuteAndWait(Executable, Argv.data(), Envp, Redirects,
/*secondsToWait*/ 0,
/*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
}
FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_,
const char *Executable_,
const ArgStringList &Arguments_,
ArrayRef<InputInfo> Inputs,
std::unique_ptr<Command> Fallback_)
: Command(Source_, Creator_, Executable_, Arguments_, Inputs),
Fallback(std::move(Fallback_)) {}
void FallbackCommand::Print(raw_ostream &OS, const char *Terminator,
bool Quote, CrashReportInfo *CrashInfo) const {
Command::Print(OS, "", Quote, CrashInfo);
OS << " ||";
Fallback->Print(OS, Terminator, Quote, CrashInfo);
}
static bool ShouldFallback(int ExitCode) {
// FIXME: We really just want to fall back for internal errors, such
// as when some symbol cannot be mangled, when we should be able to
// parse something but can't, etc.
return ExitCode != 0;
}
int FallbackCommand::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
std::string *ErrMsg, bool *ExecutionFailed) const {
int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
if (!ShouldFallback(PrimaryStatus))
return PrimaryStatus;
// Clear ExecutionFailed and ErrMsg before falling back.
if (ErrMsg)
ErrMsg->clear();
if (ExecutionFailed)
*ExecutionFailed = false;
const Driver &D = getCreator().getToolChain().getDriver();
D.Diag(diag::warn_drv_invoking_fallback) << Fallback->getExecutable();
int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed);
return SecondaryStatus;
}
ForceSuccessCommand::ForceSuccessCommand(const Action &Source_,
const Tool &Creator_,
const char *Executable_,
const ArgStringList &Arguments_,
ArrayRef<InputInfo> Inputs)
: Command(Source_, Creator_, Executable_, Arguments_, Inputs) {}
void ForceSuccessCommand::Print(raw_ostream &OS, const char *Terminator,
bool Quote, CrashReportInfo *CrashInfo) const {
Command::Print(OS, "", Quote, CrashInfo);
OS << " || (exit 0)" << Terminator;
}
int ForceSuccessCommand::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
std::string *ErrMsg,
bool *ExecutionFailed) const {
int Status = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
(void)Status;
if (ExecutionFailed)
*ExecutionFailed = false;
return 0;
}
void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote,
CrashReportInfo *CrashInfo) const {
for (const auto &Job : *this)
Job.Print(OS, Terminator, Quote, CrashInfo);
}
void JobList::clear() { Jobs.clear(); }

View File

@ -0,0 +1,300 @@
//===--- Multilib.cpp - Multilib Implementation ---------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Driver/Multilib.h"
#include "ToolChains/CommonArgs.h"
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace clang::driver;
using namespace clang;
using namespace llvm::opt;
using namespace llvm::sys;
/// normalize Segment to "/foo/bar" or "".
static void normalizePathSegment(std::string &Segment) {
StringRef seg = Segment;
// Prune trailing "/" or "./"
while (1) {
StringRef last = path::filename(seg);
if (last != ".")
break;
seg = path::parent_path(seg);
}
if (seg.empty() || seg == "/") {
Segment = "";
return;
}
// Add leading '/'
if (seg.front() != '/') {
Segment = "/" + seg.str();
} else {
Segment = seg;
}
}
Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix,
StringRef IncludeSuffix)
: GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix) {
normalizePathSegment(this->GCCSuffix);
normalizePathSegment(this->OSSuffix);
normalizePathSegment(this->IncludeSuffix);
}
Multilib &Multilib::gccSuffix(StringRef S) {
GCCSuffix = S;
normalizePathSegment(GCCSuffix);
return *this;
}
Multilib &Multilib::osSuffix(StringRef S) {
OSSuffix = S;
normalizePathSegment(OSSuffix);
return *this;
}
Multilib &Multilib::includeSuffix(StringRef S) {
IncludeSuffix = S;
normalizePathSegment(IncludeSuffix);
return *this;
}
LLVM_DUMP_METHOD void Multilib::dump() const {
print(llvm::errs());
}
void Multilib::print(raw_ostream &OS) const {
assert(GCCSuffix.empty() || (StringRef(GCCSuffix).front() == '/'));
if (GCCSuffix.empty())
OS << ".";
else {
OS << StringRef(GCCSuffix).drop_front();
}
OS << ";";
for (StringRef Flag : Flags) {
if (Flag.front() == '+')
OS << "@" << Flag.substr(1);
}
}
bool Multilib::isValid() const {
llvm::StringMap<int> FlagSet;
for (unsigned I = 0, N = Flags.size(); I != N; ++I) {
StringRef Flag(Flags[I]);
llvm::StringMap<int>::iterator SI = FlagSet.find(Flag.substr(1));
assert(StringRef(Flag).front() == '+' || StringRef(Flag).front() == '-');
if (SI == FlagSet.end())
FlagSet[Flag.substr(1)] = I;
else if (Flags[I] != Flags[SI->getValue()])
return false;
}
return true;
}
bool Multilib::operator==(const Multilib &Other) const {
// Check whether the flags sets match
// allowing for the match to be order invariant
llvm::StringSet<> MyFlags;
for (const auto &Flag : Flags)
MyFlags.insert(Flag);
for (const auto &Flag : Other.Flags)
if (MyFlags.find(Flag) == MyFlags.end())
return false;
if (osSuffix() != Other.osSuffix())
return false;
if (gccSuffix() != Other.gccSuffix())
return false;
if (includeSuffix() != Other.includeSuffix())
return false;
return true;
}
raw_ostream &clang::driver::operator<<(raw_ostream &OS, const Multilib &M) {
M.print(OS);
return OS;
}
MultilibSet &MultilibSet::Maybe(const Multilib &M) {
Multilib Opposite;
// Negate any '+' flags
for (StringRef Flag : M.flags()) {
if (Flag.front() == '+')
Opposite.flags().push_back(("-" + Flag.substr(1)).str());
}
return Either(M, Opposite);
}
MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2) {
return Either({M1, M2});
}
MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
const Multilib &M3) {
return Either({M1, M2, M3});
}
MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
const Multilib &M3, const Multilib &M4) {
return Either({M1, M2, M3, M4});
}
MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
const Multilib &M3, const Multilib &M4,
const Multilib &M5) {
return Either({M1, M2, M3, M4, M5});
}
static Multilib compose(const Multilib &Base, const Multilib &New) {
SmallString<128> GCCSuffix;
llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix());
SmallString<128> OSSuffix;
llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix());
SmallString<128> IncludeSuffix;
llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(),
New.includeSuffix());
Multilib Composed(GCCSuffix, OSSuffix, IncludeSuffix);
Multilib::flags_list &Flags = Composed.flags();
Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end());
Flags.insert(Flags.end(), New.flags().begin(), New.flags().end());
return Composed;
}
MultilibSet &MultilibSet::Either(ArrayRef<Multilib> MultilibSegments) {
multilib_list Composed;
if (Multilibs.empty())
Multilibs.insert(Multilibs.end(), MultilibSegments.begin(),
MultilibSegments.end());
else {
for (const Multilib &New : MultilibSegments) {
for (const Multilib &Base : *this) {
Multilib MO = compose(Base, New);
if (MO.isValid())
Composed.push_back(MO);
}
}
Multilibs = Composed;
}
return *this;
}
MultilibSet &MultilibSet::FilterOut(FilterCallback F) {
filterInPlace(F, Multilibs);
return *this;
}
MultilibSet &MultilibSet::FilterOut(const char *Regex) {
llvm::Regex R(Regex);
#ifndef NDEBUG
std::string Error;
if (!R.isValid(Error)) {
llvm::errs() << Error;
llvm_unreachable("Invalid regex!");
}
#endif
filterInPlace([&R](const Multilib &M) { return R.match(M.gccSuffix()); },
Multilibs);
return *this;
}
void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); }
void MultilibSet::combineWith(const MultilibSet &Other) {
Multilibs.insert(Multilibs.end(), Other.begin(), Other.end());
}
static bool isFlagEnabled(StringRef Flag) {
char Indicator = Flag.front();
assert(Indicator == '+' || Indicator == '-');
return Indicator == '+';
}
bool MultilibSet::select(const Multilib::flags_list &Flags, Multilib &M) const {
llvm::StringMap<bool> FlagSet;
// Stuff all of the flags into the FlagSet such that a true mappend indicates
// the flag was enabled, and a false mappend indicates the flag was disabled.
for (StringRef Flag : Flags)
FlagSet[Flag.substr(1)] = isFlagEnabled(Flag);
multilib_list Filtered = filterCopy([&FlagSet](const Multilib &M) {
for (StringRef Flag : M.flags()) {
llvm::StringMap<bool>::const_iterator SI = FlagSet.find(Flag.substr(1));
if (SI != FlagSet.end())
if (SI->getValue() != isFlagEnabled(Flag))
return true;
}
return false;
}, Multilibs);
if (Filtered.size() == 0)
return false;
if (Filtered.size() == 1) {
M = Filtered[0];
return true;
}
// TODO: pick the "best" multlib when more than one is suitable
assert(false);
return false;
}
LLVM_DUMP_METHOD void MultilibSet::dump() const {
print(llvm::errs());
}
void MultilibSet::print(raw_ostream &OS) const {
for (const Multilib &M : *this)
OS << M << "\n";
}
MultilibSet::multilib_list MultilibSet::filterCopy(FilterCallback F,
const multilib_list &Ms) {
multilib_list Copy(Ms);
filterInPlace(F, Copy);
return Copy;
}
void MultilibSet::filterInPlace(FilterCallback F, multilib_list &Ms) {
Ms.erase(std::remove_if(Ms.begin(), Ms.end(), F), Ms.end());
}
raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) {
MS.print(OS);
return OS;
}

View File

@ -0,0 +1,27 @@
//===--- Phases.cpp - Transformations on Driver Types ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Driver/Phases.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
using namespace clang::driver;
const char *phases::getPhaseName(ID Id) {
switch (Id) {
case Preprocess: return "preprocessor";
case Precompile: return "precompiler";
case Compile: return "compiler";
case Backend: return "backend";
case Assemble: return "assembler";
case Link: return "linker";
}
llvm_unreachable("Invalid phase id.");
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
//===--- Tool.cpp - Compilation Tools -------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Driver/Tool.h"
#include "InputInfo.h"
using namespace clang::driver;
Tool::Tool(const char *_Name, const char *_ShortName, const ToolChain &TC,
ResponseFileSupport _ResponseSupport,
llvm::sys::WindowsEncodingMethod _ResponseEncoding,
const char *_ResponseFlag)
: Name(_Name), ShortName(_ShortName), TheToolChain(TC),
ResponseSupport(_ResponseSupport), ResponseEncoding(_ResponseEncoding),
ResponseFlag(_ResponseFlag) {}
Tool::~Tool() {
}
void Tool::ConstructJobMultipleOutputs(Compilation &C, const JobAction &JA,
const InputInfoList &Outputs,
const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const {
assert(Outputs.size() == 1 && "Expected only one output by default!");
ConstructJob(C, JA, Outputs.front(), Inputs, TCArgs, LinkingOutput);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,101 @@
//===--- AMDGPU.cpp - AMDGPU ToolChain Implementations ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "AMDGPU.h"
#include "CommonArgs.h"
#include "InputInfo.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "llvm/Option/ArgList.h"
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;
void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
std::string Linker = getToolChain().GetProgramPath(getShortName());
ArgStringList CmdArgs;
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
CmdArgs.push_back("-shared");
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
CmdArgs, Inputs));
}
void amdgpu::getAMDGPUTargetFeatures(const Driver &D,
const llvm::opt::ArgList &Args,
std::vector<StringRef> &Features) {
if (const Arg *dAbi = Args.getLastArg(options::OPT_mamdgpu_debugger_abi)) {
StringRef value = dAbi->getValue();
if (value == "1.0") {
Features.push_back("+amdgpu-debugger-insert-nops");
Features.push_back("+amdgpu-debugger-reserve-regs");
Features.push_back("+amdgpu-debugger-emit-prologue");
} else {
D.Diag(diag::err_drv_clang_unsupported) << dAbi->getAsString(Args);
}
}
handleTargetFeaturesGroup(
Args, Features, options::OPT_m_amdgpu_Features_Group);
}
/// AMDGPU Toolchain
AMDGPUToolChain::AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: Generic_ELF(D, Triple, Args),
OptionsDefault({{options::OPT_O, "3"},
{options::OPT_cl_std_EQ, "CL1.2"}}) {}
Tool *AMDGPUToolChain::buildLinker() const {
return new tools::amdgpu::Linker(*this);
}
DerivedArgList *
AMDGPUToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
Action::OffloadKind DeviceOffloadKind) const {
DerivedArgList *DAL =
Generic_ELF::TranslateArgs(Args, BoundArch, DeviceOffloadKind);
// Do nothing if not OpenCL (-x cl)
if (!Args.getLastArgValue(options::OPT_x).equals("cl"))
return DAL;
if (!DAL)
DAL = new DerivedArgList(Args.getBaseArgs());
for (auto *A : Args)
DAL->append(A);
const OptTable &Opts = getDriver().getOpts();
// Phase 1 (.cl -> .bc)
if (Args.hasArg(options::OPT_c) && Args.hasArg(options::OPT_emit_llvm)) {
DAL->AddFlagArg(nullptr, Opts.getOption(getTriple().isArch64Bit()
? options::OPT_m64
: options::OPT_m32));
// Have to check OPT_O4, OPT_O0 & OPT_Ofast separately
// as they defined that way in Options.td
if (!Args.hasArg(options::OPT_O, options::OPT_O0, options::OPT_O4,
options::OPT_Ofast))
DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O),
getOptionDefault(options::OPT_O));
}
return DAL;
}

View File

@ -0,0 +1,70 @@
//===--- AMDGPU.h - AMDGPU ToolChain Implementations ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AMDGPU_H
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AMDGPU_H
#include "Gnu.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
#include <map>
namespace clang {
namespace driver {
namespace tools {
namespace amdgpu {
class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
public:
Linker(const ToolChain &TC) : GnuTool("amdgpu::Linker", "ld.lld", TC) {}
bool isLinkJob() const override { return true; }
bool hasIntegratedCPP() const override { return false; }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
void getAMDGPUTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args,
std::vector<StringRef> &Features);
} // end namespace amdgpu
} // end namespace tools
namespace toolchains {
class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF {
private:
const std::map<options::ID, const StringRef> OptionsDefault;
protected:
Tool *buildLinker() const override;
const StringRef getOptionDefault(options::ID OptID) const {
auto opt = OptionsDefault.find(OptID);
assert(opt != OptionsDefault.end() && "No Default for Option");
return opt->second;
}
public:
AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
unsigned GetDefaultDwarfVersion() const override { return 2; }
bool IsIntegratedAssemblerDefault() const override { return true; }
llvm::opt::DerivedArgList *
TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
Action::OffloadKind DeviceOffloadKind) const override;
};
} // end namespace toolchains
} // end namespace driver
} // end namespace clang
#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AMDGPU_H

View File

@ -0,0 +1,44 @@
//===--- AVR.cpp - AVR ToolChain Implementations ----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "AVR.h"
#include "CommonArgs.h"
#include "InputInfo.h"
#include "clang/Driver/Compilation.h"
#include "llvm/Option/ArgList.h"
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
/// AVR Toolchain
AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: Generic_ELF(D, Triple, Args) { }
Tool *AVRToolChain::buildLinker() const {
return new tools::AVR::Linker(*this);
}
void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
std::string Linker = getToolChain().GetProgramPath(getShortName());
ArgStringList CmdArgs;
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
CmdArgs, Inputs));
}
// AVR tools end.

View File

@ -0,0 +1,49 @@
//===--- AVR.h - AVR Tool and ToolChain Implementations ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AVR_H
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AVR_H
#include "Gnu.h"
#include "InputInfo.h"
#include "clang/Driver/ToolChain.h"
#include "clang/Driver/Tool.h"
namespace clang {
namespace driver {
namespace toolchains {
class LLVM_LIBRARY_VISIBILITY AVRToolChain : public Generic_ELF {
protected:
Tool *buildLinker() const override;
public:
AVRToolChain(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
};
} // end namespace toolchains
namespace tools {
namespace AVR {
class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
public:
Linker(const ToolChain &TC) : GnuTool("AVR::Linker", "avr-ld", 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 AVR
} // end namespace tools
} // end namespace driver
} // end namespace clang
#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AVR_H

View File

@ -0,0 +1,119 @@
//===--- Ananas.cpp - Ananas ToolChain Implementations ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Ananas.h"
#include "InputInfo.h"
#include "CommonArgs.h"
#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Path.h"
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;
void ananas::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
claimNoWarnArgs(Args);
ArgStringList CmdArgs;
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
const ToolChain &ToolChain = getToolChain();
const Driver &D = ToolChain.getDriver();
ArgStringList CmdArgs;
// Silence warning for "clang -g foo.o -o foo"
Args.ClaimAllArgs(options::OPT_g_Group);
// and "clang -emit-llvm foo.o -o foo"
Args.ClaimAllArgs(options::OPT_emit_llvm);
// and for "clang -w foo.o -o foo". Other warning options are already
// handled somewhere else.
Args.ClaimAllArgs(options::OPT_w);
if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
// Ananas only supports static linkage for now.
CmdArgs.push_back("-Bstatic");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
} else {
assert(Output.isNothing() && "Invalid output.");
}
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
Args.AddAllArgs(CmdArgs,
{options::OPT_T_Group, options::OPT_e, options::OPT_s,
options::OPT_t, options::OPT_Z_Flag, options::OPT_r});
if (D.isUsingLTO())
AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D);
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
if (ToolChain.ShouldLinkCXXStdlib(Args))
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
CmdArgs.push_back("-lc");
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
}
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
// Ananas - Ananas tool chain which can call as(1) and ld(1) directly.
Ananas::Ananas(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
}
Tool *Ananas::buildAssembler() const {
return new tools::ananas::Assembler(*this);
}
Tool *Ananas::buildLinker() const { return new tools::ananas::Linker(*this); }

View File

@ -0,0 +1,67 @@
//===--- Ananas.h - Ananas ToolChain Implementations --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H
#include "Gnu.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
namespace clang {
namespace driver {
namespace tools {
/// ananas -- Directly call GNU Binutils assembler and linker
namespace ananas {
class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
public:
Assembler(const ToolChain &TC)
: GnuTool("ananas::Assembler", "assembler", TC) {}
bool hasIntegratedCPP() const override { return false; }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
public:
Linker(const ToolChain &TC) : GnuTool("ananas::Linker", "linker", 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 ananas
} // end namespace tools
namespace toolchains {
class LLVM_LIBRARY_VISIBILITY Ananas : public Generic_ELF {
public:
Ananas(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
protected:
Tool *buildAssembler() const override;
Tool *buildLinker() const override;
};
} // end namespace toolchains
} // end namespace driver
} // end namespace clang
#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H

View File

@ -0,0 +1,203 @@
//===--- AArch64.cpp - AArch64 (not ARM) Helpers for Tools ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "AArch64.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/TargetParser.h"
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
/// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are
/// targeting. Set \p A to the Arg corresponding to the -mcpu argument if it is
/// provided, or to nullptr otherwise.
std::string aarch64::getAArch64TargetCPU(const ArgList &Args, Arg *&A) {
std::string CPU;
// If we have -mcpu, use that.
if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) {
StringRef Mcpu = A->getValue();
CPU = Mcpu.split("+").first.lower();
}
// Handle CPU name is 'native'.
if (CPU == "native")
return llvm::sys::getHostCPUName();
else if (CPU.size())
return CPU;
// Make sure we pick "cyclone" if -arch is used.
// FIXME: Should this be picked by checking the target triple instead?
if (Args.getLastArg(options::OPT_arch))
return "cyclone";
return "generic";
}
// Decode AArch64 features from string like +[no]featureA+[no]featureB+...
static bool DecodeAArch64Features(const Driver &D, StringRef text,
std::vector<StringRef> &Features) {
SmallVector<StringRef, 8> Split;
text.split(Split, StringRef("+"), -1, false);
for (StringRef Feature : Split) {
StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature);
if (!FeatureName.empty())
Features.push_back(FeatureName);
else if (Feature == "neon" || Feature == "noneon")
D.Diag(clang::diag::err_drv_no_neon_modifier);
else
return false;
}
return true;
}
// Check if the CPU name and feature modifiers in -mcpu are legal. If yes,
// decode CPU and feature.
static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU,
std::vector<StringRef> &Features) {
std::pair<StringRef, StringRef> Split = Mcpu.split("+");
CPU = Split.first;
if (CPU == "generic") {
Features.push_back("+neon");
} else {
llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseCPUArch(CPU);
if (!llvm::AArch64::getArchFeatures(ArchKind, Features))
return false;
unsigned Extension = llvm::AArch64::getDefaultExtensions(CPU, ArchKind);
if (!llvm::AArch64::getExtensionFeatures(Extension, Features))
return false;
}
if (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features))
return false;
return true;
}
static bool
getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March,
const ArgList &Args,
std::vector<StringRef> &Features) {
std::string MarchLowerCase = March.lower();
std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+");
llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseArch(Split.first);
if (ArchKind == llvm::AArch64::ArchKind::INVALID ||
!llvm::AArch64::getArchFeatures(ArchKind, Features) ||
(Split.second.size() && !DecodeAArch64Features(D, Split.second, Features)))
return false;
return true;
}
static bool
getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
const ArgList &Args,
std::vector<StringRef> &Features) {
StringRef CPU;
std::string McpuLowerCase = Mcpu.lower();
if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Features))
return false;
return true;
}
static bool
getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune,
const ArgList &Args,
std::vector<StringRef> &Features) {
std::string MtuneLowerCase = Mtune.lower();
// Check CPU name is valid
std::vector<StringRef> MtuneFeatures;
StringRef Tune;
if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, MtuneFeatures))
return false;
// Handle CPU name is 'native'.
if (MtuneLowerCase == "native")
MtuneLowerCase = llvm::sys::getHostCPUName();
if (MtuneLowerCase == "cyclone") {
Features.push_back("+zcm");
Features.push_back("+zcz");
}
return true;
}
static bool
getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
const ArgList &Args,
std::vector<StringRef> &Features) {
StringRef CPU;
std::vector<StringRef> DecodedFeature;
std::string McpuLowerCase = Mcpu.lower();
if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, DecodedFeature))
return false;
return getAArch64MicroArchFeaturesFromMtune(D, CPU, Args, Features);
}
void aarch64::getAArch64TargetFeatures(const Driver &D, const ArgList &Args,
std::vector<StringRef> &Features) {
Arg *A;
bool success = true;
// Enable NEON by default.
Features.push_back("+neon");
if ((A = Args.getLastArg(options::OPT_march_EQ)))
success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Features);
else if ((A = Args.getLastArg(options::OPT_mcpu_EQ)))
success = getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
else if (Args.hasArg(options::OPT_arch))
success = getAArch64ArchFeaturesFromMcpu(D, getAArch64TargetCPU(Args, A),
Args, Features);
if (success && (A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)))
success =
getAArch64MicroArchFeaturesFromMtune(D, A->getValue(), Args, Features);
else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ)))
success =
getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
else if (success && Args.hasArg(options::OPT_arch))
success = getAArch64MicroArchFeaturesFromMcpu(
D, getAArch64TargetCPU(Args, A), Args, Features);
if (!success)
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
if (Args.getLastArg(options::OPT_mgeneral_regs_only)) {
Features.push_back("-fp-armv8");
Features.push_back("-crypto");
Features.push_back("-neon");
}
// En/disable crc
if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
if (A->getOption().matches(options::OPT_mcrc))
Features.push_back("+crc");
else
Features.push_back("-crc");
}
if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
options::OPT_munaligned_access))
if (A->getOption().matches(options::OPT_mno_unaligned_access))
Features.push_back("+strict-align");
if (Args.hasArg(options::OPT_ffixed_x18))
Features.push_back("+reserve-x18");
if (Args.hasArg(options::OPT_mno_neg_immediates))
Features.push_back("+no-neg-immediates");
}

Some files were not shown because too many files have changed in this diff Show More