diff options
author | Samuel Antao <sfantao@us.ibm.com> | 2016-10-27 18:14:55 +0000 |
---|---|---|
committer | Samuel Antao <sfantao@us.ibm.com> | 2016-10-27 18:14:55 +0000 |
commit | 3b7e38b45061826dde67445dfc1488b489872a68 (patch) | |
tree | a4e98a6fc9c02b96637e4fb807201bd5d3221c3b /clang/lib/Driver | |
parent | 7cab8f14662bfeb0f7fc8507f09421123c5c9474 (diff) | |
download | bcm5719-llvm-3b7e38b45061826dde67445dfc1488b489872a68.tar.gz bcm5719-llvm-3b7e38b45061826dde67445dfc1488b489872a68.zip |
[Driver][OpenMP] Add support to create jobs for unbundling actions.
Summary:
This patch adds the support to create jobs for the `OffloadBundlingAction` which will invoke the `clang-offload-bundler` tool to unbundle input files.
Unlike other actions, unbundling actions have multiple outputs. Therefore, this patch adds the required changes to have a variant of `Tool::ConstructJob` with multiple outputs.
The way the naming of the results is implemented is also slightly modified so that the same action can use a different offloading prefix for each use by the different offloading actions.
With this patch, it is possible to compile a functional OpenMP binary with offloading support, even with separate compilation.
Reviewers: echristo, tra, jlebar, ABataev, hfinkel
Subscribers: mkuron, whchung, mehdi_amini, cfe-commits, Hahnfeld, andreybokhanko, arpith-jacob, carlo.bertolli, caomhin
Differential Revision: https://reviews.llvm.org/D21857
llvm-svn: 285326
Diffstat (limited to 'clang/lib/Driver')
-rw-r--r-- | clang/lib/Driver/Action.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Driver/Driver.cpp | 140 | ||||
-rw-r--r-- | clang/lib/Driver/Tool.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Driver/Tools.cpp | 66 | ||||
-rw-r--r-- | clang/lib/Driver/Tools.h | 4 |
5 files changed, 191 insertions, 42 deletions
diff --git a/clang/lib/Driver/Action.cpp b/clang/lib/Driver/Action.cpp index ad6fb718101..4e0c224c3b1 100644 --- a/clang/lib/Driver/Action.cpp +++ b/clang/lib/Driver/Action.cpp @@ -115,15 +115,18 @@ std::string Action::getOffloadingKindPrefix() const { return Res; } +/// Return a string that can be used as prefix in order to generate unique files +/// for each offloading kind. std::string -Action::getOffloadingFileNamePrefix(llvm::StringRef NormalizedTriple) const { - // A file prefix is only generated for device actions and consists of the - // offload kind and triple. - if (!OffloadingDeviceKind) +Action::GetOffloadingFileNamePrefix(OffloadKind Kind, + llvm::StringRef NormalizedTriple, + bool CreatePrefixForHost) { + // Don't generate prefix for host actions unless required. + if (!CreatePrefixForHost && (Kind == OFK_None || Kind == OFK_Host)) return ""; std::string Res("-"); - Res += getOffloadingKindPrefix(); + Res += GetOffloadKindName(Kind); Res += "-"; Res += NormalizedTriple; return Res; diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 2712efb0ffe..a2929de6aec 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -2593,7 +2593,7 @@ void Driver::BuildJobs(Compilation &C) const { /*AtTopLevel*/ true, /*MultipleArchs*/ ArchNames.size() > 1, /*LinkingOutput*/ LinkingOutput, CachedResults, - /*BuildForOffloadDevice*/ false); + /*TargetDeviceOffloadKind*/ Action::OFK_None); } // If the user passed -Qunused-arguments or there were errors, don't warn @@ -2926,31 +2926,38 @@ public: }; } -InputInfo Driver::BuildJobsForAction( - Compilation &C, const Action *A, const ToolChain *TC, StringRef BoundArch, - bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput, - std::map<std::pair<const Action *, std::string>, InputInfo> &CachedResults, - bool BuildForOffloadDevice) const { - // The bound arch is not necessarily represented in the toolchain's triple -- - // for example, armv7 and armv7s both map to the same triple -- so we need - // both in our map. Also, we need to add the offloading device kind, as the - // same tool chain can be used for host and device for some programming - // models, e.g. OpenMP. +/// Return a string that uniquely identifies the result of a job. The bound arch +/// is not necessarily represented in the toolchain's triple -- for example, +/// armv7 and armv7s both map to the same triple -- so we need both in our map. +/// Also, we need to add the offloading device kind, as the same tool chain can +/// be used for host and device for some programming models, e.g. OpenMP. +static std::string GetTriplePlusArchString(const ToolChain *TC, + StringRef BoundArch, + Action::OffloadKind OffloadKind) { std::string TriplePlusArch = TC->getTriple().normalize(); if (!BoundArch.empty()) { TriplePlusArch += "-"; TriplePlusArch += BoundArch; } TriplePlusArch += "-"; - TriplePlusArch += A->getOffloadingKindPrefix(); - std::pair<const Action *, std::string> ActionTC = {A, TriplePlusArch}; + TriplePlusArch += Action::GetOffloadKindName(OffloadKind); + return TriplePlusArch; +} + +InputInfo Driver::BuildJobsForAction( + Compilation &C, const Action *A, const ToolChain *TC, StringRef BoundArch, + bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput, + std::map<std::pair<const Action *, std::string>, InputInfo> &CachedResults, + Action::OffloadKind TargetDeviceOffloadKind) const { + std::pair<const Action *, std::string> ActionTC = { + A, GetTriplePlusArchString(TC, BoundArch, TargetDeviceOffloadKind)}; auto CachedResult = CachedResults.find(ActionTC); if (CachedResult != CachedResults.end()) { return CachedResult->second; } InputInfo Result = BuildJobsForActionNoCache( C, A, TC, BoundArch, AtTopLevel, MultipleArchs, LinkingOutput, - CachedResults, BuildForOffloadDevice); + CachedResults, TargetDeviceOffloadKind); CachedResults[ActionTC] = Result; return Result; } @@ -2959,10 +2966,11 @@ InputInfo Driver::BuildJobsForActionNoCache( Compilation &C, const Action *A, const ToolChain *TC, StringRef BoundArch, bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput, std::map<std::pair<const Action *, std::string>, InputInfo> &CachedResults, - bool BuildForOffloadDevice) const { + Action::OffloadKind TargetDeviceOffloadKind) const { llvm::PrettyStackTraceString CrashInfo("Building compilation jobs"); InputInfoList OffloadDependencesInputInfo; + bool BuildingForOffloadDevice = TargetDeviceOffloadKind != Action::OFK_None; if (const OffloadAction *OA = dyn_cast<OffloadAction>(A)) { // The offload action is expected to be used in four different situations. // @@ -2995,7 +3003,7 @@ InputInfo Driver::BuildJobsForActionNoCache( DevA = BuildJobsForAction(C, DepA, DepTC, DepBoundArch, AtTopLevel, /*MultipleArchs*/ !!DepBoundArch, LinkingOutput, - CachedResults, /*BuildForOffloadDevice=*/true); + CachedResults, DepA->getOffloadingDeviceKind()); }); return DevA; } @@ -3005,16 +3013,15 @@ InputInfo Driver::BuildJobsForActionNoCache( // generate the host dependences and override the action with the device // dependence. The dependences can't therefore be a top-level action. OA->doOnEachDependence( - /*IsHostDependence=*/BuildForOffloadDevice, + /*IsHostDependence=*/BuildingForOffloadDevice, [&](Action *DepA, const ToolChain *DepTC, const char *DepBoundArch) { OffloadDependencesInputInfo.push_back(BuildJobsForAction( C, DepA, DepTC, DepBoundArch, /*AtTopLevel=*/false, /*MultipleArchs*/ !!DepBoundArch, LinkingOutput, CachedResults, - /*BuildForOffloadDevice=*/DepA->getOffloadingDeviceKind() != - Action::OFK_None)); + DepA->getOffloadingDeviceKind())); }); - A = BuildForOffloadDevice + A = BuildingForOffloadDevice ? OA->getSingleDeviceDependence(/*DoNotConsiderHostActions=*/true) : OA->getHostDependence(); } @@ -3044,7 +3051,7 @@ InputInfo Driver::BuildJobsForActionNoCache( return BuildJobsForAction(C, *BAA->input_begin(), TC, ArchName, AtTopLevel, MultipleArchs, LinkingOutput, CachedResults, - BuildForOffloadDevice); + TargetDeviceOffloadKind); } @@ -3063,13 +3070,12 @@ InputInfo Driver::BuildJobsForActionNoCache( // need to build jobs for host/device-side inputs it may have held. for (const auto *OA : CollapsedOffloadActions) cast<OffloadAction>(OA)->doOnEachDependence( - /*IsHostDependence=*/BuildForOffloadDevice, + /*IsHostDependence=*/BuildingForOffloadDevice, [&](Action *DepA, const ToolChain *DepTC, const char *DepBoundArch) { OffloadDependencesInputInfo.push_back(BuildJobsForAction( C, DepA, DepTC, DepBoundArch, /* AtTopLevel */ false, /*MultipleArchs=*/!!DepBoundArch, LinkingOutput, CachedResults, - /*BuildForOffloadDevice=*/DepA->getOffloadingDeviceKind() != - Action::OFK_None)); + DepA->getOffloadingDeviceKind())); }); // Only use pipes when there is exactly one input. @@ -3082,7 +3088,7 @@ InputInfo Driver::BuildJobsForActionNoCache( AtTopLevel && (isa<DsymutilJobAction>(A) || isa<VerifyJobAction>(A)); InputInfos.push_back(BuildJobsForAction( C, Input, TC, BoundArch, SubJobAtTopLevel, MultipleArchs, LinkingOutput, - CachedResults, BuildForOffloadDevice)); + CachedResults, A->getOffloadingDeviceKind())); } // Always use the first input as the base input. @@ -3114,13 +3120,59 @@ InputInfo Driver::BuildJobsForActionNoCache( // Determine the place to write output to, if any. InputInfo Result; - if (JA->getType() == types::TY_Nothing) + InputInfoList UnbundlingResults; + if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(JA)) { + // If we have an unbundling job, we need to create results for all the + // outputs. We also update the results cache so that other actions using + // this unbundling action can get the right results. + for (auto &UI : UA->getDependentActionsInfo()) { + assert(UI.DependentOffloadKind != Action::OFK_None && + "Unbundling with no offloading??"); + + // Unbundling actions are never at the top level. When we generate the + // offloading prefix, we also do that for the host file because the + // unbundling action does not change the type of the output which can + // cause a overwrite. + std::string OffloadingPrefix = Action::GetOffloadingFileNamePrefix( + UI.DependentOffloadKind, + UI.DependentToolChain->getTriple().normalize(), + /*CreatePrefixForHost=*/true); + auto CurI = InputInfo( + UA, GetNamedOutputPath(C, *UA, BaseInput, UI.DependentBoundArch, + /*AtTopLevel=*/false, MultipleArchs, + OffloadingPrefix), + BaseInput); + // Save the unbundling result. + UnbundlingResults.push_back(CurI); + + // Get the unique string identifier for this dependence and cache the + // result. + CachedResults[{A, GetTriplePlusArchString( + UI.DependentToolChain, UI.DependentBoundArch, + UI.DependentOffloadKind)}] = CurI; + } + + // Now that we have all the results generated, select the one that should be + // returned for the current depending action. + std::pair<const Action *, std::string> ActionTC = { + A, GetTriplePlusArchString(TC, BoundArch, TargetDeviceOffloadKind)}; + assert(CachedResults.find(ActionTC) != CachedResults.end() && + "Result does not exist??"); + Result = CachedResults[ActionTC]; + } else if (JA->getType() == types::TY_Nothing) Result = InputInfo(A, BaseInput); - else + else { + // We only have to generate a prefix for the host if this is not a top-level + // action. + std::string OffloadingPrefix = Action::GetOffloadingFileNamePrefix( + A->getOffloadingDeviceKind(), TC->getTriple().normalize(), + /*CreatePrefixForHost=*/!!A->getOffloadingHostActiveKinds() && + !AtTopLevel); Result = InputInfo(A, GetNamedOutputPath(C, *JA, BaseInput, BoundArch, AtTopLevel, MultipleArchs, - TC->getTriple().normalize()), + OffloadingPrefix), BaseInput); + } if (CCCPrintBindings && !CCGenDiagnostics) { llvm::errs() << "# \"" << T->getToolChain().getTripleString() << '"' @@ -3130,12 +3182,28 @@ InputInfo Driver::BuildJobsForActionNoCache( if (i + 1 != e) llvm::errs() << ", "; } - llvm::errs() << "], output: " << Result.getAsString() << "\n"; + if (UnbundlingResults.empty()) + llvm::errs() << "], output: " << Result.getAsString() << "\n"; + else { + llvm::errs() << "], outputs: ["; + for (unsigned i = 0, e = UnbundlingResults.size(); i != e; ++i) { + llvm::errs() << UnbundlingResults[i].getAsString(); + if (i + 1 != e) + llvm::errs() << ", "; + } + llvm::errs() << "] \n"; + } } else { - T->ConstructJob( - C, *JA, Result, InputInfos, - C.getArgsForToolChain(TC, BoundArch, JA->getOffloadingDeviceKind()), - LinkingOutput); + if (UnbundlingResults.empty()) + T->ConstructJob( + C, *JA, Result, InputInfos, + C.getArgsForToolChain(TC, BoundArch, JA->getOffloadingDeviceKind()), + LinkingOutput); + else + T->ConstructJob( + C, *JA, UnbundlingResults, InputInfos, + C.getArgsForToolChain(TC, BoundArch, JA->getOffloadingDeviceKind()), + LinkingOutput); } return Result; } @@ -3182,7 +3250,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, const char *BaseInput, StringRef BoundArch, bool AtTopLevel, bool MultipleArchs, - StringRef NormalizedTriple) const { + StringRef OffloadingPrefix) const { llvm::PrettyStackTraceString CrashInfo("Computing output path"); // Output to a user requested destination? if (AtTopLevel && !isa<DsymutilJobAction>(JA) && !isa<VerifyJobAction>(JA)) { @@ -3268,7 +3336,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, MakeCLOutputFilename(C.getArgs(), "", BaseName, types::TY_Image); } else { SmallString<128> Output(getDefaultImageName()); - Output += JA.getOffloadingFileNamePrefix(NormalizedTriple); + Output += OffloadingPrefix; if (MultipleArchs && !BoundArch.empty()) { Output += "-"; Output.append(BoundArch); @@ -3285,7 +3353,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, if (!types::appendSuffixForType(JA.getType())) End = BaseName.rfind('.'); SmallString<128> Suffixed(BaseName.substr(0, End)); - Suffixed += JA.getOffloadingFileNamePrefix(NormalizedTriple); + Suffixed += OffloadingPrefix; if (MultipleArchs && !BoundArch.empty()) { Suffixed += "-"; Suffixed.append(BoundArch); diff --git a/clang/lib/Driver/Tool.cpp b/clang/lib/Driver/Tool.cpp index 7142e822f16..cf227bee831 100644 --- a/clang/lib/Driver/Tool.cpp +++ b/clang/lib/Driver/Tool.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Tool.h" +#include "InputInfo.h" using namespace clang::driver; @@ -21,3 +22,12 @@ Tool::Tool(const char *_Name, const char *_ShortName, const ToolChain &TC, Tool::~Tool() { } + +void Tool::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfoList &Outputs, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const { + assert(Outputs.size() == 1 && "Expected only one output by default!"); + ConstructJob(C, JA, Outputs.front(), Inputs, TCArgs, LinkingOutput); +}; diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index e7a9380d628..efc6445fb66 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -6222,7 +6222,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!JA.isDeviceOffloading(Action::OFK_None) && !JA.isDeviceOffloading(Action::OFK_Host)) { llvm::sys::path::replace_extension(F, ""); - F += JA.getOffloadingFileNamePrefix(Triple.normalize()); + F += Action::GetOffloadingFileNamePrefix(JA.getOffloadingDeviceKind(), + Triple.normalize()); F += "-"; F += JA.getOffloadingArch(); } @@ -7058,6 +7059,7 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const { + // The version with only one output is expected to refer to a bundling job. assert(isa<OffloadBundlingJobAction>(JA) && "Expecting bundling job!"); // The bundling command looks like this: @@ -7119,6 +7121,68 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs, None)); } +void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfoList &Outputs, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const { + // The version with multiple outputs is expected to refer to a unbundling job. + auto &UA = cast<OffloadUnbundlingJobAction>(JA); + + // The unbundling command looks like this: + // clang-offload-bundler -type=bc + // -targets=host-triple,openmp-triple1,openmp-triple2 + // -inputs=input_file + // -outputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2" + // -unbundle + + ArgStringList CmdArgs; + + assert(Inputs.size() == 1 && "Expecting to unbundle a single file!"); + InputInfo Input = Inputs.front(); + + // Get the type. + CmdArgs.push_back(TCArgs.MakeArgString( + Twine("-type=") + types::getTypeTempSuffix(Input.getType()))); + + // Get the targets. + SmallString<128> Triples; + Triples += "-targets="; + auto DepInfo = UA.getDependentActionsInfo(); + for (unsigned I = 0; I < DepInfo.size(); ++I) { + if (I) + Triples += ','; + + auto &Dep = DepInfo[I]; + Triples += Action::GetOffloadKindName(Dep.DependentOffloadKind); + Triples += '-'; + Triples += Dep.DependentToolChain->getTriple().normalize(); + } + + CmdArgs.push_back(TCArgs.MakeArgString(Triples)); + + // Get bundled file command. + CmdArgs.push_back( + TCArgs.MakeArgString(Twine("-inputs=") + Input.getFilename())); + + // Get unbundled files command. + SmallString<128> UB; + UB += "-outputs="; + for (unsigned I = 0; I < Outputs.size(); ++I) { + if (I) + UB += ','; + UB += Outputs[I].getFilename(); + } + CmdArgs.push_back(TCArgs.MakeArgString(UB)); + CmdArgs.push_back("-unbundle"); + + // All the inputs are encoded as commands. + C.addCommand(llvm::make_unique<Command>( + JA, *this, + TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), + CmdArgs, None)); +} + void GnuTool::anchor() {} void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, diff --git a/clang/lib/Driver/Tools.h b/clang/lib/Driver/Tools.h index 9ee3011ff7d..9687b046527 100644 --- a/clang/lib/Driver/Tools.h +++ b/clang/lib/Driver/Tools.h @@ -148,6 +148,10 @@ public: const InputInfo &Output, const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfoList &Outputs, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; }; /// \brief Base class for all GNU tools that provide the same behavior when |