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

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of clang/lib/Driver/Action.cpp