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

Reply via email to