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