477 lines · cpp
1//===- Action.cpp - Abstract compilation steps ----------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Driver/Action.h"10#include "llvm/Support/ErrorHandling.h"11#include <cassert>12#include <string>13 14using namespace clang;15using namespace driver;16using namespace llvm::opt;17 18Action::~Action() = default;19 20const char *Action::getClassName(ActionClass AC) {21 switch (AC) {22 case InputClass: return "input";23 case BindArchClass: return "bind-arch";24 case OffloadClass:25 return "offload";26 case PreprocessJobClass: return "preprocessor";27 case PrecompileJobClass: return "precompiler";28 case ExtractAPIJobClass:29 return "api-extractor";30 case AnalyzeJobClass:31 return "analyzer";32 case CompileJobClass: return "compiler";33 case BackendJobClass: return "backend";34 case AssembleJobClass: return "assembler";35 case IfsMergeJobClass: return "interface-stub-merger";36 case LinkJobClass: return "linker";37 case LipoJobClass: return "lipo";38 case DsymutilJobClass: return "dsymutil";39 case VerifyDebugInfoJobClass: return "verify-debug-info";40 case VerifyPCHJobClass: return "verify-pch";41 case OffloadBundlingJobClass:42 return "clang-offload-bundler";43 case OffloadUnbundlingJobClass:44 return "clang-offload-unbundler";45 case OffloadPackagerJobClass:46 return "llvm-offload-binary";47 case LinkerWrapperJobClass:48 return "clang-linker-wrapper";49 case StaticLibJobClass:50 return "static-lib-linker";51 case BinaryAnalyzeJobClass:52 return "binary-analyzer";53 case BinaryTranslatorJobClass:54 return "binary-translator";55 case ObjcopyJobClass:56 return "objcopy";57 }58 59 llvm_unreachable("invalid class");60}61 62void Action::propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch,63 const ToolChain *OToolChain) {64 // Offload action set its own kinds on their dependences.65 if (Kind == OffloadClass)66 return;67 // Unbundling actions use the host kinds.68 if (Kind == OffloadUnbundlingJobClass)69 return;70 71 assert((OffloadingDeviceKind == OKind || OffloadingDeviceKind == OFK_None) &&72 "Setting device kind to a different device??");73 assert(!ActiveOffloadKindMask && "Setting a device kind in a host action??");74 OffloadingDeviceKind = OKind;75 OffloadingArch = OArch;76 OffloadingToolChain = OToolChain;77 78 for (auto *A : Inputs)79 A->propagateDeviceOffloadInfo(OffloadingDeviceKind, OArch, OToolChain);80}81 82void Action::propagateHostOffloadInfo(unsigned OKinds, const char *OArch) {83 // Offload action set its own kinds on their dependences.84 if (Kind == OffloadClass)85 return;86 87 assert(OffloadingDeviceKind == OFK_None &&88 "Setting a host kind in a device action.");89 ActiveOffloadKindMask |= OKinds;90 OffloadingArch = OArch;91 92 for (auto *A : Inputs)93 A->propagateHostOffloadInfo(ActiveOffloadKindMask, OArch);94}95 96void Action::propagateOffloadInfo(const Action *A) {97 if (unsigned HK = A->getOffloadingHostActiveKinds())98 propagateHostOffloadInfo(HK, A->getOffloadingArch());99 else100 propagateDeviceOffloadInfo(A->getOffloadingDeviceKind(),101 A->getOffloadingArch(),102 A->getOffloadingToolChain());103}104 105std::string Action::getOffloadingKindPrefix() const {106 switch (OffloadingDeviceKind) {107 case OFK_None:108 break;109 case OFK_Host:110 llvm_unreachable("Host kind is not an offloading device kind.");111 break;112 case OFK_Cuda:113 return "device-cuda";114 case OFK_OpenMP:115 return "device-openmp";116 case OFK_HIP:117 return "device-hip";118 case OFK_SYCL:119 return "device-sycl";120 121 // TODO: Add other programming models here.122 }123 124 if (!ActiveOffloadKindMask)125 return {};126 127 std::string Res("host");128 assert(!((ActiveOffloadKindMask & OFK_Cuda) &&129 (ActiveOffloadKindMask & OFK_HIP)) &&130 "Cannot offload CUDA and HIP at the same time");131 if (ActiveOffloadKindMask & OFK_Cuda)132 Res += "-cuda";133 if (ActiveOffloadKindMask & OFK_HIP)134 Res += "-hip";135 if (ActiveOffloadKindMask & OFK_OpenMP)136 Res += "-openmp";137 if (ActiveOffloadKindMask & OFK_SYCL)138 Res += "-sycl";139 140 // TODO: Add other programming models here.141 142 return Res;143}144 145/// Return a string that can be used as prefix in order to generate unique files146/// for each offloading kind.147std::string148Action::GetOffloadingFileNamePrefix(OffloadKind Kind,149 StringRef NormalizedTriple,150 bool CreatePrefixForHost) {151 // Don't generate prefix for host actions unless required.152 if (!CreatePrefixForHost && (Kind == OFK_None || Kind == OFK_Host))153 return {};154 155 std::string Res("-");156 Res += GetOffloadKindName(Kind);157 Res += "-";158 Res += NormalizedTriple;159 return Res;160}161 162/// Return a string with the offload kind name. If that is not defined, we163/// assume 'host'.164StringRef Action::GetOffloadKindName(OffloadKind Kind) {165 switch (Kind) {166 case OFK_None:167 case OFK_Host:168 return "host";169 case OFK_Cuda:170 return "cuda";171 case OFK_OpenMP:172 return "openmp";173 case OFK_HIP:174 return "hip";175 case OFK_SYCL:176 return "sycl";177 178 // TODO: Add other programming models here.179 }180 181 llvm_unreachable("invalid offload kind");182}183 184void InputAction::anchor() {}185 186InputAction::InputAction(const Arg &_Input, types::ID _Type, StringRef _Id)187 : Action(InputClass, _Type), Input(_Input), Id(_Id.str()) {}188 189void BindArchAction::anchor() {}190 191BindArchAction::BindArchAction(Action *Input, StringRef ArchName)192 : Action(BindArchClass, Input), ArchName(ArchName) {}193 194void OffloadAction::anchor() {}195 196OffloadAction::OffloadAction(const HostDependence &HDep)197 : Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()) {198 OffloadingArch = HDep.getBoundArch();199 ActiveOffloadKindMask = HDep.getOffloadKinds();200 HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(),201 HDep.getBoundArch());202}203 204OffloadAction::OffloadAction(const DeviceDependences &DDeps, types::ID Ty)205 : Action(OffloadClass, DDeps.getActions(), Ty),206 DevToolChains(DDeps.getToolChains()) {207 auto &OKinds = DDeps.getOffloadKinds();208 auto &BArchs = DDeps.getBoundArchs();209 auto &OTCs = DDeps.getToolChains();210 211 // If all inputs agree on the same kind, use it also for this action.212 if (llvm::all_equal(OKinds))213 OffloadingDeviceKind = OKinds.front();214 215 // If we have a single dependency, inherit the architecture from it.216 if (OKinds.size() == 1)217 OffloadingArch = BArchs.front();218 219 // Propagate info to the dependencies.220 for (unsigned i = 0, e = getInputs().size(); i != e; ++i)221 getInputs()[i]->propagateDeviceOffloadInfo(OKinds[i], BArchs[i], OTCs[i]);222}223 224OffloadAction::OffloadAction(const HostDependence &HDep,225 const DeviceDependences &DDeps)226 : Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()),227 DevToolChains(DDeps.getToolChains()) {228 // We use the kinds of the host dependence for this action.229 OffloadingArch = HDep.getBoundArch();230 ActiveOffloadKindMask = HDep.getOffloadKinds();231 HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(),232 HDep.getBoundArch());233 234 // Add device inputs and propagate info to the device actions. Do work only if235 // we have dependencies.236 for (unsigned i = 0, e = DDeps.getActions().size(); i != e; ++i) {237 if (auto *A = DDeps.getActions()[i]) {238 getInputs().push_back(A);239 A->propagateDeviceOffloadInfo(DDeps.getOffloadKinds()[i],240 DDeps.getBoundArchs()[i],241 DDeps.getToolChains()[i]);242 // If this action is used to forward single dependency, set the toolchain.243 if (DDeps.getActions().size() == 1)244 OffloadingToolChain = DDeps.getToolChains()[i];245 }246 }247}248 249void OffloadAction::doOnHostDependence(const OffloadActionWorkTy &Work) const {250 if (!HostTC)251 return;252 assert(!getInputs().empty() && "No dependencies for offload action??");253 auto *A = getInputs().front();254 Work(A, HostTC, A->getOffloadingArch());255}256 257void OffloadAction::doOnEachDeviceDependence(258 const OffloadActionWorkTy &Work) const {259 auto I = getInputs().begin();260 auto E = getInputs().end();261 if (I == E)262 return;263 264 // We expect to have the same number of input dependences and device tool265 // chains, except if we also have a host dependence. In that case we have one266 // more dependence than we have device tool chains.267 assert(getInputs().size() == DevToolChains.size() + (HostTC ? 1 : 0) &&268 "Sizes of action dependences and toolchains are not consistent!");269 270 // Skip host action271 if (HostTC)272 ++I;273 274 auto TI = DevToolChains.begin();275 for (; I != E; ++I, ++TI)276 Work(*I, *TI, (*I)->getOffloadingArch());277}278 279void OffloadAction::doOnEachDependence(const OffloadActionWorkTy &Work) const {280 doOnHostDependence(Work);281 doOnEachDeviceDependence(Work);282}283 284void OffloadAction::doOnEachDependence(bool IsHostDependence,285 const OffloadActionWorkTy &Work) const {286 if (IsHostDependence)287 doOnHostDependence(Work);288 else289 doOnEachDeviceDependence(Work);290}291 292bool OffloadAction::hasHostDependence() const { return HostTC != nullptr; }293 294Action *OffloadAction::getHostDependence() const {295 assert(hasHostDependence() && "Host dependence does not exist!");296 assert(!getInputs().empty() && "No dependencies for offload action??");297 return HostTC ? getInputs().front() : nullptr;298}299 300bool OffloadAction::hasSingleDeviceDependence(301 bool DoNotConsiderHostActions) const {302 if (DoNotConsiderHostActions)303 return getInputs().size() == (HostTC ? 2 : 1);304 return !HostTC && getInputs().size() == 1;305}306 307Action *308OffloadAction::getSingleDeviceDependence(bool DoNotConsiderHostActions) const {309 assert(hasSingleDeviceDependence(DoNotConsiderHostActions) &&310 "Single device dependence does not exist!");311 // The previous assert ensures the number of entries in getInputs() is312 // consistent with what we are doing here.313 return HostTC ? getInputs()[1] : getInputs().front();314}315 316void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC,317 const char *BoundArch,318 OffloadKind OKind) {319 DeviceActions.push_back(&A);320 DeviceToolChains.push_back(&TC);321 DeviceBoundArchs.push_back(BoundArch);322 DeviceOffloadKinds.push_back(OKind);323}324 325void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC,326 const char *BoundArch,327 unsigned OffloadKindMask) {328 DeviceActions.push_back(&A);329 DeviceToolChains.push_back(&TC);330 DeviceBoundArchs.push_back(BoundArch);331 332 // Add each active offloading kind from a mask.333 for (OffloadKind OKind : {OFK_OpenMP, OFK_Cuda, OFK_HIP, OFK_SYCL})334 if (OKind & OffloadKindMask)335 DeviceOffloadKinds.push_back(OKind);336}337 338OffloadAction::HostDependence::HostDependence(Action &A, const ToolChain &TC,339 const char *BoundArch,340 const DeviceDependences &DDeps)341 : HostAction(A), HostToolChain(TC), HostBoundArch(BoundArch) {342 for (auto K : DDeps.getOffloadKinds())343 HostOffloadKinds |= K;344}345 346void JobAction::anchor() {}347 348JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type)349 : Action(Kind, Input, Type) {}350 351JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)352 : Action(Kind, Inputs, Type) {}353 354void PreprocessJobAction::anchor() {}355 356PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType)357 : JobAction(PreprocessJobClass, Input, OutputType) {}358 359void PrecompileJobAction::anchor() {}360 361PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType)362 : JobAction(PrecompileJobClass, Input, OutputType) {}363 364PrecompileJobAction::PrecompileJobAction(ActionClass Kind, Action *Input,365 types::ID OutputType)366 : JobAction(Kind, Input, OutputType) {367 assert(isa<PrecompileJobAction>((Action*)this) && "invalid action kind");368}369 370void ExtractAPIJobAction::anchor() {}371 372ExtractAPIJobAction::ExtractAPIJobAction(Action *Inputs, types::ID OutputType)373 : JobAction(ExtractAPIJobClass, Inputs, OutputType) {}374 375void AnalyzeJobAction::anchor() {}376 377AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)378 : JobAction(AnalyzeJobClass, Input, OutputType) {}379 380void CompileJobAction::anchor() {}381 382CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType)383 : JobAction(CompileJobClass, Input, OutputType) {}384 385void BackendJobAction::anchor() {}386 387BackendJobAction::BackendJobAction(Action *Input, types::ID OutputType)388 : JobAction(BackendJobClass, Input, OutputType) {}389 390void AssembleJobAction::anchor() {}391 392AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)393 : JobAction(AssembleJobClass, Input, OutputType) {}394 395void IfsMergeJobAction::anchor() {}396 397IfsMergeJobAction::IfsMergeJobAction(ActionList &Inputs, types::ID Type)398 : JobAction(IfsMergeJobClass, Inputs, Type) {}399 400void LinkJobAction::anchor() {}401 402LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type)403 : JobAction(LinkJobClass, Inputs, Type) {}404 405void LipoJobAction::anchor() {}406 407LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type)408 : JobAction(LipoJobClass, Inputs, Type) {}409 410void DsymutilJobAction::anchor() {}411 412DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type)413 : JobAction(DsymutilJobClass, Inputs, Type) {}414 415void VerifyJobAction::anchor() {}416 417VerifyJobAction::VerifyJobAction(ActionClass Kind, Action *Input,418 types::ID Type)419 : JobAction(Kind, Input, Type) {420 assert((Kind == VerifyDebugInfoJobClass || Kind == VerifyPCHJobClass) &&421 "ActionClass is not a valid VerifyJobAction");422}423 424void VerifyDebugInfoJobAction::anchor() {}425 426VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(Action *Input,427 types::ID Type)428 : VerifyJobAction(VerifyDebugInfoJobClass, Input, Type) {}429 430void VerifyPCHJobAction::anchor() {}431 432VerifyPCHJobAction::VerifyPCHJobAction(Action *Input, types::ID Type)433 : VerifyJobAction(VerifyPCHJobClass, Input, Type) {}434 435void OffloadBundlingJobAction::anchor() {}436 437OffloadBundlingJobAction::OffloadBundlingJobAction(ActionList &Inputs)438 : JobAction(OffloadBundlingJobClass, Inputs, Inputs.back()->getType()) {}439 440void OffloadUnbundlingJobAction::anchor() {}441 442OffloadUnbundlingJobAction::OffloadUnbundlingJobAction(Action *Input)443 : JobAction(OffloadUnbundlingJobClass, Input, Input->getType()) {}444 445void OffloadPackagerJobAction::anchor() {}446 447OffloadPackagerJobAction::OffloadPackagerJobAction(ActionList &Inputs,448 types::ID Type)449 : JobAction(OffloadPackagerJobClass, Inputs, Type) {}450 451void LinkerWrapperJobAction::anchor() {}452 453LinkerWrapperJobAction::LinkerWrapperJobAction(ActionList &Inputs,454 types::ID Type)455 : JobAction(LinkerWrapperJobClass, Inputs, Type) {}456 457void StaticLibJobAction::anchor() {}458 459StaticLibJobAction::StaticLibJobAction(ActionList &Inputs, types::ID Type)460 : JobAction(StaticLibJobClass, Inputs, Type) {}461 462void BinaryAnalyzeJobAction::anchor() {}463 464BinaryAnalyzeJobAction::BinaryAnalyzeJobAction(Action *Input, types::ID Type)465 : JobAction(BinaryAnalyzeJobClass, Input, Type) {}466 467void BinaryTranslatorJobAction::anchor() {}468 469BinaryTranslatorJobAction::BinaryTranslatorJobAction(Action *Input,470 types::ID Type)471 : JobAction(BinaryTranslatorJobClass, Input, Type) {}472 473void ObjcopyJobAction::anchor() {}474 475ObjcopyJobAction::ObjcopyJobAction(Action *Input, types::ID Type)476 : JobAction(ObjcopyJobClass, Input, Type) {}477