From 69d6f31f744a8b3dcb1a3fecae41a9d6f667b476 Mon Sep 17 00:00:00 2001 From: Samuel Antao Date: Thu, 27 Oct 2016 17:50:43 +0000 Subject: [PATCH] [Driver][OpenMP] Update actions builder to create bundling action when necessary. Summary: 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. Reviewers: echristo, tra, jlebar, ABataev, hfinkel Subscribers: whchung, mehdi_amini, cfe-commits, Hahnfeld, andreybokhanko, arpith-jacob, carlo.bertolli, caomhin Differential Revision: https://reviews.llvm.org/D21852 llvm-svn: 285323 --- clang/include/clang/Driver/Action.h | 15 +++++++- clang/lib/Driver/Action.cpp | 7 ++++ clang/lib/Driver/Driver.cpp | 70 ++++++++++++++++++++++++++++++++++--- clang/lib/Driver/ToolChain.cpp | 4 +++ clang/test/Driver/openmp-offload.c | 28 +++++++++++++++ 5 files changed, 119 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/Driver/Action.h b/clang/include/clang/Driver/Action.h index c913c4c..e24269c 100644 --- a/clang/include/clang/Driver/Action.h +++ b/clang/include/clang/Driver/Action.h @@ -66,9 +66,10 @@ public: DsymutilJobClass, VerifyDebugInfoJobClass, VerifyPCHJobClass, + OffloadBundlingJobClass, JobClassFirst = PreprocessJobClass, - JobClassLast = VerifyPCHJobClass + JobClassLast = OffloadBundlingJobClass }; // The offloading kind determines if this action is binded to a particular @@ -481,6 +482,18 @@ public: } }; +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 diff --git a/clang/lib/Driver/Action.cpp b/clang/lib/Driver/Action.cpp index a351429..90bc149 100644 --- a/clang/lib/Driver/Action.cpp +++ b/clang/lib/Driver/Action.cpp @@ -36,6 +36,8 @@ const char *Action::getClassName(ActionClass AC) { 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"); @@ -346,3 +348,8 @@ void VerifyPCHJobAction::anchor() {} VerifyPCHJobAction::VerifyPCHJobAction(Action *Input, types::ID Type) : VerifyJobAction(VerifyPCHJobClass, Input, Type) {} + +void OffloadBundlingJobAction::anchor() {} + +OffloadBundlingJobAction::OffloadBundlingJobAction(ActionList &Inputs) + : JobAction(OffloadBundlingJobClass, Inputs, Inputs.front()->getType()) {} diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index fe96052..8d96284 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -1568,6 +1568,9 @@ class OffloadingActionBuilder final { /// found. virtual bool initialize() { return false; } + /// Return true if the builder can use bundling/unbundling. + virtual bool canUseBundlerUnbundler() const { return false; } + /// Return true if this builder is valid. We have a valid builder if we have /// associated device tool chains. bool isValid() { return !ToolChains.empty(); } @@ -1911,6 +1914,26 @@ class OffloadingActionBuilder final { 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."); @@ -1937,6 +1960,11 @@ class OffloadingActionBuilder final { DeviceLinkerInputs.resize(ToolChains.size()); return false; } + + bool canUseBundlerUnbundler() const override { + // OpenMP should use bundled files whenever possible. + return true; + } }; /// @@ -1946,6 +1974,9 @@ class OffloadingActionBuilder final { /// Specialized builders being used by this offloading action builder. SmallVector SpecializedBuilders; + /// Flag set to true if all valid builders allow file bundling/unbundling. + bool CanUseBundler; + public: OffloadingActionBuilder(Compilation &C, DerivedArgList &Args, const Driver::InputList &Inputs) @@ -1964,9 +1995,22 @@ public: // 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() { @@ -2066,15 +2110,33 @@ public: return false; } - /// Add the offloading top level actions to the provided action list. + /// 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) { + // Get the device actions to be appended. + ActionList OffloadAL; for (auto *SB : SpecializedBuilders) { if (!SB->isValid()) continue; - SB->appendTopLevelActions(AL); + SB->appendTopLevelActions(OffloadAL); } + // 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. if (HostAction) diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 9023265..a82ebfe 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -263,6 +263,10 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { 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."); diff --git a/clang/test/Driver/openmp-offload.c b/clang/test/Driver/openmp-offload.c index 6ba844c..ff1c9ad 100644 --- a/clang/test/Driver/openmp-offload.c +++ b/clang/test/Driver/openmp-offload.c @@ -274,3 +274,31 @@ // CHK-COMMANDS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le--linux" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "[[HOSTASM:.+\.s]]" "-x" "ir" "[[HOSTBC]]" // CHK-COMMANDS-ST: clang{{.*}}" "-cc1as" "-triple" "powerpc64le--linux" "-filetype" "obj" {{.*}}"-o" [[HOSTOBJ:.+\.o]]" [[HOSTASM:.+\.s]] // CHK-COMMANDS-ST: ld" {{.*}}"-o" "[[HOSTBIN:.+\.out]]" {{.*}}"-lomptarget" {{.*}}"-T" "[[HOSTLK:.+\.lk]]" + + +/// ########################################################################### + +/// 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) -- 2.7.4