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