1//===- Action.h - Abstract compilation steps --------------------*- C++ -*-===//
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#ifndef LLVM_CLANG_DRIVER_ACTION_H
10#define LLVM_CLANG_DRIVER_ACTION_H
11
12#include "clang/Basic/LLVM.h"
13#include "clang/Driver/Types.h"
14#include "clang/Driver/Util.h"
15#include "llvm/ADT/ArrayRef.h"
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/ADT/SmallVector.h"
18#include "llvm/ADT/StringRef.h"
19#include "llvm/ADT/iterator_range.h"
20#include <string>
21
22namespace llvm {
23namespace opt {
24
25class Arg;
26
27} // namespace opt
28} // namespace llvm
29
30namespace clang {
31namespace driver {
32
33class ToolChain;
34
35/// Action - Represent an abstract compilation step to perform.
36///
37/// An action represents an edge in the compilation graph; typically
38/// it is a job to transform an input using some tool.
39///
40/// The current driver is hard wired to expect actions which produce a
41/// single primary output, at least in terms of controlling the
42/// compilation. Actions can produce auxiliary files, but can only
43/// produce a single output to feed into subsequent actions.
44///
45/// Actions are usually owned by a Compilation, which creates new
46/// actions via MakeAction().
47class Action {
48public:
49 using size_type = ActionList::size_type;
50 using input_iterator = ActionList::iterator;
51 using input_const_iterator = ActionList::const_iterator;
52 using input_range = llvm::iterator_range<input_iterator>;
53 using input_const_range = llvm::iterator_range<input_const_iterator>;
54
55 enum ActionClass {
56 InputClass = 0,
57 BindArchClass,
58 OffloadClass,
59 PreprocessJobClass,
60 PrecompileJobClass,
61 ExtractAPIJobClass,
62 InstallAPIJobClass,
63 AnalyzeJobClass,
64 MigrateJobClass,
65 CompileJobClass,
66 BackendJobClass,
67 AssembleJobClass,
68 LinkJobClass,
69 IfsMergeJobClass,
70 LipoJobClass,
71 DsymutilJobClass,
72 VerifyDebugInfoJobClass,
73 VerifyPCHJobClass,
74 OffloadBundlingJobClass,
75 OffloadUnbundlingJobClass,
76 OffloadPackagerJobClass,
77 LinkerWrapperJobClass,
78 StaticLibJobClass,
79 BinaryAnalyzeJobClass,
80
81 JobClassFirst = PreprocessJobClass,
82 JobClassLast = BinaryAnalyzeJobClass
83 };
84
85 // The offloading kind determines if this action is binded to a particular
86 // programming model. Each entry reserves one bit. We also have a special kind
87 // to designate the host offloading tool chain.
88 enum OffloadKind {
89 OFK_None = 0x00,
90
91 // The host offloading tool chain.
92 OFK_Host = 0x01,
93
94 // The device offloading tool chains - one bit for each programming model.
95 OFK_Cuda = 0x02,
96 OFK_OpenMP = 0x04,
97 OFK_HIP = 0x08,
98 };
99
100 static const char *getClassName(ActionClass AC);
101
102private:
103 ActionClass Kind;
104
105 /// The output type of this action.
106 types::ID Type;
107
108 ActionList Inputs;
109
110 /// Flag that is set to true if this action can be collapsed with others
111 /// actions that depend on it. This is true by default and set to false when
112 /// the action is used by two different tool chains, which is enabled by the
113 /// offloading support implementation.
114 bool CanBeCollapsedWithNextDependentAction = true;
115
116protected:
117 ///
118 /// Offload information.
119 ///
120
121 /// The host offloading kind - a combination of kinds encoded in a mask.
122 /// Multiple programming models may be supported simultaneously by the same
123 /// host.
124 unsigned ActiveOffloadKindMask = 0u;
125
126 /// Offloading kind of the device.
127 OffloadKind OffloadingDeviceKind = OFK_None;
128
129 /// The Offloading architecture associated with this action.
130 const char *OffloadingArch = nullptr;
131
132 /// The Offloading toolchain associated with this device action.
133 const ToolChain *OffloadingToolChain = nullptr;
134
135 Action(ActionClass Kind, types::ID Type) : Action(Kind, ActionList(), Type) {}
136 Action(ActionClass Kind, Action *Input, types::ID Type)
137 : Action(Kind, ActionList({Input}), Type) {}
138 Action(ActionClass Kind, Action *Input)
139 : Action(Kind, ActionList({Input}), Input->getType()) {}
140 Action(ActionClass Kind, const ActionList &Inputs, types::ID Type)
141 : Kind(Kind), Type(Type), Inputs(Inputs) {}
142
143public:
144 virtual ~Action();
145
146 const char *getClassName() const { return Action::getClassName(AC: getKind()); }
147
148 ActionClass getKind() const { return Kind; }
149 types::ID getType() const { return Type; }
150
151 ActionList &getInputs() { return Inputs; }
152 const ActionList &getInputs() const { return Inputs; }
153
154 size_type size() const { return Inputs.size(); }
155
156 input_iterator input_begin() { return Inputs.begin(); }
157 input_iterator input_end() { return Inputs.end(); }
158 input_range inputs() { return input_range(input_begin(), input_end()); }
159 input_const_iterator input_begin() const { return Inputs.begin(); }
160 input_const_iterator input_end() const { return Inputs.end(); }
161 input_const_range inputs() const {
162 return input_const_range(input_begin(), input_end());
163 }
164
165 /// Mark this action as not legal to collapse.
166 void setCannotBeCollapsedWithNextDependentAction() {
167 CanBeCollapsedWithNextDependentAction = false;
168 }
169
170 /// Return true if this function can be collapsed with others.
171 bool isCollapsingWithNextDependentActionLegal() const {
172 return CanBeCollapsedWithNextDependentAction;
173 }
174
175 /// Return a string containing the offload kind of the action.
176 std::string getOffloadingKindPrefix() const;
177
178 /// Return a string that can be used as prefix in order to generate unique
179 /// files for each offloading kind. By default, no prefix is used for
180 /// non-device kinds, except if \a CreatePrefixForHost is set.
181 static std::string
182 GetOffloadingFileNamePrefix(OffloadKind Kind,
183 StringRef NormalizedTriple,
184 bool CreatePrefixForHost = false);
185
186 /// Return a string containing a offload kind name.
187 static StringRef GetOffloadKindName(OffloadKind Kind);
188
189 /// Set the device offload info of this action and propagate it to its
190 /// dependences.
191 void propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch,
192 const ToolChain *OToolChain);
193
194 /// Append the host offload info of this action and propagate it to its
195 /// dependences.
196 void propagateHostOffloadInfo(unsigned OKinds, const char *OArch);
197
198 void setHostOffloadInfo(unsigned OKinds, const char *OArch) {
199 ActiveOffloadKindMask |= OKinds;
200 OffloadingArch = OArch;
201 }
202
203 /// Set the offload info of this action to be the same as the provided action,
204 /// and propagate it to its dependences.
205 void propagateOffloadInfo(const Action *A);
206
207 unsigned getOffloadingHostActiveKinds() const {
208 return ActiveOffloadKindMask;
209 }
210
211 OffloadKind getOffloadingDeviceKind() const { return OffloadingDeviceKind; }
212 const char *getOffloadingArch() const { return OffloadingArch; }
213 const ToolChain *getOffloadingToolChain() const {
214 return OffloadingToolChain;
215 }
216
217 /// Check if this action have any offload kinds. Note that host offload kinds
218 /// are only set if the action is a dependence to a host offload action.
219 bool isHostOffloading(unsigned int OKind) const {
220 return ActiveOffloadKindMask & OKind;
221 }
222 bool isDeviceOffloading(OffloadKind OKind) const {
223 return OffloadingDeviceKind == OKind;
224 }
225 bool isOffloading(OffloadKind OKind) const {
226 return isHostOffloading(OKind) || isDeviceOffloading(OKind);
227 }
228};
229
230class InputAction : public Action {
231 const llvm::opt::Arg &Input;
232 std::string Id;
233 virtual void anchor();
234
235public:
236 InputAction(const llvm::opt::Arg &Input, types::ID Type,
237 StringRef Id = StringRef());
238
239 const llvm::opt::Arg &getInputArg() const { return Input; }
240
241 void setId(StringRef _Id) { Id = _Id.str(); }
242 StringRef getId() const { return Id; }
243
244 static bool classof(const Action *A) {
245 return A->getKind() == InputClass;
246 }
247};
248
249class BindArchAction : public Action {
250 virtual void anchor();
251
252 /// The architecture to bind, or 0 if the default architecture
253 /// should be bound.
254 StringRef ArchName;
255
256public:
257 BindArchAction(Action *Input, StringRef ArchName);
258
259 StringRef getArchName() const { return ArchName; }
260
261 static bool classof(const Action *A) {
262 return A->getKind() == BindArchClass;
263 }
264};
265
266/// An offload action combines host or/and device actions according to the
267/// programming model implementation needs and propagates the offloading kind to
268/// its dependences.
269class OffloadAction final : public Action {
270 virtual void anchor();
271
272public:
273 /// Type used to communicate device actions. It associates bound architecture,
274 /// toolchain, and offload kind to each action.
275 class DeviceDependences final {
276 public:
277 using ToolChainList = SmallVector<const ToolChain *, 3>;
278 using BoundArchList = SmallVector<const char *, 3>;
279 using OffloadKindList = SmallVector<OffloadKind, 3>;
280
281 private:
282 // Lists that keep the information for each dependency. All the lists are
283 // meant to be updated in sync. We are adopting separate lists instead of a
284 // list of structs, because that simplifies forwarding the actions list to
285 // initialize the inputs of the base Action class.
286
287 /// The dependence actions.
288 ActionList DeviceActions;
289
290 /// The offloading toolchains that should be used with the action.
291 ToolChainList DeviceToolChains;
292
293 /// The architectures that should be used with this action.
294 BoundArchList DeviceBoundArchs;
295
296 /// The offload kind of each dependence.
297 OffloadKindList DeviceOffloadKinds;
298
299 public:
300 /// Add an action along with the associated toolchain, bound arch, and
301 /// offload kind.
302 void add(Action &A, const ToolChain &TC, const char *BoundArch,
303 OffloadKind OKind);
304
305 /// Add an action along with the associated toolchain, bound arch, and
306 /// offload kinds.
307 void add(Action &A, const ToolChain &TC, const char *BoundArch,
308 unsigned OffloadKindMask);
309
310 /// Get each of the individual arrays.
311 const ActionList &getActions() const { return DeviceActions; }
312 const ToolChainList &getToolChains() const { return DeviceToolChains; }
313 const BoundArchList &getBoundArchs() const { return DeviceBoundArchs; }
314 const OffloadKindList &getOffloadKinds() const {
315 return DeviceOffloadKinds;
316 }
317 };
318
319 /// Type used to communicate host actions. It associates bound architecture,
320 /// toolchain, and offload kinds to the host action.
321 class HostDependence final {
322 /// The dependence action.
323 Action &HostAction;
324
325 /// The offloading toolchain that should be used with the action.
326 const ToolChain &HostToolChain;
327
328 /// The architectures that should be used with this action.
329 const char *HostBoundArch = nullptr;
330
331 /// The offload kind of each dependence.
332 unsigned HostOffloadKinds = 0u;
333
334 public:
335 HostDependence(Action &A, const ToolChain &TC, const char *BoundArch,
336 const unsigned OffloadKinds)
337 : HostAction(A), HostToolChain(TC), HostBoundArch(BoundArch),
338 HostOffloadKinds(OffloadKinds) {}
339
340 /// Constructor version that obtains the offload kinds from the device
341 /// dependencies.
342 HostDependence(Action &A, const ToolChain &TC, const char *BoundArch,
343 const DeviceDependences &DDeps);
344 Action *getAction() const { return &HostAction; }
345 const ToolChain *getToolChain() const { return &HostToolChain; }
346 const char *getBoundArch() const { return HostBoundArch; }
347 unsigned getOffloadKinds() const { return HostOffloadKinds; }
348 };
349
350 using OffloadActionWorkTy =
351 llvm::function_ref<void(Action *, const ToolChain *, const char *)>;
352
353private:
354 /// The host offloading toolchain that should be used with the action.
355 const ToolChain *HostTC = nullptr;
356
357 /// The tool chains associated with the list of actions.
358 DeviceDependences::ToolChainList DevToolChains;
359
360public:
361 OffloadAction(const HostDependence &HDep);
362 OffloadAction(const DeviceDependences &DDeps, types::ID Ty);
363 OffloadAction(const HostDependence &HDep, const DeviceDependences &DDeps);
364
365 /// Execute the work specified in \a Work on the host dependence.
366 void doOnHostDependence(const OffloadActionWorkTy &Work) const;
367
368 /// Execute the work specified in \a Work on each device dependence.
369 void doOnEachDeviceDependence(const OffloadActionWorkTy &Work) const;
370
371 /// Execute the work specified in \a Work on each dependence.
372 void doOnEachDependence(const OffloadActionWorkTy &Work) const;
373
374 /// Execute the work specified in \a Work on each host or device dependence if
375 /// \a IsHostDependenceto is true or false, respectively.
376 void doOnEachDependence(bool IsHostDependence,
377 const OffloadActionWorkTy &Work) const;
378
379 /// Return true if the action has a host dependence.
380 bool hasHostDependence() const;
381
382 /// Return the host dependence of this action. This function is only expected
383 /// to be called if the host dependence exists.
384 Action *getHostDependence() const;
385
386 /// Return true if the action has a single device dependence. If \a
387 /// DoNotConsiderHostActions is set, ignore the host dependence, if any, while
388 /// accounting for the number of dependences.
389 bool hasSingleDeviceDependence(bool DoNotConsiderHostActions = false) const;
390
391 /// Return the single device dependence of this action. This function is only
392 /// expected to be called if a single device dependence exists. If \a
393 /// DoNotConsiderHostActions is set, a host dependence is allowed.
394 Action *
395 getSingleDeviceDependence(bool DoNotConsiderHostActions = false) const;
396
397 static bool classof(const Action *A) { return A->getKind() == OffloadClass; }
398};
399
400class JobAction : public Action {
401 virtual void anchor();
402
403protected:
404 JobAction(ActionClass Kind, Action *Input, types::ID Type);
405 JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type);
406
407public:
408 static bool classof(const Action *A) {
409 return (A->getKind() >= JobClassFirst &&
410 A->getKind() <= JobClassLast);
411 }
412};
413
414class PreprocessJobAction : public JobAction {
415 void anchor() override;
416
417public:
418 PreprocessJobAction(Action *Input, types::ID OutputType);
419
420 static bool classof(const Action *A) {
421 return A->getKind() == PreprocessJobClass;
422 }
423};
424
425class PrecompileJobAction : public JobAction {
426 void anchor() override;
427
428protected:
429 PrecompileJobAction(ActionClass Kind, Action *Input, types::ID OutputType);
430
431public:
432 PrecompileJobAction(Action *Input, types::ID OutputType);
433
434 static bool classof(const Action *A) {
435 return A->getKind() == PrecompileJobClass;
436 }
437};
438
439class ExtractAPIJobAction : public JobAction {
440 void anchor() override;
441
442public:
443 ExtractAPIJobAction(Action *Input, types::ID OutputType);
444
445 static bool classof(const Action *A) {
446 return A->getKind() == ExtractAPIJobClass;
447 }
448
449 void addHeaderInput(Action *Input) { getInputs().push_back(Elt: Input); }
450};
451
452class InstallAPIJobAction : public JobAction {
453 void anchor() override;
454
455public:
456 InstallAPIJobAction(Action *Input, types::ID OutputType);
457
458 static bool classof(const Action *A) {
459 return A->getKind() == InstallAPIJobClass;
460 }
461};
462
463class AnalyzeJobAction : public JobAction {
464 void anchor() override;
465
466public:
467 AnalyzeJobAction(Action *Input, types::ID OutputType);
468
469 static bool classof(const Action *A) {
470 return A->getKind() == AnalyzeJobClass;
471 }
472};
473
474class MigrateJobAction : public JobAction {
475 void anchor() override;
476
477public:
478 MigrateJobAction(Action *Input, types::ID OutputType);
479
480 static bool classof(const Action *A) {
481 return A->getKind() == MigrateJobClass;
482 }
483};
484
485class CompileJobAction : public JobAction {
486 void anchor() override;
487
488public:
489 CompileJobAction(Action *Input, types::ID OutputType);
490
491 static bool classof(const Action *A) {
492 return A->getKind() == CompileJobClass;
493 }
494};
495
496class BackendJobAction : public JobAction {
497 void anchor() override;
498
499public:
500 BackendJobAction(Action *Input, types::ID OutputType);
501
502 static bool classof(const Action *A) {
503 return A->getKind() == BackendJobClass;
504 }
505};
506
507class AssembleJobAction : public JobAction {
508 void anchor() override;
509
510public:
511 AssembleJobAction(Action *Input, types::ID OutputType);
512
513 static bool classof(const Action *A) {
514 return A->getKind() == AssembleJobClass;
515 }
516};
517
518class IfsMergeJobAction : public JobAction {
519 void anchor() override;
520
521public:
522 IfsMergeJobAction(ActionList &Inputs, types::ID Type);
523
524 static bool classof(const Action *A) {
525 return A->getKind() == IfsMergeJobClass;
526 }
527};
528
529class LinkJobAction : public JobAction {
530 void anchor() override;
531
532public:
533 LinkJobAction(ActionList &Inputs, types::ID Type);
534
535 static bool classof(const Action *A) {
536 return A->getKind() == LinkJobClass;
537 }
538};
539
540class LipoJobAction : public JobAction {
541 void anchor() override;
542
543public:
544 LipoJobAction(ActionList &Inputs, types::ID Type);
545
546 static bool classof(const Action *A) {
547 return A->getKind() == LipoJobClass;
548 }
549};
550
551class DsymutilJobAction : public JobAction {
552 void anchor() override;
553
554public:
555 DsymutilJobAction(ActionList &Inputs, types::ID Type);
556
557 static bool classof(const Action *A) {
558 return A->getKind() == DsymutilJobClass;
559 }
560};
561
562class VerifyJobAction : public JobAction {
563 void anchor() override;
564
565public:
566 VerifyJobAction(ActionClass Kind, Action *Input, types::ID Type);
567
568 static bool classof(const Action *A) {
569 return A->getKind() == VerifyDebugInfoJobClass ||
570 A->getKind() == VerifyPCHJobClass;
571 }
572};
573
574class VerifyDebugInfoJobAction : public VerifyJobAction {
575 void anchor() override;
576
577public:
578 VerifyDebugInfoJobAction(Action *Input, types::ID Type);
579
580 static bool classof(const Action *A) {
581 return A->getKind() == VerifyDebugInfoJobClass;
582 }
583};
584
585class VerifyPCHJobAction : public VerifyJobAction {
586 void anchor() override;
587
588public:
589 VerifyPCHJobAction(Action *Input, types::ID Type);
590
591 static bool classof(const Action *A) {
592 return A->getKind() == VerifyPCHJobClass;
593 }
594};
595
596class OffloadBundlingJobAction : public JobAction {
597 void anchor() override;
598
599public:
600 // Offloading bundling doesn't change the type of output.
601 OffloadBundlingJobAction(ActionList &Inputs);
602
603 static bool classof(const Action *A) {
604 return A->getKind() == OffloadBundlingJobClass;
605 }
606};
607
608class OffloadUnbundlingJobAction final : public JobAction {
609 void anchor() override;
610
611public:
612 /// Type that provides information about the actions that depend on this
613 /// unbundling action.
614 struct DependentActionInfo final {
615 /// The tool chain of the dependent action.
616 const ToolChain *DependentToolChain = nullptr;
617
618 /// The bound architecture of the dependent action.
619 StringRef DependentBoundArch;
620
621 /// The offload kind of the dependent action.
622 const OffloadKind DependentOffloadKind = OFK_None;
623
624 DependentActionInfo(const ToolChain *DependentToolChain,
625 StringRef DependentBoundArch,
626 const OffloadKind DependentOffloadKind)
627 : DependentToolChain(DependentToolChain),
628 DependentBoundArch(DependentBoundArch),
629 DependentOffloadKind(DependentOffloadKind) {}
630 };
631
632private:
633 /// Container that keeps information about each dependence of this unbundling
634 /// action.
635 SmallVector<DependentActionInfo, 6> DependentActionInfoArray;
636
637public:
638 // Offloading unbundling doesn't change the type of output.
639 OffloadUnbundlingJobAction(Action *Input);
640
641 /// Register information about a dependent action.
642 void registerDependentActionInfo(const ToolChain *TC, StringRef BoundArch,
643 OffloadKind Kind) {
644 DependentActionInfoArray.push_back(Elt: {TC, BoundArch, Kind});
645 }
646
647 /// Return the information about all depending actions.
648 ArrayRef<DependentActionInfo> getDependentActionsInfo() const {
649 return DependentActionInfoArray;
650 }
651
652 static bool classof(const Action *A) {
653 return A->getKind() == OffloadUnbundlingJobClass;
654 }
655};
656
657class OffloadPackagerJobAction : public JobAction {
658 void anchor() override;
659
660public:
661 OffloadPackagerJobAction(ActionList &Inputs, types::ID Type);
662
663 static bool classof(const Action *A) {
664 return A->getKind() == OffloadPackagerJobClass;
665 }
666};
667
668class LinkerWrapperJobAction : public JobAction {
669 void anchor() override;
670
671public:
672 LinkerWrapperJobAction(ActionList &Inputs, types::ID Type);
673
674 static bool classof(const Action *A) {
675 return A->getKind() == LinkerWrapperJobClass;
676 }
677};
678
679class StaticLibJobAction : public JobAction {
680 void anchor() override;
681
682public:
683 StaticLibJobAction(ActionList &Inputs, types::ID Type);
684
685 static bool classof(const Action *A) {
686 return A->getKind() == StaticLibJobClass;
687 }
688};
689
690class BinaryAnalyzeJobAction : public JobAction {
691 void anchor() override;
692
693public:
694 BinaryAnalyzeJobAction(Action *Input, types::ID Type);
695
696 static bool classof(const Action *A) {
697 return A->getKind() == BinaryAnalyzeJobClass;
698 }
699};
700
701} // namespace driver
702} // namespace clang
703
704#endif // LLVM_CLANG_DRIVER_ACTION_H
705

source code of clang/include/clang/Driver/Action.h