diff options
author | dim <dim@FreeBSD.org> | 2016-12-26 20:36:37 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2016-12-26 20:36:37 +0000 |
commit | 06210ae42d418d50d8d9365d5c9419308ae9e7ee (patch) | |
tree | ab60b4cdd6e430dda1f292a46a77ddb744723f31 /contrib/llvm/tools/clang/lib/Driver/Driver.cpp | |
parent | 2dd166267f53df1c3748b4325d294b9b839de74b (diff) | |
download | FreeBSD-src-06210ae42d418d50d8d9365d5c9419308ae9e7ee.zip FreeBSD-src-06210ae42d418d50d8d9365d5c9419308ae9e7ee.tar.gz |
MFC r309124:
Upgrade our copies of clang, llvm, lldb, compiler-rt and libc++ to 3.9.0
release, and add lld 3.9.0. Also completely revamp the build system for
clang, llvm, lldb and their related tools.
Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11
support to build; see UPDATING for more information.
Release notes for llvm, clang and lld are available here:
<http://llvm.org/releases/3.9.0/docs/ReleaseNotes.html>
<http://llvm.org/releases/3.9.0/tools/clang/docs/ReleaseNotes.html>
<http://llvm.org/releases/3.9.0/tools/lld/docs/ReleaseNotes.html>
Thanks to Ed Maste, Bryan Drewery, Andrew Turner, Antoine Brodin and Jan
Beich for their help.
Relnotes: yes
MFC r309147:
Pull in r282174 from upstream llvm trunk (by Krzysztof Parzyszek):
[PPC] Set SP after loading data from stack frame, if no red zone is
present
Follow-up to r280705: Make sure that the SP is only restored after
all data is loaded from the stack frame, if there is no red zone.
This completes the fix for
https://llvm.org/bugs/show_bug.cgi?id=26519.
Differential Revision: https://reviews.llvm.org/D24466
Reported by: Mark Millard
PR: 214433
MFC r309149:
Pull in r283060 from upstream llvm trunk (by Hal Finkel):
[PowerPC] Refactor soft-float support, and enable PPC64 soft float
This change enables soft-float for PowerPC64, and also makes
soft-float disable all vector instruction sets for both 32-bit and
64-bit modes. This latter part is necessary because the PPC backend
canonicalizes many Altivec vector types to floating-point types, and
so soft-float breaks scalarization support for many operations. Both
for embedded targets and for operating-system kernels desiring
soft-float support, it seems reasonable that disabling hardware
floating-point also disables vector instructions (embedded targets
without hardware floating point support are unlikely to have Altivec,
etc. and operating system kernels desiring not to use floating-point
registers to lower syscall cost are unlikely to want to use vector
registers either). If someone needs this to work, we'll need to
change the fact that we promote many Altivec operations to act on
v4f32. To make it possible to disable Altivec when soft-float is
enabled, hardware floating-point support needs to be expressed as a
positive feature, like the others, and not a negative feature,
because target features cannot have dependencies on the disabling of
some other feature. So +soft-float has now become -hard-float.
Fixes PR26970.
Pull in r283061 from upstream clang trunk (by Hal Finkel):
[PowerPC] Enable soft-float for PPC64, and +soft-float -> -hard-float
Enable soft-float support on PPC64, as the backend now supports it.
Also, the backend now uses -hard-float instead of +soft-float, so set
the target features accordingly.
Fixes PR26970.
Reported by: Mark Millard
PR: 214433
MFC r309212:
Add a few missed clang 3.9.0 files to OptionalObsoleteFiles.
MFC r309262:
Fix packaging for clang, lldb and lld 3.9.0
During the upgrade of clang/llvm etc to 3.9.0 in r309124, the PACKAGE
directive in the usr.bin/clang/*.mk files got dropped accidentally.
Restore it, with a few minor changes and additions:
* Correct license in clang.ucl to NCSA
* Add PACKAGE=clang for clang and most of the "ll" tools
* Put lldb in its own package
* Put lld in its own package
Reviewed by: gjb, jmallett
Differential Revision: https://reviews.freebsd.org/D8666
MFC r309656:
During the bootstrap phase, when building the minimal llvm library on
PowerPC, add lib/Support/Atomic.cpp. This is needed because upstream
llvm revision r271821 disabled the use of std::call_once, which causes
some fallback functions from Atomic.cpp to be used instead.
Reported by: Mark Millard
PR: 214902
MFC r309835:
Tentatively apply https://reviews.llvm.org/D18730 to work around gcc PR
70528 (bogus error: constructor required before non-static data member).
This should fix buildworld with the external gcc package.
Reported by: https://jenkins.freebsd.org/job/FreeBSD_HEAD_amd64_gcc/
MFC r310194:
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
3.9.1 release.
Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11
support to build; see UPDATING for more information.
Release notes for llvm, clang and lld will be available here:
<http://releases.llvm.org/3.9.1/docs/ReleaseNotes.html>
<http://releases.llvm.org/3.9.1/tools/clang/docs/ReleaseNotes.html>
<http://releases.llvm.org/3.9.1/tools/lld/docs/ReleaseNotes.html>
Relnotes: yes
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Driver/Driver.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/Driver.cpp | 773 |
1 files changed, 602 insertions, 171 deletions
diff --git a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp index 1e0a48d..02f4a99 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp @@ -23,6 +23,7 @@ #include "clang/Driver/ToolChain.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" @@ -41,6 +42,7 @@ #include "llvm/Support/raw_ostream.h" #include <map> #include <memory> +#include <utility> using namespace clang::driver; using namespace clang; @@ -49,9 +51,9 @@ using namespace llvm::opt; Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple, DiagnosticsEngine &Diags, IntrusiveRefCntPtr<vfs::FileSystem> VFS) - : Opts(createDriverOptTable()), Diags(Diags), VFS(VFS), Mode(GCCMode), - SaveTemps(SaveTempsNone), LTOMode(LTOK_None), - ClangExecutable(ClangExecutable), + : Opts(createDriverOptTable()), Diags(Diags), VFS(std::move(VFS)), + Mode(GCCMode), SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), + LTOMode(LTOK_None), ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT), UseStdLib(true), DefaultTargetTriple(DefaultTargetTriple), DriverTitle("clang LLVM compiler"), CCPrintOptionsFilename(nullptr), @@ -146,7 +148,9 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings) { } for (const Arg *A : Args.filtered(options::OPT_UNKNOWN)) - Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args); + Diags.Report(IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl : + diag::err_drv_unknown_argument) + << A->getAsString(Args); return Args; } @@ -276,6 +280,10 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { DAL->append(A); } + // Enforce -static if -miamcu is present. + if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false)) + DAL->AddFlagArg(0, Opts->getOption(options::OPT_static)); + // Add a default value of -mlinker-version=, if one was given and the user // didn't specify one. #if defined(HOST_LINK_VERSION) @@ -294,7 +302,8 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { /// /// This routine provides the logic to compute a target triple from various /// args passed to the driver and the default triple string. -static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, +static llvm::Triple computeTargetTriple(const Driver &D, + StringRef DefaultTargetTriple, const ArgList &Args, StringRef DarwinArchName = "") { // FIXME: Already done in Compilation *Driver::BuildCompilation @@ -339,8 +348,9 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, return Target; // Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'. - if (Arg *A = Args.getLastArg(options::OPT_m64, options::OPT_mx32, - options::OPT_m32, options::OPT_m16)) { + Arg *A = Args.getLastArg(options::OPT_m64, options::OPT_mx32, + options::OPT_m32, options::OPT_m16); + if (A) { llvm::Triple::ArchType AT = llvm::Triple::UnknownArch; if (A->getOption().matches(options::OPT_m64)) { @@ -365,6 +375,25 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, Target.setArch(AT); } + // Handle -miamcu flag. + if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false)) { + if (Target.get32BitArchVariant().getArch() != llvm::Triple::x86) + D.Diag(diag::err_drv_unsupported_opt_for_target) << "-miamcu" + << Target.str(); + + if (A && !A->getOption().matches(options::OPT_m32)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << "-miamcu" << A->getBaseArg().getAsString(Args); + + Target.setArch(llvm::Triple::x86); + Target.setArchName("i586"); + Target.setEnvironment(llvm::Triple::UnknownEnvironment); + Target.setEnvironmentName(""); + Target.setOS(llvm::Triple::ELFIAMCU); + Target.setVendor(llvm::Triple::UnknownVendor); + Target.setVendorName("intel"); + } + return Target; } @@ -394,6 +423,33 @@ void Driver::setLTOMode(const llvm::opt::ArgList &Args) { } } +void Driver::CreateOffloadingDeviceToolChains(Compilation &C, + InputList &Inputs) { + + // + // CUDA + // + // We need to generate a CUDA toolchain if any of the inputs has a CUDA type. + if (llvm::any_of(Inputs, [](std::pair<types::ID, const llvm::opt::Arg *> &I) { + return types::isCuda(I.first); + })) { + const ToolChain &TC = getToolChain( + C.getInputArgs(), + llvm::Triple(C.getSingleOffloadToolChain<Action::OFK_Host>() + ->getTriple() + .isArch64Bit() + ? "nvptx64-nvidia-cuda" + : "nvptx-nvidia-cuda")); + C.addOffloadDeviceToolChain(&TC, Action::OFK_Cuda); + } + + // + // TODO: Add support for other offloading programming models here. + // + + return; +} + Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { llvm::PrettyStackTraceString CrashInfo("Compilation construction"); @@ -479,6 +535,28 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { setLTOMode(Args); + // Ignore -fembed-bitcode options with LTO + // since the output will be bitcode anyway. + if (getLTOMode() == LTOK_None) { + if (Arg *A = Args.getLastArg(options::OPT_fembed_bitcode_EQ)) { + StringRef Name = A->getValue(); + unsigned Model = llvm::StringSwitch<unsigned>(Name) + .Case("off", EmbedNone) + .Case("all", EmbedBitcode) + .Case("bitcode", EmbedBitcode) + .Case("marker", EmbedMarker) + .Default(~0U); + if (Model == ~0U) { + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) + << Name; + } else + BitcodeEmbed = static_cast<BitcodeEmbedMode>(Model); + } + } else { + // claim the bitcode option under LTO so no warning is issued. + Args.ClaimAllArgs(options::OPT_fembed_bitcode_EQ); + } + std::unique_ptr<llvm::opt::InputArgList> UArgs = llvm::make_unique<InputArgList>(std::move(Args)); @@ -486,16 +564,12 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { DerivedArgList *TranslatedArgs = TranslateInputArgs(*UArgs); // Owned by the host. - const ToolChain &TC = - getToolChain(*UArgs, computeTargetTriple(DefaultTargetTriple, *UArgs)); + const ToolChain &TC = getToolChain( + *UArgs, computeTargetTriple(*this, DefaultTargetTriple, *UArgs)); // The compilation takes ownership of Args. Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs); - C->setCudaDeviceToolChain( - &getToolChain(C->getArgs(), llvm::Triple(TC.getTriple().isArch64Bit() - ? "nvptx64-nvidia-cuda" - : "nvptx-nvidia-cuda"))); if (!HandleImmediateArgs(*C)) return C; @@ -503,13 +577,15 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { InputList Inputs; BuildInputs(C->getDefaultToolChain(), *TranslatedArgs, Inputs); + // Populate the tool chains for the offloading devices, if any. + CreateOffloadingDeviceToolChains(*C, Inputs); + // Construct the list of abstract actions to perform for this compilation. On // MachO targets this uses the driver-driver and universal actions. if (TC.getTriple().isOSBinFormatMachO()) BuildUniversalActions(*C, C->getDefaultToolChain(), Inputs); else - BuildActions(*C, C->getDefaultToolChain(), C->getArgs(), Inputs, - C->getActions()); + BuildActions(*C, C->getArgs(), Inputs, C->getActions()); if (CCCPrintPhases) { PrintActions(*C); @@ -623,7 +699,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C, if (TC.getTriple().isOSBinFormatMachO()) BuildUniversalActions(C, TC, Inputs); else - BuildActions(C, TC, C.getArgs(), Inputs, C.getActions()); + BuildActions(C, C.getArgs(), Inputs, C.getActions()); BuildJobs(C); @@ -947,18 +1023,34 @@ static unsigned PrintActions1(const Compilation &C, Action *A, os << "\"" << IA->getInputArg().getValue() << "\""; } else if (BindArchAction *BIA = dyn_cast<BindArchAction>(A)) { os << '"' << BIA->getArchName() << '"' << ", {" - << PrintActions1(C, *BIA->begin(), Ids) << "}"; - } else if (CudaDeviceAction *CDA = dyn_cast<CudaDeviceAction>(A)) { - os << '"' << CDA->getGpuArchName() << '"' << ", {" - << PrintActions1(C, *CDA->begin(), Ids) << "}"; + << PrintActions1(C, *BIA->input_begin(), Ids) << "}"; + } else if (OffloadAction *OA = dyn_cast<OffloadAction>(A)) { + bool IsFirst = true; + OA->doOnEachDependence( + [&](Action *A, const ToolChain *TC, const char *BoundArch) { + // E.g. for two CUDA device dependences whose bound arch is sm_20 and + // sm_35 this will generate: + // "cuda-device" (nvptx64-nvidia-cuda:sm_20) {#ID}, "cuda-device" + // (nvptx64-nvidia-cuda:sm_35) {#ID} + if (!IsFirst) + os << ", "; + os << '"'; + if (TC) + os << A->getOffloadingKindPrefix(); + else + os << "host"; + os << " ("; + os << TC->getTriple().normalize(); + + if (BoundArch) + os << ":" << BoundArch; + os << ")"; + os << '"'; + os << " {" << PrintActions1(C, A, Ids) << "}"; + IsFirst = false; + }); } else { - const ActionList *AL; - if (CudaHostAction *CHA = dyn_cast<CudaHostAction>(A)) { - os << "{" << PrintActions1(C, *CHA->begin(), Ids) << "}" - << ", gpu binaries "; - AL = &CHA->getDeviceActions(); - } else - AL = &A->getInputs(); + const ActionList *AL = &A->getInputs(); if (AL->size()) { const char *Prefix = "{"; @@ -971,10 +1063,24 @@ static unsigned PrintActions1(const Compilation &C, Action *A, os << "{}"; } + // Append offload info for all options other than the offloading action + // itself (e.g. (cuda-device, sm_20) or (cuda-host)). + std::string offload_str; + llvm::raw_string_ostream offload_os(offload_str); + if (!isa<OffloadAction>(A)) { + auto S = A->getOffloadingKindPrefix(); + if (!S.empty()) { + offload_os << ", (" << S; + if (A->getOffloadingArch()) + offload_os << ", " << A->getOffloadingArch(); + offload_os << ")"; + } + } + unsigned Id = Ids.size(); Ids[A] = Id; llvm::errs() << Id << ": " << os.str() << ", " - << types::getTypeName(A->getType()) << "\n"; + << types::getTypeName(A->getType()) << offload_os.str() << "\n"; return Id; } @@ -994,7 +1100,7 @@ static bool ContainsCompileOrAssembleAction(const Action *A) { isa<AssembleJobAction>(A)) return true; - for (const Action *Input : *A) + for (const Action *Input : A->inputs()) if (ContainsCompileOrAssembleAction(Input)) return true; @@ -1033,7 +1139,7 @@ void Driver::BuildUniversalActions(Compilation &C, const ToolChain &TC, Archs.push_back(Args.MakeArgString(TC.getDefaultUniversalArchName())); ActionList SingleActions; - BuildActions(C, TC, Args, BAInputs, SingleActions); + BuildActions(C, Args, BAInputs, SingleActions); // Add in arch bindings for every top level action, as well as lipo and // dsymutil steps if needed. @@ -1091,7 +1197,7 @@ void Driver::BuildUniversalActions(Compilation &C, const ToolChain &TC, /// \brief Check that the file referenced by Value exists. If it doesn't, /// issue a diagnostic and return false. static bool DiagnoseInputExistence(const Driver &D, const DerivedArgList &Args, - StringRef Value) { + StringRef Value, types::ID Ty) { if (!D.getCheckInputsExist()) return true; @@ -1111,9 +1217,18 @@ static bool DiagnoseInputExistence(const Driver &D, const DerivedArgList &Args, if (llvm::sys::fs::exists(Twine(Path))) return true; - if (D.IsCLMode() && !llvm::sys::path::is_absolute(Twine(Path)) && - llvm::sys::Process::FindInEnvPath("LIB", Value)) - return true; + if (D.IsCLMode()) { + if (!llvm::sys::path::is_absolute(Twine(Path)) && + llvm::sys::Process::FindInEnvPath("LIB", Value)) + return true; + + if (Args.hasArg(options::OPT__SLASH_link) && Ty == types::TY_Object) { + // Arguments to the /link flag might cause the linker to search for object + // and library files in paths we don't know about. Don't error in such + // cases. + return true; + } + } D.Diag(clang::diag::err_drv_no_such_file) << Path; return false; @@ -1229,19 +1344,19 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, } } - if (DiagnoseInputExistence(*this, Args, Value)) + if (DiagnoseInputExistence(*this, Args, Value, Ty)) Inputs.push_back(std::make_pair(Ty, A)); } else if (A->getOption().matches(options::OPT__SLASH_Tc)) { StringRef Value = A->getValue(); - if (DiagnoseInputExistence(*this, Args, Value)) { + if (DiagnoseInputExistence(*this, Args, Value, types::TY_C)) { Arg *InputArg = MakeInputArg(Args, Opts, A->getValue()); Inputs.push_back(std::make_pair(types::TY_C, InputArg)); } A->claim(); } else if (A->getOption().matches(options::OPT__SLASH_Tp)) { StringRef Value = A->getValue(); - if (DiagnoseInputExistence(*this, Args, Value)) { + if (DiagnoseInputExistence(*this, Args, Value, types::TY_CXX)) { Arg *InputArg = MakeInputArg(Args, Opts, A->getValue()); Inputs.push_back(std::make_pair(types::TY_CXX, InputArg)); } @@ -1283,32 +1398,43 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, static Action *buildCudaActions(Compilation &C, DerivedArgList &Args, const Arg *InputArg, Action *HostAction, ActionList &Actions) { - Arg *PartialCompilationArg = Args.getLastArg(options::OPT_cuda_host_only, - options::OPT_cuda_device_only); - // Host-only compilation case. - if (PartialCompilationArg && - PartialCompilationArg->getOption().matches(options::OPT_cuda_host_only)) - return C.MakeAction<CudaHostAction>(HostAction, ActionList()); + Arg *PartialCompilationArg = Args.getLastArg( + options::OPT_cuda_host_only, options::OPT_cuda_device_only, + options::OPT_cuda_compile_host_device); + bool CompileHostOnly = + PartialCompilationArg && + PartialCompilationArg->getOption().matches(options::OPT_cuda_host_only); + bool CompileDeviceOnly = + PartialCompilationArg && + PartialCompilationArg->getOption().matches(options::OPT_cuda_device_only); + + if (CompileHostOnly) { + OffloadAction::HostDependence HDep( + *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), + /*BoundArch=*/nullptr, Action::OFK_Cuda); + return C.MakeAction<OffloadAction>(HDep); + } // Collect all cuda_gpu_arch parameters, removing duplicates. - SmallVector<const char *, 4> GpuArchList; - llvm::StringSet<> GpuArchNames; + SmallVector<CudaArch, 4> GpuArchList; + llvm::SmallSet<CudaArch, 4> GpuArchs; for (Arg *A : Args) { if (!A->getOption().matches(options::OPT_cuda_gpu_arch_EQ)) continue; A->claim(); - const auto& Arch = A->getValue(); - if (!CudaDeviceAction::IsValidGpuArchName(Arch)) - C.getDriver().Diag(clang::diag::err_drv_cuda_bad_gpu_arch) << Arch; - else if (GpuArchNames.insert(Arch).second) + const auto &ArchStr = A->getValue(); + CudaArch Arch = StringToCudaArch(ArchStr); + if (Arch == CudaArch::UNKNOWN) + C.getDriver().Diag(clang::diag::err_drv_cuda_bad_gpu_arch) << ArchStr; + else if (GpuArchs.insert(Arch).second) GpuArchList.push_back(Arch); } // Default to sm_20 which is the lowest common denominator for supported GPUs. // sm_20 code should work correctly, if suboptimally, on all newer GPUs. if (GpuArchList.empty()) - GpuArchList.push_back("sm_20"); + GpuArchList.push_back(CudaArch::SM_20); // Replicate inputs for each GPU architecture. Driver::InputList CudaDeviceInputs; @@ -1316,61 +1442,81 @@ static Action *buildCudaActions(Compilation &C, DerivedArgList &Args, CudaDeviceInputs.push_back(std::make_pair(types::TY_CUDA_DEVICE, InputArg)); // Build actions for all device inputs. - assert(C.getCudaDeviceToolChain() && - "Missing toolchain for device-side compilation."); ActionList CudaDeviceActions; - C.getDriver().BuildActions(C, *C.getCudaDeviceToolChain(), Args, - CudaDeviceInputs, CudaDeviceActions); + C.getDriver().BuildActions(C, Args, CudaDeviceInputs, CudaDeviceActions); assert(GpuArchList.size() == CudaDeviceActions.size() && "Failed to create actions for all devices"); // Check whether any of device actions stopped before they could generate PTX. bool PartialCompilation = llvm::any_of(CudaDeviceActions, [](const Action *a) { - return a->getKind() != Action::BackendJobClass; + return a->getKind() != Action::AssembleJobClass; }); + const ToolChain *CudaTC = C.getSingleOffloadToolChain<Action::OFK_Cuda>(); + // Figure out what to do with device actions -- pass them as inputs to the // host action or run each of them independently. - bool DeviceOnlyCompilation = PartialCompilationArg != nullptr; - if (PartialCompilation || DeviceOnlyCompilation) { + if (PartialCompilation || CompileDeviceOnly) { // In case of partial or device-only compilation results of device actions // are not consumed by the host action device actions have to be added to // top-level actions list with AtTopLevel=true and run independently. // -o is ambiguous if we have more than one top-level action. if (Args.hasArg(options::OPT_o) && - (!DeviceOnlyCompilation || GpuArchList.size() > 1)) { + (!CompileDeviceOnly || GpuArchList.size() > 1)) { C.getDriver().Diag( clang::diag::err_drv_output_argument_with_multiple_files); return nullptr; } - for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) - Actions.push_back(C.MakeAction<CudaDeviceAction>(CudaDeviceActions[I], - GpuArchList[I], - /* AtTopLevel */ true)); + for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { + OffloadAction::DeviceDependences DDep; + DDep.add(*CudaDeviceActions[I], *CudaTC, CudaArchToString(GpuArchList[I]), + Action::OFK_Cuda); + Actions.push_back( + C.MakeAction<OffloadAction>(DDep, CudaDeviceActions[I]->getType())); + } // Kill host action in case of device-only compilation. - if (DeviceOnlyCompilation) + if (CompileDeviceOnly) return nullptr; return HostAction; } - // Outputs of device actions during complete CUDA compilation get created - // with AtTopLevel=false and become inputs for the host action. + // If we're not a partial or device-only compilation, we compile each arch to + // ptx and assemble to cubin, then feed the cubin *and* the ptx into a device + // "link" action, which uses fatbinary to combine these cubins into one + // fatbin. The fatbin is then an input to the host compilation. ActionList DeviceActions; - for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) - DeviceActions.push_back( - C.MakeAction<CudaDeviceAction>(CudaDeviceActions[I], GpuArchList[I], - /* AtTopLevel */ false)); + for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { + Action* AssembleAction = CudaDeviceActions[I]; + assert(AssembleAction->getType() == types::TY_Object); + assert(AssembleAction->getInputs().size() == 1); + + Action* BackendAction = AssembleAction->getInputs()[0]; + assert(BackendAction->getType() == types::TY_PP_Asm); + + for (auto &A : {AssembleAction, BackendAction}) { + OffloadAction::DeviceDependences DDep; + DDep.add(*A, *CudaTC, CudaArchToString(GpuArchList[I]), Action::OFK_Cuda); + DeviceActions.push_back(C.MakeAction<OffloadAction>(DDep, A->getType())); + } + } + auto FatbinAction = + C.MakeAction<LinkJobAction>(DeviceActions, types::TY_CUDA_FATBIN); + // Return a new host action that incorporates original host action and all // device actions. - return C.MakeAction<CudaHostAction>(HostAction, DeviceActions); + OffloadAction::HostDependence HDep( + *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), + /*BoundArch=*/nullptr, Action::OFK_Cuda); + OffloadAction::DeviceDependences DDep; + DDep.add(*FatbinAction, *CudaTC, /*BoundArch=*/nullptr, Action::OFK_Cuda); + return C.MakeAction<OffloadAction>(HDep, DDep); } -void Driver::BuildActions(Compilation &C, const ToolChain &TC, - DerivedArgList &Args, const InputList &Inputs, - ActionList &Actions) const { +void Driver::BuildActions(Compilation &C, DerivedArgList &Args, + const InputList &Inputs, ActionList &Actions) const { llvm::PrettyStackTraceString CrashInfo("Building compilation actions"); if (!SuppressMissingInputWarning && Inputs.empty()) { @@ -1423,6 +1569,61 @@ void Driver::BuildActions(Compilation &C, const ToolChain &TC, } } + // 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 + 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); + Args.eraseArg(options::OPT__SLASH_Yu); + YcArg = YuArg = nullptr; + } + if (YcArg || YuArg) { + StringRef Val = YcArg ? YcArg->getValue() : YuArg->getValue(); + bool FoundMatchingInclude = false; + for (const Arg *Inc : Args.filtered(options::OPT_include)) { + // FIXME: Do case-insensitive matching and consider / and \ as equal. + if (Inc->getValue() == Val) + FoundMatchingInclude = true; + } + if (!FoundMatchingInclude) { + Diag(clang::diag::warn_drv_ycyu_no_fi_arg_clang_cl) + << (YcArg ? YcArg : YuArg)->getSpelling(); + Args.eraseArg(options::OPT__SLASH_Yc); + Args.eraseArg(options::OPT__SLASH_Yu); + YcArg = YuArg = nullptr; + } + } + if (YcArg && Inputs.size() > 1) { + Diag(clang::diag::warn_drv_yc_multiple_inputs_clang_cl); + 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. + Args.eraseArg(options::OPT__SLASH_Fp); + Args.eraseArg(options::OPT__SLASH_Yc); + Args.eraseArg(options::OPT__SLASH_Yu); + YcArg = YuArg = nullptr; + } + + // Track the host offload kinds used on this compilation. + unsigned CompilationActiveOffloadHostKinds = 0u; + // Construct the actions to perform. ActionList LinkerInputs; @@ -1466,12 +1667,34 @@ void Driver::BuildActions(Compilation &C, const ToolChain &TC, continue; } + if (YcArg) { + // Add a separate precompile phase for the compile phase. + if (FinalPhase >= phases::Compile) { + llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PCHPL; + types::getCompilationPhases(types::TY_CXXHeader, PCHPL); + Arg *PchInputArg = MakeInputArg(Args, Opts, YcArg->getValue()); + + // Build the pipeline for the pch file. + Action *ClangClPch = C.MakeAction<InputAction>(*PchInputArg, InputType); + for (phases::ID Phase : PCHPL) + ClangClPch = ConstructPhaseAction(C, Args, Phase, ClangClPch); + assert(ClangClPch); + Actions.push_back(ClangClPch); + // The driver currently exits after the first failed command. This + // relies on that behavior, to make sure if the pch generation fails, + // the main compilation won't run. + } + } + phases::ID CudaInjectionPhase = (phases::Compile < FinalPhase && llvm::find(PL, phases::Compile) != PL.end()) ? phases::Compile : FinalPhase; + // Track the host offload kinds used on this input. + unsigned InputActiveOffloadHostKinds = 0u; + // Build the pipeline for this file. Action *Current = C.MakeAction<InputAction>(*InputArg, InputType); for (SmallVectorImpl<phases::ID>::iterator i = PL.begin(), e = PL.end(); @@ -1497,27 +1720,42 @@ void Driver::BuildActions(Compilation &C, const ToolChain &TC, continue; // Otherwise construct the appropriate action. - Current = ConstructPhaseAction(C, TC, Args, Phase, Current); + Current = ConstructPhaseAction(C, Args, Phase, Current); if (InputType == types::TY_CUDA && Phase == CudaInjectionPhase) { Current = buildCudaActions(C, Args, InputArg, Current, Actions); if (!Current) break; + + // We produced a CUDA action for this input, so the host has to support + // CUDA. + InputActiveOffloadHostKinds |= Action::OFK_Cuda; + CompilationActiveOffloadHostKinds |= Action::OFK_Cuda; } if (Current->getType() == types::TY_Nothing) break; } - // If we ended with something, add to the output list. - if (Current) + // If we ended with something, add to the output list. Also, propagate the + // offload information to the top-level host action related with the current + // input. + if (Current) { + if (InputActiveOffloadHostKinds) + Current->propagateHostOffloadInfo(InputActiveOffloadHostKinds, + /*BoundArch=*/nullptr); Actions.push_back(Current); + } } - // Add a link action if necessary. - if (!LinkerInputs.empty()) + // Add a link action if necessary and propagate the offload information for + // the current compilation. + if (!LinkerInputs.empty()) { Actions.push_back( C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image)); + Actions.back()->propagateHostOffloadInfo(CompilationActiveOffloadHostKinds, + /*BoundArch=*/nullptr); + } // If we are linking, claim any options which are obviously only used for // compilation. @@ -1529,14 +1767,14 @@ void Driver::BuildActions(Compilation &C, const ToolChain &TC, // Claim ignored clang-cl options. Args.ClaimAllArgs(options::OPT_cl_ignored_Group); - // Claim --cuda-host-only arg which may be passed to non-CUDA - // compilations and should not trigger warnings there. + // Claim --cuda-host-only and --cuda-compile-host-device, which may be passed + // to non-CUDA compilations and should not trigger warnings there. Args.ClaimAllArgs(options::OPT_cuda_host_only); + Args.ClaimAllArgs(options::OPT_cuda_compile_host_device); } -Action *Driver::ConstructPhaseAction(Compilation &C, const ToolChain &TC, - const ArgList &Args, phases::ID Phase, - Action *Input) const { +Action *Driver::ConstructPhaseAction(Compilation &C, const ArgList &Args, + phases::ID Phase, Action *Input) const { llvm::PrettyStackTraceString CrashInfo("Constructing phase actions"); // Build the appropriate action. switch (Phase) { @@ -1600,7 +1838,7 @@ Action *Driver::ConstructPhaseAction(Compilation &C, const ToolChain &TC, return C.MakeAction<BackendJobAction>(Input, types::TY_PP_Asm); } case phases::Assemble: - return C.MakeAction<AssembleJobAction>(Input, types::TY_Object); + return C.MakeAction<AssembleJobAction>(std::move(Input), types::TY_Object); } llvm_unreachable("invalid phase in ConstructPhaseAction"); @@ -1632,6 +1870,8 @@ void Driver::BuildJobs(Compilation &C) const { if (A->getOption().matches(options::OPT_arch)) ArchNames.insert(A->getValue()); + // Set of (Action, canonical ToolChain triple) pairs we've built jobs for. + std::map<std::pair<const Action *, std::string>, InputInfo> CachedResults; for (Action *A : C.getActions()) { // If we are linking an image for multiple archs then the linker wants // -arch_multiple and -final_output <final image name>. Unfortunately, this @@ -1651,7 +1891,8 @@ void Driver::BuildJobs(Compilation &C) const { /*BoundArch*/ nullptr, /*AtTopLevel*/ true, /*MultipleArchs*/ ArchNames.size() > 1, - /*LinkingOutput*/ LinkingOutput); + /*LinkingOutput*/ LinkingOutput, CachedResults, + /*BuildForOffloadDevice*/ false); } // If the user passed -Qunused-arguments or there were errors, don't warn @@ -1663,8 +1904,9 @@ void Driver::BuildJobs(Compilation &C) const { // Claim -### here. (void)C.getArgs().hasArg(options::OPT__HASH_HASH_HASH); - // Claim --driver-mode, it was handled earlier. + // Claim --driver-mode, --rsp-quoting, it was handled earlier. (void)C.getArgs().hasArg(options::OPT_driver_mode); + (void)C.getArgs().hasArg(options::OPT_rsp_quoting); for (Arg *A : C.getArgs()) { // FIXME: It would be nice to be able to send the argument to the @@ -1691,74 +1933,123 @@ void Driver::BuildJobs(Compilation &C) const { continue; } - Diag(clang::diag::warn_drv_unused_argument) - << A->getAsString(C.getArgs()); + // In clang-cl, don't mention unknown arguments here since they have + // already been warned about. + if (!IsCLMode() || !A->getOption().matches(options::OPT_UNKNOWN)) + Diag(clang::diag::warn_drv_unused_argument) + << A->getAsString(C.getArgs()); } } } - +/// Collapse an offloading action looking for a job of the given type. The input +/// action is changed to the input of the collapsed sequence. If we effectively +/// had a collapse return the corresponding offloading action, otherwise return +/// null. +template <typename T> +static OffloadAction *collapseOffloadingAction(Action *&CurAction) { + if (!CurAction) + return nullptr; + if (auto *OA = dyn_cast<OffloadAction>(CurAction)) { + if (OA->hasHostDependence()) + if (auto *HDep = dyn_cast<T>(OA->getHostDependence())) { + CurAction = HDep; + return OA; + } + if (OA->hasSingleDeviceDependence()) + if (auto *DDep = dyn_cast<T>(OA->getSingleDeviceDependence())) { + CurAction = DDep; + return OA; + } + } + return nullptr; +} // Returns a Tool for a given JobAction. In case the action and its // predecessors can be combined, updates Inputs with the inputs of the // first combined action. If one of the collapsed actions is a // CudaHostAction, updates CollapsedCHA with the pointer to it so the // caller can deal with extra handling such action requires. static const Tool *selectToolForJob(Compilation &C, bool SaveTemps, - const ToolChain *TC, const JobAction *JA, + bool EmbedBitcode, const ToolChain *TC, + const JobAction *JA, const ActionList *&Inputs, - const CudaHostAction *&CollapsedCHA) { + ActionList &CollapsedOffloadAction) { const Tool *ToolForJob = nullptr; - CollapsedCHA = nullptr; + CollapsedOffloadAction.clear(); // See if we should look for a compiler with an integrated assembler. We match // bottom up, so what we are actually looking for is an assembler job with a // compiler input. + // Look through offload actions between assembler and backend actions. + Action *BackendJA = (isa<AssembleJobAction>(JA) && Inputs->size() == 1) + ? *Inputs->begin() + : nullptr; + auto *BackendOA = collapseOffloadingAction<BackendJobAction>(BackendJA); + if (TC->useIntegratedAs() && !SaveTemps && !C.getArgs().hasArg(options::OPT_via_file_asm) && !C.getArgs().hasArg(options::OPT__SLASH_FA) && - !C.getArgs().hasArg(options::OPT__SLASH_Fa) && - isa<AssembleJobAction>(JA) && Inputs->size() == 1 && - isa<BackendJobAction>(*Inputs->begin())) { - // A BackendJob is always preceded by a CompileJob, and without - // -save-temps they will always get combined together, so instead of - // checking the backend tool, check if the tool for the CompileJob - // has an integrated assembler. - const ActionList *BackendInputs = &(*Inputs)[0]->getInputs(); - // Compile job may be wrapped in CudaHostAction, extract it if - // that's the case and update CollapsedCHA if we combine phases. - CudaHostAction *CHA = dyn_cast<CudaHostAction>(*BackendInputs->begin()); - JobAction *CompileJA = - cast<CompileJobAction>(CHA ? *CHA->begin() : *BackendInputs->begin()); - assert(CompileJA && "Backend job is not preceeded by compile job."); - const Tool *Compiler = TC->SelectTool(*CompileJA); + !C.getArgs().hasArg(options::OPT__SLASH_Fa) && BackendJA && + isa<BackendJobAction>(BackendJA)) { + // A BackendJob is always preceded by a CompileJob, and without -save-temps + // or -fembed-bitcode, they will always get combined together, so instead of + // checking the backend tool, check if the tool for the CompileJob has an + // integrated assembler. For -fembed-bitcode, CompileJob is still used to + // look up tools for BackendJob, but they need to match before we can split + // them. + + // Look through offload actions between backend and compile actions. + Action *CompileJA = *BackendJA->getInputs().begin(); + auto *CompileOA = collapseOffloadingAction<CompileJobAction>(CompileJA); + + assert(CompileJA && isa<CompileJobAction>(CompileJA) && + "Backend job is not preceeded by compile job."); + const Tool *Compiler = TC->SelectTool(*cast<CompileJobAction>(CompileJA)); if (!Compiler) return nullptr; + // When using -fembed-bitcode, it is required to have the same tool (clang) + // for both CompilerJA and BackendJA. Otherwise, combine two stages. + if (EmbedBitcode) { + JobAction *InputJA = cast<JobAction>(*Inputs->begin()); + const Tool *BackendTool = TC->SelectTool(*InputJA); + if (BackendTool == Compiler) + CompileJA = InputJA; + } if (Compiler->hasIntegratedAssembler()) { Inputs = &CompileJA->getInputs(); ToolForJob = Compiler; - CollapsedCHA = CHA; + // Save the collapsed offload actions because they may still contain + // device actions. + if (CompileOA) + CollapsedOffloadAction.push_back(CompileOA); + if (BackendOA) + CollapsedOffloadAction.push_back(BackendOA); } } // A backend job should always be combined with the preceding compile job - // unless OPT_save_temps is enabled and the compiler is capable of emitting - // LLVM IR as an intermediate output. + // unless OPT_save_temps or OPT_fembed_bitcode is enabled and the compiler is + // capable of emitting LLVM IR as an intermediate output. if (isa<BackendJobAction>(JA)) { // Check if the compiler supports emitting LLVM IR. assert(Inputs->size() == 1); - // Compile job may be wrapped in CudaHostAction, extract it if - // that's the case and update CollapsedCHA if we combine phases. - CudaHostAction *CHA = dyn_cast<CudaHostAction>(*Inputs->begin()); - JobAction *CompileJA = - cast<CompileJobAction>(CHA ? *CHA->begin() : *Inputs->begin()); - assert(CompileJA && "Backend job is not preceeded by compile job."); - const Tool *Compiler = TC->SelectTool(*CompileJA); + + // Look through offload actions between backend and compile actions. + Action *CompileJA = *JA->getInputs().begin(); + auto *CompileOA = collapseOffloadingAction<CompileJobAction>(CompileJA); + + assert(CompileJA && isa<CompileJobAction>(CompileJA) && + "Backend job is not preceeded by compile job."); + const Tool *Compiler = TC->SelectTool(*cast<CompileJobAction>(CompileJA)); if (!Compiler) return nullptr; - if (!Compiler->canEmitIR() || !SaveTemps) { + if (!Compiler->canEmitIR() || + (!SaveTemps && !EmbedBitcode)) { Inputs = &CompileJA->getInputs(); ToolForJob = Compiler; - CollapsedCHA = CHA; + + if (CompileOA) + CollapsedOffloadAction.push_back(CompileOA); } } @@ -1769,33 +2060,112 @@ static const Tool *selectToolForJob(Compilation &C, bool SaveTemps, // See if we should use an integrated preprocessor. We do so when we have // exactly one input, since this is the only use case we care about // (irrelevant since we don't support combine yet). - if (Inputs->size() == 1 && isa<PreprocessJobAction>(*Inputs->begin()) && + + // Look through offload actions after preprocessing. + Action *PreprocessJA = (Inputs->size() == 1) ? *Inputs->begin() : nullptr; + auto *PreprocessOA = + collapseOffloadingAction<PreprocessJobAction>(PreprocessJA); + + if (PreprocessJA && isa<PreprocessJobAction>(PreprocessJA) && !C.getArgs().hasArg(options::OPT_no_integrated_cpp) && !C.getArgs().hasArg(options::OPT_traditional_cpp) && !SaveTemps && !C.getArgs().hasArg(options::OPT_rewrite_objc) && - ToolForJob->hasIntegratedCPP()) - Inputs = &(*Inputs)[0]->getInputs(); + ToolForJob->hasIntegratedCPP()) { + Inputs = &PreprocessJA->getInputs(); + if (PreprocessOA) + CollapsedOffloadAction.push_back(PreprocessOA); + } return ToolForJob; } -InputInfo Driver::BuildJobsForAction(Compilation &C, const Action *A, - const ToolChain *TC, const char *BoundArch, - bool AtTopLevel, bool MultipleArchs, - const char *LinkingOutput) const { +InputInfo Driver::BuildJobsForAction( + Compilation &C, const Action *A, const ToolChain *TC, const char *BoundArch, + bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput, + std::map<std::pair<const Action *, std::string>, InputInfo> &CachedResults, + bool BuildForOffloadDevice) const { + // The bound arch is not necessarily represented in the toolchain's triple -- + // for example, armv7 and armv7s both map to the same triple -- so we need + // both in our map. + std::string TriplePlusArch = TC->getTriple().normalize(); + if (BoundArch) { + TriplePlusArch += "-"; + TriplePlusArch += BoundArch; + } + std::pair<const Action *, std::string> ActionTC = {A, TriplePlusArch}; + auto CachedResult = CachedResults.find(ActionTC); + if (CachedResult != CachedResults.end()) { + return CachedResult->second; + } + InputInfo Result = BuildJobsForActionNoCache( + C, A, TC, BoundArch, AtTopLevel, MultipleArchs, LinkingOutput, + CachedResults, BuildForOffloadDevice); + CachedResults[ActionTC] = Result; + return Result; +} + +InputInfo Driver::BuildJobsForActionNoCache( + Compilation &C, const Action *A, const ToolChain *TC, const char *BoundArch, + bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput, + std::map<std::pair<const Action *, std::string>, InputInfo> &CachedResults, + bool BuildForOffloadDevice) const { llvm::PrettyStackTraceString CrashInfo("Building compilation jobs"); - InputInfoList CudaDeviceInputInfos; - if (const CudaHostAction *CHA = dyn_cast<CudaHostAction>(A)) { - // Append outputs of device jobs to the input list. - for (const Action *DA : CHA->getDeviceActions()) { - CudaDeviceInputInfos.push_back( - BuildJobsForAction(C, DA, TC, nullptr, AtTopLevel, - /*MultipleArchs*/ false, LinkingOutput)); + InputInfoList OffloadDependencesInputInfo; + if (const OffloadAction *OA = dyn_cast<OffloadAction>(A)) { + // The offload action is expected to be used in four different situations. + // + // a) Set a toolchain/architecture/kind for a host action: + // Host Action 1 -> OffloadAction -> Host Action 2 + // + // b) Set a toolchain/architecture/kind for a device action; + // Device Action 1 -> OffloadAction -> Device Action 2 + // + // c) Specify a device dependences to a host action; + // Device Action 1 _ + // \ + // Host Action 1 ---> OffloadAction -> Host Action 2 + // + // d) Specify a host dependence to a device action. + // Host Action 1 _ + // \ + // Device Action 1 ---> OffloadAction -> Device Action 2 + // + // For a) and b), we just return the job generated for the dependence. 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()) { + InputInfo DevA; + OA->doOnEachDeviceDependence([&](Action *DepA, const ToolChain *DepTC, + const char *DepBoundArch) { + DevA = + BuildJobsForAction(C, DepA, DepTC, DepBoundArch, AtTopLevel, + /*MultipleArchs*/ !!DepBoundArch, LinkingOutput, + CachedResults, /*BuildForOffloadDevice=*/true); + }); + return DevA; } - // Override current action with a real host compile action and continue - // processing it. - A = *CHA->begin(); + + // If 'Action 2' is host, we generate jobs for the device dependences and + // override the current action with the host dependence. Otherwise, we + // generate the host dependences and override the action with the device + // dependence. The dependences can't therefore be a top-level action. + OA->doOnEachDependence( + /*IsHostDependence=*/BuildForOffloadDevice, + [&](Action *DepA, const ToolChain *DepTC, const char *DepBoundArch) { + OffloadDependencesInputInfo.push_back(BuildJobsForAction( + C, DepA, DepTC, DepBoundArch, /*AtTopLevel=*/false, + /*MultipleArchs*/ !!DepBoundArch, LinkingOutput, CachedResults, + /*BuildForOffloadDevice=*/DepA->getOffloadingDeviceKind() != + Action::OFK_None)); + }); + + A = BuildForOffloadDevice + ? OA->getSingleDeviceDependence(/*DoNotConsiderHostActions=*/true) + : OA->getHostDependence(); } if (const InputAction *IA = dyn_cast<InputAction>(A)) { @@ -1815,43 +2185,41 @@ InputInfo Driver::BuildJobsForAction(Compilation &C, const Action *A, const char *ArchName = BAA->getArchName(); if (ArchName) - TC = &getToolChain( - C.getArgs(), - computeTargetTriple(DefaultTargetTriple, C.getArgs(), ArchName)); + TC = &getToolChain(C.getArgs(), + computeTargetTriple(*this, DefaultTargetTriple, + C.getArgs(), ArchName)); else TC = &C.getDefaultToolChain(); - return BuildJobsForAction(C, *BAA->begin(), TC, ArchName, AtTopLevel, - MultipleArchs, LinkingOutput); + return BuildJobsForAction(C, *BAA->input_begin(), TC, ArchName, AtTopLevel, + MultipleArchs, LinkingOutput, CachedResults, + BuildForOffloadDevice); } - if (const CudaDeviceAction *CDA = dyn_cast<CudaDeviceAction>(A)) { - // Initial processing of CudaDeviceAction carries host params. - // Call BuildJobsForAction() again, now with correct device parameters. - assert(CDA->getGpuArchName() && "No GPU name in device action."); - return BuildJobsForAction(C, *CDA->begin(), C.getCudaDeviceToolChain(), - CDA->getGpuArchName(), CDA->isAtTopLevel(), - /*MultipleArchs*/ true, LinkingOutput); - } const ActionList *Inputs = &A->getInputs(); const JobAction *JA = cast<JobAction>(A); - const CudaHostAction *CollapsedCHA = nullptr; + ActionList CollapsedOffloadActions; + const Tool *T = - selectToolForJob(C, isSaveTempsEnabled(), TC, JA, Inputs, CollapsedCHA); + selectToolForJob(C, isSaveTempsEnabled(), embedBitcodeEnabled(), TC, JA, + Inputs, CollapsedOffloadActions); if (!T) return InputInfo(); - // If we've collapsed action list that contained CudaHostAction we - // need to build jobs for device-side inputs it may have held. - if (CollapsedCHA) { - for (const Action *DA : CollapsedCHA->getDeviceActions()) { - CudaDeviceInputInfos.push_back( - BuildJobsForAction(C, DA, TC, "", AtTopLevel, - /*MultipleArchs*/ false, LinkingOutput)); - } - } + // 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) + cast<OffloadAction>(OA)->doOnEachDependence( + /*IsHostDependence=*/BuildForOffloadDevice, + [&](Action *DepA, const ToolChain *DepTC, const char *DepBoundArch) { + OffloadDependencesInputInfo.push_back(BuildJobsForAction( + C, DepA, DepTC, DepBoundArch, AtTopLevel, + /*MultipleArchs=*/!!DepBoundArch, LinkingOutput, CachedResults, + /*BuildForOffloadDevice=*/DepA->getOffloadingDeviceKind() != + Action::OFK_None)); + }); // Only use pipes when there is exactly one input. InputInfoList InputInfos; @@ -1861,9 +2229,9 @@ InputInfo Driver::BuildJobsForAction(Compilation &C, const Action *A, // FIXME: Clean this up. bool SubJobAtTopLevel = AtTopLevel && (isa<DsymutilJobAction>(A) || isa<VerifyJobAction>(A)); - InputInfos.push_back(BuildJobsForAction(C, Input, TC, BoundArch, - SubJobAtTopLevel, MultipleArchs, - LinkingOutput)); + InputInfos.push_back(BuildJobsForAction( + C, Input, TC, BoundArch, SubJobAtTopLevel, MultipleArchs, LinkingOutput, + CachedResults, BuildForOffloadDevice)); } // Always use the first input as the base input. @@ -1874,9 +2242,10 @@ InputInfo Driver::BuildJobsForAction(Compilation &C, const Action *A, if (JA->getType() == types::TY_dSYM) BaseInput = InputInfos[0].getFilename(); - // Append outputs of cuda device jobs to the input list - if (CudaDeviceInputInfos.size()) - InputInfos.append(CudaDeviceInputInfos.begin(), CudaDeviceInputInfos.end()); + // Append outputs of offload device jobs to the input list + if (!OffloadDependencesInputInfo.empty()) + InputInfos.append(OffloadDependencesInputInfo.begin(), + OffloadDependencesInputInfo.end()); // Determine the place to write output to, if any. InputInfo Result; @@ -1884,7 +2253,8 @@ InputInfo Driver::BuildJobsForAction(Compilation &C, const Action *A, Result = InputInfo(A, BaseInput); else Result = InputInfo(A, GetNamedOutputPath(C, *JA, BaseInput, BoundArch, - AtTopLevel, MultipleArchs), + AtTopLevel, MultipleArchs, + TC->getTriple().normalize()), BaseInput); if (CCCPrintBindings && !CCGenDiagnostics) { @@ -1944,7 +2314,8 @@ static const char *MakeCLOutputFilename(const ArgList &Args, StringRef ArgValue, const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, const char *BaseInput, const char *BoundArch, bool AtTopLevel, - bool MultipleArchs) const { + bool MultipleArchs, + StringRef NormalizedTriple) const { llvm::PrettyStackTraceString CrashInfo("Computing output path"); // Output to a user requested destination? if (AtTopLevel && !isa<DsymutilJobAction>(JA) && !isa<VerifyJobAction>(JA)) { @@ -2030,11 +2401,15 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, MakeCLOutputFilename(C.getArgs(), "", BaseName, types::TY_Image); } else if (MultipleArchs && BoundArch) { SmallString<128> Output(getDefaultImageName()); + Output += JA.getOffloadingFileNamePrefix(NormalizedTriple); Output += "-"; Output.append(BoundArch); NamedOutput = C.getArgs().MakeArgString(Output.c_str()); - } else + } else { NamedOutput = getDefaultImageName(); + } + } else if (JA.getType() == types::TY_PCH && IsCLMode()) { + NamedOutput = C.getArgs().MakeArgString(GetClPchPath(C, BaseName).c_str()); } else { const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode()); assert(Suffix && "All types used for output should have a suffix."); @@ -2043,6 +2418,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, if (!types::appendSuffixForType(JA.getType())) End = BaseName.rfind('.'); SmallString<128> Suffixed(BaseName.substr(0, End)); + Suffixed += JA.getOffloadingFileNamePrefix(NormalizedTriple); if (MultipleArchs && BoundArch) { Suffixed += "-"; Suffixed.append(BoundArch); @@ -2088,7 +2464,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, } // As an annoying special case, PCH generation doesn't strip the pathname. - if (JA.getType() == types::TY_PCH) { + if (JA.getType() == types::TY_PCH && !IsCLMode()) { llvm::sys::path::remove_filename(BasePath); if (BasePath.empty()) BasePath = NamedOutput; @@ -2200,12 +2576,34 @@ std::string Driver::GetTemporaryPath(StringRef Prefix, 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)) { + // FIXME: If anybody needs it, implement this obscure rule: + // "If you specify a directory without a file name, the default file name + // is VCx0.pch., where x is the major version of Visual C++ in use." + Output = FpArg->getValue(); + + // "If you do not specify an extension as part of the path name, an + // extension of .pch is assumed. " + if (!llvm::sys::path::has_extension(Output)) + Output += ".pch"; + } else { + Output = BaseName; + llvm::sys::path::replace_extension(Output, ".pch"); + } + return Output.str(); +} + const ToolChain &Driver::getToolChain(const ArgList &Args, const llvm::Triple &Target) const { ToolChain *&TC = ToolChains[Target.str()]; if (!TC) { switch (Target.getOS()) { + case llvm::Triple::Haiku: + TC = new toolchains::Haiku(*this, Target, Args); + break; case llvm::Triple::CloudABI: TC = new toolchains::CloudABI(*this, Target, Args); break; @@ -2235,6 +2633,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, TC = new toolchains::Minix(*this, Target, Args); break; case llvm::Triple::Linux: + case llvm::Triple::ELFIAMCU: if (Target.getArch() == llvm::Triple::hexagon) TC = new toolchains::HexagonToolChain(*this, Target, Args); else if ((Target.getVendor() == llvm::Triple::MipsTechnologies) && @@ -2290,6 +2689,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::hexagon: TC = new toolchains::HexagonToolChain(*this, Target, Args); break; + case llvm::Triple::lanai: + TC = new toolchains::LanaiToolChain(*this, Target, Args); + break; case llvm::Triple::xcore: TC = new toolchains::XCoreToolChain(*this, Target, Args); break; @@ -2314,7 +2716,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, bool Driver::ShouldUseClangCompiler(const JobAction &JA) const { // Say "no" if there is not exactly one input of a type clang understands. - if (JA.size() != 1 || !types::isAcceptedByClang((*JA.begin())->getType())) + if (JA.size() != 1 || + !types::isAcceptedByClang((*JA.input_begin())->getType())) return false; // And say "no" if this is not a kind of action clang understands. @@ -2363,6 +2766,34 @@ bool Driver::GetReleaseVersion(const char *Str, unsigned &Major, return true; } +/// Parse digits from a string \p Str and fulfill \p Digits with +/// the parsed numbers. This method assumes that the max number of +/// digits to look for is equal to Digits.size(). +/// +/// \return True if the entire string was parsed and there are +/// no extra characters remaining at the end. +bool Driver::GetReleaseVersion(const char *Str, + MutableArrayRef<unsigned> Digits) { + if (*Str == '\0') + return false; + + char *End; + unsigned CurDigit = 0; + while (CurDigit < Digits.size()) { + unsigned Digit = (unsigned)strtol(Str, &End, 10); + Digits[CurDigit] = Digit; + if (*Str != '\0' && *End == '\0') + return true; + if (*End != '.' || Str == End) + return false; + Str = End + 1; + CurDigit++; + } + + // More digits than requested, bail out... + return false; +} + std::pair<unsigned, unsigned> Driver::getIncludeExcludeOptionFlagMasks() const { unsigned IncludedFlagsBitmask = 0; unsigned ExcludedFlagsBitmask = options::NoDriverOption; |