aboutsummaryrefslogtreecommitdiff
path: root/lib/Driver/Driver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Driver/Driver.cpp')
-rw-r--r--lib/Driver/Driver.cpp478
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;