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