sfantao created this revision.
sfantao added reviewers: echristo, tra, jlebar, hfinkel, ABataev.
sfantao added subscribers: caomhin, carlo.bertolli, arpith-jacob, 
andreybokhanko, Hahnfeld, cfe-commits.
Herald added a subscriber: mehdi_amini.

In order to save the user from dealing with multiple output files (for host and 
device) while using separate compilation, a new action `OffloadBundlingAction` 
is used when the last phase is not linking. This action will then result in a 
job that uses the proposed bundling tool to create a single 
preprocessed/IR/ASM/Object file from multiple ones.

The job creation for the new action will be proposed in a separate patch.

http://reviews.llvm.org/D21852

Files:
  include/clang/Driver/Action.h
  lib/Driver/Action.cpp
  lib/Driver/Driver.cpp
  lib/Driver/ToolChain.cpp
  test/Driver/openmp-offload.c

Index: test/Driver/openmp-offload.c
===================================================================
--- test/Driver/openmp-offload.c
+++ test/Driver/openmp-offload.c
@@ -228,3 +228,31 @@
 // CHK-LKS:   }
 // CHK-LKS: }
 // CHK-LKS: INSERT BEFORE .data
+
+
+/// ###########################################################################
+
+/// Check separate compilation with offloading - bundling actions
+// RUN:   %clang -### -ccc-print-phases -fopenmp -c -o %t.o -lsomelib -target powerpc64le-linux -fopenmp-targets=powerpc64le-ibm-linux-gnu,x86_64-pc-linux-gnu %s 2>&1 \
+// RUN:   | FileCheck -check-prefix=CHK-BUACTIONS %s
+
+// CHK-BUACTIONS: 0: input, "[[INPUT:.+\.c]]", c, (host-openmp)
+// CHK-BUACTIONS: 1: preprocessor, {0}, cpp-output, (host-openmp)
+// CHK-BUACTIONS: 2: compiler, {1}, ir, (host-openmp)
+// CHK-BUACTIONS: 3: input, "[[INPUT]]", c, (device-openmp)
+// CHK-BUACTIONS: 4: preprocessor, {3}, cpp-output, (device-openmp)
+// CHK-BUACTIONS: 5: compiler, {4}, ir, (device-openmp)
+// CHK-BUACTIONS: 6: offload, "host-openmp (powerpc64le--linux)" {2}, "device-openmp (powerpc64le-ibm-linux-gnu)" {5}, ir
+// CHK-BUACTIONS: 7: backend, {6}, assembler, (device-openmp)
+// CHK-BUACTIONS: 8: assembler, {7}, object, (device-openmp)
+// CHK-BUACTIONS: 9: offload, "device-openmp (powerpc64le-ibm-linux-gnu)" {8}, object
+// CHK-BUACTIONS: 10: input, "[[INPUT]]", c, (device-openmp)
+// CHK-BUACTIONS: 11: preprocessor, {10}, cpp-output, (device-openmp)
+// CHK-BUACTIONS: 12: compiler, {11}, ir, (device-openmp)
+// CHK-BUACTIONS: 13: offload, "host-openmp (powerpc64le--linux)" {2}, "device-openmp (x86_64-pc-linux-gnu)" {12}, ir
+// CHK-BUACTIONS: 14: backend, {13}, assembler, (device-openmp)
+// CHK-BUACTIONS: 15: assembler, {14}, object, (device-openmp)
+// CHK-BUACTIONS: 16: offload, "device-openmp (x86_64-pc-linux-gnu)" {15}, object
+// CHK-BUACTIONS: 17: backend, {2}, assembler, (host-openmp)
+// CHK-BUACTIONS: 18: assembler, {17}, object, (host-openmp)
+// CHK-BUACTIONS: 19: clang-offload-bundler, {9, 16, 18}, object, (host-openmp)
\ No newline at end of file
Index: lib/Driver/ToolChain.cpp
===================================================================
--- lib/Driver/ToolChain.cpp
+++ lib/Driver/ToolChain.cpp
@@ -262,6 +262,10 @@
   case Action::VerifyPCHJobClass:
   case Action::BackendJobClass:
     return getClang();
+
+  case Action::OffloadBundlingJobClass:
+    // FIXME: Add a tool for the bundling actions.
+    return nullptr;
   }
 
   llvm_unreachable("Invalid tool kind.");
Index: lib/Driver/Driver.cpp
===================================================================
--- lib/Driver/Driver.cpp
+++ lib/Driver/Driver.cpp
@@ -1530,6 +1530,9 @@
     // are found.
     virtual bool initialize() { return false; }
 
+    // \brief Return true if the builder can use bundling/unbundling.
+    virtual bool canUseBundlerUnbundler() const { return false; }
+
     // \brief Return true if this builder is valid. We have a valid builder if
     // we have associated device tool chains.
     bool isValid() { return !ToolChains.empty(); }
@@ -1853,6 +1856,26 @@
       return ABRT_Success;
     }
 
+    void appendTopLevelActions(ActionList &AL) override {
+      if (OpenMPDeviceActions.empty())
+        return;
+
+      // We should always have an action for each input.
+      assert(OpenMPDeviceActions.size() == ToolChains.size() &&
+             "Number of OpenMP actions and toolchains do not match.");
+
+      // Append all device actions followed by the proper offload action.
+      auto TI = ToolChains.begin();
+      for (auto *A : OpenMPDeviceActions) {
+        OffloadAction::DeviceDependences Dep;
+        Dep.add(*A, **TI, /*BoundArch=*/nullptr, Action::OFK_OpenMP);
+        AL.push_back(C.MakeAction<OffloadAction>(Dep, A->getType()));
+        ++TI;
+      }
+      // We no longer need the action stored in this builder.
+      OpenMPDeviceActions.clear();
+    }
+
     void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {
       assert(ToolChains.size() == DeviceLinkerInputs.size() &&
              "Toolchains and linker inputs sizes do not match.");
@@ -1879,6 +1902,11 @@
       DeviceLinkerInputs.resize(ToolChains.size());
       return false;
     }
+
+    bool canUseBundlerUnbundler() const override {
+      // OpenMP should use bundled files whenever possible.
+      return true;
+    }
   };
 
   ///
@@ -1888,6 +1916,10 @@
   /// \brief Specialized builders being used by this offloading action builder.
   SmallVector<DeviceActionBuilder *, 4> SpecializedBuilders;
 
+  /// \brief Flag set to true if all valid builders allow file
+  /// bundling/unbundling.
+  bool CanUseBundler;
+
 public:
   OffloadingActionBuilder(Compilation &C, DerivedArgList &Args,
                           const Driver::InputList &Inputs)
@@ -1906,9 +1938,22 @@
     // TODO: Build other specialized builders here.
     //
 
-    // Initialize all the builders, keeping track of errors.
-    for (auto *SB : SpecializedBuilders)
+    // Initialize all the builders, keeping track of errors. If all valid
+    // builders agree that we can use bundling, set the flag to true.
+    unsigned ValidBuilders = 0u;
+    unsigned ValidBuildersSupportingBundling = 0u;
+    for (auto *SB : SpecializedBuilders) {
       IsValid = IsValid && !SB->initialize();
+
+      // Update the counters if the builder is valid.
+      if (SB->isValid()) {
+        ++ValidBuilders;
+        if (SB->canUseBundlerUnbundler())
+          ++ValidBuildersSupportingBundling;
+      }
+    }
+    CanUseBundler =
+        ValidBuilders && ValidBuilders == ValidBuildersSupportingBundling;
   }
 
   ~OffloadingActionBuilder() {
@@ -2008,27 +2053,41 @@
   }
 
   /// \brief Add the offloading top level actions to the provided action list.
+  /// This function can replace the host action by a bundling action if the
+  /// programming models allow it.
   bool appendTopLevelActions(ActionList &AL, Action *HostAction,
                              const Arg *InputArg) {
-    auto NumActions = AL.size();
-
+    // Get the device actions to be appended.
+    ActionList OffloadAL;
     for (auto *SB : SpecializedBuilders) {
       if (!SB->isValid())
         continue;
-      SB->appendTopLevelActions(AL);
+      SB->appendTopLevelActions(OffloadAL);
     }
 
-    assert(NumActions <= AL.size() && "Expecting more actions, not less!");
+    // 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()) {
+      // Add the host action to the list in order to create the bundling action.
+      OffloadAL.push_back(HostAction);
+
+      // We expect that the host action was just appended to the action list
+      // before this method was called.
+      assert(HostAction == AL.back() && "Host action not in the list??");
+      HostAction = C.MakeAction<OffloadBundlingJobAction>(OffloadAL);
+      AL.back() = HostAction;
+    } else
+      AL.append(OffloadAL.begin(), OffloadAL.end());
 
     // Propagate to the current host action (if any) the offload information
     // associated with the current input.
     if (HostAction)
       HostAction->propagateHostOffloadInfo(InputArgToOffloadKindMap[InputArg],
                                            /*BoundArch=*/nullptr);
 
     // If any action is added by the builders, -o is ambiguous if we have more
-    // than one top-level action.
-    if (NumActions < AL.size() && Args.hasArg(options::OPT_o) &&
+    // than one top-level action. If a bundler is used, there is no ambiguity.
+    if (!CanUseBundler && !OffloadAL.empty() && Args.hasArg(options::OPT_o) &&
         AL.size() > 1) {
       C.getDriver().Diag(
           clang::diag::err_drv_output_argument_with_multiple_files);
Index: lib/Driver/Action.cpp
===================================================================
--- lib/Driver/Action.cpp
+++ lib/Driver/Action.cpp
@@ -36,6 +36,8 @@
   case DsymutilJobClass: return "dsymutil";
   case VerifyDebugInfoJobClass: return "verify-debug-info";
   case VerifyPCHJobClass: return "verify-pch";
+  case OffloadBundlingJobClass:
+    return "clang-offload-bundler";
   }
 
   llvm_unreachable("invalid class");
@@ -339,3 +341,9 @@
 
 VerifyPCHJobAction::VerifyPCHJobAction(Action *Input, types::ID Type)
     : VerifyJobAction(VerifyPCHJobClass, Input, Type) {}
+
+void OffloadBundlingJobAction::anchor() {}
+
+OffloadBundlingJobAction::OffloadBundlingJobAction(ActionList &Inputs)
+    : JobAction(OffloadBundlingJobClass, Inputs, Inputs.front()->getType()) {}
+
Index: include/clang/Driver/Action.h
===================================================================
--- include/clang/Driver/Action.h
+++ include/clang/Driver/Action.h
@@ -65,9 +65,10 @@
     DsymutilJobClass,
     VerifyDebugInfoJobClass,
     VerifyPCHJobClass,
+    OffloadBundlingJobClass,
 
-    JobClassFirst=PreprocessJobClass,
-    JobClassLast=VerifyPCHJobClass
+    JobClassFirst = PreprocessJobClass,
+    JobClassLast = OffloadBundlingJobClass
   };
 
   // The offloading kind determines if this action is binded to a particular
@@ -476,6 +477,19 @@
   }
 };
 
+class OffloadBundlingJobAction : public JobAction {
+  void anchor() override;
+
+public:
+  // Offloading bundling doesn't change the type of output.
+  OffloadBundlingJobAction(ActionList &Inputs);
+
+  static bool classof(const Action *A) {
+    return A->getKind() == OffloadBundlingJobClass;
+  }
+};
+
+
 } // end namespace driver
 } // end namespace clang
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to