xref: /freebsd/contrib/llvm-project/clang/lib/Driver/Action.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
getClassName(ActionClass AC)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:
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 
propagateDeviceOffloadInfo(OffloadKind OKind,const char * OArch,const ToolChain * OToolChain)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 
propagateHostOffloadInfo(unsigned OKinds,const char * OArch)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 
propagateOffloadInfo(const Action * A)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 
getOffloadingKindPrefix() const103 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   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.
145 std::string
GetOffloadingFileNamePrefix(OffloadKind Kind,StringRef NormalizedTriple,bool CreatePrefixForHost)146 Action::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'.
GetOffloadKindName(OffloadKind Kind)162 StringRef 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 
anchor()182 void InputAction::anchor() {}
183 
InputAction(const Arg & _Input,types::ID _Type,StringRef _Id)184 InputAction::InputAction(const Arg &_Input, types::ID _Type, StringRef _Id)
185     : Action(InputClass, _Type), Input(_Input), Id(_Id.str()) {}
186 
anchor()187 void BindArchAction::anchor() {}
188 
BindArchAction(Action * Input,StringRef ArchName)189 BindArchAction::BindArchAction(Action *Input, StringRef ArchName)
190     : Action(BindArchClass, Input), ArchName(ArchName) {}
191 
anchor()192 void OffloadAction::anchor() {}
193 
OffloadAction(const HostDependence & HDep)194 OffloadAction::OffloadAction(const HostDependence &HDep)
195     : Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()) {
196   OffloadingArch = HDep.getBoundArch();
197   ActiveOffloadKindMask = HDep.getOffloadKinds();
198   HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(),
199                                              HDep.getBoundArch());
200 }
201 
OffloadAction(const DeviceDependences & DDeps,types::ID Ty)202 OffloadAction::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(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(OKinds[i], BArchs[i], OTCs[i]);
220 }
221 
OffloadAction(const HostDependence & HDep,const DeviceDependences & DDeps)222 OffloadAction::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(HDep.getOffloadKinds(),
230                                              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(A);
237       A->propagateDeviceOffloadInfo(DDeps.getOffloadKinds()[i],
238                                     DDeps.getBoundArchs()[i],
239                                     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 
doOnHostDependence(const OffloadActionWorkTy & Work) const247 void 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 
doOnEachDeviceDependence(const OffloadActionWorkTy & Work) const255 void 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 
doOnEachDependence(const OffloadActionWorkTy & Work) const277 void OffloadAction::doOnEachDependence(const OffloadActionWorkTy &Work) const {
278   doOnHostDependence(Work);
279   doOnEachDeviceDependence(Work);
280 }
281 
doOnEachDependence(bool IsHostDependence,const OffloadActionWorkTy & Work) const282 void OffloadAction::doOnEachDependence(bool IsHostDependence,
283                                        const OffloadActionWorkTy &Work) const {
284   if (IsHostDependence)
285     doOnHostDependence(Work);
286   else
287     doOnEachDeviceDependence(Work);
288 }
289 
hasHostDependence() const290 bool OffloadAction::hasHostDependence() const { return HostTC != nullptr; }
291 
getHostDependence() const292 Action *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 
hasSingleDeviceDependence(bool DoNotConsiderHostActions) const298 bool OffloadAction::hasSingleDeviceDependence(
299     bool DoNotConsiderHostActions) const {
300   if (DoNotConsiderHostActions)
301     return getInputs().size() == (HostTC ? 2 : 1);
302   return !HostTC && getInputs().size() == 1;
303 }
304 
305 Action *
getSingleDeviceDependence(bool DoNotConsiderHostActions) const306 OffloadAction::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 
add(Action & A,const ToolChain & TC,const char * BoundArch,OffloadKind OKind)314 void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC,
315                                            const char *BoundArch,
316                                            OffloadKind OKind) {
317   DeviceActions.push_back(&A);
318   DeviceToolChains.push_back(&TC);
319   DeviceBoundArchs.push_back(BoundArch);
320   DeviceOffloadKinds.push_back(OKind);
321 }
322 
add(Action & A,const ToolChain & TC,const char * BoundArch,unsigned OffloadKindMask)323 void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC,
324                                            const char *BoundArch,
325                                            unsigned OffloadKindMask) {
326   DeviceActions.push_back(&A);
327   DeviceToolChains.push_back(&TC);
328   DeviceBoundArchs.push_back(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(OKind);
334 }
335 
HostDependence(Action & A,const ToolChain & TC,const char * BoundArch,const DeviceDependences & DDeps)336 OffloadAction::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 
anchor()344 void JobAction::anchor() {}
345 
JobAction(ActionClass Kind,Action * Input,types::ID Type)346 JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type)
347     : Action(Kind, Input, Type) {}
348 
JobAction(ActionClass Kind,const ActionList & Inputs,types::ID Type)349 JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
350     : Action(Kind, Inputs, Type) {}
351 
anchor()352 void PreprocessJobAction::anchor() {}
353 
PreprocessJobAction(Action * Input,types::ID OutputType)354 PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType)
355     : JobAction(PreprocessJobClass, Input, OutputType) {}
356 
anchor()357 void PrecompileJobAction::anchor() {}
358 
PrecompileJobAction(Action * Input,types::ID OutputType)359 PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType)
360     : JobAction(PrecompileJobClass, Input, OutputType) {}
361 
PrecompileJobAction(ActionClass Kind,Action * Input,types::ID OutputType)362 PrecompileJobAction::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 
anchor()368 void ExtractAPIJobAction::anchor() {}
369 
ExtractAPIJobAction(Action * Inputs,types::ID OutputType)370 ExtractAPIJobAction::ExtractAPIJobAction(Action *Inputs, types::ID OutputType)
371     : JobAction(ExtractAPIJobClass, Inputs, OutputType) {}
372 
anchor()373 void AnalyzeJobAction::anchor() {}
374 
AnalyzeJobAction(Action * Input,types::ID OutputType)375 AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)
376     : JobAction(AnalyzeJobClass, Input, OutputType) {}
377 
anchor()378 void CompileJobAction::anchor() {}
379 
CompileJobAction(Action * Input,types::ID OutputType)380 CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType)
381     : JobAction(CompileJobClass, Input, OutputType) {}
382 
anchor()383 void BackendJobAction::anchor() {}
384 
BackendJobAction(Action * Input,types::ID OutputType)385 BackendJobAction::BackendJobAction(Action *Input, types::ID OutputType)
386     : JobAction(BackendJobClass, Input, OutputType) {}
387 
anchor()388 void AssembleJobAction::anchor() {}
389 
AssembleJobAction(Action * Input,types::ID OutputType)390 AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)
391     : JobAction(AssembleJobClass, Input, OutputType) {}
392 
anchor()393 void IfsMergeJobAction::anchor() {}
394 
IfsMergeJobAction(ActionList & Inputs,types::ID Type)395 IfsMergeJobAction::IfsMergeJobAction(ActionList &Inputs, types::ID Type)
396     : JobAction(IfsMergeJobClass, Inputs, Type) {}
397 
anchor()398 void LinkJobAction::anchor() {}
399 
LinkJobAction(ActionList & Inputs,types::ID Type)400 LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type)
401     : JobAction(LinkJobClass, Inputs, Type) {}
402 
anchor()403 void LipoJobAction::anchor() {}
404 
LipoJobAction(ActionList & Inputs,types::ID Type)405 LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type)
406     : JobAction(LipoJobClass, Inputs, Type) {}
407 
anchor()408 void DsymutilJobAction::anchor() {}
409 
DsymutilJobAction(ActionList & Inputs,types::ID Type)410 DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type)
411     : JobAction(DsymutilJobClass, Inputs, Type) {}
412 
anchor()413 void VerifyJobAction::anchor() {}
414 
VerifyJobAction(ActionClass Kind,Action * Input,types::ID Type)415 VerifyJobAction::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 
anchor()422 void VerifyDebugInfoJobAction::anchor() {}
423 
VerifyDebugInfoJobAction(Action * Input,types::ID Type)424 VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(Action *Input,
425                                                    types::ID Type)
426     : VerifyJobAction(VerifyDebugInfoJobClass, Input, Type) {}
427 
anchor()428 void VerifyPCHJobAction::anchor() {}
429 
VerifyPCHJobAction(Action * Input,types::ID Type)430 VerifyPCHJobAction::VerifyPCHJobAction(Action *Input, types::ID Type)
431     : VerifyJobAction(VerifyPCHJobClass, Input, Type) {}
432 
anchor()433 void OffloadBundlingJobAction::anchor() {}
434 
OffloadBundlingJobAction(ActionList & Inputs)435 OffloadBundlingJobAction::OffloadBundlingJobAction(ActionList &Inputs)
436     : JobAction(OffloadBundlingJobClass, Inputs, Inputs.back()->getType()) {}
437 
anchor()438 void OffloadUnbundlingJobAction::anchor() {}
439 
OffloadUnbundlingJobAction(Action * Input)440 OffloadUnbundlingJobAction::OffloadUnbundlingJobAction(Action *Input)
441     : JobAction(OffloadUnbundlingJobClass, Input, Input->getType()) {}
442 
anchor()443 void OffloadPackagerJobAction::anchor() {}
444 
OffloadPackagerJobAction(ActionList & Inputs,types::ID Type)445 OffloadPackagerJobAction::OffloadPackagerJobAction(ActionList &Inputs,
446                                                    types::ID Type)
447     : JobAction(OffloadPackagerJobClass, Inputs, Type) {}
448 
anchor()449 void LinkerWrapperJobAction::anchor() {}
450 
LinkerWrapperJobAction(ActionList & Inputs,types::ID Type)451 LinkerWrapperJobAction::LinkerWrapperJobAction(ActionList &Inputs,
452                                                types::ID Type)
453     : JobAction(LinkerWrapperJobClass, Inputs, Type) {}
454 
anchor()455 void StaticLibJobAction::anchor() {}
456 
StaticLibJobAction(ActionList & Inputs,types::ID Type)457 StaticLibJobAction::StaticLibJobAction(ActionList &Inputs, types::ID Type)
458     : JobAction(StaticLibJobClass, Inputs, Type) {}
459 
anchor()460 void BinaryAnalyzeJobAction::anchor() {}
461 
BinaryAnalyzeJobAction(Action * Input,types::ID Type)462 BinaryAnalyzeJobAction::BinaryAnalyzeJobAction(Action *Input, types::ID Type)
463     : JobAction(BinaryAnalyzeJobClass, Input, Type) {}
464 
anchor()465 void BinaryTranslatorJobAction::anchor() {}
466 
BinaryTranslatorJobAction(Action * Input,types::ID Type)467 BinaryTranslatorJobAction::BinaryTranslatorJobAction(Action *Input,
468                                                      types::ID Type)
469     : JobAction(BinaryTranslatorJobClass, Input, Type) {}
470