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