aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Driver/Driver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Driver/Driver.cpp')
-rw-r--r--clang/lib/Driver/Driver.cpp1199
1 files changed, 625 insertions, 574 deletions
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 3f29afd35971..661d9977fbc5 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -94,8 +94,10 @@
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h"
+#include <cstdlib> // ::getenv
#include <map>
#include <memory>
+#include <optional>
#include <utility>
#if LLVM_ON_UNIX
#include <unistd.h> // getpid
@@ -105,8 +107,8 @@ using namespace clang::driver;
using namespace clang;
using namespace llvm::opt;
-static llvm::Optional<llvm::Triple>
-getOffloadTargetTriple(const Driver &D, const ArgList &Args) {
+static std::optional<llvm::Triple> getOffloadTargetTriple(const Driver &D,
+ const ArgList &Args) {
auto OffloadTargets = Args.getAllArgValues(options::OPT_offload_EQ);
// Offload compilation flow does not support multiple targets for now. We
// need the HIPActionBuilder (and possibly the CudaActionBuilder{,Base}too)
@@ -114,17 +116,17 @@ getOffloadTargetTriple(const Driver &D, const ArgList &Args) {
switch (OffloadTargets.size()) {
default:
D.Diag(diag::err_drv_only_one_offload_target_supported);
- return llvm::None;
+ return std::nullopt;
case 0:
D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << "";
- return llvm::None;
+ return std::nullopt;
case 1:
break;
}
return llvm::Triple(OffloadTargets[0]);
}
-static llvm::Optional<llvm::Triple>
+static std::optional<llvm::Triple>
getNVIDIAOffloadTargetTriple(const Driver &D, const ArgList &Args,
const llvm::Triple &HostTriple) {
if (!Args.hasArg(options::OPT_offload_EQ)) {
@@ -137,19 +139,19 @@ getNVIDIAOffloadTargetTriple(const Driver &D, const ArgList &Args,
if (Args.hasArg(options::OPT_emit_llvm))
return TT;
D.Diag(diag::err_drv_cuda_offload_only_emit_bc);
- return llvm::None;
+ return std::nullopt;
}
D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << TT->str();
- return llvm::None;
+ return std::nullopt;
}
-static llvm::Optional<llvm::Triple>
+static std::optional<llvm::Triple>
getHIPOffloadTargetTriple(const Driver &D, const ArgList &Args) {
if (!Args.hasArg(options::OPT_offload_EQ)) {
return llvm::Triple("amdgcn-amd-amdhsa"); // Default HIP triple.
}
auto TT = getOffloadTargetTriple(D, Args);
if (!TT)
- return llvm::None;
+ return std::nullopt;
if (TT->getArch() == llvm::Triple::amdgcn &&
TT->getVendor() == llvm::Triple::AMD &&
TT->getOS() == llvm::Triple::AMDHSA)
@@ -157,7 +159,7 @@ getHIPOffloadTargetTriple(const Driver &D, const ArgList &Args) {
if (TT->getArch() == llvm::Triple::spirv64)
return TT;
D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << TT->str();
- return llvm::None;
+ return std::nullopt;
}
// static
@@ -180,8 +182,8 @@ std::string Driver::GetResourcesPath(StringRef BinaryPath,
// path of the embedding binary, which for LLVM binaries will be in bin/.
// ../lib gets us to lib/ in both cases.
P = llvm::sys::path::parent_path(Dir);
- llvm::sys::path::append(P, Twine("lib") + CLANG_LIBDIR_SUFFIX, "clang",
- CLANG_VERSION_STRING);
+ llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang",
+ CLANG_VERSION_MAJOR_STRING);
}
return std::string(P.str());
@@ -196,7 +198,7 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
ModulesModeCXX20(false), LTOMode(LTOK_None),
ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
DriverTitle(Title), CCCPrintBindings(false), CCPrintOptions(false),
- CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false),
+ CCLogDiagnostics(false), CCGenDiagnostics(false),
CCPrintProcessStats(false), TargetTriple(TargetTriple), Saver(Alloc),
CheckInputsExist(true), ProbePrecompiled(true),
SuppressMissingInputWarning(false) {
@@ -219,7 +221,11 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
SystemConfigDir = CLANG_CONFIG_FILE_SYSTEM_DIR;
#endif
#if defined(CLANG_CONFIG_FILE_USER_DIR)
- UserConfigDir = CLANG_CONFIG_FILE_USER_DIR;
+ {
+ SmallString<128> P;
+ llvm::sys::fs::expand_tilde(CLANG_CONFIG_FILE_USER_DIR, P);
+ UserConfigDir = static_cast<std::string>(P);
+ }
#endif
// Compute the path to the resource directory.
@@ -229,14 +235,14 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
void Driver::setDriverMode(StringRef Value) {
static const std::string OptName =
getOpts().getOption(options::OPT_driver_mode).getPrefixedName();
- if (auto M = llvm::StringSwitch<llvm::Optional<DriverMode>>(Value)
+ if (auto M = llvm::StringSwitch<std::optional<DriverMode>>(Value)
.Case("gcc", GCCMode)
.Case("g++", GXXMode)
.Case("cpp", CPPMode)
.Case("cl", CLMode)
.Case("flang", FlangMode)
.Case("dxc", DXCMode)
- .Default(None))
+ .Default(std::nullopt))
Mode = *M;
else
Diag(diag::err_drv_unsupported_option_argument) << OptName << Value;
@@ -305,11 +311,17 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings,
unsigned DiagID;
auto ArgString = A->getAsString(Args);
std::string Nearest;
- if (getOpts().findNearest(
- ArgString, Nearest, IncludedFlagsBitmask, ExcludedFlagsBitmask) > 1) {
- DiagID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl
- : diag::err_drv_unknown_argument;
- Diags.Report(DiagID) << ArgString;
+ if (getOpts().findNearest(ArgString, Nearest, IncludedFlagsBitmask,
+ ExcludedFlagsBitmask) > 1) {
+ if (!IsCLMode() &&
+ getOpts().findExact(ArgString, Nearest, options::CC1Option)) {
+ DiagID = diag::err_drv_unknown_argument_with_suggestion;
+ Diags.Report(DiagID) << ArgString << "-Xclang " + Nearest;
+ } else {
+ DiagID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl
+ : diag::err_drv_unknown_argument;
+ Diags.Report(DiagID) << ArgString;
+ }
} else {
DiagID = IsCLMode()
? diag::warn_drv_unknown_argument_clang_cl_with_suggestion
@@ -320,6 +332,19 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings,
DiagnosticsEngine::Warning;
}
+ for (const Arg *A : Args.filtered(options::OPT_o)) {
+ if (ArgStrings[A->getIndex()] == A->getSpelling())
+ continue;
+
+ // Warn on joined arguments that are similar to a long argument.
+ std::string ArgString = ArgStrings[A->getIndex()];
+ std::string Nearest;
+ if (getOpts().findExact("-" + ArgString, Nearest, IncludedFlagsBitmask,
+ ExcludedFlagsBitmask))
+ Diags.Report(diag::warn_drv_potentially_misspelled_joined_argument)
+ << A->getAsString(Args) << Nearest;
+ }
+
return Args;
}
@@ -551,7 +576,7 @@ static llvm::Triple computeTargetTriple(const Driver &D,
// On AIX, the env OBJECT_MODE may affect the resulting arch variant.
if (Target.isOSAIX()) {
- if (Optional<std::string> ObjectModeValue =
+ if (std::optional<std::string> ObjectModeValue =
llvm::sys::Process::GetEnv("OBJECT_MODE")) {
StringRef ObjectMode = *ObjectModeValue;
llvm::Triple::ArchType AT = llvm::Triple::UnknownArch;
@@ -628,36 +653,38 @@ static llvm::Triple computeTargetTriple(const Driver &D,
// If target is MIPS adjust the target triple
// accordingly to provided ABI name.
- A = Args.getLastArg(options::OPT_mabi_EQ);
- if (A && Target.isMIPS()) {
- StringRef ABIName = A->getValue();
- if (ABIName == "32") {
- Target = Target.get32BitArchVariant();
- if (Target.getEnvironment() == llvm::Triple::GNUABI64 ||
- Target.getEnvironment() == llvm::Triple::GNUABIN32)
- Target.setEnvironment(llvm::Triple::GNU);
- } else if (ABIName == "n32") {
- Target = Target.get64BitArchVariant();
- if (Target.getEnvironment() == llvm::Triple::GNU ||
- Target.getEnvironment() == llvm::Triple::GNUABI64)
- Target.setEnvironment(llvm::Triple::GNUABIN32);
- } else if (ABIName == "64") {
- Target = Target.get64BitArchVariant();
- if (Target.getEnvironment() == llvm::Triple::GNU ||
- Target.getEnvironment() == llvm::Triple::GNUABIN32)
- Target.setEnvironment(llvm::Triple::GNUABI64);
+ if (Target.isMIPS()) {
+ if ((A = Args.getLastArg(options::OPT_mabi_EQ))) {
+ StringRef ABIName = A->getValue();
+ if (ABIName == "32") {
+ Target = Target.get32BitArchVariant();
+ if (Target.getEnvironment() == llvm::Triple::GNUABI64 ||
+ Target.getEnvironment() == llvm::Triple::GNUABIN32)
+ Target.setEnvironment(llvm::Triple::GNU);
+ } else if (ABIName == "n32") {
+ Target = Target.get64BitArchVariant();
+ if (Target.getEnvironment() == llvm::Triple::GNU ||
+ Target.getEnvironment() == llvm::Triple::GNUABI64)
+ Target.setEnvironment(llvm::Triple::GNUABIN32);
+ } else if (ABIName == "64") {
+ Target = Target.get64BitArchVariant();
+ if (Target.getEnvironment() == llvm::Triple::GNU ||
+ Target.getEnvironment() == llvm::Triple::GNUABIN32)
+ Target.setEnvironment(llvm::Triple::GNUABI64);
+ }
}
}
// If target is RISC-V adjust the target triple according to
// provided architecture name
- A = Args.getLastArg(options::OPT_march_EQ);
- if (A && Target.isRISCV()) {
- StringRef ArchName = A->getValue();
- if (ArchName.startswith_insensitive("rv32"))
- Target.setArch(llvm::Triple::riscv32);
- else if (ArchName.startswith_insensitive("rv64"))
- Target.setArch(llvm::Triple::riscv64);
+ if (Target.isRISCV()) {
+ if ((A = Args.getLastArg(options::OPT_march_EQ))) {
+ StringRef ArchName = A->getValue();
+ if (ArchName.startswith_insensitive("rv32"))
+ Target.setArch(llvm::Triple::riscv32);
+ else if (ArchName.startswith_insensitive("rv64"))
+ Target.setArch(llvm::Triple::riscv64);
+ }
}
return Target;
@@ -681,7 +708,7 @@ static driver::LTOKind parseLTOMode(Driver &D, const llvm::opt::ArgList &Args,
if (LTOMode == LTOK_Unknown) {
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << A->getValue();
+ << A->getSpelling() << A->getValue();
return LTOK_None;
}
return LTOMode;
@@ -694,6 +721,17 @@ void Driver::setLTOMode(const llvm::opt::ArgList &Args) {
OffloadLTOMode = parseLTOMode(*this, Args, options::OPT_foffload_lto_EQ,
options::OPT_fno_offload_lto);
+
+ // Try to enable `-foffload-lto=full` if `-fopenmp-target-jit` is on.
+ if (Args.hasFlag(options::OPT_fopenmp_target_jit,
+ options::OPT_fno_openmp_target_jit, false)) {
+ if (Arg *A = Args.getLastArg(options::OPT_foffload_lto_EQ,
+ options::OPT_fno_offload_lto))
+ if (OffloadLTOMode != LTOK_Full)
+ Diag(diag::err_drv_incompatible_options)
+ << A->getSpelling() << "-fopenmp-target-jit";
+ OffloadLTOMode = LTOK_Full;
+ }
}
/// Compute the desired OpenMP runtime from the flags provided.
@@ -713,7 +751,7 @@ Driver::OpenMPRuntimeKind Driver::getOpenMPRuntime(const ArgList &Args) const {
if (RT == OMPRT_Unknown) {
if (A)
Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << A->getValue();
+ << A->getSpelling() << A->getValue();
else
// FIXME: We could use a nicer diagnostic here.
Diag(diag::err_drv_unsupported_opt) << "-fopenmp";
@@ -757,7 +795,7 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
auto &CudaTC = ToolChains[CudaTriple->str() + "/" + HostTriple.str()];
if (!CudaTC) {
CudaTC = std::make_unique<toolchains::CudaToolChain>(
- *this, *CudaTriple, *HostTC, C.getInputArgs(), OFK);
+ *this, *CudaTriple, *HostTC, C.getInputArgs());
}
C.addOffloadDeviceToolChain(CudaTC.get(), OFK);
} else if (IsHIP) {
@@ -821,9 +859,30 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
HostTC->getTriple());
// Attempt to deduce the offloading triple from the set of architectures.
- // We can only correctly deduce NVPTX / AMDGPU triples currently.
- llvm::DenseSet<StringRef> Archs =
- getOffloadArchs(C, C.getArgs(), Action::OFK_OpenMP, nullptr);
+ // We can only correctly deduce NVPTX / AMDGPU triples currently. We need
+ // to temporarily create these toolchains so that we can access tools for
+ // inferring architectures.
+ llvm::DenseSet<StringRef> Archs;
+ if (NVPTXTriple) {
+ auto TempTC = std::make_unique<toolchains::CudaToolChain>(
+ *this, *NVPTXTriple, *HostTC, C.getInputArgs());
+ for (StringRef Arch : getOffloadArchs(
+ C, C.getArgs(), Action::OFK_OpenMP, &*TempTC, true))
+ Archs.insert(Arch);
+ }
+ if (AMDTriple) {
+ auto TempTC = std::make_unique<toolchains::AMDGPUOpenMPToolChain>(
+ *this, *AMDTriple, *HostTC, C.getInputArgs());
+ for (StringRef Arch : getOffloadArchs(
+ C, C.getArgs(), Action::OFK_OpenMP, &*TempTC, true))
+ Archs.insert(Arch);
+ }
+ if (!AMDTriple && !NVPTXTriple) {
+ for (StringRef Arch :
+ getOffloadArchs(C, C.getArgs(), Action::OFK_OpenMP, nullptr, true))
+ Archs.insert(Arch);
+ }
+
for (StringRef Arch : Archs) {
if (NVPTXTriple && IsNVIDIAGpuArch(StringToCudaArch(
getProcessorFromTargetID(*NVPTXTriple, Arch)))) {
@@ -838,6 +897,13 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
}
}
+ // If the set is empty then we failed to find a native architecture.
+ if (Archs.empty()) {
+ Diag(clang::diag::err_drv_failed_to_deduce_target_from_arch)
+ << "native";
+ return;
+ }
+
for (const auto &TripleAndArchs : DerivedArchs)
OpenMPTriples.push_back(TripleAndArchs.first());
}
@@ -874,7 +940,7 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
if (!DeviceTC) {
if (TT.isNVPTX())
DeviceTC = std::make_unique<toolchains::CudaToolChain>(
- *this, TT, *HostTC, C.getInputArgs(), Action::OFK_OpenMP);
+ *this, TT, *HostTC, C.getInputArgs());
else if (TT.isAMDGCN())
DeviceTC = std::make_unique<toolchains::AMDGPUOpenMPToolChain>(
*this, TT, *HostTC, C.getInputArgs());
@@ -900,69 +966,78 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
//
}
-/// Looks the given directories for the specified file.
-///
-/// \param[out] FilePath File path, if the file was found.
-/// \param[in] Dirs Directories used for the search.
-/// \param[in] FileName Name of the file to search for.
-/// \return True if file was found.
-///
-/// Looks for file specified by FileName sequentially in directories specified
-/// by Dirs.
-///
-static bool searchForFile(SmallVectorImpl<char> &FilePath,
- ArrayRef<StringRef> Dirs, StringRef FileName) {
- SmallString<128> WPath;
- for (const StringRef &Dir : Dirs) {
- if (Dir.empty())
- continue;
- WPath.clear();
- llvm::sys::path::append(WPath, Dir, FileName);
- llvm::sys::path::native(WPath);
- if (llvm::sys::fs::is_regular_file(WPath)) {
- FilePath = std::move(WPath);
- return true;
- }
- }
- return false;
+static void appendOneArg(InputArgList &Args, const Arg *Opt,
+ const Arg *BaseArg) {
+ // The args for config files or /clang: flags belong to different InputArgList
+ // objects than Args. This copies an Arg from one of those other InputArgLists
+ // to the ownership of Args.
+ 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);
}
-bool Driver::readConfigFile(StringRef FileName) {
+bool Driver::readConfigFile(StringRef FileName,
+ llvm::cl::ExpansionContext &ExpCtx) {
+ // Try opening the given file.
+ auto Status = getVFS().status(FileName);
+ if (!Status) {
+ Diag(diag::err_drv_cannot_open_config_file)
+ << FileName << Status.getError().message();
+ return true;
+ }
+ if (Status->getType() != llvm::sys::fs::file_type::regular_file) {
+ Diag(diag::err_drv_cannot_open_config_file)
+ << FileName << "not a regular file";
+ return true;
+ }
+
// Try reading the given file.
SmallVector<const char *, 32> NewCfgArgs;
- if (!llvm::cl::readConfigFile(FileName, Saver, NewCfgArgs)) {
- Diag(diag::err_drv_cannot_read_config_file) << FileName;
+ if (llvm::Error Err = ExpCtx.readConfigFile(FileName, NewCfgArgs)) {
+ Diag(diag::err_drv_cannot_read_config_file)
+ << FileName << toString(std::move(Err));
return true;
}
// Read options from config file.
llvm::SmallString<128> CfgFileName(FileName);
llvm::sys::path::native(CfgFileName);
- ConfigFile = std::string(CfgFileName);
bool ContainErrors;
- CfgOptions = std::make_unique<InputArgList>(
+ std::unique_ptr<InputArgList> NewOptions = std::make_unique<InputArgList>(
ParseArgStrings(NewCfgArgs, IsCLMode(), ContainErrors));
- if (ContainErrors) {
- CfgOptions.reset();
- return true;
- }
-
- if (CfgOptions->hasArg(options::OPT_config)) {
- CfgOptions.reset();
- Diag(diag::err_drv_nested_config_file);
+ if (ContainErrors)
return true;
- }
// Claim all arguments that come from a configuration file so that the driver
// does not warn on any that is unused.
- for (Arg *A : *CfgOptions)
+ for (Arg *A : *NewOptions)
A->claim();
+
+ if (!CfgOptions)
+ CfgOptions = std::move(NewOptions);
+ else {
+ // If this is a subsequent config file, append options to the previous one.
+ for (auto *Opt : *NewOptions) {
+ const Arg *BaseArg = &Opt->getBaseArg();
+ if (BaseArg == Opt)
+ BaseArg = nullptr;
+ appendOneArg(*CfgOptions, Opt, BaseArg);
+ }
+ }
+ ConfigFiles.push_back(std::string(CfgFileName));
return false;
}
-bool Driver::loadConfigFile() {
- std::string CfgFileName;
- bool FileSpecifiedExplicitly = false;
+bool Driver::loadConfigFiles() {
+ llvm::cl::ExpansionContext ExpCtx(Saver.getAllocator(),
+ llvm::cl::tokenizeConfigFile);
+ ExpCtx.setVFS(&getVFS());
// Process options that change search path for config files.
if (CLOptions) {
@@ -970,143 +1045,141 @@ bool Driver::loadConfigFile() {
SmallString<128> CfgDir;
CfgDir.append(
CLOptions->getLastArgValue(options::OPT_config_system_dir_EQ));
- if (!CfgDir.empty()) {
- if (llvm::sys::fs::make_absolute(CfgDir).value() != 0)
- SystemConfigDir.clear();
- else
- SystemConfigDir = static_cast<std::string>(CfgDir);
- }
+ if (CfgDir.empty() || getVFS().makeAbsolute(CfgDir))
+ SystemConfigDir.clear();
+ else
+ SystemConfigDir = static_cast<std::string>(CfgDir);
}
if (CLOptions->hasArg(options::OPT_config_user_dir_EQ)) {
SmallString<128> CfgDir;
- CfgDir.append(
- CLOptions->getLastArgValue(options::OPT_config_user_dir_EQ));
- if (!CfgDir.empty()) {
- if (llvm::sys::fs::make_absolute(CfgDir).value() != 0)
- UserConfigDir.clear();
- else
- UserConfigDir = static_cast<std::string>(CfgDir);
- }
+ llvm::sys::fs::expand_tilde(
+ CLOptions->getLastArgValue(options::OPT_config_user_dir_EQ), CfgDir);
+ if (CfgDir.empty() || getVFS().makeAbsolute(CfgDir))
+ UserConfigDir.clear();
+ else
+ UserConfigDir = static_cast<std::string>(CfgDir);
}
}
- // First try to find config file specified in command line.
- if (CLOptions) {
- std::vector<std::string> ConfigFiles =
- CLOptions->getAllArgValues(options::OPT_config);
- if (ConfigFiles.size() > 1) {
- if (!llvm::all_of(ConfigFiles, [ConfigFiles](const std::string &s) {
- return s == ConfigFiles[0];
- })) {
- Diag(diag::err_drv_duplicate_config);
- return true;
- }
- }
+ // Prepare list of directories where config file is searched for.
+ StringRef CfgFileSearchDirs[] = {UserConfigDir, SystemConfigDir, Dir};
+ ExpCtx.setSearchDirs(CfgFileSearchDirs);
- if (!ConfigFiles.empty()) {
- CfgFileName = ConfigFiles.front();
- assert(!CfgFileName.empty());
+ // First try to load configuration from the default files, return on error.
+ if (loadDefaultConfigFiles(ExpCtx))
+ return true;
+ // Then load configuration files specified explicitly.
+ SmallString<128> CfgFilePath;
+ if (CLOptions) {
+ for (auto CfgFileName : CLOptions->getAllArgValues(options::OPT_config)) {
// If argument contains directory separator, treat it as a path to
// configuration file.
if (llvm::sys::path::has_parent_path(CfgFileName)) {
- SmallString<128> CfgFilePath;
- if (llvm::sys::path::is_relative(CfgFileName))
- llvm::sys::fs::current_path(CfgFilePath);
- llvm::sys::path::append(CfgFilePath, CfgFileName);
- if (!llvm::sys::fs::is_regular_file(CfgFilePath)) {
- Diag(diag::err_drv_config_file_not_exist) << CfgFilePath;
- return true;
+ CfgFilePath.assign(CfgFileName);
+ if (llvm::sys::path::is_relative(CfgFilePath)) {
+ if (getVFS().makeAbsolute(CfgFilePath)) {
+ Diag(diag::err_drv_cannot_open_config_file)
+ << CfgFilePath << "cannot get absolute path";
+ return true;
+ }
}
- return readConfigFile(CfgFilePath);
+ } else if (!ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) {
+ // Report an error that the config file could not be found.
+ Diag(diag::err_drv_config_file_not_found) << CfgFileName;
+ for (const StringRef &SearchDir : CfgFileSearchDirs)
+ if (!SearchDir.empty())
+ Diag(diag::note_drv_config_file_searched_in) << SearchDir;
+ return true;
}
- FileSpecifiedExplicitly = true;
+ // Try to read the config file, return on error.
+ if (readConfigFile(CfgFilePath, ExpCtx))
+ return true;
}
}
- // If config file is not specified explicitly, try to deduce configuration
- // from executable name. For instance, an executable 'armv7l-clang' will
- // search for config file 'armv7l-clang.cfg'.
- if (CfgFileName.empty() && !ClangNameParts.TargetPrefix.empty())
- CfgFileName = ClangNameParts.TargetPrefix + '-' + ClangNameParts.ModeSuffix;
+ // No error occurred.
+ return false;
+}
- if (CfgFileName.empty())
+bool Driver::loadDefaultConfigFiles(llvm::cl::ExpansionContext &ExpCtx) {
+ // Disable default config if CLANG_NO_DEFAULT_CONFIG is set to a non-empty
+ // value.
+ if (const char *NoConfigEnv = ::getenv("CLANG_NO_DEFAULT_CONFIG")) {
+ if (*NoConfigEnv)
+ return false;
+ }
+ if (CLOptions && CLOptions->hasArg(options::OPT_no_default_config))
return false;
- // Determine architecture part of the file name, if it is present.
- StringRef CfgFileArch = CfgFileName;
- size_t ArchPrefixLen = CfgFileArch.find('-');
- if (ArchPrefixLen == StringRef::npos)
- ArchPrefixLen = CfgFileArch.size();
- llvm::Triple CfgTriple;
- CfgFileArch = CfgFileArch.take_front(ArchPrefixLen);
- CfgTriple = llvm::Triple(llvm::Triple::normalize(CfgFileArch));
- if (CfgTriple.getArch() == llvm::Triple::ArchType::UnknownArch)
- ArchPrefixLen = 0;
-
- if (!StringRef(CfgFileName).endswith(".cfg"))
- CfgFileName += ".cfg";
-
- // If config file starts with architecture name and command line options
- // redefine architecture (with options like -m32 -LE etc), try finding new
- // config file with that architecture.
- SmallString<128> FixedConfigFile;
- size_t FixedArchPrefixLen = 0;
- if (ArchPrefixLen) {
- // Get architecture name from config file name like 'i386.cfg' or
- // 'armv7l-clang.cfg'.
- // Check if command line options changes effective triple.
- llvm::Triple EffectiveTriple = computeTargetTriple(*this,
- CfgTriple.getTriple(), *CLOptions);
- if (CfgTriple.getArch() != EffectiveTriple.getArch()) {
- FixedConfigFile = EffectiveTriple.getArchName();
- FixedArchPrefixLen = FixedConfigFile.size();
- // Append the rest of original file name so that file name transforms
- // like: i386-clang.cfg -> x86_64-clang.cfg.
- if (ArchPrefixLen < CfgFileName.size())
- FixedConfigFile += CfgFileName.substr(ArchPrefixLen);
- }
+ std::string RealMode = getExecutableForDriverMode(Mode);
+ std::string Triple;
+
+ // If name prefix is present, no --target= override was passed via CLOptions
+ // and the name prefix is not a valid triple, force it for backwards
+ // compatibility.
+ if (!ClangNameParts.TargetPrefix.empty() &&
+ computeTargetTriple(*this, "/invalid/", *CLOptions).str() ==
+ "/invalid/") {
+ llvm::Triple PrefixTriple{ClangNameParts.TargetPrefix};
+ if (PrefixTriple.getArch() == llvm::Triple::UnknownArch ||
+ PrefixTriple.isOSUnknown())
+ Triple = PrefixTriple.str();
+ }
+
+ // Otherwise, use the real triple as used by the driver.
+ if (Triple.empty()) {
+ llvm::Triple RealTriple =
+ computeTargetTriple(*this, TargetTriple, *CLOptions);
+ Triple = RealTriple.str();
+ assert(!Triple.empty());
+ }
+
+ // Search for config files in the following order:
+ // 1. <triple>-<mode>.cfg using real driver mode
+ // (e.g. i386-pc-linux-gnu-clang++.cfg).
+ // 2. <triple>-<mode>.cfg using executable suffix
+ // (e.g. i386-pc-linux-gnu-clang-g++.cfg for *clang-g++).
+ // 3. <triple>.cfg + <mode>.cfg using real driver mode
+ // (e.g. i386-pc-linux-gnu.cfg + clang++.cfg).
+ // 4. <triple>.cfg + <mode>.cfg using executable suffix
+ // (e.g. i386-pc-linux-gnu.cfg + clang-g++.cfg for *clang-g++).
+
+ // Try loading <triple>-<mode>.cfg, and return if we find a match.
+ SmallString<128> CfgFilePath;
+ std::string CfgFileName = Triple + '-' + RealMode + ".cfg";
+ if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath))
+ return readConfigFile(CfgFilePath, ExpCtx);
+
+ bool TryModeSuffix = !ClangNameParts.ModeSuffix.empty() &&
+ ClangNameParts.ModeSuffix != RealMode;
+ if (TryModeSuffix) {
+ CfgFileName = Triple + '-' + ClangNameParts.ModeSuffix + ".cfg";
+ if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath))
+ return readConfigFile(CfgFilePath, ExpCtx);
+ }
+
+ // Try loading <mode>.cfg, and return if loading failed. If a matching file
+ // was not found, still proceed on to try <triple>.cfg.
+ CfgFileName = RealMode + ".cfg";
+ if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) {
+ if (readConfigFile(CfgFilePath, ExpCtx))
+ return true;
+ } else if (TryModeSuffix) {
+ CfgFileName = ClangNameParts.ModeSuffix + ".cfg";
+ if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath) &&
+ readConfigFile(CfgFilePath, ExpCtx))
+ return true;
}
- // Prepare list of directories where config file is searched for.
- StringRef CfgFileSearchDirs[] = {UserConfigDir, SystemConfigDir, Dir};
-
- // Try to find config file. First try file with corrected architecture.
- llvm::SmallString<128> CfgFilePath;
- if (!FixedConfigFile.empty()) {
- if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile))
- return readConfigFile(CfgFilePath);
- // If 'x86_64-clang.cfg' was not found, try 'x86_64.cfg'.
- FixedConfigFile.resize(FixedArchPrefixLen);
- FixedConfigFile.append(".cfg");
- if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile))
- return readConfigFile(CfgFilePath);
- }
-
- // Then try original file name.
- if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName))
- return readConfigFile(CfgFilePath);
-
- // Finally try removing driver mode part: 'x86_64-clang.cfg' -> 'x86_64.cfg'.
- if (!ClangNameParts.ModeSuffix.empty() &&
- !ClangNameParts.TargetPrefix.empty()) {
- CfgFileName.assign(ClangNameParts.TargetPrefix);
- CfgFileName.append(".cfg");
- if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName))
- return readConfigFile(CfgFilePath);
- }
-
- // Report error but only if config file was specified explicitly, by option
- // --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 StringRef &SearchDir : CfgFileSearchDirs)
- if (!SearchDir.empty())
- Diag(diag::note_drv_config_file_searched_in) << SearchDir;
- return true;
- }
+ // Try loading <triple>.cfg and return if we find a match.
+ CfgFileName = Triple + ".cfg";
+ if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath))
+ return readConfigFile(CfgFilePath, ExpCtx);
+ // If we were unable to find a config file deduced from executable name,
+ // that is not an error.
return false;
}
@@ -1132,28 +1205,13 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// Try parsing configuration file.
if (!ContainsError)
- ContainsError = loadConfigFile();
+ ContainsError = loadConfigFiles();
bool HasConfigFile = !ContainsError && (CfgOptions.get() != nullptr);
// All arguments, from both config file and command line.
InputArgList Args = std::move(HasConfigFile ? std::move(*CfgOptions)
: std::move(*CLOptions));
- // The args for config files or /clang: flags belong to different InputArgList
- // 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(), 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)
for (auto *Opt : *CLOptions) {
if (Opt->getOption().matches(options::OPT_config))
@@ -1161,7 +1219,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
const Arg *BaseArg = &Opt->getBaseArg();
if (BaseArg == Opt)
BaseArg = nullptr;
- appendOneArg(Opt, BaseArg);
+ appendOneArg(Args, Opt, BaseArg);
}
// In CL mode, look for any pass-through arguments
@@ -1180,7 +1238,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
if (!ContainsError)
for (auto *Opt : *CLModePassThroughOptions) {
- appendOneArg(Opt, nullptr);
+ appendOneArg(Args, Opt, nullptr);
}
}
}
@@ -1193,9 +1251,6 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// FIXME: This stuff needs to go into the Compilation, not the driver.
bool CCCPrintPhases;
- // Silence driver warnings if requested
- Diags.setIgnoreAllWarnings(Args.hasArg(options::OPT_w));
-
// -canonical-prefixes, -no-canonical-prefixes are used very early in main.
Args.ClaimAllArgs(options::OPT_canonical_prefixes);
Args.ClaimAllArgs(options::OPT_no_canonical_prefixes);
@@ -1235,6 +1290,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
T.setVendor(llvm::Triple::PC);
T.setEnvironment(llvm::Triple::MSVC);
T.setObjectFormat(llvm::Triple::COFF);
+ if (Args.hasArg(options::OPT__SLASH_arm64EC))
+ T.setArch(llvm::Triple::aarch64, llvm::Triple::AArch64SubArch_arm64ec);
TargetTriple = T.str();
} else if (IsDXCMode()) {
// Build TargetTriple from target_profile option for clang-dxc.
@@ -1260,7 +1317,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
A->claim();
PrefixDirs.push_back(A->getValue(0));
}
- if (Optional<std::string> CompilerPathValue =
+ if (std::optional<std::string> CompilerPathValue =
llvm::sys::Process::GetEnv("COMPILER_PATH")) {
StringRef CompilerPath = *CompilerPathValue;
while (!CompilerPath.empty()) {
@@ -1359,6 +1416,14 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
const ToolChain &TC = getToolChain(
*UArgs, computeTargetTriple(*this, TargetTriple, *UArgs));
+ // Report warning when arm64EC option is overridden by specified target
+ if ((TC.getTriple().getArch() != llvm::Triple::aarch64 ||
+ TC.getTriple().getSubArch() != llvm::Triple::AArch64SubArch_arm64ec) &&
+ UArgs->hasArg(options::OPT__SLASH_arm64EC)) {
+ getDiags().Report(clang::diag::warn_target_override_arm64ec)
+ << TC.getTriple().str();
+ }
+
// The compilation takes ownership of Args.
Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs,
ContainsError);
@@ -1498,6 +1563,11 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename,
return false;
}
+static const char BugReporMsg[] =
+ "\n********************\n\n"
+ "PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:\n"
+ "Preprocessed source(s) and associated run script(s) are located at:";
+
// When clang crashes, produce diagnostic information including the fully
// preprocessed source file(s). Request that the developer attach the
// diagnostic information to a bug report.
@@ -1507,11 +1577,36 @@ void Driver::generateCompilationDiagnostics(
if (C.getArgs().hasArg(options::OPT_fno_crash_diagnostics))
return;
- // Don't try to generate diagnostics for link or dsymutil jobs.
- if (FailingCommand.getCreator().isLinkJob() ||
- FailingCommand.getCreator().isDsymutilJob())
+ unsigned Level = 1;
+ if (Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_EQ)) {
+ Level = llvm::StringSwitch<unsigned>(A->getValue())
+ .Case("off", 0)
+ .Case("compiler", 1)
+ .Case("all", 2)
+ .Default(1);
+ }
+ if (!Level)
+ return;
+
+ // Don't try to generate diagnostics for dsymutil jobs.
+ if (FailingCommand.getCreator().isDsymutilJob())
return;
+ bool IsLLD = false;
+ ArgStringList SavedTemps;
+ if (FailingCommand.getCreator().isLinkJob()) {
+ C.getDefaultToolChain().GetLinkerPath(&IsLLD);
+ if (!IsLLD || Level < 2)
+ return;
+
+ // If lld crashed, we will re-run the same command with the input it used
+ // to have. In that case we should not remove temp files in
+ // initCompilationForDiagnostics yet. They will be added back and removed
+ // later.
+ SavedTemps = std::move(C.getTempFiles());
+ assert(!C.getTempFiles().size());
+ }
+
// Print the version of the compiler.
PrintVersion(C, llvm::errs());
@@ -1528,6 +1623,29 @@ void Driver::generateCompilationDiagnostics(
// Suppress tool output.
C.initCompilationForDiagnostics();
+ // If lld failed, rerun it again with --reproduce.
+ if (IsLLD) {
+ const char *TmpName = CreateTempFile(C, "linker-crash", "tar");
+ Command NewLLDInvocation = Cmd;
+ llvm::opt::ArgStringList ArgList = NewLLDInvocation.getArguments();
+ StringRef ReproduceOption =
+ C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment()
+ ? "/reproduce:"
+ : "--reproduce=";
+ ArgList.push_back(Saver.save(Twine(ReproduceOption) + TmpName).data());
+ NewLLDInvocation.replaceArguments(std::move(ArgList));
+
+ // Redirect stdout/stderr to /dev/null.
+ NewLLDInvocation.Execute({std::nullopt, {""}, {""}}, nullptr, nullptr);
+ Diag(clang::diag::note_drv_command_failed_diag_msg) << BugReporMsg;
+ Diag(clang::diag::note_drv_command_failed_diag_msg) << TmpName;
+ Diag(clang::diag::note_drv_command_failed_diag_msg)
+ << "\n\n********************";
+ if (Report)
+ Report->TemporaryFiles.push_back(TmpName);
+ return;
+ }
+
// Construct the list of inputs.
InputList Inputs;
BuildInputs(C.getDefaultToolChain(), C.getArgs(), Inputs);
@@ -1612,10 +1730,7 @@ void Driver::generateCompilationDiagnostics(
return;
}
- Diag(clang::diag::note_drv_command_failed_diag_msg)
- << "\n********************\n\n"
- "PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:\n"
- "Preprocessed source(s) and associated run script(s) are located at:";
+ Diag(clang::diag::note_drv_command_failed_diag_msg) << BugReporMsg;
SmallString<128> VFS;
SmallString<128> ReproCrashFilename;
@@ -1635,6 +1750,9 @@ void Driver::generateCompilationDiagnostics(
}
}
+ for (const char *TempFile : SavedTemps)
+ C.addTempFile(TempFile);
+
// Assume associated files are based off of the first temporary file.
CrashReportInfo CrashInfo(TempFiles[0], VFS);
@@ -1830,8 +1948,8 @@ void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const {
// Print out the install directory.
OS << "InstalledDir: " << InstalledDir << '\n';
- // If configuration file was used, print its path.
- if (!ConfigFile.empty())
+ // If configuration files were used, print their paths.
+ for (auto ConfigFile : ConfigFiles)
OS << "Configuration file: " << ConfigFile << '\n';
}
@@ -2114,12 +2232,6 @@ 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;
@@ -2371,7 +2483,7 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value,
// they can be influenced by linker flags the clang driver might not
// understand.
// Examples:
- // - `clang-cl main.cc ole32.lib` in a a non-MSVC shell will make the driver
+ // - `clang-cl main.cc ole32.lib` in a non-MSVC shell will make the driver
// module look for an MSVC installation in the registry. (We could ask
// the MSVCToolChain object if it can find `ole32.lib`, but the logic to
// look in the registry might move into lld-link in the future so that
@@ -2694,7 +2806,7 @@ class OffloadingActionBuilder final {
/// Update the state to include the provided host action \a HostAction as a
/// dependency of the current device action. By default it is inactive.
- virtual ActionBuilderReturnCode addDeviceDepences(Action *HostAction) {
+ virtual ActionBuilderReturnCode addDeviceDependences(Action *HostAction) {
return ABRT_Inactive;
}
@@ -2782,7 +2894,7 @@ class OffloadingActionBuilder final {
Action::OffloadKind OFKind)
: DeviceActionBuilder(C, Args, Inputs, OFKind) {}
- ActionBuilderReturnCode addDeviceDepences(Action *HostAction) override {
+ ActionBuilderReturnCode addDeviceDependences(Action *HostAction) override {
// While generating code for CUDA, we only depend on the host input action
// to trigger the creation of all the CUDA device actions.
@@ -2856,12 +2968,16 @@ class OffloadingActionBuilder final {
std::string FileName = IA->getInputArg().getAsString(Args);
// Check if the type of the file is the same as the action. Do not
// unbundle it if it is not. Do not unbundle .so files, for example,
- // which are not object files.
+ // which are not object files. Files with extension ".lib" is classified
+ // as TY_Object but they are actually archives, therefore should not be
+ // unbundled here as objects. They will be handled at other places.
+ const StringRef LibFileExt = ".lib";
if (IA->getType() == types::TY_Object &&
(!llvm::sys::path::has_extension(FileName) ||
types::lookupTypeForExtension(
llvm::sys::path::extension(FileName).drop_front()) !=
- types::TY_Object))
+ types::TY_Object ||
+ llvm::sys::path::extension(FileName) == LibFileExt))
return ABRT_Inactive;
for (auto Arch : GpuArchList) {
@@ -2912,7 +3028,7 @@ class OffloadingActionBuilder final {
/// option is invalid.
virtual StringRef getCanonicalOffloadArch(StringRef Arch) = 0;
- virtual llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
+ virtual std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
getConflictOffloadArchCombination(const std::set<StringRef> &GpuArchs) = 0;
bool initialize() override {
@@ -2990,6 +3106,19 @@ class OffloadingActionBuilder final {
if (A->getOption().matches(options::OPT_no_offload_arch_EQ) &&
ArchStr == "all") {
GpuArchs.clear();
+ } else if (ArchStr == "native") {
+ const ToolChain &TC = *ToolChains.front();
+ auto GPUsOrErr = ToolChains.front()->getSystemGPUArchs(Args);
+ if (!GPUsOrErr) {
+ TC.getDriver().Diag(diag::err_drv_undetermined_gpu_arch)
+ << llvm::Triple::getArchTypeName(TC.getArch())
+ << llvm::toString(GPUsOrErr.takeError()) << "--offload-arch";
+ continue;
+ }
+
+ for (auto GPU : *GPUsOrErr) {
+ GpuArchs.insert(Args.MakeArgString(GPU));
+ }
} else {
ArchStr = getCanonicalOffloadArch(ArchStr);
if (ArchStr.empty()) {
@@ -3049,10 +3178,10 @@ class OffloadingActionBuilder final {
return CudaArchToString(Arch);
}
- llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
+ std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
getConflictOffloadArchCombination(
const std::set<StringRef> &GpuArchs) override {
- return llvm::None;
+ return std::nullopt;
}
ActionBuilderReturnCode
@@ -3168,13 +3297,13 @@ class OffloadingActionBuilder final {
// 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;
+ std::optional<bool> BundleOutput;
public:
HIPActionBuilder(Compilation &C, DerivedArgList &Args,
const Driver::InputList &Inputs)
: CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) {
- DefaultCudaArch = CudaArch::GFX803;
+ DefaultCudaArch = CudaArch::GFX906;
if (Args.hasArg(options::OPT_gpu_bundle_output,
options::OPT_no_gpu_bundle_output))
BundleOutput = Args.hasFlag(options::OPT_gpu_bundle_output,
@@ -3199,7 +3328,7 @@ class OffloadingActionBuilder final {
return Args.MakeArgStringRef(CanId);
};
- llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
+ std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
getConflictOffloadArchCombination(
const std::set<StringRef> &GpuArchs) override {
return getConflictTargetIDCombination(GpuArchs);
@@ -3326,7 +3455,7 @@ class OffloadingActionBuilder final {
AssociatedOffloadKind);
if (CompileDeviceOnly && CurPhase == FinalPhase && BundleOutput &&
- BundleOutput.value()) {
+ *BundleOutput) {
for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) {
OffloadAction::DeviceDependences DDep;
DDep.add(*CudaDeviceActions[I], *ToolChains.front(), GpuArchList[I],
@@ -3401,178 +3530,6 @@ class OffloadingActionBuilder final {
void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {}
};
- /// OpenMP action builder. The host bitcode is passed to the device frontend
- /// and all the device linked images are passed to the host link phase.
- class OpenMPActionBuilder final : public DeviceActionBuilder {
- /// The OpenMP actions for the current input.
- ActionList OpenMPDeviceActions;
-
- /// The linker inputs obtained for each toolchain.
- SmallVector<ActionList, 8> DeviceLinkerInputs;
-
- public:
- OpenMPActionBuilder(Compilation &C, DerivedArgList &Args,
- const Driver::InputList &Inputs)
- : DeviceActionBuilder(C, Args, Inputs, Action::OFK_OpenMP) {}
-
- ActionBuilderReturnCode
- getDeviceDependences(OffloadAction::DeviceDependences &DA,
- phases::ID CurPhase, phases::ID FinalPhase,
- PhasesTy &Phases) override {
- if (OpenMPDeviceActions.empty())
- return ABRT_Inactive;
-
- // We should always have an action for each input.
- assert(OpenMPDeviceActions.size() == ToolChains.size() &&
- "Number of OpenMP actions and toolchains do not match.");
-
- // The host only depends on device action in the linking phase, when all
- // the device images have to be embedded in the host image.
- if (CurPhase == phases::Link) {
- assert(ToolChains.size() == DeviceLinkerInputs.size() &&
- "Toolchains and linker inputs sizes do not match.");
- auto LI = DeviceLinkerInputs.begin();
- for (auto *A : OpenMPDeviceActions) {
- LI->push_back(A);
- ++LI;
- }
-
- // We passed the device action as a host dependence, so we don't need to
- // do anything else with them.
- OpenMPDeviceActions.clear();
- return ABRT_Success;
- }
-
- // By default, we produce an action for each device arch.
- for (Action *&A : OpenMPDeviceActions)
- A = C.getDriver().ConstructPhaseAction(C, Args, CurPhase, A);
-
- return ABRT_Success;
- }
-
- ActionBuilderReturnCode addDeviceDepences(Action *HostAction) override {
-
- // If this is an input action replicate it for each OpenMP toolchain.
- if (auto *IA = dyn_cast<InputAction>(HostAction)) {
- OpenMPDeviceActions.clear();
- for (unsigned I = 0; I < ToolChains.size(); ++I)
- OpenMPDeviceActions.push_back(
- C.MakeAction<InputAction>(IA->getInputArg(), IA->getType()));
- return ABRT_Success;
- }
-
- // If this is an unbundling action use it as is for each OpenMP toolchain.
- if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(HostAction)) {
- OpenMPDeviceActions.clear();
- auto *IA = cast<InputAction>(UA->getInputs().back());
- std::string FileName = IA->getInputArg().getAsString(Args);
- // Check if the type of the file is the same as the action. Do not
- // unbundle it if it is not. Do not unbundle .so files, for example,
- // which are not object files.
- if (IA->getType() == types::TY_Object &&
- (!llvm::sys::path::has_extension(FileName) ||
- types::lookupTypeForExtension(
- llvm::sys::path::extension(FileName).drop_front()) !=
- types::TY_Object))
- return ABRT_Inactive;
- for (unsigned I = 0; I < ToolChains.size(); ++I) {
- OpenMPDeviceActions.push_back(UA);
- UA->registerDependentActionInfo(
- ToolChains[I], /*BoundArch=*/StringRef(), Action::OFK_OpenMP);
- }
- return ABRT_Success;
- }
-
- // When generating code for OpenMP we use the host compile phase result as
- // a dependence to the device compile phase so that it can learn what
- // declarations should be emitted. However, this is not the only use for
- // the host action, so we prevent it from being collapsed.
- if (isa<CompileJobAction>(HostAction)) {
- HostAction->setCannotBeCollapsedWithNextDependentAction();
- assert(ToolChains.size() == OpenMPDeviceActions.size() &&
- "Toolchains and device action sizes do not match.");
- OffloadAction::HostDependence HDep(
- *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
- /*BoundArch=*/nullptr, Action::OFK_OpenMP);
- auto TC = ToolChains.begin();
- for (Action *&A : OpenMPDeviceActions) {
- assert(isa<CompileJobAction>(A));
- OffloadAction::DeviceDependences DDep;
- DDep.add(*A, **TC, /*BoundArch=*/nullptr, Action::OFK_OpenMP);
- A = C.MakeAction<OffloadAction>(HDep, DDep);
- ++TC;
- }
- }
- return ABRT_Success;
- }
-
- void appendTopLevelActions(ActionList &AL) override {
- if (OpenMPDeviceActions.empty())
- return;
-
- // We should always have an action for each input.
- assert(OpenMPDeviceActions.size() == ToolChains.size() &&
- "Number of OpenMP actions and toolchains do not match.");
-
- // Append all device actions followed by the proper offload action.
- auto TI = ToolChains.begin();
- for (auto *A : OpenMPDeviceActions) {
- OffloadAction::DeviceDependences Dep;
- Dep.add(*A, **TI, /*BoundArch=*/nullptr, Action::OFK_OpenMP);
- AL.push_back(C.MakeAction<OffloadAction>(Dep, A->getType()));
- ++TI;
- }
- // We no longer need the action stored in this builder.
- OpenMPDeviceActions.clear();
- }
-
- void appendLinkDeviceActions(ActionList &AL) override {
- assert(ToolChains.size() == DeviceLinkerInputs.size() &&
- "Toolchains and linker inputs sizes do not match.");
-
- // Append a new link action for each device.
- auto TC = ToolChains.begin();
- for (auto &LI : DeviceLinkerInputs) {
- auto *DeviceLinkAction =
- C.MakeAction<LinkJobAction>(LI, types::TY_Image);
- OffloadAction::DeviceDependences DeviceLinkDeps;
- DeviceLinkDeps.add(*DeviceLinkAction, **TC, /*BoundArch=*/nullptr,
- Action::OFK_OpenMP);
- AL.push_back(C.MakeAction<OffloadAction>(DeviceLinkDeps,
- DeviceLinkAction->getType()));
- ++TC;
- }
- 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 {
- // Get the OpenMP toolchains. If we don't get any, the action builder will
- // know there is nothing to do related to OpenMP offloading.
- auto OpenMPTCRange = C.getOffloadToolChains<Action::OFK_OpenMP>();
- for (auto TI = OpenMPTCRange.first, TE = OpenMPTCRange.second; TI != TE;
- ++TI)
- ToolChains.push_back(TI->second);
-
- DeviceLinkerInputs.resize(ToolChains.size());
- return false;
- }
-
- bool canUseBundlerUnbundler() const override {
- // OpenMP should use bundled files whenever possible.
- return true;
- }
- };
-
///
/// TODO: Add the implementation for other specialized builders here.
///
@@ -3597,9 +3554,6 @@ public:
// Create a specialized builder for HIP.
SpecializedBuilders.push_back(new HIPActionBuilder(C, Args, Inputs));
- // Create a specialized builder for OpenMP.
- SpecializedBuilders.push_back(new OpenMPActionBuilder(C, Args, Inputs));
-
//
// TODO: Build other specialized builders here.
//
@@ -3736,7 +3690,7 @@ public:
if (!SB->isValid())
continue;
- auto RetCode = SB->addDeviceDepences(HostAction);
+ auto RetCode = SB->addDeviceDependences(HostAction);
// Host dependences for device actions are not compatible with that same
// action being ignored.
@@ -3858,7 +3812,7 @@ public:
/*BoundArch=*/nullptr);
// Propagate active offloading kinds for each input to the link action.
// Each input may have different active offloading kind.
- for (auto A : HostAction->inputs()) {
+ for (auto *A : HostAction->inputs()) {
auto ArgLoc = HostActionToInputArgMap.find(A);
if (ArgLoc == HostActionToInputArgMap.end())
continue;
@@ -4006,11 +3960,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
return;
}
- // Reject -Z* at the top level, these options should never have been exposed
- // by gcc.
- if (Arg *A = Args.getLastArg(options::OPT_Z_Joined))
- Diag(clang::diag::err_drv_use_of_Z_option) << A->getAsString(Args);
-
// Diagnose misuse of /Fo.
if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fo)) {
StringRef V = A->getValue();
@@ -4046,18 +3995,18 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
handleArguments(C, Args, Inputs, Actions);
- // Builder to be used to build offloading actions.
- OffloadingActionBuilder OffloadBuilder(C, Args, Inputs);
-
bool UseNewOffloadingDriver =
- (C.isOffloadingHostKind(Action::OFK_OpenMP) &&
- Args.hasFlag(options::OPT_fopenmp_new_driver,
- options::OPT_no_offload_new_driver, true)) ||
+ C.isOffloadingHostKind(Action::OFK_OpenMP) ||
Args.hasFlag(options::OPT_offload_new_driver,
options::OPT_no_offload_new_driver, false);
+ // Builder to be used to build offloading actions.
+ std::unique_ptr<OffloadingActionBuilder> OffloadBuilder =
+ !UseNewOffloadingDriver
+ ? std::make_unique<OffloadingActionBuilder>(C, Args, Inputs)
+ : nullptr;
+
// Construct the actions to perform.
- HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr;
ExtractAPIJobAction *ExtractAPIAction = nullptr;
ActionList LinkerInputs;
ActionList MergerInputs;
@@ -4078,14 +4027,14 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
// Use the current host action in any of the offloading actions, if
// required.
if (!UseNewOffloadingDriver)
- if (OffloadBuilder.addHostDependenceToDeviceActions(Current, InputArg))
+ if (OffloadBuilder->addHostDependenceToDeviceActions(Current, InputArg))
break;
for (phases::ID Phase : PL) {
// Add any offload action the host action depends on.
if (!UseNewOffloadingDriver)
- Current = OffloadBuilder.addDeviceDependencesToHostAction(
+ Current = OffloadBuilder->addDeviceDependencesToHostAction(
Current, InputArg, Phase, PL.back(), FullPL);
if (!Current)
break;
@@ -4112,16 +4061,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
break;
}
- // Each precompiled header file after a module file action is a module
- // header of that same module file, rather than being compiled to a
- // separate PCH.
- if (Phase == phases::Precompile && HeaderModuleAction &&
- getPrecompiledType(InputType) == types::TY_PCH) {
- HeaderModuleAction->addModuleHeaderInput(Current);
- Current = nullptr;
- break;
- }
-
if (Phase == phases::Precompile && ExtractAPIAction) {
ExtractAPIAction->addHeaderInput(Current);
Current = nullptr;
@@ -4138,9 +4077,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
if (NewCurrent == Current)
continue;
- if (auto *HMA = dyn_cast<HeaderModulePrecompileJobAction>(NewCurrent))
- HeaderModuleAction = HMA;
- else if (auto *EAA = dyn_cast<ExtractAPIJobAction>(NewCurrent))
+ if (auto *EAA = dyn_cast<ExtractAPIJobAction>(NewCurrent))
ExtractAPIAction = EAA;
Current = NewCurrent;
@@ -4148,7 +4085,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
// Use the current host action in any of the offloading actions, if
// required.
if (!UseNewOffloadingDriver)
- if (OffloadBuilder.addHostDependenceToDeviceActions(Current, InputArg))
+ if (OffloadBuilder->addHostDependenceToDeviceActions(Current, InputArg))
break;
// Try to build the offloading actions and add the result as a dependency
@@ -4166,7 +4103,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
// Add any top level actions generated for offloading.
if (!UseNewOffloadingDriver)
- OffloadBuilder.appendTopLevelActions(Actions, Current, InputArg);
+ OffloadBuilder->appendTopLevelActions(Actions, Current, InputArg);
else if (Current)
Current->propagateHostOffloadInfo(C.getActiveOffloadKinds(),
/*BoundArch=*/nullptr);
@@ -4178,12 +4115,12 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
Arg *FinalPhaseArg;
if (getFinalPhase(Args, &FinalPhaseArg) == phases::Link)
if (!UseNewOffloadingDriver)
- OffloadBuilder.appendDeviceLinkActions(Actions);
+ OffloadBuilder->appendDeviceLinkActions(Actions);
}
if (!LinkerInputs.empty()) {
if (!UseNewOffloadingDriver)
- if (Action *Wrapper = OffloadBuilder.makeHostLinkAction())
+ if (Action *Wrapper = OffloadBuilder->makeHostLinkAction())
LinkerInputs.push_back(Wrapper);
Action *LA;
// Check if this Linker Job should emit a static library.
@@ -4198,7 +4135,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
LA = C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image);
}
if (!UseNewOffloadingDriver)
- LA = OffloadBuilder.processHostLinkAction(LA);
+ LA = OffloadBuilder->processHostLinkAction(LA);
Actions.push_back(LA);
}
@@ -4284,16 +4221,17 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
static StringRef getCanonicalArchString(Compilation &C,
const llvm::opt::DerivedArgList &Args,
StringRef ArchStr,
- const llvm::Triple &Triple) {
+ const llvm::Triple &Triple,
+ bool SuppressError = false) {
// Lookup the CUDA / HIP architecture string. Only report an error if we were
// expecting the triple to be only NVPTX / AMDGPU.
CudaArch Arch = StringToCudaArch(getProcessorFromTargetID(Triple, ArchStr));
- if (Triple.isNVPTX() &&
+ if (!SuppressError && Triple.isNVPTX() &&
(Arch == CudaArch::UNKNOWN || !IsNVIDIAGpuArch(Arch))) {
C.getDriver().Diag(clang::diag::err_drv_offload_bad_gpu_arch)
<< "CUDA" << ArchStr;
return StringRef();
- } else if (Triple.isAMDGPU() &&
+ } else if (!SuppressError && Triple.isAMDGPU() &&
(Arch == CudaArch::UNKNOWN || !IsAMDGpuArch(Arch))) {
C.getDriver().Diag(clang::diag::err_drv_offload_bad_gpu_arch)
<< "HIP" << ArchStr;
@@ -4323,11 +4261,11 @@ static StringRef getCanonicalArchString(Compilation &C,
/// Checks if the set offloading architectures does not conflict. Returns the
/// incompatible pair if a conflict occurs.
-static llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
+static std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
getConflictOffloadArchCombination(const llvm::DenseSet<StringRef> &Archs,
Action::OffloadKind Kind) {
if (Kind != Action::OFK_HIP)
- return None;
+ return std::nullopt;
std::set<StringRef> ArchSet;
llvm::copy(Archs, std::inserter(ArchSet, ArchSet.begin()));
@@ -4336,7 +4274,8 @@ getConflictOffloadArchCombination(const llvm::DenseSet<StringRef> &Archs,
llvm::DenseSet<StringRef>
Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
- Action::OffloadKind Kind, const ToolChain *TC) const {
+ Action::OffloadKind Kind, const ToolChain *TC,
+ bool SuppressError) const {
if (!TC)
TC = &C.getDefaultToolChain();
@@ -4366,15 +4305,46 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
Arg = ExtractedArg.get();
}
+ // Add or remove the seen architectures in order of appearance. If an
+ // invalid architecture is given we simply exit.
if (Arg->getOption().matches(options::OPT_offload_arch_EQ)) {
- for (StringRef Arch : llvm::split(Arg->getValue(), ","))
- Archs.insert(getCanonicalArchString(C, Args, Arch, TC->getTriple()));
+ for (StringRef Arch : llvm::split(Arg->getValue(), ",")) {
+ if (Arch == "native" || Arch.empty()) {
+ auto GPUsOrErr = TC->getSystemGPUArchs(Args);
+ if (!GPUsOrErr) {
+ if (SuppressError)
+ llvm::consumeError(GPUsOrErr.takeError());
+ else
+ TC->getDriver().Diag(diag::err_drv_undetermined_gpu_arch)
+ << llvm::Triple::getArchTypeName(TC->getArch())
+ << llvm::toString(GPUsOrErr.takeError()) << "--offload-arch";
+ continue;
+ }
+
+ for (auto ArchStr : *GPUsOrErr) {
+ Archs.insert(
+ getCanonicalArchString(C, Args, Args.MakeArgString(ArchStr),
+ TC->getTriple(), SuppressError));
+ }
+ } else {
+ StringRef ArchStr = getCanonicalArchString(
+ C, Args, Arch, TC->getTriple(), SuppressError);
+ if (ArchStr.empty())
+ return Archs;
+ Archs.insert(ArchStr);
+ }
+ }
} else if (Arg->getOption().matches(options::OPT_no_offload_arch_EQ)) {
for (StringRef Arch : llvm::split(Arg->getValue(), ",")) {
- if (Arch == StringRef("all"))
+ if (Arch == "all") {
Archs.clear();
- else
- Archs.erase(getCanonicalArchString(C, Args, Arch, TC->getTriple()));
+ } else {
+ StringRef ArchStr = getCanonicalArchString(
+ C, Args, Arch, TC->getTriple(), SuppressError);
+ if (ArchStr.empty())
+ return Archs;
+ Archs.erase(ArchStr);
+ }
}
}
}
@@ -4385,6 +4355,10 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
C.setContainsError();
}
+ // Skip filling defaults if we're just querying what is availible.
+ if (SuppressError)
+ return Archs;
+
if (Archs.empty()) {
if (Kind == Action::OFK_Cuda)
Archs.insert(CudaArchToString(CudaArch::CudaDefault));
@@ -4459,10 +4433,17 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
auto TCAndArch = TCAndArchs.begin();
for (Action *&A : DeviceActions) {
+ if (A->getType() == types::TY_Nothing)
+ continue;
+
+ // Propagate the ToolChain so we can use it in ConstructPhaseAction.
+ A->propagateDeviceOffloadInfo(Kind, TCAndArch->second.data(),
+ TCAndArch->first);
A = ConstructPhaseAction(C, Args, Phase, A, Kind);
if (isa<CompileJobAction>(A) && isa<CompileJobAction>(HostAction) &&
- Kind == Action::OFK_OpenMP) {
+ Kind == Action::OFK_OpenMP &&
+ HostAction->getType() != types::TY_Nothing) {
// OpenMP offloading has a dependency on the host compile action to
// identify which declarations need to be emitted. This shouldn't be
// collapsed with any other actions so we can use it in the device.
@@ -4474,13 +4455,16 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
DDep.add(*A, *TCAndArch->first, TCAndArch->second.data(), Kind);
A = C.MakeAction<OffloadAction>(HDep, DDep);
}
+
++TCAndArch;
}
}
// Compiling HIP in non-RDC mode requires linking each action individually.
for (Action *&A : DeviceActions) {
- if (A->getType() != types::TY_Object || Kind != Action::OFK_HIP ||
+ if ((A->getType() != types::TY_Object &&
+ A->getType() != types::TY_LTO_BC) ||
+ Kind != Action::OFK_HIP ||
Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false))
continue;
ActionList LinkerInput = {A};
@@ -4527,14 +4511,18 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
Action *PackagerAction =
C.MakeAction<OffloadPackagerJobAction>(OffloadActions, types::TY_Image);
DDep.add(*PackagerAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
- nullptr, Action::OFK_None);
+ nullptr, C.getActiveOffloadKinds());
}
+ // If we are unable to embed a single device output into the host, we need to
+ // add each device output as a host dependency to ensure they are still built.
+ bool SingleDeviceOutput = !llvm::any_of(OffloadActions, [](Action *A) {
+ return A->getType() == types::TY_Nothing;
+ }) && isa<CompileJobAction>(HostAction);
OffloadAction::HostDependence HDep(
*HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
- /*BoundArch=*/nullptr, isa<CompileJobAction>(HostAction) ? DDep : DDeps);
- return C.MakeAction<OffloadAction>(
- HDep, isa<CompileJobAction>(HostAction) ? DDep : DDeps);
+ /*BoundArch=*/nullptr, SingleDeviceOutput ? DDep : DDeps);
+ return C.MakeAction<OffloadAction>(HDep, SingleDeviceOutput ? DDep : DDeps);
}
Action *Driver::ConstructPhaseAction(
@@ -4602,9 +4590,6 @@ Action *Driver::ConstructPhaseAction(
OutputTy = types::TY_Nothing;
}
- if (ModName)
- return C.MakeAction<HeaderModulePrecompileJobAction>(Input, OutputTy,
- ModName);
return C.MakeAction<PrecompileJobAction>(Input, OutputTy);
}
case phases::Compile: {
@@ -4642,11 +4627,21 @@ Action *Driver::ConstructPhaseAction(
return C.MakeAction<BackendJobAction>(Input, Output);
}
if (Args.hasArg(options::OPT_emit_llvm) ||
- (TargetDeviceOffloadKind == Action::OFK_HIP &&
- Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
- false))) {
+ (((Input->getOffloadingToolChain() &&
+ Input->getOffloadingToolChain()->getTriple().isAMDGPU()) ||
+ TargetDeviceOffloadKind == Action::OFK_HIP) &&
+ (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
+ false) ||
+ TargetDeviceOffloadKind == Action::OFK_OpenMP))) {
types::ID Output =
- Args.hasArg(options::OPT_S) ? types::TY_LLVM_IR : types::TY_LLVM_BC;
+ Args.hasArg(options::OPT_S) &&
+ (TargetDeviceOffloadKind == Action::OFK_None ||
+ offloadDeviceOnly() ||
+ (TargetDeviceOffloadKind == Action::OFK_HIP &&
+ !Args.hasFlag(options::OPT_offload_new_driver,
+ options::OPT_no_offload_new_driver, false)))
+ ? types::TY_LLVM_IR
+ : types::TY_LLVM_BC;
return C.MakeAction<BackendJobAction>(Input, Output);
}
return C.MakeAction<BackendJobAction>(Input, types::TY_PP_Asm);
@@ -4676,10 +4671,14 @@ void Driver::BuildJobs(Compilation &C) const {
// we are also generating .o files. So we allow more than one output file in
// this case as well.
//
+ // OffloadClass of type TY_Nothing: device-only output will place many outputs
+ // into a single offloading action. We should count all inputs to the action
+ // as outputs. Also ignore device-only outputs if we're compiling with
+ // -fsyntax-only.
if (FinalOutput) {
unsigned NumOutputs = 0;
unsigned NumIfsOutputs = 0;
- for (const Action *A : C.getActions())
+ for (const Action *A : C.getActions()) {
if (A->getType() != types::TY_Nothing &&
!(A->getKind() == Action::IfsMergeJobClass ||
(A->getType() == clang::driver::types::TY_IFS_CPP &&
@@ -4688,6 +4687,11 @@ void Driver::BuildJobs(Compilation &C) const {
(A->getKind() == Action::BindArchClass && A->getInputs().size() &&
A->getInputs().front()->getKind() == Action::IfsMergeJobClass)))
++NumOutputs;
+ else if (A->getKind() == Action::OffloadClass &&
+ A->getType() == types::TY_Nothing &&
+ !C.getArgs().hasArg(options::OPT_fsyntax_only))
+ NumOutputs += A->size();
+ }
if (NumOutputs > 1) {
Diag(clang::diag::err_drv_output_argument_with_multiple_files);
@@ -4744,7 +4748,7 @@ void Driver::BuildJobs(Compilation &C) const {
if (CCPrintProcessStats) {
C.setPostCallback([=](const Command &Cmd, int Res) {
- Optional<llvm::sys::ProcessStatistics> ProcStat =
+ std::optional<llvm::sys::ProcessStatistics> ProcStat =
Cmd.getProcessStatistics();
if (!ProcStat)
return;
@@ -5225,20 +5229,21 @@ InputInfoList Driver::BuildJobsForActionNoCache(
// \
// Device Action 1 ---> OffloadAction -> Device Action 2
//
- // For a) and b), we just return the job generated for the dependence. For
+ // For a) and b), we just return the job generated for the dependences. For
// c) and d) we override the current action with the host/device dependence
// if the current toolchain is host/device and set the offload dependences
// info with the jobs obtained from the device/host dependence(s).
- // If there is a single device option, just generate the job for it.
- if (OA->hasSingleDeviceDependence()) {
+ // If there is a single device option or has no host action, just generate
+ // the job for it.
+ if (OA->hasSingleDeviceDependence() || !OA->hasHostDependence()) {
InputInfoList DevA;
OA->doOnEachDeviceDependence([&](Action *DepA, const ToolChain *DepTC,
const char *DepBoundArch) {
- DevA =
- BuildJobsForAction(C, DepA, DepTC, DepBoundArch, AtTopLevel,
- /*MultipleArchs*/ !!DepBoundArch, LinkingOutput,
- CachedResults, DepA->getOffloadingDeviceKind());
+ DevA.append(BuildJobsForAction(C, DepA, DepTC, DepBoundArch, AtTopLevel,
+ /*MultipleArchs*/ !!DepBoundArch,
+ LinkingOutput, CachedResults,
+ DepA->getOffloadingDeviceKind()));
});
return DevA;
}
@@ -5313,25 +5318,6 @@ InputInfoList 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)
@@ -5371,10 +5357,6 @@ InputInfoList Driver::BuildJobsForActionNoCache(
if (JA->getType() == types::TY_dSYM)
BaseInput = InputInfos[0].getFilename();
- // ... and in header module compilations, which use the module name.
- if (auto *ModuleJA = dyn_cast<HeaderModulePrecompileJobAction>(JA))
- BaseInput = ModuleJA->getModuleName();
-
// Append outputs of offload device jobs to the input list
if (!OffloadDependencesInputInfo.empty())
InputInfos.append(OffloadDependencesInputInfo.begin(),
@@ -5457,14 +5439,6 @@ InputInfoList Driver::BuildJobsForActionNoCache(
/*CreatePrefixForHost=*/isa<OffloadPackagerJobAction>(A) ||
!(A->getOffloadingHostActiveKinds() == Action::OFK_None ||
AtTopLevel));
- if (isa<OffloadWrapperJobAction>(JA)) {
- 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,
OffloadingPrefix),
@@ -5554,6 +5528,71 @@ static bool HasPreprocessOutput(const Action &JA) {
return false;
}
+const char *Driver::CreateTempFile(Compilation &C, StringRef Prefix,
+ StringRef Suffix, bool MultipleArchs,
+ StringRef BoundArch) const {
+ SmallString<128> TmpName;
+ Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_dir);
+ std::optional<std::string> CrashDirectory =
+ CCGenDiagnostics && A
+ ? std::string(A->getValue())
+ : llvm::sys::Process::GetEnv("CLANG_CRASH_DIAGNOSTICS_DIR");
+ if (CrashDirectory) {
+ if (!getVFS().exists(*CrashDirectory))
+ llvm::sys::fs::create_directories(*CrashDirectory);
+ SmallString<128> Path(*CrashDirectory);
+ llvm::sys::path::append(Path, Prefix);
+ const char *Middle = !Suffix.empty() ? "-%%%%%%." : "-%%%%%%";
+ if (std::error_code EC =
+ llvm::sys::fs::createUniqueFile(Path + Middle + Suffix, TmpName)) {
+ Diag(clang::diag::err_unable_to_make_temp) << EC.message();
+ return "";
+ }
+ } else {
+ if (MultipleArchs && !BoundArch.empty()) {
+ TmpName = GetTemporaryDirectory(Prefix);
+ llvm::sys::path::append(TmpName,
+ Twine(Prefix) + "-" + BoundArch + "." + Suffix);
+ } else {
+ TmpName = GetTemporaryPath(Prefix, Suffix);
+ }
+ }
+ return C.addTempFile(C.getArgs().MakeArgString(TmpName));
+}
+
+// Calculate the output path of the module file when compiling a module unit
+// with the `-fmodule-output` option or `-fmodule-output=` option specified.
+// The behavior is:
+// - If `-fmodule-output=` is specfied, then the module file is
+// writing to the value.
+// - Otherwise if the output object file of the module unit is specified, the
+// output path
+// of the module file should be the same with the output object file except
+// the corresponding suffix. This requires both `-o` and `-c` are specified.
+// - Otherwise, the output path of the module file will be the same with the
+// input with the corresponding suffix.
+static const char *GetModuleOutputPath(Compilation &C, const JobAction &JA,
+ const char *BaseInput) {
+ assert(isa<PrecompileJobAction>(JA) && JA.getType() == types::TY_ModuleFile &&
+ (C.getArgs().hasArg(options::OPT_fmodule_output) ||
+ C.getArgs().hasArg(options::OPT_fmodule_output_EQ)));
+
+ if (Arg *ModuleOutputEQ =
+ C.getArgs().getLastArg(options::OPT_fmodule_output_EQ))
+ return C.addResultFile(ModuleOutputEQ->getValue(), &JA);
+
+ SmallString<64> OutputPath;
+ Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o);
+ if (FinalOutput && C.getArgs().hasArg(options::OPT_c))
+ OutputPath = FinalOutput->getValue();
+ else
+ OutputPath = BaseInput;
+
+ const char *Extension = types::getTypeTempSuffix(JA.getType());
+ llvm::sys::path::replace_extension(OutputPath, Extension);
+ return C.addResultFile(C.getArgs().MakeArgString(OutputPath.c_str()), &JA);
+}
+
const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
const char *BaseInput,
StringRef OrigBoundArch, bool AtTopLevel,
@@ -5595,6 +5634,9 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
return "-";
}
+ if (IsDXCMode() && !C.getArgs().hasArg(options::OPT_o))
+ return "-";
+
// Is this the assembly listing for /FA?
if (JA.getType() == types::TY_PP_Asm &&
(C.getArgs().hasArg(options::OPT__SLASH_FA) ||
@@ -5607,37 +5649,26 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
&JA);
}
+ bool SpecifiedModuleOutput =
+ C.getArgs().hasArg(options::OPT_fmodule_output) ||
+ C.getArgs().hasArg(options::OPT_fmodule_output_EQ);
+ if (MultipleArchs && SpecifiedModuleOutput)
+ Diag(clang::diag::err_drv_module_output_with_multiple_arch);
+
+ // If we're emitting a module output with the specified option
+ // `-fmodule-output`.
+ if (!AtTopLevel && isa<PrecompileJobAction>(JA) &&
+ JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput)
+ return GetModuleOutputPath(C, JA, BaseInput);
+
// Output to a temporary file?
if ((!AtTopLevel && !isSaveTempsEnabled() &&
!C.getArgs().hasArg(options::OPT__SLASH_Fo)) ||
CCGenDiagnostics) {
StringRef Name = llvm::sys::path::filename(BaseInput);
std::pair<StringRef, StringRef> Split = Name.split('.');
- SmallString<128> TmpName;
const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode());
- Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_dir);
- if (CCGenDiagnostics && A) {
- SmallString<128> CrashDirectory(A->getValue());
- if (!getVFS().exists(CrashDirectory))
- llvm::sys::fs::create_directories(CrashDirectory);
- llvm::sys::path::append(CrashDirectory, Split.first);
- const char *Middle = Suffix ? "-%%%%%%." : "-%%%%%%";
- std::error_code EC = llvm::sys::fs::createUniqueFile(
- CrashDirectory + Middle + Suffix, TmpName);
- if (EC) {
- Diag(clang::diag::err_unable_to_make_temp) << EC.message();
- return "";
- }
- } else {
- if (MultipleArchs && !BoundArch.empty()) {
- TmpName = GetTemporaryDirectory(Split.first);
- llvm::sys::path::append(TmpName,
- Split.first + "-" + BoundArch + "." + Suffix);
- } else {
- TmpName = GetTemporaryPath(Split.first, Suffix);
- }
- }
- return C.addTempFile(C.getArgs().MakeArgString(TmpName));
+ return CreateTempFile(C, Split.first, Suffix, MultipleArchs, BoundArch);
}
SmallString<128> BasePath(BaseInput);
@@ -5733,19 +5764,22 @@ 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.
- auto IsHIPRDCInCompilePhase = [](const JobAction &JA,
+ auto IsAMDRDCInCompilePhase = [](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.)
+ // The relocatable compilation in HIP and OpenMP implies -emit-llvm.
+ // Similarly, use a ".tmp.bc" suffix for the unoptimized bitcode
+ // (generated in the compile phase.)
+ const ToolChain *TC = JA.getOffloadingToolChain();
return isa<CompileJobAction>(JA) &&
- JA.getOffloadingDeviceKind() == Action::OFK_HIP &&
- Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
- false);
+ ((JA.getOffloadingDeviceKind() == Action::OFK_HIP &&
+ Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
+ false)) ||
+ (JA.getOffloadingDeviceKind() == Action::OFK_OpenMP && TC &&
+ TC->getTriple().isAMDGPU()));
};
if (!AtTopLevel && JA.getType() == types::TY_LLVM_BC &&
(C.getArgs().hasArg(options::OPT_emit_llvm) ||
- IsHIPRDCInCompilePhase(JA, C.getArgs())))
+ IsAMDRDCInCompilePhase(JA, C.getArgs())))
Suffixed += ".tmp";
Suffixed += '.';
Suffixed += Suffix;
@@ -5789,15 +5823,15 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
else
llvm::sys::path::append(BasePath, NamedOutput);
return C.addResultFile(C.getArgs().MakeArgString(BasePath.c_str()), &JA);
- } else {
- return C.addResultFile(NamedOutput, &JA);
}
+
+ return C.addResultFile(NamedOutput, &JA);
}
std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const {
// Search for Name in a list of paths.
auto SearchPaths = [&](const llvm::SmallVectorImpl<std::string> &P)
- -> llvm::Optional<std::string> {
+ -> std::optional<std::string> {
// Respect a limited subset of the '-Bprefix' functionality in GCC by
// attempting to use this prefix when looking for file paths.
for (const auto &Dir : P) {
@@ -5808,7 +5842,7 @@ std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const {
if (llvm::sys::fs::exists(Twine(P)))
return std::string(P);
}
- return None;
+ return std::nullopt;
};
if (auto P = SearchPaths(PrefixDirs))
@@ -6012,6 +6046,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
case llvm::Triple::Solaris:
TC = std::make_unique<toolchains::Solaris>(*this, Target, Args);
break;
+ case llvm::Triple::CUDA:
+ TC = std::make_unique<toolchains::NVPTXToolChain>(*this, Target, Args);
+ break;
case llvm::Triple::AMDHSA:
TC = std::make_unique<toolchains::ROCMToolChain>(*this, Target, Args);
break;
@@ -6131,11 +6168,6 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
}
}
- // Intentionally omitted from the switch above: llvm::Triple::CUDA. CUDA
- // compiles always need two toolchains, the CUDA toolchain and the host
- // toolchain. So the only valid way to create a CUDA toolchain is via
- // CreateOffloadingDeviceToolChains.
-
return *TC;
}
@@ -6300,6 +6332,25 @@ Driver::getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const {
return std::make_pair(IncludedFlagsBitmask, ExcludedFlagsBitmask);
}
+const char *Driver::getExecutableForDriverMode(DriverMode Mode) {
+ switch (Mode) {
+ case GCCMode:
+ return "clang";
+ case GXXMode:
+ return "clang++";
+ case CPPMode:
+ return "clang-cpp";
+ case CLMode:
+ return "clang-cl";
+ case FlangMode:
+ return "flang";
+ case DXCMode:
+ return "clang-dxc";
+ }
+
+ llvm_unreachable("Unhandled Mode");
+}
+
bool clang::driver::isOptimizationLevelFast(const ArgList &Args) {
return Args.hasFlag(options::OPT_Ofast, options::OPT_O_Group, false);
}