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