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-exception
6//
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 HeaderModulePrecompileJobClass: return "header-module-precompiler";
29  case AnalyzeJobClass: return "analyzer";
30  case MigrateJobClass: return "migrator";
31  case CompileJobClass: return "compiler";
32  case BackendJobClass: return "backend";
33  case AssembleJobClass: return "assembler";
34  case IfsMergeJobClass: return "interface-stub-merger";
35  case LinkJobClass: return "linker";
36  case LipoJobClass: return "lipo";
37  case DsymutilJobClass: return "dsymutil";
38  case VerifyDebugInfoJobClass: return "verify-debug-info";
39  case VerifyPCHJobClass: return "verify-pch";
40  case OffloadBundlingJobClass:
41    return "clang-offload-bundler";
42  case OffloadUnbundlingJobClass:
43    return "clang-offload-unbundler";
44  case OffloadWrapperJobClass:
45    return "clang-offload-wrapper";
46  }
47
48  llvm_unreachable("invalid class");
49}
50
51void Action::propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch) {
52  // Offload action set its own kinds on their dependences.
53  if (Kind == OffloadClass)
54    return;
55  // Unbundling actions use the host kinds.
56  if (Kind == OffloadUnbundlingJobClass)
57    return;
58
59  assert((OffloadingDeviceKind == OKind || OffloadingDeviceKind == OFK_None) &&
60         "Setting device kind to a different device??");
61  assert(!ActiveOffloadKindMask && "Setting a device kind in a host action??");
62  OffloadingDeviceKind = OKind;
63  OffloadingArch = OArch;
64
65  for (auto *A : Inputs)
66    A->propagateDeviceOffloadInfo(OffloadingDeviceKind, OArch);
67}
68
69void Action::propagateHostOffloadInfo(unsigned OKinds, const char *OArch) {
70  // Offload action set its own kinds on their dependences.
71  if (Kind == OffloadClass)
72    return;
73
74  assert(OffloadingDeviceKind == OFK_None &&
75         "Setting a host kind in a device action.");
76  ActiveOffloadKindMask |= OKinds;
77  OffloadingArch = OArch;
78
79  for (auto *A : Inputs)
80    A->propagateHostOffloadInfo(ActiveOffloadKindMask, OArch);
81}
82
83void Action::propagateOffloadInfo(const Action *A) {
84  if (unsigned HK = A->getOffloadingHostActiveKinds())
85    propagateHostOffloadInfo(HK, A->getOffloadingArch());
86  else
87    propagateDeviceOffloadInfo(A->getOffloadingDeviceKind(),
88                               A->getOffloadingArch());
89}
90
91std::string Action::getOffloadingKindPrefix() const {
92  switch (OffloadingDeviceKind) {
93  case OFK_None:
94    break;
95  case OFK_Host:
96    llvm_unreachable("Host kind is not an offloading device kind.");
97    break;
98  case OFK_Cuda:
99    return "device-cuda";
100  case OFK_OpenMP:
101    return "device-openmp";
102  case OFK_HIP:
103    return "device-hip";
104
105    // TODO: Add other programming models here.
106  }
107
108  if (!ActiveOffloadKindMask)
109    return {};
110
111  std::string Res("host");
112  assert(!((ActiveOffloadKindMask & OFK_Cuda) &&
113           (ActiveOffloadKindMask & OFK_HIP)) &&
114         "Cannot offload CUDA and HIP at the same time");
115  if (ActiveOffloadKindMask & OFK_Cuda)
116    Res += "-cuda";
117  if (ActiveOffloadKindMask & OFK_HIP)
118    Res += "-hip";
119  if (ActiveOffloadKindMask & OFK_OpenMP)
120    Res += "-openmp";
121
122  // TODO: Add other programming models here.
123
124  return Res;
125}
126
127/// Return a string that can be used as prefix in order to generate unique files
128/// for each offloading kind.
129std::string
130Action::GetOffloadingFileNamePrefix(OffloadKind Kind,
131                                    StringRef NormalizedTriple,
132                                    bool CreatePrefixForHost) {
133  // Don't generate prefix for host actions unless required.
134  if (!CreatePrefixForHost && (Kind == OFK_None || Kind == OFK_Host))
135    return {};
136
137  std::string Res("-");
138  Res += GetOffloadKindName(Kind);
139  Res += "-";
140  Res += NormalizedTriple;
141  return Res;
142}
143
144/// Return a string with the offload kind name. If that is not defined, we
145/// assume 'host'.
146StringRef Action::GetOffloadKindName(OffloadKind Kind) {
147  switch (Kind) {
148  case OFK_None:
149  case OFK_Host:
150    return "host";
151  case OFK_Cuda:
152    return "cuda";
153  case OFK_OpenMP:
154    return "openmp";
155  case OFK_HIP:
156    return "hip";
157
158    // TODO: Add other programming models here.
159  }
160
161  llvm_unreachable("invalid offload kind");
162}
163
164void InputAction::anchor() {}
165
166InputAction::InputAction(const Arg &_Input, types::ID _Type)
167    : Action(InputClass, _Type), Input(_Input) {}
168
169void BindArchAction::anchor() {}
170
171BindArchAction::BindArchAction(Action *Input, StringRef ArchName)
172    : Action(BindArchClass, Input), ArchName(ArchName) {}
173
174void OffloadAction::anchor() {}
175
176OffloadAction::OffloadAction(const HostDependence &HDep)
177    : Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()) {
178  OffloadingArch = HDep.getBoundArch();
179  ActiveOffloadKindMask = HDep.getOffloadKinds();
180  HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(),
181                                             HDep.getBoundArch());
182}
183
184OffloadAction::OffloadAction(const DeviceDependences &DDeps, types::ID Ty)
185    : Action(OffloadClass, DDeps.getActions(), Ty),
186      DevToolChains(DDeps.getToolChains()) {
187  auto &OKinds = DDeps.getOffloadKinds();
188  auto &BArchs = DDeps.getBoundArchs();
189
190  // If all inputs agree on the same kind, use it also for this action.
191  if (llvm::all_of(OKinds, [&](OffloadKind K) { return K == OKinds.front(); }))
192    OffloadingDeviceKind = OKinds.front();
193
194  // If we have a single dependency, inherit the architecture from it.
195  if (OKinds.size() == 1)
196    OffloadingArch = BArchs.front();
197
198  // Propagate info to the dependencies.
199  for (unsigned i = 0, e = getInputs().size(); i != e; ++i)
200    getInputs()[i]->propagateDeviceOffloadInfo(OKinds[i], BArchs[i]);
201}
202
203OffloadAction::OffloadAction(const HostDependence &HDep,
204                             const DeviceDependences &DDeps)
205    : Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()),
206      DevToolChains(DDeps.getToolChains()) {
207  // We use the kinds of the host dependence for this action.
208  OffloadingArch = HDep.getBoundArch();
209  ActiveOffloadKindMask = HDep.getOffloadKinds();
210  HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(),
211                                             HDep.getBoundArch());
212
213  // Add device inputs and propagate info to the device actions. Do work only if
214  // we have dependencies.
215  for (unsigned i = 0, e = DDeps.getActions().size(); i != e; ++i)
216    if (auto *A = DDeps.getActions()[i]) {
217      getInputs().push_back(A);
218      A->propagateDeviceOffloadInfo(DDeps.getOffloadKinds()[i],
219                                    DDeps.getBoundArchs()[i]);
220    }
221}
222
223void OffloadAction::doOnHostDependence(const OffloadActionWorkTy &Work) const {
224  if (!HostTC)
225    return;
226  assert(!getInputs().empty() && "No dependencies for offload action??");
227  auto *A = getInputs().front();
228  Work(A, HostTC, A->getOffloadingArch());
229}
230
231void OffloadAction::doOnEachDeviceDependence(
232    const OffloadActionWorkTy &Work) const {
233  auto I = getInputs().begin();
234  auto E = getInputs().end();
235  if (I == E)
236    return;
237
238  // We expect to have the same number of input dependences and device tool
239  // chains, except if we also have a host dependence. In that case we have one
240  // more dependence than we have device tool chains.
241  assert(getInputs().size() == DevToolChains.size() + (HostTC ? 1 : 0) &&
242         "Sizes of action dependences and toolchains are not consistent!");
243
244  // Skip host action
245  if (HostTC)
246    ++I;
247
248  auto TI = DevToolChains.begin();
249  for (; I != E; ++I, ++TI)
250    Work(*I, *TI, (*I)->getOffloadingArch());
251}
252
253void OffloadAction::doOnEachDependence(const OffloadActionWorkTy &Work) const {
254  doOnHostDependence(Work);
255  doOnEachDeviceDependence(Work);
256}
257
258void OffloadAction::doOnEachDependence(bool IsHostDependence,
259                                       const OffloadActionWorkTy &Work) const {
260  if (IsHostDependence)
261    doOnHostDependence(Work);
262  else
263    doOnEachDeviceDependence(Work);
264}
265
266bool OffloadAction::hasHostDependence() const { return HostTC != nullptr; }
267
268Action *OffloadAction::getHostDependence() const {
269  assert(hasHostDependence() && "Host dependence does not exist!");
270  assert(!getInputs().empty() && "No dependencies for offload action??");
271  return HostTC ? getInputs().front() : nullptr;
272}
273
274bool OffloadAction::hasSingleDeviceDependence(
275    bool DoNotConsiderHostActions) const {
276  if (DoNotConsiderHostActions)
277    return getInputs().size() == (HostTC ? 2 : 1);
278  return !HostTC && getInputs().size() == 1;
279}
280
281Action *
282OffloadAction::getSingleDeviceDependence(bool DoNotConsiderHostActions) const {
283  assert(hasSingleDeviceDependence(DoNotConsiderHostActions) &&
284         "Single device dependence does not exist!");
285  // The previous assert ensures the number of entries in getInputs() is
286  // consistent with what we are doing here.
287  return HostTC ? getInputs()[1] : getInputs().front();
288}
289
290void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC,
291                                           const char *BoundArch,
292                                           OffloadKind OKind) {
293  DeviceActions.push_back(&A);
294  DeviceToolChains.push_back(&TC);
295  DeviceBoundArchs.push_back(BoundArch);
296  DeviceOffloadKinds.push_back(OKind);
297}
298
299OffloadAction::HostDependence::HostDependence(Action &A, const ToolChain &TC,
300                                              const char *BoundArch,
301                                              const DeviceDependences &DDeps)
302    : HostAction(A), HostToolChain(TC), HostBoundArch(BoundArch) {
303  for (auto K : DDeps.getOffloadKinds())
304    HostOffloadKinds |= K;
305}
306
307void JobAction::anchor() {}
308
309JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type)
310    : Action(Kind, Input, Type) {}
311
312JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
313    : Action(Kind, Inputs, Type) {}
314
315void PreprocessJobAction::anchor() {}
316
317PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType)
318    : JobAction(PreprocessJobClass, Input, OutputType) {}
319
320void PrecompileJobAction::anchor() {}
321
322PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType)
323    : JobAction(PrecompileJobClass, Input, OutputType) {}
324
325PrecompileJobAction::PrecompileJobAction(ActionClass Kind, Action *Input,
326                                         types::ID OutputType)
327    : JobAction(Kind, Input, OutputType) {
328  assert(isa<PrecompileJobAction>((Action*)this) && "invalid action kind");
329}
330
331void HeaderModulePrecompileJobAction::anchor() {}
332
333HeaderModulePrecompileJobAction::HeaderModulePrecompileJobAction(
334    Action *Input, types::ID OutputType, const char *ModuleName)
335    : PrecompileJobAction(HeaderModulePrecompileJobClass, Input, OutputType),
336      ModuleName(ModuleName) {}
337
338void AnalyzeJobAction::anchor() {}
339
340AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)
341    : JobAction(AnalyzeJobClass, Input, OutputType) {}
342
343void MigrateJobAction::anchor() {}
344
345MigrateJobAction::MigrateJobAction(Action *Input, types::ID OutputType)
346    : JobAction(MigrateJobClass, Input, OutputType) {}
347
348void CompileJobAction::anchor() {}
349
350CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType)
351    : JobAction(CompileJobClass, Input, OutputType) {}
352
353void BackendJobAction::anchor() {}
354
355BackendJobAction::BackendJobAction(Action *Input, types::ID OutputType)
356    : JobAction(BackendJobClass, Input, OutputType) {}
357
358void AssembleJobAction::anchor() {}
359
360AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)
361    : JobAction(AssembleJobClass, Input, OutputType) {}
362
363void IfsMergeJobAction::anchor() {}
364
365IfsMergeJobAction::IfsMergeJobAction(ActionList &Inputs, types::ID Type)
366    : JobAction(IfsMergeJobClass, Inputs, Type) {}
367
368void LinkJobAction::anchor() {}
369
370LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type)
371    : JobAction(LinkJobClass, Inputs, Type) {}
372
373void LipoJobAction::anchor() {}
374
375LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type)
376    : JobAction(LipoJobClass, Inputs, Type) {}
377
378void DsymutilJobAction::anchor() {}
379
380DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type)
381    : JobAction(DsymutilJobClass, Inputs, Type) {}
382
383void VerifyJobAction::anchor() {}
384
385VerifyJobAction::VerifyJobAction(ActionClass Kind, Action *Input,
386                                 types::ID Type)
387    : JobAction(Kind, Input, Type) {
388  assert((Kind == VerifyDebugInfoJobClass || Kind == VerifyPCHJobClass) &&
389         "ActionClass is not a valid VerifyJobAction");
390}
391
392void VerifyDebugInfoJobAction::anchor() {}
393
394VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(Action *Input,
395                                                   types::ID Type)
396    : VerifyJobAction(VerifyDebugInfoJobClass, Input, Type) {}
397
398void VerifyPCHJobAction::anchor() {}
399
400VerifyPCHJobAction::VerifyPCHJobAction(Action *Input, types::ID Type)
401    : VerifyJobAction(VerifyPCHJobClass, Input, Type) {}
402
403void OffloadBundlingJobAction::anchor() {}
404
405OffloadBundlingJobAction::OffloadBundlingJobAction(ActionList &Inputs)
406    : JobAction(OffloadBundlingJobClass, Inputs, Inputs.back()->getType()) {}
407
408void OffloadUnbundlingJobAction::anchor() {}
409
410OffloadUnbundlingJobAction::OffloadUnbundlingJobAction(Action *Input)
411    : JobAction(OffloadUnbundlingJobClass, Input, Input->getType()) {}
412
413void OffloadWrapperJobAction::anchor() {}
414
415OffloadWrapperJobAction::OffloadWrapperJobAction(ActionList &Inputs,
416                                                 types::ID Type)
417  : JobAction(OffloadWrapperJobClass, Inputs, Type) {}
418