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