diff options
Diffstat (limited to 'clang/lib/Driver/Driver.cpp')
-rw-r--r-- | clang/lib/Driver/Driver.cpp | 1199 |
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); } |