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