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