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