diff options
author | Greg Steuck <gnezdo@cvs.openbsd.org> | 2022-03-04 16:46:24 +0000 |
---|---|---|
committer | Greg Steuck <gnezdo@cvs.openbsd.org> | 2022-03-04 16:46:24 +0000 |
commit | 93dfb9c84a51ff32677cdef21bc79b73c5ccc3e1 (patch) | |
tree | fa47f02f3292f2adcde2270c975798acd0d53d97 | |
parent | 5db61140f844a379a7b1bcb5facf8f8141a4c027 (diff) |
Report versioned lib.so in cc --print-file-name given short name
E.g. `cc --print-file-name libc.so` reports /usr/lib/libc.so.96.1
This is a complement of the major.minor finding logic in DriverUtils.
`ld -lc -L/usr/lib` currently find the libraries with this logic.
To make things more obviously related the code was extracted into a
function which was copied over verbatim.
fine with mortimer@
ok patrick@
-rw-r--r-- | gnu/llvm/clang/lib/Driver/Driver.cpp | 1034 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/DriverUtils.cpp | 60 |
2 files changed, 816 insertions, 278 deletions
diff --git a/gnu/llvm/clang/lib/Driver/Driver.cpp b/gnu/llvm/clang/lib/Driver/Driver.cpp index fb8335a3695..399c37d15ab 100644 --- a/gnu/llvm/clang/lib/Driver/Driver.cpp +++ b/gnu/llvm/clang/lib/Driver/Driver.cpp @@ -7,9 +7,9 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Driver.h" -#include "InputInfo.h" #include "ToolChains/AIX.h" #include "ToolChains/AMDGPU.h" +#include "ToolChains/AMDGPUOpenMP.h" #include "ToolChains/AVR.h" #include "ToolChains/Ananas.h" #include "ToolChains/BareMetal.h" @@ -38,18 +38,22 @@ #include "ToolChains/NaCl.h" #include "ToolChains/NetBSD.h" #include "ToolChains/OpenBSD.h" -#include "ToolChains/PS4CPU.h" #include "ToolChains/PPCLinux.h" +#include "ToolChains/PS4CPU.h" #include "ToolChains/RISCVToolchain.h" #include "ToolChains/Solaris.h" #include "ToolChains/TCE.h" +#include "ToolChains/VEToolchain.h" #include "ToolChains/WebAssembly.h" #include "ToolChains/XCore.h" +#include "ToolChains/ZOS.h" +#include "clang/Basic/TargetID.h" #include "clang/Basic/Version.h" #include "clang/Config/config.h" #include "clang/Driver/Action.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/InputInfo.h" #include "clang/Driver/Job.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" @@ -59,6 +63,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Config/llvm-config.h" @@ -69,8 +74,11 @@ #include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ExitCodes.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/MD5.h" #include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" @@ -84,13 +92,17 @@ #include <utility> #if LLVM_ON_UNIX #include <unistd.h> // getpid -#include <sysexits.h> // EX_IOERR #endif using namespace clang::driver; using namespace clang; using namespace llvm::opt; +static llvm::Triple getHIPOffloadTargetTriple() { + static const llvm::Triple T("amdgcn-amd-amdhsa"); + return T; +} + // static std::string Driver::GetResourcesPath(StringRef BinaryPath, StringRef CustomResourceDir) { @@ -99,7 +111,7 @@ std::string Driver::GetResourcesPath(StringRef BinaryPath, // exact same string ("a/../b/" and "b/" get different hashes, for example). // Dir is bin/ or lib/, depending on where BinaryPath is. - std::string Dir = llvm::sys::path::parent_path(BinaryPath); + std::string Dir = std::string(llvm::sys::path::parent_path(BinaryPath)); SmallString<128> P(Dir); if (CustomResourceDir != "") { @@ -115,31 +127,37 @@ std::string Driver::GetResourcesPath(StringRef BinaryPath, CLANG_VERSION_STRING); } - return P.str(); + return std::string(P.str()); } Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, - DiagnosticsEngine &Diags, + DiagnosticsEngine &Diags, std::string Title, IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) : Diags(Diags), VFS(std::move(VFS)), Mode(GCCMode), SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), LTOMode(LTOK_None), ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT), - DriverTitle("clang LLVM compiler"), CCPrintOptionsFilename(nullptr), - CCPrintHeadersFilename(nullptr), CCLogDiagnosticsFilename(nullptr), + DriverTitle(Title), CCPrintStatReportFilename(), CCPrintOptionsFilename(), + CCPrintHeadersFilename(), CCLogDiagnosticsFilename(), CCCPrintBindings(false), CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false), - TargetTriple(TargetTriple), CCCGenericGCCName(""), Saver(Alloc), - CheckInputsExist(true), GenReproducer(false), - SuppressMissingInputWarning(false) { - + CCPrintProcessStats(false), TargetTriple(TargetTriple), + CCCGenericGCCName(""), Saver(Alloc), CheckInputsExist(true), + GenReproducer(false), SuppressMissingInputWarning(false) { // Provide a sane fallback if no VFS is specified. if (!this->VFS) this->VFS = llvm::vfs::getRealFileSystem(); - Name = llvm::sys::path::filename(ClangExecutable); - Dir = llvm::sys::path::parent_path(ClangExecutable); + Name = std::string(llvm::sys::path::filename(ClangExecutable)); + Dir = std::string(llvm::sys::path::parent_path(ClangExecutable)); InstalledDir = Dir; // Provide a sensible default installed dir. + if ((!SysRoot.empty()) && llvm::sys::path::is_relative(SysRoot)) { + // Prepend InstalledDir if SysRoot is relative + SmallString<128> P(InstalledDir); + llvm::sys::path::append(P, SysRoot); + SysRoot = std::string(P); + } + #if defined(CLANG_CONFIG_FILE_SYSTEM_DIR) SystemConfigDir = CLANG_CONFIG_FILE_SYSTEM_DIR; #endif @@ -151,28 +169,9 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, ResourceDir = GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR); } -void Driver::ParseDriverMode(StringRef ProgramName, - ArrayRef<const char *> Args) { - if (ClangNameParts.isEmpty()) - ClangNameParts = ToolChain::getTargetAndModeFromProgramName(ProgramName); - setDriverModeFromOption(ClangNameParts.DriverMode); - - for (const char *ArgPtr : Args) { - // Ignore nullptrs, they are the response file's EOL markers. - if (ArgPtr == nullptr) - continue; - const StringRef Arg = ArgPtr; - setDriverModeFromOption(Arg); - } -} - -void Driver::setDriverModeFromOption(StringRef Opt) { - const std::string OptName = +void Driver::setDriverMode(StringRef Value) { + static const std::string OptName = getOpts().getOption(options::OPT_driver_mode).getPrefixedName(); - if (!Opt.startswith(OptName)) - return; - StringRef Value = Opt.drop_front(OptName.size()); - if (auto M = llvm::StringSwitch<llvm::Optional<DriverMode>>(Value) .Case("gcc", GCCMode) .Case("g++", GXXMode) @@ -196,6 +195,11 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings, std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) = getIncludeExcludeOptionFlagMasks(IsClCompatMode); + // Make sure that Flang-only options don't pollute the Clang output + // TODO: Make sure that Clang-only options don't pollute Flang output + if (!IsFlangMode()) + ExcludedFlagsBitmask |= options::FlangOnlyOption; + unsigned MissingArgIndex, MissingArgCount; InputArgList Args = getOpts().ParseArgs(ArgStrings, MissingArgIndex, MissingArgCount, @@ -467,6 +471,26 @@ static llvm::Triple computeTargetTriple(const Driver &D, Target.getOS() == llvm::Triple::Minix) return Target; + // On AIX, the env OBJECT_MODE may affect the resulting arch variant. + if (Target.isOSAIX()) { + if (Optional<std::string> ObjectModeValue = + llvm::sys::Process::GetEnv("OBJECT_MODE")) { + StringRef ObjectMode = *ObjectModeValue; + llvm::Triple::ArchType AT = llvm::Triple::UnknownArch; + + if (ObjectMode.equals("64")) { + AT = Target.get64BitArchVariant().getArch(); + } else if (ObjectMode.equals("32")) { + AT = Target.get32BitArchVariant().getArch(); + } else { + D.Diag(diag::err_drv_invalid_object_mode) << ObjectMode; + } + + if (AT != llvm::Triple::UnknownArch && AT != Target.getArch()) + Target.setArch(AT); + } + } + // Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'. Arg *A = Args.getLastArg(options::OPT_m64, options::OPT_mx32, options::OPT_m32, options::OPT_m16); @@ -477,14 +501,21 @@ static llvm::Triple computeTargetTriple(const Driver &D, AT = Target.get64BitArchVariant().getArch(); if (Target.getEnvironment() == llvm::Triple::GNUX32) Target.setEnvironment(llvm::Triple::GNU); + else if (Target.getEnvironment() == llvm::Triple::MuslX32) + Target.setEnvironment(llvm::Triple::Musl); } else if (A->getOption().matches(options::OPT_mx32) && Target.get64BitArchVariant().getArch() == llvm::Triple::x86_64) { AT = llvm::Triple::x86_64; - Target.setEnvironment(llvm::Triple::GNUX32); + if (Target.getEnvironment() == llvm::Triple::Musl) + Target.setEnvironment(llvm::Triple::MuslX32); + else + Target.setEnvironment(llvm::Triple::GNUX32); } else if (A->getOption().matches(options::OPT_m32)) { AT = Target.get32BitArchVariant().getArch(); if (Target.getEnvironment() == llvm::Triple::GNUX32) Target.setEnvironment(llvm::Triple::GNU); + else if (Target.getEnvironment() == llvm::Triple::MuslX32) + Target.setEnvironment(llvm::Triple::Musl); } else if (A->getOption().matches(options::OPT_m16) && Target.get32BitArchVariant().getArch() == llvm::Triple::x86) { AT = llvm::Triple::x86; @@ -542,9 +573,9 @@ static llvm::Triple computeTargetTriple(const Driver &D, A = Args.getLastArg(options::OPT_march_EQ); if (A && Target.isRISCV()) { StringRef ArchName = A->getValue(); - if (ArchName.startswith_lower("rv32")) + if (ArchName.startswith_insensitive("rv32")) Target.setArch(llvm::Triple::riscv32); - else if (ArchName.startswith_lower("rv64")) + else if (ArchName.startswith_insensitive("rv64")) Target.setArch(llvm::Triple::riscv64); } @@ -552,16 +583,24 @@ static llvm::Triple computeTargetTriple(const Driver &D, } // Parse the LTO options and record the type of LTO compilation -// based on which -f(no-)?lto(=.*)? option occurs last. -void Driver::setLTOMode(const llvm::opt::ArgList &Args) { - LTOMode = LTOK_None; - if (!Args.hasFlag(options::OPT_flto, options::OPT_flto_EQ, - options::OPT_fno_lto, false)) - return; +// based on which -f(no-)?lto(=.*)? or -f(no-)?offload-lto(=.*)? +// option occurs last. +static llvm::Optional<driver::LTOKind> +parseLTOMode(Driver &D, const llvm::opt::ArgList &Args, OptSpecifier OptPos, + OptSpecifier OptNeg, OptSpecifier OptEq, bool IsOffload) { + driver::LTOKind LTOMode = LTOK_None; + // Non-offload LTO allows -flto=auto and -flto=jobserver. Offload LTO does + // not support those options. + if (!Args.hasFlag(OptPos, OptEq, OptNeg, false) && + (IsOffload || + (!Args.hasFlag(options::OPT_flto_EQ_auto, options::OPT_fno_lto, false) && + !Args.hasFlag(options::OPT_flto_EQ_jobserver, options::OPT_fno_lto, + false)))) + return None; StringRef LTOName("full"); - const Arg *A = Args.getLastArg(options::OPT_flto_EQ); + const Arg *A = Args.getLastArg(OptEq); if (A) LTOName = A->getValue(); @@ -572,9 +611,27 @@ void Driver::setLTOMode(const llvm::opt::ArgList &Args) { if (LTOMode == LTOK_Unknown) { assert(A); - Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() - << A->getValue(); + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << A->getValue(); + return None; } + return LTOMode; +} + +// Parse the LTO options. +void Driver::setLTOMode(const llvm::opt::ArgList &Args) { + LTOMode = LTOK_None; + if (auto M = parseLTOMode(*this, Args, options::OPT_flto, + options::OPT_fno_lto, options::OPT_flto_EQ, + /*IsOffload=*/false)) + LTOMode = M.getValue(); + + OffloadLTOMode = LTOK_None; + if (auto M = parseLTOMode(*this, Args, options::OPT_foffload_lto, + options::OPT_fno_offload_lto, + options::OPT_foffload_lto_EQ, + /*IsOffload=*/true)) + OffloadLTOMode = M.getValue(); } /// Compute the desired OpenMP runtime from the flags provided. @@ -644,10 +701,8 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, } else if (IsHIP) { const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>(); const llvm::Triple &HostTriple = HostTC->getTriple(); - StringRef DeviceTripleStr; auto OFK = Action::OFK_HIP; - DeviceTripleStr = "amdgcn-amd-amdhsa"; - llvm::Triple HIPTriple(DeviceTripleStr); + llvm::Triple HIPTriple = getHIPOffloadTargetTriple(); // Use the HIP and host triples as the key into the ToolChains map, // because the device toolchain we create depends on both. auto &HIPTC = ToolChains[HIPTriple.str() + "/" + HostTriple.str()]; @@ -701,18 +756,27 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, Diag(clang::diag::err_drv_invalid_omp_target) << Val; else { const ToolChain *TC; - // CUDA toolchains have to be selected differently. They pair host + // Device toolchains have to be selected differently. They pair host // and device in their implementation. - if (TT.isNVPTX()) { + if (TT.isNVPTX() || TT.isAMDGCN()) { const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>(); assert(HostTC && "Host toolchain should be always defined."); - auto &CudaTC = + auto &DeviceTC = ToolChains[TT.str() + "/" + HostTC->getTriple().normalize()]; - if (!CudaTC) - CudaTC = std::make_unique<toolchains::CudaToolChain>( - *this, TT, *HostTC, C.getInputArgs(), Action::OFK_OpenMP); - TC = CudaTC.get(); + if (!DeviceTC) { + if (TT.isNVPTX()) + DeviceTC = std::make_unique<toolchains::CudaToolChain>( + *this, TT, *HostTC, C.getInputArgs(), Action::OFK_OpenMP); + else if (TT.isAMDGCN()) + DeviceTC = + std::make_unique<toolchains::AMDGPUOpenMPToolChain>( + *this, TT, *HostTC, C.getInputArgs()); + else + assert(DeviceTC && "Device toolchain not defined."); + } + + TC = DeviceTC.get(); } else TC = &getToolChain(C.getInputArgs(), TT); C.addOffloadDeviceToolChain(TC, Action::OFK_OpenMP); @@ -741,10 +805,9 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, /// by Dirs. /// static bool searchForFile(SmallVectorImpl<char> &FilePath, - ArrayRef<std::string> Dirs, - StringRef FileName) { + ArrayRef<StringRef> Dirs, StringRef FileName) { SmallString<128> WPath; - for (const std::string &Dir : Dirs) { + for (const StringRef &Dir : Dirs) { if (Dir.empty()) continue; WPath.clear(); @@ -769,7 +832,7 @@ bool Driver::readConfigFile(StringRef FileName) { // Read options from config file. llvm::SmallString<128> CfgFileName(FileName); llvm::sys::path::native(CfgFileName); - ConfigFile = CfgFileName.str(); + ConfigFile = std::string(CfgFileName); bool ContainErrors; CfgOptions = std::make_unique<InputArgList>( ParseArgStrings(NewCfgArgs, IsCLMode(), ContainErrors)); @@ -826,8 +889,13 @@ bool Driver::loadConfigFile() { std::vector<std::string> ConfigFiles = CLOptions->getAllArgValues(options::OPT_config); if (ConfigFiles.size() > 1) { - Diag(diag::err_drv_duplicate_config); - return true; + if (!std::all_of(ConfigFiles.begin(), ConfigFiles.end(), + [ConfigFiles](const std::string &s) { + return s == ConfigFiles[0]; + })) { + Diag(diag::err_drv_duplicate_config); + return true; + } } if (!ConfigFiles.empty()) { @@ -897,10 +965,7 @@ bool Driver::loadConfigFile() { } // Prepare list of directories where config file is searched for. - SmallVector<std::string, 3> CfgFileSearchDirs; - CfgFileSearchDirs.push_back(UserConfigDir); - CfgFileSearchDirs.push_back(SystemConfigDir); - CfgFileSearchDirs.push_back(Dir); + StringRef CfgFileSearchDirs[] = {UserConfigDir, SystemConfigDir, Dir}; // Try to find config file. First try file with corrected architecture. llvm::SmallString<128> CfgFilePath; @@ -931,7 +996,7 @@ bool Driver::loadConfigFile() { // --config. If it was deduced from executable name, it is not an error. if (FileSpecifiedExplicitly) { Diag(diag::err_drv_config_file_not_found) << CfgFileName; - for (const std::string &SearchDir : CfgFileSearchDirs) + for (const StringRef &SearchDir : CfgFileSearchDirs) if (!SearchDir.empty()) Diag(diag::note_drv_config_file_searched_in) << SearchDir; return true; @@ -946,20 +1011,12 @@ 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 (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); - PrefixDirs.push_back(Split.first); - CompilerPath = Split.second; - } - } - // We look for the driver mode option early, because the mode can affect // how other options are parsed. - ParseDriverMode(ClangExecutable, ArgList.slice(1)); + + auto DriverMode = getDriverMode(ClangExecutable, ArgList.slice(1)); + if (!DriverMode.empty()) + setDriverMode(DriverMode); // FIXME: What are we going to do with -V and -b? @@ -981,13 +1038,15 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // objects than Args. This copies an Arg from one of those other InputArgLists // to the ownership of Args. auto appendOneArg = [&Args](const Arg *Opt, const Arg *BaseArg) { - unsigned Index = Args.MakeIndex(Opt->getSpelling()); - Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Opt->getSpelling(), - Index, BaseArg); - Copy->getValues() = Opt->getValues(); - if (Opt->isClaimed()) - Copy->claim(); - Args.append(Copy); + unsigned Index = Args.MakeIndex(Opt->getSpelling()); + Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Args.getArgString(Index), + Index, BaseArg); + Copy->getValues() = Opt->getValues(); + if (Opt->isClaimed()) + Copy->claim(); + Copy->setOwnsValues(Opt->getOwnsValues()); + Opt->setOwnsValues(false); + Args.append(Copy); }; if (HasConfigFile) @@ -1055,6 +1114,15 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { GenReproducer = Args.hasFlag(options::OPT_gen_reproducer, options::OPT_fno_crash_diagnostics, !!::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")); + + // Process -fproc-stat-report options. + if (const Arg *A = Args.getLastArg(options::OPT_fproc_stat_report_EQ)) { + CCPrintProcessStats = true; + CCPrintStatReportFilename = A->getValue(); + } + if (Args.hasArg(options::OPT_fproc_stat_report)) + CCPrintProcessStats = true; + // FIXME: TargetTriple is used by the target-prefixed calls to as/ld // and getToolChain is const. if (IsCLMode()) { @@ -1074,6 +1142,16 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { A->claim(); PrefixDirs.push_back(A->getValue(0)); } + 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); + PrefixDirs.push_back(std::string(Split.first)); + CompilerPath = Split.second; + } + } if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) SysRoot = A->getValue(); if (const Arg *A = Args.getLastArg(options::OPT__dyld_prefix_EQ)) @@ -1156,7 +1234,7 @@ static void printArgList(raw_ostream &OS, const llvm::opt::ArgList &Args) { for (auto I = ASL.begin(), E = ASL.end(); I != E; ++I) { if (I != ASL.begin()) OS << ' '; - Command::printArg(OS, *I, true); + llvm::sys::printArg(OS, *I, true); } OS << '\n'; } @@ -1267,10 +1345,6 @@ void Driver::generateCompilationDiagnostics( // Print the version of the compiler. PrintVersion(C, llvm::errs()); - Diag(clang::diag::note_drv_command_failed_diag_msg) - << "PLEASE submit a bug report to " BUG_REPORT_URL " and include the " - "crash backtrace, preprocessed source, and associated run script."; - // Suppress driver output and emit preprocessor output to temp file. Mode = CPPMode; CCGenDiagnostics = true; @@ -1398,7 +1472,9 @@ void Driver::generateCompilationDiagnostics( llvm::SmallString<128> Script(CrashInfo.Filename); llvm::sys::path::replace_extension(Script, "sh"); std::error_code EC; - llvm::raw_fd_ostream ScriptOS(Script, EC, llvm::sys::fs::CD_CreateNew); + llvm::raw_fd_ostream ScriptOS(Script, EC, llvm::sys::fs::CD_CreateNew, + llvm::sys::fs::FA_Write, + llvm::sys::fs::OF_Text); if (EC) { Diag(clang::diag::note_drv_command_failed_diag_msg) << "Error generating run script: " << Script << " " << EC.message(); @@ -1413,7 +1489,7 @@ void Driver::generateCompilationDiagnostics( ScriptOS << "\n# Additional information: " << AdditionalInformation << "\n"; if (Report) - Report->TemporaryFiles.push_back(Script.str()); + Report->TemporaryFiles.push_back(std::string(Script.str())); Diag(clang::diag::note_drv_command_failed_diag_msg) << Script; } @@ -1435,8 +1511,7 @@ void Driver::generateCompilationDiagnostics( } } - for (const auto &A : C.getArgs().filtered(options::OPT_frewrite_map_file, - options::OPT_frewrite_map_file_EQ)) + for (const auto &A : C.getArgs().filtered(options::OPT_frewrite_map_file_EQ)) Diag(clang::diag::note_drv_command_failed_diag_msg) << A->getValue(); Diag(clang::diag::note_drv_command_failed_diag_msg) @@ -1448,7 +1523,8 @@ void Driver::setUpResponseFiles(Compilation &C, Command &Cmd) { // capacity if the tool does not support response files, there is a chance/ // that things will just work without a response file, so we silently just // skip it. - if (Cmd.getCreator().getResponseFilesSupport() == Tool::RF_None || + if (Cmd.getResponseFileSupport().ResponseKind == + ResponseFileSupport::RF_None || llvm::sys::commandLineFitsWithinSystemLimits(Cmd.getExecutable(), Cmd.getArguments())) return; @@ -1538,16 +1614,25 @@ void Driver::PrintHelp(bool ShowHidden) const { if (!ShowHidden) ExcludedFlagsBitmask |= HelpHidden; + if (IsFlangMode()) + IncludedFlagsBitmask |= options::FlangOption; + else + ExcludedFlagsBitmask |= options::FlangOnlyOption; + std::string Usage = llvm::formatv("{0} [options] file...", Name).str(); - getOpts().PrintHelp(llvm::outs(), Usage.c_str(), DriverTitle.c_str(), + getOpts().printHelp(llvm::outs(), Usage.c_str(), DriverTitle.c_str(), IncludedFlagsBitmask, ExcludedFlagsBitmask, /*ShowAllAliases=*/false); } void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const { - // FIXME: The following handlers should use a callback mechanism, we don't - // know what the client would like to do. - OS << getClangFullVersion() << '\n'; + if (IsFlangMode()) { + OS << getClangToolFullVersion("flang-new") << '\n'; + } else { + // FIXME: The following handlers should use a callback mechanism, we don't + // know what the client would like to do. + OS << getClangFullVersion() << '\n'; + } const ToolChain &TC = C.getDefaultToolChain(); OS << "Target: " << TC.getTripleString() << '\n'; @@ -1585,9 +1670,14 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const { std::vector<std::string> SuggestedCompletions; std::vector<std::string> Flags; - unsigned short DisableFlags = + unsigned int DisableFlags = options::NoDriverOption | options::Unsupported | options::Ignored; + // Make sure that Flang-only options don't pollute the Clang output + // TODO: Make sure that Clang-only options don't pollute Flang output + if (!IsFlangMode()) + DisableFlags |= options::FlangOnlyOption; + // Distinguish "--autocomplete=-someflag" and "--autocomplete=-someflag," // because the latter indicates that the user put space before pushing tab // which should end up in a file completion. @@ -1642,7 +1732,7 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const { // this code. for (StringRef S : DiagnosticIDs::getDiagnosticFlags()) if (S.startswith(Cur)) - SuggestedCompletions.push_back(S); + SuggestedCompletions.push_back(std::string(S)); } // Sort the autocomplete candidates so that shells print them out in a @@ -1650,7 +1740,7 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const { // case-insensitive sorting for consistency with the -help option // which prints out options in the case-insensitive alphabetical order. llvm::sort(SuggestedCompletions, [](StringRef A, StringRef B) { - if (int X = A.compare_lower(B)) + if (int X = A.compare_insensitive(B)) return X < 0; return A.compare(B) > 0; }); @@ -1720,6 +1810,13 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { if (C.getArgs().hasArg(options::OPT_print_search_dirs)) { llvm::outs() << "programs: ="; bool separator = false; + // Print -B and COMPILER_PATH. + for (const std::string &Path : PrefixDirs) { + if (separator) + llvm::outs() << llvm::sys::EnvPathSeparator; + llvm::outs() << Path; + separator = true; + } for (const std::string &Path : TC.getProgramPaths()) { if (separator) llvm::outs() << llvm::sys::EnvPathSeparator; @@ -1744,6 +1841,15 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { return false; } + if (C.getArgs().hasArg(options::OPT_print_runtime_dir)) { + std::string CandidateRuntimePath = TC.getRuntimePath(); + if (getVFS().exists(CandidateRuntimePath)) + llvm::outs() << CandidateRuntimePath << '\n'; + else + llvm::outs() << TC.getCompilerRTPath() << '\n'; + return false; + } + // FIXME: The following handlers should use a callback mechanism, we don't // know what the client would like to do. if (Arg *A = C.getArgs().getLastArg(options::OPT_print_file_name_EQ)) { @@ -1812,6 +1918,17 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { return false; } + if (C.getArgs().hasArg(options::OPT_print_multiarch)) { + llvm::outs() << TC.getMultiarchTriple(*this, TC.getTriple(), SysRoot) + << "\n"; + return false; + } + + if (C.getArgs().hasArg(options::OPT_print_targets)) { + llvm::TargetRegistry::printRegisteredTargetsForVersion(llvm::outs()); + return false; + } + return true; } @@ -1849,6 +1966,7 @@ static unsigned PrintActions1(const Compilation &C, Action *A, bool IsFirst = true; OA->doOnEachDependence( [&](Action *A, const ToolChain *TC, const char *BoundArch) { + assert(TC && "Unknown host toolchain"); // E.g. for two CUDA device dependences whose bound arch is sm_20 and // sm_35 this will generate: // "cuda-device" (nvptx64-nvidia-cuda:sm_20) {#ID}, "cuda-device" @@ -1856,13 +1974,9 @@ static unsigned PrintActions1(const Compilation &C, Action *A, if (!IsFirst) os << ", "; os << '"'; - if (TC) - os << A->getOffloadingKindPrefix(); - else - os << "host"; + os << A->getOffloadingKindPrefix(); os << " ("; os << TC->getTriple().normalize(); - if (BoundArch) os << ":" << BoundArch; os << ")"; @@ -2036,7 +2150,7 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value, if (IsCLMode()) { if (!llvm::sys::path::is_absolute(Twine(Value)) && - llvm::sys::Process::FindInEnvPath("LIB", Value)) + llvm::sys::Process::FindInEnvPath("LIB", Value, ';')) return true; if (Args.hasArg(options::OPT__SLASH_link) && Ty == types::TY_Object) { @@ -2119,15 +2233,20 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, // stdin must be handled specially. if (memcmp(Value, "-", 2) == 0) { - // If running with -E, treat as a C input (this changes the builtin - // macros, for example). This may be overridden by -ObjC below. - // - // Otherwise emit an error but still use a valid type to avoid - // spurious errors (e.g., no inputs). - if (!Args.hasArgNoClaim(options::OPT_E) && !CCCIsCPP()) - Diag(IsCLMode() ? clang::diag::err_drv_unknown_stdin_type_clang_cl - : clang::diag::err_drv_unknown_stdin_type); - Ty = types::TY_C; + if (IsFlangMode()) { + Ty = types::TY_Fortran; + } else { + // If running with -E, treat as a C input (this changes the + // builtin macros, for example). This may be overridden by -ObjC + // below. + // + // Otherwise emit an error but still use a valid type to avoid + // spurious errors (e.g., no inputs). + if (!Args.hasArgNoClaim(options::OPT_E) && !CCCIsCPP()) + Diag(IsCLMode() ? clang::diag::err_drv_unknown_stdin_type_clang_cl + : clang::diag::err_drv_unknown_stdin_type); + Ty = types::TY_C; + } } else { // Otherwise lookup by extension. // Fallback is C if invoked as C preprocessor, C++ if invoked with @@ -2316,8 +2435,11 @@ class OffloadingActionBuilder final { /// Append top level actions generated by the builder. virtual void appendTopLevelActions(ActionList &AL) {} - /// Append linker actions generated by the builder. - virtual void appendLinkActions(ActionList &AL) {} + /// Append linker device actions generated by the builder. + virtual void appendLinkDeviceActions(ActionList &AL) {} + + /// Append linker host action generated by the builder. + virtual Action* appendLinkHostActions(ActionList &AL) { return nullptr; } /// Append linker actions generated by the builder. virtual void appendLinkDependences(OffloadAction::DeviceDependences &DA) {} @@ -2350,8 +2472,20 @@ class OffloadingActionBuilder final { bool EmitLLVM = false; bool EmitAsm = false; + /// ID to identify each device compilation. For CUDA it is simply the + /// GPU arch string. For HIP it is either the GPU arch string or GPU + /// arch string plus feature strings delimited by a plus sign, e.g. + /// gfx906+xnack. + struct TargetID { + /// Target ID string which is persistent throughout the compilation. + const char *ID; + TargetID(CudaArch Arch) { ID = CudaArchToString(Arch); } + TargetID(const char *ID) : ID(ID) {} + operator const char *() { return ID; } + operator StringRef() { return StringRef(ID); } + }; /// List of GPU architectures to use in this compilation. - SmallVector<CudaArch, 4> GpuArchList; + SmallVector<TargetID, 4> GpuArchList; /// The CUDA actions for the current input. ActionList CudaDeviceActions; @@ -2368,6 +2502,14 @@ class OffloadingActionBuilder final { /// Default GPU architecture if there's no one specified. CudaArch DefaultCudaArch = CudaArch::UNKNOWN; + /// Method to generate compilation unit ID specified by option + /// '-fuse-cuid='. + enum UseCUIDKind { CUID_Hash, CUID_Random, CUID_None, CUID_Invalid }; + UseCUIDKind UseCUID = CUID_Hash; + + /// Compilation unit ID specified by option '-cuid='. + StringRef FixedCUID; + public: CudaActionBuilderBase(Compilation &C, DerivedArgList &Args, const Driver::InputList &Inputs, @@ -2387,8 +2529,9 @@ class OffloadingActionBuilder final { // If the host input is not CUDA or HIP, we don't need to bother about // this input. - if (IA->getType() != types::TY_CUDA && - IA->getType() != types::TY_HIP) { + if (!(IA->getType() == types::TY_CUDA || + IA->getType() == types::TY_HIP || + IA->getType() == types::TY_PP_HIP)) { // The builder will ignore this input. IsActive = false; return ABRT_Inactive; @@ -2403,9 +2546,32 @@ class OffloadingActionBuilder final { // Replicate inputs for each GPU architecture. auto Ty = IA->getType() == types::TY_HIP ? types::TY_HIP_DEVICE : types::TY_CUDA_DEVICE; + std::string CUID = FixedCUID.str(); + if (CUID.empty()) { + if (UseCUID == CUID_Random) + CUID = llvm::utohexstr(llvm::sys::Process::GetRandomNumber(), + /*LowerCase=*/true); + else if (UseCUID == CUID_Hash) { + llvm::MD5 Hasher; + llvm::MD5::MD5Result Hash; + SmallString<256> RealPath; + llvm::sys::fs::real_path(IA->getInputArg().getValue(), RealPath, + /*expand_tilde=*/true); + Hasher.update(RealPath); + for (auto *A : Args) { + if (A->getOption().matches(options::OPT_INPUT)) + continue; + Hasher.update(A->getAsString(Args)); + } + Hasher.final(Hash); + CUID = llvm::utohexstr(Hash.low(), /*LowerCase=*/true); + } + } + IA->setId(CUID); + for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { CudaDeviceActions.push_back( - C.MakeAction<InputAction>(IA->getInputArg(), Ty)); + C.MakeAction<InputAction>(IA->getInputArg(), Ty, IA->getId())); } return ABRT_Success; @@ -2416,7 +2582,7 @@ class OffloadingActionBuilder final { // If -fgpu-rdc is disabled, should not unbundle since there is no // device code to link. - if (!Relocatable) + if (UA->getType() == types::TY_Object && !Relocatable) return ABRT_Inactive; CudaDeviceActions.clear(); @@ -2434,7 +2600,7 @@ class OffloadingActionBuilder final { for (auto Arch : GpuArchList) { CudaDeviceActions.push_back(UA); - UA->registerDependentActionInfo(ToolChains[0], CudaArchToString(Arch), + UA->registerDependentActionInfo(ToolChains[0], Arch, AssociatedOffloadKind); } return ABRT_Success; @@ -2445,16 +2611,15 @@ class OffloadingActionBuilder final { void appendTopLevelActions(ActionList &AL) override { // Utility to append actions to the top level list. - auto AddTopLevel = [&](Action *A, CudaArch BoundArch) { + auto AddTopLevel = [&](Action *A, TargetID TargetID) { OffloadAction::DeviceDependences Dep; - Dep.add(*A, *ToolChains.front(), CudaArchToString(BoundArch), - AssociatedOffloadKind); + Dep.add(*A, *ToolChains.front(), TargetID, AssociatedOffloadKind); 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); + AddTopLevel(CudaFatBinary, CudaArch::UNUSED); CudaDeviceActions.clear(); CudaFatBinary = nullptr; return; @@ -2476,6 +2641,13 @@ class OffloadingActionBuilder final { CudaDeviceActions.clear(); } + /// Get canonicalized offload arch option. \returns empty StringRef if the + /// option is invalid. + virtual StringRef getCanonicalOffloadArch(StringRef Arch) = 0; + + virtual llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>> + getConflictOffloadArchCombination(const std::set<StringRef> &GpuArchs) = 0; + bool initialize() override { assert(AssociatedOffloadKind == Action::OFK_Cuda || AssociatedOffloadKind == Action::OFK_HIP); @@ -2521,37 +2693,60 @@ class OffloadingActionBuilder final { options::OPT_cuda_device_only); EmitLLVM = Args.getLastArg(options::OPT_emit_llvm); EmitAsm = Args.getLastArg(options::OPT_S); + FixedCUID = Args.getLastArgValue(options::OPT_cuid_EQ); + if (Arg *A = Args.getLastArg(options::OPT_fuse_cuid_EQ)) { + StringRef UseCUIDStr = A->getValue(); + UseCUID = llvm::StringSwitch<UseCUIDKind>(UseCUIDStr) + .Case("hash", CUID_Hash) + .Case("random", CUID_Random) + .Case("none", CUID_None) + .Default(CUID_Invalid); + if (UseCUID == CUID_Invalid) { + C.getDriver().Diag(diag::err_drv_invalid_value) + << A->getAsString(Args) << UseCUIDStr; + C.setContainsError(); + return true; + } + } // Collect all cuda_gpu_arch parameters, removing duplicates. - std::set<CudaArch> GpuArchs; + std::set<StringRef> 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))) + if (!(A->getOption().matches(options::OPT_offload_arch_EQ) || + A->getOption().matches(options::OPT_no_offload_arch_EQ))) continue; A->claim(); - const StringRef ArchStr = A->getValue(); - if (A->getOption().matches(options::OPT_no_cuda_gpu_arch_EQ) && + StringRef ArchStr = A->getValue(); + if (A->getOption().matches(options::OPT_no_offload_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; + ArchStr = getCanonicalOffloadArch(ArchStr); + if (ArchStr.empty()) { 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 if (A->getOption().matches(options::OPT_offload_arch_EQ)) + GpuArchs.insert(ArchStr); + else if (A->getOption().matches(options::OPT_no_offload_arch_EQ)) + GpuArchs.erase(ArchStr); else llvm_unreachable("Unexpected option."); } + auto &&ConflictingArchs = getConflictOffloadArchCombination(GpuArchs); + if (ConflictingArchs) { + C.getDriver().Diag(clang::diag::err_drv_bad_offload_arch_combo) + << ConflictingArchs.getValue().first + << ConflictingArchs.getValue().second; + C.setContainsError(); + return true; + } + // Collect list of GPUs remaining in the set. - for (CudaArch Arch : GpuArchs) - GpuArchList.push_back(Arch); + for (auto Arch : GpuArchs) + GpuArchList.push_back(Arch.data()); // Default to sm_20 which is the lowest common denominator for // supported GPUs. sm_20 code should work correctly, if @@ -2573,6 +2768,21 @@ class OffloadingActionBuilder final { DefaultCudaArch = CudaArch::SM_20; } + StringRef getCanonicalOffloadArch(StringRef ArchStr) override { + CudaArch Arch = StringToCudaArch(ArchStr); + if (Arch == CudaArch::UNKNOWN || !IsNVIDIAGpuArch(Arch)) { + C.getDriver().Diag(clang::diag::err_drv_cuda_bad_gpu_arch) << ArchStr; + return StringRef(); + } + return CudaArchToString(Arch); + } + + llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>> + getConflictOffloadArchCombination( + const std::set<StringRef> &GpuArchs) override { + return llvm::None; + } + ActionBuilderReturnCode getDeviceDependences(OffloadAction::DeviceDependences &DA, phases::ID CurPhase, phases::ID FinalPhase, @@ -2632,8 +2842,7 @@ class OffloadingActionBuilder final { for (auto &A : {AssembleAction, BackendAction}) { OffloadAction::DeviceDependences DDep; - DDep.add(*A, *ToolChains.front(), CudaArchToString(GpuArchList[I]), - Action::OFK_Cuda); + DDep.add(*A, *ToolChains.front(), GpuArchList[I], Action::OFK_Cuda); DeviceActions.push_back( C.MakeAction<OffloadAction>(DDep, A->getType())); } @@ -2682,16 +2891,48 @@ class OffloadingActionBuilder final { class HIPActionBuilder final : public CudaActionBuilderBase { /// The linker inputs obtained for each device arch. SmallVector<ActionList, 8> DeviceLinkerInputs; + bool GPUSanitize; + // The default bundling behavior depends on the type of output, therefore + // BundleOutput needs to be tri-value: None, true, or false. + // Bundle code objects except --no-gpu-output is specified for device + // only compilation. Bundle other type of output files only if + // --gpu-bundle-output is specified for device only compilation. + Optional<bool> BundleOutput; public: HIPActionBuilder(Compilation &C, DerivedArgList &Args, const Driver::InputList &Inputs) : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) { DefaultCudaArch = CudaArch::GFX803; + GPUSanitize = Args.hasFlag(options::OPT_fgpu_sanitize, + options::OPT_fno_gpu_sanitize, false); + if (Args.hasArg(options::OPT_gpu_bundle_output, + options::OPT_no_gpu_bundle_output)) + BundleOutput = Args.hasFlag(options::OPT_gpu_bundle_output, + options::OPT_no_gpu_bundle_output); } bool canUseBundlerUnbundler() const override { return true; } + StringRef getCanonicalOffloadArch(StringRef IdStr) override { + llvm::StringMap<bool> Features; + auto ArchStr = + parseTargetID(getHIPOffloadTargetTriple(), IdStr, &Features); + if (!ArchStr) { + C.getDriver().Diag(clang::diag::err_drv_bad_target_id) << IdStr; + C.setContainsError(); + return StringRef(); + } + auto CanId = getCanonicalTargetID(ArchStr.getValue(), Features); + return Args.MakeArgStringRef(CanId); + }; + + llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>> + getConflictOffloadArchCombination( + const std::set<StringRef> &GpuArchs) override { + return getConflictTargetIDCombination(GpuArchs); + } + ActionBuilderReturnCode getDeviceDependences(OffloadAction::DeviceDependences &DA, phases::ID CurPhase, phases::ID FinalPhase, @@ -2700,9 +2941,7 @@ class OffloadingActionBuilder final { // backend and assemble phases to output LLVM IR. Except for generating // non-relocatable device coee, where we generate fat binary for device // code and pass to host in Backend phase. - if (CudaDeviceActions.empty() || - (CurPhase == phases::Backend && Relocatable) || - CurPhase == phases::Assemble) + if (CudaDeviceActions.empty()) return ABRT_Success; assert(((CurPhase == phases::Link && Relocatable) || @@ -2719,12 +2958,31 @@ class OffloadingActionBuilder final { // a fat binary containing all the code objects for different GPU's. // The fat binary is then an input to the host action. for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { - // Create a link action to link device IR with device library - // and generate ISA. - ActionList AL; - AL.push_back(CudaDeviceActions[I]); - CudaDeviceActions[I] = - C.MakeAction<LinkJobAction>(AL, types::TY_Image); + if (C.getDriver().isUsingLTO(/*IsOffload=*/true)) { + // When LTO is enabled, skip the backend and assemble phases and + // use lld to link the bitcode. + ActionList AL; + AL.push_back(CudaDeviceActions[I]); + // Create a link action to link device IR with device library + // and generate ISA. + CudaDeviceActions[I] = + C.MakeAction<LinkJobAction>(AL, types::TY_Image); + } else { + // When LTO is not enabled, we follow the conventional + // compiler phases, including backend and assemble phases. + ActionList AL; + auto BackendAction = C.getDriver().ConstructPhaseAction( + C, Args, phases::Backend, CudaDeviceActions[I], + AssociatedOffloadKind); + auto AssembleAction = C.getDriver().ConstructPhaseAction( + C, Args, phases::Assemble, BackendAction, + AssociatedOffloadKind); + AL.push_back(AssembleAction); + // Create a link action to link device IR with device library + // and generate ISA. + CudaDeviceActions[I] = + C.MakeAction<LinkJobAction>(AL, types::TY_Image); + } // OffloadingActionBuilder propagates device arch until an offload // action. Since the next action for creating fatbin does @@ -2733,27 +2991,30 @@ class OffloadingActionBuilder final { // device arch of the next action being propagated to the above link // action. OffloadAction::DeviceDependences DDep; - DDep.add(*CudaDeviceActions[I], *ToolChains.front(), - CudaArchToString(GpuArchList[I]), AssociatedOffloadKind); + DDep.add(*CudaDeviceActions[I], *ToolChains.front(), GpuArchList[I], + AssociatedOffloadKind); CudaDeviceActions[I] = C.MakeAction<OffloadAction>( DDep, CudaDeviceActions[I]->getType()); } - // Create HIP fat binary with a special "link" action. - CudaFatBinary = - C.MakeAction<LinkJobAction>(CudaDeviceActions, - types::TY_HIP_FATBIN); - if (!CompileDeviceOnly) { - DA.add(*CudaFatBinary, *ToolChains.front(), /*BoundArch=*/nullptr, - AssociatedOffloadKind); - // Clear the fat binary, it is already a dependence to an host - // action. - CudaFatBinary = nullptr; - } + if (!CompileDeviceOnly || !BundleOutput.hasValue() || + BundleOutput.getValue()) { + // Create HIP fat binary with a special "link" action. + CudaFatBinary = C.MakeAction<LinkJobAction>(CudaDeviceActions, + types::TY_HIP_FATBIN); - // Remove the CUDA actions as they are already connected to an host - // action or fat binary. - CudaDeviceActions.clear(); + if (!CompileDeviceOnly) { + DA.add(*CudaFatBinary, *ToolChains.front(), /*BoundArch=*/nullptr, + AssociatedOffloadKind); + // 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(); + } return CompileDeviceOnly ? ABRT_Ignore_Host : ABRT_Success; } else if (CurPhase == phases::Link) { @@ -2780,21 +3041,63 @@ class OffloadingActionBuilder final { A = C.getDriver().ConstructPhaseAction(C, Args, CurPhase, A, AssociatedOffloadKind); + if (CompileDeviceOnly && CurPhase == FinalPhase && + BundleOutput.hasValue() && BundleOutput.getValue()) { + for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { + OffloadAction::DeviceDependences DDep; + DDep.add(*CudaDeviceActions[I], *ToolChains.front(), GpuArchList[I], + AssociatedOffloadKind); + CudaDeviceActions[I] = C.MakeAction<OffloadAction>( + DDep, CudaDeviceActions[I]->getType()); + } + CudaFatBinary = + C.MakeAction<OffloadBundlingJobAction>(CudaDeviceActions); + CudaDeviceActions.clear(); + } + return (CompileDeviceOnly && CurPhase == FinalPhase) ? ABRT_Ignore_Host : ABRT_Success; } - void appendLinkDependences(OffloadAction::DeviceDependences &DA) override { + void appendLinkDeviceActions(ActionList &AL) override { + if (DeviceLinkerInputs.size() == 0) + return; + + assert(DeviceLinkerInputs.size() == GpuArchList.size() && + "Linker inputs and GPU arch list sizes do not match."); + // Append a new link action for each device. unsigned I = 0; for (auto &LI : DeviceLinkerInputs) { + // Each entry in DeviceLinkerInputs corresponds to a GPU arch. auto *DeviceLinkAction = C.MakeAction<LinkJobAction>(LI, types::TY_Image); - DA.add(*DeviceLinkAction, *ToolChains[0], - CudaArchToString(GpuArchList[I]), AssociatedOffloadKind); + // Linking all inputs for the current GPU arch. + // LI contains all the inputs for the linker. + OffloadAction::DeviceDependences DeviceLinkDeps; + DeviceLinkDeps.add(*DeviceLinkAction, *ToolChains[0], + GpuArchList[I], AssociatedOffloadKind); + AL.push_back(C.MakeAction<OffloadAction>(DeviceLinkDeps, + DeviceLinkAction->getType())); ++I; } + DeviceLinkerInputs.clear(); + + // Create a host object from all the device images by embedding them + // in a fat binary. + OffloadAction::DeviceDependences DDeps; + auto *TopDeviceLinkAction = + C.MakeAction<LinkJobAction>(AL, types::TY_Object); + DDeps.add(*TopDeviceLinkAction, *ToolChains[0], + nullptr, AssociatedOffloadKind); + + // Offload the host object to the host linker. + AL.push_back(C.MakeAction<OffloadAction>(DDeps, TopDeviceLinkAction->getType())); } + + Action* appendLinkHostActions(ActionList &AL) override { return AL.back(); } + + void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {} }; /// OpenMP action builder. The host bitcode is passed to the device frontend @@ -2922,7 +3225,7 @@ class OffloadingActionBuilder final { OpenMPDeviceActions.clear(); } - void appendLinkActions(ActionList &AL) override { + void appendLinkDeviceActions(ActionList &AL) override { assert(ToolChains.size() == DeviceLinkerInputs.size() && "Toolchains and linker inputs sizes do not match."); @@ -2941,6 +3244,14 @@ class OffloadingActionBuilder final { DeviceLinkerInputs.clear(); } + Action* appendLinkHostActions(ActionList &AL) override { + // Create wrapper bitcode from the result of device link actions and compile + // it to an object which will be added to the host link command. + auto *BC = C.MakeAction<OffloadWrapperJobAction>(AL, types::TY_LLVM_BC); + auto *ASM = C.MakeAction<BackendJobAction>(BC, types::TY_PP_Asm); + return C.MakeAction<AssembleJobAction>(ASM, types::TY_Object); + } + void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {} bool initialize() override { @@ -3091,7 +3402,8 @@ public: // the input is not a bundle. if (CanUseBundler && isa<InputAction>(HostAction) && InputArg->getOption().getKind() == llvm::opt::Option::InputClass && - !types::isSrcFile(HostAction->getType())) { + (!types::isSrcFile(HostAction->getType()) || + HostAction->getType() == types::TY_PP_HIP)) { auto UnbundlingHostAction = C.MakeAction<OffloadUnbundlingJobAction>(HostAction); UnbundlingHostAction->registerDependentActionInfo( @@ -3173,17 +3485,20 @@ public: for (DeviceActionBuilder *SB : SpecializedBuilders) { if (!SB->isValid()) continue; - SB->appendLinkActions(DeviceAL); + SB->appendLinkDeviceActions(DeviceAL); } if (DeviceAL.empty()) return nullptr; - // Create wrapper bitcode from the result of device link actions and compile - // it to an object which will be added to the host link command. - auto *BC = C.MakeAction<OffloadWrapperJobAction>(DeviceAL, types::TY_LLVM_BC); - auto *ASM = C.MakeAction<BackendJobAction>(BC, types::TY_PP_Asm); - return C.MakeAction<AssembleJobAction>(ASM, types::TY_Object); + // Let builders add host linking actions. + Action* HA = nullptr; + for (DeviceActionBuilder *SB : SpecializedBuilders) { + if (!SB->isValid()) + continue; + HA = SB->appendLinkHostActions(DeviceAL); + } + return HA; } /// Processes the host linker action. This currently consists of replacing it @@ -3252,7 +3567,8 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, if (Args.hasArg(options::OPT_emit_llvm)) Diag(clang::diag::err_drv_emit_llvm_link); if (IsCLMode() && LTOMode != LTOK_None && - !Args.getLastArgValue(options::OPT_fuse_ld_EQ).equals_lower("lld")) + !Args.getLastArgValue(options::OPT_fuse_ld_EQ) + .equals_insensitive("lld")) Diag(clang::diag::err_drv_lto_without_lld); } @@ -3271,8 +3587,7 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, types::ID InputType = I.first; const Arg *InputArg = I.second; - llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PL; - types::getCompilationPhases(InputType, PL); + auto PL = types::getCompilationPhases(InputType); LastPLSize = PL.size(); // If the first step comes after the final phase we are doing as part of @@ -3317,11 +3632,9 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, // 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(HeaderType, PCHPL); // Build the pipeline for the pch file. Action *ClangClPch = C.MakeAction<InputAction>(*InputArg, HeaderType); - for (phases::ID Phase : PCHPL) + for (phases::ID Phase : types::getCompilationPhases(HeaderType)) ClangClPch = ConstructPhaseAction(C, Args, Phase, ClangClPch); assert(ClangClPch); Actions.push_back(ClangClPch); @@ -3404,13 +3717,11 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, types::ID InputType = I.first; const Arg *InputArg = I.second; - llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PL; - types::getCompilationPhases(*this, Args, InputType, PL); + auto PL = types::getCompilationPhases(*this, Args, InputType); if (PL.empty()) continue; - llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> FullPL; - types::getCompilationPhases(InputType, FullPL); + auto FullPL = types::getCompilationPhases(InputType); // Build the pipeline for this file. Action *Current = C.MakeAction<InputAction>(*InputArg, InputType); @@ -3493,7 +3804,13 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, if (!LinkerInputs.empty()) { if (Action *Wrapper = OffloadBuilder.makeHostLinkAction()) LinkerInputs.push_back(Wrapper); - Action *LA = C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image); + Action *LA; + // Check if this Linker Job should emit a static library. + if (ShouldEmitStaticLibrary(Args)) { + LA = C.MakeAction<StaticLibJobAction>(LinkerInputs, types::TY_Image); + } else { + LA = C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image); + } LA = OffloadBuilder.processHostLinkAction(LA); Actions.push_back(LA); } @@ -3504,15 +3821,9 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, C.MakeAction<IfsMergeJobAction>(MergerInputs, types::TY_Image)); if (Args.hasArg(options::OPT_emit_interface_stubs)) { - llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PhaseList; - if (Args.hasArg(options::OPT_c)) { - llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> CompilePhaseList; - types::getCompilationPhases(types::TY_IFS_CPP, CompilePhaseList); - llvm::copy_if(CompilePhaseList, std::back_inserter(PhaseList), - [&](phases::ID Phase) { return Phase <= phases::Compile; }); - } else { - types::getCompilationPhases(types::TY_IFS_CPP, PhaseList); - } + auto PhaseList = types::getCompilationPhases( + types::TY_IFS_CPP, + Args.hasArg(options::OPT_c) ? phases::Compile : phases::LastPhase); ActionList MergerInputs; @@ -3674,7 +3985,10 @@ Action *Driver::ConstructPhaseAction( Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC; return C.MakeAction<BackendJobAction>(Input, Output); } - if (Args.hasArg(options::OPT_emit_llvm)) { + if (Args.hasArg(options::OPT_emit_llvm) || + (TargetDeviceOffloadKind == Action::OFK_HIP && + Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, + false))) { types::ID Output = Args.hasArg(options::OPT_S) ? types::TY_LLVM_IR : types::TY_LLVM_BC; return C.MakeAction<BackendJobAction>(Input, Output); @@ -3725,9 +4039,18 @@ void Driver::BuildJobs(Compilation &C) const { } } + const llvm::Triple &RawTriple = C.getDefaultToolChain().getTriple(); + if (RawTriple.isOSAIX()) { + if (Arg *A = C.getArgs().getLastArg(options::OPT_G)) + Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << RawTriple.str(); + if (LTOMode == LTOK_Thin) + Diag(diag::err_drv_clang_unsupported) << "thinLTO on AIX"; + } + // Collect the list of architectures. llvm::StringSet<> ArchNames; - if (C.getDefaultToolChain().getTriple().isOSBinFormatMachO()) + if (RawTriple.isOSBinFormatMachO()) for (const Arg *A : C.getArgs()) if (A->getOption().matches(options::OPT_arch)) ArchNames.insert(A->getValue()); @@ -3757,11 +4080,68 @@ void Driver::BuildJobs(Compilation &C) const { /*TargetDeviceOffloadKind*/ Action::OFK_None); } - // If we have more than one job, then disable integrated-cc1 for now. - if (C.getJobs().size() > 1) + // If we have more than one job, then disable integrated-cc1 for now. Do this + // also when we need to report process execution statistics. + if (C.getJobs().size() > 1 || CCPrintProcessStats) for (auto &J : C.getJobs()) J.InProcess = false; + if (CCPrintProcessStats) { + C.setPostCallback([=](const Command &Cmd, int Res) { + Optional<llvm::sys::ProcessStatistics> ProcStat = + Cmd.getProcessStatistics(); + if (!ProcStat) + return; + + const char *LinkingOutput = nullptr; + if (FinalOutput) + LinkingOutput = FinalOutput->getValue(); + else if (!Cmd.getOutputFilenames().empty()) + LinkingOutput = Cmd.getOutputFilenames().front().c_str(); + else + LinkingOutput = getDefaultImageName(); + + if (CCPrintStatReportFilename.empty()) { + using namespace llvm; + // Human readable output. + outs() << sys::path::filename(Cmd.getExecutable()) << ": " + << "output=" << LinkingOutput; + outs() << ", total=" + << format("%.3f", ProcStat->TotalTime.count() / 1000.) << " ms" + << ", user=" + << format("%.3f", ProcStat->UserTime.count() / 1000.) << " ms" + << ", mem=" << ProcStat->PeakMemory << " Kb\n"; + } else { + // CSV format. + std::string Buffer; + llvm::raw_string_ostream Out(Buffer); + llvm::sys::printArg(Out, llvm::sys::path::filename(Cmd.getExecutable()), + /*Quote*/ true); + Out << ','; + llvm::sys::printArg(Out, LinkingOutput, true); + Out << ',' << ProcStat->TotalTime.count() << ',' + << ProcStat->UserTime.count() << ',' << ProcStat->PeakMemory + << '\n'; + Out.flush(); + std::error_code EC; + llvm::raw_fd_ostream OS(CCPrintStatReportFilename.c_str(), EC, + llvm::sys::fs::OF_Append | + llvm::sys::fs::OF_Text); + if (EC) + return; + auto L = OS.lock(); + if (!L) { + llvm::errs() << "ERROR: Cannot lock file " + << CCPrintStatReportFilename << ": " + << toString(L.takeError()) << "\n"; + return; + } + OS << Buffer; + OS.flush(); + } + }); + } + // If the user passed -Qunused-arguments or there were errors, don't warn // about any unused arguments. if (Diags.hasErrorOccurred() || @@ -4250,6 +4630,25 @@ InputInfo Driver::BuildJobsForActionNoCache( if (!T) return InputInfo(); + if (BuildingForOffloadDevice && + A->getOffloadingDeviceKind() == Action::OFK_OpenMP) { + if (TC->getTriple().isAMDGCN()) { + // AMDGCN treats backend and assemble actions as no-op because + // linker does not support object files. + if (const BackendJobAction *BA = dyn_cast<BackendJobAction>(A)) { + return BuildJobsForAction(C, *BA->input_begin(), TC, BoundArch, + AtTopLevel, MultipleArchs, LinkingOutput, + CachedResults, TargetDeviceOffloadKind); + } + + if (const AssembleJobAction *AA = dyn_cast<AssembleJobAction>(A)) { + return BuildJobsForAction(C, *AA->input_begin(), TC, BoundArch, + AtTopLevel, MultipleArchs, LinkingOutput, + CachedResults, TargetDeviceOffloadKind); + } + } + } + // If we've collapsed action list that contained OffloadAction we // need to build jobs for host/device-side inputs it may have held. for (const auto *OA : CollapsedOffloadActions) @@ -4369,11 +4768,12 @@ InputInfo Driver::BuildJobsForActionNoCache( /*CreatePrefixForHost=*/!!A->getOffloadingHostActiveKinds() && !AtTopLevel); if (isa<OffloadWrapperJobAction>(JA)) { - OffloadingPrefix += "-wrapper"; if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) BaseInput = FinalOutput->getValue(); else BaseInput = getDefaultImageName(); + BaseInput = + C.getArgs().MakeArgString(std::string(BaseInput) + "-wrapper"); } Result = InputInfo(A, GetNamedOutputPath(C, *JA, BaseInput, BoundArch, AtTopLevel, MultipleArchs, @@ -4453,11 +4853,29 @@ static const char *MakeCLOutputFilename(const ArgList &Args, StringRef ArgValue, return Args.MakeArgString(Filename.c_str()); } +static bool HasPreprocessOutput(const Action &JA) { + if (isa<PreprocessJobAction>(JA)) + return true; + if (isa<OffloadAction>(JA) && isa<PreprocessJobAction>(JA.getInputs()[0])) + return true; + if (isa<OffloadBundlingJobAction>(JA) && + HasPreprocessOutput(*(JA.getInputs()[0]))) + return true; + return false; +} + const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, const char *BaseInput, - StringRef BoundArch, bool AtTopLevel, + StringRef OrigBoundArch, bool AtTopLevel, bool MultipleArchs, StringRef OffloadingPrefix) const { + std::string BoundArch = OrigBoundArch.str(); +#if defined(_WIN32) + // BoundArch may contains ':', which is invalid in file names on Windows, + // therefore replace it with '%'. + std::replace(BoundArch.begin(), BoundArch.end(), ':', '@'); +#endif + llvm::PrettyStackTraceString CrashInfo("Computing output path"); // Output to a user requested destination? if (AtTopLevel && !isa<DsymutilJobAction>(JA) && !isa<VerifyJobAction>(JA)) { @@ -4478,8 +4896,14 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, } // Default to writing to stdout? - if (AtTopLevel && !CCGenDiagnostics && isa<PreprocessJobAction>(JA)) + if (AtTopLevel && !CCGenDiagnostics && HasPreprocessOutput(JA)) { return "-"; + } + + if (JA.getType() == types::TY_ModuleFile && + C.getArgs().getLastArg(options::OPT_module_file_info)) { + return "-"; + } // Is this the assembly listing for /FA? if (JA.getType() == types::TY_PP_Asm && @@ -4521,10 +4945,20 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, } SmallString<128> BasePath(BaseInput); + SmallString<128> ExternalPath(""); StringRef BaseName; // Dsymutil actions should use the full path. - if (isa<DsymutilJobAction>(JA) || isa<VerifyJobAction>(JA)) + if (isa<DsymutilJobAction>(JA) && C.getArgs().hasArg(options::OPT_dsym_dir)) { + ExternalPath += C.getArgs().getLastArg(options::OPT_dsym_dir)->getValue(); + // We use posix style here because the tests (specifically + // darwin-dsymutil.c) demonstrate that posix style paths are acceptable + // even on Windows and if we don't then the similar test covering this + // fails. + llvm::sys::path::append(ExternalPath, llvm::sys::path::Style::posix, + llvm::sys::path::filename(BasePath)); + BaseName = ExternalPath; + } else if (isa<DsymutilJobAction>(JA) || isa<VerifyJobAction>(JA)) BaseName = BasePath; else BaseName = llvm::sys::path::filename(BasePath); @@ -4594,8 +5028,19 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, // When using both -save-temps and -emit-llvm, use a ".tmp.bc" suffix for // the unoptimized bitcode so that it does not get overwritten by the ".bc" // optimized bitcode output. - if (!AtTopLevel && C.getArgs().hasArg(options::OPT_emit_llvm) && - JA.getType() == types::TY_LLVM_BC) + auto IsHIPRDCInCompilePhase = [](const JobAction &JA, + const llvm::opt::DerivedArgList &Args) { + // The relocatable compilation in HIP implies -emit-llvm. Similarly, use a + // ".tmp.bc" suffix for the unoptimized bitcode (generated in the compile + // phase.) + return isa<CompileJobAction>(JA) && + JA.getOffloadingDeviceKind() == Action::OFK_HIP && + Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, + false); + }; + if (!AtTopLevel && JA.getType() == types::TY_LLVM_BC && + (C.getArgs().hasArg(options::OPT_emit_llvm) || + IsHIPRDCInCompilePhase(JA, C.getArgs()))) Suffixed += ".tmp"; Suffixed += '.'; Suffixed += Suffix; @@ -4644,7 +5089,50 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, } } + +namespace { +static Optional<std::string> findFile(StringRef path1, const Twine &path2) { + SmallString<128> s; + llvm::sys::path::append(s, path1, path2); + + if (llvm::sys::fs::exists(s)) + return std::string(s); + return None; +} + +// Must be in sync with findMajMinShlib in lld/ELF/DriverUtils.cpp. +llvm::Optional<std::string> findMajMinShlib(StringRef dir, const Twine& libNameSo) { + // Handle OpenBSD-style maj/min shlib scheme + llvm::SmallString<128> Scratch; + const StringRef LibName = (libNameSo + ".").toStringRef(Scratch); + int MaxMaj = -1, MaxMin = -1; + std::error_code EC; + for (llvm::sys::fs::directory_iterator LI(dir, EC), LE; + LI != LE; LI = LI.increment(EC)) { + StringRef FilePath = LI->path(); + StringRef FileName = llvm::sys::path::filename(FilePath); + if (!(FileName.startswith(LibName))) + continue; + std::pair<StringRef, StringRef> MajMin = + FileName.substr(LibName.size()).split('.'); + int Maj, Min; + if (MajMin.first.getAsInteger(10, Maj) || Maj < 0) + continue; + if (MajMin.second.getAsInteger(10, Min) || Min < 0) + continue; + if (Maj > MaxMaj) + MaxMaj = Maj, MaxMin = Min; + if (MaxMaj == Maj && Min > MaxMin) + MaxMin = Min; + } + if (MaxMaj >= 0) + return findFile(dir, LibName + Twine(MaxMaj) + "." + Twine(MaxMin)); + return None; +} +} // namespace + std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const { + const bool lookForLibDotSo = Name.startswith("lib") && Name.endswith(".so"); // Search for Name in a list of paths. auto SearchPaths = [&](const llvm::SmallVectorImpl<std::string> &P) -> llvm::Optional<std::string> { @@ -4654,9 +5142,14 @@ std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const { if (Dir.empty()) continue; SmallString<128> P(Dir[0] == '=' ? SysRoot + Dir.substr(1) : Dir); - llvm::sys::path::append(P, Name); - if (llvm::sys::fs::exists(Twine(P))) - return P.str().str(); + if (!lookForLibDotSo) { + llvm::sys::path::append(P, Name); + if (llvm::sys::fs::exists(Twine(P))) + return std::string(P); + } else { + if (auto s = findMajMinShlib(P, Name)) + return std::string(*s); + } } return None; }; @@ -4667,17 +5160,17 @@ std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const { SmallString<128> R(ResourceDir); llvm::sys::path::append(R, Name); if (llvm::sys::fs::exists(Twine(R))) - return R.str(); + return std::string(R.str()); SmallString<128> P(TC.getCompilerRTPath()); llvm::sys::path::append(P, Name); if (llvm::sys::fs::exists(Twine(P))) - return P.str(); + return std::string(P.str()); SmallString<128> D(Dir); llvm::sys::path::append(D, "..", Name); if (llvm::sys::fs::exists(Twine(D))) - return D.str(); + return std::string(D.str()); if (auto P = SearchPaths(TC.getLibraryPaths())) return *P; @@ -4685,7 +5178,7 @@ std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const { if (auto P = SearchPaths(TC.getFilePaths())) return *P; - return Name; + return std::string(Name); } void Driver::generatePrefixedToolNames( @@ -4694,21 +5187,13 @@ void Driver::generatePrefixedToolNames( // FIXME: Needs a better variable than TargetTriple Names.emplace_back((TargetTriple + "-" + Tool).str()); Names.emplace_back(Tool); - - // Allow the discovery of tools prefixed with LLVM's default target triple. - std::string DefaultTargetTriple = llvm::sys::getDefaultTargetTriple(); - if (DefaultTargetTriple != TargetTriple) - Names.emplace_back((DefaultTargetTriple + "-" + Tool).str()); } -static bool ScanDirForExecutable(SmallString<128> &Dir, - ArrayRef<std::string> Names) { - for (const auto &Name : Names) { - llvm::sys::path::append(Dir, Name); - if (llvm::sys::fs::can_execute(Twine(Dir))) - return true; - llvm::sys::path::remove_filename(Dir); - } +static bool ScanDirForExecutable(SmallString<128> &Dir, StringRef Name) { + llvm::sys::path::append(Dir, Name); + if (llvm::sys::fs::can_execute(Twine(Dir))) + return true; + llvm::sys::path::remove_filename(Dir); return false; } @@ -4721,29 +5206,37 @@ std::string Driver::GetProgramPath(StringRef Name, const ToolChain &TC) const { for (const auto &PrefixDir : PrefixDirs) { if (llvm::sys::fs::is_directory(PrefixDir)) { SmallString<128> P(PrefixDir); - if (ScanDirForExecutable(P, TargetSpecificExecutables)) - return P.str(); + if (ScanDirForExecutable(P, Name)) + return std::string(P.str()); } else { SmallString<128> P((PrefixDir + Name).str()); if (llvm::sys::fs::can_execute(Twine(P))) - return P.str(); + return std::string(P.str()); } } const ToolChain::path_list &List = TC.getProgramPaths(); - for (const auto &Path : List) { - SmallString<128> P(Path); - if (ScanDirForExecutable(P, TargetSpecificExecutables)) - return P.str(); - } + for (const auto &TargetSpecificExecutable : TargetSpecificExecutables) { + // For each possible name of the tool look for it in + // program paths first, then the path. + // Higher priority names will be first, meaning that + // a higher priority name in the path will be found + // instead of a lower priority name in the program path. + // E.g. <triple>-gcc on the path will be found instead + // of gcc in the program path + for (const auto &Path : List) { + SmallString<128> P(Path); + if (ScanDirForExecutable(P, TargetSpecificExecutable)) + return std::string(P.str()); + } - // If all else failed, search the path. - for (const auto &TargetSpecificExecutable : TargetSpecificExecutables) + // Fall back to the path if (llvm::ErrorOr<std::string> P = llvm::sys::findProgramByName(TargetSpecificExecutable)) return *P; + } - return Name; + return std::string(Name); } std::string Driver::GetTemporaryPath(StringRef Prefix, StringRef Suffix) const { @@ -4754,7 +5247,7 @@ std::string Driver::GetTemporaryPath(StringRef Prefix, StringRef Suffix) const { return ""; } - return Path.str(); + return std::string(Path.str()); } std::string Driver::GetTemporaryDirectory(StringRef Prefix) const { @@ -4765,7 +5258,7 @@ std::string Driver::GetTemporaryDirectory(StringRef Prefix) const { return ""; } - return Path.str(); + return std::string(Path.str()); } std::string Driver::GetClPchPath(Compilation &C, StringRef BaseName) const { @@ -4787,7 +5280,7 @@ std::string Driver::GetClPchPath(Compilation &C, StringRef BaseName) const { Output = BaseName; llvm::sys::path::replace_extension(Output, ".pch"); } - return Output.str(); + return std::string(Output.str()); } const ToolChain &Driver::getToolChain(const ArgList &Args, @@ -4839,11 +5332,12 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, !Target.hasEnvironment()) TC = std::make_unique<toolchains::MipsLLVMToolChain>(*this, Target, Args); - else if (Target.getArch() == llvm::Triple::ppc || - Target.getArch() == llvm::Triple::ppc64 || - Target.getArch() == llvm::Triple::ppc64le) + else if (Target.isPPC()) TC = std::make_unique<toolchains::PPCLinuxToolChain>(*this, Target, Args); + else if (Target.getArch() == llvm::Triple::ve) + TC = std::make_unique<toolchains::VEToolChain>(*this, Target, Args); + else TC = std::make_unique<toolchains::Linux>(*this, Target, Args); break; @@ -4857,6 +5351,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, TC = std::make_unique<toolchains::Solaris>(*this, Target, Args); break; case llvm::Triple::AMDHSA: + TC = std::make_unique<toolchains::ROCMToolChain>(*this, Target, Args); + break; case llvm::Triple::AMDPAL: case llvm::Triple::Mesa3D: TC = std::make_unique<toolchains::AMDGPUToolChain>(*this, Target, Args); @@ -4881,7 +5377,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::MSVC: case llvm::Triple::UnknownEnvironment: if (Args.getLastArgValue(options::OPT_fuse_ld_EQ) - .startswith_lower("bfd")) + .startswith_insensitive("bfd")) TC = std::make_unique<toolchains::CrossWindowsToolChain>( *this, Target, Args); else @@ -4899,6 +5395,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::Hurd: TC = std::make_unique<toolchains::Hurd>(*this, Target, Args); break; + case llvm::Triple::ZOS: + TC = std::make_unique<toolchains::ZOS>(*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. @@ -4932,7 +5431,14 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, break; case llvm::Triple::riscv32: case llvm::Triple::riscv64: - TC = std::make_unique<toolchains::RISCVToolChain>(*this, Target, Args); + if (toolchains::RISCVToolChain::hasGCCToolchain(*this, Args)) + TC = + std::make_unique<toolchains::RISCVToolChain>(*this, Target, Args); + else + TC = std::make_unique<toolchains::BareMetal>(*this, Target, Args); + break; + case llvm::Triple::ve: + TC = std::make_unique<toolchains::VEToolChain>(*this, Target, Args); break; default: if (Target.getVendor() == llvm::Triple::Myriad) @@ -4985,6 +5491,13 @@ bool Driver::ShouldUseFlangCompiler(const JobAction &JA) const { return true; } +bool Driver::ShouldEmitStaticLibrary(const ArgList &Args) const { + // Only emit static library if the flag is set explicitly. + if (Args.hasArg(options::OPT_emit_static_lib)) + return true; + return false; +} + /// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the /// grouped values as integers. Numbers which are not provided are set to 0. /// @@ -5093,3 +5606,20 @@ bool clang::driver::willEmitRemarks(const ArgList &Args) { return true; return false; } + +llvm::StringRef clang::driver::getDriverMode(StringRef ProgName, + ArrayRef<const char *> Args) { + static const std::string OptName = + getDriverOptTable().getOption(options::OPT_driver_mode).getPrefixedName(); + llvm::StringRef Opt; + for (StringRef Arg : Args) { + if (!Arg.startswith(OptName)) + continue; + Opt = Arg; + } + if (Opt.empty()) + Opt = ToolChain::getTargetAndModeFromProgramName(ProgName).DriverMode; + return Opt.consume_front(OptName) ? Opt : ""; +} + +bool driver::IsClangCL(StringRef DriverMode) { return DriverMode.equals("cl"); } diff --git a/gnu/llvm/lld/ELF/DriverUtils.cpp b/gnu/llvm/lld/ELF/DriverUtils.cpp index 6b164e30677..2fee8538913 100644 --- a/gnu/llvm/lld/ELF/DriverUtils.cpp +++ b/gnu/llvm/lld/ELF/DriverUtils.cpp @@ -230,6 +230,38 @@ Optional<std::string> elf::findFromSearchPaths(StringRef path) { return None; } +namespace { +// Must be in sync with findMajMinShlib in clang/lib/Driver/Driver.cpp. +llvm::Optional<std::string> findMajMinShlib(StringRef dir, const Twine& libNameSo) { + // Handle OpenBSD-style maj/min shlib scheme + llvm::SmallString<128> Scratch; + const StringRef LibName = (libNameSo + ".").toStringRef(Scratch); + int MaxMaj = -1, MaxMin = -1; + std::error_code EC; + for (llvm::sys::fs::directory_iterator LI(dir, EC), LE; + LI != LE; LI = LI.increment(EC)) { + StringRef FilePath = LI->path(); + StringRef FileName = llvm::sys::path::filename(FilePath); + if (!(FileName.startswith(LibName))) + continue; + std::pair<StringRef, StringRef> MajMin = + FileName.substr(LibName.size()).split('.'); + int Maj, Min; + if (MajMin.first.getAsInteger(10, Maj) || Maj < 0) + continue; + if (MajMin.second.getAsInteger(10, Min) || Min < 0) + continue; + if (Maj > MaxMaj) + MaxMaj = Maj, MaxMin = Min; + if (MaxMaj == Maj && Min > MaxMin) + MaxMin = Min; + } + if (MaxMaj >= 0) + return findFile(dir, LibName + Twine(MaxMaj) + "." + Twine(MaxMin)); + return None; +} +} // namespace + // This is for -l<basename>. We'll look for lib<basename>.so or lib<basename>.a from // search paths. Optional<std::string> elf::searchLibraryBaseName(StringRef name) { @@ -237,32 +269,8 @@ Optional<std::string> elf::searchLibraryBaseName(StringRef name) { if (!config->isStatic) { if (Optional<std::string> s = findFile(dir, "lib" + name + ".so")) return s; - - // Handle OpenBSD-style maj/min shlib scheme - llvm::SmallString<128> Scratch; - const StringRef LibName = ("lib" + name + ".so.").toStringRef(Scratch); - int MaxMaj = -1, MaxMin = -1; - std::error_code EC; - for (fs::directory_iterator LI(dir, EC), LE; - LI != LE; LI = LI.increment(EC)) { - StringRef FilePath = LI->path(); - StringRef FileName = path::filename(FilePath); - if (!(FileName.startswith(LibName))) - continue; - std::pair<StringRef, StringRef> MajMin = - FileName.substr(LibName.size()).split('.'); - int Maj, Min; - if (MajMin.first.getAsInteger(10, Maj) || Maj < 0) - continue; - if (MajMin.second.getAsInteger(10, Min) || Min < 0) - continue; - if (Maj > MaxMaj) - MaxMaj = Maj, MaxMin = Min; - if (MaxMaj == Maj && Min > MaxMin) - MaxMin = Min; - } - if (MaxMaj >= 0) - return findFile(dir, LibName + Twine(MaxMaj) + "." + Twine(MaxMin)); + if (Optional<std::string> s = findMajMinShlib(dir, "lib" + name + ".so")) + return s; } if (Optional<std::string> s = findFile(dir, "lib" + name + ".a")) return s; |