diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Driver')
17 files changed, 4518 insertions, 1659 deletions
diff --git a/contrib/llvm/tools/clang/lib/Driver/Action.cpp b/contrib/llvm/tools/clang/lib/Driver/Action.cpp index 29a4679..85e466a 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Action.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Action.cpp @@ -9,6 +9,7 @@ #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" @@ -36,6 +37,10 @@ const char *Action::getClassName(ActionClass AC) { 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"); @@ -45,6 +50,9 @@ 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??"); @@ -87,6 +95,8 @@ std::string Action::getOffloadingKindPrefix() const { break; case OFK_Cuda: return "device-cuda"; + case OFK_OpenMP: + return "device-openmp"; // TODO: Add other programming models here. } @@ -97,26 +107,49 @@ std::string Action::getOffloadingKindPrefix() const { 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(llvm::StringRef NormalizedTriple) const { - // A file prefix is only generated for device actions and consists of the - // offload kind and triple. - if (!OffloadingDeviceKind) +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 += getOffloadingKindPrefix(); + 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) @@ -125,8 +158,8 @@ InputAction::InputAction(const Arg &_Input, types::ID _Type) void BindArchAction::anchor() {} -BindArchAction::BindArchAction(Action *Input, const char *_ArchName) - : Action(BindArchClass, Input), ArchName(_ArchName) {} +BindArchAction::BindArchAction(Action *Input, llvm::StringRef ArchName) + : Action(BindArchClass, Input), ArchName(ArchName) {} void OffloadAction::anchor() {} @@ -342,3 +375,13 @@ 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()) {} diff --git a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp index 6a2616f..5c13e59 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp @@ -37,11 +37,9 @@ Compilation::~Compilation() { delete Args; // Free any derived arg lists. - for (llvm::DenseMap<std::pair<const ToolChain*, const char*>, - DerivedArgList*>::iterator it = TCArgs.begin(), - ie = TCArgs.end(); it != ie; ++it) - if (it->second != TranslatedArgs) - delete it->second; + for (auto Arg : TCArgs) + if (Arg.second != TranslatedArgs) + delete Arg.second; // Free redirections of stdout/stderr. if (Redirects) { @@ -52,14 +50,15 @@ Compilation::~Compilation() { } } -const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC, - const char *BoundArch) { +const DerivedArgList & +Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) { if (!TC) TC = &DefaultToolChain; - DerivedArgList *&Entry = TCArgs[std::make_pair(TC, BoundArch)]; + DerivedArgList *&Entry = TCArgs[{TC, BoundArch, DeviceOffloadKind}]; if (!Entry) { - Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch); + Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind); if (!Entry) Entry = TranslatedArgs; } diff --git a/contrib/llvm/tools/clang/lib/Driver/CrossWindowsToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/CrossWindowsToolChain.cpp index 4ebbc53..28036ea 100644 --- a/contrib/llvm/tools/clang/lib/Driver/CrossWindowsToolChain.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/CrossWindowsToolChain.cpp @@ -11,6 +11,7 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" using namespace clang::driver; using namespace clang::driver::toolchains; diff --git a/contrib/llvm/tools/clang/lib/Driver/Distro.cpp b/contrib/llvm/tools/clang/lib/Driver/Distro.cpp new file mode 100644 index 0000000..d305b17 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Driver/Distro.cpp @@ -0,0 +1,134 @@ +//===--- 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) + .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; + 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/arch-release")) + return Distro::ArchLinux; + + return Distro::UnknownDistro; +} + +Distro::Distro(vfs::FileSystem &VFS) : DistroVal(DetectDistro(VFS)) {} diff --git a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp index 02f4a99..15f830d 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp @@ -32,7 +32,6 @@ #include "llvm/Option/OptSpecifier.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" -#include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -43,6 +42,9 @@ #include <map> #include <memory> #include <utility> +#if LLVM_ON_UNIX +#include <unistd.h> // getpid +#endif using namespace clang::driver; using namespace clang; @@ -55,12 +57,12 @@ Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple, Mode(GCCMode), SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), LTOMode(LTOK_None), ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT), UseStdLib(true), - DefaultTargetTriple(DefaultTargetTriple), DriverTitle("clang LLVM compiler"), CCPrintOptionsFilename(nullptr), CCPrintHeadersFilename(nullptr), CCLogDiagnosticsFilename(nullptr), CCCPrintBindings(false), CCPrintHeaders(false), CCLogDiagnostics(false), - CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true), - CCCUsePCH(true), SuppressMissingInputWarning(false) { + CCGenDiagnostics(false), DefaultTargetTriple(DefaultTargetTriple), + CCCGenericGCCName(""), CheckInputsExist(true), CCCUsePCH(true), + SuppressMissingInputWarning(false) { // Provide a sane fallback if no VFS is specified. if (!this->VFS) @@ -89,31 +91,39 @@ Driver::~Driver() { llvm::DeleteContainerSeconds(ToolChains); } -void Driver::ParseDriverMode(ArrayRef<const char *> Args) { - const std::string OptName = - getOpts().getOption(options::OPT_driver_mode).getPrefixedName(); +void Driver::ParseDriverMode(StringRef ProgramName, + ArrayRef<const char *> Args) { + auto Default = ToolChain::getTargetAndModeFromProgramName(ProgramName); + StringRef DefaultMode(Default.second); + setDriverModeFromOption(DefaultMode); for (const char *ArgPtr : Args) { // Ingore nullptrs, they are response file's EOL markers if (ArgPtr == nullptr) continue; const StringRef Arg = ArgPtr; - if (!Arg.startswith(OptName)) - continue; + setDriverModeFromOption(Arg); + } +} - const StringRef Value = Arg.drop_front(OptName.size()); - const unsigned M = llvm::StringSwitch<unsigned>(Value) - .Case("gcc", GCCMode) - .Case("g++", GXXMode) - .Case("cpp", CPPMode) - .Case("cl", CLMode) - .Default(~0U); +void Driver::setDriverModeFromOption(StringRef Opt) { + const std::string OptName = + getOpts().getOption(options::OPT_driver_mode).getPrefixedName(); + if (!Opt.startswith(OptName)) + return; + StringRef Value = Opt.drop_front(OptName.size()); - if (M != ~0U) - Mode = static_cast<DriverMode>(M); - else - Diag(diag::err_drv_unsupported_option_argument) << OptName << Value; - } + const unsigned M = llvm::StringSwitch<unsigned>(Value) + .Case("gcc", GCCMode) + .Case("g++", GXXMode) + .Case("cpp", CPPMode) + .Case("cl", CLMode) + .Default(~0U); + + if (M != ~0U) + Mode = static_cast<DriverMode>(M); + else + Diag(diag::err_drv_unsupported_option_argument) << OptName << Value; } InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings) { @@ -170,6 +180,10 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, (PhaseArg = DAL.getLastArg(options::OPT__SLASH_P))) { FinalPhase = phases::Preprocess; + // --precompile only runs up to precompilation. + } else if ((PhaseArg = DAL.getLastArg(options::OPT__precompile))) { + FinalPhase = phases::Precompile; + // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. } else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) || (PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) || @@ -423,6 +437,32 @@ void Driver::setLTOMode(const llvm::opt::ArgList &Args) { } } +/// Compute the desired OpenMP runtime from the flags provided. +Driver::OpenMPRuntimeKind Driver::getOpenMPRuntime(const ArgList &Args) const { + StringRef RuntimeName(CLANG_DEFAULT_OPENMP_RUNTIME); + + const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ); + if (A) + RuntimeName = A->getValue(); + + auto RT = llvm::StringSwitch<OpenMPRuntimeKind>(RuntimeName) + .Case("libomp", OMPRT_OMP) + .Case("libgomp", OMPRT_GOMP) + .Case("libiomp5", OMPRT_IOMP5) + .Default(OMPRT_Unknown); + + if (RT == OMPRT_Unknown) { + if (A) + Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << A->getValue(); + else + // FIXME: We could use a nicer diagnostic here. + Diag(diag::err_drv_unsupported_opt) << "-fopenmp"; + } + + return RT; +} + void Driver::CreateOffloadingDeviceToolChains(Compilation &C, InputList &Inputs) { @@ -433,14 +473,71 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, if (llvm::any_of(Inputs, [](std::pair<types::ID, const llvm::opt::Arg *> &I) { return types::isCuda(I.first); })) { - const ToolChain &TC = getToolChain( - C.getInputArgs(), - llvm::Triple(C.getSingleOffloadToolChain<Action::OFK_Host>() - ->getTriple() - .isArch64Bit() - ? "nvptx64-nvidia-cuda" - : "nvptx-nvidia-cuda")); - C.addOffloadDeviceToolChain(&TC, Action::OFK_Cuda); + const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>(); + const llvm::Triple &HostTriple = HostTC->getTriple(); + llvm::Triple CudaTriple(HostTriple.isArch64Bit() ? "nvptx64-nvidia-cuda" + : "nvptx-nvidia-cuda"); + // Use the CUDA and host triples as the key into the ToolChains map, because + // the device toolchain we create depends on both. + ToolChain *&CudaTC = ToolChains[CudaTriple.str() + "/" + HostTriple.str()]; + if (!CudaTC) { + CudaTC = new toolchains::CudaToolChain(*this, CudaTriple, *HostTC, + C.getInputArgs()); + } + C.addOffloadDeviceToolChain(CudaTC, Action::OFK_Cuda); + } + + // + // OpenMP + // + // We need to generate an OpenMP toolchain if the user specified targets with + // the -fopenmp-targets option. + if (Arg *OpenMPTargets = + C.getInputArgs().getLastArg(options::OPT_fopenmp_targets_EQ)) { + if (OpenMPTargets->getNumValues()) { + // We expect that -fopenmp-targets is always used in conjunction with the + // option -fopenmp specifying a valid runtime with offloading support, + // i.e. libomp or libiomp. + bool HasValidOpenMPRuntime = C.getInputArgs().hasFlag( + options::OPT_fopenmp, options::OPT_fopenmp_EQ, + options::OPT_fno_openmp, false); + if (HasValidOpenMPRuntime) { + OpenMPRuntimeKind OpenMPKind = getOpenMPRuntime(C.getInputArgs()); + HasValidOpenMPRuntime = + OpenMPKind == OMPRT_OMP || OpenMPKind == OMPRT_IOMP5; + } + + if (HasValidOpenMPRuntime) { + llvm::StringMap<const char *> FoundNormalizedTriples; + for (const char *Val : OpenMPTargets->getValues()) { + llvm::Triple TT(Val); + std::string NormalizedName = TT.normalize(); + + // Make sure we don't have a duplicate triple. + auto Duplicate = FoundNormalizedTriples.find(NormalizedName); + if (Duplicate != FoundNormalizedTriples.end()) { + Diag(clang::diag::warn_drv_omp_offload_target_duplicate) + << Val << Duplicate->second; + continue; + } + + // Store the current triple so that we can check for duplicates in the + // following iterations. + FoundNormalizedTriples[NormalizedName] = Val; + + // If the specified target is invalid, emit a diagnostic. + if (TT.getArch() == llvm::Triple::UnknownArch) + Diag(clang::diag::err_drv_invalid_omp_target) << Val; + else { + const ToolChain &TC = getToolChain(C.getInputArgs(), TT); + C.addOffloadDeviceToolChain(&TC, Action::OFK_OpenMP); + } + } + } else + Diag(clang::diag::err_drv_expecting_fopenmp_with_fopenmp_targets); + } else + Diag(clang::diag::warn_drv_empty_joined_argument) + << OpenMPTargets->getAsString(C.getInputArgs()); } // @@ -456,8 +553,9 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // FIXME: Handle environment options which affect driver behavior, somewhere // (client?). GCC_EXEC_PREFIX, LPATH, CC_PRINT_OPTIONS. - if (char *env = ::getenv("COMPILER_PATH")) { - StringRef CompilerPath = env; + if (Optional<std::string> CompilerPathValue = + llvm::sys::Process::GetEnv("COMPILER_PATH")) { + StringRef CompilerPath = *CompilerPathValue; while (!CompilerPath.empty()) { std::pair<StringRef, StringRef> Split = CompilerPath.split(llvm::sys::EnvPathSeparator); @@ -468,7 +566,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // We look for the driver mode option early, because the mode can affect // how other options are parsed. - ParseDriverMode(ArgList.slice(1)); + ParseDriverMode(ClangExecutable, ArgList.slice(1)); // FIXME: What are we going to do with -V and -b? @@ -535,26 +633,20 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { setLTOMode(Args); - // Ignore -fembed-bitcode options with LTO - // since the output will be bitcode anyway. - if (getLTOMode() == LTOK_None) { - if (Arg *A = Args.getLastArg(options::OPT_fembed_bitcode_EQ)) { - StringRef Name = A->getValue(); - unsigned Model = llvm::StringSwitch<unsigned>(Name) - .Case("off", EmbedNone) - .Case("all", EmbedBitcode) - .Case("bitcode", EmbedBitcode) - .Case("marker", EmbedMarker) - .Default(~0U); - if (Model == ~0U) { - Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) - << Name; - } else - BitcodeEmbed = static_cast<BitcodeEmbedMode>(Model); - } - } else { - // claim the bitcode option under LTO so no warning is issued. - Args.ClaimAllArgs(options::OPT_fembed_bitcode_EQ); + // Process -fembed-bitcode= flags. + if (Arg *A = Args.getLastArg(options::OPT_fembed_bitcode_EQ)) { + StringRef Name = A->getValue(); + unsigned Model = llvm::StringSwitch<unsigned>(Name) + .Case("off", EmbedNone) + .Case("all", EmbedBitcode) + .Case("bitcode", EmbedBitcode) + .Case("marker", EmbedMarker) + .Default(~0U); + if (Model == ~0U) { + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) + << Name; + } else + BitcodeEmbed = static_cast<BitcodeEmbedMode>(Model); } std::unique_ptr<llvm::opt::InputArgList> UArgs = @@ -610,6 +702,95 @@ static void printArgList(raw_ostream &OS, const llvm::opt::ArgList &Args) { OS << '\n'; } +bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename, + SmallString<128> &CrashDiagDir) { + using namespace llvm::sys; + assert(llvm::Triple(llvm::sys::getProcessTriple()).isOSDarwin() && + "Only knows about .crash files on Darwin"); + + // The .crash file can be found on at ~/Library/Logs/DiagnosticReports/ + // (or /Library/Logs/DiagnosticReports for root) and has the filename pattern + // clang-<VERSION>_<YYYY-MM-DD-HHMMSS>_<hostname>.crash. + path::home_directory(CrashDiagDir); + if (CrashDiagDir.startswith("/var/root")) + CrashDiagDir = "/"; + path::append(CrashDiagDir, "Library/Logs/DiagnosticReports"); + int PID = +#if LLVM_ON_UNIX + getpid(); +#else + 0; +#endif + std::error_code EC; + fs::file_status FileStatus; + TimePoint<> LastAccessTime; + SmallString<128> CrashFilePath; + // Lookup the .crash files and get the one generated by a subprocess spawned + // by this driver invocation. + for (fs::directory_iterator File(CrashDiagDir, EC), FileEnd; + File != FileEnd && !EC; File.increment(EC)) { + StringRef FileName = path::filename(File->path()); + if (!FileName.startswith(Name)) + continue; + if (fs::status(File->path(), FileStatus)) + continue; + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> CrashFile = + llvm::MemoryBuffer::getFile(File->path()); + if (!CrashFile) + continue; + // The first line should start with "Process:", otherwise this isn't a real + // .crash file. + StringRef Data = CrashFile.get()->getBuffer(); + if (!Data.startswith("Process:")) + continue; + // Parse parent process pid line, e.g: "Parent Process: clang-4.0 [79141]" + size_t ParentProcPos = Data.find("Parent Process:"); + if (ParentProcPos == StringRef::npos) + continue; + size_t LineEnd = Data.find_first_of("\n", ParentProcPos); + if (LineEnd == StringRef::npos) + continue; + StringRef ParentProcess = Data.slice(ParentProcPos+15, LineEnd).trim(); + int OpenBracket = -1, CloseBracket = -1; + for (size_t i = 0, e = ParentProcess.size(); i < e; ++i) { + if (ParentProcess[i] == '[') + OpenBracket = i; + if (ParentProcess[i] == ']') + CloseBracket = i; + } + // Extract the parent process PID from the .crash file and check whether + // it matches this driver invocation pid. + int CrashPID; + if (OpenBracket < 0 || CloseBracket < 0 || + ParentProcess.slice(OpenBracket + 1, CloseBracket) + .getAsInteger(10, CrashPID) || CrashPID != PID) { + continue; + } + + // Found a .crash file matching the driver pid. To avoid getting an older + // and misleading crash file, continue looking for the most recent. + // FIXME: the driver can dispatch multiple cc1 invocations, leading to + // multiple crashes poiting to the same parent process. Since the driver + // does not collect pid information for the dispatched invocation there's + // currently no way to distinguish among them. + const auto FileAccessTime = FileStatus.getLastModificationTime(); + if (FileAccessTime > LastAccessTime) { + CrashFilePath.assign(File->path()); + LastAccessTime = FileAccessTime; + } + } + + // If found, copy it over to the location of other reproducer files. + if (!CrashFilePath.empty()) { + EC = fs::copy_file(CrashFilePath, ReproCrashFilename); + if (EC) + return false; + return true; + } + + return false; +} + // When clang crashes, produce diagnostic information including the fully // preprocessed source file(s). Request that the developer attach the // diagnostic information to a bug report. @@ -737,8 +918,13 @@ void Driver::generateCompilationDiagnostics(Compilation &C, "Preprocessed source(s) and associated run script(s) are located at:"; SmallString<128> VFS; + SmallString<128> ReproCrashFilename; for (const char *TempFile : TempFiles) { Diag(clang::diag::note_drv_command_failed_diag_msg) << TempFile; + if (ReproCrashFilename.empty()) { + ReproCrashFilename = TempFile; + llvm::sys::path::replace_extension(ReproCrashFilename, ".crash"); + } if (StringRef(TempFile).endswith(".cache")) { // In some cases (modules) we'll dump extra data to help with reproducing // the crash into a directory next to the output. @@ -766,6 +952,24 @@ void Driver::generateCompilationDiagnostics(Compilation &C, Diag(clang::diag::note_drv_command_failed_diag_msg) << Script; } + // On darwin, provide information about the .crash diagnostic report. + if (llvm::Triple(llvm::sys::getProcessTriple()).isOSDarwin()) { + SmallString<128> CrashDiagDir; + if (getCrashDiagnosticFile(ReproCrashFilename, CrashDiagDir)) { + Diag(clang::diag::note_drv_command_failed_diag_msg) + << ReproCrashFilename.str(); + } else { // Suggest a directory for the user to look for .crash files. + llvm::sys::path::append(CrashDiagDir, Name); + CrashDiagDir += "_<YYYY-MM-DD-HHMMSS>_<hostname>.crash"; + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "Crash backtrace is located in"; + Diag(clang::diag::note_drv_command_failed_diag_msg) + << CrashDiagDir.str(); + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "(choose the .crash file that corresponds to your crash)"; + } + } + for (const auto &A : C.getArgs().filtered(options::OPT_frewrite_map_file, options::OPT_frewrite_map_file_EQ)) Diag(clang::diag::note_drv_command_failed_diag_msg) << A->getValue(); @@ -783,8 +987,7 @@ void Driver::setUpResponseFiles(Compilation &C, Command &Cmd) { return; std::string TmpName = GetTemporaryPath("response", "txt"); - Cmd.setResponseFile( - C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str()))); + Cmd.setResponseFile(C.addTempFile(C.getArgs().MakeArgString(TmpName))); } int Driver::ExecuteCompilation( @@ -982,7 +1185,15 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { } if (C.getArgs().hasArg(options::OPT_print_libgcc_file_name)) { - llvm::outs() << GetFilePath("libgcc.a", TC) << "\n"; + ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(C.getArgs()); + switch (RLT) { + case ToolChain::RLT_CompilerRT: + llvm::outs() << TC.getCompilerRT(C.getArgs(), "builtins") << "\n"; + break; + case ToolChain::RLT_Libgcc: + llvm::outs() << GetFilePath("libgcc.a", TC) << "\n"; + break; + } return false; } @@ -1388,132 +1599,745 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, } } -// For each unique --cuda-gpu-arch= argument creates a TY_CUDA_DEVICE -// input action and then wraps each in CudaDeviceAction paired with -// appropriate GPU arch name. In case of partial (i.e preprocessing -// only) or device-only compilation, each device action is added to /p -// Actions and /p Current is released. Otherwise the function creates -// and returns a new CudaHostAction which wraps /p Current and device -// side actions. -static Action *buildCudaActions(Compilation &C, DerivedArgList &Args, - const Arg *InputArg, Action *HostAction, - ActionList &Actions) { - Arg *PartialCompilationArg = Args.getLastArg( - options::OPT_cuda_host_only, options::OPT_cuda_device_only, - options::OPT_cuda_compile_host_device); - bool CompileHostOnly = - PartialCompilationArg && - PartialCompilationArg->getOption().matches(options::OPT_cuda_host_only); - bool CompileDeviceOnly = - PartialCompilationArg && - PartialCompilationArg->getOption().matches(options::OPT_cuda_device_only); - - if (CompileHostOnly) { +namespace { +/// Provides a convenient interface for different programming models to generate +/// the required device actions. +class OffloadingActionBuilder final { + /// Flag used to trace errors in the builder. + bool IsValid = false; + + /// The compilation that is using this builder. + Compilation &C; + + /// Map between an input argument and the offload kinds used to process it. + std::map<const Arg *, unsigned> InputArgToOffloadKindMap; + + /// Builder interface. It doesn't build anything or keep any state. + class DeviceActionBuilder { + public: + typedef llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PhasesTy; + + enum ActionBuilderReturnCode { + // The builder acted successfully on the current action. + ABRT_Success, + // The builder didn't have to act on the current action. + ABRT_Inactive, + // The builder was successful and requested the host action to not be + // generated. + ABRT_Ignore_Host, + }; + + protected: + /// Compilation associated with this builder. + Compilation &C; + + /// Tool chains associated with this builder. The same programming + /// model may have associated one or more tool chains. + SmallVector<const ToolChain *, 2> ToolChains; + + /// The derived arguments associated with this builder. + DerivedArgList &Args; + + /// The inputs associated with this builder. + const Driver::InputList &Inputs; + + /// The associated offload kind. + Action::OffloadKind AssociatedOffloadKind = Action::OFK_None; + + public: + DeviceActionBuilder(Compilation &C, DerivedArgList &Args, + const Driver::InputList &Inputs, + Action::OffloadKind AssociatedOffloadKind) + : C(C), Args(Args), Inputs(Inputs), + AssociatedOffloadKind(AssociatedOffloadKind) {} + virtual ~DeviceActionBuilder() {} + + /// Fill up the array \a DA with all the device dependences that should be + /// added to the provided host action \a HostAction. By default it is + /// inactive. + virtual ActionBuilderReturnCode + getDeviceDependences(OffloadAction::DeviceDependences &DA, + phases::ID CurPhase, phases::ID FinalPhase, + PhasesTy &Phases) { + return ABRT_Inactive; + } + + /// Update the state to include the provided host action \a HostAction as a + /// dependency of the current device action. By default it is inactive. + virtual ActionBuilderReturnCode addDeviceDepences(Action *HostAction) { + return ABRT_Inactive; + } + + /// Append top level actions generated by the builder. Return true if errors + /// were found. + virtual void appendTopLevelActions(ActionList &AL) {} + + /// Append linker actions generated by the builder. Return true if errors + /// were found. + virtual void appendLinkDependences(OffloadAction::DeviceDependences &DA) {} + + /// Initialize the builder. Return true if any initialization errors are + /// found. + virtual bool initialize() { return false; } + + /// Return true if the builder can use bundling/unbundling. + virtual bool canUseBundlerUnbundler() const { return false; } + + /// Return true if this builder is valid. We have a valid builder if we have + /// associated device tool chains. + bool isValid() { return !ToolChains.empty(); } + + /// Return the associated offload kind. + Action::OffloadKind getAssociatedOffloadKind() { + return AssociatedOffloadKind; + } + }; + + /// \brief CUDA action builder. It injects device code in the host backend + /// action. + class CudaActionBuilder final : public DeviceActionBuilder { + /// Flags to signal if the user requested host-only or device-only + /// compilation. + bool CompileHostOnly = false; + bool CompileDeviceOnly = false; + + /// List of GPU architectures to use in this compilation. + SmallVector<CudaArch, 4> GpuArchList; + + /// The CUDA actions for the current input. + ActionList CudaDeviceActions; + + /// The CUDA fat binary if it was generated for the current input. + Action *CudaFatBinary = nullptr; + + /// Flag that is set to true if this builder acted on the current input. + bool IsActive = false; + + public: + CudaActionBuilder(Compilation &C, DerivedArgList &Args, + const Driver::InputList &Inputs) + : DeviceActionBuilder(C, Args, Inputs, Action::OFK_Cuda) {} + + ActionBuilderReturnCode + getDeviceDependences(OffloadAction::DeviceDependences &DA, + phases::ID CurPhase, phases::ID FinalPhase, + PhasesTy &Phases) override { + if (!IsActive) + return ABRT_Inactive; + + // If we don't have more CUDA actions, we don't have any dependences to + // create for the host. + if (CudaDeviceActions.empty()) + return ABRT_Success; + + assert(CudaDeviceActions.size() == GpuArchList.size() && + "Expecting one action per GPU architecture."); + assert(!CompileHostOnly && + "Not expecting CUDA actions in host-only compilation."); + + // If we are generating code for the device or we are in a backend phase, + // we attempt to generate the fat binary. We compile each arch to ptx and + // assemble to cubin, then feed the cubin *and* the ptx into a device + // "link" action, which uses fatbinary to combine these cubins into one + // fatbin. The fatbin is then an input to the host action if not in + // device-only mode. + if (CompileDeviceOnly || CurPhase == phases::Backend) { + ActionList DeviceActions; + for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { + // Produce the device action from the current phase up to the assemble + // phase. + for (auto Ph : Phases) { + // Skip the phases that were already dealt with. + if (Ph < CurPhase) + continue; + // We have to be consistent with the host final phase. + if (Ph > FinalPhase) + break; + + CudaDeviceActions[I] = C.getDriver().ConstructPhaseAction( + C, Args, Ph, CudaDeviceActions[I]); + + if (Ph == phases::Assemble) + break; + } + + // If we didn't reach the assemble phase, we can't generate the fat + // binary. We don't need to generate the fat binary if we are not in + // device-only mode. + if (!isa<AssembleJobAction>(CudaDeviceActions[I]) || + CompileDeviceOnly) + continue; + + Action *AssembleAction = CudaDeviceActions[I]; + assert(AssembleAction->getType() == types::TY_Object); + assert(AssembleAction->getInputs().size() == 1); + + Action *BackendAction = AssembleAction->getInputs()[0]; + assert(BackendAction->getType() == types::TY_PP_Asm); + + for (auto &A : {AssembleAction, BackendAction}) { + OffloadAction::DeviceDependences DDep; + DDep.add(*A, *ToolChains.front(), CudaArchToString(GpuArchList[I]), + Action::OFK_Cuda); + DeviceActions.push_back( + C.MakeAction<OffloadAction>(DDep, A->getType())); + } + } + + // We generate the fat binary if we have device input actions. + if (!DeviceActions.empty()) { + CudaFatBinary = + C.MakeAction<LinkJobAction>(DeviceActions, types::TY_CUDA_FATBIN); + + if (!CompileDeviceOnly) { + DA.add(*CudaFatBinary, *ToolChains.front(), /*BoundArch=*/nullptr, + Action::OFK_Cuda); + // Clear the fat binary, it is already a dependence to an host + // action. + CudaFatBinary = nullptr; + } + + // Remove the CUDA actions as they are already connected to an host + // action or fat binary. + CudaDeviceActions.clear(); + } + + // We avoid creating host action in device-only mode. + return CompileDeviceOnly ? ABRT_Ignore_Host : ABRT_Success; + } else if (CurPhase > phases::Backend) { + // If we are past the backend phase and still have a device action, we + // don't have to do anything as this action is already a device + // top-level action. + return ABRT_Success; + } + + assert(CurPhase < phases::Backend && "Generating single CUDA " + "instructions should only occur " + "before the backend phase!"); + + // By default, we produce an action for each device arch. + for (Action *&A : CudaDeviceActions) + A = C.getDriver().ConstructPhaseAction(C, Args, CurPhase, A); + + return ABRT_Success; + } + + ActionBuilderReturnCode addDeviceDepences(Action *HostAction) override { + // While generating code for CUDA, we only depend on the host input action + // to trigger the creation of all the CUDA device actions. + + // If we are dealing with an input action, replicate it for each GPU + // architecture. If we are in host-only mode we return 'success' so that + // the host uses the CUDA offload kind. + if (auto *IA = dyn_cast<InputAction>(HostAction)) { + assert(!GpuArchList.empty() && + "We should have at least one GPU architecture."); + + // If the host input is not CUDA, we don't need to bother about this + // input. + if (IA->getType() != types::TY_CUDA) { + // The builder will ignore this input. + IsActive = false; + return ABRT_Inactive; + } + + // Set the flag to true, so that the builder acts on the current input. + IsActive = true; + + if (CompileHostOnly) + return ABRT_Success; + + // Replicate inputs for each GPU architecture. + for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) + CudaDeviceActions.push_back(C.MakeAction<InputAction>( + IA->getInputArg(), types::TY_CUDA_DEVICE)); + + return ABRT_Success; + } + + return IsActive ? ABRT_Success : ABRT_Inactive; + } + + void appendTopLevelActions(ActionList &AL) override { + // Utility to append actions to the top level list. + auto AddTopLevel = [&](Action *A, CudaArch BoundArch) { + OffloadAction::DeviceDependences Dep; + Dep.add(*A, *ToolChains.front(), CudaArchToString(BoundArch), + Action::OFK_Cuda); + AL.push_back(C.MakeAction<OffloadAction>(Dep, A->getType())); + }; + + // If we have a fat binary, add it to the list. + if (CudaFatBinary) { + AddTopLevel(CudaFatBinary, CudaArch::UNKNOWN); + CudaDeviceActions.clear(); + CudaFatBinary = nullptr; + return; + } + + if (CudaDeviceActions.empty()) + return; + + // If we have CUDA actions at this point, that's because we have a have + // partial compilation, so we should have an action for each GPU + // architecture. + assert(CudaDeviceActions.size() == GpuArchList.size() && + "Expecting one action per GPU architecture."); + assert(ToolChains.size() == 1 && + "Expecting to have a sing CUDA toolchain."); + for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) + AddTopLevel(CudaDeviceActions[I], GpuArchList[I]); + + CudaDeviceActions.clear(); + } + + bool initialize() override { + // We don't need to support CUDA. + if (!C.hasOffloadToolChain<Action::OFK_Cuda>()) + return false; + + const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>(); + assert(HostTC && "No toolchain for host compilation."); + if (HostTC->getTriple().isNVPTX()) { + // We do not support targeting NVPTX for host compilation. Throw + // an error and abort pipeline construction early so we don't trip + // asserts that assume device-side compilation. + C.getDriver().Diag(diag::err_drv_cuda_nvptx_host); + return true; + } + + ToolChains.push_back(C.getSingleOffloadToolChain<Action::OFK_Cuda>()); + + Arg *PartialCompilationArg = Args.getLastArg( + options::OPT_cuda_host_only, options::OPT_cuda_device_only, + options::OPT_cuda_compile_host_device); + CompileHostOnly = PartialCompilationArg && + PartialCompilationArg->getOption().matches( + options::OPT_cuda_host_only); + CompileDeviceOnly = PartialCompilationArg && + PartialCompilationArg->getOption().matches( + options::OPT_cuda_device_only); + + // Collect all cuda_gpu_arch parameters, removing duplicates. + std::set<CudaArch> GpuArchs; + bool Error = false; + for (Arg *A : Args) { + if (!(A->getOption().matches(options::OPT_cuda_gpu_arch_EQ) || + A->getOption().matches(options::OPT_no_cuda_gpu_arch_EQ))) + continue; + A->claim(); + + const StringRef ArchStr = A->getValue(); + if (A->getOption().matches(options::OPT_no_cuda_gpu_arch_EQ) && + ArchStr == "all") { + GpuArchs.clear(); + continue; + } + CudaArch Arch = StringToCudaArch(ArchStr); + if (Arch == CudaArch::UNKNOWN) { + C.getDriver().Diag(clang::diag::err_drv_cuda_bad_gpu_arch) << ArchStr; + Error = true; + } else if (A->getOption().matches(options::OPT_cuda_gpu_arch_EQ)) + GpuArchs.insert(Arch); + else if (A->getOption().matches(options::OPT_no_cuda_gpu_arch_EQ)) + GpuArchs.erase(Arch); + else + llvm_unreachable("Unexpected option."); + } + + // Collect list of GPUs remaining in the set. + for (CudaArch Arch : GpuArchs) + GpuArchList.push_back(Arch); + + // Default to sm_20 which is the lowest common denominator for + // supported GPUs. sm_20 code should work correctly, if + // suboptimally, on all newer GPUs. + if (GpuArchList.empty()) + GpuArchList.push_back(CudaArch::SM_20); + + return Error; + } + }; + + /// OpenMP action builder. The host bitcode is passed to the device frontend + /// and all the device linked images are passed to the host link phase. + class OpenMPActionBuilder final : public DeviceActionBuilder { + /// The OpenMP actions for the current input. + ActionList OpenMPDeviceActions; + + /// The linker inputs obtained for each toolchain. + SmallVector<ActionList, 8> DeviceLinkerInputs; + + public: + OpenMPActionBuilder(Compilation &C, DerivedArgList &Args, + const Driver::InputList &Inputs) + : DeviceActionBuilder(C, Args, Inputs, Action::OFK_OpenMP) {} + + ActionBuilderReturnCode + getDeviceDependences(OffloadAction::DeviceDependences &DA, + phases::ID CurPhase, phases::ID FinalPhase, + PhasesTy &Phases) override { + + // We should always have an action for each input. + assert(OpenMPDeviceActions.size() == ToolChains.size() && + "Number of OpenMP actions and toolchains do not match."); + + // The host only depends on device action in the linking phase, when all + // the device images have to be embedded in the host image. + if (CurPhase == phases::Link) { + assert(ToolChains.size() == DeviceLinkerInputs.size() && + "Toolchains and linker inputs sizes do not match."); + auto LI = DeviceLinkerInputs.begin(); + for (auto *A : OpenMPDeviceActions) { + LI->push_back(A); + ++LI; + } + + // We passed the device action as a host dependence, so we don't need to + // do anything else with them. + OpenMPDeviceActions.clear(); + return ABRT_Success; + } + + // By default, we produce an action for each device arch. + for (Action *&A : OpenMPDeviceActions) + A = C.getDriver().ConstructPhaseAction(C, Args, CurPhase, A); + + return ABRT_Success; + } + + ActionBuilderReturnCode addDeviceDepences(Action *HostAction) override { + + // If this is an input action replicate it for each OpenMP toolchain. + if (auto *IA = dyn_cast<InputAction>(HostAction)) { + OpenMPDeviceActions.clear(); + for (unsigned I = 0; I < ToolChains.size(); ++I) + OpenMPDeviceActions.push_back( + C.MakeAction<InputAction>(IA->getInputArg(), IA->getType())); + return ABRT_Success; + } + + // If this is an unbundling action use it as is for each OpenMP toolchain. + if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(HostAction)) { + OpenMPDeviceActions.clear(); + for (unsigned I = 0; I < ToolChains.size(); ++I) { + OpenMPDeviceActions.push_back(UA); + UA->registerDependentActionInfo( + ToolChains[I], /*BoundArch=*/StringRef(), Action::OFK_OpenMP); + } + return ABRT_Success; + } + + // When generating code for OpenMP we use the host compile phase result as + // a dependence to the device compile phase so that it can learn what + // declarations should be emitted. However, this is not the only use for + // the host action, so we prevent it from being collapsed. + if (isa<CompileJobAction>(HostAction)) { + HostAction->setCannotBeCollapsedWithNextDependentAction(); + assert(ToolChains.size() == OpenMPDeviceActions.size() && + "Toolchains and device action sizes do not match."); + OffloadAction::HostDependence HDep( + *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), + /*BoundArch=*/nullptr, Action::OFK_OpenMP); + auto TC = ToolChains.begin(); + for (Action *&A : OpenMPDeviceActions) { + assert(isa<CompileJobAction>(A)); + OffloadAction::DeviceDependences DDep; + DDep.add(*A, **TC, /*BoundArch=*/nullptr, Action::OFK_OpenMP); + A = C.MakeAction<OffloadAction>(HDep, DDep); + ++TC; + } + } + return ABRT_Success; + } + + void appendTopLevelActions(ActionList &AL) override { + if (OpenMPDeviceActions.empty()) + return; + + // We should always have an action for each input. + assert(OpenMPDeviceActions.size() == ToolChains.size() && + "Number of OpenMP actions and toolchains do not match."); + + // Append all device actions followed by the proper offload action. + auto TI = ToolChains.begin(); + for (auto *A : OpenMPDeviceActions) { + OffloadAction::DeviceDependences Dep; + Dep.add(*A, **TI, /*BoundArch=*/nullptr, Action::OFK_OpenMP); + AL.push_back(C.MakeAction<OffloadAction>(Dep, A->getType())); + ++TI; + } + // We no longer need the action stored in this builder. + OpenMPDeviceActions.clear(); + } + + void appendLinkDependences(OffloadAction::DeviceDependences &DA) override { + assert(ToolChains.size() == DeviceLinkerInputs.size() && + "Toolchains and linker inputs sizes do not match."); + + // Append a new link action for each device. + auto TC = ToolChains.begin(); + for (auto &LI : DeviceLinkerInputs) { + auto *DeviceLinkAction = + C.MakeAction<LinkJobAction>(LI, types::TY_Image); + DA.add(*DeviceLinkAction, **TC, /*BoundArch=*/nullptr, + Action::OFK_OpenMP); + ++TC; + } + } + + bool initialize() override { + // Get the OpenMP toolchains. If we don't get any, the action builder will + // know there is nothing to do related to OpenMP offloading. + auto OpenMPTCRange = C.getOffloadToolChains<Action::OFK_OpenMP>(); + for (auto TI = OpenMPTCRange.first, TE = OpenMPTCRange.second; TI != TE; + ++TI) + ToolChains.push_back(TI->second); + + DeviceLinkerInputs.resize(ToolChains.size()); + return false; + } + + bool canUseBundlerUnbundler() const override { + // OpenMP should use bundled files whenever possible. + return true; + } + }; + + /// + /// TODO: Add the implementation for other specialized builders here. + /// + + /// Specialized builders being used by this offloading action builder. + SmallVector<DeviceActionBuilder *, 4> SpecializedBuilders; + + /// Flag set to true if all valid builders allow file bundling/unbundling. + bool CanUseBundler; + +public: + OffloadingActionBuilder(Compilation &C, DerivedArgList &Args, + const Driver::InputList &Inputs) + : C(C) { + // Create a specialized builder for each device toolchain. + + IsValid = true; + + // Create a specialized builder for CUDA. + SpecializedBuilders.push_back(new CudaActionBuilder(C, Args, Inputs)); + + // Create a specialized builder for OpenMP. + SpecializedBuilders.push_back(new OpenMPActionBuilder(C, Args, Inputs)); + + // + // TODO: Build other specialized builders here. + // + + // Initialize all the builders, keeping track of errors. If all valid + // builders agree that we can use bundling, set the flag to true. + unsigned ValidBuilders = 0u; + unsigned ValidBuildersSupportingBundling = 0u; + for (auto *SB : SpecializedBuilders) { + IsValid = IsValid && !SB->initialize(); + + // Update the counters if the builder is valid. + if (SB->isValid()) { + ++ValidBuilders; + if (SB->canUseBundlerUnbundler()) + ++ValidBuildersSupportingBundling; + } + } + CanUseBundler = + ValidBuilders && ValidBuilders == ValidBuildersSupportingBundling; + } + + ~OffloadingActionBuilder() { + for (auto *SB : SpecializedBuilders) + delete SB; + } + + /// Generate an action that adds device dependences (if any) to a host action. + /// If no device dependence actions exist, just return the host action \a + /// HostAction. If an error is found or if no builder requires the host action + /// to be generated, return nullptr. + Action * + addDeviceDependencesToHostAction(Action *HostAction, const Arg *InputArg, + phases::ID CurPhase, phases::ID FinalPhase, + DeviceActionBuilder::PhasesTy &Phases) { + if (!IsValid) + return nullptr; + + if (SpecializedBuilders.empty()) + return HostAction; + + assert(HostAction && "Invalid host action!"); + + OffloadAction::DeviceDependences DDeps; + // Check if all the programming models agree we should not emit the host + // action. Also, keep track of the offloading kinds employed. + auto &OffloadKind = InputArgToOffloadKindMap[InputArg]; + unsigned InactiveBuilders = 0u; + unsigned IgnoringBuilders = 0u; + for (auto *SB : SpecializedBuilders) { + if (!SB->isValid()) { + ++InactiveBuilders; + continue; + } + + auto RetCode = + SB->getDeviceDependences(DDeps, CurPhase, FinalPhase, Phases); + + // If the builder explicitly says the host action should be ignored, + // we need to increment the variable that tracks the builders that request + // the host object to be ignored. + if (RetCode == DeviceActionBuilder::ABRT_Ignore_Host) + ++IgnoringBuilders; + + // Unless the builder was inactive for this action, we have to record the + // offload kind because the host will have to use it. + if (RetCode != DeviceActionBuilder::ABRT_Inactive) + OffloadKind |= SB->getAssociatedOffloadKind(); + } + + // If all builders agree that the host object should be ignored, just return + // nullptr. + if (IgnoringBuilders && + SpecializedBuilders.size() == (InactiveBuilders + IgnoringBuilders)) + return nullptr; + + if (DDeps.getActions().empty()) + return HostAction; + + // We have dependences we need to bundle together. We use an offload action + // for that. OffloadAction::HostDependence HDep( *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), - /*BoundArch=*/nullptr, Action::OFK_Cuda); - return C.MakeAction<OffloadAction>(HDep); + /*BoundArch=*/nullptr, DDeps); + return C.MakeAction<OffloadAction>(HDep, DDeps); } - // Collect all cuda_gpu_arch parameters, removing duplicates. - SmallVector<CudaArch, 4> GpuArchList; - llvm::SmallSet<CudaArch, 4> GpuArchs; - for (Arg *A : Args) { - if (!A->getOption().matches(options::OPT_cuda_gpu_arch_EQ)) - continue; - A->claim(); + /// Generate an action that adds a host dependence to a device action. The + /// results will be kept in this action builder. Return true if an error was + /// found. + bool addHostDependenceToDeviceActions(Action *&HostAction, + const Arg *InputArg) { + if (!IsValid) + return true; - const auto &ArchStr = A->getValue(); - CudaArch Arch = StringToCudaArch(ArchStr); - if (Arch == CudaArch::UNKNOWN) - C.getDriver().Diag(clang::diag::err_drv_cuda_bad_gpu_arch) << ArchStr; - else if (GpuArchs.insert(Arch).second) - GpuArchList.push_back(Arch); - } - - // Default to sm_20 which is the lowest common denominator for supported GPUs. - // sm_20 code should work correctly, if suboptimally, on all newer GPUs. - if (GpuArchList.empty()) - GpuArchList.push_back(CudaArch::SM_20); - - // Replicate inputs for each GPU architecture. - Driver::InputList CudaDeviceInputs; - for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) - CudaDeviceInputs.push_back(std::make_pair(types::TY_CUDA_DEVICE, InputArg)); - - // Build actions for all device inputs. - ActionList CudaDeviceActions; - C.getDriver().BuildActions(C, Args, CudaDeviceInputs, CudaDeviceActions); - assert(GpuArchList.size() == CudaDeviceActions.size() && - "Failed to create actions for all devices"); - - // Check whether any of device actions stopped before they could generate PTX. - bool PartialCompilation = - llvm::any_of(CudaDeviceActions, [](const Action *a) { - return a->getKind() != Action::AssembleJobClass; - }); + // If we are supporting bundling/unbundling and the current action is an + // input action of non-source file, we replace the host action by the + // unbundling action. The bundler tool has the logic to detect if an input + // is a bundle or not and if the input is not a bundle it assumes it is a + // host file. Therefore it is safe to create an unbundling action even if + // the input is not a bundle. + if (CanUseBundler && isa<InputAction>(HostAction) && + InputArg->getOption().getKind() == llvm::opt::Option::InputClass && + !types::isSrcFile(HostAction->getType())) { + auto UnbundlingHostAction = + C.MakeAction<OffloadUnbundlingJobAction>(HostAction); + UnbundlingHostAction->registerDependentActionInfo( + C.getSingleOffloadToolChain<Action::OFK_Host>(), + /*BoundArch=*/StringRef(), Action::OFK_Host); + HostAction = UnbundlingHostAction; + } - const ToolChain *CudaTC = C.getSingleOffloadToolChain<Action::OFK_Cuda>(); + assert(HostAction && "Invalid host action!"); - // Figure out what to do with device actions -- pass them as inputs to the - // host action or run each of them independently. - if (PartialCompilation || CompileDeviceOnly) { - // In case of partial or device-only compilation results of device actions - // are not consumed by the host action device actions have to be added to - // top-level actions list with AtTopLevel=true and run independently. + // Register the offload kinds that are used. + auto &OffloadKind = InputArgToOffloadKindMap[InputArg]; + for (auto *SB : SpecializedBuilders) { + if (!SB->isValid()) + continue; - // -o is ambiguous if we have more than one top-level action. - if (Args.hasArg(options::OPT_o) && - (!CompileDeviceOnly || GpuArchList.size() > 1)) { - C.getDriver().Diag( - clang::diag::err_drv_output_argument_with_multiple_files); - return nullptr; + auto RetCode = SB->addDeviceDepences(HostAction); + + // Host dependences for device actions are not compatible with that same + // action being ignored. + assert(RetCode != DeviceActionBuilder::ABRT_Ignore_Host && + "Host dependence not expected to be ignored.!"); + + // Unless the builder was inactive for this action, we have to record the + // offload kind because the host will have to use it. + if (RetCode != DeviceActionBuilder::ABRT_Inactive) + OffloadKind |= SB->getAssociatedOffloadKind(); } - for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { - OffloadAction::DeviceDependences DDep; - DDep.add(*CudaDeviceActions[I], *CudaTC, CudaArchToString(GpuArchList[I]), - Action::OFK_Cuda); - Actions.push_back( - C.MakeAction<OffloadAction>(DDep, CudaDeviceActions[I]->getType())); + return false; + } + + /// Add the offloading top level actions to the provided action list. This + /// function can replace the host action by a bundling action if the + /// programming models allow it. + bool appendTopLevelActions(ActionList &AL, Action *HostAction, + const Arg *InputArg) { + // Get the device actions to be appended. + ActionList OffloadAL; + for (auto *SB : SpecializedBuilders) { + if (!SB->isValid()) + continue; + SB->appendTopLevelActions(OffloadAL); } - // Kill host action in case of device-only compilation. - if (CompileDeviceOnly) - return nullptr; - return HostAction; - } - - // If we're not a partial or device-only compilation, we compile each arch to - // ptx and assemble to cubin, then feed the cubin *and* the ptx into a device - // "link" action, which uses fatbinary to combine these cubins into one - // fatbin. The fatbin is then an input to the host compilation. - ActionList DeviceActions; - for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { - Action* AssembleAction = CudaDeviceActions[I]; - assert(AssembleAction->getType() == types::TY_Object); - assert(AssembleAction->getInputs().size() == 1); - - Action* BackendAction = AssembleAction->getInputs()[0]; - assert(BackendAction->getType() == types::TY_PP_Asm); - - for (auto &A : {AssembleAction, BackendAction}) { - OffloadAction::DeviceDependences DDep; - DDep.add(*A, *CudaTC, CudaArchToString(GpuArchList[I]), Action::OFK_Cuda); - DeviceActions.push_back(C.MakeAction<OffloadAction>(DDep, A->getType())); - } - } - auto FatbinAction = - C.MakeAction<LinkJobAction>(DeviceActions, types::TY_CUDA_FATBIN); - - // Return a new host action that incorporates original host action and all - // device actions. - OffloadAction::HostDependence HDep( - *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), - /*BoundArch=*/nullptr, Action::OFK_Cuda); - OffloadAction::DeviceDependences DDep; - DDep.add(*FatbinAction, *CudaTC, /*BoundArch=*/nullptr, Action::OFK_Cuda); - return C.MakeAction<OffloadAction>(HDep, DDep); -} + + // If we can use the bundler, replace the host action by the bundling one in + // the resulting list. Otherwise, just append the device actions. + if (CanUseBundler && !OffloadAL.empty()) { + // Add the host action to the list in order to create the bundling action. + OffloadAL.push_back(HostAction); + + // We expect that the host action was just appended to the action list + // before this method was called. + assert(HostAction == AL.back() && "Host action not in the list??"); + HostAction = C.MakeAction<OffloadBundlingJobAction>(OffloadAL); + AL.back() = HostAction; + } else + AL.append(OffloadAL.begin(), OffloadAL.end()); + + // Propagate to the current host action (if any) the offload information + // associated with the current input. + if (HostAction) + HostAction->propagateHostOffloadInfo(InputArgToOffloadKindMap[InputArg], + /*BoundArch=*/nullptr); + return false; + } + + /// Processes the host linker action. This currently consists of replacing it + /// with an offload action if there are device link objects and propagate to + /// the host action all the offload kinds used in the current compilation. The + /// resulting action is returned. + Action *processHostLinkAction(Action *HostAction) { + // Add all the dependences from the device linking actions. + OffloadAction::DeviceDependences DDeps; + for (auto *SB : SpecializedBuilders) { + if (!SB->isValid()) + continue; + + SB->appendLinkDependences(DDeps); + } + + // Calculate all the offload kinds used in the current compilation. + unsigned ActiveOffloadKinds = 0u; + for (auto &I : InputArgToOffloadKindMap) + ActiveOffloadKinds |= I.second; + + // If we don't have device dependencies, we don't have to create an offload + // action. + if (DDeps.getActions().empty()) { + // Propagate all the active kinds to host action. Given that it is a link + // action it is assumed to depend on all actions generated so far. + HostAction->propagateHostOffloadInfo(ActiveOffloadKinds, + /*BoundArch=*/nullptr); + return HostAction; + } + + // Create the offload action with all dependences. When an offload action + // is created the kinds are propagated to the host action, so we don't have + // to do that explicitly here. + OffloadAction::HostDependence HDep( + *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), + /*BoundArch*/ nullptr, ActiveOffloadKinds); + return C.MakeAction<OffloadAction>(HDep, DDeps); + } +}; +} // anonymous namespace. void Driver::BuildActions(Compilation &C, DerivedArgList &Args, const InputList &Inputs, ActionList &Actions) const { @@ -1621,8 +2445,8 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, YcArg = YuArg = nullptr; } - // Track the host offload kinds used on this compilation. - unsigned CompilationActiveOffloadHostKinds = 0u; + // Builder to be used to build offloading actions. + OffloadingActionBuilder OffloadBuilder(C, Args, Inputs); // Construct the actions to perform. ActionList LinkerInputs; @@ -1670,12 +2494,14 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, if (YcArg) { // Add a separate precompile phase for the compile phase. if (FinalPhase >= phases::Compile) { + const types::ID HeaderType = lookupHeaderTypeForSourceType(InputType); llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PCHPL; - types::getCompilationPhases(types::TY_CXXHeader, PCHPL); + types::getCompilationPhases(HeaderType, PCHPL); Arg *PchInputArg = MakeInputArg(Args, Opts, YcArg->getValue()); // Build the pipeline for the pch file. - Action *ClangClPch = C.MakeAction<InputAction>(*PchInputArg, InputType); + Action *ClangClPch = + C.MakeAction<InputAction>(*PchInputArg, HeaderType); for (phases::ID Phase : PCHPL) ClangClPch = ConstructPhaseAction(C, Args, Phase, ClangClPch); assert(ClangClPch); @@ -1686,17 +2512,14 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, } } - phases::ID CudaInjectionPhase = - (phases::Compile < FinalPhase && - llvm::find(PL, phases::Compile) != PL.end()) - ? phases::Compile - : FinalPhase; - - // Track the host offload kinds used on this input. - unsigned InputActiveOffloadHostKinds = 0u; - // Build the pipeline for this file. Action *Current = C.MakeAction<InputAction>(*InputArg, InputType); + + // Use the current host action in any of the offloading actions, if + // required. + if (OffloadBuilder.addHostDependenceToDeviceActions(Current, InputArg)) + break; + for (SmallVectorImpl<phases::ID>::iterator i = PL.begin(), e = PL.end(); i != e; ++i) { phases::ID Phase = *i; @@ -1705,6 +2528,12 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, if (Phase > FinalPhase) break; + // Add any offload action the host action depends on. + Current = OffloadBuilder.addDeviceDependencesToHostAction( + Current, InputArg, Phase, FinalPhase, PL); + if (!Current) + break; + // Queue linker inputs. if (Phase == phases::Link) { assert((i + 1) == e && "linking must be final compilation step."); @@ -1713,48 +2542,37 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, break; } - // Some types skip the assembler phase (e.g., llvm-bc), but we can't - // encode this in the steps because the intermediate type depends on - // arguments. Just special case here. - if (Phase == phases::Assemble && Current->getType() != types::TY_PP_Asm) - continue; - // Otherwise construct the appropriate action. - Current = ConstructPhaseAction(C, Args, Phase, Current); + auto *NewCurrent = ConstructPhaseAction(C, Args, Phase, Current); - if (InputType == types::TY_CUDA && Phase == CudaInjectionPhase) { - Current = buildCudaActions(C, Args, InputArg, Current, Actions); - if (!Current) - break; + // We didn't create a new action, so we will just move to the next phase. + if (NewCurrent == Current) + continue; - // We produced a CUDA action for this input, so the host has to support - // CUDA. - InputActiveOffloadHostKinds |= Action::OFK_Cuda; - CompilationActiveOffloadHostKinds |= Action::OFK_Cuda; - } + Current = NewCurrent; + + // Use the current host action in any of the offloading actions, if + // required. + if (OffloadBuilder.addHostDependenceToDeviceActions(Current, InputArg)) + break; if (Current->getType() == types::TY_Nothing) break; } - // If we ended with something, add to the output list. Also, propagate the - // offload information to the top-level host action related with the current - // input. - if (Current) { - if (InputActiveOffloadHostKinds) - Current->propagateHostOffloadInfo(InputActiveOffloadHostKinds, - /*BoundArch=*/nullptr); + // If we ended with something, add to the output list. + if (Current) Actions.push_back(Current); - } + + // Add any top level actions generated for offloading. + OffloadBuilder.appendTopLevelActions(Actions, Current, InputArg); } - // Add a link action if necessary and propagate the offload information for - // the current compilation. + // Add a link action if necessary. if (!LinkerInputs.empty()) { - Actions.push_back( - C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image)); - Actions.back()->propagateHostOffloadInfo(CompilationActiveOffloadHostKinds, - /*BoundArch=*/nullptr); + Action *LA = C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image); + LA = OffloadBuilder.processHostLinkAction(LA); + Actions.push_back(LA); } // If we are linking, claim any options which are obviously only used for @@ -1776,6 +2594,13 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, Action *Driver::ConstructPhaseAction(Compilation &C, const ArgList &Args, phases::ID Phase, Action *Input) const { llvm::PrettyStackTraceString CrashInfo("Constructing phase actions"); + + // Some types skip the assembler phase (e.g., llvm-bc), but we can't + // encode this in the steps because the intermediate type depends on + // arguments. Just special case here. + if (Phase == phases::Assemble && Input->getType() != types::TY_PP_Asm) + return Input; + // Build the appropriate action. switch (Phase) { case phases::Link: @@ -1797,7 +2622,9 @@ Action *Driver::ConstructPhaseAction(Compilation &C, const ArgList &Args, return C.MakeAction<PreprocessJobAction>(Input, OutputTy); } case phases::Precompile: { - types::ID OutputTy = types::TY_PCH; + types::ID OutputTy = getPrecompiledType(Input->getType()); + assert(OutputTy != types::TY_INVALID && + "Cannot precompile this input type!"); if (Args.hasArg(options::OPT_fsyntax_only)) { // Syntax checks should not emit a PCH file OutputTy = types::TY_Nothing; @@ -1888,11 +2715,11 @@ void Driver::BuildJobs(Compilation &C) const { } BuildJobsForAction(C, A, &C.getDefaultToolChain(), - /*BoundArch*/ nullptr, + /*BoundArch*/ StringRef(), /*AtTopLevel*/ true, /*MultipleArchs*/ ArchNames.size() > 1, /*LinkingOutput*/ LinkingOutput, CachedResults, - /*BuildForOffloadDevice*/ false); + /*TargetDeviceOffloadKind*/ Action::OFK_None); } // If the user passed -Qunused-arguments or there were errors, don't warn @@ -1941,177 +2768,335 @@ void Driver::BuildJobs(Compilation &C) const { } } } -/// Collapse an offloading action looking for a job of the given type. The input -/// action is changed to the input of the collapsed sequence. If we effectively -/// had a collapse return the corresponding offloading action, otherwise return -/// null. -template <typename T> -static OffloadAction *collapseOffloadingAction(Action *&CurAction) { - if (!CurAction) - return nullptr; - if (auto *OA = dyn_cast<OffloadAction>(CurAction)) { - if (OA->hasHostDependence()) - if (auto *HDep = dyn_cast<T>(OA->getHostDependence())) { - CurAction = HDep; - return OA; - } - if (OA->hasSingleDeviceDependence()) - if (auto *DDep = dyn_cast<T>(OA->getSingleDeviceDependence())) { - CurAction = DDep; - return OA; + +namespace { +/// Utility class to control the collapse of dependent actions and select the +/// tools accordingly. +class ToolSelector final { + /// The tool chain this selector refers to. + const ToolChain &TC; + + /// The compilation this selector refers to. + const Compilation &C; + + /// The base action this selector refers to. + const JobAction *BaseAction; + + /// Set to true if the current toolchain refers to host actions. + bool IsHostSelector; + + /// Set to true if save-temps and embed-bitcode functionalities are active. + bool SaveTemps; + bool EmbedBitcode; + + /// Get previous dependent action or null if that does not exist. If + /// \a CanBeCollapsed is false, that action must be legal to collapse or + /// null will be returned. + const JobAction *getPrevDependentAction(const ActionList &Inputs, + ActionList &SavedOffloadAction, + bool CanBeCollapsed = true) { + // An option can be collapsed only if it has a single input. + if (Inputs.size() != 1) + return nullptr; + + Action *CurAction = *Inputs.begin(); + if (CanBeCollapsed && + !CurAction->isCollapsingWithNextDependentActionLegal()) + return nullptr; + + // If the input action is an offload action. Look through it and save any + // offload action that can be dropped in the event of a collapse. + if (auto *OA = dyn_cast<OffloadAction>(CurAction)) { + // If the dependent action is a device action, we will attempt to collapse + // only with other device actions. Otherwise, we would do the same but + // with host actions only. + if (!IsHostSelector) { + if (OA->hasSingleDeviceDependence(/*DoNotConsiderHostActions=*/true)) { + CurAction = + OA->getSingleDeviceDependence(/*DoNotConsiderHostActions=*/true); + if (CanBeCollapsed && + !CurAction->isCollapsingWithNextDependentActionLegal()) + return nullptr; + SavedOffloadAction.push_back(OA); + return dyn_cast<JobAction>(CurAction); + } + } else if (OA->hasHostDependence()) { + CurAction = OA->getHostDependence(); + if (CanBeCollapsed && + !CurAction->isCollapsingWithNextDependentActionLegal()) + return nullptr; + SavedOffloadAction.push_back(OA); + return dyn_cast<JobAction>(CurAction); } - } - return nullptr; -} -// Returns a Tool for a given JobAction. In case the action and its -// predecessors can be combined, updates Inputs with the inputs of the -// first combined action. If one of the collapsed actions is a -// CudaHostAction, updates CollapsedCHA with the pointer to it so the -// caller can deal with extra handling such action requires. -static const Tool *selectToolForJob(Compilation &C, bool SaveTemps, - bool EmbedBitcode, const ToolChain *TC, - const JobAction *JA, - const ActionList *&Inputs, - ActionList &CollapsedOffloadAction) { - const Tool *ToolForJob = nullptr; - CollapsedOffloadAction.clear(); - - // See if we should look for a compiler with an integrated assembler. We match - // bottom up, so what we are actually looking for is an assembler job with a - // compiler input. - - // Look through offload actions between assembler and backend actions. - Action *BackendJA = (isa<AssembleJobAction>(JA) && Inputs->size() == 1) - ? *Inputs->begin() - : nullptr; - auto *BackendOA = collapseOffloadingAction<BackendJobAction>(BackendJA); - - if (TC->useIntegratedAs() && !SaveTemps && - !C.getArgs().hasArg(options::OPT_via_file_asm) && - !C.getArgs().hasArg(options::OPT__SLASH_FA) && - !C.getArgs().hasArg(options::OPT__SLASH_Fa) && BackendJA && - isa<BackendJobAction>(BackendJA)) { - // A BackendJob is always preceded by a CompileJob, and without -save-temps - // or -fembed-bitcode, they will always get combined together, so instead of - // checking the backend tool, check if the tool for the CompileJob has an - // integrated assembler. For -fembed-bitcode, CompileJob is still used to - // look up tools for BackendJob, but they need to match before we can split - // them. - - // Look through offload actions between backend and compile actions. - Action *CompileJA = *BackendJA->getInputs().begin(); - auto *CompileOA = collapseOffloadingAction<CompileJobAction>(CompileJA); - - assert(CompileJA && isa<CompileJobAction>(CompileJA) && - "Backend job is not preceeded by compile job."); - const Tool *Compiler = TC->SelectTool(*cast<CompileJobAction>(CompileJA)); - if (!Compiler) return nullptr; + } + + return dyn_cast<JobAction>(CurAction); + } + + /// Return true if an assemble action can be collapsed. + bool canCollapseAssembleAction() const { + return TC.useIntegratedAs() && !SaveTemps && + !C.getArgs().hasArg(options::OPT_via_file_asm) && + !C.getArgs().hasArg(options::OPT__SLASH_FA) && + !C.getArgs().hasArg(options::OPT__SLASH_Fa); + } + + /// Return true if a preprocessor action can be collapsed. + bool canCollapsePreprocessorAction() const { + return !C.getArgs().hasArg(options::OPT_no_integrated_cpp) && + !C.getArgs().hasArg(options::OPT_traditional_cpp) && !SaveTemps && + !C.getArgs().hasArg(options::OPT_rewrite_objc); + } + + /// Struct that relates an action with the offload actions that would be + /// collapsed with it. + struct JobActionInfo final { + /// The action this info refers to. + const JobAction *JA = nullptr; + /// The offload actions we need to take care off if this action is + /// collapsed. + ActionList SavedOffloadAction; + }; + + /// Append collapsed offload actions from the give nnumber of elements in the + /// action info array. + static void AppendCollapsedOffloadAction(ActionList &CollapsedOffloadAction, + ArrayRef<JobActionInfo> &ActionInfo, + unsigned ElementNum) { + assert(ElementNum <= ActionInfo.size() && "Invalid number of elements."); + for (unsigned I = 0; I < ElementNum; ++I) + CollapsedOffloadAction.append(ActionInfo[I].SavedOffloadAction.begin(), + ActionInfo[I].SavedOffloadAction.end()); + } + + /// Functions that attempt to perform the combining. They detect if that is + /// legal, and if so they update the inputs \a Inputs and the offload action + /// that were collapsed in \a CollapsedOffloadAction. A tool that deals with + /// the combined action is returned. If the combining is not legal or if the + /// tool does not exist, null is returned. + /// Currently three kinds of collapsing are supported: + /// - Assemble + Backend + Compile; + /// - Assemble + Backend ; + /// - Backend + Compile. + const Tool * + combineAssembleBackendCompile(ArrayRef<JobActionInfo> ActionInfo, + const ActionList *&Inputs, + ActionList &CollapsedOffloadAction) { + if (ActionInfo.size() < 3 || !canCollapseAssembleAction()) + return nullptr; + auto *AJ = dyn_cast<AssembleJobAction>(ActionInfo[0].JA); + auto *BJ = dyn_cast<BackendJobAction>(ActionInfo[1].JA); + auto *CJ = dyn_cast<CompileJobAction>(ActionInfo[2].JA); + if (!AJ || !BJ || !CJ) + return nullptr; + + // Get compiler tool. + const Tool *T = TC.SelectTool(*CJ); + if (!T) + return nullptr; + // When using -fembed-bitcode, it is required to have the same tool (clang) // for both CompilerJA and BackendJA. Otherwise, combine two stages. if (EmbedBitcode) { - JobAction *InputJA = cast<JobAction>(*Inputs->begin()); - const Tool *BackendTool = TC->SelectTool(*InputJA); - if (BackendTool == Compiler) - CompileJA = InputJA; - } - if (Compiler->hasIntegratedAssembler()) { - Inputs = &CompileJA->getInputs(); - ToolForJob = Compiler; - // Save the collapsed offload actions because they may still contain - // device actions. - if (CompileOA) - CollapsedOffloadAction.push_back(CompileOA); - if (BackendOA) - CollapsedOffloadAction.push_back(BackendOA); - } - } - - // A backend job should always be combined with the preceding compile job - // unless OPT_save_temps or OPT_fembed_bitcode is enabled and the compiler is - // capable of emitting LLVM IR as an intermediate output. - if (isa<BackendJobAction>(JA)) { - // Check if the compiler supports emitting LLVM IR. - assert(Inputs->size() == 1); - - // Look through offload actions between backend and compile actions. - Action *CompileJA = *JA->getInputs().begin(); - auto *CompileOA = collapseOffloadingAction<CompileJobAction>(CompileJA); - - assert(CompileJA && isa<CompileJobAction>(CompileJA) && - "Backend job is not preceeded by compile job."); - const Tool *Compiler = TC->SelectTool(*cast<CompileJobAction>(CompileJA)); - if (!Compiler) + const Tool *BT = TC.SelectTool(*BJ); + if (BT == T) + return nullptr; + } + + if (!T->hasIntegratedAssembler()) return nullptr; - if (!Compiler->canEmitIR() || - (!SaveTemps && !EmbedBitcode)) { - Inputs = &CompileJA->getInputs(); - ToolForJob = Compiler; - if (CompileOA) - CollapsedOffloadAction.push_back(CompileOA); - } + Inputs = &CJ->getInputs(); + AppendCollapsedOffloadAction(CollapsedOffloadAction, ActionInfo, + /*NumElements=*/3); + return T; } + const Tool *combineAssembleBackend(ArrayRef<JobActionInfo> ActionInfo, + const ActionList *&Inputs, + ActionList &CollapsedOffloadAction) { + if (ActionInfo.size() < 2 || !canCollapseAssembleAction()) + return nullptr; + auto *AJ = dyn_cast<AssembleJobAction>(ActionInfo[0].JA); + auto *BJ = dyn_cast<BackendJobAction>(ActionInfo[1].JA); + if (!AJ || !BJ) + return nullptr; - // Otherwise use the tool for the current job. - if (!ToolForJob) - ToolForJob = TC->SelectTool(*JA); + // Retrieve the compile job, backend action must always be preceded by one. + ActionList CompileJobOffloadActions; + auto *CJ = getPrevDependentAction(BJ->getInputs(), CompileJobOffloadActions, + /*CanBeCollapsed=*/false); + if (!AJ || !BJ || !CJ) + return nullptr; - // See if we should use an integrated preprocessor. We do so when we have - // exactly one input, since this is the only use case we care about - // (irrelevant since we don't support combine yet). + assert(isa<CompileJobAction>(CJ) && + "Expecting compile job preceding backend job."); - // Look through offload actions after preprocessing. - Action *PreprocessJA = (Inputs->size() == 1) ? *Inputs->begin() : nullptr; - auto *PreprocessOA = - collapseOffloadingAction<PreprocessJobAction>(PreprocessJA); + // Get compiler tool. + const Tool *T = TC.SelectTool(*CJ); + if (!T) + return nullptr; - if (PreprocessJA && isa<PreprocessJobAction>(PreprocessJA) && - !C.getArgs().hasArg(options::OPT_no_integrated_cpp) && - !C.getArgs().hasArg(options::OPT_traditional_cpp) && !SaveTemps && - !C.getArgs().hasArg(options::OPT_rewrite_objc) && - ToolForJob->hasIntegratedCPP()) { - Inputs = &PreprocessJA->getInputs(); - if (PreprocessOA) - CollapsedOffloadAction.push_back(PreprocessOA); + if (!T->hasIntegratedAssembler()) + return nullptr; + + Inputs = &BJ->getInputs(); + AppendCollapsedOffloadAction(CollapsedOffloadAction, ActionInfo, + /*NumElements=*/2); + return T; } + const Tool *combineBackendCompile(ArrayRef<JobActionInfo> ActionInfo, + const ActionList *&Inputs, + ActionList &CollapsedOffloadAction) { + if (ActionInfo.size() < 2 || !canCollapsePreprocessorAction()) + return nullptr; + auto *BJ = dyn_cast<BackendJobAction>(ActionInfo[0].JA); + auto *CJ = dyn_cast<CompileJobAction>(ActionInfo[1].JA); + if (!BJ || !CJ) + return nullptr; + + // Get compiler tool. + const Tool *T = TC.SelectTool(*CJ); + if (!T) + return nullptr; + + if (T->canEmitIR() && (SaveTemps || EmbedBitcode)) + return nullptr; + + Inputs = &CJ->getInputs(); + AppendCollapsedOffloadAction(CollapsedOffloadAction, ActionInfo, + /*NumElements=*/2); + return T; + } + + /// Updates the inputs if the obtained tool supports combining with + /// preprocessor action, and the current input is indeed a preprocessor + /// action. If combining results in the collapse of offloading actions, those + /// are appended to \a CollapsedOffloadAction. + void combineWithPreprocessor(const Tool *T, const ActionList *&Inputs, + ActionList &CollapsedOffloadAction) { + if (!T || !canCollapsePreprocessorAction() || !T->hasIntegratedCPP()) + return; + + // Attempt to get a preprocessor action dependence. + ActionList PreprocessJobOffloadActions; + auto *PJ = getPrevDependentAction(*Inputs, PreprocessJobOffloadActions); + if (!PJ || !isa<PreprocessJobAction>(PJ)) + return; + + // This is legal to combine. Append any offload action we found and set the + // current inputs to preprocessor inputs. + CollapsedOffloadAction.append(PreprocessJobOffloadActions.begin(), + PreprocessJobOffloadActions.end()); + Inputs = &PJ->getInputs(); + } + +public: + ToolSelector(const JobAction *BaseAction, const ToolChain &TC, + const Compilation &C, bool SaveTemps, bool EmbedBitcode) + : TC(TC), C(C), BaseAction(BaseAction), SaveTemps(SaveTemps), + EmbedBitcode(EmbedBitcode) { + assert(BaseAction && "Invalid base action."); + IsHostSelector = BaseAction->getOffloadingDeviceKind() == Action::OFK_None; + } + + /// Check if a chain of actions can be combined and return the tool that can + /// handle the combination of actions. The pointer to the current inputs \a + /// Inputs and the list of offload actions \a CollapsedOffloadActions + /// connected to collapsed actions are updated accordingly. The latter enables + /// the caller of the selector to process them afterwards instead of just + /// dropping them. If no suitable tool is found, null will be returned. + const Tool *getTool(const ActionList *&Inputs, + ActionList &CollapsedOffloadAction) { + // + // Get the largest chain of actions that we could combine. + // + + SmallVector<JobActionInfo, 5> ActionChain(1); + ActionChain.back().JA = BaseAction; + while (ActionChain.back().JA) { + const Action *CurAction = ActionChain.back().JA; + + // Grow the chain by one element. + ActionChain.resize(ActionChain.size() + 1); + JobActionInfo &AI = ActionChain.back(); + + // Attempt to fill it with the + AI.JA = + getPrevDependentAction(CurAction->getInputs(), AI.SavedOffloadAction); + } + + // Pop the last action info as it could not be filled. + ActionChain.pop_back(); + + // + // Attempt to combine actions. If all combining attempts failed, just return + // the tool of the provided action. At the end we attempt to combine the + // action with any preprocessor action it may depend on. + // - return ToolForJob; + const Tool *T = combineAssembleBackendCompile(ActionChain, Inputs, + CollapsedOffloadAction); + if (!T) + T = combineAssembleBackend(ActionChain, Inputs, CollapsedOffloadAction); + if (!T) + T = combineBackendCompile(ActionChain, Inputs, CollapsedOffloadAction); + if (!T) { + Inputs = &BaseAction->getInputs(); + T = TC.SelectTool(*BaseAction); + } + + combineWithPreprocessor(T, Inputs, CollapsedOffloadAction); + return T; + } +}; } -InputInfo Driver::BuildJobsForAction( - Compilation &C, const Action *A, const ToolChain *TC, const char *BoundArch, - bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput, - std::map<std::pair<const Action *, std::string>, InputInfo> &CachedResults, - bool BuildForOffloadDevice) const { - // The bound arch is not necessarily represented in the toolchain's triple -- - // for example, armv7 and armv7s both map to the same triple -- so we need - // both in our map. +/// Return a string that uniquely identifies the result of a job. The bound arch +/// is not necessarily represented in the toolchain's triple -- for example, +/// armv7 and armv7s both map to the same triple -- so we need both in our map. +/// Also, we need to add the offloading device kind, as the same tool chain can +/// be used for host and device for some programming models, e.g. OpenMP. +static std::string GetTriplePlusArchString(const ToolChain *TC, + StringRef BoundArch, + Action::OffloadKind OffloadKind) { std::string TriplePlusArch = TC->getTriple().normalize(); - if (BoundArch) { + if (!BoundArch.empty()) { TriplePlusArch += "-"; TriplePlusArch += BoundArch; } - std::pair<const Action *, std::string> ActionTC = {A, TriplePlusArch}; + TriplePlusArch += "-"; + TriplePlusArch += Action::GetOffloadKindName(OffloadKind); + return TriplePlusArch; +} + +InputInfo Driver::BuildJobsForAction( + Compilation &C, const Action *A, const ToolChain *TC, StringRef BoundArch, + bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput, + std::map<std::pair<const Action *, std::string>, InputInfo> &CachedResults, + Action::OffloadKind TargetDeviceOffloadKind) const { + std::pair<const Action *, std::string> ActionTC = { + A, GetTriplePlusArchString(TC, BoundArch, TargetDeviceOffloadKind)}; auto CachedResult = CachedResults.find(ActionTC); if (CachedResult != CachedResults.end()) { return CachedResult->second; } InputInfo Result = BuildJobsForActionNoCache( C, A, TC, BoundArch, AtTopLevel, MultipleArchs, LinkingOutput, - CachedResults, BuildForOffloadDevice); + CachedResults, TargetDeviceOffloadKind); CachedResults[ActionTC] = Result; return Result; } InputInfo Driver::BuildJobsForActionNoCache( - Compilation &C, const Action *A, const ToolChain *TC, const char *BoundArch, + Compilation &C, const Action *A, const ToolChain *TC, StringRef BoundArch, bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput, std::map<std::pair<const Action *, std::string>, InputInfo> &CachedResults, - bool BuildForOffloadDevice) const { + Action::OffloadKind TargetDeviceOffloadKind) const { llvm::PrettyStackTraceString CrashInfo("Building compilation jobs"); InputInfoList OffloadDependencesInputInfo; + bool BuildingForOffloadDevice = TargetDeviceOffloadKind != Action::OFK_None; if (const OffloadAction *OA = dyn_cast<OffloadAction>(A)) { // The offload action is expected to be used in four different situations. // @@ -2121,7 +3106,7 @@ InputInfo Driver::BuildJobsForActionNoCache( // b) Set a toolchain/architecture/kind for a device action; // Device Action 1 -> OffloadAction -> Device Action 2 // - // c) Specify a device dependences to a host action; + // c) Specify a device dependence to a host action; // Device Action 1 _ // \ // Host Action 1 ---> OffloadAction -> Host Action 2 @@ -2144,7 +3129,7 @@ InputInfo Driver::BuildJobsForActionNoCache( DevA = BuildJobsForAction(C, DepA, DepTC, DepBoundArch, AtTopLevel, /*MultipleArchs*/ !!DepBoundArch, LinkingOutput, - CachedResults, /*BuildForOffloadDevice=*/true); + CachedResults, DepA->getOffloadingDeviceKind()); }); return DevA; } @@ -2154,16 +3139,15 @@ InputInfo Driver::BuildJobsForActionNoCache( // generate the host dependences and override the action with the device // dependence. The dependences can't therefore be a top-level action. OA->doOnEachDependence( - /*IsHostDependence=*/BuildForOffloadDevice, + /*IsHostDependence=*/BuildingForOffloadDevice, [&](Action *DepA, const ToolChain *DepTC, const char *DepBoundArch) { OffloadDependencesInputInfo.push_back(BuildJobsForAction( C, DepA, DepTC, DepBoundArch, /*AtTopLevel=*/false, /*MultipleArchs*/ !!DepBoundArch, LinkingOutput, CachedResults, - /*BuildForOffloadDevice=*/DepA->getOffloadingDeviceKind() != - Action::OFK_None)); + DepA->getOffloadingDeviceKind())); }); - A = BuildForOffloadDevice + A = BuildingForOffloadDevice ? OA->getSingleDeviceDependence(/*DoNotConsiderHostActions=*/true) : OA->getHostDependence(); } @@ -2182,9 +3166,9 @@ InputInfo Driver::BuildJobsForActionNoCache( if (const BindArchAction *BAA = dyn_cast<BindArchAction>(A)) { const ToolChain *TC; - const char *ArchName = BAA->getArchName(); + StringRef ArchName = BAA->getArchName(); - if (ArchName) + if (!ArchName.empty()) TC = &getToolChain(C.getArgs(), computeTargetTriple(*this, DefaultTargetTriple, C.getArgs(), ArchName)); @@ -2193,7 +3177,7 @@ InputInfo Driver::BuildJobsForActionNoCache( return BuildJobsForAction(C, *BAA->input_begin(), TC, ArchName, AtTopLevel, MultipleArchs, LinkingOutput, CachedResults, - BuildForOffloadDevice); + TargetDeviceOffloadKind); } @@ -2202,9 +3186,9 @@ InputInfo Driver::BuildJobsForActionNoCache( const JobAction *JA = cast<JobAction>(A); ActionList CollapsedOffloadActions; - const Tool *T = - selectToolForJob(C, isSaveTempsEnabled(), embedBitcodeEnabled(), TC, JA, - Inputs, CollapsedOffloadActions); + ToolSelector TS(JA, *TC, C, isSaveTempsEnabled(), embedBitcodeInObject()); + const Tool *T = TS.getTool(Inputs, CollapsedOffloadActions); + if (!T) return InputInfo(); @@ -2212,13 +3196,12 @@ InputInfo Driver::BuildJobsForActionNoCache( // need to build jobs for host/device-side inputs it may have held. for (const auto *OA : CollapsedOffloadActions) cast<OffloadAction>(OA)->doOnEachDependence( - /*IsHostDependence=*/BuildForOffloadDevice, + /*IsHostDependence=*/BuildingForOffloadDevice, [&](Action *DepA, const ToolChain *DepTC, const char *DepBoundArch) { OffloadDependencesInputInfo.push_back(BuildJobsForAction( - C, DepA, DepTC, DepBoundArch, AtTopLevel, + C, DepA, DepTC, DepBoundArch, /* AtTopLevel */ false, /*MultipleArchs=*/!!DepBoundArch, LinkingOutput, CachedResults, - /*BuildForOffloadDevice=*/DepA->getOffloadingDeviceKind() != - Action::OFK_None)); + DepA->getOffloadingDeviceKind())); }); // Only use pipes when there is exactly one input. @@ -2231,7 +3214,7 @@ InputInfo Driver::BuildJobsForActionNoCache( AtTopLevel && (isa<DsymutilJobAction>(A) || isa<VerifyJobAction>(A)); InputInfos.push_back(BuildJobsForAction( C, Input, TC, BoundArch, SubJobAtTopLevel, MultipleArchs, LinkingOutput, - CachedResults, BuildForOffloadDevice)); + CachedResults, A->getOffloadingDeviceKind())); } // Always use the first input as the base input. @@ -2247,15 +3230,75 @@ InputInfo Driver::BuildJobsForActionNoCache( InputInfos.append(OffloadDependencesInputInfo.begin(), OffloadDependencesInputInfo.end()); + // Set the effective triple of the toolchain for the duration of this job. + llvm::Triple EffectiveTriple; + const ToolChain &ToolTC = T->getToolChain(); + const ArgList &Args = + C.getArgsForToolChain(TC, BoundArch, A->getOffloadingDeviceKind()); + if (InputInfos.size() != 1) { + EffectiveTriple = llvm::Triple(ToolTC.ComputeEffectiveClangTriple(Args)); + } else { + // Pass along the input type if it can be unambiguously determined. + EffectiveTriple = llvm::Triple( + ToolTC.ComputeEffectiveClangTriple(Args, InputInfos[0].getType())); + } + RegisterEffectiveTriple TripleRAII(ToolTC, EffectiveTriple); + // Determine the place to write output to, if any. InputInfo Result; - if (JA->getType() == types::TY_Nothing) + InputInfoList UnbundlingResults; + if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(JA)) { + // If we have an unbundling job, we need to create results for all the + // outputs. We also update the results cache so that other actions using + // this unbundling action can get the right results. + for (auto &UI : UA->getDependentActionsInfo()) { + assert(UI.DependentOffloadKind != Action::OFK_None && + "Unbundling with no offloading??"); + + // Unbundling actions are never at the top level. When we generate the + // offloading prefix, we also do that for the host file because the + // unbundling action does not change the type of the output which can + // cause a overwrite. + std::string OffloadingPrefix = Action::GetOffloadingFileNamePrefix( + UI.DependentOffloadKind, + UI.DependentToolChain->getTriple().normalize(), + /*CreatePrefixForHost=*/true); + auto CurI = InputInfo( + UA, GetNamedOutputPath(C, *UA, BaseInput, UI.DependentBoundArch, + /*AtTopLevel=*/false, MultipleArchs, + OffloadingPrefix), + BaseInput); + // Save the unbundling result. + UnbundlingResults.push_back(CurI); + + // Get the unique string identifier for this dependence and cache the + // result. + CachedResults[{A, GetTriplePlusArchString( + UI.DependentToolChain, UI.DependentBoundArch, + UI.DependentOffloadKind)}] = CurI; + } + + // Now that we have all the results generated, select the one that should be + // returned for the current depending action. + std::pair<const Action *, std::string> ActionTC = { + A, GetTriplePlusArchString(TC, BoundArch, TargetDeviceOffloadKind)}; + assert(CachedResults.find(ActionTC) != CachedResults.end() && + "Result does not exist??"); + Result = CachedResults[ActionTC]; + } else if (JA->getType() == types::TY_Nothing) Result = InputInfo(A, BaseInput); - else + else { + // We only have to generate a prefix for the host if this is not a top-level + // action. + std::string OffloadingPrefix = Action::GetOffloadingFileNamePrefix( + A->getOffloadingDeviceKind(), TC->getTriple().normalize(), + /*CreatePrefixForHost=*/!!A->getOffloadingHostActiveKinds() && + !AtTopLevel); Result = InputInfo(A, GetNamedOutputPath(C, *JA, BaseInput, BoundArch, AtTopLevel, MultipleArchs, - TC->getTriple().normalize()), + OffloadingPrefix), BaseInput); + } if (CCCPrintBindings && !CCGenDiagnostics) { llvm::errs() << "# \"" << T->getToolChain().getTripleString() << '"' @@ -2265,10 +3308,28 @@ InputInfo Driver::BuildJobsForActionNoCache( if (i + 1 != e) llvm::errs() << ", "; } - llvm::errs() << "], output: " << Result.getAsString() << "\n"; + if (UnbundlingResults.empty()) + llvm::errs() << "], output: " << Result.getAsString() << "\n"; + else { + llvm::errs() << "], outputs: ["; + for (unsigned i = 0, e = UnbundlingResults.size(); i != e; ++i) { + llvm::errs() << UnbundlingResults[i].getAsString(); + if (i + 1 != e) + llvm::errs() << ", "; + } + llvm::errs() << "] \n"; + } } else { - T->ConstructJob(C, *JA, Result, InputInfos, - C.getArgsForToolChain(TC, BoundArch), LinkingOutput); + if (UnbundlingResults.empty()) + T->ConstructJob( + C, *JA, Result, InputInfos, + C.getArgsForToolChain(TC, BoundArch, JA->getOffloadingDeviceKind()), + LinkingOutput); + else + T->ConstructJobMultipleOutputs( + C, *JA, UnbundlingResults, InputInfos, + C.getArgsForToolChain(TC, BoundArch, JA->getOffloadingDeviceKind()), + LinkingOutput); } return Result; } @@ -2313,9 +3374,9 @@ static const char *MakeCLOutputFilename(const ArgList &Args, StringRef ArgValue, const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, const char *BaseInput, - const char *BoundArch, bool AtTopLevel, + StringRef BoundArch, bool AtTopLevel, bool MultipleArchs, - StringRef NormalizedTriple) const { + StringRef OffloadingPrefix) const { llvm::PrettyStackTraceString CrashInfo("Computing output path"); // Output to a user requested destination? if (AtTopLevel && !isa<DsymutilJobAction>(JA) && !isa<VerifyJobAction>(JA)) { @@ -2360,7 +3421,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, std::pair<StringRef, StringRef> Split = Name.split('.'); std::string TmpName = GetTemporaryPath( Split.first, types::getTypeTempSuffix(JA.getType(), IsCLMode())); - return C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str())); + return C.addTempFile(C.getArgs().MakeArgString(TmpName)); } SmallString<128> BasePath(BaseInput); @@ -2375,7 +3436,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, // Determine what the derived output name should be. const char *NamedOutput; - if (JA.getType() == types::TY_Object && + if ((JA.getType() == types::TY_Object || JA.getType() == types::TY_LTO_BC) && C.getArgs().hasArg(options::OPT__SLASH_Fo, options::OPT__SLASH_o)) { // The /Fo or /o flag decides the object filename. StringRef Val = @@ -2399,17 +3460,17 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, // clang-cl uses BaseName for the executable name. NamedOutput = MakeCLOutputFilename(C.getArgs(), "", BaseName, types::TY_Image); - } else if (MultipleArchs && BoundArch) { + } else { SmallString<128> Output(getDefaultImageName()); - Output += JA.getOffloadingFileNamePrefix(NormalizedTriple); - Output += "-"; - Output.append(BoundArch); + Output += OffloadingPrefix; + if (MultipleArchs && !BoundArch.empty()) { + Output += "-"; + Output.append(BoundArch); + } NamedOutput = C.getArgs().MakeArgString(Output.c_str()); - } else { - NamedOutput = getDefaultImageName(); } } else if (JA.getType() == types::TY_PCH && IsCLMode()) { - NamedOutput = C.getArgs().MakeArgString(GetClPchPath(C, BaseName).c_str()); + NamedOutput = C.getArgs().MakeArgString(GetClPchPath(C, BaseName)); } else { const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode()); assert(Suffix && "All types used for output should have a suffix."); @@ -2418,8 +3479,8 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, if (!types::appendSuffixForType(JA.getType())) End = BaseName.rfind('.'); SmallString<128> Suffixed(BaseName.substr(0, End)); - Suffixed += JA.getOffloadingFileNamePrefix(NormalizedTriple); - if (MultipleArchs && BoundArch) { + Suffixed += OffloadingPrefix; + if (MultipleArchs && !BoundArch.empty()) { Suffixed += "-"; Suffixed.append(BoundArch); } @@ -2459,7 +3520,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, std::pair<StringRef, StringRef> Split = Name.split('.'); std::string TmpName = GetTemporaryPath( Split.first, types::getTypeTempSuffix(JA.getType(), IsCLMode())); - return C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str())); + return C.addTempFile(C.getArgs().MakeArgString(TmpName)); } } @@ -2476,7 +3537,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, } } -std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const { +std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const { // Respect a limited subset of the '-Bprefix' functionality in GCC by // attempting to use this prefix when looking for file paths. for (const std::string &Dir : PrefixDirs) { @@ -2506,16 +3567,16 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const { } void Driver::generatePrefixedToolNames( - const char *Tool, const ToolChain &TC, + StringRef Tool, const ToolChain &TC, SmallVectorImpl<std::string> &Names) const { // FIXME: Needs a better variable than DefaultTargetTriple - Names.emplace_back(DefaultTargetTriple + "-" + Tool); + Names.emplace_back((DefaultTargetTriple + "-" + Tool).str()); Names.emplace_back(Tool); // Allow the discovery of tools prefixed with LLVM's default target triple. std::string LLVMDefaultTargetTriple = llvm::sys::getDefaultTargetTriple(); if (LLVMDefaultTargetTriple != DefaultTargetTriple) - Names.emplace_back(LLVMDefaultTargetTriple + "-" + Tool); + Names.emplace_back((LLVMDefaultTargetTriple + "-" + Tool).str()); } static bool ScanDirForExecutable(SmallString<128> &Dir, @@ -2529,8 +3590,7 @@ static bool ScanDirForExecutable(SmallString<128> &Dir, return false; } -std::string Driver::GetProgramPath(const char *Name, - const ToolChain &TC) const { +std::string Driver::GetProgramPath(StringRef Name, const ToolChain &TC) const { SmallVector<std::string, 2> TargetSpecificExecutables; generatePrefixedToolNames(Name, TC, TargetSpecificExecutables); @@ -2542,7 +3602,7 @@ std::string Driver::GetProgramPath(const char *Name, if (ScanDirForExecutable(P, TargetSpecificExecutables)) return P.str(); } else { - SmallString<128> P(PrefixDir + Name); + SmallString<128> P((PrefixDir + Name).str()); if (llvm::sys::fs::can_execute(Twine(P))) return P.str(); } @@ -2564,8 +3624,7 @@ std::string Driver::GetProgramPath(const char *Name, return Name; } -std::string Driver::GetTemporaryPath(StringRef Prefix, - const char *Suffix) const { +std::string Driver::GetTemporaryPath(StringRef Prefix, StringRef Suffix) const { SmallString<128> Path; std::error_code EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, Path); if (EC) { @@ -2645,6 +3704,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::NaCl: TC = new toolchains::NaClToolChain(*this, Target, Args); break; + case llvm::Triple::Fuchsia: + TC = new toolchains::Fuchsia(*this, Target, Args); + break; case llvm::Triple::Solaris: TC = new toolchains::Solaris(*this, Target, Args); break; @@ -2673,12 +3735,12 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, break; } break; - case llvm::Triple::CUDA: - TC = new toolchains::CudaToolChain(*this, Target, Args); - break; case llvm::Triple::PS4: TC = new toolchains::PS4CPU(*this, Target, Args); break; + case llvm::Triple::Contiki: + TC = new toolchains::Contiki(*this, Target, Args); + break; default: // Of these targets, Hexagon is the only one that might have // an OS of Linux, in which case it got handled above already. @@ -2686,6 +3748,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::tce: TC = new toolchains::TCEToolChain(*this, Target, Args); break; + case llvm::Triple::tcele: + TC = new toolchains::TCELEToolChain(*this, Target, Args); + break; case llvm::Triple::hexagon: TC = new toolchains::HexagonToolChain(*this, Target, Args); break; @@ -2699,6 +3764,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::wasm64: TC = new toolchains::WebAssembly(*this, Target, Args); break; + case llvm::Triple::avr: + TC = new toolchains::AVRToolChain(*this, Target, Args); + break; default: if (Target.getVendor() == llvm::Triple::Myriad) TC = new toolchains::MyriadToolChain(*this, Target, Args); @@ -2711,6 +3779,12 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, } } } + + // Intentionally omitted from the switch above: llvm::Triple::CUDA. CUDA + // compiles always need two toolchains, the CUDA toolchain and the host + // toolchain. So the only valid way to create a CUDA toolchain is via + // CreateOffloadingDeviceToolChains. + return *TC; } @@ -2733,36 +3807,35 @@ bool Driver::ShouldUseClangCompiler(const JobAction &JA) const { /// /// \return True if the entire string was parsed (9.2), or all groups were /// parsed (10.3.5extrastuff). -bool Driver::GetReleaseVersion(const char *Str, unsigned &Major, - unsigned &Minor, unsigned &Micro, - bool &HadExtra) { +bool Driver::GetReleaseVersion(StringRef Str, unsigned &Major, unsigned &Minor, + unsigned &Micro, bool &HadExtra) { HadExtra = false; Major = Minor = Micro = 0; - if (*Str == '\0') + if (Str.empty()) return false; - char *End; - Major = (unsigned)strtol(Str, &End, 10); - if (*Str != '\0' && *End == '\0') + if (Str.consumeInteger(10, Major)) + return false; + if (Str.empty()) return true; - if (*End != '.') + if (Str[0] != '.') return false; - Str = End + 1; - Minor = (unsigned)strtol(Str, &End, 10); - if (*Str != '\0' && *End == '\0') + Str = Str.drop_front(1); + + if (Str.consumeInteger(10, Minor)) + return false; + if (Str.empty()) return true; - if (*End != '.') + if (Str[0] != '.') return false; + Str = Str.drop_front(1); - Str = End + 1; - Micro = (unsigned)strtol(Str, &End, 10); - if (*Str != '\0' && *End == '\0') - return true; - if (Str == End) + if (Str.consumeInteger(10, Micro)) return false; - HadExtra = true; + if (!Str.empty()) + HadExtra = true; return true; } @@ -2772,21 +3845,22 @@ bool Driver::GetReleaseVersion(const char *Str, unsigned &Major, /// /// \return True if the entire string was parsed and there are /// no extra characters remaining at the end. -bool Driver::GetReleaseVersion(const char *Str, +bool Driver::GetReleaseVersion(StringRef Str, MutableArrayRef<unsigned> Digits) { - if (*Str == '\0') + if (Str.empty()) return false; - char *End; unsigned CurDigit = 0; while (CurDigit < Digits.size()) { - unsigned Digit = (unsigned)strtol(Str, &End, 10); + unsigned Digit; + if (Str.consumeInteger(10, Digit)) + return false; Digits[CurDigit] = Digit; - if (*Str != '\0' && *End == '\0') + if (Str.empty()) return true; - if (*End != '.' || Str == End) + if (Str[0] != '.') return false; - Str = End + 1; + Str = Str.drop_front(1); CurDigit++; } diff --git a/contrib/llvm/tools/clang/lib/Driver/Job.cpp b/contrib/llvm/tools/clang/lib/Driver/Job.cpp index 2d99b1f..9fd8808 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Job.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Job.cpp @@ -7,18 +7,20 @@ // //===----------------------------------------------------------------------===// +#include "clang/Driver/Job.h" #include "InputInfo.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" -#include "clang/Driver/Job.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" #include "llvm/ADT/ArrayRef.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> @@ -37,50 +39,62 @@ Command::Command(const Action &Source, const Tool &Creator, InputFilenames.push_back(II.getFilename()); } -static int skipArgs(const char *Flag, bool HaveCrashVFS) { +/// @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 Res = llvm::StringSwitch<bool>(Flag) + bool ShouldSkip = llvm::StringSwitch<bool>(Flag) .Cases("-MF", "-MT", "-MQ", "-serialize-diagnostic-file", true) .Cases("-o", "-coverage-file", "-dependency-file", true) - .Cases("-fdebug-compilation-dir", "-idirafter", true) - .Cases("-include", "-include-pch", "-internal-isystem", true) - .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true) - .Cases("-iwithprefixbefore", "-isystem", "-iquote", true) + .Cases("-fdebug-compilation-dir", "-diagnostic-log-file", true) .Cases("-dwarf-debug-flags", "-ivfsoverlay", true) - .Cases("-header-include-file", "-diagnostic-log-file", true) - // Some include flags shouldn't be skipped if we have a crash VFS - .Cases("-isysroot", "-I", "-F", "-resource-dir", !HaveCrashVFS) .Default(false); - - // Match found. - if (Res) - return 2; + 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. - Res = llvm::StringSwitch<bool>(Flag) + ShouldSkip = llvm::StringSwitch<bool>(Flag) .Cases("-M", "-MM", "-MG", "-MP", "-MD", true) .Case("-MMD", true) .Default(false); // Match found. - if (Res) - return 1; + SkipNum = 1; + if (ShouldSkip) + return true; // These flags are treated as a single argument (e.g., -F<Dir>). StringRef FlagRef(Flag); - if ((!HaveCrashVFS && - (FlagRef.startswith("-F") || FlagRef.startswith("-I"))) || - FlagRef.startswith("-fmodules-cache-path=")) - return 1; - - return 0; + 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, const char *Arg, bool Quote) { - const bool Escape = std::strpbrk(Arg, "\"\\$"); +void Command::printArg(raw_ostream &OS, StringRef Arg, bool Quote) { + const bool Escape = Arg.find_first_of("\"\\$") != StringRef::npos; if (!Quote && !Escape) { OS << Arg; @@ -89,7 +103,7 @@ void Command::printArg(raw_ostream &OS, const char *Arg, bool Quote) { // Quote and escape. This isn't really complete, but good enough. OS << '"'; - while (const char c = *Arg++) { + for (const char c : Arg) { if (c == '"' || c == '\\' || c == '$') OS << '\\'; OS << c; @@ -152,6 +166,45 @@ void Command::buildArgvForResponseFile( } } +/// @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. @@ -170,10 +223,27 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, const char *const Arg = Args[i]; if (CrashInfo) { - if (int Skip = skipArgs(Arg, HaveCrashVFS)) { - i += Skip - 1; + 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() && @@ -181,7 +251,7 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, // Replace the input file name with the crashinfo's file name. OS << ' '; StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename); - printArg(OS, ShortName.str().c_str(), Quote); + printArg(OS, ShortName.str(), Quote); continue; } } @@ -194,19 +264,22 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, OS << ' '; printArg(OS, "-ivfsoverlay", Quote); OS << ' '; - printArg(OS, CrashInfo->VFSPath.str().c_str(), Quote); + printArg(OS, CrashInfo->VFSPath.str(), Quote); - // Insert -fmodules-cache-path and use the relative module directory - // <name>.cache/vfs/modules where we already dumped the modules. + // 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, "modules"); + llvm::sys::path::append(RelModCacheDir, "repro-modules"); std::string ModCachePath = "-fmodules-cache-path="; ModCachePath.append(RelModCacheDir.c_str()); OS << ' '; - printArg(OS, ModCachePath.c_str(), Quote); + printArg(OS, ModCachePath, Quote); } if (ResponseFile != nullptr) { diff --git a/contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp index b8de5ad..17fd6ac 100644 --- a/contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp @@ -16,12 +16,14 @@ #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Config/llvm-config.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include <cstdio> @@ -45,9 +47,9 @@ using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; -MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple& Triple, +MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : ToolChain(D, Triple, Args) { + : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); @@ -92,6 +94,15 @@ bool MSVCToolChain::isPICDefaultForced() const { return getArch() == llvm::Triple::x86_64; } +void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); +} + +void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const { + CudaInstallation.print(OS); +} + #ifdef USE_WIN32 static bool readFullStringValue(HKEY hkey, const char *valueName, std::string &value) { @@ -113,6 +124,9 @@ static bool readFullStringValue(HKEY hkey, const char *valueName, if (result == ERROR_SUCCESS) { std::wstring WideValue(reinterpret_cast<const wchar_t *>(buffer.data()), valueSize / sizeof(wchar_t)); + if (valueSize && WideValue.back() == L'\0') { + WideValue.pop_back(); + } // The destination buffer must be empty as an invariant of the conversion // function; but this function is sometimes called in a loop that passes in // the same buffer, however. Simply clear it out so we can overwrite it. @@ -190,8 +204,7 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName, lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0, KEY_READ | KEY_WOW64_32KEY, &hKey); if (lResult == ERROR_SUCCESS) { - lResult = readFullStringValue(hKey, valueName, value); - if (lResult == ERROR_SUCCESS) { + if (readFullStringValue(hKey, valueName, value)) { bestValue = dvalue; if (phValue) *phValue = bestName; @@ -208,8 +221,7 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName, lResult = RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); if (lResult == ERROR_SUCCESS) { - lResult = readFullStringValue(hKey, valueName, value); - if (lResult == ERROR_SUCCESS) + if (readFullStringValue(hKey, valueName, value)) returnValue = true; if (phValue) phValue->clear(); @@ -470,6 +482,14 @@ bool MSVCToolChain::getVisualStudioBinariesFolder(const char *clangProgramPath, return true; } +VersionTuple MSVCToolChain::getMSVCVersionFromTriple() const { + unsigned Major, Minor, Micro; + getTriple().getEnvironmentVersion(Major, Minor, Micro); + if (Major || Minor || Micro) + return VersionTuple(Major, Minor, Micro); + return VersionTuple(); +} + VersionTuple MSVCToolChain::getMSVCVersionFromExe() const { VersionTuple Version; #ifdef USE_WIN32 @@ -512,9 +532,9 @@ VersionTuple MSVCToolChain::getMSVCVersionFromExe() const { // Get Visual Studio installation directory. bool MSVCToolChain::getVisualStudioInstallDir(std::string &path) const { // First check the environment variables that vsvars32.bat sets. - const char *vcinstalldir = getenv("VCINSTALLDIR"); - if (vcinstalldir) { - path = vcinstalldir; + if (llvm::Optional<std::string> VcInstallDir = + llvm::sys::Process::GetEnv("VCINSTALLDIR")) { + path = std::move(*VcInstallDir); path = path.substr(0, path.find("\\VC")); return true; } @@ -540,26 +560,26 @@ bool MSVCToolChain::getVisualStudioInstallDir(std::string &path) const { } // Try the environment. - const char *vs120comntools = getenv("VS120COMNTOOLS"); - const char *vs100comntools = getenv("VS100COMNTOOLS"); - const char *vs90comntools = getenv("VS90COMNTOOLS"); - const char *vs80comntools = getenv("VS80COMNTOOLS"); - - const char *vscomntools = nullptr; - - // Find any version we can - if (vs120comntools) - vscomntools = vs120comntools; - else if (vs100comntools) - vscomntools = vs100comntools; - else if (vs90comntools) - vscomntools = vs90comntools; - else if (vs80comntools) - vscomntools = vs80comntools; - - if (vscomntools && *vscomntools) { - const char *p = strstr(vscomntools, "\\Common7\\Tools"); - path = p ? std::string(vscomntools, p) : vscomntools; + std::string vcomntools; + if (llvm::Optional<std::string> vs120comntools = + llvm::sys::Process::GetEnv("VS120COMNTOOLS")) + vcomntools = std::move(*vs120comntools); + else if (llvm::Optional<std::string> vs100comntools = + llvm::sys::Process::GetEnv("VS100COMNTOOLS")) + vcomntools = std::move(*vs100comntools); + else if (llvm::Optional<std::string> vs90comntools = + llvm::sys::Process::GetEnv("VS90COMNTOOLS")) + vcomntools = std::move(*vs90comntools); + else if (llvm::Optional<std::string> vs80comntools = + llvm::sys::Process::GetEnv("VS80COMNTOOLS")) + vcomntools = std::move(*vs80comntools); + + // Find any version we can. + if (!vcomntools.empty()) { + size_t p = vcomntools.find("\\Common7\\Tools"); + if (p != std::string::npos) + vcomntools.resize(p); + path = std::move(vcomntools); return true; } return false; @@ -592,9 +612,10 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, return; // Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat. - if (const char *cl_include_dir = getenv("INCLUDE")) { + if (llvm::Optional<std::string> cl_include_dir = + llvm::sys::Process::GetEnv("INCLUDE")) { SmallVector<StringRef, 8> Dirs; - StringRef(cl_include_dir) + StringRef(*cl_include_dir) .split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false); for (StringRef Dir : Dirs) addSystemInclude(DriverArgs, CC1Args, Dir); @@ -646,6 +667,7 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, return; } +#if defined(LLVM_ON_WIN32) // As a fallback, select default install paths. // FIXME: Don't guess drives and paths like this on Windows. const StringRef Paths[] = { @@ -656,6 +678,7 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include" }; addSystemIncludes(DriverArgs, CC1Args, Paths); +#endif } void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, @@ -663,21 +686,34 @@ void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, // FIXME: There should probably be logic here to find libc++ on Windows. } +VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D, + const ArgList &Args) const { + bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment(); + VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args); + if (MSVT.empty()) MSVT = getMSVCVersionFromTriple(); + if (MSVT.empty() && IsWindowsMSVC) MSVT = getMSVCVersionFromExe(); + if (MSVT.empty() && + Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, + IsWindowsMSVC)) { + // -fms-compatibility-version=18.00 is default. + // FIXME: Consider bumping this to 19 (MSVC2015) soon. + MSVT = VersionTuple(18); + } + return MSVT; +} + std::string MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const { - std::string TripleStr = - ToolChain::ComputeEffectiveClangTriple(Args, InputType); - llvm::Triple Triple(TripleStr); - VersionTuple MSVT = - tools::visualstudio::getMSVCVersion(/*D=*/nullptr, *this, Triple, Args, - /*IsWindowsMSVC=*/true); - if (MSVT.empty()) - return TripleStr; - + // The MSVC version doesn't care about the architecture, even though it + // may look at the triple internally. + VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args); MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().getValueOr(0), MSVT.getSubminor().getValueOr(0)); + // For the rest of the triple, however, a computed architecture name may + // be needed. + llvm::Triple Triple(ToolChain::ComputeEffectiveClangTriple(Args, InputType)); if (Triple.getEnvironment() == llvm::Triple::MSVC) { StringRef ObjFmt = Triple.getEnvironmentName().split('-').second; if (ObjFmt.empty()) @@ -806,7 +842,7 @@ static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL, llvm::opt::DerivedArgList * MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, - const char *BoundArch) const { + StringRef BoundArch, Action::OffloadKind) const { DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); const OptTable &Opts = getDriver().getOpts(); diff --git a/contrib/llvm/tools/clang/lib/Driver/MinGWToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/MinGWToolChain.cpp index 938440b..e971869 100644 --- a/contrib/llvm/tools/clang/lib/Driver/MinGWToolChain.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/MinGWToolChain.cpp @@ -20,10 +20,9 @@ using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; -namespace { // Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple. -bool findGccVersion(StringRef LibDir, std::string &GccLibDir, - std::string &Ver) { +static bool findGccVersion(StringRef LibDir, std::string &GccLibDir, + std::string &Ver) { Generic_GCC::GCCVersion Version = Generic_GCC::GCCVersion::Parse("0.0.0"); std::error_code EC; for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE; @@ -40,7 +39,6 @@ bool findGccVersion(StringRef LibDir, std::string &GccLibDir, } return Ver.size(); } -} void MinGW::findGccLibDir() { llvm::SmallVector<llvm::SmallString<32>, 2> Archs; @@ -63,7 +61,7 @@ void MinGW::findGccLibDir() { } MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : ToolChain(D, Triple, Args) { + : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); // In Windows there aren't any standard install locations, we search @@ -135,6 +133,15 @@ bool MinGW::UseSEHExceptions() const { return getArch() == llvm::Triple::x86_64; } +void MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); +} + +void MinGW::printVerboseInfo(raw_ostream &OS) const { + CudaInstallation.print(OS); +} + // Include directories for various hosts: // Windows, mingw.org diff --git a/contrib/llvm/tools/clang/lib/Driver/Multilib.cpp b/contrib/llvm/tools/clang/lib/Driver/Multilib.cpp index 34ad6a7..a88edf7 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Multilib.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Multilib.cpp @@ -13,12 +13,10 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" -#include "llvm/ADT/Triple.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" -#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Regex.h" #include "llvm/Support/YAMLParser.h" diff --git a/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp index 30cc3f4..f4f6dad 100644 --- a/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp @@ -49,8 +49,11 @@ enum CoverageFeature { CoverageIndirCall = 1 << 3, CoverageTraceBB = 1 << 4, CoverageTraceCmp = 1 << 5, - Coverage8bitCounters = 1 << 6, - CoverageTracePC = 1 << 7, + CoverageTraceDiv = 1 << 6, + CoverageTraceGep = 1 << 7, + Coverage8bitCounters = 1 << 8, + CoverageTracePC = 1 << 9, + CoverageTracePCGuard = 1 << 10, }; /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any @@ -162,7 +165,8 @@ bool SanitizerArgs::needsUbsanRt() const { return ((Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) || CoverageFeatures) && !Sanitizers.has(Address) && !Sanitizers.has(Memory) && - !Sanitizers.has(Thread) && !Sanitizers.has(DataFlow) && !CfiCrossDso; + !Sanitizers.has(Thread) && !Sanitizers.has(DataFlow) && + !Sanitizers.has(Leak) && !CfiCrossDso; } bool SanitizerArgs::needsCfiRt() const { @@ -434,6 +438,18 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, TC.getTriple().getArch() == llvm::Triple::x86_64); } + if (AllAddedKinds & Thread) { + TsanMemoryAccess = Args.hasFlag(options::OPT_fsanitize_thread_memory_access, + options::OPT_fno_sanitize_thread_memory_access, + TsanMemoryAccess); + TsanFuncEntryExit = Args.hasFlag(options::OPT_fsanitize_thread_func_entry_exit, + options::OPT_fno_sanitize_thread_func_entry_exit, + TsanFuncEntryExit); + TsanAtomics = Args.hasFlag(options::OPT_fsanitize_thread_atomics, + options::OPT_fno_sanitize_thread_atomics, + TsanAtomics); + } + if (AllAddedKinds & CFI) { CfiCrossDso = Args.hasFlag(options::OPT_fsanitize_cfi_cross_dso, options::OPT_fno_sanitize_cfi_cross_dso, false); @@ -524,7 +540,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, << "-fsanitize-coverage=8bit-counters" << "-fsanitize-coverage=(func|bb|edge)"; // trace-pc w/o func/bb/edge implies edge. - if ((CoverageFeatures & CoverageTracePC) && + if ((CoverageFeatures & (CoverageTracePC | CoverageTracePCGuard)) && !(CoverageFeatures & CoverageTypes)) CoverageFeatures |= CoverageEdge; @@ -556,14 +572,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime); } } - } - AsanUseAfterScope = - Args.hasArg(options::OPT_fsanitize_address_use_after_scope); - if (AsanUseAfterScope && !(AllAddedKinds & Address)) { - D.Diag(clang::diag::err_drv_argument_only_allowed_with) - << "-fsanitize-address-use-after-scope" - << "-fsanitize=address"; + if (Arg *A = Args.getLastArg( + options::OPT_fsanitize_address_use_after_scope, + options::OPT_fno_sanitize_address_use_after_scope)) { + AsanUseAfterScope = A->getOption().getID() == + options::OPT_fsanitize_address_use_after_scope; + } } // Parse -link-cxx-sanitizer flag. @@ -605,6 +620,12 @@ static void addIncludeLinkerOption(const ToolChain &TC, void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, types::ID InputType) const { + // NVPTX doesn't currently support sanitizers. Bailing out here means that + // e.g. -fsanitize=address applies only to host code, which is what we want + // for now. + if (TC.getTriple().isNVPTX()) + return; + // Translate available CoverageFeatures to corresponding clang-cc1 flags. // Do it even if Sanitizers.empty() since some forms of coverage don't require // sanitizers. @@ -615,8 +636,11 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, std::make_pair(CoverageIndirCall, "-fsanitize-coverage-indirect-calls"), std::make_pair(CoverageTraceBB, "-fsanitize-coverage-trace-bb"), std::make_pair(CoverageTraceCmp, "-fsanitize-coverage-trace-cmp"), + std::make_pair(CoverageTraceDiv, "-fsanitize-coverage-trace-div"), + std::make_pair(CoverageTraceGep, "-fsanitize-coverage-trace-gep"), std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters"), - std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc")}; + std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc"), + std::make_pair(CoverageTracePCGuard, "-fsanitize-coverage-trace-pc-guard")}; for (auto F : CoverageFlags) { if (CoverageFeatures & F.first) CmdArgs.push_back(Args.MakeArgString(F.second)); @@ -674,6 +698,22 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, if (MsanUseAfterDtor) CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-use-after-dtor")); + // FIXME: Pass these parameters as function attributes, not as -llvm flags. + if (!TsanMemoryAccess) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-tsan-instrument-memory-accesses=0"); + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-tsan-instrument-memintrinsics=0"); + } + if (!TsanFuncEntryExit) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-tsan-instrument-func-entry-exit=0"); + } + if (!TsanAtomics) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-tsan-instrument-atomics=0"); + } + if (CfiCrossDso) CmdArgs.push_back(Args.MakeArgString("-fsanitize-cfi-cross-dso")); @@ -752,8 +792,11 @@ int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) { .Case("indirect-calls", CoverageIndirCall) .Case("trace-bb", CoverageTraceBB) .Case("trace-cmp", CoverageTraceCmp) + .Case("trace-div", CoverageTraceDiv) + .Case("trace-gep", CoverageTraceGep) .Case("8bit-counters", Coverage8bitCounters) .Case("trace-pc", CoverageTracePC) + .Case("trace-pc-guard", CoverageTracePCGuard) .Default(0); if (F == 0) D.Diag(clang::diag::err_drv_unsupported_option_argument) diff --git a/contrib/llvm/tools/clang/lib/Driver/Tool.cpp b/contrib/llvm/tools/clang/lib/Driver/Tool.cpp index 7142e82..8184946 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tool.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Tool.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Tool.h" +#include "InputInfo.h" using namespace clang::driver; @@ -21,3 +22,12 @@ Tool::Tool(const char *_Name, const char *_ShortName, const ToolChain &TC, 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); +} diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp index e96688c..6adc038 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Driver/ToolChain.h" #include "Tools.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Config/config.h" @@ -15,16 +16,15 @@ #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" -#include "clang/Driver/ToolChain.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/Path.h" #include "llvm/Support/TargetParser.h" +#include "llvm/Support/TargetRegistry.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -68,7 +68,8 @@ static ToolChain::RTTIMode CalculateRTTIMode(const ArgList &Args, ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, const ArgList &Args) : D(D), Triple(T), Args(Args), CachedRTTIArg(GetRTTIArgument(Args)), - CachedRTTIMode(CalculateRTTIMode(Args, Triple, CachedRTTIArg)) { + CachedRTTIMode(CalculateRTTIMode(Args, Triple, CachedRTTIArg)), + EffectiveTriple() { if (Arg *A = Args.getLastArg(options::OPT_mthread_model)) if (!isThreadModelSupported(A->getValue())) D.Diag(diag::err_drv_invalid_thread_model_for_target) @@ -238,6 +239,12 @@ Tool *ToolChain::getLink() const { return Link.get(); } +Tool *ToolChain::getOffloadBundler() const { + if (!OffloadBundler) + OffloadBundler.reset(new tools::OffloadBundler(*this)); + return OffloadBundler.get(); +} + Tool *ToolChain::getTool(Action::ActionClass AC) const { switch (AC) { case Action::AssembleJobClass: @@ -262,6 +269,10 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { case Action::VerifyPCHJobClass: case Action::BackendJobClass: return getClang(); + + case Action::OffloadBundlingJobClass: + case Action::OffloadUnbundlingJobClass: + return getOffloadBundler(); } llvm_unreachable("Invalid tool kind."); @@ -340,36 +351,34 @@ std::string ToolChain::GetProgramPath(const char *Name) const { } std::string ToolChain::GetLinkerPath() const { - if (Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { - StringRef UseLinker = A->getValue(); - - if (llvm::sys::path::is_absolute(UseLinker)) { - // If we're passed -fuse-ld= with what looks like an absolute path, - // don't attempt to second-guess that. - if (llvm::sys::fs::exists(UseLinker)) - return UseLinker; - } else { - // If we're passed -fuse-ld= with no argument, or with the argument ld, - // then use whatever the default system linker is. - if (UseLinker.empty() || UseLinker == "ld") - return GetProgramPath("ld"); - - llvm::SmallString<8> LinkerName("ld."); - LinkerName.append(UseLinker); - - std::string LinkerPath(GetProgramPath(LinkerName.c_str())); - if (llvm::sys::fs::exists(LinkerPath)) - return LinkerPath; - } + const Arg* A = Args.getLastArg(options::OPT_fuse_ld_EQ); + StringRef UseLinker = A ? A->getValue() : CLANG_DEFAULT_LINKER; + + if (llvm::sys::path::is_absolute(UseLinker)) { + // If we're passed what looks like an absolute path, don't attempt to + // second-guess that. + if (llvm::sys::fs::exists(UseLinker)) + return UseLinker; + } else if (UseLinker.empty() || UseLinker == "ld") { + // If we're passed -fuse-ld= with no argument, or with the argument ld, + // then use whatever the default system linker is. + return GetProgramPath(getDefaultLinker()); + } else { + llvm::SmallString<8> LinkerName("ld."); + LinkerName.append(UseLinker); + + std::string LinkerPath(GetProgramPath(LinkerName.c_str())); + if (llvm::sys::fs::exists(LinkerPath)) + return LinkerPath; + } + if (A) getDriver().Diag(diag::err_drv_invalid_linker_name) << A->getAsString(Args); - return ""; - } - return GetProgramPath(DefaultLinker); + return GetProgramPath(getDefaultLinker()); } -types::ID ToolChain::LookupTypeForExtension(const char *Ext) const { +types::ID ToolChain::LookupTypeForExtension(StringRef Ext) const { return types::lookupTypeForExtension(Ext); } @@ -487,8 +496,10 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, ArchName = "arm"; // Assembly files should start in ARM mode, unless arch is M-profile. + // Windows is always thumb. if ((InputType != types::TY_PP_Asm && Args.hasFlag(options::OPT_mthumb, - options::OPT_mno_thumb, ThumbDefault)) || IsMProfile) { + options::OPT_mno_thumb, ThumbDefault)) || IsMProfile || + getTriple().isOSWindows()) { if (IsBigEndian) ArchName = "thumbeb"; else @@ -526,54 +537,39 @@ void ToolChain::addProfileRTLibs(const llvm::opt::ArgList &Args, ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType( const ArgList &Args) const { - if (Arg *A = Args.getLastArg(options::OPT_rtlib_EQ)) { - StringRef Value = A->getValue(); - if (Value == "compiler-rt") - return ToolChain::RLT_CompilerRT; - if (Value == "libgcc") - return ToolChain::RLT_Libgcc; - getDriver().Diag(diag::err_drv_invalid_rtlib_name) - << A->getAsString(Args); - } + const Arg* A = Args.getLastArg(options::OPT_rtlib_EQ); + StringRef LibName = A ? A->getValue() : CLANG_DEFAULT_RTLIB; - return GetDefaultRuntimeLibType(); -} + // Only use "platform" in tests to override CLANG_DEFAULT_RTLIB! + if (LibName == "compiler-rt") + return ToolChain::RLT_CompilerRT; + else if (LibName == "libgcc") + return ToolChain::RLT_Libgcc; + else if (LibName == "platform") + return GetDefaultRuntimeLibType(); -static bool ParseCXXStdlibType(const StringRef& Name, - ToolChain::CXXStdlibType& Type) { - if (Name == "libc++") - Type = ToolChain::CST_Libcxx; - else if (Name == "libstdc++") - Type = ToolChain::CST_Libstdcxx; - else - return false; + if (A) + getDriver().Diag(diag::err_drv_invalid_rtlib_name) << A->getAsString(Args); - return true; + return GetDefaultRuntimeLibType(); } ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{ - ToolChain::CXXStdlibType Type; - bool HasValidType = false; - bool ForcePlatformDefault = false; - const Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); - if (A) { - StringRef Value = A->getValue(); - HasValidType = ParseCXXStdlibType(Value, Type); - - // Only use in tests to override CLANG_DEFAULT_CXX_STDLIB! - if (Value == "platform") - ForcePlatformDefault = true; - else if (!HasValidType) - getDriver().Diag(diag::err_drv_invalid_stdlib_name) - << A->getAsString(Args); - } + StringRef LibName = A ? A->getValue() : CLANG_DEFAULT_CXX_STDLIB; + + // Only use "platform" in tests to override CLANG_DEFAULT_CXX_STDLIB! + if (LibName == "libc++") + return ToolChain::CST_Libcxx; + else if (LibName == "libstdc++") + return ToolChain::CST_Libstdcxx; + else if (LibName == "platform") + return GetDefaultCXXStdlibType(); - if (!HasValidType && (ForcePlatformDefault || - !ParseCXXStdlibType(CLANG_DEFAULT_CXX_STDLIB, Type))) - Type = GetDefaultCXXStdlibType(); + if (A) + getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); - return Type; + return GetDefaultCXXStdlibType(); } /// \brief Utility function to add a system include directory to CC1 arguments. @@ -688,7 +684,11 @@ SanitizerMask ToolChain::getSupportedSanitizers() const { SanitizerMask Res = (Undefined & ~Vptr & ~Function) | (CFI & ~CFIICall) | CFICastStrict | UnsignedIntegerOverflow | LocalBounds; if (getTriple().getArch() == llvm::Triple::x86 || - getTriple().getArch() == llvm::Triple::x86_64) + getTriple().getArch() == llvm::Triple::x86_64 || + getTriple().getArch() == llvm::Triple::arm || + getTriple().getArch() == llvm::Triple::aarch64 || + getTriple().getArch() == llvm::Triple::wasm32 || + getTriple().getArch() == llvm::Triple::wasm64) Res |= CFIICall; return Res; } @@ -698,3 +698,57 @@ void ToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, void ToolChain::AddIAMCUIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const {} + +static VersionTuple separateMSVCFullVersion(unsigned Version) { + if (Version < 100) + return VersionTuple(Version); + + if (Version < 10000) + return VersionTuple(Version / 100, Version % 100); + + unsigned Build = 0, Factor = 1; + for (; Version > 10000; Version = Version / 10, Factor = Factor * 10) + Build = Build + (Version % 10) * Factor; + return VersionTuple(Version / 100, Version % 100, Build); +} + +VersionTuple +ToolChain::computeMSVCVersion(const Driver *D, + const llvm::opt::ArgList &Args) const { + const Arg *MSCVersion = Args.getLastArg(options::OPT_fmsc_version); + const Arg *MSCompatibilityVersion = + Args.getLastArg(options::OPT_fms_compatibility_version); + + if (MSCVersion && MSCompatibilityVersion) { + if (D) + D->Diag(diag::err_drv_argument_not_allowed_with) + << MSCVersion->getAsString(Args) + << MSCompatibilityVersion->getAsString(Args); + return VersionTuple(); + } + + if (MSCompatibilityVersion) { + VersionTuple MSVT; + if (MSVT.tryParse(MSCompatibilityVersion->getValue())) { + if (D) + D->Diag(diag::err_drv_invalid_value) + << MSCompatibilityVersion->getAsString(Args) + << MSCompatibilityVersion->getValue(); + } else { + return MSVT; + } + } + + if (MSCVersion) { + unsigned Version = 0; + if (StringRef(MSCVersion->getValue()).getAsInteger(10, Version)) { + if (D) + D->Diag(diag::err_drv_invalid_value) + << MSCVersion->getAsString(Args) << MSCVersion->getValue(); + } else { + return separateMSVCFullVersion(Version); + } + } + + return VersionTuple(); +} diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp index 1b02f46..9bc9ae4 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp @@ -14,6 +14,7 @@ #include "clang/Basic/VirtualFileSystem.h" #include "clang/Config/config.h" // for GCC_INSTALL_PREFIX #include "clang/Driver/Compilation.h" +#include "clang/Driver/Distro.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" @@ -52,9 +53,10 @@ MachO::MachO(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) /// Darwin - Darwin tool chain for i386 and x86_64. Darwin::Darwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : MachO(D, Triple, Args), TargetInitialized(false) {} + : MachO(D, Triple, Args), TargetInitialized(false), + CudaInstallation(D, Triple, Args) {} -types::ID MachO::LookupTypeForExtension(const char *Ext) const { +types::ID MachO::LookupTypeForExtension(StringRef Ext) const { types::ID Ty = types::lookupTypeForExtension(Ext); // Darwin always preprocesses assembly files (unless -x is used explicitly). @@ -99,6 +101,11 @@ bool Darwin::hasBlocksRuntime() const { } } +void Darwin::AddCudaIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); +} + // This is just a MachO name translation routine and there's no // way to join this into ARMTargetParser without breaking all // other assumptions. Maybe MachO should consider standardising @@ -176,13 +183,6 @@ Darwin::~Darwin() {} MachO::~MachO() {} -std::string MachO::ComputeEffectiveClangTriple(const ArgList &Args, - types::ID InputType) const { - llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); - - return Triple.getTriple(); -} - std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const { llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); @@ -296,6 +296,14 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args, CmdArgs.push_back(Args.MakeArgString(P)); } +unsigned DarwinClang::GetDefaultDwarfVersion() const { + // Default to use DWARF 2 on OS X 10.10 / iOS 8 and lower. + if ((isTargetMacOS() && isMacosxVersionLT(10, 11)) || + (isTargetIOSBased() && isIPhoneOSVersionLT(9))) + return 2; + return 4; +} + void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, StringRef DarwinLibName, bool AlwaysLink, bool IsEmbedded, bool AddRPath) const { @@ -400,17 +408,22 @@ void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args, /*AddRPath*/ true); } +ToolChain::RuntimeLibType DarwinClang::GetRuntimeLibType( + const ArgList &Args) const { + if (Arg* A = Args.getLastArg(options::OPT_rtlib_EQ)) { + StringRef Value = A->getValue(); + if (Value != "compiler-rt") + getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform) + << Value << "darwin"; + } + + return ToolChain::RLT_CompilerRT; +} + void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - // Darwin only supports the compiler-rt based runtime libraries. - switch (GetRuntimeLibType(Args)) { - case ToolChain::RLT_CompilerRT: - break; - default: - getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform) - << Args.getLastArg(options::OPT_rtlib_EQ)->getValue() << "darwin"; - return; - } + // Call once to ensure diagnostic is printed if wrong value was specified + GetRuntimeLibType(Args); // Darwin doesn't support real static executables, don't link any runtime // libraries with -static. @@ -803,7 +816,8 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args, } DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args, - const char *BoundArch) const { + StringRef BoundArch, + Action::OffloadKind) const { DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); const OptTable &Opts = getDriver().getOpts(); @@ -821,7 +835,7 @@ DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args, llvm::Triple::ArchType XarchArch = tools::darwin::getArchTypeForMachOArchName(A->getValue(0)); if (!(XarchArch == getArch() || - (BoundArch && + (!BoundArch.empty() && XarchArch == tools::darwin::getArchTypeForMachOArchName(BoundArch)))) continue; @@ -937,7 +951,7 @@ DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args, // Add the arch options based on the particular spelling of -arch, to match // how the driver driver works. - if (BoundArch) { + if (!BoundArch.empty()) { StringRef Name = BoundArch; const Option MCpu = Opts.getOption(options::OPT_mcpu_EQ); const Option MArch = Opts.getOption(options::OPT_march_EQ); @@ -1032,14 +1046,16 @@ void MachO::AddLinkRuntimeLibArgs(const ArgList &Args, AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, false, true); } -DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, - const char *BoundArch) const { +DerivedArgList * +Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const { // First get the generic Apple args, before moving onto Darwin-specific ones. - DerivedArgList *DAL = MachO::TranslateArgs(Args, BoundArch); + DerivedArgList *DAL = + MachO::TranslateArgs(Args, BoundArch, DeviceOffloadKind); const OptTable &Opts = getDriver().getOpts(); // If no architecture is bound, none of the translations here are relevant. - if (!BoundArch) + if (BoundArch.empty()) return DAL; // Add an explicit version min argument for the deployment target. We do this @@ -1087,6 +1103,18 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, } } + auto Arch = tools::darwin::getArchTypeForMachOArchName(BoundArch); + if ((Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)) { + if (Args.hasFlag(options::OPT_fomit_frame_pointer, + options::OPT_fno_omit_frame_pointer, false)) + getDriver().Diag(clang::diag::warn_drv_unsupported_opt_for_target) + << "-fomit-frame-pointer" << BoundArch; + if (Args.hasFlag(options::OPT_momit_leaf_frame_pointer, + options::OPT_mno_omit_leaf_frame_pointer, false)) + getDriver().Diag(clang::diag::warn_drv_unsupported_opt_for_target) + << "-momit-leaf-frame-pointer" << BoundArch; + } + return DAL; } @@ -1275,6 +1303,10 @@ SanitizerMask Darwin::getSupportedSanitizers() const { return Res; } +void Darwin::printVerboseInfo(raw_ostream &OS) const { + CudaInstallation.print(OS); +} + /// Generic_GCC - A tool chain using the 'gcc' command to perform /// all subcommands; this relies on gcc translating the majority of /// command line options. @@ -1420,6 +1452,25 @@ void Generic_GCC::GCCInstallationDetector::init( } } + // Try to respect gcc-config on Gentoo. However, do that only + // if --gcc-toolchain is not provided or equal to the Gentoo install + // in /usr. This avoids accidentally enforcing the system GCC version + // when using a custom toolchain. + if (GCCToolchainDir == "" || GCCToolchainDir == D.SysRoot + "/usr") { + for (StringRef CandidateTriple : ExtraTripleAliases) { + if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) + return; + } + for (StringRef CandidateTriple : CandidateTripleAliases) { + if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) + return; + } + for (StringRef CandidateTriple : CandidateBiarchTripleAliases) { + if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple, true)) + return; + } + } + // Loop over the various components which exist and select the best GCC // installation available. GCC installs are ranked by version number. Version = GCCVersion::Parse("0.0.0"); @@ -1480,7 +1531,7 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { static const char *const AArch64LibDirs[] = {"/lib64", "/lib"}; static const char *const AArch64Triples[] = { "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-linux-android", - "aarch64-redhat-linux"}; + "aarch64-redhat-linux", "aarch64-suse-linux"}; static const char *const AArch64beLibDirs[] = {"/lib"}; static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu", "aarch64_be-linux-gnu"}; @@ -1518,8 +1569,8 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { "mips-mti-linux-gnu", "mips-img-linux-gnu"}; static const char *const MIPSELLibDirs[] = {"/lib"}; - static const char *const MIPSELTriples[] = { - "mipsel-linux-gnu", "mipsel-linux-android", "mips-img-linux-gnu"}; + static const char *const MIPSELTriples[] = {"mipsel-linux-gnu", + "mips-img-linux-gnu"}; static const char *const MIPS64LibDirs[] = {"/lib64", "/lib"}; static const char *const MIPS64Triples[] = { @@ -1528,7 +1579,15 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { static const char *const MIPS64ELLibDirs[] = {"/lib64", "/lib"}; static const char *const MIPS64ELTriples[] = { "mips64el-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu", - "mips64el-linux-android", "mips64el-linux-gnuabi64"}; + "mips64el-linux-gnuabi64"}; + + static const char *const MIPSELAndroidLibDirs[] = {"/lib", "/libr2", + "/libr6"}; + static const char *const MIPSELAndroidTriples[] = {"mipsel-linux-android"}; + static const char *const MIPS64ELAndroidLibDirs[] = {"/lib64", "/lib", + "/libr2", "/libr6"}; + static const char *const MIPS64ELAndroidTriples[] = { + "mips64el-linux-android"}; static const char *const PPCLibDirs[] = {"/lib32", "/lib"}; static const char *const PPCTriples[] = { @@ -1630,11 +1689,22 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { BiarchTripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples)); break; case llvm::Triple::mipsel: - LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); - TripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); - TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); - BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); - BiarchTripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); + if (TargetTriple.isAndroid()) { + LibDirs.append(begin(MIPSELAndroidLibDirs), end(MIPSELAndroidLibDirs)); + TripleAliases.append(begin(MIPSELAndroidTriples), + end(MIPSELAndroidTriples)); + BiarchLibDirs.append(begin(MIPS64ELAndroidLibDirs), + end(MIPS64ELAndroidLibDirs)); + BiarchTripleAliases.append(begin(MIPS64ELAndroidTriples), + end(MIPS64ELAndroidTriples)); + + } else { + LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); + TripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); + TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); + BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); + BiarchTripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); + } break; case llvm::Triple::mips64: LibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs)); @@ -1643,11 +1713,23 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); break; case llvm::Triple::mips64el: - LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); - TripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); - BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); - BiarchTripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); - BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); + if (TargetTriple.isAndroid()) { + LibDirs.append(begin(MIPS64ELAndroidLibDirs), + end(MIPS64ELAndroidLibDirs)); + TripleAliases.append(begin(MIPS64ELAndroidTriples), + end(MIPS64ELAndroidTriples)); + BiarchLibDirs.append(begin(MIPSELAndroidLibDirs), + end(MIPSELAndroidLibDirs)); + BiarchTripleAliases.append(begin(MIPSELAndroidTriples), + end(MIPSELAndroidTriples)); + + } else { + LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); + TripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); + BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); + BiarchTripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); + BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); + } break; case llvm::Triple::ppc: LibDirs.append(begin(PPCLibDirs), end(PPCLibDirs)); @@ -1706,8 +1788,8 @@ static CudaVersion ParseCudaVersionFile(llvm::StringRef V) { int Major = -1, Minor = -1; auto First = V.split('.'); auto Second = First.second.split('.'); - if (!First.first.getAsInteger(10, Major) || - !Second.first.getAsInteger(10, Minor)) + if (First.first.getAsInteger(10, Major) || + Second.first.getAsInteger(10, Minor)) return CudaVersion::UNKNOWN; if (Major == 7 && Minor == 0) { @@ -1722,21 +1804,27 @@ static CudaVersion ParseCudaVersionFile(llvm::StringRef V) { return CudaVersion::UNKNOWN; } -// \brief -- try common CUDA installation paths looking for files we need for -// CUDA compilation. -void Generic_GCC::CudaInstallationDetector::init( - const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args) { +CudaInstallationDetector::CudaInstallationDetector( + const Driver &D, const llvm::Triple &HostTriple, + const llvm::opt::ArgList &Args) + : D(D) { SmallVector<std::string, 4> CudaPathCandidates; - if (Args.hasArg(options::OPT_cuda_path_EQ)) + // In decreasing order so we prefer newer versions to older versions. + std::initializer_list<const char *> Versions = {"8.0", "7.5", "7.0"}; + + if (Args.hasArg(options::OPT_cuda_path_EQ)) { CudaPathCandidates.push_back( Args.getLastArgValue(options::OPT_cuda_path_EQ)); - else { + } else if (HostTriple.isOSWindows()) { + for (const char *Ver : Versions) + CudaPathCandidates.push_back( + D.SysRoot + "/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v" + + Ver); + } else { CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda"); - // FIXME: Uncomment this once we can compile the cuda 8 headers. - // CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-8.0"); - CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-7.5"); - CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-7.0"); + for (const char *Ver : Versions) + CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-" + Ver); } for (const auto &CudaPath : CudaPathCandidates) { @@ -1747,13 +1835,35 @@ void Generic_GCC::CudaInstallationDetector::init( BinPath = CudaPath + "/bin"; IncludePath = InstallPath + "/include"; LibDevicePath = InstallPath + "/nvvm/libdevice"; - LibPath = InstallPath + (TargetTriple.isArch64Bit() ? "/lib64" : "/lib"); auto &FS = D.getVFS(); - if (!(FS.exists(IncludePath) && FS.exists(BinPath) && FS.exists(LibPath) && + if (!(FS.exists(IncludePath) && FS.exists(BinPath) && FS.exists(LibDevicePath))) continue; + // On Linux, we have both lib and lib64 directories, and we need to choose + // based on our triple. On MacOS, we have only a lib directory. + // + // It's sufficient for our purposes to be flexible: If both lib and lib64 + // exist, we choose whichever one matches our triple. Otherwise, if only + // lib exists, we use it. + if (HostTriple.isArch64Bit() && FS.exists(InstallPath + "/lib64")) + LibPath = InstallPath + "/lib64"; + else if (FS.exists(InstallPath + "/lib")) + LibPath = InstallPath + "/lib"; + else + continue; + + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile = + FS.getBufferForFile(InstallPath + "/version.txt"); + if (!VersionFile) { + // CUDA 7.0 doesn't have a version.txt, so guess that's our version if + // version.txt isn't present. + Version = CudaVersion::CUDA_70; + } else { + Version = ParseCudaVersionFile((*VersionFile)->getBuffer()); + } + std::error_code EC; for (llvm::sys::fs::directory_iterator LI(LibDevicePath, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { @@ -1766,42 +1876,67 @@ void Generic_GCC::CudaInstallationDetector::init( StringRef GpuArch = FileName.slice( LibDeviceName.size(), FileName.find('.', LibDeviceName.size())); LibDeviceMap[GpuArch] = FilePath.str(); - // Insert map entries for specifc devices with this compute capability. + // Insert map entries for specifc devices with this compute + // capability. NVCC's choice of the libdevice library version is + // rather peculiar and depends on the CUDA version. if (GpuArch == "compute_20") { LibDeviceMap["sm_20"] = FilePath; LibDeviceMap["sm_21"] = FilePath; + LibDeviceMap["sm_32"] = FilePath; } else if (GpuArch == "compute_30") { LibDeviceMap["sm_30"] = FilePath; - LibDeviceMap["sm_32"] = FilePath; + if (Version < CudaVersion::CUDA_80) { + LibDeviceMap["sm_50"] = FilePath; + LibDeviceMap["sm_52"] = FilePath; + LibDeviceMap["sm_53"] = FilePath; + } + LibDeviceMap["sm_60"] = FilePath; + LibDeviceMap["sm_61"] = FilePath; + LibDeviceMap["sm_62"] = FilePath; } else if (GpuArch == "compute_35") { LibDeviceMap["sm_35"] = FilePath; LibDeviceMap["sm_37"] = FilePath; } else if (GpuArch == "compute_50") { - LibDeviceMap["sm_50"] = FilePath; - LibDeviceMap["sm_52"] = FilePath; - LibDeviceMap["sm_53"] = FilePath; - LibDeviceMap["sm_60"] = FilePath; - LibDeviceMap["sm_61"] = FilePath; - LibDeviceMap["sm_62"] = FilePath; + if (Version >= CudaVersion::CUDA_80) { + LibDeviceMap["sm_50"] = FilePath; + LibDeviceMap["sm_52"] = FilePath; + LibDeviceMap["sm_53"] = FilePath; + } } } - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile = - FS.getBufferForFile(InstallPath + "/version.txt"); - if (!VersionFile) { - // CUDA 7.0 doesn't have a version.txt, so guess that's our version if - // version.txt isn't present. - Version = CudaVersion::CUDA_70; - } else { - Version = ParseCudaVersionFile((*VersionFile)->getBuffer()); - } - IsValid = true; break; } } -void Generic_GCC::CudaInstallationDetector::CheckCudaVersionSupportsArch( +void CudaInstallationDetector::AddCudaIncludeArgs( + const ArgList &DriverArgs, ArgStringList &CC1Args) const { + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + // Add cuda_wrappers/* to our system include path. This lets us wrap + // standard library headers. + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include"); + llvm::sys::path::append(P, "cuda_wrappers"); + CC1Args.push_back("-internal-isystem"); + CC1Args.push_back(DriverArgs.MakeArgString(P)); + } + + if (DriverArgs.hasArg(options::OPT_nocudainc)) + return; + + if (!isValid()) { + D.Diag(diag::err_drv_no_cuda_installation); + return; + } + + CC1Args.push_back("-internal-isystem"); + CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath())); + CC1Args.push_back("-include"); + CC1Args.push_back("__clang_cuda_runtime_wrapper.h"); +} + +void CudaInstallationDetector::CheckCudaVersionSupportsArch( CudaArch Arch) const { if (Arch == CudaArch::UNKNOWN || Version == CudaVersion::UNKNOWN || ArchsWithVersionTooLowErrors.count(Arch) > 0) @@ -1816,7 +1951,7 @@ void Generic_GCC::CudaInstallationDetector::CheckCudaVersionSupportsArch( } } -void Generic_GCC::CudaInstallationDetector::print(raw_ostream &OS) const { +void CudaInstallationDetector::print(raw_ostream &OS) const { if (isValid()) OS << "Found CUDA installation: " << InstallPath << ", version " << CudaVersionToString(Version) << "\n"; @@ -1985,7 +2120,8 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, return false; } -static bool findMipsAndroidMultilibs(const Multilib::flags_list &Flags, +static bool findMipsAndroidMultilibs(vfs::FileSystem &VFS, StringRef Path, + const Multilib::flags_list &Flags, FilterNonExistent &NonExistent, DetectedMultilibs &Result) { @@ -1995,8 +2131,29 @@ static bool findMipsAndroidMultilibs(const Multilib::flags_list &Flags, .Maybe(Multilib("/mips-r6").flag("+march=mips32r6")) .FilterOut(NonExistent); - if (AndroidMipsMultilibs.select(Flags, Result.SelectedMultilib)) { - Result.Multilibs = AndroidMipsMultilibs; + MultilibSet AndroidMipselMultilibs = + MultilibSet() + .Either(Multilib().flag("+march=mips32"), + Multilib("/mips-r2", "", "/mips-r2").flag("+march=mips32r2"), + Multilib("/mips-r6", "", "/mips-r6").flag("+march=mips32r6")) + .FilterOut(NonExistent); + + MultilibSet AndroidMips64elMultilibs = + MultilibSet() + .Either( + Multilib().flag("+march=mips64r6"), + Multilib("/32/mips-r1", "", "/mips-r1").flag("+march=mips32"), + Multilib("/32/mips-r2", "", "/mips-r2").flag("+march=mips32r2"), + Multilib("/32/mips-r6", "", "/mips-r6").flag("+march=mips32r6")) + .FilterOut(NonExistent); + + MultilibSet *MS = &AndroidMipsMultilibs; + if (VFS.exists(Path + "/mips-r6")) + MS = &AndroidMipselMultilibs; + else if (VFS.exists(Path + "/32")) + MS = &AndroidMips64elMultilibs; + if (MS->select(Flags, Result.SelectedMultilib)) { + Result.Multilibs = *MS; return true; } return false; @@ -2323,6 +2480,7 @@ static bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple, addMultilibFlag(CPUName == "mips64r2" || CPUName == "mips64r3" || CPUName == "mips64r5" || CPUName == "octeon", "march=mips64r2", Flags); + addMultilibFlag(CPUName == "mips64r6", "march=mips64r6", Flags); addMultilibFlag(isMicroMips(Args), "mmicromips", Flags); addMultilibFlag(tools::mips::isUCLibc(Args), "muclibc", Flags); addMultilibFlag(tools::mips::isNaN2008(Args, TargetTriple), "mnan=2008", @@ -2335,7 +2493,8 @@ static bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple, addMultilibFlag(!isMipsEL(TargetArch), "EB", Flags); if (TargetTriple.isAndroid()) - return findMipsAndroidMultilibs(Flags, NonExistent, Result); + return findMipsAndroidMultilibs(D.getVFS(), Path, Flags, NonExistent, + Result); if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && TargetTriple.getOS() == llvm::Triple::Linux && @@ -2546,6 +2705,33 @@ void Generic_GCC::GCCInstallationDetector::scanLibDirForGCCTripleSolaris( } } +bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( + const llvm::Triple &TargetTriple, const ArgList &Args, + StringRef Path, bool NeedsBiarchSuffix) { + llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); + DetectedMultilibs Detected; + + // Android standalone toolchain could have multilibs for ARM and Thumb. + // Debian mips multilibs behave more like the rest of the biarch ones, + // so handle them there + if (isArmOrThumbArch(TargetArch) && TargetTriple.isAndroid()) { + // It should also work without multilibs in a simplified toolchain. + findAndroidArmMultilibs(D, TargetTriple, Path, Args, Detected); + } else if (isMipsArch(TargetArch)) { + if (!findMIPSMultilibs(D, TargetTriple, Path, Args, Detected)) + return false; + } else if (!findBiarchMultilibs(D, TargetTriple, Path, Args, + NeedsBiarchSuffix, Detected)) { + return false; + } + + Multilibs = Detected.Multilibs; + SelectedMultilib = Detected.SelectedMultilib; + BiarchSibling = Detected.BiarchSibling; + + return true; +} + void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( const llvm::Triple &TargetTriple, const ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, @@ -2601,25 +2787,10 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( if (CandidateVersion <= Version) continue; - DetectedMultilibs Detected; - - // Android standalone toolchain could have multilibs for ARM and Thumb. - // Debian mips multilibs behave more like the rest of the biarch ones, - // so handle them there - if (isArmOrThumbArch(TargetArch) && TargetTriple.isAndroid()) { - // It should also work without multilibs in a simplified toolchain. - findAndroidArmMultilibs(D, TargetTriple, LI->getName(), Args, Detected); - } else if (isMipsArch(TargetArch)) { - if (!findMIPSMultilibs(D, TargetTriple, LI->getName(), Args, Detected)) - continue; - } else if (!findBiarchMultilibs(D, TargetTriple, LI->getName(), Args, - NeedsBiarchSuffix, Detected)) { + if (!ScanGCCForMultilibs(TargetTriple, Args, LI->getName(), + NeedsBiarchSuffix)) continue; - } - Multilibs = Detected.Multilibs; - SelectedMultilib = Detected.SelectedMultilib; - BiarchSibling = Detected.BiarchSibling; Version = CandidateVersion; GCCTriple.setTriple(CandidateTriple); // FIXME: We hack together the directory name here instead of @@ -2633,9 +2804,49 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( } } +bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( + const llvm::Triple &TargetTriple, const ArgList &Args, + StringRef CandidateTriple, bool NeedsBiarchSuffix) { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = + D.getVFS().getBufferForFile(D.SysRoot + "/etc/env.d/gcc/config-" + + CandidateTriple.str()); + if (File) { + SmallVector<StringRef, 2> Lines; + File.get()->getBuffer().split(Lines, "\n"); + for (StringRef Line : Lines) { + // CURRENT=triple-version + if (Line.consume_front("CURRENT=")) { + const std::pair<StringRef, StringRef> ActiveVersion = + Line.rsplit('-'); + // Note: Strictly speaking, we should be reading + // /etc/env.d/gcc/${CURRENT} now. However, the file doesn't + // contain anything new or especially useful to us. + const std::string GentooPath = D.SysRoot + "/usr/lib/gcc/" + + ActiveVersion.first.str() + "/" + + ActiveVersion.second.str(); + if (D.getVFS().exists(GentooPath + "/crtbegin.o")) { + if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath, + NeedsBiarchSuffix)) + return false; + + Version = GCCVersion::Parse(ActiveVersion.second); + GCCInstallPath = GentooPath; + GCCParentLibPath = GentooPath + "/../../.."; + GCCTriple.setTriple(ActiveVersion.first); + IsValid = true; + return true; + } + } + } + } + + return false; +} + Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : ToolChain(D, Triple, Args), GCCInstallation(D), CudaInstallation(D) { + : ToolChain(D, Triple, Args), GCCInstallation(D), + CudaInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); @@ -2675,7 +2886,15 @@ bool Generic_GCC::IsUnwindTablesDefault() const { } bool Generic_GCC::isPICDefault() const { - return getArch() == llvm::Triple::x86_64 && getTriple().isOSWindows(); + switch (getArch()) { + case llvm::Triple::x86_64: + return getTriple().isOSWindows(); + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + return !getTriple().isOSBinFormatMachO() && !getTriple().isMacOSX(); + default: + return false; + } } bool Generic_GCC::isPIEDefault() const { return false; } @@ -2703,11 +2922,50 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const { case llvm::Triple::mips: case llvm::Triple::mipsel: return true; + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + // Enabled for Debian mips64/mips64el only. Other targets are unable to + // distinguish N32 from N64. + if (getTriple().getEnvironment() == llvm::Triple::GNUABI64) + return true; + return false; default: return false; } } +void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: { + std::string Path = findLibCxxIncludePath(); + if (!Path.empty()) + addSystemInclude(DriverArgs, CC1Args, Path); + break; + } + + case ToolChain::CST_Libstdcxx: + addLibStdCxxIncludePaths(DriverArgs, CC1Args); + break; + } +} + +std::string Generic_GCC::findLibCxxIncludePath() const { + // FIXME: The Linux behavior would probaby be a better approach here. + return getDriver().SysRoot + "/usr/include/c++/v1"; +} + +void +Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + // By default, we don't assume we know where libstdc++ might be installed. + // FIXME: If we have a valid GCCInstallation, use it. +} + /// \brief Helper to add the variant paths of a libstdc++ installation. bool Generic_GCC::addLibStdCXXIncludePaths( Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, @@ -2741,6 +2999,49 @@ bool Generic_GCC::addLibStdCXXIncludePaths( return true; } +llvm::opt::DerivedArgList * +Generic_GCC::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef, + Action::OffloadKind DeviceOffloadKind) const { + + // If this tool chain is used for an OpenMP offloading device we have to make + // sure we always generate a shared library regardless of the commands the + // user passed to the host. This is required because the runtime library + // is required to load the device image dynamically at run time. + if (DeviceOffloadKind == Action::OFK_OpenMP) { + DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); + const OptTable &Opts = getDriver().getOpts(); + + // Request the shared library. Given that these options are decided + // implicitly, they do not refer to any base argument. + DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_shared)); + DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_fPIC)); + + // Filter all the arguments we don't care passing to the offloading + // toolchain as they can mess up with the creation of a shared library. + for (auto *A : Args) { + switch ((options::ID)A->getOption().getID()) { + default: + DAL->append(A); + break; + case options::OPT_shared: + case options::OPT_dynamic: + case options::OPT_static: + case options::OPT_fPIC: + case options::OPT_fno_PIC: + case options::OPT_fpic: + case options::OPT_fno_pic: + case options::OPT_fPIE: + case options::OPT_fno_PIE: + case options::OPT_fpie: + case options::OPT_fno_pie: + break; + } + } + return DAL; + } + return nullptr; +} + void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args) const { const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion(); @@ -2773,9 +3074,6 @@ MipsLLVMToolChain::MipsLLVMToolChain(const Driver &D, LibSuffix = tools::mips::getMipsABILibSuffix(Args, Triple); getFilePaths().clear(); getFilePaths().push_back(computeSysRoot() + "/usr/lib" + LibSuffix); - - // Use LLD by default. - DefaultLinker = "lld"; } void MipsLLVMToolChain::AddClangSystemIncludeArgs( @@ -2832,25 +3130,16 @@ MipsLLVMToolChain::GetCXXStdlibType(const ArgList &Args) const { return ToolChain::CST_Libcxx; } -void MipsLLVMToolChain::AddClangCXXStdlibIncludeArgs( - const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) - return; - - assert((GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) && - "Only -lc++ (aka libcxx) is suported in this toolchain."); - - const auto &Callback = Multilibs.includeDirsCallback(); - if (Callback) { +std::string MipsLLVMToolChain::findLibCxxIncludePath() const { + if (const auto &Callback = Multilibs.includeDirsCallback()) { for (std::string Path : Callback(SelectedMultilib)) { Path = getDriver().getInstalledDir() + Path + "/c++/v1"; if (llvm::sys::fs::exists(Path)) { - addSystemInclude(DriverArgs, CC1Args, Path); - break; + return Path; } } } + return ""; } void MipsLLVMToolChain::AddCXXStdlibLibArgs(const ArgList &Args, @@ -2890,7 +3179,7 @@ std::string HexagonToolChain::getHexagonTargetDir( if (getVFS().exists(InstallRelDir = InstalledDir + "/../target")) return InstallRelDir; - return InstallRelDir; + return InstalledDir; } Optional<unsigned> HexagonToolChain::getSmallDataThreshold( @@ -2997,15 +3286,14 @@ void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include"); } -void HexagonToolChain::AddClangCXXStdlibIncludeArgs( - const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) - return; +void HexagonToolChain::addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { const Driver &D = getDriver(); std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs); - addSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include/c++"); + addLibStdCXXIncludePaths(TargetDir, "/hexagon/include/c++", "", "", "", "", + DriverArgs, CC1Args); } ToolChain::CXXStdlibType @@ -3163,37 +3451,25 @@ void NaClToolChain::AddCXXStdlibLibArgs(const ArgList &Args, CmdArgs.push_back("-lc++"); } -void NaClToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { +std::string NaClToolChain::findLibCxxIncludePath() const { const Driver &D = getDriver(); - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) - return; - - // Check for -stdlib= flags. We only support libc++ but this consumes the arg - // if the value is libc++, and emits an error for other values. - GetCXXStdlibType(DriverArgs); SmallString<128> P(D.Dir + "/../"); switch (getTriple().getArch()) { case llvm::Triple::arm: llvm::sys::path::append(P, "arm-nacl/include/c++/v1"); - addSystemInclude(DriverArgs, CC1Args, P.str()); - break; + return P.str(); case llvm::Triple::x86: llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1"); - addSystemInclude(DriverArgs, CC1Args, P.str()); - break; + return P.str(); case llvm::Triple::x86_64: llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1"); - addSystemInclude(DriverArgs, CC1Args, P.str()); - break; + return P.str(); case llvm::Triple::mipsel: llvm::sys::path::append(P, "mipsel-nacl/include/c++/v1"); - addSystemInclude(DriverArgs, CC1Args, P.str()); - break; + return P.str(); default: - break; + return ""; } } @@ -3254,6 +3530,13 @@ bool TCEToolChain::isPIEDefault() const { return false; } bool TCEToolChain::isPICDefaultForced() const { return false; } +TCELEToolChain::TCELEToolChain(const Driver &D, const llvm::Triple& Triple, + const ArgList &Args) + : TCEToolChain(D, Triple, Args) { +} + +TCELEToolChain::~TCELEToolChain() {} + // CloudABI - CloudABI tool chain which can call ld(1) directly. CloudABI::CloudABI(const Driver &D, const llvm::Triple &Triple, @@ -3264,15 +3547,10 @@ CloudABI::CloudABI(const Driver &D, const llvm::Triple &Triple, getFilePaths().push_back(P.str()); } -void CloudABI::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdlibinc) && - DriverArgs.hasArg(options::OPT_nostdincxx)) - return; - +std::string CloudABI::findLibCxxIncludePath() const { SmallString<128> P(getDriver().Dir); llvm::sys::path::append(P, "..", getTriple().str(), "include/c++/v1"); - addSystemInclude(DriverArgs, CC1Args, P.str()); + return P.str(); } void CloudABI::AddCXXStdlibLibArgs(const ArgList &Args, @@ -3316,29 +3594,14 @@ Haiku::Haiku(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) } -void Haiku::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) - return; - - switch (GetCXXStdlibType(DriverArgs)) { - case ToolChain::CST_Libcxx: - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/system/develop/headers/c++/v1"); - break; - case ToolChain::CST_Libstdcxx: - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/system/develop/headers/c++"); - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/system/develop/headers/c++/backward"); +std::string Haiku::findLibCxxIncludePath() const { + return getDriver().SysRoot + "/system/develop/headers/c++/v1"; +} - StringRef Triple = getTriple().str(); - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/system/develop/headers/c++/" + - Triple); - break; - } +void Haiku::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + addLibStdCXXIncludePaths(getDriver().SysRoot, "/system/develop/headers/c++", + getTriple().str(), "", "", "", DriverArgs, CC1Args); } /// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly. @@ -3374,34 +3637,13 @@ ToolChain::CXXStdlibType Bitrig::GetDefaultCXXStdlibType() const { return ToolChain::CST_Libcxx; } -void Bitrig::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) - return; - - switch (GetCXXStdlibType(DriverArgs)) { - case ToolChain::CST_Libcxx: - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/v1"); - break; - case ToolChain::CST_Libstdcxx: - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/stdc++"); - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/stdc++/backward"); - - StringRef Triple = getTriple().str(); - if (Triple.startswith("amd64")) - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/stdc++/x86_64" + - Triple.substr(5)); - else - addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + - "/usr/include/c++/stdc++/" + - Triple); - break; - } +void Bitrig::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + std::string Triple = getTriple().str(); + if (StringRef(Triple).startswith("amd64")) + Triple = "x86_64" + Triple.substr(5); + addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/c++/stdc++", + Triple, "", "", "", DriverArgs, CC1Args); } void Bitrig::AddCXXStdlibLibArgs(const ArgList &Args, @@ -3440,24 +3682,11 @@ ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const { return ToolChain::CST_Libstdcxx; } -void FreeBSD::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) - return; - - switch (GetCXXStdlibType(DriverArgs)) { - case ToolChain::CST_Libcxx: - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/v1"); - break; - case ToolChain::CST_Libstdcxx: - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/4.2"); - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/4.2/backward"); - break; - } +void FreeBSD::addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/c++/4.2", "", "", + "", "", DriverArgs, CC1Args); } void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args, @@ -3583,6 +3812,7 @@ ToolChain::CXXStdlibType NetBSD::GetDefaultCXXStdlibType() const { if (Major >= 7 || Major == 0) { switch (getArch()) { case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: @@ -3602,24 +3832,14 @@ ToolChain::CXXStdlibType NetBSD::GetDefaultCXXStdlibType() const { return ToolChain::CST_Libstdcxx; } -void NetBSD::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) - return; +std::string NetBSD::findLibCxxIncludePath() const { + return getDriver().SysRoot + "/usr/include/c++/"; +} - switch (GetCXXStdlibType(DriverArgs)) { - case ToolChain::CST_Libcxx: - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/"); - break; - case ToolChain::CST_Libstdcxx: - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/g++"); - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/g++/backward"); - break; - } +void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/g++", "", "", "", + "", DriverArgs, CC1Args); } /// Minix - Minix tool chain which can call as(1) and ld(1) directly. @@ -3692,6 +3912,9 @@ void Solaris::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, // Include the support directory for things like xlocale and fudged system // headers. + // FIXME: This is a weird mix of libc++ and libstdc++. We should also be + // checking the value of -stdlib= here and adding the includes for libc++ + // rather than libstdc++ if it's requested. addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/v1/support/solaris"); if (GCCInstallation.isValid()) { @@ -3709,137 +3932,6 @@ void Solaris::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, } } -/// Distribution (very bare-bones at the moment). - -enum Distro { - // NB: Releases of a particular Linux distro should be kept together - // in this enum, because some tests are done by integer comparison against - // the first and last known member in the family, e.g. IsRedHat(). - ArchLinux, - DebianLenny, - DebianSqueeze, - DebianWheezy, - DebianJessie, - DebianStretch, - Exherbo, - RHEL5, - RHEL6, - RHEL7, - Fedora, - OpenSUSE, - UbuntuHardy, - UbuntuIntrepid, - UbuntuJaunty, - UbuntuKarmic, - UbuntuLucid, - UbuntuMaverick, - UbuntuNatty, - UbuntuOneiric, - UbuntuPrecise, - UbuntuQuantal, - UbuntuRaring, - UbuntuSaucy, - UbuntuTrusty, - UbuntuUtopic, - UbuntuVivid, - UbuntuWily, - UbuntuXenial, - UnknownDistro -}; - -static bool IsRedhat(enum Distro Distro) { - return Distro == Fedora || (Distro >= RHEL5 && Distro <= RHEL7); -} - -static bool IsOpenSUSE(enum Distro Distro) { return Distro == OpenSUSE; } - -static bool IsDebian(enum Distro Distro) { - return Distro >= DebianLenny && Distro <= DebianStretch; -} - -static bool IsUbuntu(enum Distro Distro) { - return Distro >= UbuntuHardy && Distro <= UbuntuXenial; -} - -static Distro DetectDistro(const Driver &D, llvm::Triple::ArchType Arch) { - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = - llvm::MemoryBuffer::getFile("/etc/lsb-release"); - if (File) { - StringRef Data = File.get()->getBuffer(); - SmallVector<StringRef, 16> Lines; - Data.split(Lines, "\n"); - Distro Version = UnknownDistro; - for (StringRef Line : Lines) - if (Version == UnknownDistro && Line.startswith("DISTRIB_CODENAME=")) - Version = llvm::StringSwitch<Distro>(Line.substr(17)) - .Case("hardy", UbuntuHardy) - .Case("intrepid", UbuntuIntrepid) - .Case("jaunty", UbuntuJaunty) - .Case("karmic", UbuntuKarmic) - .Case("lucid", UbuntuLucid) - .Case("maverick", UbuntuMaverick) - .Case("natty", UbuntuNatty) - .Case("oneiric", UbuntuOneiric) - .Case("precise", UbuntuPrecise) - .Case("quantal", UbuntuQuantal) - .Case("raring", UbuntuRaring) - .Case("saucy", UbuntuSaucy) - .Case("trusty", UbuntuTrusty) - .Case("utopic", UbuntuUtopic) - .Case("vivid", UbuntuVivid) - .Case("wily", UbuntuWily) - .Case("xenial", UbuntuXenial) - .Default(UnknownDistro); - if (Version != UnknownDistro) - return Version; - } - - File = llvm::MemoryBuffer::getFile("/etc/redhat-release"); - if (File) { - StringRef Data = File.get()->getBuffer(); - if (Data.startswith("Fedora release")) - return Fedora; - if (Data.startswith("Red Hat Enterprise Linux") || - Data.startswith("CentOS") || - Data.startswith("Scientific Linux")) { - if (Data.find("release 7") != StringRef::npos) - return RHEL7; - else if (Data.find("release 6") != StringRef::npos) - return RHEL6; - else if (Data.find("release 5") != StringRef::npos) - return RHEL5; - } - return UnknownDistro; - } - - File = llvm::MemoryBuffer::getFile("/etc/debian_version"); - if (File) { - StringRef Data = File.get()->getBuffer(); - if (Data[0] == '5') - return DebianLenny; - else if (Data.startswith("squeeze/sid") || Data[0] == '6') - return DebianSqueeze; - else if (Data.startswith("wheezy/sid") || Data[0] == '7') - return DebianWheezy; - else if (Data.startswith("jessie/sid") || Data[0] == '8') - return DebianJessie; - else if (Data.startswith("stretch/sid") || Data[0] == '9') - return DebianStretch; - return UnknownDistro; - } - - if (D.getVFS().exists("/etc/SuSE-release")) - return OpenSUSE; - - if (D.getVFS().exists("/etc/exherbo-release")) - return Exherbo; - - if (D.getVFS().exists("/etc/arch-release")) - return ArchLinux; - - return UnknownDistro; -} - /// \brief Get our best guess at the multiarch triple for a target. /// /// Debian-based systems are starting to use a multiarch setup where they use @@ -3952,6 +4044,15 @@ static std::string getMultiarchTriple(const Driver &D, static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { if (isMipsArch(Triple.getArch())) { + if (Triple.isAndroid()) { + StringRef CPUName; + StringRef ABIName; + tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); + if (CPUName == "mips32r6") + return "libr6"; + if (CPUName == "mips32r2") + return "libr2"; + } // lib32 directory has a special meaning on MIPS targets. // It contains N32 ABI binaries. Use this folder if produce // code for N32 ABI only. @@ -3992,7 +4093,6 @@ static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); - CudaInstallation.init(Triple, Args); Multilibs = GCCInstallation.getMultilibs(); llvm::Triple::ArchType Arch = Triple.getArch(); std::string SysRoot = computeSysRoot(); @@ -4010,9 +4110,9 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) GCCInstallation.getTriple().str() + "/bin") .str()); - Distro Distro = DetectDistro(D, Arch); + Distro Distro(D.getVFS()); - if (IsOpenSUSE(Distro) || IsUbuntu(Distro)) { + if (Distro.IsOpenSUSE() || Distro.IsUbuntu()) { ExtraOpts.push_back("-z"); ExtraOpts.push_back("relro"); } @@ -4032,23 +4132,23 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // ABI requires a mapping between the GOT and the symbol table. // Android loader does not support .gnu.hash. if (!IsMips && !IsAndroid) { - if (IsRedhat(Distro) || IsOpenSUSE(Distro) || - (IsUbuntu(Distro) && Distro >= UbuntuMaverick)) + if (Distro.IsRedhat() || Distro.IsOpenSUSE() || + (Distro.IsUbuntu() && Distro >= Distro::UbuntuMaverick)) ExtraOpts.push_back("--hash-style=gnu"); - if (IsDebian(Distro) || IsOpenSUSE(Distro) || Distro == UbuntuLucid || - Distro == UbuntuJaunty || Distro == UbuntuKarmic) + if (Distro.IsDebian() || Distro.IsOpenSUSE() || Distro == Distro::UbuntuLucid || + Distro == Distro::UbuntuJaunty || Distro == Distro::UbuntuKarmic) ExtraOpts.push_back("--hash-style=both"); } - if (IsRedhat(Distro) && Distro != RHEL5 && Distro != RHEL6) + if (Distro.IsRedhat() && Distro != Distro::RHEL5 && Distro != Distro::RHEL6) ExtraOpts.push_back("--no-add-needed"); #ifdef ENABLE_LINKER_BUILD_ID ExtraOpts.push_back("--build-id"); #endif - if (IsOpenSUSE(Distro)) + if (Distro.IsOpenSUSE()) ExtraOpts.push_back("--enable-new-dtags"); // The selection of paths to try here is designed to match the patterns which @@ -4214,23 +4314,32 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { const llvm::Triple::ArchType Arch = getArch(); const llvm::Triple &Triple = getTriple(); - const enum Distro Distro = DetectDistro(getDriver(), Arch); + const Distro Distro(getDriver().getVFS()); if (Triple.isAndroid()) return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker"; - else if (Triple.isMusl()) { + + if (Triple.isMusl()) { std::string ArchName; + bool IsArm = false; + switch (Arch) { + case llvm::Triple::arm: case llvm::Triple::thumb: ArchName = "arm"; + IsArm = true; break; + case llvm::Triple::armeb: case llvm::Triple::thumbeb: ArchName = "armeb"; + IsArm = true; break; default: ArchName = Triple.getArchName().str(); } - if (Triple.getEnvironment() == llvm::Triple::MuslEABIHF) + if (IsArm && + (Triple.getEnvironment() == llvm::Triple::MuslEABIHF || + tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard)) ArchName += "hf"; return "/lib/ld-musl-" + ArchName + ".so.1"; @@ -4323,8 +4432,8 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { } } - if (Distro == Exherbo && (Triple.getVendor() == llvm::Triple::UnknownVendor || - Triple.getVendor() == llvm::Triple::PC)) + if (Distro == Distro::Exherbo && (Triple.getVendor() == llvm::Triple::UnknownVendor || + Triple.getVendor() == llvm::Triple::PC)) return "/usr/" + Triple.str() + "/lib/" + Loader; return "/" + LibDir + "/" + Loader; } @@ -4517,33 +4626,27 @@ static std::string DetectLibcxxIncludePath(StringRef base) { return MaxVersion ? (base + "/" + MaxVersionString).str() : ""; } -void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) - return; - - // Check if libc++ has been enabled and provide its include paths if so. - if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) { - const std::string LibCXXIncludePathCandidates[] = { - DetectLibcxxIncludePath(getDriver().Dir + "/../include/c++"), - // If this is a development, non-installed, clang, libcxx will - // not be found at ../include/c++ but it likely to be found at - // one of the following two locations: - DetectLibcxxIncludePath(getDriver().SysRoot + "/usr/local/include/c++"), - DetectLibcxxIncludePath(getDriver().SysRoot + "/usr/include/c++") }; - for (const auto &IncludePath : LibCXXIncludePathCandidates) { - if (IncludePath.empty() || !getVFS().exists(IncludePath)) - continue; - // Add the first candidate that exists. - addSystemInclude(DriverArgs, CC1Args, IncludePath); - break; - } - return; +std::string Linux::findLibCxxIncludePath() const { + const std::string LibCXXIncludePathCandidates[] = { + DetectLibcxxIncludePath(getDriver().Dir + "/../include/c++"), + // If this is a development, non-installed, clang, libcxx will + // not be found at ../include/c++ but it likely to be found at + // one of the following two locations: + DetectLibcxxIncludePath(getDriver().SysRoot + "/usr/local/include/c++"), + DetectLibcxxIncludePath(getDriver().SysRoot + "/usr/include/c++") }; + for (const auto &IncludePath : LibCXXIncludePathCandidates) { + if (IncludePath.empty() || !getVFS().exists(IncludePath)) + continue; + // Use the first candidate that exists. + return IncludePath; } + return ""; +} +void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { // We need a detected GCC installation on Linux to provide libstdc++'s - // headers. We handled the libc++ case above. + // headers. if (!GCCInstallation.isValid()) return; @@ -4594,17 +4697,7 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, void Linux::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nocudainc)) - return; - - if (!CudaInstallation.isValid()) { - getDriver().Diag(diag::err_drv_no_cuda_installation); - return; - } - - addSystemInclude(DriverArgs, CC1Args, CudaInstallation.getIncludePath()); - CC1Args.push_back("-include"); - CC1Args.push_back("__clang_cuda_runtime_wrapper.h"); + CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); } void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs, @@ -4641,7 +4734,7 @@ SanitizerMask Linux::getSupportedSanitizers() const { Res |= SanitizerKind::Thread; if (IsX86_64 || IsMIPS64 || IsPowerPC64 || IsAArch64) Res |= SanitizerKind::Memory; - if (IsX86_64) + if (IsX86_64 || IsMIPS64) Res |= SanitizerKind::Efficiency; if (IsX86 || IsX86_64) { Res |= SanitizerKind::Function; @@ -4661,6 +4754,99 @@ void Linux::addProfileRTLibs(const llvm::opt::ArgList &Args, ToolChain::addProfileRTLibs(Args, CmdArgs); } +/// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly. + +Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + + getFilePaths().push_back(D.SysRoot + "/lib"); + getFilePaths().push_back(D.ResourceDir + "/lib/fuchsia"); +} + +Tool *Fuchsia::buildAssembler() const { + return new tools::gnutools::Assembler(*this); +} + +Tool *Fuchsia::buildLinker() const { + return new tools::fuchsia::Linker(*this); +} + +ToolChain::RuntimeLibType Fuchsia::GetRuntimeLibType( + const ArgList &Args) const { + if (Arg *A = Args.getLastArg(options::OPT_rtlib_EQ)) { + StringRef Value = A->getValue(); + if (Value != "compiler-rt") + getDriver().Diag(diag::err_drv_invalid_rtlib_name) + << A->getAsString(Args); + } + + return ToolChain::RLT_CompilerRT; +} + +ToolChain::CXXStdlibType +Fuchsia::GetCXXStdlibType(const ArgList &Args) const { + if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { + StringRef Value = A->getValue(); + if (Value != "libc++") + getDriver().Diag(diag::err_drv_invalid_stdlib_name) + << A->getAsString(Args); + } + + return ToolChain::CST_Libcxx; +} + +void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, true)) + CC1Args.push_back("-fuse-init-array"); +} + +void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include"); + addSystemInclude(DriverArgs, CC1Args, P); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + // Check for configure-time C include directories. + StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (CIncludeDirs != "") { + SmallVector<StringRef, 5> dirs; + CIncludeDirs.split(dirs, ":"); + for (StringRef dir : dirs) { + StringRef Prefix = + llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; + addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); + } + return; + } + + addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include"); +} + +std::string Fuchsia::findLibCxxIncludePath() const { + return getDriver().SysRoot + "/include/c++/v1"; +} + +void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + (void) GetCXXStdlibType(Args); + CmdArgs.push_back("-lc++"); + CmdArgs.push_back("-lc++abi"); + CmdArgs.push_back("-lunwind"); +} + /// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. DragonFly::DragonFly(const Driver &D, const llvm::Triple &Triple, @@ -4690,16 +4876,18 @@ Tool *DragonFly::buildLinker() const { /// together object files from the assembler into a single blob. CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Linux(D, Triple, Args) { + const ToolChain &HostTC, const ArgList &Args) + : ToolChain(D, Triple, Args), HostTC(HostTC), + CudaInstallation(D, HostTC.getTriple(), Args) { if (CudaInstallation.isValid()) getProgramPaths().push_back(CudaInstallation.getBinPath()); } -void -CudaToolChain::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - Linux::addClangTargetOptions(DriverArgs, CC1Args); +void CudaToolChain::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + HostTC.addClangTargetOptions(DriverArgs, CC1Args); + CC1Args.push_back("-fcuda-is-device"); if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, @@ -4713,18 +4901,23 @@ CudaToolChain::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, if (DriverArgs.hasArg(options::OPT_nocudalib)) return; - std::string LibDeviceFile = CudaInstallation.getLibDeviceFile( - DriverArgs.getLastArgValue(options::OPT_march_EQ)); - if (!LibDeviceFile.empty()) { - CC1Args.push_back("-mlink-cuda-bitcode"); - CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile)); - - // Libdevice in CUDA-7.0 requires PTX version that's more recent - // than LLVM defaults to. Use PTX4.2 which is the PTX version that - // came with CUDA-7.0. - CC1Args.push_back("-target-feature"); - CC1Args.push_back("+ptx42"); + StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ); + assert(!GpuArch.empty() && "Must have an explicit GPU arch."); + std::string LibDeviceFile = CudaInstallation.getLibDeviceFile(GpuArch); + + if (LibDeviceFile.empty()) { + getDriver().Diag(diag::err_drv_no_cuda_libdevice) << GpuArch; + return; } + + CC1Args.push_back("-mlink-cuda-bitcode"); + CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile)); + + // Libdevice in CUDA-7.0 requires PTX version that's more recent + // than LLVM defaults to. Use PTX4.2 which is the PTX version that + // came with CUDA-7.0. + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+ptx42"); } void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, @@ -4736,19 +4929,24 @@ void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, assert(!Arch.empty() && "Must have an explicit GPU arch."); CudaInstallation.CheckCudaVersionSupportsArch(StringToCudaArch(Arch)); } - Linux::AddCudaIncludeArgs(DriverArgs, CC1Args); + CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); } llvm::opt::DerivedArgList * CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, - const char *BoundArch) const { - DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); + StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const { + DerivedArgList *DAL = + HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind); + if (!DAL) + DAL = new DerivedArgList(Args.getBaseArgs()); + const OptTable &Opts = getDriver().getOpts(); for (Arg *A : Args) { if (A->getOption().matches(options::OPT_Xarch__)) { // Skip this argument unless the architecture matches BoundArch - if (!BoundArch || A->getValue(0) != StringRef(BoundArch)) + if (BoundArch.empty() || A->getValue(0) != BoundArch) continue; unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); @@ -4779,7 +4977,7 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, DAL->append(A); } - if (BoundArch) { + if (!BoundArch.empty()) { DAL->eraseArg(options::OPT_march_EQ); DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch); } @@ -4794,6 +4992,48 @@ Tool *CudaToolChain::buildLinker() const { return new tools::NVPTX::Linker(*this); } +void CudaToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { + HostTC.addClangWarningOptions(CC1Args); +} + +ToolChain::CXXStdlibType +CudaToolChain::GetCXXStdlibType(const ArgList &Args) const { + return HostTC.GetCXXStdlibType(Args); +} + +void CudaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); +} + +void CudaToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args, + ArgStringList &CC1Args) const { + HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args); +} + +void CudaToolChain::AddIAMCUIncludeArgs(const ArgList &Args, + ArgStringList &CC1Args) const { + HostTC.AddIAMCUIncludeArgs(Args, CC1Args); +} + +SanitizerMask CudaToolChain::getSupportedSanitizers() const { + // The CudaToolChain only supports sanitizers in the sense that it allows + // sanitizer arguments on the command line if they are supported by the host + // toolchain. The CudaToolChain will actually ignore any command line + // arguments for any of these "supported" sanitizers. That means that no + // sanitization of device code is actually supported at this time. + // + // This behavior is necessary because the host and device toolchains + // invocations often share the command line, so the device toolchain must + // tolerate flags meant only for the host toolchain. + return HostTC.getSupportedSanitizers(); +} + +VersionTuple CudaToolChain::computeMSVCVersion(const Driver *D, + const ArgList &Args) const { + return HostTC.computeMSVCVersion(D, Args); +} + /// XCore tool chain XCoreToolChain::XCoreToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) @@ -4878,24 +5118,13 @@ MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple, } if (GCCInstallation.isValid()) { - // The contents of LibDir are independent of the version of gcc. - // This contains libc, libg (a superset of libc), libm, libstdc++, libssp. - SmallString<128> LibDir(GCCInstallation.getParentLibPath()); - if (Triple.getArch() == llvm::Triple::sparcel) - llvm::sys::path::append(LibDir, "../sparc-myriad-elf/lib/le"); - else - llvm::sys::path::append(LibDir, "../sparc-myriad-elf/lib"); - addPathIfExists(D, LibDir, getFilePaths()); - // This directory contains crt{i,n,begin,end}.o as well as libgcc. // These files are tied to a particular version of gcc. SmallString<128> CompilerSupportDir(GCCInstallation.getInstallPath()); - // There are actually 4 choices: {le,be} x {fpu,nofpu} - // but as this toolchain is for LEON sparc, it can assume FPU. - if (Triple.getArch() == llvm::Triple::sparcel) - llvm::sys::path::append(CompilerSupportDir, "le"); addPathIfExists(D, CompilerSupportDir, getFilePaths()); } + // libstd++ and libc++ must both be found in this one place. + addPathIfExists(D, D.Dir + "/../sparc-myriad-elf/lib", getFilePaths()); } MyriadToolChain::~MyriadToolChain() {} @@ -4906,18 +5135,18 @@ void MyriadToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include"); } -void MyriadToolChain::AddClangCXXStdlibIncludeArgs( - const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) - return; +std::string MyriadToolChain::findLibCxxIncludePath() const { + std::string Path(getDriver().getInstalledDir()); + return Path + "/../include/c++/v1"; +} - // Only libstdc++, for now. +void MyriadToolChain::addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { StringRef LibDir = GCCInstallation.getParentLibPath(); const GCCVersion &Version = GCCInstallation.getVersion(); StringRef TripleStr = GCCInstallation.getTriple().str(); const Multilib &Multilib = GCCInstallation.getMultilib(); - addLibStdCXXIncludePaths( LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, "", TripleStr, "", "", Multilib.includeSuffix(), DriverArgs, CC1Args); @@ -4948,6 +5177,10 @@ Tool *MyriadToolChain::buildLinker() const { return new tools::Myriad::Linker(*this); } +SanitizerMask MyriadToolChain::getSupportedSanitizers() const { + return SanitizerKind::Address; +} + WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args) : ToolChain(D, Triple, Args) { @@ -4955,9 +5188,6 @@ WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, assert(Triple.isArch32Bit() != Triple.isArch64Bit()); getFilePaths().push_back( getDriver().SysRoot + "/lib" + (Triple.isArch32Bit() ? "32" : "64")); - - // Use LLD by default. - DefaultLinker = "lld"; } bool WebAssembly::IsMathErrnoDefault() const { return false; } @@ -5005,9 +5235,8 @@ void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs, addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include"); } -void WebAssembly::AddClangCXXStdlibIncludeArgs( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { +void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { if (!DriverArgs.hasArg(options::OPT_nostdlibinc) && !DriverArgs.hasArg(options::OPT_nostdincxx)) addSystemInclude(DriverArgs, CC1Args, @@ -5091,3 +5320,23 @@ SanitizerMask PS4CPU::getSupportedSanitizers() const { Res |= SanitizerKind::Vptr; return Res; } + +Contiki::Contiki(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) + : Generic_ELF(D, Triple, Args) {} + +SanitizerMask Contiki::getSupportedSanitizers() const { + const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + if (IsX86) + Res |= SanitizerKind::SafeStack; + return Res; +} + +/// 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); +} +// End AVR diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains.h index 369712f..3240357 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.h @@ -16,7 +16,6 @@ #include "clang/Driver/Action.h" #include "clang/Driver/Multilib.h" #include "clang/Driver/ToolChain.h" -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallSet.h" #include "llvm/Support/Compiler.h" @@ -25,6 +24,60 @@ namespace clang { namespace driver { + +/// A class to find a viable CUDA installation +class CudaInstallationDetector { +private: + const Driver &D; + bool IsValid = false; + CudaVersion Version = CudaVersion::UNKNOWN; + std::string InstallPath; + std::string BinPath; + std::string LibPath; + std::string LibDevicePath; + std::string IncludePath; + llvm::StringMap<std::string> LibDeviceMap; + + // CUDA architectures for which we have raised an error in + // CheckCudaVersionSupportsArch. + mutable llvm::SmallSet<CudaArch, 4> ArchsWithVersionTooLowErrors; + +public: + CudaInstallationDetector(const Driver &D, const llvm::Triple &HostTriple, + const llvm::opt::ArgList &Args); + + void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + + /// \brief Emit an error if Version does not support the given Arch. + /// + /// If either Version or Arch is unknown, does not emit an error. Emits at + /// most one error per Arch. + void CheckCudaVersionSupportsArch(CudaArch Arch) const; + + /// \brief Check whether we detected a valid Cuda install. + bool isValid() const { return IsValid; } + /// \brief Print information about the detected CUDA installation. + void print(raw_ostream &OS) const; + + /// \brief Get the detected Cuda install's version. + CudaVersion version() const { return Version; } + /// \brief Get the detected Cuda installation path. + StringRef getInstallPath() const { return InstallPath; } + /// \brief Get the detected path to Cuda's bin directory. + StringRef getBinPath() const { return BinPath; } + /// \brief Get the detected Cuda Include path. + StringRef getIncludePath() const { return IncludePath; } + /// \brief Get the detected Cuda library path. + StringRef getLibPath() const { return LibPath; } + /// \brief Get the detected Cuda device library path. + StringRef getLibDevicePath() const { return LibDevicePath; } + /// \brief Get libdevice file for given architecture + std::string getLibDeviceFile(StringRef Gpu) const { + return LibDeviceMap.lookup(Gpu); + } +}; + namespace toolchains { /// Generic_GCC - A tool chain using the 'gcc' command to perform @@ -143,6 +196,11 @@ public: SmallVectorImpl<StringRef> &BiarchLibDirs, SmallVectorImpl<StringRef> &BiarchTripleAliases); + bool ScanGCCForMultilibs(const llvm::Triple &TargetTriple, + const llvm::opt::ArgList &Args, + StringRef Path, + bool NeedsBiarchSuffix = false); + void ScanLibDirForGCCTriple(const llvm::Triple &TargetArch, const llvm::opt::ArgList &Args, const std::string &LibDir, @@ -154,61 +212,15 @@ public: const std::string &LibDir, StringRef CandidateTriple, bool NeedsBiarchSuffix = false); + + bool ScanGentooGccConfig(const llvm::Triple &TargetTriple, + const llvm::opt::ArgList &Args, + StringRef CandidateTriple, + bool NeedsBiarchSuffix = false); }; protected: GCCInstallationDetector GCCInstallation; - - // \brief A class to find a viable CUDA installation - class CudaInstallationDetector { - private: - const Driver &D; - bool IsValid = false; - CudaVersion Version = CudaVersion::UNKNOWN; - std::string InstallPath; - std::string BinPath; - std::string LibPath; - std::string LibDevicePath; - std::string IncludePath; - llvm::StringMap<std::string> LibDeviceMap; - - // CUDA architectures for which we have raised an error in - // CheckCudaVersionSupportsArch. - mutable llvm::SmallSet<CudaArch, 4> ArchsWithVersionTooLowErrors; - - public: - CudaInstallationDetector(const Driver &D) : D(D) {} - void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args); - - /// \brief Emit an error if Version does not support the given Arch. - /// - /// If either Version or Arch is unknown, does not emit an error. Emits at - /// most one error per Arch. - void CheckCudaVersionSupportsArch(CudaArch Arch) const; - - /// \brief Check whether we detected a valid Cuda install. - bool isValid() const { return IsValid; } - /// \brief Print information about the detected CUDA installation. - void print(raw_ostream &OS) const; - - /// \brief Get the deteced Cuda install's version. - CudaVersion version() const { return Version; } - /// \brief Get the detected Cuda installation path. - StringRef getInstallPath() const { return InstallPath; } - /// \brief Get the detected path to Cuda's bin directory. - StringRef getBinPath() const { return BinPath; } - /// \brief Get the detected Cuda Include path. - StringRef getIncludePath() const { return IncludePath; } - /// \brief Get the detected Cuda library path. - StringRef getLibPath() const { return LibPath; } - /// \brief Get the detected Cuda device library path. - StringRef getLibDevicePath() const { return LibDevicePath; } - /// \brief Get libdevice file for given architecture - std::string getLibDeviceFile(StringRef Gpu) const { - return LibDeviceMap.lookup(Gpu); - } - }; - CudaInstallationDetector CudaInstallation; public: @@ -223,6 +235,9 @@ public: bool isPIEDefault() const override; bool isPICDefaultForced() const override; bool IsIntegratedAssemblerDefault() const override; + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; protected: Tool *getTool(Action::ActionClass AC) const override; @@ -238,6 +253,17 @@ protected: /// \brief Check whether the target triple's architecture is 32-bits. bool isTarget32Bit() const { return getTriple().isArch32Bit(); } + // FIXME: This should be final, but the Solaris tool chain does weird + // things we can't easily represent. + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + virtual std::string findLibCxxIncludePath() const; + virtual void + addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, StringRef TargetMultiarchTriple, @@ -313,16 +339,13 @@ public: /// @name ToolChain Implementation /// { - std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, - types::ID InputType) const override; - - types::ID LookupTypeForExtension(const char *Ext) const override; + types::ID LookupTypeForExtension(StringRef Ext) const override; bool HasNativeLLVMSupport() const override; llvm::opt::DerivedArgList * - TranslateArgs(const llvm::opt::DerivedArgList &Args, - const char *BoundArch) const override; + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; bool IsBlocksDefault() const override { // Always allow blocks on Apple; users interested in versioning are @@ -393,6 +416,8 @@ public: /// The OS version we are targeting. mutable VersionTuple TargetVersion; + CudaInstallationDetector CudaInstallation; + private: void AddDeploymentTarget(llvm::opt::DerivedArgList &Args) const; @@ -526,13 +551,16 @@ public: bool isCrossCompiling() const override { return false; } llvm::opt::DerivedArgList * - TranslateArgs(const llvm::opt::DerivedArgList &Args, - const char *BoundArch) const override; + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; CXXStdlibType GetDefaultCXXStdlibType() const override; ObjCRuntime getDefaultObjCRuntime(bool isNonFragile) const override; bool hasBlocksRuntime() const override; + void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + bool UseObjCMixedDispatch() const override { // This is only used with the non-fragile ABI and non-legacy dispatch. @@ -562,6 +590,8 @@ public: bool SupportsEmbeddedBitcode() const override; SanitizerMask getSupportedSanitizers() const override; + + void printVerboseInfo(raw_ostream &OS) const override; }; /// DarwinClang - The Darwin toolchain used by Clang. @@ -573,6 +603,8 @@ public: /// @name Apple ToolChain Implementation /// { + RuntimeLibType GetRuntimeLibType(const llvm::opt::ArgList &Args) const override; + void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; @@ -587,7 +619,7 @@ public: void AddLinkARCArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; - unsigned GetDefaultDwarfVersion() const override { return 2; } + unsigned GetDefaultDwarfVersion() const override; // Until dtrace (via CTF) and LLDB can deal with distributed debug info, // Darwin defaults to standalone/full debug info. bool GetDefaultStandaloneDebug() const override { return true; } @@ -628,9 +660,7 @@ public: GetCXXStdlibType(const llvm::opt::ArgList &Args) const override { return ToolChain::CST_Libcxx; } - void AddClangCXXStdlibIncludeArgs( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + std::string findLibCxxIncludePath() const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; @@ -679,12 +709,19 @@ public: const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + void printVerboseInfo(raw_ostream &OS) const override; + protected: Tool *getTool(Action::ActionClass AC) const override; Tool *buildLinker() const override; Tool *buildAssembler() const override; private: + CudaInstallationDetector CudaInstallation; + std::string Base; std::string GccLibDir; std::string Ver; @@ -699,11 +736,14 @@ public: Haiku(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); - bool isPIEDefault() const override { return getTriple().getArch() == llvm::Triple::x86_64; } + bool isPIEDefault() const override { + return getTriple().getArch() == llvm::Triple::x86_64; + } - void - AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + std::string findLibCxxIncludePath() const override; + void addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; }; class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF { @@ -734,7 +774,7 @@ public: bool IsObjCNonFragileABIDefault() const override { return true; } CXXStdlibType GetDefaultCXXStdlibType() const override; - void AddClangCXXStdlibIncludeArgs( + void addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, @@ -758,7 +798,7 @@ public: bool IsObjCNonFragileABIDefault() const override { return true; } CXXStdlibType GetDefaultCXXStdlibType() const override; - void AddClangCXXStdlibIncludeArgs( + void addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, @@ -787,9 +827,11 @@ public: CXXStdlibType GetDefaultCXXStdlibType() const override; - void AddClangCXXStdlibIncludeArgs( + std::string findLibCxxIncludePath() const override; + void addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + bool IsUnwindTablesDefault() const override { return true; } protected: @@ -829,7 +871,8 @@ public: void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - void AddClangCXXStdlibIncludeArgs( + std::string findLibCxxIncludePath() const override; + void addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, @@ -851,30 +894,53 @@ protected: Tool *buildLinker() const override; }; -class LLVM_LIBRARY_VISIBILITY CudaToolChain : public Linux { +class LLVM_LIBRARY_VISIBILITY CudaToolChain : public ToolChain { public: CudaToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); + const ToolChain &HostTC, const llvm::opt::ArgList &Args); + + virtual const llvm::Triple *getAuxTriple() const override { + return &HostTC.getTriple(); + } llvm::opt::DerivedArgList * - TranslateArgs(const llvm::opt::DerivedArgList &Args, - const char *BoundArch) const override; + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; // Never try to use the integrated assembler with CUDA; always fork out to // ptxas. bool useIntegratedAs() const override { return false; } + bool isCrossCompiling() const override { return true; } + bool isPICDefault() const override { return false; } + bool isPIEDefault() const override { return false; } + bool isPICDefaultForced() const override { return false; } + bool SupportsProfiling() const override { return false; } + bool SupportsObjCGC() const override { return false; } void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - const Generic_GCC::CudaInstallationDetector &cudaInstallation() const { - return CudaInstallation; - } - Generic_GCC::CudaInstallationDetector &cudaInstallation() { - return CudaInstallation; - } + void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override; + CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CC1Args) const override; + void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + SanitizerMask getSupportedSanitizers() const override; + + VersionTuple + computeMSVCVersion(const Driver *D, + const llvm::opt::ArgList &Args) const override; + + const ToolChain &HostTC; + CudaInstallationDetector CudaInstallation; protected: Tool *buildAssembler() const override; // ptxas @@ -895,9 +961,7 @@ public: CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; - void AddClangCXXStdlibIncludeArgs( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + std::string findLibCxxIncludePath() const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; @@ -912,6 +976,10 @@ public: : RuntimeLibType::RLT_CompilerRT; } + const char *getDefaultLinker() const override { + return "lld"; + } + private: Multilib SelectedMultilib; std::string LibSuffix; @@ -922,6 +990,13 @@ public: LanaiToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args) : Generic_ELF(D, Triple, Args) {} + + // No support for finding a C++ standard library yet. + std::string findLibCxxIncludePath() const override { return ""; } + void addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override {} + bool IsIntegratedAssemblerDefault() const override { return true; } }; @@ -939,7 +1014,7 @@ public: void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - void AddClangCXXStdlibIncludeArgs( + void addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; @@ -981,9 +1056,7 @@ public: void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - void AddClangCXXStdlibIncludeArgs( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + std::string findLibCxxIncludePath() const override; CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; @@ -1010,6 +1083,41 @@ private: std::string NaClArmMacrosPath; }; +class LLVM_LIBRARY_VISIBILITY Fuchsia : public Generic_ELF { +public: + Fuchsia(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool isPIEDefault() const override { return true; } + bool HasNativeLLVMSupport() const override { return true; } + bool IsIntegratedAssemblerDefault() const override { return true; } + llvm::DebuggerKind getDefaultDebuggerTuning() const override { + return llvm::DebuggerKind::GDB; + } + + RuntimeLibType + GetRuntimeLibType(const llvm::opt::ArgList &Args) const override; + CXXStdlibType + GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + std::string findLibCxxIncludePath() const override; + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + const char *getDefaultLinker() const override { + return "lld"; + } + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + /// TCEToolChain - A tool chain using the llvm bitcode tools to perform /// all subcommands. See http://tce.cs.tut.fi for our peculiar target. class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain { @@ -1024,14 +1132,22 @@ public: bool isPICDefaultForced() const override; }; +/// Toolchain for little endian TCE cores. +class LLVM_LIBRARY_VISIBILITY TCELEToolChain : public TCEToolChain { +public: + TCELEToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + ~TCELEToolChain() override; +}; + class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain { public: MSVCToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); llvm::opt::DerivedArgList * - TranslateArgs(const llvm::opt::DerivedArgList &Args, - const char *BoundArch) const override; + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; bool IsIntegratedAssemblerDefault() const override; bool IsUnwindTablesDefault() const override; @@ -1046,6 +1162,9 @@ public: const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + bool getWindowsSDKDir(std::string &path, int &major, std::string &windowsSDKIncludeVersion, std::string &windowsSDKLibVersion) const; @@ -1057,12 +1176,16 @@ public: bool getVisualStudioInstallDir(std::string &path) const; bool getVisualStudioBinariesFolder(const char *clangProgramPath, std::string &path) const; - VersionTuple getMSVCVersionFromExe() const override; + VersionTuple + computeMSVCVersion(const Driver *D, + const llvm::opt::ArgList &Args) const override; std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, types::ID InputType) const override; SanitizerMask getSupportedSanitizers() const override; + void printVerboseInfo(raw_ostream &OS) const override; + protected: void AddSystemIncludeWithSubfolder(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, @@ -1073,6 +1196,11 @@ protected: Tool *buildLinker() const override; Tool *buildAssembler() const override; +private: + VersionTuple getMSVCVersionFromTriple() const; + VersionTuple getMSVCVersionFromExe() const; + + CudaInstallationDetector CudaInstallation; }; class LLVM_LIBRARY_VISIBILITY CrossWindowsToolChain : public Generic_GCC { @@ -1144,11 +1272,13 @@ public: void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - void AddClangCXXStdlibIncludeArgs( + std::string findLibCxxIncludePath() const override; + void addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; Tool *SelectTool(const JobAction &JA) const override; unsigned GetDefaultDwarfVersion() const override { return 2; } + SanitizerMask getSupportedSanitizers() const override; protected: Tool *buildLinker() const override; @@ -1189,6 +1319,10 @@ private: const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + const char *getDefaultLinker() const override { + return "lld"; + } + Tool *buildLinker() const override; }; @@ -1197,6 +1331,12 @@ public: PS4CPU(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); + // No support for finding a C++ standard library yet. + std::string findLibCxxIncludePath() const override { return ""; } + void addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override {} + bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } bool HasNativeLLVMSupport() const override; @@ -1217,6 +1357,30 @@ protected: Tool *buildLinker() const override; }; +class LLVM_LIBRARY_VISIBILITY Contiki : public Generic_ELF { +public: + Contiki(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + // No support for finding a C++ standard library yet. + std::string findLibCxxIncludePath() const override { return ""; } + void addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override {} + + SanitizerMask getSupportedSanitizers() const override; +}; + +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); + bool IsIntegratedAssemblerDefault() const override { return true; } +}; + + } // end namespace toolchains } // end namespace driver } // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp index 1b3229a..3c3d453 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp @@ -40,8 +40,9 @@ #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/TargetParser.h" +#include "llvm/Support/YAMLParser.h" #ifdef LLVM_ON_UNIX #include <unistd.h> // For getuid(). @@ -53,7 +54,7 @@ using namespace clang; using namespace llvm::opt; static void handleTargetFeaturesGroup(const ArgList &Args, - std::vector<const char *> &Features, + std::vector<StringRef> &Features, OptSpecifier Group) { for (const Arg *A : Args.filtered(Group)) { StringRef Name = A->getOption().getName(); @@ -108,8 +109,6 @@ static const char *getSparcAsmModeForCPU(StringRef Name, } } -/// CheckPreprocessingOptions - Perform some validation of preprocessing -/// arguments that is shared with gcc. static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_C, options::OPT_CC)) { if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_P) && @@ -121,8 +120,6 @@ static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { } } -/// CheckCodeGenerationOptions - Perform some validation of code generation -/// arguments that is shared with gcc. static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) { // In gcc, only ARM checks this, but it seems reasonable to check universally. if (Args.hasArg(options::OPT_static)) @@ -233,7 +230,8 @@ static void addDirectoryList(const ArgList &Args, ArgStringList &CmdArgs, } static void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, - const ArgList &Args, ArgStringList &CmdArgs) { + const ArgList &Args, ArgStringList &CmdArgs, + const JobAction &JA) { const Driver &D = TC.getDriver(); // Add extra linker input arguments which are not treated as inputs @@ -241,6 +239,14 @@ static void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input); for (const auto &II : Inputs) { + // If the current tool chain refers to an OpenMP offloading host, we should + // ignore inputs that refer to OpenMP offloading devices - they will be + // embedded according to a proper linker script. + if (auto *IA = II.getAction()) + if (JA.isHostOffloading(Action::OFK_OpenMP) && + IA->isDeviceOffloading(Action::OFK_OpenMP)) + continue; + if (!TC.HasNativeLLVMSupport() && types::isLLVMIR(II.getType())) // Don't try to pass LLVM inputs unless we have native support. D.Diag(diag::err_drv_no_linker_llvm_support) << TC.getTripleString(); @@ -274,6 +280,131 @@ static void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH"); } +/// Add OpenMP linker script arguments at the end of the argument list so that +/// the fat binary is built by embedding each of the device images into the +/// host. The linker script also defines a few symbols required by the code +/// generation so that the images can be easily retrieved at runtime by the +/// offloading library. This should be used only in tool chains that support +/// linker scripts. +static void AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, ArgStringList &CmdArgs, + const JobAction &JA) { + + // If this is not an OpenMP host toolchain, we don't need to do anything. + if (!JA.isHostOffloading(Action::OFK_OpenMP)) + return; + + // Create temporary linker script. Keep it if save-temps is enabled. + const char *LKS; + SmallString<256> Name = llvm::sys::path::filename(Output.getFilename()); + if (C.getDriver().isSaveTempsEnabled()) { + llvm::sys::path::replace_extension(Name, "lk"); + LKS = C.getArgs().MakeArgString(Name.c_str()); + } else { + llvm::sys::path::replace_extension(Name, ""); + Name = C.getDriver().GetTemporaryPath(Name, "lk"); + LKS = C.addTempFile(C.getArgs().MakeArgString(Name.c_str())); + } + + // Add linker script option to the command. + CmdArgs.push_back("-T"); + CmdArgs.push_back(LKS); + + // Create a buffer to write the contents of the linker script. + std::string LksBuffer; + llvm::raw_string_ostream LksStream(LksBuffer); + + // Get the OpenMP offload tool chains so that we can extract the triple + // associated with each device input. + auto OpenMPToolChains = C.getOffloadToolChains<Action::OFK_OpenMP>(); + assert(OpenMPToolChains.first != OpenMPToolChains.second && + "No OpenMP toolchains??"); + + // Track the input file name and device triple in order to build the script, + // inserting binaries in the designated sections. + SmallVector<std::pair<std::string, const char *>, 8> InputBinaryInfo; + + // Add commands to embed target binaries. We ensure that each section and + // image is 16-byte aligned. This is not mandatory, but increases the + // likelihood of data to be aligned with a cache block in several main host + // machines. + LksStream << "/*\n"; + LksStream << " OpenMP Offload Linker Script\n"; + LksStream << " *** Automatically generated by Clang ***\n"; + LksStream << "*/\n"; + LksStream << "TARGET(binary)\n"; + auto DTC = OpenMPToolChains.first; + for (auto &II : Inputs) { + const Action *A = II.getAction(); + // Is this a device linking action? + if (A && isa<LinkJobAction>(A) && + A->isDeviceOffloading(Action::OFK_OpenMP)) { + assert(DTC != OpenMPToolChains.second && + "More device inputs than device toolchains??"); + InputBinaryInfo.push_back(std::make_pair( + DTC->second->getTriple().normalize(), II.getFilename())); + ++DTC; + LksStream << "INPUT(" << II.getFilename() << ")\n"; + } + } + + assert(DTC == OpenMPToolChains.second && + "Less device inputs than device toolchains??"); + + LksStream << "SECTIONS\n"; + LksStream << "{\n"; + LksStream << " .omp_offloading :\n"; + LksStream << " ALIGN(0x10)\n"; + LksStream << " {\n"; + + for (auto &BI : InputBinaryInfo) { + LksStream << " . = ALIGN(0x10);\n"; + LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_start." << BI.first + << " = .);\n"; + LksStream << " " << BI.second << "\n"; + LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_end." << BI.first + << " = .);\n"; + } + + LksStream << " }\n"; + // Add commands to define host entries begin and end. We use 1-byte subalign + // so that the linker does not add any padding and the elements in this + // section form an array. + LksStream << " .omp_offloading.entries :\n"; + LksStream << " ALIGN(0x10)\n"; + LksStream << " SUBALIGN(0x01)\n"; + LksStream << " {\n"; + LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_begin = .);\n"; + LksStream << " *(.omp_offloading.entries)\n"; + LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_end = .);\n"; + LksStream << " }\n"; + LksStream << "}\n"; + LksStream << "INSERT BEFORE .data\n"; + LksStream.flush(); + + // Dump the contents of the linker script if the user requested that. We + // support this option to enable testing of behavior with -###. + if (C.getArgs().hasArg(options::OPT_fopenmp_dump_offload_linker_script)) + llvm::errs() << LksBuffer; + + // If this is a dry run, do not create the linker script file. + if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) + return; + + // Open script file and write the contents. + std::error_code EC; + llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::F_None); + + if (EC) { + C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); + return; + } + + Lksf << LksBuffer; +} + /// \brief Determine whether Objective-C automated reference counting is /// enabled. static bool isObjCAutoRefCount(const ArgList &Args) { @@ -296,38 +427,25 @@ static bool forwardToGCC(const Option &O) { !O.hasFlag(options::DriverOption) && !O.hasFlag(options::LinkerInput); } -/// Add the C++ include args of other offloading toolchains. If this is a host -/// job, the device toolchains are added. If this is a device job, the host -/// toolchains will be added. -static void addExtraOffloadCXXStdlibIncludeArgs(Compilation &C, - const JobAction &JA, - const ArgList &Args, - ArgStringList &CmdArgs) { - - if (JA.isHostOffloading(Action::OFK_Cuda)) - C.getSingleOffloadToolChain<Action::OFK_Cuda>() - ->AddClangCXXStdlibIncludeArgs(Args, CmdArgs); - else if (JA.isDeviceOffloading(Action::OFK_Cuda)) - C.getSingleOffloadToolChain<Action::OFK_Host>() - ->AddClangCXXStdlibIncludeArgs(Args, CmdArgs); - - // TODO: Add support for other programming models here. -} - -/// Add the include args that are specific of each offloading programming model. -static void addExtraOffloadSpecificIncludeArgs(Compilation &C, - const JobAction &JA, - const ArgList &Args, - ArgStringList &CmdArgs) { - +/// Apply \a Work on the current tool chain \a RegularToolChain and any other +/// offloading tool chain that is associated with the current action \a JA. +static void +forAllAssociatedToolChains(Compilation &C, const JobAction &JA, + const ToolChain &RegularToolChain, + llvm::function_ref<void(const ToolChain &)> Work) { + // Apply Work on the current/regular tool chain. + Work(RegularToolChain); + + // Apply Work on all the offloading tool chains associated with the current + // action. if (JA.isHostOffloading(Action::OFK_Cuda)) - C.getSingleOffloadToolChain<Action::OFK_Host>()->AddCudaIncludeArgs( - Args, CmdArgs); + Work(*C.getSingleOffloadToolChain<Action::OFK_Cuda>()); else if (JA.isDeviceOffloading(Action::OFK_Cuda)) - C.getSingleOffloadToolChain<Action::OFK_Cuda>()->AddCudaIncludeArgs( - Args, CmdArgs); + Work(*C.getSingleOffloadToolChain<Action::OFK_Host>()); - // TODO: Add support for other programming models here. + // + // TODO: Add support for other offloading programming models here. + // } void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, @@ -423,6 +541,13 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, } } + // Add offload include arguments specific for CUDA. This must happen before + // we -I or -include anything else, because we must pick up the CUDA headers + // from the particular CUDA installation, rather than from e.g. + // /usr/local/include. + if (JA.isOffloading(Action::OFK_Cuda)) + getToolChain().AddCudaIncludeArgs(Args, CmdArgs); + // Add -i* options, and automatically translate to // -include-pch/-include-pth for transparent PCH support. It's // wonky, but we include looking for .gch so we can support seamless @@ -604,22 +729,22 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, // of an offloading programming model. // Add C++ include arguments, if needed. - if (types::isCXX(Inputs[0].getType())) { - getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs); - addExtraOffloadCXXStdlibIncludeArgs(C, JA, Args, CmdArgs); - } + if (types::isCXX(Inputs[0].getType())) + forAllAssociatedToolChains(C, JA, getToolChain(), + [&Args, &CmdArgs](const ToolChain &TC) { + TC.AddClangCXXStdlibIncludeArgs(Args, CmdArgs); + }); // Add system include arguments for all targets but IAMCU. - if (!IsIAMCU) { - getToolChain().AddClangSystemIncludeArgs(Args, CmdArgs); - addExtraOffloadCXXStdlibIncludeArgs(C, JA, Args, CmdArgs); - } else { + if (!IsIAMCU) + forAllAssociatedToolChains(C, JA, getToolChain(), + [&Args, &CmdArgs](const ToolChain &TC) { + TC.AddClangSystemIncludeArgs(Args, CmdArgs); + }); + else { // For IAMCU add special include arguments. getToolChain().AddIAMCUIncludeArgs(Args, CmdArgs); } - - // Add offload include arguments, if needed. - addExtraOffloadSpecificIncludeArgs(C, JA, Args, CmdArgs); } // FIXME: Move to target hook. @@ -703,7 +828,7 @@ static void getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch, // FIXME: Use ARMTargetParser. static void getARMHWDivFeatures(const Driver &D, const Arg *A, const ArgList &Args, StringRef HWDiv, - std::vector<const char *> &Features) { + std::vector<StringRef> &Features) { unsigned HWDivID = llvm::ARM::parseHWDiv(HWDiv); if (!llvm::ARM::getHWDivFeatures(HWDivID, Features)) D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); @@ -712,7 +837,7 @@ static void getARMHWDivFeatures(const Driver &D, const Arg *A, // Handle -mfpu=. static void getARMFPUFeatures(const Driver &D, const Arg *A, const ArgList &Args, StringRef FPU, - std::vector<const char *> &Features) { + std::vector<StringRef> &Features) { unsigned FPUID = llvm::ARM::parseFPU(FPU); if (!llvm::ARM::getFPUFeatures(FPUID, Features)) D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); @@ -720,13 +845,13 @@ static void getARMFPUFeatures(const Driver &D, const Arg *A, // Decode ARM features from string like +[no]featureA+[no]featureB+... static bool DecodeARMFeatures(const Driver &D, StringRef text, - std::vector<const char *> &Features) { + std::vector<StringRef> &Features) { SmallVector<StringRef, 8> Split; text.split(Split, StringRef("+"), -1, false); for (StringRef Feature : Split) { - const char *FeatureName = llvm::ARM::getArchExtFeature(Feature); - if (FeatureName) + StringRef FeatureName = llvm::ARM::getArchExtFeature(Feature); + if (!FeatureName.empty()) Features.push_back(FeatureName); else return false; @@ -739,7 +864,7 @@ static bool DecodeARMFeatures(const Driver &D, StringRef text, // to handle -march=native correctly. static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args, llvm::StringRef ArchName, - std::vector<const char *> &Features, + std::vector<StringRef> &Features, const llvm::Triple &Triple) { std::pair<StringRef, StringRef> Split = ArchName.split("+"); @@ -752,7 +877,7 @@ static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args, // Check -mcpu=. Needs ArchName to handle -mcpu=generic. static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args, llvm::StringRef CPUName, llvm::StringRef ArchName, - std::vector<const char *> &Features, + std::vector<StringRef> &Features, const llvm::Triple &Triple) { std::pair<StringRef, StringRef> Split = CPUName.split("+"); @@ -773,7 +898,7 @@ static bool useAAPCSForMachO(const llvm::Triple &T) { // -mfloat-abi=. arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { const Driver &D = TC.getDriver(); - const llvm::Triple Triple(TC.ComputeEffectiveClangTriple(Args)); + const llvm::Triple &Triple = TC.getEffectiveTriple(); auto SubArch = getARMSubArchVersionNumber(Triple); arm::FloatABI ABI = FloatABI::Invalid; if (Arg *A = @@ -876,7 +1001,8 @@ arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { static void getARMTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, const ArgList &Args, - std::vector<const char *> &Features, + ArgStringList &CmdArgs, + std::vector<StringRef> &Features, bool ForAS) { const Driver &D = TC.getDriver(); @@ -1014,6 +1140,29 @@ static void getARMTargetFeatures(const ToolChain &TC, Features.push_back("+long-calls"); } + // Generate execute-only output (no data access to code sections). + // Supported only on ARMv6T2 and ARMv7 and above. + // Cannot be combined with -mno-movt or -mlong-calls + if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) { + if (A->getOption().matches(options::OPT_mexecute_only)) { + if (getARMSubArchVersionNumber(Triple) < 7 && + llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::AK_ARMV6T2) + D.Diag(diag::err_target_unsupported_execute_only) << Triple.getArchName(); + else if (Arg *B = Args.getLastArg(options::OPT_mno_movt)) + D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args); + // Long calls create constant pool entries and have not yet been fixed up + // to play nicely with execute-only. Hence, they cannot be used in + // execute-only code for now + else if (Arg *B = Args.getLastArg(options::OPT_mlong_calls, options::OPT_mno_long_calls)) { + if (B->getOption().matches(options::OPT_mlong_calls)) + D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args); + } + + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-arm-execute-only"); + } + } + // Kernel code has more strict alignment requirements. if (KernelOrKext) Features.push_back("+strict-align"); @@ -1146,9 +1295,9 @@ void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, // ARM tools end. /// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are -/// targeting. -static std::string getAArch64TargetCPU(const ArgList &Args) { - Arg *A; +/// targeting. Set \p A to the Arg corresponding to the -mcpu or -mtune +/// arguments if they are provided, or to nullptr otherwise. +static std::string getAArch64TargetCPU(const ArgList &Args, Arg *&A) { std::string CPU; // If we have -mtune or -mcpu, use that. if ((A = Args.getLastArg(options::OPT_mtune_EQ))) { @@ -1174,8 +1323,7 @@ static std::string getAArch64TargetCPU(const ArgList &Args) { void Clang::AddAArch64TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); - llvm::Triple Triple(TripleStr); + const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || Args.hasArg(options::OPT_mkernel) || @@ -1373,7 +1521,7 @@ static mips::FloatABI getMipsFloatABI(const Driver &D, const ArgList &Args) { } static void AddTargetFeature(const ArgList &Args, - std::vector<const char *> &Features, + std::vector<StringRef> &Features, OptSpecifier OnOpt, OptSpecifier OffOpt, StringRef FeatureName) { if (Arg *A = Args.getLastArg(OnOpt, OffOpt)) { @@ -1386,7 +1534,7 @@ static void AddTargetFeature(const ArgList &Args, static void getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, - std::vector<const char *> &Features) { + std::vector<StringRef> &Features) { StringRef CPUName; StringRef ABIName; mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); @@ -1597,7 +1745,7 @@ static std::string getPPCTargetCPU(const ArgList &Args) { static void getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, - std::vector<const char *> &Features) { + std::vector<StringRef> &Features) { handleTargetFeaturesGroup(Args, Features, options::OPT_m_ppc_Features_Group); ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args); @@ -1760,7 +1908,7 @@ sparc::FloatABI sparc::getSparcFloatABI(const Driver &D, } static void getSparcTargetFeatures(const Driver &D, const ArgList &Args, - std::vector<const char *> &Features) { + std::vector<StringRef> &Features) { sparc::FloatABI FloatABI = sparc::getSparcFloatABI(D, Args); if (FloatABI == sparc::FloatABI::Soft) Features.push_back("+soft-float"); @@ -1797,7 +1945,7 @@ static const char *getSystemZTargetCPU(const ArgList &Args) { } static void getSystemZTargetFeatures(const ArgList &Args, - std::vector<const char *> &Features) { + std::vector<StringRef> &Features) { // -m(no-)htm overrides use of the transactional-execution facility. if (Arg *A = Args.getLastArg(options::OPT_mhtm, options::OPT_mno_htm)) { if (A->getOption().matches(options::OPT_mhtm)) @@ -1868,6 +2016,11 @@ static const char *getX86TargetCPU(const ArgList &Args, if (Triple.isOSDarwin()) { if (Triple.getArchName() == "x86_64h") return "core-avx2"; + // macosx10.12 drops support for all pre-Penryn Macs. + // Simulators can still run on 10.11 though, like Xcode. + if (Triple.isMacOSX() && !Triple.isOSVersionLT(10, 12)) + return "penryn"; + // The oldest x86_64 Macs have core2/Merom; the oldest x86 Macs have Yonah. return Is64Bit ? "core2" : "yonah"; } @@ -1919,13 +2072,15 @@ static StringRef getWebAssemblyTargetCPU(const ArgList &Args) { static std::string getCPUName(const ArgList &Args, const llvm::Triple &T, bool FromAs = false) { + Arg *A; + switch (T.getArch()) { default: return ""; case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: - return getAArch64TargetCPU(Args); + return getAArch64TargetCPU(Args, A); case llvm::Triple::arm: case llvm::Triple::armeb: @@ -2000,8 +2155,27 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T, } } +static unsigned getLTOParallelism(const ArgList &Args, const Driver &D) { + unsigned Parallelism = 0; + Arg *LtoJobsArg = Args.getLastArg(options::OPT_flto_jobs_EQ); + if (LtoJobsArg && + StringRef(LtoJobsArg->getValue()).getAsInteger(10, Parallelism)) + D.Diag(diag::err_drv_invalid_int_value) << LtoJobsArg->getAsString(Args) + << LtoJobsArg->getValue(); + return Parallelism; +} + +// CloudABI and WebAssembly use -ffunction-sections and -fdata-sections by +// default. +static bool isUseSeparateSections(const llvm::Triple &Triple) { + return Triple.getOS() == llvm::Triple::CloudABI || + Triple.getArch() == llvm::Triple::wasm32 || + Triple.getArch() == llvm::Triple::wasm64; +} + static void AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, - ArgStringList &CmdArgs, bool IsThinLTO) { + ArgStringList &CmdArgs, bool IsThinLTO, + const Driver &D) { // Tell the linker to load the plugin. This has to come before AddLinkerInputs // as gold requires -plugin to come before any -plugin-opt that -Wl might // forward. @@ -2034,6 +2208,10 @@ static void AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, if (IsThinLTO) CmdArgs.push_back("-plugin-opt=thinlto"); + if (unsigned Parallelism = getLTOParallelism(Args, D)) + CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") + + llvm::to_string(Parallelism))); + // If an explicit debugger tuning argument appeared, pass it along. if (Arg *A = Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) { @@ -2044,6 +2222,28 @@ static void AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, else CmdArgs.push_back("-plugin-opt=-debugger-tune=gdb"); } + + bool UseSeparateSections = + isUseSeparateSections(ToolChain.getEffectiveTriple()); + + if (Args.hasFlag(options::OPT_ffunction_sections, + options::OPT_fno_function_sections, UseSeparateSections)) { + CmdArgs.push_back("-plugin-opt=-function-sections"); + } + + if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, + UseSeparateSections)) { + CmdArgs.push_back("-plugin-opt=-data-sections"); + } + + if (Arg *A = Args.getLastArg(options::OPT_fprofile_sample_use_EQ)) { + StringRef FName = A->getValue(); + if (!llvm::sys::fs::exists(FName)) + D.Diag(diag::err_drv_no_such_file) << FName; + else + CmdArgs.push_back( + Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName)); + } } /// This is a helper function for validating the optional refinement step @@ -2179,7 +2379,7 @@ static void ParseMRecip(const Driver &D, const ArgList &Args, static void getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, - std::vector<const char *> &Features) { + std::vector<StringRef> &Features) { // If -march=native, autodetect the feature list. if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { if (StringRef(A->getValue()) == "native") { @@ -2338,29 +2538,14 @@ void Clang::AddWebAssemblyTargetArgs(const ArgList &Args, // Decode AArch64 features from string like +[no]featureA+[no]featureB+... static bool DecodeAArch64Features(const Driver &D, StringRef text, - std::vector<const char *> &Features) { + std::vector<StringRef> &Features) { SmallVector<StringRef, 8> Split; text.split(Split, StringRef("+"), -1, false); for (StringRef Feature : Split) { - const char *result = llvm::StringSwitch<const char *>(Feature) - .Case("fp", "+fp-armv8") - .Case("simd", "+neon") - .Case("crc", "+crc") - .Case("crypto", "+crypto") - .Case("fp16", "+fullfp16") - .Case("profile", "+spe") - .Case("ras", "+ras") - .Case("nofp", "-fp-armv8") - .Case("nosimd", "-neon") - .Case("nocrc", "-crc") - .Case("nocrypto", "-crypto") - .Case("nofp16", "-fullfp16") - .Case("noprofile", "-spe") - .Case("noras", "-ras") - .Default(nullptr); - if (result) - Features.push_back(result); + StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature); + if (!FeatureName.empty()) + Features.push_back(FeatureName); else if (Feature == "neon" || Feature == "noneon") D.Diag(diag::err_drv_no_neon_modifier); else @@ -2372,23 +2557,21 @@ static bool DecodeAArch64Features(const Driver &D, StringRef text, // 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<const char *> &Features) { + std::vector<StringRef> &Features) { std::pair<StringRef, StringRef> Split = Mcpu.split("+"); CPU = Split.first; - if (CPU == "cortex-a53" || CPU == "cortex-a57" || - CPU == "cortex-a72" || CPU == "cortex-a35" || CPU == "exynos-m1" || - CPU == "kryo" || CPU == "cortex-a73" || CPU == "vulcan") { - Features.push_back("+neon"); - Features.push_back("+crc"); - Features.push_back("+crypto"); - } else if (CPU == "cyclone") { - Features.push_back("+neon"); - Features.push_back("+crypto"); - } else if (CPU == "generic") { + + if (CPU == "generic") { Features.push_back("+neon"); } else { - return false; - } + unsigned 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; @@ -2399,21 +2582,14 @@ static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU, static bool getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, const ArgList &Args, - std::vector<const char *> &Features) { + std::vector<StringRef> &Features) { std::string MarchLowerCase = March.lower(); std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+"); - if (Split.first == "armv8-a" || Split.first == "armv8a") { - // ok, no additional features. - } else if (Split.first == "armv8.1-a" || Split.first == "armv8.1a") { - Features.push_back("+v8.1a"); - } else if (Split.first == "armv8.2-a" || Split.first == "armv8.2a" ) { - Features.push_back("+v8.2a"); - } else { - return false; - } - - if (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features)) + unsigned ArchKind = llvm::AArch64::parseArch(Split.first); + if (ArchKind == static_cast<unsigned>(llvm::AArch64::ArchKind::AK_INVALID) || + !llvm::AArch64::getArchFeatures(ArchKind, Features) || + (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features))) return false; return true; @@ -2422,7 +2598,7 @@ getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, static bool getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, const ArgList &Args, - std::vector<const char *> &Features) { + std::vector<StringRef> &Features) { StringRef CPU; std::string McpuLowerCase = Mcpu.lower(); if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Features)) @@ -2434,7 +2610,7 @@ getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, static bool getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, const ArgList &Args, - std::vector<const char *> &Features) { + std::vector<StringRef> &Features) { std::string MtuneLowerCase = Mtune.lower(); // Handle CPU name is 'native'. if (MtuneLowerCase == "native") @@ -2449,9 +2625,9 @@ getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, static bool getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, const ArgList &Args, - std::vector<const char *> &Features) { + std::vector<StringRef> &Features) { StringRef CPU; - std::vector<const char *> DecodedFeature; + std::vector<StringRef> DecodedFeature; std::string McpuLowerCase = Mcpu.lower(); if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, DecodedFeature)) return false; @@ -2460,7 +2636,7 @@ getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, } static void getAArch64TargetFeatures(const Driver &D, const ArgList &Args, - std::vector<const char *> &Features) { + std::vector<StringRef> &Features) { Arg *A; bool success = true; // Enable NEON by default. @@ -2470,8 +2646,8 @@ static void getAArch64TargetFeatures(const Driver &D, const ArgList &Args, 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), Args, - Features); + success = getAArch64ArchFeaturesFromMcpu(D, getAArch64TargetCPU(Args, A), + Args, Features); if (success && (A = Args.getLastArg(options::OPT_mtune_EQ))) success = @@ -2479,9 +2655,9 @@ static void getAArch64TargetFeatures(const Driver &D, const ArgList &Args, else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ))) success = getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features); - else if (Args.hasArg(options::OPT_arch)) - success = getAArch64MicroArchFeaturesFromMcpu(D, getAArch64TargetCPU(Args), - 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); @@ -2510,38 +2686,27 @@ static void getAArch64TargetFeatures(const Driver &D, const ArgList &Args, } static void getHexagonTargetFeatures(const ArgList &Args, - std::vector<const char *> &Features) { - bool HasHVX = false, HasHVXD = false; - - // FIXME: This should be able to use handleTargetFeaturesGroup except it is - // doing dependent option handling here rather than in initFeatureMap or a - // similar handler. - for (auto &A : Args) { - auto &Opt = A->getOption(); - if (Opt.matches(options::OPT_mhexagon_hvx)) - HasHVX = true; - else if (Opt.matches(options::OPT_mno_hexagon_hvx)) - HasHVXD = HasHVX = false; - else if (Opt.matches(options::OPT_mhexagon_hvx_double)) - HasHVXD = HasHVX = true; - else if (Opt.matches(options::OPT_mno_hexagon_hvx_double)) - HasHVXD = false; - else - continue; - A->claim(); + std::vector<StringRef> &Features) { + handleTargetFeaturesGroup(Args, Features, + options::OPT_m_hexagon_Features_Group); + + bool UseLongCalls = false; + if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, + options::OPT_mno_long_calls)) { + if (A->getOption().matches(options::OPT_mlong_calls)) + UseLongCalls = true; } - Features.push_back(HasHVX ? "+hvx" : "-hvx"); - Features.push_back(HasHVXD ? "+hvx-double" : "-hvx-double"); + Features.push_back(UseLongCalls ? "+long-calls" : "-long-calls"); } static void getWebAssemblyTargetFeatures(const ArgList &Args, - std::vector<const char *> &Features) { + std::vector<StringRef> &Features) { handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group); } static void getAMDGPUTargetFeatures(const Driver &D, const ArgList &Args, - std::vector<const char *> &Features) { + std::vector<StringRef> &Features) { if (const Arg *dAbi = Args.getLastArg(options::OPT_mamdgpu_debugger_abi)) { StringRef value = dAbi->getValue(); if (value == "1.0") { @@ -2561,7 +2726,7 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, const ArgList &Args, ArgStringList &CmdArgs, bool ForAS) { const Driver &D = TC.getDriver(); - std::vector<const char *> Features; + std::vector<StringRef> Features; switch (Triple.getArch()) { default: break; @@ -2576,7 +2741,7 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: - getARMTargetFeatures(TC, Triple, Args, Features, ForAS); + getARMTargetFeatures(TC, Triple, Args, CmdArgs, Features, ForAS); break; case llvm::Triple::ppc: @@ -2601,7 +2766,7 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, case llvm::Triple::wasm32: case llvm::Triple::wasm64: getWebAssemblyTargetFeatures(Args, Features); - break; + break; case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::sparcv9: @@ -2616,22 +2781,22 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, // Find the last of each feature. llvm::StringMap<unsigned> LastOpt; for (unsigned I = 0, N = Features.size(); I < N; ++I) { - const char *Name = Features[I]; + StringRef Name = Features[I]; assert(Name[0] == '-' || Name[0] == '+'); - LastOpt[Name + 1] = I; + LastOpt[Name.drop_front(1)] = I; } for (unsigned I = 0, N = Features.size(); I < N; ++I) { // If this feature was overridden, ignore it. - const char *Name = Features[I]; - llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name + 1); + StringRef Name = Features[I]; + llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name.drop_front(1)); assert(LastI != LastOpt.end()); unsigned Last = LastI->second; if (Last != I) continue; CmdArgs.push_back("-target-feature"); - CmdArgs.push_back(Name); + CmdArgs.push_back(Name.data()); } } @@ -2857,6 +3022,27 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, DefaultIncrementalLinkerCompatible)) CmdArgs.push_back("-mincremental-linker-compatible"); + switch (C.getDefaultToolChain().getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + if (Arg *A = Args.getLastArg(options::OPT_mimplicit_it_EQ)) { + StringRef Value = A->getValue(); + if (Value == "always" || Value == "never" || Value == "arm" || + Value == "thumb") { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-arm-implicit-it=" + Value)); + } else { + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; + } + } + break; + default: + break; + } + // When passing -I arguments to the assembler we sometimes need to // unconditionally take the next argument. For example, when parsing // '-Wa,-I -Wa,foo' we need to accept the -Wa,foo arg after seeing the @@ -2881,6 +3067,10 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, continue; } + if (C.getDefaultToolChain().getTriple().isOSBinFormatCOFF() && + Value == "-mbig-obj") + continue; // LLVM handles bigobj automatically + switch (C.getDefaultToolChain().getArch()) { default: break; @@ -2969,6 +3159,27 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, } else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") || Value.startswith("-mhwdiv") || Value.startswith("-march")) { // Do nothing, we'll validate it later. + } else if (Value == "-defsym") { + if (A->getNumValues() != 2) { + D.Diag(diag::err_drv_defsym_invalid_format) << Value; + break; + } + const char *S = A->getValue(1); + auto Pair = StringRef(S).split('='); + auto Sym = Pair.first; + auto SVal = Pair.second; + + if (Sym.empty() || SVal.empty()) { + D.Diag(diag::err_drv_defsym_invalid_format) << S; + break; + } + int64_t IVal; + if (SVal.getAsInteger(0, IVal)) { + D.Diag(diag::err_drv_defsym_invalid_symval) << SVal; + break; + } + CmdArgs.push_back(Value.data()); + TakeNextArg = true; } else { D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; @@ -2997,72 +3208,23 @@ static void addClangRT(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins")); } -namespace { -enum OpenMPRuntimeKind { - /// An unknown OpenMP runtime. We can't generate effective OpenMP code - /// without knowing what runtime to target. - OMPRT_Unknown, - - /// The LLVM OpenMP runtime. When completed and integrated, this will become - /// the default for Clang. - OMPRT_OMP, - - /// The GNU OpenMP runtime. Clang doesn't support generating OpenMP code for - /// this runtime but can swallow the pragmas, and find and link against the - /// runtime library itself. - OMPRT_GOMP, - - /// The legacy name for the LLVM OpenMP runtime from when it was the Intel - /// OpenMP runtime. We support this mode for users with existing dependencies - /// on this runtime library name. - OMPRT_IOMP5 -}; -} - -/// Compute the desired OpenMP runtime from the flag provided. -static OpenMPRuntimeKind getOpenMPRuntime(const ToolChain &TC, - const ArgList &Args) { - StringRef RuntimeName(CLANG_DEFAULT_OPENMP_RUNTIME); - - const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ); - if (A) - RuntimeName = A->getValue(); - - auto RT = llvm::StringSwitch<OpenMPRuntimeKind>(RuntimeName) - .Case("libomp", OMPRT_OMP) - .Case("libgomp", OMPRT_GOMP) - .Case("libiomp5", OMPRT_IOMP5) - .Default(OMPRT_Unknown); - - if (RT == OMPRT_Unknown) { - if (A) - TC.getDriver().Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << A->getValue(); - else - // FIXME: We could use a nicer diagnostic here. - TC.getDriver().Diag(diag::err_drv_unsupported_opt) << "-fopenmp"; - } - - return RT; -} - static void addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, const ArgList &Args) { if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, options::OPT_fno_openmp, false)) return; - switch (getOpenMPRuntime(TC, Args)) { - case OMPRT_OMP: + switch (TC.getDriver().getOpenMPRuntime(Args)) { + case Driver::OMPRT_OMP: CmdArgs.push_back("-lomp"); break; - case OMPRT_GOMP: + case Driver::OMPRT_GOMP: CmdArgs.push_back("-lgomp"); break; - case OMPRT_IOMP5: + case Driver::OMPRT_IOMP5: CmdArgs.push_back("-liomp5"); break; - case OMPRT_Unknown: + case Driver::OMPRT_Unknown: // Already diagnosed. break; } @@ -3096,11 +3258,15 @@ static void linkSanitizerRuntimeDeps(const ToolChain &TC, // Force linking against the system libraries sanitizers depends on // (see PR15823 why this is necessary). CmdArgs.push_back("--no-as-needed"); - CmdArgs.push_back("-lpthread"); - CmdArgs.push_back("-lrt"); + // There's no libpthread or librt on RTEMS. + if (TC.getTriple().getOS() != llvm::Triple::RTEMS) { + CmdArgs.push_back("-lpthread"); + CmdArgs.push_back("-lrt"); + } CmdArgs.push_back("-lm"); - // There's no libdl on FreeBSD. - if (TC.getTriple().getOS() != llvm::Triple::FreeBSD) + // There's no libdl on FreeBSD or RTEMS. + if (TC.getTriple().getOS() != llvm::Triple::FreeBSD && + TC.getTriple().getOS() != llvm::Triple::RTEMS) CmdArgs.push_back("-ldl"); } @@ -3200,6 +3366,11 @@ static bool addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, // to be dynamic to be sure we export sanitizer interface functions. if (AddExportDynamic) CmdArgs.push_back("-export-dynamic"); + + const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); + if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic) + CmdArgs.push_back("-export-dynamic-symbol=__cfi_check"); + return !StaticRuntimes.empty(); } @@ -3238,8 +3409,20 @@ static bool areOptimizationsEnabled(const ArgList &Args) { return false; } -static bool shouldUseFramePointerForTarget(const ArgList &Args, - const llvm::Triple &Triple) { +static bool mustUseFramePointerForTarget(const llvm::Triple &Triple) { + switch (Triple.getArch()){ + default: + return false; + case llvm::Triple::arm: + case llvm::Triple::thumb: + // ARM Darwin targets require a frame pointer to be always present to aid + // offline debugging via backtraces. + return Triple.isOSDarwin(); + } +} + +static bool useFramePointerForTargetByDefault(const ArgList &Args, + const llvm::Triple &Triple) { switch (Triple.getArch()) { case llvm::Triple::xcore: case llvm::Triple::wasm32: @@ -3291,25 +3474,29 @@ static bool shouldUseFramePointer(const ArgList &Args, const llvm::Triple &Triple) { if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer, options::OPT_fomit_frame_pointer)) - return A->getOption().matches(options::OPT_fno_omit_frame_pointer); + return A->getOption().matches(options::OPT_fno_omit_frame_pointer) || + mustUseFramePointerForTarget(Triple); + if (Args.hasArg(options::OPT_pg)) return true; - return shouldUseFramePointerForTarget(Args, Triple); + return useFramePointerForTargetByDefault(Args, Triple); } static bool shouldUseLeafFramePointer(const ArgList &Args, const llvm::Triple &Triple) { if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer, options::OPT_momit_leaf_frame_pointer)) - return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer); + return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer) || + mustUseFramePointerForTarget(Triple); + if (Args.hasArg(options::OPT_pg)) return true; if (Triple.isPS4CPU()) return false; - return shouldUseFramePointerForTarget(Args, Triple); + return useFramePointerForTargetByDefault(Args, Triple); } /// Add a CC1 option to specify the debug compilation directory. @@ -3409,19 +3596,6 @@ static void addDashXForInput(const ArgList &Args, const InputInfo &Input, CmdArgs.push_back(types::getTypeName(Input.getType())); } -static VersionTuple getMSCompatibilityVersion(unsigned Version) { - if (Version < 100) - return VersionTuple(Version); - - if (Version < 10000) - return VersionTuple(Version / 100, Version % 100); - - unsigned Build = 0, Factor = 1; - for (; Version > 10000; Version = Version / 10, Factor = Factor * 10) - Build = Build + (Version % 10) * Factor; - return VersionTuple(Version / 100, Version % 100, Build); -} - // Claim options we don't want to warn if they are unused. We do this for // options that build systems might add but are unused when assembling or only // running the preprocessor for example. @@ -3465,58 +3639,17 @@ static void appendUserToPath(SmallVectorImpl<char> &Result) { Result.append(UID.begin(), UID.end()); } -VersionTuple visualstudio::getMSVCVersion(const Driver *D, const ToolChain &TC, - const llvm::Triple &Triple, - const llvm::opt::ArgList &Args, - bool IsWindowsMSVC) { - if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, - IsWindowsMSVC) || - Args.hasArg(options::OPT_fmsc_version) || - Args.hasArg(options::OPT_fms_compatibility_version)) { - const Arg *MSCVersion = Args.getLastArg(options::OPT_fmsc_version); - const Arg *MSCompatibilityVersion = - Args.getLastArg(options::OPT_fms_compatibility_version); - - if (MSCVersion && MSCompatibilityVersion) { - if (D) - D->Diag(diag::err_drv_argument_not_allowed_with) - << MSCVersion->getAsString(Args) - << MSCompatibilityVersion->getAsString(Args); - return VersionTuple(); - } - - if (MSCompatibilityVersion) { - VersionTuple MSVT; - if (MSVT.tryParse(MSCompatibilityVersion->getValue()) && D) - D->Diag(diag::err_drv_invalid_value) - << MSCompatibilityVersion->getAsString(Args) - << MSCompatibilityVersion->getValue(); - return MSVT; - } - - if (MSCVersion) { - unsigned Version = 0; - if (StringRef(MSCVersion->getValue()).getAsInteger(10, Version) && D) - D->Diag(diag::err_drv_invalid_value) << MSCVersion->getAsString(Args) - << MSCVersion->getValue(); - return getMSCompatibilityVersion(Version); - } - - unsigned Major, Minor, Micro; - Triple.getEnvironmentVersion(Major, Minor, Micro); - if (Major || Minor || Micro) - return VersionTuple(Major, Minor, Micro); +static Arg *getLastProfileUseArg(const ArgList &Args) { + auto *ProfileUseArg = Args.getLastArg( + options::OPT_fprofile_instr_use, options::OPT_fprofile_instr_use_EQ, + options::OPT_fprofile_use, options::OPT_fprofile_use_EQ, + options::OPT_fno_profile_instr_use); - if (IsWindowsMSVC) { - VersionTuple MSVT = TC.getMSVCVersionFromExe(); - if (!MSVT.empty()) - return MSVT; + if (ProfileUseArg && + ProfileUseArg->getOption().matches(options::OPT_fno_profile_instr_use)) + ProfileUseArg = nullptr; - // FIXME: Consider bumping this to 19 (MSVC2015) soon. - return VersionTuple(18); - } - } - return VersionTuple(); + return ProfileUseArg; } static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, @@ -3543,13 +3676,7 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, D.Diag(diag::err_drv_argument_not_allowed_with) << PGOGenerateArg->getSpelling() << ProfileGenerateArg->getSpelling(); - auto *ProfileUseArg = Args.getLastArg( - options::OPT_fprofile_instr_use, options::OPT_fprofile_instr_use_EQ, - options::OPT_fprofile_use, options::OPT_fprofile_use_EQ, - options::OPT_fno_profile_instr_use); - if (ProfileUseArg && - ProfileUseArg->getOption().matches(options::OPT_fno_profile_instr_use)) - ProfileUseArg = nullptr; + auto *ProfileUseArg = getLastProfileUseArg(Args); if (PGOGenerateArg && ProfileUseArg) D.Diag(diag::err_drv_argument_not_allowed_with) @@ -3573,7 +3700,7 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, if (PGOGenerateArg->getOption().matches( options::OPT_fprofile_generate_EQ)) { SmallString<128> Path(PGOGenerateArg->getValue()); - llvm::sys::path::append(Path, "default.profraw"); + llvm::sys::path::append(Path, "default_%m.profraw"); CmdArgs.push_back( Args.MakeArgString(Twine("-fprofile-instrument-path=") + Path)); } @@ -3618,13 +3745,13 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, if (C.getArgs().hasArg(options::OPT_c) || C.getArgs().hasArg(options::OPT_S)) { if (Output.isFilename()) { - CmdArgs.push_back("-coverage-file"); - SmallString<128> CoverageFilename; - if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) { - CoverageFilename = FinalOutput->getValue(); - } else { - CoverageFilename = llvm::sys::path::filename(Output.getBaseInput()); - } + CmdArgs.push_back("-coverage-notes-file"); + SmallString<128> OutputFilename; + if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) + OutputFilename = FinalOutput->getValue(); + else + OutputFilename = llvm::sys::path::filename(Output.getBaseInput()); + SmallString<128> CoverageFilename = OutputFilename; if (llvm::sys::path::is_relative(CoverageFilename)) { SmallString<128> Pwd; if (!llvm::sys::fs::current_path(Pwd)) { @@ -3632,7 +3759,23 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, CoverageFilename.swap(Pwd); } } + llvm::sys::path::replace_extension(CoverageFilename, "gcno"); CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); + + // Leave -fprofile-dir= an unused argument unless .gcda emission is + // enabled. To be polite, with '-fprofile-arcs -fno-profile-arcs' consider + // the flag used. There is no -fno-profile-dir, so the user has no + // targeted way to suppress the warning. + if (Args.hasArg(options::OPT_fprofile_arcs) || + Args.hasArg(options::OPT_coverage)) { + CmdArgs.push_back("-coverage-data-file"); + if (Arg *FProfileDir = Args.getLastArg(options::OPT_fprofile_dir)) { + CoverageFilename = FProfileDir->getValue(); + llvm::sys::path::append(CoverageFilename, OutputFilename); + } + llvm::sys::path::replace_extension(CoverageFilename, "gcda"); + CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); + } } } } @@ -3659,15 +3802,14 @@ static void addPS4ProfileRTArgs(const ToolChain &TC, const ArgList &Args, /// this compile should be using PIC mode or not. Returns a tuple of /// (RelocationModel, PICLevel, IsPIE). static std::tuple<llvm::Reloc::Model, unsigned, bool> -ParsePICArgs(const ToolChain &ToolChain, const llvm::Triple &Triple, - const ArgList &Args) { - // FIXME: why does this code...and so much everywhere else, use both - // ToolChain.getTriple() and Triple? +ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { + const llvm::Triple &EffectiveTriple = ToolChain.getEffectiveTriple(); + const llvm::Triple &Triple = ToolChain.getTriple(); + bool PIE = ToolChain.isPIEDefault(); bool PIC = PIE || ToolChain.isPICDefault(); // The Darwin/MachO default to use PIC does not apply when using -static. - if (ToolChain.getTriple().isOSBinFormatMachO() && - Args.hasArg(options::OPT_static)) + if (Triple.isOSBinFormatMachO() && Args.hasArg(options::OPT_static)) PIE = PIC = false; bool IsPICLevelTwo = PIC; @@ -3675,8 +3817,8 @@ ParsePICArgs(const ToolChain &ToolChain, const llvm::Triple &Triple, Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); // Android-specific defaults for PIC/PIE - if (ToolChain.getTriple().isAndroid()) { - switch (ToolChain.getArch()) { + if (Triple.isAndroid()) { + switch (Triple.getArch()) { case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: @@ -3701,7 +3843,7 @@ ParsePICArgs(const ToolChain &ToolChain, const llvm::Triple &Triple, } // OpenBSD-specific defaults for PIE - if (ToolChain.getTriple().getOS() == llvm::Triple::OpenBSD) { + if (Triple.getOS() == llvm::Triple::OpenBSD) { switch (ToolChain.getArch()) { case llvm::Triple::mips64: case llvm::Triple::mips64el: @@ -3730,6 +3872,17 @@ ParsePICArgs(const ToolChain &ToolChain, const llvm::Triple &Triple, options::OPT_fpic, options::OPT_fno_pic, options::OPT_fPIE, options::OPT_fno_PIE, options::OPT_fpie, options::OPT_fno_pie); + if (Triple.isOSWindows() && LastPICArg && + LastPICArg == + Args.getLastArg(options::OPT_fPIC, options::OPT_fpic, + options::OPT_fPIE, options::OPT_fpie)) { + ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) + << LastPICArg->getSpelling() << Triple.str(); + if (Triple.getArch() == llvm::Triple::x86_64) + return std::make_tuple(llvm::Reloc::PIC_, 2U, false); + return std::make_tuple(llvm::Reloc::Static, 0U, false); + } + // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness // is forced, then neither PIC nor PIE flags will have no effect. if (!ToolChain.isPICDefaultForced()) { @@ -3744,7 +3897,7 @@ ParsePICArgs(const ToolChain &ToolChain, const llvm::Triple &Triple, O.matches(options::OPT_fPIE) || O.matches(options::OPT_fPIC); } else { PIE = PIC = false; - if (Triple.isPS4CPU()) { + if (EffectiveTriple.isPS4CPU()) { Arg *ModelArg = Args.getLastArg(options::OPT_mcmodel_EQ); StringRef Model = ModelArg ? ModelArg->getValue() : ""; if (Model != "kernel") { @@ -3760,21 +3913,22 @@ ParsePICArgs(const ToolChain &ToolChain, const llvm::Triple &Triple, // Introduce a Darwin and PS4-specific hack. If the default is PIC, but the // PIC level would've been set to level 1, force it back to level 2 PIC // instead. - if (PIC && (ToolChain.getTriple().isOSDarwin() || Triple.isPS4CPU())) + if (PIC && (Triple.isOSDarwin() || EffectiveTriple.isPS4CPU())) IsPICLevelTwo |= ToolChain.isPICDefault(); // This kernel flags are a trump-card: they will disable PIC/PIE // generation, independent of the argument order. - if (KernelOrKext && ((!Triple.isiOS() || Triple.isOSVersionLT(6)) && - !Triple.isWatchOS())) + if (KernelOrKext && + ((!EffectiveTriple.isiOS() || EffectiveTriple.isOSVersionLT(6)) && + !EffectiveTriple.isWatchOS())) PIC = PIE = false; if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) { // This is a very special mode. It trumps the other modes, almost no one // uses it, and it isn't even valid on any OS but Darwin. - if (!ToolChain.getTriple().isOSDarwin()) + if (!Triple.isOSDarwin()) ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) - << A->getSpelling() << ToolChain.getTriple().str(); + << A->getSpelling() << Triple.str(); // FIXME: Warn when this flag trumps some other PIC or PIE flag. @@ -3783,13 +3937,54 @@ ParsePICArgs(const ToolChain &ToolChain, const llvm::Triple &Triple, // match that of llvm-gcc and Apple GCC before that. PIC = ToolChain.isPICDefault() && ToolChain.isPICDefaultForced(); - return std::make_tuple(llvm::Reloc::DynamicNoPIC, PIC ? 2 : 0, false); + return std::make_tuple(llvm::Reloc::DynamicNoPIC, PIC ? 2U : 0U, false); + } + + bool EmbeddedPISupported; + switch (Triple.getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + EmbeddedPISupported = true; + break; + default: + EmbeddedPISupported = false; + break; + } + + bool ROPI = false, RWPI = false; + Arg* LastROPIArg = Args.getLastArg(options::OPT_fropi, options::OPT_fno_ropi); + if (LastROPIArg && LastROPIArg->getOption().matches(options::OPT_fropi)) { + if (!EmbeddedPISupported) + ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) + << LastROPIArg->getSpelling() << Triple.str(); + ROPI = true; + } + Arg *LastRWPIArg = Args.getLastArg(options::OPT_frwpi, options::OPT_fno_rwpi); + if (LastRWPIArg && LastRWPIArg->getOption().matches(options::OPT_frwpi)) { + if (!EmbeddedPISupported) + ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) + << LastRWPIArg->getSpelling() << Triple.str(); + RWPI = true; } + // ROPI and RWPI are not comaptible with PIC or PIE. + if ((ROPI || RWPI) && (PIC || PIE)) + ToolChain.getDriver().Diag(diag::err_drv_ropi_rwpi_incompatible_with_pic); + if (PIC) - return std::make_tuple(llvm::Reloc::PIC_, IsPICLevelTwo ? 2 : 1, PIE); + return std::make_tuple(llvm::Reloc::PIC_, IsPICLevelTwo ? 2U : 1U, PIE); + + llvm::Reloc::Model RelocM = llvm::Reloc::Static; + if (ROPI && RWPI) + RelocM = llvm::Reloc::ROPI_RWPI; + else if (ROPI) + RelocM = llvm::Reloc::ROPI; + else if (RWPI) + RelocM = llvm::Reloc::RWPI; - return std::make_tuple(llvm::Reloc::Static, 0, false); + return std::make_tuple(RelocM, 0U, false); } static const char *RelocationModelName(llvm::Reloc::Model Model) { @@ -3800,6 +3995,12 @@ static const char *RelocationModelName(llvm::Reloc::Model Model) { return "pic"; case llvm::Reloc::DynamicNoPIC: return "dynamic-no-pic"; + case llvm::Reloc::ROPI: + return "ropi"; + case llvm::Reloc::RWPI: + return "rwpi"; + case llvm::Reloc::ROPI_RWPI: + return "ropi-rwpi"; } llvm_unreachable("Unknown Reloc::Model kind"); } @@ -3809,24 +4010,95 @@ static void AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args, llvm::Reloc::Model RelocationModel; unsigned PICLevel; bool IsPIE; - std::tie(RelocationModel, PICLevel, IsPIE) = - ParsePICArgs(ToolChain, ToolChain.getTriple(), Args); + std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(ToolChain, Args); if (RelocationModel != llvm::Reloc::Static) CmdArgs.push_back("-KPIC"); } +void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, + StringRef Target, const InputInfo &Output, + const InputInfo &Input, const ArgList &Args) const { + // If this is a dry run, do not create the compilation database file. + if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) + return; + + using llvm::yaml::escape; + const Driver &D = getToolChain().getDriver(); + + if (!CompilationDatabase) { + std::error_code EC; + auto File = llvm::make_unique<llvm::raw_fd_ostream>(Filename, EC, llvm::sys::fs::F_Text); + if (EC) { + D.Diag(clang::diag::err_drv_compilationdatabase) << Filename + << EC.message(); + return; + } + CompilationDatabase = std::move(File); + } + auto &CDB = *CompilationDatabase; + SmallString<128> Buf; + if (llvm::sys::fs::current_path(Buf)) + Buf = "."; + CDB << "{ \"directory\": \"" << escape(Buf) << "\""; + CDB << ", \"file\": \"" << escape(Input.getFilename()) << "\""; + CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\""; + CDB << ", \"arguments\": [\"" << escape(D.ClangExecutable) << "\""; + Buf = "-x"; + Buf += types::getTypeName(Input.getType()); + CDB << ", \"" << escape(Buf) << "\""; + if (!D.SysRoot.empty() && !Args.hasArg(options::OPT__sysroot_EQ)) { + Buf = "--sysroot="; + Buf += D.SysRoot; + CDB << ", \"" << escape(Buf) << "\""; + } + CDB << ", \"" << escape(Input.getFilename()) << "\""; + for (auto &A: Args) { + auto &O = A->getOption(); + // Skip language selection, which is positional. + if (O.getID() == options::OPT_x) + continue; + // Skip writing dependency output and the compilation database itself. + if (O.getGroup().isValid() && O.getGroup().getID() == options::OPT_M_Group) + continue; + // Skip inputs. + if (O.getKind() == Option::InputClass) + continue; + // All other arguments are quoted and appended. + ArgStringList ASL; + A->render(Args, ASL); + for (auto &it: ASL) + CDB << ", \"" << escape(it) << "\""; + } + Buf = "--target="; + Buf += Target; + CDB << ", \"" << escape(Buf) << "\"]},\n"; +} + void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); - const llvm::Triple Triple(TripleStr); + const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); + const std::string &TripleStr = Triple.getTriple(); bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; + // Check number of inputs for sanity. We need at least one input. + assert(Inputs.size() >= 1 && "Must have at least one input."); + const InputInfo &Input = Inputs[0]; + // CUDA compilation may have multiple inputs (source file + results of + // device-side compilations). OpenMP device jobs also take the host IR as a + // second input. All other jobs are expected to have exactly one + // input. + bool IsCuda = JA.isOffloading(Action::OFK_Cuda); + bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); + assert((IsCuda || (IsOpenMPDevice && Inputs.size() == 2) || + Inputs.size() == 1) && + "Unable to handle multiple inputs."); + bool IsWindowsGNU = getToolChain().getTriple().isWindowsGNUEnvironment(); bool IsWindowsCygnus = getToolChain().getTriple().isWindowsCygwinEnvironment(); @@ -3834,14 +4106,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, bool IsPS4CPU = getToolChain().getTriple().isPS4CPU(); bool IsIAMCU = getToolChain().getTriple().isOSIAMCU(); - // Check number of inputs for sanity. We need at least one input. - assert(Inputs.size() >= 1 && "Must have at least one input."); - const InputInfo &Input = Inputs[0]; - // CUDA compilation may have multiple inputs (source file + results of - // device-side compilations). All other jobs are expected to have exactly one - // input. - bool IsCuda = JA.isOffloading(Action::OFK_Cuda); - assert((IsCuda || Inputs.size() == 1) && "Unable to handle multiple inputs."); + // Adjust IsWindowsXYZ for CUDA compilations. Even when compiling in device + // mode (i.e., getToolchain().getTriple() is NVPTX, not Windows), we need to + // pass Windows-specific flags to cc1. + if (IsCuda) { + const llvm::Triple *AuxTriple = getToolChain().getAuxTriple(); + IsWindowsMSVC |= AuxTriple && AuxTriple->isWindowsMSVCEnvironment(); + IsWindowsGNU |= AuxTriple && AuxTriple->isWindowsGNUEnvironment(); + IsWindowsCygnus |= AuxTriple && AuxTriple->isWindowsCygwinEnvironment(); + } // C++ is not supported for IAMCU. if (IsIAMCU && types::isCXX(Input.getType())) @@ -3856,6 +4129,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-triple"); CmdArgs.push_back(Args.MakeArgString(TripleStr)); + if (const Arg *MJ = Args.getLastArg(options::OPT_MJ)) { + DumpCompilationDatabase(C, MJ->getValue(), TripleStr, Output, Input, Args); + Args.ClaimAllArgs(options::OPT_MJ); + } + if (IsCuda) { // We have to pass the triple of the host if compiling for a CUDA device and // vice-versa. @@ -3918,6 +4196,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (JA.getType() == types::TY_Nothing) CmdArgs.push_back("-fsyntax-only"); + else if (JA.getType() == types::TY_ModuleFile) + CmdArgs.push_back("-emit-module-interface"); else if (UsePCH) CmdArgs.push_back("-emit-pch"); else @@ -3970,12 +4250,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // Embed-bitcode option. - if (C.getDriver().embedBitcodeEnabled() && + if (C.getDriver().embedBitcodeInObject() && (isa<BackendJobAction>(JA) || isa<AssembleJobAction>(JA))) { // Add flags implied by -fembed-bitcode. Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ); // Disable all llvm IR level optimizations. - CmdArgs.push_back("-disable-llvm-optzns"); + CmdArgs.push_back("-disable-llvm-passes"); } if (C.getDriver().embedBitcodeMarkerOnly()) CmdArgs.push_back("-fembed-bitcode=marker"); @@ -4015,6 +4295,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Add default argument set. if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { CmdArgs.push_back("-analyzer-checker=core"); + CmdArgs.push_back("-analyzer-checker=apiModeling"); if (!IsWindowsMSVC) { CmdArgs.push_back("-analyzer-checker=unix"); @@ -4081,9 +4362,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, unsigned PICLevel; bool IsPIE; std::tie(RelocationModel, PICLevel, IsPIE) = - ParsePICArgs(getToolChain(), Triple, Args); + ParsePICArgs(getToolChain(), Args); const char *RMName = RelocationModelName(RelocationModel); + + if ((RelocationModel == llvm::Reloc::ROPI || + RelocationModel == llvm::Reloc::ROPI_RWPI) && + types::isCXX(Input.getType()) && + !Args.hasArg(options::OPT_fallow_unsupported)) + D.Diag(diag::err_drv_ropi_incompatible_with_cxx); + if (RMName) { CmdArgs.push_back("-mrelocation-model"); CmdArgs.push_back(RMName); @@ -4118,9 +4406,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.hasArg(options::OPT_frewrite_map_file_EQ)) { for (const Arg *A : Args.filtered(options::OPT_frewrite_map_file, options::OPT_frewrite_map_file_EQ)) { - CmdArgs.push_back("-frewrite-map-file"); - CmdArgs.push_back(A->getValue()); - A->claim(); + StringRef Map = A->getValue(); + if (!llvm::sys::fs::exists(Map)) { + D.Diag(diag::err_drv_no_such_file) << Map; + } else { + CmdArgs.push_back("-frewrite-map-file"); + CmdArgs.push_back(A->getValue()); + A->claim(); + } } } @@ -4135,6 +4428,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, true)) CmdArgs.push_back("-fno-jump-tables"); + if (!Args.hasFlag(options::OPT_fpreserve_as_comments, + options::OPT_fno_preserve_as_comments, true)) + CmdArgs.push_back("-fno-preserve-as-comments"); + if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) { CmdArgs.push_back("-mregparm"); CmdArgs.push_back(A->getValue()); @@ -4179,6 +4476,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums, false)) CmdArgs.push_back("-fstrict-enums"); + if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return, + true)) + CmdArgs.push_back("-fno-strict-return"); if (Args.hasFlag(options::OPT_fstrict_vtable_pointers, options::OPT_fno_strict_vtable_pointers, false)) @@ -4293,6 +4593,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (ReciprocalMath) CmdArgs.push_back("-freciprocal-math"); + if (!TrappingMath) + CmdArgs.push_back("-fno-trapping-math"); + + + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, + options::OPT_fno_fast_math, + options::OPT_funsafe_math_optimizations, + options::OPT_fno_unsafe_math_optimizations, + options::OPT_fdenormal_fp_math_EQ)) + if (A->getOption().getID() != options::OPT_fno_fast_math && + A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations) + Args.AddLastArg(CmdArgs, options::OPT_fdenormal_fp_math_EQ); + // Validate and pass through -fp-contract option. if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, @@ -4367,6 +4680,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mms-bitfields"); } + if (Args.hasFlag(options::OPT_mpie_copy_relocations, + options::OPT_mno_pie_copy_relocations, + false)) { + CmdArgs.push_back("-mpie-copy-relocations"); + } + // This is a coarse approximation of what llvm-gcc actually does, both // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more // complicated ways. @@ -4528,6 +4847,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, : "-"); } + bool splitDwarfInlining = + Args.hasFlag(options::OPT_fsplit_dwarf_inlining, + options::OPT_fno_split_dwarf_inlining, true); + Args.ClaimAllArgs(options::OPT_g_Group); Arg *SplitDwarfArg = Args.getLastArg(options::OPT_gsplit_dwarf); if (Arg *A = Args.getLastArg(options::OPT_g_Group)) { @@ -4537,9 +4860,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // If you say "-gsplit-dwarf -gline-tables-only", -gsplit-dwarf loses. // But -gsplit-dwarf is not a g_group option, hence we have to check the // order explicitly. (If -gsplit-dwarf wins, we fix DebugInfoKind later.) - if (SplitDwarfArg && DebugInfoKind < codegenoptions::LimitedDebugInfo && - A->getIndex() > SplitDwarfArg->getIndex()) - SplitDwarfArg = nullptr; + // This gets a bit more complicated if you've disabled inline info in the + // skeleton CUs (splitDwarfInlining) - then there's value in composing + // split-dwarf and line-tables-only, so let those compose naturally in + // that case. + // And if you just turned off debug info, (-gsplit-dwarf -g0) - do that. + if (SplitDwarfArg) { + if (A->getIndex() > SplitDwarfArg->getIndex()) { + if (DebugInfoKind == codegenoptions::NoDebugInfo || + (DebugInfoKind == codegenoptions::DebugLineTablesOnly && + splitDwarfInlining)) + SplitDwarfArg = nullptr; + } else if (splitDwarfInlining) + DebugInfoKind = codegenoptions::NoDebugInfo; + } } else // For any other 'g' option, use Limited. DebugInfoKind = codegenoptions::LimitedDebugInfo; @@ -4574,13 +4908,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // We ignore flags -gstrict-dwarf and -grecord-gcc-switches for now. Args.ClaimAllArgs(options::OPT_g_flags_Group); - // PS4 defaults to no column info + // Column info is included by default for everything except PS4 and CodeView. + // Clang doesn't track end columns, just starting columns, which, in theory, + // is fine for CodeView (and PDB). In practice, however, the Microsoft + // debuggers don't handle missing end columns well, so it's better not to + // include any column info. if (Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info, - /*Default=*/ !IsPS4CPU)) + /*Default=*/ !IsPS4CPU && !(IsWindowsMSVC && EmitCodeView))) CmdArgs.push_back("-dwarf-column-info"); // FIXME: Move backend command line options to the module. - if (Args.hasArg(options::OPT_gmodules)) { + // If -gline-tables-only is the last option it wins. + if (DebugInfoKind != codegenoptions::DebugLineTablesOnly && + Args.hasArg(options::OPT_gmodules)) { DebugInfoKind = codegenoptions::LimitedDebugInfo; CmdArgs.push_back("-dwarf-ext-refs"); CmdArgs.push_back("-fmodule-format=obj"); @@ -4590,7 +4930,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // splitting and extraction. // FIXME: Currently only works on Linux. if (getToolChain().getTriple().isOSLinux() && SplitDwarfArg) { - DebugInfoKind = codegenoptions::LimitedDebugInfo; + if (!splitDwarfInlining) + CmdArgs.push_back("-fno-split-dwarf-inlining"); + if (DebugInfoKind == codegenoptions::NoDebugInfo) + DebugInfoKind = codegenoptions::LimitedDebugInfo; CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-split-dwarf=Enable"); } @@ -4628,11 +4971,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-generate-type-units"); } - // CloudABI and WebAssembly use -ffunction-sections and -fdata-sections by - // default. - bool UseSeparateSections = Triple.getOS() == llvm::Triple::CloudABI || - Triple.getArch() == llvm::Triple::wasm32 || - Triple.getArch() == llvm::Triple::wasm64; + bool UseSeparateSections = isUseSeparateSections(Triple); if (Args.hasFlag(options::OPT_ffunction_sections, options::OPT_fno_function_sections, UseSeparateSections)) { @@ -4652,7 +4991,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_fxray_instrument, options::OPT_fnoxray_instrument, false)) { - CmdArgs.push_back("-fxray-instrument"); + const char *const XRayInstrumentOption = "-fxray-instrument"; + if (Triple.getOS() == llvm::Triple::Linux) + switch (Triple.getArch()) { + case llvm::Triple::x86_64: + case llvm::Triple::arm: + case llvm::Triple::aarch64: + // Supported. + break; + default: + D.Diag(diag::err_drv_clang_unsupported) + << (std::string(XRayInstrumentOption) + " on " + Triple.str()); + } + else + D.Diag(diag::err_drv_clang_unsupported) + << (std::string(XRayInstrumentOption) + " on non-Linux target OS"); + CmdArgs.push_back(XRayInstrumentOption); if (const Arg *A = Args.getLastArg(options::OPT_fxray_instruction_threshold_, options::OPT_fxray_instruction_threshold_EQ)) { @@ -4787,6 +5141,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, claimNoWarnArgs(Args); Args.AddAllArgs(CmdArgs, options::OPT_R_Group); + Args.AddAllArgs(CmdArgs, options::OPT_W_Group); if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false)) CmdArgs.push_back("-pedantic"); @@ -4991,9 +5346,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ); // -fhosted is default. + bool IsHosted = true; if (Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false) || - KernelOrKext) + KernelOrKext) { CmdArgs.push_back("-ffreestanding"); + IsHosted = false; + } // Forward -f (flag) options which we can pass directly. Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); @@ -5014,15 +5372,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type); // Forward flags for OpenMP. We don't do this if the current action is an - // device offloading action. - // - // TODO: Allow OpenMP offload actions when they become available. + // device offloading action other than OpenMP. if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, options::OPT_fno_openmp, false) && - JA.isDeviceOffloading(Action::OFK_None)) { - switch (getOpenMPRuntime(getToolChain(), Args)) { - case OMPRT_OMP: - case OMPRT_IOMP5: + (JA.isDeviceOffloading(Action::OFK_None) || + JA.isDeviceOffloading(Action::OFK_OpenMP))) { + switch (getToolChain().getDriver().getOpenMPRuntime(Args)) { + case Driver::OMPRT_OMP: + case Driver::OMPRT_IOMP5: // Clang can generate useful OpenMP code for these two runtime libraries. CmdArgs.push_back("-fopenmp"); @@ -5127,6 +5484,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } else { StackProtectorLevel = getToolChain().GetDefaultStackProtectorLevel(KernelOrKext); + // Only use a default stack protector on Darwin in case -ffreestanding + // is not specified. + if (Triple.isOSDarwin() && !IsHosted) + StackProtectorLevel = 0; } if (StackProtectorLevel) { CmdArgs.push_back("-stack-protector"); @@ -5232,6 +5593,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.getLastArg(options::OPT_cl_denorms_are_zero)) { CmdArgs.push_back("-cl-denorms-are-zero"); } + if (Args.getLastArg(options::OPT_cl_fp32_correctly_rounded_divide_sqrt)) { + CmdArgs.push_back("-cl-fp32-correctly-rounded-divide-sqrt"); + } // Forward -f options with positive and negative forms; we translate // these by hand. @@ -5287,23 +5651,35 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fblocks-runtime-optional"); } + if (Args.hasFlag(options::OPT_fcoroutines_ts, options::OPT_fno_coroutines_ts, + false) && + types::isCXX(InputType)) { + CmdArgs.push_back("-fcoroutines-ts"); + } + // -fmodules enables the use of precompiled modules (off by default). // Users can pass -fno-cxx-modules to turn off modules support for // C++/Objective-C++ programs. - bool HaveModules = false; + bool HaveClangModules = false; if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) { bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules, options::OPT_fno_cxx_modules, true); if (AllowedInCXX || !types::isCXX(InputType)) { CmdArgs.push_back("-fmodules"); - HaveModules = true; + HaveClangModules = true; } } + bool HaveAnyModules = HaveClangModules; + if (Args.hasArg(options::OPT_fmodules_ts)) { + CmdArgs.push_back("-fmodules-ts"); + HaveAnyModules = true; + } + // -fmodule-maps enables implicit reading of module map files. By default, - // this is enabled if we are using precompiled modules. + // this is enabled if we are using Clang's flavor of precompiled modules. if (Args.hasFlag(options::OPT_fimplicit_module_maps, - options::OPT_fno_implicit_module_maps, HaveModules)) { + options::OPT_fno_implicit_module_maps, HaveClangModules)) { CmdArgs.push_back("-fimplicit-module-maps"); } @@ -5323,9 +5699,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fno-implicit-modules turns off implicitly compiling modules on demand. if (!Args.hasFlag(options::OPT_fimplicit_modules, - options::OPT_fno_implicit_modules)) { - CmdArgs.push_back("-fno-implicit-modules"); - } else if (HaveModules) { + options::OPT_fno_implicit_modules, HaveClangModules)) { + if (HaveAnyModules) + CmdArgs.push_back("-fno-implicit-modules"); + } else if (HaveAnyModules) { // -fmodule-cache-path specifies where our implicitly-built module files // should be written. SmallString<128> Path; @@ -5349,6 +5726,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Path)); } + if (HaveAnyModules) { + // -fprebuilt-module-path specifies where to load the prebuilt module files. + for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path)) + CmdArgs.push_back(Args.MakeArgString( + std::string("-fprebuilt-module-path=") + A->getValue())); + } + // -fmodule-name specifies the module that is currently being built (or // used for header checking by -fmodule-maps). Args.AddLastArg(CmdArgs, options::OPT_fmodule_name_EQ); @@ -5357,15 +5741,27 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // definitions. Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file); + // -fbuiltin-module-map can be used to load the clang + // builtin headers modulemap file. + if (Args.hasArg(options::OPT_fbuiltin_module_map)) { + SmallString<128> BuiltinModuleMap(getToolChain().getDriver().ResourceDir); + llvm::sys::path::append(BuiltinModuleMap, "include"); + llvm::sys::path::append(BuiltinModuleMap, "module.modulemap"); + if (llvm::sys::fs::exists(BuiltinModuleMap)) { + CmdArgs.push_back(Args.MakeArgString("-fmodule-map-file=" + + BuiltinModuleMap)); + } + } + // -fmodule-file can be used to specify files containing precompiled modules. - if (HaveModules) + if (HaveAnyModules) Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file); else Args.ClaimAllArgs(options::OPT_fmodule_file); // When building modules and generating crashdumps, we need to dump a module // dependency VFS alongside the output. - if (HaveModules && C.isForDiagnostics()) { + if (HaveClangModules && C.isForDiagnostics()) { SmallString<128> VFSDir(Output.getFilename()); llvm::sys::path::replace_extension(VFSDir, ".cache"); // Add the cache directory as a temp so the crash diagnostics pick it up. @@ -5376,7 +5772,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(VFSDir)); } - if (HaveModules) + if (HaveClangModules) Args.AddLastArg(CmdArgs, options::OPT_fmodules_user_build_path); // Pass through all -fmodules-ignore-macro arguments. @@ -5394,9 +5790,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, llvm::sys::fs::file_status Status; if (llvm::sys::fs::status(A->getValue(), Status)) D.Diag(diag::err_drv_no_such_file) << A->getValue(); - CmdArgs.push_back(Args.MakeArgString( - "-fbuild-session-timestamp=" + - Twine((uint64_t)Status.getLastModificationTime().toEpochTime()))); + CmdArgs.push_back( + Args.MakeArgString("-fbuild-session-timestamp=" + + Twine((uint64_t)Status.getLastModificationTime() + .time_since_epoch() + .count()))); } if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) { @@ -5409,6 +5807,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } Args.AddLastArg(CmdArgs, options::OPT_fmodules_validate_system_headers); + Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation); // -faccess-control is default. if (Args.hasFlag(options::OPT_fno_access_control, @@ -5475,9 +5874,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_ms_extensions, true)))) CmdArgs.push_back("-fms-compatibility"); - // -fms-compatibility-version=18.00 is default. - VersionTuple MSVT = visualstudio::getMSVCVersion( - &D, getToolChain(), getToolChain().getTriple(), Args, IsWindowsMSVC); + VersionTuple MSVT = + getToolChain().computeMSVCVersion(&getToolChain().getDriver(), Args); if (!MSVT.empty()) CmdArgs.push_back( Args.MakeArgString("-fms-compatibility-version=" + MSVT.getAsString())); @@ -5548,10 +5946,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_inline_functions)) InlineArg->render(Args, CmdArgs); + Args.AddLastArg(CmdArgs, options::OPT_fexperimental_new_pass_manager, + options::OPT_fno_experimental_new_pass_manager); + ObjCRuntime objcRuntime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind); // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and - // legacy is the default. Except for deployment taget of 10.5, + // legacy is the default. Except for deployment target of 10.5, // next runtime is always legacy dispatch and -fno-objc-legacy-dispatch // gets ignored silently. if (objcRuntime.isNonFragile()) { @@ -5613,31 +6014,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (rewriteKind != RK_None) CmdArgs.push_back("-fno-objc-infer-related-result-type"); - // Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only - // takes precedence. - const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only); - if (!GCArg) - GCArg = Args.getLastArg(options::OPT_fobjc_gc); - if (GCArg) { - if (ARC) { - D.Diag(diag::err_drv_objc_gc_arr) << GCArg->getAsString(Args); - } else if (getToolChain().SupportsObjCGC()) { - GCArg->render(Args, CmdArgs); - } else { - // FIXME: We should move this to a hard error. - D.Diag(diag::warn_drv_objc_gc_unsupported) << GCArg->getAsString(Args); - } - } - // Pass down -fobjc-weak or -fno-objc-weak if present. if (types::isObjC(InputType)) { auto WeakArg = Args.getLastArg(options::OPT_fobjc_weak, options::OPT_fno_objc_weak); if (!WeakArg) { // nothing to do - } else if (GCArg) { - if (WeakArg->getOption().matches(options::OPT_fobjc_weak)) - D.Diag(diag::err_objc_weak_with_gc); } else if (!objcRuntime.allowsWeak()) { if (WeakArg->getOption().matches(options::OPT_fobjc_weak)) D.Diag(diag::err_objc_weak_unsupported); @@ -5664,12 +6046,37 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_assume_sane_operator_new)) CmdArgs.push_back("-fno-assume-sane-operator-new"); + // -frelaxed-template-template-args is off by default, as it is a severe + // breaking change until a corresponding change to template partial ordering + // is provided. + if (Args.hasFlag(options::OPT_frelaxed_template_template_args, + options::OPT_fno_relaxed_template_template_args, false)) + CmdArgs.push_back("-frelaxed-template-template-args"); + // -fsized-deallocation is off by default, as it is an ABI-breaking change for // most platforms. if (Args.hasFlag(options::OPT_fsized_deallocation, options::OPT_fno_sized_deallocation, false)) CmdArgs.push_back("-fsized-deallocation"); + // -faligned-allocation is on by default in C++17 onwards and otherwise off + // by default. + if (Arg *A = Args.getLastArg(options::OPT_faligned_allocation, + options::OPT_fno_aligned_allocation, + options::OPT_faligned_new_EQ)) { + if (A->getOption().matches(options::OPT_fno_aligned_allocation)) + CmdArgs.push_back("-fno-aligned-allocation"); + else + CmdArgs.push_back("-faligned-allocation"); + } + + // The default new alignment can be specified using a dedicated option or via + // a GCC-compatible option that also turns on aligned allocation. + if (Arg *A = Args.getLastArg(options::OPT_fnew_alignment_EQ, + options::OPT_faligned_new_EQ)) + CmdArgs.push_back( + Args.MakeArgString(Twine("-fnew-alignment=") + A->getValue())); + // -fconstant-cfstrings is default, and may be subject to argument translation // on Darwin. if (!Args.hasFlag(options::OPT_fconstant_cfstrings, @@ -5737,7 +6144,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -finput_charset=UTF-8 is default. Reject others if (Arg *inputCharset = Args.getLastArg(options::OPT_finput_charset_EQ)) { StringRef value = inputCharset->getValue(); - if (value != "UTF-8") + if (!value.equals_lower("utf-8")) D.Diag(diag::err_drv_invalid_value) << inputCharset->getAsString(Args) << value; } @@ -5745,7 +6152,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fexec_charset=UTF-8 is default. Reject others if (Arg *execCharset = Args.getLastArg(options::OPT_fexec_charset_EQ)) { StringRef value = execCharset->getValue(); - if (value != "UTF-8") + if (!value.equals_lower("utf-8")) D.Diag(diag::err_drv_invalid_value) << execCharset->getAsString(Args) << value; } @@ -5771,6 +6178,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } + if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness, + options::OPT_fno_diagnostics_show_hotness, false)) + CmdArgs.push_back("-fdiagnostics-show-hotness"); + if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) { CmdArgs.push_back("-fdiagnostics-format"); CmdArgs.push_back(A->getValue()); @@ -5816,6 +6227,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_show_source_location)) CmdArgs.push_back("-fno-show-source-location"); + if (Args.hasArg(options::OPT_fdiagnostics_absolute_paths)) + CmdArgs.push_back("-fdiagnostics-absolute-paths"); + if (!Args.hasFlag(options::OPT_fshow_column, options::OPT_fno_show_column, true)) CmdArgs.push_back("-fno-show-column"); @@ -5893,6 +6307,40 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fno-math-builtin"); } + if (Args.hasFlag(options::OPT_fsave_optimization_record, + options::OPT_fno_save_optimization_record, false)) { + CmdArgs.push_back("-opt-record-file"); + + const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); + if (A) { + CmdArgs.push_back(A->getValue()); + } else { + SmallString<128> F; + if (Output.isFilename() && (Args.hasArg(options::OPT_c) || + Args.hasArg(options::OPT_S))) { + F = Output.getFilename(); + } else { + // Use the input filename. + F = llvm::sys::path::stem(Input.getBaseInput()); + + // If we're compiling for an offload architecture (i.e. a CUDA device), + // we need to make the file name for the device compilation different + // from the host compilation. + if (!JA.isDeviceOffloading(Action::OFK_None) && + !JA.isDeviceOffloading(Action::OFK_Host)) { + llvm::sys::path::replace_extension(F, ""); + F += Action::GetOffloadingFileNamePrefix(JA.getOffloadingDeviceKind(), + Triple.normalize()); + F += "-"; + F += JA.getOffloadingArch(); + } + } + + llvm::sys::path::replace_extension(F, "opt.yaml"); + CmdArgs.push_back(Args.MakeArgString(F)); + } + } + // Default to -fno-builtin-str{cat,cpy} on Darwin for ARM. // // FIXME: Now that PR4941 has been fixed this can be enabled. @@ -5913,7 +6361,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // nice to enable this when doing a crashdump for modules as well. if (Args.hasFlag(options::OPT_frewrite_includes, options::OPT_fno_rewrite_includes, false) || - (C.isForDiagnostics() && !HaveModules)) + (C.isForDiagnostics() && !HaveAnyModules)) CmdArgs.push_back("-frewrite-includes"); // Only allow -traditional or -traditional-cpp outside in preprocessing modes. @@ -5949,6 +6397,33 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->claim(); } + // Setup statistics file output. + if (const Arg *A = Args.getLastArg(options::OPT_save_stats_EQ)) { + StringRef SaveStats = A->getValue(); + + SmallString<128> StatsFile; + bool DoSaveStats = false; + if (SaveStats == "obj") { + if (Output.isFilename()) { + StatsFile.assign(Output.getFilename()); + llvm::sys::path::remove_filename(StatsFile); + } + DoSaveStats = true; + } else if (SaveStats == "cwd") { + DoSaveStats = true; + } else { + D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << SaveStats; + } + + if (DoSaveStats) { + StringRef BaseName = llvm::sys::path::filename(Input.getBaseInput()); + llvm::sys::path::append(StatsFile, BaseName); + llvm::sys::path::replace_extension(StatsFile, "stats"); + CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + + StatsFile)); + } + } + // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option // parser. Args.AddAllArgValues(CmdArgs, options::OPT_Xclang); @@ -5956,11 +6431,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->claim(); // We translate this by hand to the -cc1 argument, since nightly test uses - // it and developers have been trained to spell it with -mllvm. + // it and developers have been trained to spell it with -mllvm. Both + // spellings are now deprecated and should be removed. if (StringRef(A->getValue(0)) == "-disable-llvm-optzns") { CmdArgs.push_back("-disable-llvm-optzns"); - } else + } else { A->render(Args, CmdArgs); + } } // With -save-temps, we want to save the unoptimized bitcode output from the @@ -5972,7 +6449,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // pristine IR generated by the frontend. Ideally, a new compile action should // be added so both IR can be captured. if (C.getDriver().isSaveTempsEnabled() && - !C.getDriver().embedBitcodeEnabled() && isa<CompileJobAction>(JA)) + !C.getDriver().embedBitcodeInObject() && isa<CompileJobAction>(JA)) CmdArgs.push_back("-disable-llvm-passes"); if (Output.getType() == types::TY_Dependencies) { @@ -6034,6 +6511,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(I->getFilename()); } + // OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path + // to specify the result of the compile phase on the host, so the meaningful + // device declarations can be identified. Also, -fopenmp-is-device is passed + // along to tell the frontend that it is generating code for a device, so that + // only the relevant declarations are emitted. + if (IsOpenMPDevice && Inputs.size() == 2) { + CmdArgs.push_back("-fopenmp-is-device"); + CmdArgs.push_back("-fopenmp-host-ir-file-path"); + CmdArgs.push_back(Args.MakeArgString(Inputs.back().getFilename())); + } + + // For all the host OpenMP offloading compile jobs we need to pass the targets + // information using -fopenmp-targets= option. + if (isa<CompileJobAction>(JA) && JA.isHostOffloading(Action::OFK_OpenMP)) { + SmallString<128> TargetInfo("-fopenmp-targets="); + + Arg *Tgts = Args.getLastArg(options::OPT_fopenmp_targets_EQ); + assert(Tgts && Tgts->getNumValues() && + "OpenMP offloading has to have targets specified."); + for (unsigned i = 0; i < Tgts->getNumValues(); ++i) { + if (i) + TargetInfo += ','; + // We need to get the string from the triple because it may be not exactly + // the same as the one we get directly from the arguments. + llvm::Triple T(Tgts->getValue(i)); + TargetInfo += T.getTriple(); + } + CmdArgs.push_back(Args.MakeArgString(TargetInfo.str())); + } + bool WholeProgramVTables = Args.hasFlag(options::OPT_fwhole_program_vtables, options::OPT_fno_whole_program_vtables, false); @@ -6458,6 +6965,20 @@ void ClangAs::AddMIPSTargetArgs(const ArgList &Args, CmdArgs.push_back(ABIName.data()); } +void ClangAs::AddX86TargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) { + StringRef Value = A->getValue(); + if (Value == "intel" || Value == "att") { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); + } else { + getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; + } + } +} + void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, @@ -6467,9 +6988,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, assert(Inputs.size() == 1 && "Unexpected number of inputs."); const InputInfo &Input = Inputs[0]; - std::string TripleStr = - getToolChain().ComputeEffectiveClangTriple(Args, Input.getType()); - const llvm::Triple Triple(TripleStr); + const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); + const std::string &TripleStr = Triple.getTriple(); // Don't warn about "clang -w -c foo.s" Args.ClaimAllArgs(options::OPT_w); @@ -6564,7 +7084,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, unsigned PICLevel; bool IsPIE; std::tie(RelocationModel, PICLevel, IsPIE) = - ParsePICArgs(getToolChain(), Triple, Args); + ParsePICArgs(getToolChain(), Args); const char *RMName = RelocationModelName(RelocationModel); if (RMName) { @@ -6605,6 +7125,11 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::mips64el: AddMIPSTargetArgs(Args, CmdArgs); break; + + case llvm::Triple::x86: + case llvm::Triple::x86_64: + AddX86TargetArgs(Args, CmdArgs); + break; } // Consume all the warning flags. Usually this would be handled more @@ -6638,6 +7163,134 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, SplitDebugName(Args, Input)); } +void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const { + // The version with only one output is expected to refer to a bundling job. + assert(isa<OffloadBundlingJobAction>(JA) && "Expecting bundling job!"); + + // The bundling command looks like this: + // clang-offload-bundler -type=bc + // -targets=host-triple,openmp-triple1,openmp-triple2 + // -outputs=input_file + // -inputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2" + + ArgStringList CmdArgs; + + // Get the type. + CmdArgs.push_back(TCArgs.MakeArgString( + Twine("-type=") + types::getTypeTempSuffix(Output.getType()))); + + assert(JA.getInputs().size() == Inputs.size() && + "Not have inputs for all dependence actions??"); + + // Get the targets. + SmallString<128> Triples; + Triples += "-targets="; + for (unsigned I = 0; I < Inputs.size(); ++I) { + if (I) + Triples += ','; + + Action::OffloadKind CurKind = Action::OFK_Host; + const ToolChain *CurTC = &getToolChain(); + const Action *CurDep = JA.getInputs()[I]; + + if (const auto *OA = dyn_cast<OffloadAction>(CurDep)) { + OA->doOnEachDependence([&](Action *A, const ToolChain *TC, const char *) { + CurKind = A->getOffloadingDeviceKind(); + CurTC = TC; + }); + } + Triples += Action::GetOffloadKindName(CurKind); + Triples += '-'; + Triples += CurTC->getTriple().normalize(); + } + CmdArgs.push_back(TCArgs.MakeArgString(Triples)); + + // Get bundled file command. + CmdArgs.push_back( + TCArgs.MakeArgString(Twine("-outputs=") + Output.getFilename())); + + // Get unbundled files command. + SmallString<128> UB; + UB += "-inputs="; + for (unsigned I = 0; I < Inputs.size(); ++I) { + if (I) + UB += ','; + UB += Inputs[I].getFilename(); + } + CmdArgs.push_back(TCArgs.MakeArgString(UB)); + + // All the inputs are encoded as commands. + C.addCommand(llvm::make_unique<Command>( + JA, *this, + TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), + CmdArgs, None)); +} + +void OffloadBundler::ConstructJobMultipleOutputs( + Compilation &C, const JobAction &JA, const InputInfoList &Outputs, + const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const { + // The version with multiple outputs is expected to refer to a unbundling job. + auto &UA = cast<OffloadUnbundlingJobAction>(JA); + + // The unbundling command looks like this: + // clang-offload-bundler -type=bc + // -targets=host-triple,openmp-triple1,openmp-triple2 + // -inputs=input_file + // -outputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2" + // -unbundle + + ArgStringList CmdArgs; + + assert(Inputs.size() == 1 && "Expecting to unbundle a single file!"); + InputInfo Input = Inputs.front(); + + // Get the type. + CmdArgs.push_back(TCArgs.MakeArgString( + Twine("-type=") + types::getTypeTempSuffix(Input.getType()))); + + // Get the targets. + SmallString<128> Triples; + Triples += "-targets="; + auto DepInfo = UA.getDependentActionsInfo(); + for (unsigned I = 0; I < DepInfo.size(); ++I) { + if (I) + Triples += ','; + + auto &Dep = DepInfo[I]; + Triples += Action::GetOffloadKindName(Dep.DependentOffloadKind); + Triples += '-'; + Triples += Dep.DependentToolChain->getTriple().normalize(); + } + + CmdArgs.push_back(TCArgs.MakeArgString(Triples)); + + // Get bundled file command. + CmdArgs.push_back( + TCArgs.MakeArgString(Twine("-inputs=") + Input.getFilename())); + + // Get unbundled files command. + SmallString<128> UB; + UB += "-outputs="; + for (unsigned I = 0; I < Outputs.size(); ++I) { + if (I) + UB += ','; + UB += Outputs[I].getFilename(); + } + CmdArgs.push_back(TCArgs.MakeArgString(UB)); + CmdArgs.push_back("-unbundle"); + + // All the inputs are encoded as commands. + C.addCommand(llvm::make_unique<Command>( + JA, *this, + TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), + CmdArgs, None)); +} + void GnuTool::anchor() {} void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, @@ -7015,7 +7668,7 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, {options::OPT_T_Group, options::OPT_e, options::OPT_s, options::OPT_t, options::OPT_u_Group}); - AddLinkerInputs(HTC, Inputs, Args, CmdArgs); + AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); //---------------------------------------------------------------------------- // Libraries @@ -7074,7 +7727,7 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, std::string Linker = getToolChain().GetProgramPath(getShortName()); ArgStringList CmdArgs; - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); CmdArgs.push_back("-shared"); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); @@ -7137,7 +7790,7 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); } - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) @@ -7390,11 +8043,14 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) { void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) { const llvm::Triple::ArchType Arch = getArchTypeForMachOArchName(Str); + unsigned ArchKind = llvm::ARM::parseArch(Str); T.setArch(Arch); if (Str == "x86_64h") T.setArchName(Str); - else if (Str == "armv6m" || Str == "armv7m" || Str == "armv7em") { + else if (ArchKind == llvm::ARM::AK_ARMV6M || + ArchKind == llvm::ARM::AK_ARMV7M || + ArchKind == llvm::ARM::AK_ARMV7EM) { T.setOS(llvm::Triple::UnknownOS); T.setObjectFormat(llvm::Triple::MachO); } @@ -7481,9 +8137,9 @@ void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); if (D.isUsingLTO()) - AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin); + AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) @@ -7593,6 +8249,29 @@ bool darwin::Linker::NeedsTempPath(const InputInfoList &Inputs) const { return false; } +/// \brief Pass -no_deduplicate to ld64 under certain conditions: +/// +/// - Either -O0 or -O1 is explicitly specified +/// - No -O option is specified *and* this is a compile+link (implicit -O0) +/// +/// Also do *not* add -no_deduplicate when no -O option is specified and this +/// is just a link (we can't imply -O0) +static bool shouldLinkerNotDedup(bool IsLinkerOnlyAction, const ArgList &Args) { + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + if (A->getOption().matches(options::OPT_O0)) + return true; + if (A->getOption().matches(options::OPT_O)) + return llvm::StringSwitch<bool>(A->getValue()) + .Case("1", true) + .Default(false); + return false; // OPT_Ofast & OPT_O4 + } + + if (!IsLinkerOnlyAction) // Implicit -O0 for compile+linker only. + return true; + return false; +} + void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, ArgStringList &CmdArgs, const InputInfoList &Inputs) const { @@ -7649,6 +8328,10 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, CmdArgs.push_back(C.getArgs().MakeArgString(LibLTOPath)); } + // ld64 version 262 and above run the deduplicate pass by default. + if (Version[0] >= 262 && shouldLinkerNotDedup(C.getJobs().empty(), Args)) + CmdArgs.push_back("-no_deduplicate"); + // Derived from the "link" spec. Args.AddAllArgs(CmdArgs, options::OPT_static); if (!Args.hasArg(options::OPT_static)) @@ -7735,9 +8418,9 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, else CmdArgs.push_back("-no_pie"); } + // for embed-bitcode, use -bitcode_bundle in linker command - if (C.getDriver().embedBitcodeEnabled() || - C.getDriver().embedBitcodeMarkerOnly()) { + if (C.getDriver().embedBitcodeEnabled()) { // Check if the toolchain supports bitcode build flow. if (MachOTC.SupportsEmbeddedBitcode()) CmdArgs.push_back("-bitcode_bundle"); @@ -7830,6 +8513,24 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, // we follow suite for ease of comparison. AddLinkArgs(C, Args, CmdArgs, Inputs); + // For LTO, pass the name of the optimization record file. + if (Args.hasFlag(options::OPT_fsave_optimization_record, + options::OPT_fno_save_optimization_record, false)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-lto-pass-remarks-output"); + CmdArgs.push_back("-mllvm"); + + SmallString<128> F; + F = Output.getFilename(); + F += ".opt.yaml"; + CmdArgs.push_back(Args.MakeArgString(F)); + + if (getLastProfileUseArg(Args)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-lto-pass-remarks-with-hotness"); + } + } + // It seems that the 'e' option is completely ignored for dynamic executables // (the default), and with static executables, the last one wins, as expected. Args.AddAllArgs(CmdArgs, {options::OPT_d_Flag, options::OPT_s, options::OPT_t, @@ -7859,7 +8560,7 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); // Build the input file for -filelist (list of linker input files) in case we // need it later for (const auto &II : Inputs) { @@ -7902,6 +8603,13 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, getMachOToolChain().addProfileRTLibs(Args, CmdArgs); + if (unsigned Parallelism = + getLTOParallelism(Args, getToolChain().getDriver())) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back( + Args.MakeArgString(Twine("-threads=") + llvm::to_string(Parallelism))); + } + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (getToolChain().getDriver().CCCIsCXX()) getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); @@ -8077,7 +8785,7 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, options::OPT_e, options::OPT_r}); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (getToolChain().getDriver().CCCIsCXX()) @@ -8229,6 +8937,10 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("gcrt0.o"))); + else if (Args.hasArg(options::OPT_static) && + !Args.hasArg(options::OPT_nopie)) + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("rcrt0.o"))); else CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crt0.o"))); @@ -8250,7 +8962,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_e, options::OPT_s, options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { @@ -8369,7 +9081,7 @@ void bitrig::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, options::OPT_e}); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { @@ -8632,10 +9344,10 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_r); if (D.isUsingLTO()) - AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin); + AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { addOpenMPRuntime(CmdArgs, ToolChain, Args); @@ -8842,9 +9554,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, break; case llvm::Triple::armeb: case llvm::Triple::thumbeb: - arm::appendEBLinkFlags( - Args, CmdArgs, - llvm::Triple(getToolChain().ComputeEffectiveClangTriple(Args))); + arm::appendEBLinkFlags(Args, CmdArgs, getToolChain().getEffectiveTriple()); CmdArgs.push_back("-m"); switch (getToolChain().getTriple().getEnvironment()) { case llvm::Triple::EABI: @@ -8932,7 +9642,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); unsigned Major, Minor, Micro; getToolChain().getTriple().getOSVersion(Major, Minor, Micro); @@ -8940,6 +9650,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Major >= 7 || Major == 0) { switch (getToolChain().getArch()) { case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: @@ -9008,16 +9719,13 @@ void gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { claimNoWarnArgs(Args); - std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); - llvm::Triple Triple = llvm::Triple(TripleStr); - ArgStringList CmdArgs; llvm::Reloc::Model RelocationModel; unsigned PICLevel; bool IsPIE; std::tie(RelocationModel, PICLevel, IsPIE) = - ParsePICArgs(getToolChain(), Triple, Args); + ParsePICArgs(getToolChain(), Args); switch (getToolChain().getArch()) { default: @@ -9100,7 +9808,7 @@ void gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA, // march from being picked in the absence of a cpu flag. Arg *A; if ((A = Args.getLastArg(options::OPT_mcpu_EQ)) && - StringRef(A->getValue()).lower() == "krait") + StringRef(A->getValue()).equals_lower("krait")) CmdArgs.push_back("-mcpu=cortex-a15"); else Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ); @@ -9266,6 +9974,7 @@ static void AddRunTimeLibs(const ToolChain &TC, const Driver &D, llvm_unreachable("unsupported OS"); case llvm::Triple::Win32: case llvm::Triple::Linux: + case llvm::Triple::Fuchsia: addClangRT(TC, Args, CmdArgs); break; } @@ -9331,7 +10040,7 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { return "elf32_x86_64"; return "elf_x86_64"; default: - llvm_unreachable("Unexpected arch"); + return nullptr; } } @@ -9344,8 +10053,7 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, static_cast<const toolchains::Linux &>(getToolChain()); const Driver &D = ToolChain.getDriver(); - std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); - llvm::Triple Triple = llvm::Triple(TripleStr); + const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); const llvm::Triple::ArchType Arch = ToolChain.getArch(); const bool isAndroid = ToolChain.getTriple().isAndroid(); @@ -9390,6 +10098,14 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Arch == llvm::Triple::armeb || Arch == llvm::Triple::thumbeb) arm::appendEBLinkFlags(Args, CmdArgs, Triple); + // Most Android ARM64 targets should enable the linker fix for erratum + // 843419. Only non-Cortex-A53 devices are allowed to skip this flag. + if (Arch == llvm::Triple::aarch64 && isAndroid) { + std::string CPU = getCPUName(Args, Triple); + if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53") + CmdArgs.push_back("--fix-cortex-a53-843419"); + } + for (const auto &Opt : ToolChain.ExtraOpts) CmdArgs.push_back(Opt.c_str()); @@ -9397,8 +10113,13 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--eh-frame-hdr"); } - CmdArgs.push_back("-m"); - CmdArgs.push_back(getLDMOption(ToolChain.getTriple(), Args)); + if (const char *LDMOption = getLDMOption(ToolChain.getTriple(), Args)) { + CmdArgs.push_back("-m"); + CmdArgs.push_back(LDMOption); + } else { + D.Diag(diag::err_target_unknown_triple) << Triple.str(); + return; + } if (Args.hasArg(options::OPT_static)) { if (Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb || @@ -9469,14 +10190,14 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, ToolChain.AddFilePathLibArgs(Args, CmdArgs); if (D.isUsingLTO()) - AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin); + AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); // The profile runtime also needs access to system libraries. getToolChain().addProfileRTLibs(Args, CmdArgs); @@ -9515,24 +10236,26 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, WantPthread = true; // Also link the particular OpenMP runtimes. - switch (getOpenMPRuntime(ToolChain, Args)) { - case OMPRT_OMP: + switch (ToolChain.getDriver().getOpenMPRuntime(Args)) { + case Driver::OMPRT_OMP: CmdArgs.push_back("-lomp"); break; - case OMPRT_GOMP: + case Driver::OMPRT_GOMP: CmdArgs.push_back("-lgomp"); // FIXME: Exclude this for platforms with libgomp that don't require // librt. Most modern Linux platforms require it, but some may not. CmdArgs.push_back("-lrt"); break; - case OMPRT_IOMP5: + case Driver::OMPRT_IOMP5: CmdArgs.push_back("-liomp5"); break; - case OMPRT_Unknown: + case Driver::OMPRT_Unknown: // Already diagnosed. break; } + if (JA.isHostOffloading(Action::OFK_OpenMP)) + CmdArgs.push_back("-lomptarget"); } AddRunTimeLibs(ToolChain, D, CmdArgs, Args); @@ -9578,6 +10301,9 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } + // Add OpenMP offloading linker script args if required. + AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } @@ -9687,7 +10413,7 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { @@ -9753,6 +10479,112 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } +void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const toolchains::Fuchsia &ToolChain = + static_cast<const toolchains::Fuchsia &>(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); + + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); + if (llvm::sys::path::stem(Exec).equals_lower("lld")) { + CmdArgs.push_back("-flavor"); + CmdArgs.push_back("gnu"); + } + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r)) + CmdArgs.push_back("-pie"); + + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + + if (Args.hasArg(options::OPT_s)) + CmdArgs.push_back("-s"); + + if (Args.hasArg(options::OPT_r)) + CmdArgs.push_back("-r"); + else + CmdArgs.push_back("--build-id"); + + if (!Args.hasArg(options::OPT_static)) + CmdArgs.push_back("--eh-frame-hdr"); + + if (Args.hasArg(options::OPT_static)) + CmdArgs.push_back("-Bstatic"); + else if (Args.hasArg(options::OPT_shared)) + CmdArgs.push_back("-shared"); + + if (!Args.hasArg(options::OPT_static)) { + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + + if (!Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back("-dynamic-linker"); + CmdArgs.push_back(Args.MakeArgString(D.DyldPrefix + "ld.so.1")); + } + } + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o"))); + } + } + + Args.AddAllArgs(CmdArgs, options::OPT_L); + Args.AddAllArgs(CmdArgs, options::OPT_u); + + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (Args.hasArg(options::OPT_static)) + CmdArgs.push_back("-Bdynamic"); + + if (D.CCCIsCXX()) { + bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && + !Args.hasArg(options::OPT_static); + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bstatic"); + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bdynamic"); + CmdArgs.push_back("-lm"); + } + + AddRunTimeLibs(ToolChain, D, CmdArgs, Args); + + if (Args.hasArg(options::OPT_pthread) || + Args.hasArg(options::OPT_pthreads)) + CmdArgs.push_back("-lpthread"); + + if (Args.hasArg(options::OPT_fsplit_stack)) + CmdArgs.push_back("--wrap=pthread_create"); + + CmdArgs.push_back("-lc"); + } + + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + void minix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -9799,7 +10631,7 @@ void minix::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, options::OPT_e}); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); getToolChain().addProfileRTLibs(Args, CmdArgs); @@ -9920,7 +10752,7 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, options::OPT_e}); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { CmdArgs.push_back("-L/usr/lib/gcc50"); @@ -10043,14 +10875,14 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, std::string UniversalCRTLibPath; if (MSVC.getUniversalCRTLibraryPath(UniversalCRTLibPath)) CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + - UniversalCRTLibPath.c_str())); + UniversalCRTLibPath)); } } std::string WindowsSdkLibPath; if (MSVC.getWindowsSDKLibraryPath(WindowsSdkLibPath)) - CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + - WindowsSdkLibPath.c_str())); + CmdArgs.push_back( + Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath)); } if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L)) @@ -10076,12 +10908,16 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (TC.getSanitizerArgs().needsAsanRt()) { CmdArgs.push_back(Args.MakeArgString("-debug")); CmdArgs.push_back(Args.MakeArgString("-incremental:no")); - if (Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) { + if (TC.getSanitizerArgs().needsSharedAsanRt() || + Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) { for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"}) CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); // Make sure the dynamic runtime thunk is not optimized out at link time // to ensure proper SEH handling. - CmdArgs.push_back(Args.MakeArgString("-include:___asan_seh_interceptor")); + CmdArgs.push_back(Args.MakeArgString( + TC.getArch() == llvm::Triple::x86 + ? "-include:___asan_seh_interceptor" + : "-include:__asan_seh_interceptor")); } else if (DLL) { CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk")); } else { @@ -10098,16 +10934,16 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-nodefaultlib:vcompd.lib"); CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + TC.getDriver().Dir + "/../lib")); - switch (getOpenMPRuntime(getToolChain(), Args)) { - case OMPRT_OMP: + switch (TC.getDriver().getOpenMPRuntime(Args)) { + case Driver::OMPRT_OMP: CmdArgs.push_back("-defaultlib:libomp.lib"); break; - case OMPRT_IOMP5: + case Driver::OMPRT_IOMP5: CmdArgs.push_back("-defaultlib:libiomp5md.lib"); break; - case OMPRT_GOMP: + case Driver::OMPRT_GOMP: break; - case OMPRT_Unknown: + case Driver::OMPRT_Unknown: // Already diagnosed. break; } @@ -10265,6 +11101,14 @@ std::unique_ptr<Command> visualstudio::Compiler::GetCommand( options::OPT__SLASH_MT, options::OPT__SLASH_MTd)) A->render(Args, CmdArgs); + // Use MSVC's default threadsafe statics behaviour unless there was a flag. + if (Arg *A = Args.getLastArg(options::OPT_fthreadsafe_statics, + options::OPT_fno_threadsafe_statics)) { + CmdArgs.push_back(A->getOption().getID() == options::OPT_fthreadsafe_statics + ? "/Zc:threadSafeInit" + : "/Zc:threadSafeInit-"); + } + // Pass through all unknown arguments so that the fallback command can see // them too. Args.AddAllArgs(CmdArgs, options::OPT_UNKNOWN); @@ -10447,7 +11291,7 @@ void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); TC.AddFilePathLibArgs(Args, CmdArgs); - AddLinkerInputs(TC, Inputs, Args, CmdArgs); + AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); // TODO: Add ASan stuff here @@ -10571,7 +11415,7 @@ void XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA, false)) CmdArgs.push_back("-fexceptions"); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc")); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); @@ -10725,7 +11569,7 @@ void CrossWindows::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); TC.AddFilePathLibArgs(Args, CmdArgs); - AddLinkerInputs(TC, Inputs, Args, CmdArgs); + AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { @@ -10791,12 +11635,14 @@ void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA, // Append all -I, -iquote, -isystem paths, defines/undefines, // 'f' flags, optimize flags, and warning options. // These are spelled the same way in clang and moviCompile. - Args.AddAllArgs(CmdArgs, {options::OPT_I_Group, options::OPT_clang_i_Group, - options::OPT_std_EQ, options::OPT_D, options::OPT_U, - options::OPT_f_Group, options::OPT_f_clang_Group, - options::OPT_g_Group, options::OPT_M_Group, - options::OPT_O_Group, options::OPT_W_Group, - options::OPT_mcpu_EQ}); + Args.AddAllArgsExcept( + CmdArgs, + {options::OPT_I_Group, options::OPT_clang_i_Group, options::OPT_std_EQ, + options::OPT_D, options::OPT_U, options::OPT_f_Group, + options::OPT_f_clang_Group, options::OPT_g_Group, options::OPT_M_Group, + options::OPT_O_Group, options::OPT_W_Group, options::OPT_mcpu_EQ}, + {options::OPT_fno_split_dwarf_inlining}); + Args.hasArg(options::OPT_fno_split_dwarf_inlining); // Claim it if present. // If we're producing a dependency file, and assembly is the final action, // then the name of the target in the dependency file should be the '.o' @@ -10872,6 +11718,8 @@ void tools::Myriad::Linker::ConstructJob(Compilation &C, const JobAction &JA, !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); bool UseDefaultLibs = !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs); + // Silence warning if the args contain both -nostdlib and -stdlib=. + Args.getLastArg(options::OPT_stdlib_EQ); if (T.getArch() == llvm::Triple::sparc) CmdArgs.push_back("-EB"); @@ -10906,22 +11754,31 @@ void tools::Myriad::Linker::ConstructJob(Compilation &C, const JobAction &JA, TC.AddFilePathLibArgs(Args, CmdArgs); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + bool NeedsSanitizerDeps = addSanitizerRuntimes(TC, Args, CmdArgs); + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); if (UseDefaultLibs) { - if (C.getDriver().CCCIsCXX()) - CmdArgs.push_back("-lstdc++"); + if (NeedsSanitizerDeps) + linkSanitizerRuntimeDeps(TC, CmdArgs); + if (C.getDriver().CCCIsCXX()) { + if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) { + CmdArgs.push_back("-lc++"); + CmdArgs.push_back("-lc++abi"); + } else + CmdArgs.push_back("-lstdc++"); + } if (T.getOS() == llvm::Triple::RTEMS) { CmdArgs.push_back("--start-group"); CmdArgs.push_back("-lc"); + CmdArgs.push_back("-lgcc"); // circularly dependent on rtems // You must provide your own "-L" option to enable finding these. CmdArgs.push_back("-lrtemscpu"); CmdArgs.push_back("-lrtemsbsp"); CmdArgs.push_back("--end-group"); } else { CmdArgs.push_back("-lc"); + CmdArgs.push_back("-lgcc"); } - CmdArgs.push_back("-lgcc"); } if (UseStartfiles) { CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); @@ -11015,7 +11872,7 @@ static void ConstructPS4LinkJob(const Tool &T, Compilation &C, if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (Args.hasArg(options::OPT_pthread)) { CmdArgs.push_back("-lpthread"); @@ -11111,7 +11968,7 @@ static void ConstructGoldLinkJob(const Tool &T, Compilation &C, if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { // For PS4, we always want to pass libm, libstdc++ and libkernel @@ -11247,7 +12104,7 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA, // Check that our installation's ptxas supports gpu_arch. if (!Args.hasArg(options::OPT_no_cuda_version_check)) { - TC.cudaInstallation().CheckCudaVersionSupportsArch(gpu_arch); + TC.CudaInstallation.CheckCudaVersionSupportsArch(gpu_arch); } ArgStringList CmdArgs; @@ -11300,7 +12157,11 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA, for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_ptxas)) CmdArgs.push_back(Args.MakeArgString(A)); - const char *Exec = Args.MakeArgString(TC.GetProgramPath("ptxas")); + const char *Exec; + if (Arg *A = Args.getLastArg(options::OPT_ptxas_path_EQ)) + Exec = A->getValue(); + else + Exec = Args.MakeArgString(TC.GetProgramPath("ptxas")); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } @@ -11347,3 +12208,19 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(TC.GetProgramPath("fatbinary")); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } + +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. diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.h b/contrib/llvm/tools/clang/lib/Driver/Tools.h index 02bdb8e..9d5b892 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.h +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.h @@ -17,6 +17,7 @@ #include "clang/Driver/Util.h" #include "llvm/ADT/Triple.h" #include "llvm/Option/Option.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Compiler.h" namespace clang { @@ -101,6 +102,12 @@ private: mutable std::unique_ptr<visualstudio::Compiler> CLFallback; + mutable std::unique_ptr<llvm::raw_fd_ostream> CompilationDatabase = nullptr; + void DumpCompilationDatabase(Compilation &C, StringRef Filename, + StringRef Target, + const InputInfo &Output, const InputInfo &Input, + const llvm::opt::ArgList &Args) const; + public: // CAUTION! The first constructor argument ("clang") is not arbitrary, // as it is for other tools. Some operations on a Tool actually test @@ -125,6 +132,8 @@ public: : Tool("clang::as", "clang integrated assembler", TC, RF_Full) {} void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + void AddX86TargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; bool hasGoodDiagnostics() const override { return true; } bool hasIntegratedAssembler() const override { return false; } bool hasIntegratedCPP() const override { return false; } @@ -135,6 +144,24 @@ public: const char *LinkingOutput) const override; }; +/// Offload bundler tool. +class LLVM_LIBRARY_VISIBILITY OffloadBundler final : public Tool { +public: + OffloadBundler(const ToolChain &TC) + : Tool("offload bundler", "clang-offload-bundler", 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; + void ConstructJobMultipleOutputs(Compilation &C, const JobAction &JA, + const InputInfoList &Outputs, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + /// \brief Base class for all GNU tools that provide the same behavior when /// it comes to response files support class LLVM_LIBRARY_VISIBILITY GnuTool : public Tool { @@ -594,6 +621,21 @@ public: }; } // end namespace nacltools +namespace fuchsia { +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: + Linker(const ToolChain &TC) : GnuTool("fuchsia::Linker", "ld.lld", 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 fuchsia + /// minix -- Directly call GNU Binutils assembler and linker namespace minix { class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { @@ -683,10 +725,6 @@ public: /// Visual studio tools. namespace visualstudio { -VersionTuple getMSVCVersion(const Driver *D, const ToolChain &TC, - const llvm::Triple &Triple, - const llvm::opt::ArgList &Args, bool IsWindowsMSVC); - class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: Linker(const ToolChain &TC) @@ -952,6 +990,19 @@ class LLVM_LIBRARY_VISIBILITY Linker : public Tool { } // end namespace NVPTX +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 diff --git a/contrib/llvm/tools/clang/lib/Driver/Types.cpp b/contrib/llvm/tools/clang/lib/Driver/Types.cpp index f8e1e40..ab63f0e 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Types.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Types.cpp @@ -44,13 +44,28 @@ types::ID types::getPreprocessedType(ID Id) { return getInfo(Id).PreprocessedType; } +types::ID types::getPrecompiledType(ID Id) { + if (strchr(getInfo(Id).Flags, 'm')) + return TY_ModuleFile; + if (onlyPrecompileType(Id)) + return TY_PCH; + return TY_INVALID; +} + const char *types::getTypeTempSuffix(ID Id, bool CLMode) { - if (Id == TY_Object && CLMode) - return "obj"; - if (Id == TY_Image && CLMode) - return "exe"; - if (Id == TY_PP_Asm && CLMode) - return "asm"; + if (CLMode) { + switch (Id) { + case TY_Object: + case TY_LTO_BC: + return "obj"; + case TY_Image: + return "exe"; + case TY_PP_Asm: + return "asm"; + default: + break; + } + } return getInfo(Id).TempSuffix; } @@ -95,6 +110,7 @@ bool types::isAcceptedByClang(ID Id) { case TY_ObjCHeader: case TY_PP_ObjCHeader: case TY_CXXHeader: case TY_PP_CXXHeader: case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: + case TY_CXXModule: case TY_PP_CXXModule: case TY_AST: case TY_ModuleFile: case TY_LLVM_IR: case TY_LLVM_BC: return true; @@ -123,6 +139,7 @@ bool types::isCXX(ID Id) { case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias: case TY_CXXHeader: case TY_PP_CXXHeader: case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: + case TY_CXXModule: case TY_PP_CXXModule: case TY_CUDA: case TY_PP_CUDA: case TY_CUDA_DEVICE: return true; } @@ -153,58 +170,67 @@ bool types::isCuda(ID Id) { } } -types::ID types::lookupTypeForExtension(const char *Ext) { +bool types::isSrcFile(ID Id) { + return Id != TY_Object && getPreprocessedType(Id) != TY_INVALID; +} + +types::ID types::lookupTypeForExtension(llvm::StringRef Ext) { return llvm::StringSwitch<types::ID>(Ext) .Case("c", TY_C) + .Case("C", TY_CXX) + .Case("F", TY_Fortran) + .Case("f", TY_PP_Fortran) + .Case("h", TY_CHeader) + .Case("H", TY_CXXHeader) .Case("i", TY_PP_C) .Case("m", TY_ObjC) .Case("M", TY_ObjCXX) - .Case("h", TY_CHeader) - .Case("C", TY_CXX) - .Case("H", TY_CXXHeader) - .Case("f", TY_PP_Fortran) - .Case("F", TY_Fortran) - .Case("s", TY_PP_Asm) - .Case("asm", TY_PP_Asm) - .Case("S", TY_Asm) .Case("o", TY_Object) - .Case("obj", TY_Object) - .Case("lib", TY_Object) - .Case("ii", TY_PP_CXX) - .Case("mi", TY_PP_ObjC) - .Case("mm", TY_ObjCXX) + .Case("S", TY_Asm) + .Case("s", TY_PP_Asm) .Case("bc", TY_LLVM_BC) .Case("cc", TY_CXX) .Case("CC", TY_CXX) .Case("cl", TY_CL) .Case("cp", TY_CXX) .Case("cu", TY_CUDA) - .Case("cui", TY_PP_CUDA) .Case("hh", TY_CXXHeader) + .Case("ii", TY_PP_CXX) .Case("ll", TY_LLVM_IR) - .Case("hpp", TY_CXXHeader) - .Case("ads", TY_Ada) + .Case("mi", TY_PP_ObjC) + .Case("mm", TY_ObjCXX) + .Case("rs", TY_RenderScript) .Case("adb", TY_Ada) + .Case("ads", TY_Ada) + .Case("asm", TY_PP_Asm) .Case("ast", TY_AST) + .Case("ccm", TY_CXXModule) + .Case("cpp", TY_CXX) + .Case("CPP", TY_CXX) .Case("c++", TY_CXX) .Case("C++", TY_CXX) + .Case("cui", TY_PP_CUDA) .Case("cxx", TY_CXX) - .Case("cpp", TY_CXX) - .Case("CPP", TY_CXX) .Case("CXX", TY_CXX) + .Case("F90", TY_Fortran) + .Case("f90", TY_PP_Fortran) + .Case("F95", TY_Fortran) + .Case("f95", TY_PP_Fortran) .Case("for", TY_PP_Fortran) .Case("FOR", TY_PP_Fortran) .Case("fpp", TY_Fortran) .Case("FPP", TY_Fortran) - .Case("f90", TY_PP_Fortran) - .Case("f95", TY_PP_Fortran) - .Case("F90", TY_Fortran) - .Case("F95", TY_Fortran) + .Case("gch", TY_PCH) + .Case("hpp", TY_CXXHeader) + .Case("iim", TY_PP_CXXModule) + .Case("lib", TY_Object) .Case("mii", TY_PP_ObjCXX) - .Case("pcm", TY_ModuleFile) + .Case("obj", TY_Object) .Case("pch", TY_PCH) - .Case("gch", TY_PCH) - .Case("rs", TY_RenderScript) + .Case("pcm", TY_ModuleFile) + .Case("c++m", TY_CXXModule) + .Case("cppm", TY_CXXModule) + .Case("cxxm", TY_CXXModule) .Default(TY_INVALID); } @@ -226,9 +252,11 @@ void types::getCompilationPhases(ID Id, llvm::SmallVectorImpl<phases::ID> &P) { P.push_back(phases::Preprocess); } - if (onlyPrecompileType(Id)) { + if (getPrecompiledType(Id) != TY_INVALID) { P.push_back(phases::Precompile); - } else { + } + + if (!onlyPrecompileType(Id)) { if (!onlyAssembleType(Id)) { P.push_back(phases::Compile); P.push_back(phases::Backend); @@ -237,7 +265,7 @@ void types::getCompilationPhases(ID Id, llvm::SmallVectorImpl<phases::ID> &P) { } } - if (!onlyPrecompileType(Id) && Id != TY_CUDA_DEVICE) { + if (!onlyPrecompileType(Id)) { P.push_back(phases::Link); } assert(0 < P.size() && "Not enough phases in list"); @@ -259,3 +287,21 @@ ID types::lookupCXXTypeForCType(ID Id) { return types::TY_PP_CXXHeader; } } + +ID types::lookupHeaderTypeForSourceType(ID Id) { + switch (Id) { + default: + return Id; + + case types::TY_C: + return types::TY_CHeader; + case types::TY_CXX: + return types::TY_CXXHeader; + case types::TY_ObjC: + return types::TY_ObjCHeader; + case types::TY_ObjCXX: + return types::TY_ObjCXXHeader; + case types::TY_CL: + return types::TY_CLHeader; + } +} |