//===--- Action.h - Abstract compilation steps ------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_DRIVER_ACTION_H #define LLVM_CLANG_DRIVER_ACTION_H #include "clang/Basic/Cuda.h" #include "clang/Driver/Types.h" #include "clang/Driver/Util.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" namespace llvm { class StringRef; namespace opt { class Arg; } } namespace clang { namespace driver { class ToolChain; /// Action - Represent an abstract compilation step to perform. /// /// An action represents an edge in the compilation graph; typically /// it is a job to transform an input using some tool. /// /// The current driver is hard wired to expect actions which produce a /// single primary output, at least in terms of controlling the /// compilation. Actions can produce auxiliary files, but can only /// produce a single output to feed into subsequent actions. /// /// Actions are usually owned by a Compilation, which creates new /// actions via MakeAction(). class Action { public: typedef ActionList::size_type size_type; typedef ActionList::iterator input_iterator; typedef ActionList::const_iterator input_const_iterator; typedef llvm::iterator_range input_range; typedef llvm::iterator_range input_const_range; enum ActionClass { InputClass = 0, BindArchClass, OffloadClass, PreprocessJobClass, PrecompileJobClass, AnalyzeJobClass, MigrateJobClass, CompileJobClass, BackendJobClass, AssembleJobClass, LinkJobClass, LipoJobClass, DsymutilJobClass, VerifyDebugInfoJobClass, VerifyPCHJobClass, JobClassFirst = PreprocessJobClass, JobClassLast = VerifyPCHJobClass }; // The offloading kind determines if this action is binded to a particular // programming model. Each entry reserves one bit. We also have a special kind // to designate the host offloading tool chain. enum OffloadKind { OFK_None = 0x00, // The host offloading tool chain. OFK_Host = 0x01, // The device offloading tool chains - one bit for each programming model. OFK_Cuda = 0x02, }; static const char *getClassName(ActionClass AC); private: ActionClass Kind; /// The output type of this action. types::ID Type; ActionList Inputs; protected: /// /// Offload information. /// /// The host offloading kind - a combination of kinds encoded in a mask. /// Multiple programming models may be supported simultaneously by the same /// host. unsigned ActiveOffloadKindMask = 0u; /// Offloading kind of the device. OffloadKind OffloadingDeviceKind = OFK_None; /// The Offloading architecture associated with this action. const char *OffloadingArch = nullptr; Action(ActionClass Kind, types::ID Type) : Action(Kind, ActionList(), Type) {} Action(ActionClass Kind, Action *Input, types::ID Type) : Action(Kind, ActionList({Input}), Type) {} Action(ActionClass Kind, Action *Input) : Action(Kind, ActionList({Input}), Input->getType()) {} Action(ActionClass Kind, const ActionList &Inputs, types::ID Type) : Kind(Kind), Type(Type), Inputs(Inputs) {} public: virtual ~Action(); const char *getClassName() const { return Action::getClassName(getKind()); } ActionClass getKind() const { return Kind; } types::ID getType() const { return Type; } ActionList &getInputs() { return Inputs; } const ActionList &getInputs() const { return Inputs; } size_type size() const { return Inputs.size(); } input_iterator input_begin() { return Inputs.begin(); } input_iterator input_end() { return Inputs.end(); } input_range inputs() { return input_range(input_begin(), input_end()); } input_const_iterator input_begin() const { return Inputs.begin(); } input_const_iterator input_end() const { return Inputs.end(); } input_const_range inputs() const { return input_const_range(input_begin(), input_end()); } /// Return a string containing the offload kind of the action. std::string getOffloadingKindPrefix() const; /// Return a string that can be used as prefix in order to generate unique /// files for each offloading kind. std::string getOffloadingFileNamePrefix(llvm::StringRef NormalizedTriple) const; /// Set the device offload info of this action and propagate it to its /// dependences. void propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch); /// Append the host offload info of this action and propagate it to its /// dependences. void propagateHostOffloadInfo(unsigned OKinds, const char *OArch); /// Set the offload info of this action to be the same as the provided action, /// and propagate it to its dependences. void propagateOffloadInfo(const Action *A); unsigned getOffloadingHostActiveKinds() const { return ActiveOffloadKindMask; } OffloadKind getOffloadingDeviceKind() const { return OffloadingDeviceKind; } const char *getOffloadingArch() const { return OffloadingArch; } /// Check if this action have any offload kinds. Note that host offload kinds /// are only set if the action is a dependence to a host offload action. bool isHostOffloading(OffloadKind OKind) const { return ActiveOffloadKindMask & OKind; } bool isDeviceOffloading(OffloadKind OKind) const { return OffloadingDeviceKind == OKind; } bool isOffloading(OffloadKind OKind) const { return isHostOffloading(OKind) || isDeviceOffloading(OKind); } }; class InputAction : public Action { virtual void anchor(); const llvm::opt::Arg &Input; public: InputAction(const llvm::opt::Arg &Input, types::ID Type); const llvm::opt::Arg &getInputArg() const { return Input; } static bool classof(const Action *A) { return A->getKind() == InputClass; } }; class BindArchAction : public Action { virtual void anchor(); /// The architecture to bind, or 0 if the default architecture /// should be bound. const char *ArchName; public: BindArchAction(Action *Input, const char *ArchName); const char *getArchName() const { return ArchName; } static bool classof(const Action *A) { return A->getKind() == BindArchClass; } }; /// An offload action combines host or/and device actions according to the /// programming model implementation needs and propagates the offloading kind to /// its dependences. class OffloadAction final : public Action { virtual void anchor(); public: /// Type used to communicate device actions. It associates bound architecture, /// toolchain, and offload kind to each action. class DeviceDependences final { public: typedef SmallVector ToolChainList; typedef SmallVector BoundArchList; typedef SmallVector OffloadKindList; private: // Lists that keep the information for each dependency. All the lists are // meant to be updated in sync. We are adopting separate lists instead of a // list of structs, because that simplifies forwarding the actions list to // initialize the inputs of the base Action class. /// The dependence actions. ActionList DeviceActions; /// The offloading toolchains that should be used with the action. ToolChainList DeviceToolChains; /// The architectures that should be used with this action. BoundArchList DeviceBoundArchs; /// The offload kind of each dependence. OffloadKindList DeviceOffloadKinds; public: /// Add a action along with the associated toolchain, bound arch, and /// offload kind. void add(Action &A, const ToolChain &TC, const char *BoundArch, OffloadKind OKind); /// Get each of the individual arrays. const ActionList &getActions() const { return DeviceActions; }; const ToolChainList &getToolChains() const { return DeviceToolChains; }; const BoundArchList &getBoundArchs() const { return DeviceBoundArchs; }; const OffloadKindList &getOffloadKinds() const { return DeviceOffloadKinds; }; }; /// Type used to communicate host actions. It associates bound architecture, /// toolchain, and offload kinds to the host action. class HostDependence final { /// The dependence action. Action &HostAction; /// The offloading toolchain that should be used with the action. const ToolChain &HostToolChain; /// The architectures that should be used with this action. const char *HostBoundArch = nullptr; /// The offload kind of each dependence. unsigned HostOffloadKinds = 0u; public: HostDependence(Action &A, const ToolChain &TC, const char *BoundArch, const unsigned OffloadKinds) : HostAction(A), HostToolChain(TC), HostBoundArch(BoundArch), HostOffloadKinds(OffloadKinds){}; /// Constructor version that obtains the offload kinds from the device /// dependencies. HostDependence(Action &A, const ToolChain &TC, const char *BoundArch, const DeviceDependences &DDeps); Action *getAction() const { return &HostAction; }; const ToolChain *getToolChain() const { return &HostToolChain; }; const char *getBoundArch() const { return HostBoundArch; }; unsigned getOffloadKinds() const { return HostOffloadKinds; }; }; typedef llvm::function_ref OffloadActionWorkTy; private: /// The host offloading toolchain that should be used with the action. const ToolChain *HostTC = nullptr; /// The tool chains associated with the list of actions. DeviceDependences::ToolChainList DevToolChains; public: OffloadAction(const HostDependence &HDep); OffloadAction(const DeviceDependences &DDeps, types::ID Ty); OffloadAction(const HostDependence &HDep, const DeviceDependences &DDeps); /// Execute the work specified in \a Work on the host dependence. void doOnHostDependence(const OffloadActionWorkTy &Work) const; /// Execute the work specified in \a Work on each device dependence. void doOnEachDeviceDependence(const OffloadActionWorkTy &Work) const; /// Execute the work specified in \a Work on each dependence. void doOnEachDependence(const OffloadActionWorkTy &Work) const; /// Execute the work specified in \a Work on each host or device dependence if /// \a IsHostDependenceto is true or false, respectively. void doOnEachDependence(bool IsHostDependence, const OffloadActionWorkTy &Work) const; /// Return true if the action has a host dependence. bool hasHostDependence() const; /// Return the host dependence of this action. This function is only expected /// to be called if the host dependence exists. Action *getHostDependence() const; /// Return true if the action has a single device dependence. If \a /// DoNotConsiderHostActions is set, ignore the host dependence, if any, while /// accounting for the number of dependences. bool hasSingleDeviceDependence(bool DoNotConsiderHostActions = false) const; /// Return the single device dependence of this action. This function is only /// expected to be called if a single device dependence exists. If \a /// DoNotConsiderHostActions is set, a host dependence is allowed. Action * getSingleDeviceDependence(bool DoNotConsiderHostActions = false) const; static bool classof(const Action *A) { return A->getKind() == OffloadClass; } }; class JobAction : public Action { virtual void anchor(); protected: JobAction(ActionClass Kind, Action *Input, types::ID Type); JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type); public: static bool classof(const Action *A) { return (A->getKind() >= JobClassFirst && A->getKind() <= JobClassLast); } }; class PreprocessJobAction : public JobAction { void anchor() override; public: PreprocessJobAction(Action *Input, types::ID OutputType); static bool classof(const Action *A) { return A->getKind() == PreprocessJobClass; } }; class PrecompileJobAction : public JobAction { void anchor() override; public: PrecompileJobAction(Action *Input, types::ID OutputType); static bool classof(const Action *A) { return A->getKind() == PrecompileJobClass; } }; class AnalyzeJobAction : public JobAction { void anchor() override; public: AnalyzeJobAction(Action *Input, types::ID OutputType); static bool classof(const Action *A) { return A->getKind() == AnalyzeJobClass; } }; class MigrateJobAction : public JobAction { void anchor() override; public: MigrateJobAction(Action *Input, types::ID OutputType); static bool classof(const Action *A) { return A->getKind() == MigrateJobClass; } }; class CompileJobAction : public JobAction { void anchor() override; public: CompileJobAction(Action *Input, types::ID OutputType); static bool classof(const Action *A) { return A->getKind() == CompileJobClass; } }; class BackendJobAction : public JobAction { void anchor() override; public: BackendJobAction(Action *Input, types::ID OutputType); static bool classof(const Action *A) { return A->getKind() == BackendJobClass; } }; class AssembleJobAction : public JobAction { void anchor() override; public: AssembleJobAction(Action *Input, types::ID OutputType); static bool classof(const Action *A) { return A->getKind() == AssembleJobClass; } }; class LinkJobAction : public JobAction { void anchor() override; public: LinkJobAction(ActionList &Inputs, types::ID Type); static bool classof(const Action *A) { return A->getKind() == LinkJobClass; } }; class LipoJobAction : public JobAction { void anchor() override; public: LipoJobAction(ActionList &Inputs, types::ID Type); static bool classof(const Action *A) { return A->getKind() == LipoJobClass; } }; class DsymutilJobAction : public JobAction { void anchor() override; public: DsymutilJobAction(ActionList &Inputs, types::ID Type); static bool classof(const Action *A) { return A->getKind() == DsymutilJobClass; } }; class VerifyJobAction : public JobAction { void anchor() override; public: VerifyJobAction(ActionClass Kind, Action *Input, types::ID Type); static bool classof(const Action *A) { return A->getKind() == VerifyDebugInfoJobClass || A->getKind() == VerifyPCHJobClass; } }; class VerifyDebugInfoJobAction : public VerifyJobAction { void anchor() override; public: VerifyDebugInfoJobAction(Action *Input, types::ID Type); static bool classof(const Action *A) { return A->getKind() == VerifyDebugInfoJobClass; } }; class VerifyPCHJobAction : public VerifyJobAction { void anchor() override; public: VerifyPCHJobAction(Action *Input, types::ID Type); static bool classof(const Action *A) { return A->getKind() == VerifyPCHJobClass; } }; } // end namespace driver } // end namespace clang #endif