summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Steuck <gnezdo@cvs.openbsd.org>2022-03-04 16:46:24 +0000
committerGreg Steuck <gnezdo@cvs.openbsd.org>2022-03-04 16:46:24 +0000
commit93dfb9c84a51ff32677cdef21bc79b73c5ccc3e1 (patch)
treefa47f02f3292f2adcde2270c975798acd0d53d97
parent5db61140f844a379a7b1bcb5facf8f8141a4c027 (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.cpp1034
-rw-r--r--gnu/llvm/lld/ELF/DriverUtils.cpp60
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;