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 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: 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(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 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,17 +2053,31 @@ } /// \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(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. @@ -2027,8 +2086,8 @@ /*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/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: 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