diff options
Diffstat (limited to 'lib/Driver/Driver.cpp')
-rw-r--r-- | lib/Driver/Driver.cpp | 478 |
1 files changed, 360 insertions, 118 deletions
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 952a716cb6e6..a784e218f139 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -26,8 +26,10 @@ #include "ToolChains/HIP.h" #include "ToolChains/Haiku.h" #include "ToolChains/Hexagon.h" +#include "ToolChains/Hurd.h" #include "ToolChains/Lanai.h" #include "ToolChains/Linux.h" +#include "ToolChains/MSP430.h" #include "ToolChains/MSVC.h" #include "ToolChains/MinGW.h" #include "ToolChains/Minix.h" @@ -37,13 +39,12 @@ #include "ToolChains/NetBSD.h" #include "ToolChains/OpenBSD.h" #include "ToolChains/PS4CPU.h" -#include "ToolChains/RISCV.h" +#include "ToolChains/RISCVToolchain.h" #include "ToolChains/Solaris.h" #include "ToolChains/TCE.h" #include "ToolChains/WebAssembly.h" #include "ToolChains/XCore.h" #include "clang/Basic/Version.h" -#include "clang/Basic/VirtualFileSystem.h" #include "clang/Config/config.h" #include "clang/Driver/Action.h" #include "clang/Driver/Compilation.h" @@ -68,18 +69,21 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include "llvm/Support/StringSaver.h" #include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include <map> #include <memory> #include <utility> #if LLVM_ON_UNIX #include <unistd.h> // getpid +#include <sysexits.h> // EX_IOERR #endif using namespace clang::driver; @@ -88,7 +92,7 @@ using namespace llvm::opt; Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr<vfs::FileSystem> VFS) + IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) : Opts(createDriverOptTable()), Diags(Diags), VFS(std::move(VFS)), Mode(GCCMode), SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), LTOMode(LTOK_None), ClangExecutable(ClangExecutable), @@ -98,12 +102,11 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false), TargetTriple(TargetTriple), CCCGenericGCCName(""), Saver(Alloc), CheckInputsExist(true), - CCCUsePCH(true), GenReproducer(false), - SuppressMissingInputWarning(false) { + GenReproducer(false), SuppressMissingInputWarning(false) { // Provide a sane fallback if no VFS is specified. if (!this->VFS) - this->VFS = vfs::getRealFileSystem(); + this->VFS = llvm::vfs::getRealFileSystem(); Name = llvm::sys::path::filename(ClangExecutable); Dir = llvm::sys::path::parent_path(ClangExecutable); @@ -164,6 +167,7 @@ void Driver::setDriverModeFromOption(StringRef Opt) { } InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings, + bool IsClCompatMode, bool &ContainsError) { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); ContainsError = false; @@ -171,7 +175,7 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings, unsigned IncludedFlagsBitmask; unsigned ExcludedFlagsBitmask; std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) = - getIncludeExcludeOptionFlagMasks(); + getIncludeExcludeOptionFlagMasks(IsClCompatMode); unsigned MissingArgIndex, MissingArgCount; InputArgList Args = @@ -300,6 +304,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { DerivedArgList *DAL = new DerivedArgList(Args); bool HasNostdlib = Args.hasArg(options::OPT_nostdlib); + bool HasNostdlibxx = Args.hasArg(options::OPT_nostdlibxx); bool HasNodefaultlib = Args.hasArg(options::OPT_nodefaultlibs); for (Arg *A : Args) { // Unfortunately, we have to parse some forwarding options (-Xassembler, @@ -344,7 +349,8 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { StringRef Value = A->getValue(); // Rewrite unless -nostdlib is present. - if (!HasNostdlib && !HasNodefaultlib && Value == "stdc++") { + if (!HasNostdlib && !HasNodefaultlib && !HasNostdlibxx && + Value == "stdc++") { DAL->AddFlagArg(A, Opts->getOption(options::OPT_Z_reserved_lib_stdcxx)); continue; } @@ -399,6 +405,13 @@ static llvm::Triple computeTargetTriple(const Driver &D, llvm::Triple Target(llvm::Triple::normalize(TargetTriple)); + // GNU/Hurd's triples should have been -hurd-gnu*, but were historically made + // -gnu* only, and we can not change this, so we have to detect that case as + // being the Hurd OS. + if (TargetTriple.find("-unknown-gnu") != StringRef::npos || + TargetTriple.find("-pc-gnu") != StringRef::npos) + Target.setOSName("hurd"); + // Handle Apple-specific options available here. if (Target.isOSBinFormatMachO()) { // If an explicit Darwin arch name is given, that trumps all. @@ -481,6 +494,29 @@ static llvm::Triple computeTargetTriple(const Driver &D, Target.setVendorName("intel"); } + // 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); + } + } + return Target; } @@ -705,7 +741,7 @@ bool Driver::readConfigFile(StringRef FileName) { ConfigFile = CfgFileName.str(); bool ContainErrors; CfgOptions = llvm::make_unique<InputArgList>( - ParseArgStrings(NewCfgArgs, ContainErrors)); + ParseArgStrings(NewCfgArgs, IsCLMode(), ContainErrors)); if (ContainErrors) { CfgOptions.reset(); return true; @@ -899,7 +935,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // Arguments specified in command line. bool ContainsError; CLOptions = llvm::make_unique<InputArgList>( - ParseArgStrings(ArgList.slice(1), ContainsError)); + ParseArgStrings(ArgList.slice(1), IsCLMode(), ContainsError)); // Try parsing configuration file. if (!ContainsError) @@ -909,22 +945,48 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // All arguments, from both config file and command line. InputArgList Args = std::move(HasConfigFile ? std::move(*CfgOptions) : std::move(*CLOptions)); - if (HasConfigFile) - for (auto *Opt : *CLOptions) { - if (Opt->getOption().matches(options::OPT_config)) - continue; + + auto appendOneArg = [&Args](const Arg *Opt, const Arg *BaseArg) { unsigned Index = Args.MakeIndex(Opt->getSpelling()); - const Arg *BaseArg = &Opt->getBaseArg(); - if (BaseArg == Opt) - BaseArg = nullptr; Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Opt->getSpelling(), Index, BaseArg); Copy->getValues() = Opt->getValues(); if (Opt->isClaimed()) Copy->claim(); Args.append(Copy); + }; + + if (HasConfigFile) + for (auto *Opt : *CLOptions) { + if (Opt->getOption().matches(options::OPT_config)) + continue; + const Arg *BaseArg = &Opt->getBaseArg(); + if (BaseArg == Opt) + BaseArg = nullptr; + appendOneArg(Opt, BaseArg); } + // In CL mode, look for any pass-through arguments + if (IsCLMode() && !ContainsError) { + SmallVector<const char *, 16> CLModePassThroughArgList; + for (const auto *A : Args.filtered(options::OPT__SLASH_clang)) { + A->claim(); + CLModePassThroughArgList.push_back(A->getValue()); + } + + if (!CLModePassThroughArgList.empty()) { + // Parse any pass through args using default clang processing rather + // than clang-cl processing. + auto CLModePassThroughOptions = llvm::make_unique<InputArgList>( + ParseArgStrings(CLModePassThroughArgList, false, ContainsError)); + + if (!ContainsError) + for (auto *Opt : *CLModePassThroughOptions) { + appendOneArg(Opt, nullptr); + } + } + } + // FIXME: This stuff needs to go into the Compilation, not the driver. bool CCCPrintPhases; @@ -947,8 +1009,6 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { CCCPrintBindings = Args.hasArg(options::OPT_ccc_print_bindings); if (const Arg *A = Args.getLastArg(options::OPT_ccc_gcc_name)) CCCGenericGCCName = A->getValue(); - CCCUsePCH = - Args.hasFlag(options::OPT_ccc_pch_is_pch, options::OPT_ccc_pch_is_pth); GenReproducer = Args.hasFlag(options::OPT_gen_reproducer, options::OPT_fno_crash_diagnostics, !!::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")); @@ -1377,8 +1437,9 @@ int Driver::ExecuteCompilation( // Otherwise, remove result files and print extra information about abnormal // failures. + int Res = 0; for (const auto &CmdPair : FailingCommands) { - int Res = CmdPair.first; + int CommandRes = CmdPair.first; const Command *FailingCommand = CmdPair.second; // Remove result files if we're not saving temps. @@ -1387,10 +1448,19 @@ int Driver::ExecuteCompilation( C.CleanupFileMap(C.getResultFiles(), JA, true); // Failure result files are valid unless we crashed. - if (Res < 0) + if (CommandRes < 0) C.CleanupFileMap(C.getFailureResultFiles(), JA, true); } +#if LLVM_ON_UNIX + // llvm/lib/Support/Unix/Signals.inc will exit with a special return code + // for SIGPIPE. Do not print diagnostics for this case. + if (CommandRes == EX_IOERR) { + Res = CommandRes; + continue; + } +#endif + // Print extra information about abnormal failures, if possible. // // This is ad-hoc, but we don't want to be excessively noisy. If the result @@ -1400,30 +1470,31 @@ int Driver::ExecuteCompilation( // diagnostics, so always print the diagnostic there. const Tool &FailingTool = FailingCommand->getCreator(); - if (!FailingCommand->getCreator().hasGoodDiagnostics() || Res != 1) { + if (!FailingCommand->getCreator().hasGoodDiagnostics() || CommandRes != 1) { // FIXME: See FIXME above regarding result code interpretation. - if (Res < 0) + if (CommandRes < 0) Diag(clang::diag::err_drv_command_signalled) << FailingTool.getShortName(); else - Diag(clang::diag::err_drv_command_failed) << FailingTool.getShortName() - << Res; + Diag(clang::diag::err_drv_command_failed) + << FailingTool.getShortName() << CommandRes; } } - return 0; + return Res; } void Driver::PrintHelp(bool ShowHidden) const { unsigned IncludedFlagsBitmask; unsigned ExcludedFlagsBitmask; std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) = - getIncludeExcludeOptionFlagMasks(); + getIncludeExcludeOptionFlagMasks(IsCLMode()); ExcludedFlagsBitmask |= options::NoDriverOption; if (!ShowHidden) ExcludedFlagsBitmask |= HelpHidden; - getOpts().PrintHelp(llvm::outs(), Name.c_str(), DriverTitle.c_str(), + std::string Usage = llvm::formatv("{0} [options] file...", Name).str(); + getOpts().PrintHelp(llvm::outs(), Usage.c_str(), DriverTitle.c_str(), IncludedFlagsBitmask, ExcludedFlagsBitmask, /*ShowAllAliases=*/false); } @@ -1472,6 +1543,11 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const { unsigned short DisableFlags = options::NoDriverOption | options::Unsupported | options::Ignored; + // Distinguish "--autocomplete=-someflag" and "--autocomplete=-someflag," + // because the latter indicates that the user put space before pushing tab + // which should end up in a file completion. + const bool HasSpace = PassedFlags.endswith(","); + // Parse PassedFlags by "," as all the command-line flags are passed to this // function separated by "," StringRef TargetFlags = PassedFlags; @@ -1498,7 +1574,19 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const { if (SuggestedCompletions.empty()) SuggestedCompletions = Opts->suggestValueCompletions(Cur, ""); - if (SuggestedCompletions.empty()) { + // If Flags were empty, it means the user typed `clang [tab]` where we should + // list all possible flags. If there was no value completion and the user + // pressed tab after a space, we should fall back to a file completion. + // We're printing a newline to be consistent with what we print at the end of + // this function. + if (SuggestedCompletions.empty() && HasSpace && !Flags.empty()) { + llvm::outs() << '\n'; + return; + } + + // When flag ends with '=' and there was no value completion, return empty + // string and fall back to the file autocompletion. + if (SuggestedCompletions.empty() && !Cur.endswith("=")) { // If the flag is in the form of "--autocomplete=-foo", // we were requested to print out all option names that start with "-foo". // For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only". @@ -1516,12 +1604,11 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const { // deterministic order. We could sort in any way, but we chose // case-insensitive sorting for consistency with the -help option // which prints out options in the case-insensitive alphabetical order. - llvm::sort(SuggestedCompletions.begin(), SuggestedCompletions.end(), - [](StringRef A, StringRef B) { - if (int X = A.compare_lower(B)) - return X < 0; - return A.compare(B) > 0; - }); + llvm::sort(SuggestedCompletions, [](StringRef A, StringRef B) { + if (int X = A.compare_lower(B)) + return X < 0; + return A.compare(B) > 0; + }); llvm::outs() << llvm::join(SuggestedCompletions, "\n") << '\n'; } @@ -1661,17 +1748,28 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { } if (C.getArgs().hasArg(options::OPT_print_multi_directory)) { - for (const Multilib &Multilib : TC.getMultilibs()) { - if (Multilib.gccSuffix().empty()) - llvm::outs() << ".\n"; - else { - StringRef Suffix(Multilib.gccSuffix()); - assert(Suffix.front() == '/'); - llvm::outs() << Suffix.substr(1) << "\n"; - } + const Multilib &Multilib = TC.getMultilib(); + if (Multilib.gccSuffix().empty()) + llvm::outs() << ".\n"; + else { + StringRef Suffix(Multilib.gccSuffix()); + assert(Suffix.front() == '/'); + llvm::outs() << Suffix.substr(1) << "\n"; } return false; } + + if (C.getArgs().hasArg(options::OPT_print_target_triple)) { + llvm::outs() << TC.getTripleString() << "\n"; + return false; + } + + if (C.getArgs().hasArg(options::OPT_print_effective_triple)) { + const llvm::Triple Triple(TC.ComputeEffectiveClangTriple(C.getArgs())); + llvm::outs() << Triple.getTriple() << "\n"; + return false; + } + return true; } @@ -1882,7 +1980,7 @@ static bool DiagnoseInputExistence(const Driver &D, const DerivedArgList &Args, } } - if (llvm::sys::fs::exists(Twine(Path))) + if (D.getVFS().exists(Path)) return true; if (D.IsCLMode()) { @@ -1960,7 +2058,8 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, Ty = types::TY_C; } else { // Otherwise lookup by extension. - // Fallback is C if invoked as C preprocessor or Object otherwise. + // Fallback is C if invoked as C preprocessor, C++ if invoked with + // clang-cl /E, or Object otherwise. // We use a host hook here because Darwin at least has its own // idea of what .s is. if (const char *Ext = strrchr(Value, '.')) @@ -1969,6 +2068,8 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, if (Ty == types::TY_INVALID) { if (CCCIsCPP()) Ty = types::TY_C; + else if (IsCLMode() && Args.hasArgNoClaim(options::OPT_E)) + Ty = types::TY_CXX; else Ty = types::TY_Object; } @@ -2223,6 +2324,18 @@ class OffloadingActionBuilder final { // If this is an unbundling action use it as is for each CUDA toolchain. if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(HostAction)) { CudaDeviceActions.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 (auto Arch : GpuArchList) { CudaDeviceActions.push_back(UA); UA->registerDependentActionInfo(ToolChains[0], CudaArchToString(Arch), @@ -2466,11 +2579,13 @@ class OffloadingActionBuilder final { class HIPActionBuilder final : public CudaActionBuilderBase { /// The linker inputs obtained for each device arch. SmallVector<ActionList, 8> DeviceLinkerInputs; + bool Relocatable; public: HIPActionBuilder(Compilation &C, DerivedArgList &Args, const Driver::InputList &Inputs) - : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) {} + : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP), + Relocatable(false) {} bool canUseBundlerUnbundler() const override { return true; } @@ -2479,23 +2594,70 @@ class OffloadingActionBuilder final { phases::ID CurPhase, phases::ID FinalPhase, PhasesTy &Phases) override { // amdgcn does not support linking of object files, therefore we skip - // backend and assemble phases to output LLVM IR. - if (CudaDeviceActions.empty() || CurPhase == phases::Backend || + // backend and assemble phases to output LLVM IR. Except for generating + // non-relocatable device coee, where we generate fat binary for device + // code and pass to host in Backend phase. + if (CudaDeviceActions.empty() || + (CurPhase == phases::Backend && Relocatable) || CurPhase == phases::Assemble) return ABRT_Success; - assert((CurPhase == phases::Link || + assert(((CurPhase == phases::Link && Relocatable) || CudaDeviceActions.size() == GpuArchList.size()) && "Expecting one action per GPU architecture."); assert(!CompileHostOnly && "Not expecting CUDA actions in host-only compilation."); - // Save CudaDeviceActions to DeviceLinkerInputs for each GPU subarch. - // This happens to each device action originated from each input file. - // Later on, device actions in DeviceLinkerInputs are used to create - // device link actions in appendLinkDependences and the created device - // link actions are passed to the offload action as device dependence. - if (CurPhase == phases::Link) { + if (!Relocatable && CurPhase == phases::Backend) { + // If we are in backend phase, we attempt to generate the fat binary. + // We compile each arch to IR and use a link action to generate code + // object containing ISA. Then we use a special "link" action to create + // a fat binary containing all the code objects for different GPU's. + // The fat binary is then an input to the host action. + for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { + // Create a link action to link device IR with device library + // and generate ISA. + ActionList AL; + AL.push_back(CudaDeviceActions[I]); + CudaDeviceActions[I] = + C.MakeAction<LinkJobAction>(AL, types::TY_Image); + + // OffloadingActionBuilder propagates device arch until an offload + // action. Since the next action for creating fatbin does + // not have device arch, whereas the above link action and its input + // have device arch, an offload action is needed to stop the null + // device arch of the next action being propagated to the above link + // action. + OffloadAction::DeviceDependences DDep; + DDep.add(*CudaDeviceActions[I], *ToolChains.front(), + CudaArchToString(GpuArchList[I]), AssociatedOffloadKind); + CudaDeviceActions[I] = C.MakeAction<OffloadAction>( + DDep, CudaDeviceActions[I]->getType()); + } + // Create HIP fat binary with a special "link" action. + CudaFatBinary = + C.MakeAction<LinkJobAction>(CudaDeviceActions, + types::TY_HIP_FATBIN); + + if (!CompileDeviceOnly) { + DA.add(*CudaFatBinary, *ToolChains.front(), /*BoundArch=*/nullptr, + AssociatedOffloadKind); + // Clear the fat binary, it is already a dependence to an host + // action. + CudaFatBinary = nullptr; + } + + // Remove the CUDA actions as they are already connected to an host + // action or fat binary. + CudaDeviceActions.clear(); + + return CompileDeviceOnly ? ABRT_Ignore_Host : ABRT_Success; + } else if (CurPhase == phases::Link) { + // Save CudaDeviceActions to DeviceLinkerInputs for each GPU subarch. + // This happens to each device action originated from each input file. + // Later on, device actions in DeviceLinkerInputs are used to create + // device link actions in appendLinkDependences and the created device + // link actions are passed to the offload action as device dependence. DeviceLinkerInputs.resize(CudaDeviceActions.size()); auto LI = DeviceLinkerInputs.begin(); for (auto *A : CudaDeviceActions) { @@ -2528,6 +2690,13 @@ class OffloadingActionBuilder final { ++I; } } + + bool initialize() override { + Relocatable = Args.hasFlag(options::OPT_fgpu_rdc, + options::OPT_fno_gpu_rdc, /*Default=*/false); + + return CudaActionBuilderBase::initialize(); + } }; /// OpenMP action builder. The host bitcode is passed to the device frontend @@ -2548,6 +2717,8 @@ class OffloadingActionBuilder final { 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() && @@ -2591,6 +2762,17 @@ class OffloadingActionBuilder final { // 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( @@ -2835,6 +3017,11 @@ public: OffloadKind |= SB->getAssociatedOffloadKind(); } + // Do not use unbundler if the Host does not depend on device action. + if (OffloadKind == Action::OFK_None && CanUseBundler) + if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(HostAction)) + HostAction = UA->getInputs().back(); + return false; } @@ -2852,8 +3039,10 @@ public: } // If we can use the bundler, replace the host action by the bundling one in - // the resulting list. Otherwise, just append the device actions. - if (CanUseBundler && !OffloadAL.empty()) { + // the resulting list. Otherwise, just append the device actions. For + // device only compilation, HostAction is a null pointer, therefore only do + // this when HostAction is not a null pointer. + if (CanUseBundler && HostAction && !OffloadAL.empty()) { // Add the host action to the list in order to create the bundling action. OffloadAL.push_back(HostAction); @@ -2971,22 +3160,9 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, } } - // Diagnose unsupported forms of /Yc /Yu. Ignore /Yc/Yu for now if: - // * no filename after it - // * both /Yc and /Yu passed but with different filenames - // * corresponding file not also passed as /FI + // Ignore /Yc/Yu if both /Yc and /Yu passed but with different filenames. Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc); Arg *YuArg = Args.getLastArg(options::OPT__SLASH_Yu); - if (YcArg && YcArg->getValue()[0] == '\0') { - Diag(clang::diag::warn_drv_ycyu_no_arg_clang_cl) << YcArg->getSpelling(); - Args.eraseArg(options::OPT__SLASH_Yc); - YcArg = nullptr; - } - if (YuArg && YuArg->getValue()[0] == '\0') { - Diag(clang::diag::warn_drv_ycyu_no_arg_clang_cl) << YuArg->getSpelling(); - Args.eraseArg(options::OPT__SLASH_Yu); - YuArg = nullptr; - } if (YcArg && YuArg && strcmp(YcArg->getValue(), YuArg->getValue()) != 0) { Diag(clang::diag::warn_drv_ycyu_different_arg_clang_cl); Args.eraseArg(options::OPT__SLASH_Yc); @@ -2998,9 +3174,10 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, Args.eraseArg(options::OPT__SLASH_Yc); YcArg = nullptr; } - if (Args.hasArg(options::OPT__SLASH_Y_)) { - // /Y- disables all pch handling. Rather than check for it everywhere, - // just remove clang-cl pch-related flags here. + if (FinalPhase == phases::Preprocess || Args.hasArg(options::OPT__SLASH_Y_)) { + // If only preprocessing or /Y- is used, all pch handling is disabled. + // Rather than check for it everywhere, just remove clang-cl pch-related + // flags here. Args.eraseArg(options::OPT__SLASH_Fp); Args.eraseArg(options::OPT__SLASH_Yc); Args.eraseArg(options::OPT__SLASH_Yu); @@ -3011,6 +3188,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, OffloadingActionBuilder OffloadBuilder(C, Args, Inputs); // Construct the actions to perform. + HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr; ActionList LinkerInputs; llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PL; @@ -3107,13 +3285,29 @@ 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; + } + + // FIXME: Should we include any prior module file outputs as inputs of + // later actions in the same command line? + // Otherwise construct the appropriate action. - auto *NewCurrent = ConstructPhaseAction(C, Args, Phase, Current); + Action *NewCurrent = ConstructPhaseAction(C, Args, Phase, Current); // We didn't create a new action, so we will just move to the next phase. if (NewCurrent == Current) continue; + if (auto *HMA = dyn_cast<HeaderModulePrecompileJobAction>(NewCurrent)) + HeaderModuleAction = HMA; + Current = NewCurrent; // Use the current host action in any of the offloading actions, if @@ -3193,10 +3387,25 @@ Action *Driver::ConstructPhaseAction( types::ID OutputTy = getPrecompiledType(Input->getType()); assert(OutputTy != types::TY_INVALID && "Cannot precompile this input type!"); + + // If we're given a module name, precompile header file inputs as a + // module, not as a precompiled header. + const char *ModName = nullptr; + if (OutputTy == types::TY_PCH) { + if (Arg *A = Args.getLastArg(options::OPT_fmodule_name_EQ)) + ModName = A->getValue(); + if (ModName) + OutputTy = types::TY_ModuleFile; + } + if (Args.hasArg(options::OPT_fsyntax_only)) { // Syntax checks should not emit a PCH file OutputTy = types::TY_Nothing; } + + if (ModName) + return C.MakeAction<HeaderModulePrecompileJobAction>(Input, OutputTy, + ModName); return C.MakeAction<PrecompileJobAction>(Input, OutputTy); } case phases::Compile: { @@ -3449,7 +3658,7 @@ class ToolSelector final { /// - Backend + Compile. const Tool * combineAssembleBackendCompile(ArrayRef<JobActionInfo> ActionInfo, - const ActionList *&Inputs, + ActionList &Inputs, ActionList &CollapsedOffloadAction) { if (ActionInfo.size() < 3 || !canCollapseAssembleAction()) return nullptr; @@ -3475,13 +3684,13 @@ class ToolSelector final { if (!T->hasIntegratedAssembler()) return nullptr; - Inputs = &CJ->getInputs(); + Inputs = CJ->getInputs(); AppendCollapsedOffloadAction(CollapsedOffloadAction, ActionInfo, /*NumElements=*/3); return T; } const Tool *combineAssembleBackend(ArrayRef<JobActionInfo> ActionInfo, - const ActionList *&Inputs, + ActionList &Inputs, ActionList &CollapsedOffloadAction) { if (ActionInfo.size() < 2 || !canCollapseAssembleAction()) return nullptr; @@ -3508,13 +3717,13 @@ class ToolSelector final { if (!T->hasIntegratedAssembler()) return nullptr; - Inputs = &BJ->getInputs(); + Inputs = BJ->getInputs(); AppendCollapsedOffloadAction(CollapsedOffloadAction, ActionInfo, /*NumElements=*/2); return T; } const Tool *combineBackendCompile(ArrayRef<JobActionInfo> ActionInfo, - const ActionList *&Inputs, + ActionList &Inputs, ActionList &CollapsedOffloadAction) { if (ActionInfo.size() < 2) return nullptr; @@ -3546,7 +3755,7 @@ class ToolSelector final { if (T->canEmitIR() && ((SaveTemps && !InputIsBitcode) || EmbedBitcode)) return nullptr; - Inputs = &CJ->getInputs(); + Inputs = CJ->getInputs(); AppendCollapsedOffloadAction(CollapsedOffloadAction, ActionInfo, /*NumElements=*/2); return T; @@ -3556,22 +3765,28 @@ class ToolSelector final { /// preprocessor action, and the current input is indeed a preprocessor /// action. If combining results in the collapse of offloading actions, those /// are appended to \a CollapsedOffloadAction. - void combineWithPreprocessor(const Tool *T, const ActionList *&Inputs, + void combineWithPreprocessor(const Tool *T, ActionList &Inputs, ActionList &CollapsedOffloadAction) { if (!T || !canCollapsePreprocessorAction() || !T->hasIntegratedCPP()) return; // Attempt to get a preprocessor action dependence. ActionList PreprocessJobOffloadActions; - auto *PJ = getPrevDependentAction(*Inputs, PreprocessJobOffloadActions); - if (!PJ || !isa<PreprocessJobAction>(PJ)) - return; + ActionList NewInputs; + for (Action *A : Inputs) { + auto *PJ = getPrevDependentAction({A}, PreprocessJobOffloadActions); + if (!PJ || !isa<PreprocessJobAction>(PJ)) { + NewInputs.push_back(A); + continue; + } - // This is legal to combine. Append any offload action we found and set the - // current inputs to preprocessor inputs. - CollapsedOffloadAction.append(PreprocessJobOffloadActions.begin(), - PreprocessJobOffloadActions.end()); - Inputs = &PJ->getInputs(); + // This is legal to combine. Append any offload action we found and add the + // current input to preprocessor inputs. + CollapsedOffloadAction.append(PreprocessJobOffloadActions.begin(), + PreprocessJobOffloadActions.end()); + NewInputs.append(PJ->input_begin(), PJ->input_end()); + } + Inputs = NewInputs; } public: @@ -3589,7 +3804,7 @@ public: /// connected to collapsed actions are updated accordingly. The latter enables /// the caller of the selector to process them afterwards instead of just /// dropping them. If no suitable tool is found, null will be returned. - const Tool *getTool(const ActionList *&Inputs, + const Tool *getTool(ActionList &Inputs, ActionList &CollapsedOffloadAction) { // // Get the largest chain of actions that we could combine. @@ -3625,7 +3840,7 @@ public: if (!T) T = combineBackendCompile(ActionChain, Inputs, CollapsedOffloadAction); if (!T) { - Inputs = &BaseAction->getInputs(); + Inputs = BaseAction->getInputs(); T = TC.SelectTool(*BaseAction); } @@ -3770,7 +3985,7 @@ InputInfo Driver::BuildJobsForActionNoCache( } - const ActionList *Inputs = &A->getInputs(); + ActionList Inputs = A->getInputs(); const JobAction *JA = cast<JobAction>(A); ActionList CollapsedOffloadActions; @@ -3796,7 +4011,7 @@ InputInfo Driver::BuildJobsForActionNoCache( // Only use pipes when there is exactly one input. InputInfoList InputInfos; - for (const Action *Input : *Inputs) { + for (const Action *Input : Inputs) { // Treat dsymutil and verify sub-jobs as being at the top-level too, they // shouldn't get temporary output names. // FIXME: Clean this up. @@ -3815,6 +4030,10 @@ InputInfo 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(), @@ -4153,16 +4372,24 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, } std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const { - // Respect a limited subset of the '-Bprefix' functionality in GCC by - // attempting to use this prefix when looking for file paths. - for (const std::string &Dir : PrefixDirs) { - if (Dir.empty()) - continue; - SmallString<128> P(Dir[0] == '=' ? SysRoot + Dir.substr(1) : Dir); - llvm::sys::path::append(P, Name); - if (llvm::sys::fs::exists(Twine(P))) - return P.str(); - } + // Search for Name in a list of paths. + auto SearchPaths = [&](const llvm::SmallVectorImpl<std::string> &P) + -> llvm::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) { + if (Dir.empty()) + continue; + SmallString<128> P(Dir[0] == '=' ? SysRoot + Dir.substr(1) : Dir); + llvm::sys::path::append(P, Name); + if (llvm::sys::fs::exists(Twine(P))) + return P.str().str(); + } + return None; + }; + + if (auto P = SearchPaths(PrefixDirs)) + return *P; SmallString<128> R(ResourceDir); llvm::sys::path::append(R, Name); @@ -4174,14 +4401,11 @@ std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const { if (llvm::sys::fs::exists(Twine(P))) return P.str(); - for (const std::string &Dir : TC.getFilePaths()) { - if (Dir.empty()) - continue; - SmallString<128> P(Dir[0] == '=' ? SysRoot + Dir.substr(1) : Dir); - llvm::sys::path::append(P, Name); - if (llvm::sys::fs::exists(Twine(P))) - return P.str(); - } + if (auto P = SearchPaths(TC.getLibraryPaths())) + return *P; + + if (auto P = SearchPaths(TC.getFilePaths())) + return *P; return Name; } @@ -4255,6 +4479,17 @@ std::string Driver::GetTemporaryPath(StringRef Prefix, StringRef Suffix) const { return Path.str(); } +std::string Driver::GetTemporaryDirectory(StringRef Prefix) const { + SmallString<128> Path; + std::error_code EC = llvm::sys::fs::createUniqueDirectory(Prefix, Path); + if (EC) { + Diag(clang::diag::err_unable_to_make_temp) << EC.message(); + return ""; + } + + return Path.str(); +} + std::string Driver::GetClPchPath(Compilation &C, StringRef BaseName) const { SmallString<128> Output; if (Arg *FpArg = C.getArgs().getLastArg(options::OPT__SLASH_Fp)) { @@ -4267,11 +4502,11 @@ std::string Driver::GetClPchPath(Compilation &C, StringRef BaseName) const { // extension of .pch is assumed. " if (!llvm::sys::path::has_extension(Output)) Output += ".pch"; - } else if (Arg *YcArg = C.getArgs().getLastArg(options::OPT__SLASH_Yc)) { - Output = YcArg->getValue(); - llvm::sys::path::replace_extension(Output, ".pch"); } else { - Output = BaseName; + if (Arg *YcArg = C.getArgs().getLastArg(options::OPT__SLASH_Yc)) + Output = YcArg->getValue(); + if (Output.empty()) + Output = BaseName; llvm::sys::path::replace_extension(Output, ".pch"); } return Output.str(); @@ -4373,6 +4608,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::Contiki: TC = llvm::make_unique<toolchains::Contiki>(*this, Target, Args); break; + case llvm::Triple::Hurd: + TC = llvm::make_unique<toolchains::Hurd>(*this, Target, Args); + break; default: // Of these targets, Hexagon is the only one that might have // an OS of Linux, in which case it got handled above already. @@ -4400,6 +4638,10 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::avr: TC = llvm::make_unique<toolchains::AVRToolChain>(*this, Target, Args); break; + case llvm::Triple::msp430: + TC = + llvm::make_unique<toolchains::MSP430ToolChain>(*this, Target, Args); + break; case llvm::Triple::riscv32: case llvm::Triple::riscv64: TC = llvm::make_unique<toolchains::RISCVToolChain>(*this, Target, Args); @@ -4508,11 +4750,11 @@ bool Driver::GetReleaseVersion(StringRef Str, return false; } -std::pair<unsigned, unsigned> Driver::getIncludeExcludeOptionFlagMasks() const { +std::pair<unsigned, unsigned> Driver::getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const { unsigned IncludedFlagsBitmask = 0; unsigned ExcludedFlagsBitmask = options::NoDriverOption; - if (Mode == CLMode) { + if (IsClCompatMode) { // Include CL and Core options. IncludedFlagsBitmask |= options::CLOption; IncludedFlagsBitmask |= options::CoreOption; |