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