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