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