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