sfantao created this revision. sfantao added reviewers: ABataev, jlebar, tra, echristo, hfinkel. sfantao added subscribers: caomhin, carlo.bertolli, arpith-jacob, cfe-commits.
This patch introduces the concept of offloading tool chain and offloading kind. Each tool chain may have associated an offloading kind that marks it as used in a given programming model that requires offloading. It also adds the logic to iterate on the tool chains based on the kind. Currently, only CUDA is supported, but in general a programming model (an offloading kind) may have associated multiple tool chains that require supporting offloading. This patch does not add tests - its goal is to keep the existing functionality. This patch is the first of a series of three that attempts to make the current support of CUDA more generic and easier to extend to other programming models, namely OpenMP. It tries to capture the suggestions/improvements/concerns on the initial proposal in http://lists.llvm.org/pipermail/cfe-dev/2016-February/047547.html. It only tackles the more consensual part of the proposal, i.e.does not address the problem of intermediate files bundling yet. http://reviews.llvm.org/D18170 Files: include/clang/Driver/Action.h include/clang/Driver/Compilation.h include/clang/Driver/Driver.h lib/Driver/Compilation.cpp lib/Driver/Driver.cpp lib/Driver/Tools.cpp
Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -3583,10 +3583,11 @@ // particular compilation pass we're constructing here. For now we // can check which toolchain we're using and pick the other one to // extract the triple. - if (&getToolChain() == C.getCudaDeviceToolChain()) - AuxToolChain = C.getCudaHostToolChain(); - else if (&getToolChain() == C.getCudaHostToolChain()) - AuxToolChain = C.getCudaDeviceToolChain(); + if (&getToolChain() == + C.getSingleOffloadDeviceToolChain<Action::OFFLOAD_CUDA>()) + AuxToolChain = C.getOffloadingHostToolChain(); + else if (&getToolChain() == C.getOffloadingHostToolChain()) + AuxToolChain = C.getSingleOffloadDeviceToolChain<Action::OFFLOAD_CUDA>(); else llvm_unreachable("Can't figure out CUDA compilation mode."); assert(AuxToolChain != nullptr && "No aux toolchain."); Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -396,6 +396,32 @@ } } +void Driver::CreateOffloadingDeviceToolChains(Compilation &C, + InputList &Inputs) { + + // + // CUDA + // + // We need to generate a CUDA toolchain if any of the inputs has a CUDA type. + for (auto &I : Inputs) + // Have we founs a CUDA file? If so generate the toolchain. + if (types::isCuda(I.first)) { + const ToolChain &TC = getToolChain( + C.getInputArgs(), + llvm::Triple(C.getOffloadingHostToolChain()->getTriple().isArch64Bit() + ? "nvptx64-nvidia-cuda" + : "nvptx-nvidia-cuda")); + C.addOffloadDeviceToolChain(&TC, Action::OFFLOAD_CUDA); + break; + } + + // + // Add support for other offloading programming models here. + // + + return; +} + Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { llvm::PrettyStackTraceString CrashInfo("Compilation construction"); @@ -507,17 +533,16 @@ // 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; // Construct the list of inputs. InputList Inputs; BuildInputs(C->getDefaultToolChain(), *TranslatedArgs, Inputs); + // Get the toolchains 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()) @@ -1331,7 +1356,7 @@ CudaDeviceInputs.push_back(std::make_pair(types::TY_CUDA_DEVICE, InputArg)); // Build actions for all device inputs. - assert(C.getCudaDeviceToolChain() && + assert(C.getSingleOffloadDeviceToolChain<Action::OFFLOAD_CUDA>() && "Missing toolchain for device-side compilation."); ActionList CudaDeviceActions; C.getDriver().BuildActions(C, Args, CudaDeviceInputs, CudaDeviceActions); @@ -1971,7 +1996,8 @@ // Initial processing of CudaDeviceAction carries host params. // Call BuildJobsForAction() again, now with correct device parameters. InputInfo II = BuildJobsForAction( - C, *CDA->input_begin(), C.getCudaDeviceToolChain(), + C, *CDA->input_begin(), + C.getSingleOffloadDeviceToolChain<Action::OFFLOAD_CUDA>(), CDA->getGpuArchName(), CDA->isAtTopLevel(), /*MultipleArchs=*/true, LinkingOutput, CachedResults); // Currently II's Action is *CDA->input_begin(). Set it to CDA instead, so Index: lib/Driver/Compilation.cpp =================================================================== --- lib/Driver/Compilation.cpp +++ lib/Driver/Compilation.cpp @@ -25,7 +25,7 @@ Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain, InputArgList *_Args, DerivedArgList *_TranslatedArgs) : TheDriver(D), DefaultToolChain(_DefaultToolChain), - CudaHostToolChain(&DefaultToolChain), CudaDeviceToolChain(nullptr), + OffloadHostToolChain(&DefaultToolChain), OffloadHostKinds(0u), Args(_Args), TranslatedArgs(_TranslatedArgs), Redirects(nullptr), ForDiagnostics(false) {} Index: include/clang/Driver/Driver.h =================================================================== --- include/clang/Driver/Driver.h +++ include/clang/Driver/Driver.h @@ -275,6 +275,11 @@ /// @name Primary Functionality /// @{ + /// CreateOffloadingDeviceToolChains - create all the toolchains required to + /// support offloading devices given the programming models specified in the + /// current compilation. Also, update the host tool chain kind accordingly. + void CreateOffloadingDeviceToolChains(Compilation &C, InputList &Inputs); + /// BuildCompilation - Construct a compilation object for a command /// line argument vector. /// Index: include/clang/Driver/Compilation.h =================================================================== --- include/clang/Driver/Compilation.h +++ include/clang/Driver/Compilation.h @@ -38,8 +38,17 @@ /// The default tool chain. const ToolChain &DefaultToolChain; - const ToolChain *CudaHostToolChain; - const ToolChain *CudaDeviceToolChain; + /// The tool chain of the offload host. + const ToolChain *OffloadHostToolChain; + + /// The host offload kinds, it will be a mask of all the programming models + /// the host has to support. + unsigned OffloadHostKinds; + + /// Array with the toolchains of offloading devices in the order they were + /// requested by the user. + typedef std::pair<const ToolChain *, Action::OffloadKind> OffloadToolChainTy; + SmallVector<OffloadToolChainTy, 4> OrderedOffloadingToolchains; /// The original (untranslated) input argument list. llvm::opt::InputArgList *Args; @@ -89,16 +98,73 @@ const Driver &getDriver() const { return TheDriver; } const ToolChain &getDefaultToolChain() const { return DefaultToolChain; } - const ToolChain *getCudaHostToolChain() const { return CudaHostToolChain; } - const ToolChain *getCudaDeviceToolChain() const { - return CudaDeviceToolChain; + const ToolChain *getOffloadingHostToolChain() const { + return OffloadHostToolChain; + } + unsigned isOffloadingHostKind(Action::OffloadKind Kind) const { + return OffloadHostKinds & Kind; } - void setCudaHostToolChain(const ToolChain *HostToolChain) { - CudaHostToolChain = HostToolChain; + /// Iterator that visits device toolchains of a given kind. + template <Action::OffloadKind Kind> + class specific_offload_kind_iterator + : public llvm::iterator_adaptor_base< + specific_offload_kind_iterator<Kind>, + ArrayRef<OffloadToolChainTy>::const_iterator, + std::forward_iterator_tag, OffloadToolChainTy, ptrdiff_t, + OffloadToolChainTy, OffloadToolChainTy> { + ArrayRef<OffloadToolChainTy>::const_iterator End; + + void SkipKinds() { + while (this->I != End && this->I->second != Kind) + ++this->I; + } + + public: + explicit specific_offload_kind_iterator(ArrayRef<OffloadToolChainTy> TCs) + : specific_offload_kind_iterator::iterator_adaptor_base(TCs.begin()), + End(TCs.end()) { + SkipKinds(); + } + + const ToolChain *operator*() const { return this->I->first; } + const ToolChain *operator->() const { return **this; } + + specific_offload_kind_iterator &operator++() { + ++this->I; + SkipKinds(); + return *this; + } + }; + + template <Action::OffloadKind Kind> + llvm::iterator_range<specific_offload_kind_iterator<Kind>> + getOffloadDeviceToolChains() const { + return {specific_offload_kind_iterator<Kind>(OrderedOffloadingToolchains), + specific_offload_kind_iterator<Kind>( + llvm::makeArrayRef(OrderedOffloadingToolchains.end(), 0))}; } - void setCudaDeviceToolChain(const ToolChain *DeviceToolChain) { - CudaDeviceToolChain = DeviceToolChain; + + // Return an offload device toolchain of the provided kind. Only one is + // expected to exist. If we can't match any toolchain, return nullptr. + template <Action::OffloadKind Kind> + const ToolChain *getSingleOffloadDeviceToolChain() const { + auto TCs = getOffloadDeviceToolChains<Kind>(); + + if (TCs.begin() != TCs.end()) { + assert(std::next(TCs.begin()) == TCs.end() && + "More than one tool chain of the this kind exist."); + return *TCs.begin(); + } + return nullptr; + } + + void addOffloadDeviceToolChain(const ToolChain *DeviceToolChain, + Action::OffloadKind OffloadKind) { + // Update the host offload kind to also contain this kind. + OffloadHostKinds |= OffloadKind; + OrderedOffloadingToolchains.push_back( + std::make_pair(DeviceToolChain, OffloadKind)); } const llvm::opt::InputArgList &getInputArgs() const { return *Args; } Index: include/clang/Driver/Action.h =================================================================== --- include/clang/Driver/Action.h +++ include/clang/Driver/Action.h @@ -68,6 +68,17 @@ JobClassLast=VerifyPCHJobClass }; + // The offloading kind determines if this action is binded to a particular + // programming model. Each entry reserves one bit. + // + // FIXME: This is currently used to indicate that toolchains are used in a + // given programming as well, but will be used here as well once a generic + // offloading action is implemented. + enum OffloadKind { + OFFLOAD_None = 0x00, + OFFLOAD_CUDA = 0x01, + }; + static const char *getClassName(ActionClass AC); private:
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits