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