|  | //===--- Action.cpp - Abstract compilation steps --------------------------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "clang/Driver/Action.h" | 
|  | #include "clang/Driver/ToolChain.h" | 
|  | #include "llvm/ADT/StringSwitch.h" | 
|  | #include "llvm/Support/ErrorHandling.h" | 
|  | #include "llvm/Support/Regex.h" | 
|  | #include <cassert> | 
|  | using namespace clang::driver; | 
|  | using namespace llvm::opt; | 
|  |  | 
|  | Action::~Action() {} | 
|  |  | 
|  | const char *Action::getClassName(ActionClass AC) { | 
|  | switch (AC) { | 
|  | case InputClass: return "input"; | 
|  | case BindArchClass: return "bind-arch"; | 
|  | case OffloadClass: | 
|  | return "offload"; | 
|  | case PreprocessJobClass: return "preprocessor"; | 
|  | case PrecompileJobClass: return "precompiler"; | 
|  | case AnalyzeJobClass: return "analyzer"; | 
|  | case MigrateJobClass: return "migrator"; | 
|  | case CompileJobClass: return "compiler"; | 
|  | case BackendJobClass: return "backend"; | 
|  | case AssembleJobClass: return "assembler"; | 
|  | case LinkJobClass: return "linker"; | 
|  | case LipoJobClass: return "lipo"; | 
|  | case DsymutilJobClass: return "dsymutil"; | 
|  | case VerifyDebugInfoJobClass: return "verify-debug-info"; | 
|  | case VerifyPCHJobClass: return "verify-pch"; | 
|  | } | 
|  |  | 
|  | llvm_unreachable("invalid class"); | 
|  | } | 
|  |  | 
|  | void Action::propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch) { | 
|  | // Offload action set its own kinds on their dependences. | 
|  | if (Kind == OffloadClass) | 
|  | return; | 
|  |  | 
|  | assert((OffloadingDeviceKind == OKind || OffloadingDeviceKind == OFK_None) && | 
|  | "Setting device kind to a different device??"); | 
|  | assert(!ActiveOffloadKindMask && "Setting a device kind in a host action??"); | 
|  | OffloadingDeviceKind = OKind; | 
|  | OffloadingArch = OArch; | 
|  |  | 
|  | for (auto *A : Inputs) | 
|  | A->propagateDeviceOffloadInfo(OffloadingDeviceKind, OArch); | 
|  | } | 
|  |  | 
|  | void Action::propagateHostOffloadInfo(unsigned OKinds, const char *OArch) { | 
|  | // Offload action set its own kinds on their dependences. | 
|  | if (Kind == OffloadClass) | 
|  | return; | 
|  |  | 
|  | assert(OffloadingDeviceKind == OFK_None && | 
|  | "Setting a host kind in a device action."); | 
|  | ActiveOffloadKindMask |= OKinds; | 
|  | OffloadingArch = OArch; | 
|  |  | 
|  | for (auto *A : Inputs) | 
|  | A->propagateHostOffloadInfo(ActiveOffloadKindMask, OArch); | 
|  | } | 
|  |  | 
|  | void Action::propagateOffloadInfo(const Action *A) { | 
|  | if (unsigned HK = A->getOffloadingHostActiveKinds()) | 
|  | propagateHostOffloadInfo(HK, A->getOffloadingArch()); | 
|  | else | 
|  | propagateDeviceOffloadInfo(A->getOffloadingDeviceKind(), | 
|  | A->getOffloadingArch()); | 
|  | } | 
|  |  | 
|  | std::string Action::getOffloadingKindPrefix() const { | 
|  | switch (OffloadingDeviceKind) { | 
|  | case OFK_None: | 
|  | break; | 
|  | case OFK_Host: | 
|  | llvm_unreachable("Host kind is not an offloading device kind."); | 
|  | break; | 
|  | case OFK_Cuda: | 
|  | return "device-cuda"; | 
|  | case OFK_OpenMP: | 
|  | return "device-openmp"; | 
|  |  | 
|  | // TODO: Add other programming models here. | 
|  | } | 
|  |  | 
|  | if (!ActiveOffloadKindMask) | 
|  | return ""; | 
|  |  | 
|  | std::string Res("host"); | 
|  | if (ActiveOffloadKindMask & OFK_Cuda) | 
|  | Res += "-cuda"; | 
|  | if (ActiveOffloadKindMask & OFK_OpenMP) | 
|  | Res += "-openmp"; | 
|  |  | 
|  | // TODO: Add other programming models here. | 
|  |  | 
|  | return Res; | 
|  | } | 
|  |  | 
|  | 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) | 
|  | return ""; | 
|  |  | 
|  | std::string Res("-"); | 
|  | Res += getOffloadingKindPrefix(); | 
|  | Res += "-"; | 
|  | Res += NormalizedTriple; | 
|  | return Res; | 
|  | } | 
|  |  | 
|  | void InputAction::anchor() {} | 
|  |  | 
|  | InputAction::InputAction(const Arg &_Input, types::ID _Type) | 
|  | : Action(InputClass, _Type), Input(_Input) { | 
|  | } | 
|  |  | 
|  | void BindArchAction::anchor() {} | 
|  |  | 
|  | BindArchAction::BindArchAction(Action *Input, llvm::StringRef ArchName) | 
|  | : Action(BindArchClass, Input), ArchName(ArchName) {} | 
|  |  | 
|  | void OffloadAction::anchor() {} | 
|  |  | 
|  | OffloadAction::OffloadAction(const HostDependence &HDep) | 
|  | : Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()) { | 
|  | OffloadingArch = HDep.getBoundArch(); | 
|  | ActiveOffloadKindMask = HDep.getOffloadKinds(); | 
|  | HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(), | 
|  | HDep.getBoundArch()); | 
|  | } | 
|  |  | 
|  | OffloadAction::OffloadAction(const DeviceDependences &DDeps, types::ID Ty) | 
|  | : Action(OffloadClass, DDeps.getActions(), Ty), | 
|  | DevToolChains(DDeps.getToolChains()) { | 
|  | auto &OKinds = DDeps.getOffloadKinds(); | 
|  | auto &BArchs = DDeps.getBoundArchs(); | 
|  |  | 
|  | // If all inputs agree on the same kind, use it also for this action. | 
|  | if (llvm::all_of(OKinds, [&](OffloadKind K) { return K == OKinds.front(); })) | 
|  | OffloadingDeviceKind = OKinds.front(); | 
|  |  | 
|  | // If we have a single dependency, inherit the architecture from it. | 
|  | if (OKinds.size() == 1) | 
|  | OffloadingArch = BArchs.front(); | 
|  |  | 
|  | // Propagate info to the dependencies. | 
|  | for (unsigned i = 0, e = getInputs().size(); i != e; ++i) | 
|  | getInputs()[i]->propagateDeviceOffloadInfo(OKinds[i], BArchs[i]); | 
|  | } | 
|  |  | 
|  | OffloadAction::OffloadAction(const HostDependence &HDep, | 
|  | const DeviceDependences &DDeps) | 
|  | : Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()), | 
|  | DevToolChains(DDeps.getToolChains()) { | 
|  | // We use the kinds of the host dependence for this action. | 
|  | OffloadingArch = HDep.getBoundArch(); | 
|  | ActiveOffloadKindMask = HDep.getOffloadKinds(); | 
|  | HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(), | 
|  | HDep.getBoundArch()); | 
|  |  | 
|  | // Add device inputs and propagate info to the device actions. Do work only if | 
|  | // we have dependencies. | 
|  | for (unsigned i = 0, e = DDeps.getActions().size(); i != e; ++i) | 
|  | if (auto *A = DDeps.getActions()[i]) { | 
|  | getInputs().push_back(A); | 
|  | A->propagateDeviceOffloadInfo(DDeps.getOffloadKinds()[i], | 
|  | DDeps.getBoundArchs()[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | void OffloadAction::doOnHostDependence(const OffloadActionWorkTy &Work) const { | 
|  | if (!HostTC) | 
|  | return; | 
|  | assert(!getInputs().empty() && "No dependencies for offload action??"); | 
|  | auto *A = getInputs().front(); | 
|  | Work(A, HostTC, A->getOffloadingArch()); | 
|  | } | 
|  |  | 
|  | void OffloadAction::doOnEachDeviceDependence( | 
|  | const OffloadActionWorkTy &Work) const { | 
|  | auto I = getInputs().begin(); | 
|  | auto E = getInputs().end(); | 
|  | if (I == E) | 
|  | return; | 
|  |  | 
|  | // We expect to have the same number of input dependences and device tool | 
|  | // chains, except if we also have a host dependence. In that case we have one | 
|  | // more dependence than we have device tool chains. | 
|  | assert(getInputs().size() == DevToolChains.size() + (HostTC ? 1 : 0) && | 
|  | "Sizes of action dependences and toolchains are not consistent!"); | 
|  |  | 
|  | // Skip host action | 
|  | if (HostTC) | 
|  | ++I; | 
|  |  | 
|  | auto TI = DevToolChains.begin(); | 
|  | for (; I != E; ++I, ++TI) | 
|  | Work(*I, *TI, (*I)->getOffloadingArch()); | 
|  | } | 
|  |  | 
|  | void OffloadAction::doOnEachDependence(const OffloadActionWorkTy &Work) const { | 
|  | doOnHostDependence(Work); | 
|  | doOnEachDeviceDependence(Work); | 
|  | } | 
|  |  | 
|  | void OffloadAction::doOnEachDependence(bool IsHostDependence, | 
|  | const OffloadActionWorkTy &Work) const { | 
|  | if (IsHostDependence) | 
|  | doOnHostDependence(Work); | 
|  | else | 
|  | doOnEachDeviceDependence(Work); | 
|  | } | 
|  |  | 
|  | bool OffloadAction::hasHostDependence() const { return HostTC != nullptr; } | 
|  |  | 
|  | Action *OffloadAction::getHostDependence() const { | 
|  | assert(hasHostDependence() && "Host dependence does not exist!"); | 
|  | assert(!getInputs().empty() && "No dependencies for offload action??"); | 
|  | return HostTC ? getInputs().front() : nullptr; | 
|  | } | 
|  |  | 
|  | bool OffloadAction::hasSingleDeviceDependence( | 
|  | bool DoNotConsiderHostActions) const { | 
|  | if (DoNotConsiderHostActions) | 
|  | return getInputs().size() == (HostTC ? 2 : 1); | 
|  | return !HostTC && getInputs().size() == 1; | 
|  | } | 
|  |  | 
|  | Action * | 
|  | OffloadAction::getSingleDeviceDependence(bool DoNotConsiderHostActions) const { | 
|  | assert(hasSingleDeviceDependence(DoNotConsiderHostActions) && | 
|  | "Single device dependence does not exist!"); | 
|  | // The previous assert ensures the number of entries in getInputs() is | 
|  | // consistent with what we are doing here. | 
|  | return HostTC ? getInputs()[1] : getInputs().front(); | 
|  | } | 
|  |  | 
|  | void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC, | 
|  | const char *BoundArch, | 
|  | OffloadKind OKind) { | 
|  | DeviceActions.push_back(&A); | 
|  | DeviceToolChains.push_back(&TC); | 
|  | DeviceBoundArchs.push_back(BoundArch); | 
|  | DeviceOffloadKinds.push_back(OKind); | 
|  | } | 
|  |  | 
|  | OffloadAction::HostDependence::HostDependence(Action &A, const ToolChain &TC, | 
|  | const char *BoundArch, | 
|  | const DeviceDependences &DDeps) | 
|  | : HostAction(A), HostToolChain(TC), HostBoundArch(BoundArch) { | 
|  | for (auto K : DDeps.getOffloadKinds()) | 
|  | HostOffloadKinds |= K; | 
|  | } | 
|  |  | 
|  | void JobAction::anchor() {} | 
|  |  | 
|  | JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type) | 
|  | : Action(Kind, Input, Type) {} | 
|  |  | 
|  | JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type) | 
|  | : Action(Kind, Inputs, Type) { | 
|  | } | 
|  |  | 
|  | void PreprocessJobAction::anchor() {} | 
|  |  | 
|  | PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType) | 
|  | : JobAction(PreprocessJobClass, Input, OutputType) {} | 
|  |  | 
|  | void PrecompileJobAction::anchor() {} | 
|  |  | 
|  | PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType) | 
|  | : JobAction(PrecompileJobClass, Input, OutputType) {} | 
|  |  | 
|  | void AnalyzeJobAction::anchor() {} | 
|  |  | 
|  | AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType) | 
|  | : JobAction(AnalyzeJobClass, Input, OutputType) {} | 
|  |  | 
|  | void MigrateJobAction::anchor() {} | 
|  |  | 
|  | MigrateJobAction::MigrateJobAction(Action *Input, types::ID OutputType) | 
|  | : JobAction(MigrateJobClass, Input, OutputType) {} | 
|  |  | 
|  | void CompileJobAction::anchor() {} | 
|  |  | 
|  | CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType) | 
|  | : JobAction(CompileJobClass, Input, OutputType) {} | 
|  |  | 
|  | void BackendJobAction::anchor() {} | 
|  |  | 
|  | BackendJobAction::BackendJobAction(Action *Input, types::ID OutputType) | 
|  | : JobAction(BackendJobClass, Input, OutputType) {} | 
|  |  | 
|  | void AssembleJobAction::anchor() {} | 
|  |  | 
|  | AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType) | 
|  | : JobAction(AssembleJobClass, Input, OutputType) {} | 
|  |  | 
|  | void LinkJobAction::anchor() {} | 
|  |  | 
|  | LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type) | 
|  | : JobAction(LinkJobClass, Inputs, Type) { | 
|  | } | 
|  |  | 
|  | void LipoJobAction::anchor() {} | 
|  |  | 
|  | LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type) | 
|  | : JobAction(LipoJobClass, Inputs, Type) { | 
|  | } | 
|  |  | 
|  | void DsymutilJobAction::anchor() {} | 
|  |  | 
|  | DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type) | 
|  | : JobAction(DsymutilJobClass, Inputs, Type) { | 
|  | } | 
|  |  | 
|  | void VerifyJobAction::anchor() {} | 
|  |  | 
|  | VerifyJobAction::VerifyJobAction(ActionClass Kind, Action *Input, | 
|  | types::ID Type) | 
|  | : JobAction(Kind, Input, Type) { | 
|  | assert((Kind == VerifyDebugInfoJobClass || Kind == VerifyPCHJobClass) && | 
|  | "ActionClass is not a valid VerifyJobAction"); | 
|  | } | 
|  |  | 
|  | void VerifyDebugInfoJobAction::anchor() {} | 
|  |  | 
|  | VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(Action *Input, | 
|  | types::ID Type) | 
|  | : VerifyJobAction(VerifyDebugInfoJobClass, Input, Type) {} | 
|  |  | 
|  | void VerifyPCHJobAction::anchor() {} | 
|  |  | 
|  | VerifyPCHJobAction::VerifyPCHJobAction(Action *Input, types::ID Type) | 
|  | : VerifyJobAction(VerifyPCHJobClass, Input, Type) {} |