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 22 namespace llvm { 23 namespace opt { 24 25 class Arg; 26 27 } // namespace opt 28 } // namespace llvm 29 30 namespace clang { 31 namespace driver { 32 33 class 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(). 47 class Action { 48 public: 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 HeaderModulePrecompileJobClass, 62 ExtractAPIJobClass, 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 OffloadWrapperJobClass, 77 OffloadPackagerJobClass, 78 LinkerWrapperJobClass, 79 StaticLibJobClass, 80 81 JobClassFirst = PreprocessJobClass, 82 JobClassLast = StaticLibJobClass 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 102 private: 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 116 protected: 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 143 public: 144 virtual ~Action(); 145 146 const char *getClassName() const { return Action::getClassName(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 230 class InputAction : public Action { 231 const llvm::opt::Arg &Input; 232 std::string Id; 233 virtual void anchor(); 234 235 public: 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 249 class 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 256 public: 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. 269 class OffloadAction final : public Action { 270 virtual void anchor(); 271 272 public: 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 a 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 /// Get each of the individual arrays. 306 const ActionList &getActions() const { return DeviceActions; } 307 const ToolChainList &getToolChains() const { return DeviceToolChains; } 308 const BoundArchList &getBoundArchs() const { return DeviceBoundArchs; } 309 const OffloadKindList &getOffloadKinds() const { 310 return DeviceOffloadKinds; 311 } 312 }; 313 314 /// Type used to communicate host actions. It associates bound architecture, 315 /// toolchain, and offload kinds to the host action. 316 class HostDependence final { 317 /// The dependence action. 318 Action &HostAction; 319 320 /// The offloading toolchain that should be used with the action. 321 const ToolChain &HostToolChain; 322 323 /// The architectures that should be used with this action. 324 const char *HostBoundArch = nullptr; 325 326 /// The offload kind of each dependence. 327 unsigned HostOffloadKinds = 0u; 328 329 public: 330 HostDependence(Action &A, const ToolChain &TC, const char *BoundArch, 331 const unsigned OffloadKinds) 332 : HostAction(A), HostToolChain(TC), HostBoundArch(BoundArch), 333 HostOffloadKinds(OffloadKinds) {} 334 335 /// Constructor version that obtains the offload kinds from the device 336 /// dependencies. 337 HostDependence(Action &A, const ToolChain &TC, const char *BoundArch, 338 const DeviceDependences &DDeps); 339 Action *getAction() const { return &HostAction; } 340 const ToolChain *getToolChain() const { return &HostToolChain; } 341 const char *getBoundArch() const { return HostBoundArch; } 342 unsigned getOffloadKinds() const { return HostOffloadKinds; } 343 }; 344 345 using OffloadActionWorkTy = 346 llvm::function_ref<void(Action *, const ToolChain *, const char *)>; 347 348 private: 349 /// The host offloading toolchain that should be used with the action. 350 const ToolChain *HostTC = nullptr; 351 352 /// The tool chains associated with the list of actions. 353 DeviceDependences::ToolChainList DevToolChains; 354 355 public: 356 OffloadAction(const HostDependence &HDep); 357 OffloadAction(const DeviceDependences &DDeps, types::ID Ty); 358 OffloadAction(const HostDependence &HDep, const DeviceDependences &DDeps); 359 360 /// Execute the work specified in \a Work on the host dependence. 361 void doOnHostDependence(const OffloadActionWorkTy &Work) const; 362 363 /// Execute the work specified in \a Work on each device dependence. 364 void doOnEachDeviceDependence(const OffloadActionWorkTy &Work) const; 365 366 /// Execute the work specified in \a Work on each dependence. 367 void doOnEachDependence(const OffloadActionWorkTy &Work) const; 368 369 /// Execute the work specified in \a Work on each host or device dependence if 370 /// \a IsHostDependenceto is true or false, respectively. 371 void doOnEachDependence(bool IsHostDependence, 372 const OffloadActionWorkTy &Work) const; 373 374 /// Return true if the action has a host dependence. 375 bool hasHostDependence() const; 376 377 /// Return the host dependence of this action. This function is only expected 378 /// to be called if the host dependence exists. 379 Action *getHostDependence() const; 380 381 /// Return true if the action has a single device dependence. If \a 382 /// DoNotConsiderHostActions is set, ignore the host dependence, if any, while 383 /// accounting for the number of dependences. 384 bool hasSingleDeviceDependence(bool DoNotConsiderHostActions = false) const; 385 386 /// Return the single device dependence of this action. This function is only 387 /// expected to be called if a single device dependence exists. If \a 388 /// DoNotConsiderHostActions is set, a host dependence is allowed. 389 Action * 390 getSingleDeviceDependence(bool DoNotConsiderHostActions = false) const; 391 392 static bool classof(const Action *A) { return A->getKind() == OffloadClass; } 393 }; 394 395 class JobAction : public Action { 396 virtual void anchor(); 397 398 protected: 399 JobAction(ActionClass Kind, Action *Input, types::ID Type); 400 JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type); 401 402 public: 403 static bool classof(const Action *A) { 404 return (A->getKind() >= JobClassFirst && 405 A->getKind() <= JobClassLast); 406 } 407 }; 408 409 class PreprocessJobAction : public JobAction { 410 void anchor() override; 411 412 public: 413 PreprocessJobAction(Action *Input, types::ID OutputType); 414 415 static bool classof(const Action *A) { 416 return A->getKind() == PreprocessJobClass; 417 } 418 }; 419 420 class PrecompileJobAction : public JobAction { 421 void anchor() override; 422 423 protected: 424 PrecompileJobAction(ActionClass Kind, Action *Input, types::ID OutputType); 425 426 public: 427 PrecompileJobAction(Action *Input, types::ID OutputType); 428 429 static bool classof(const Action *A) { 430 return A->getKind() == PrecompileJobClass || 431 A->getKind() == HeaderModulePrecompileJobClass; 432 } 433 }; 434 435 class HeaderModulePrecompileJobAction : public PrecompileJobAction { 436 void anchor() override; 437 438 const char *ModuleName; 439 440 public: 441 HeaderModulePrecompileJobAction(Action *Input, types::ID OutputType, 442 const char *ModuleName); 443 444 static bool classof(const Action *A) { 445 return A->getKind() == HeaderModulePrecompileJobClass; 446 } 447 448 void addModuleHeaderInput(Action *Input) { 449 getInputs().push_back(Input); 450 } 451 452 const char *getModuleName() const { return ModuleName; } 453 }; 454 455 class ExtractAPIJobAction : public JobAction { 456 void anchor() override; 457 458 public: 459 ExtractAPIJobAction(Action *Input, types::ID OutputType); 460 461 static bool classof(const Action *A) { 462 return A->getKind() == ExtractAPIJobClass; 463 } 464 465 void addHeaderInput(Action *Input) { getInputs().push_back(Input); } 466 }; 467 468 class AnalyzeJobAction : public JobAction { 469 void anchor() override; 470 471 public: 472 AnalyzeJobAction(Action *Input, types::ID OutputType); 473 474 static bool classof(const Action *A) { 475 return A->getKind() == AnalyzeJobClass; 476 } 477 }; 478 479 class MigrateJobAction : public JobAction { 480 void anchor() override; 481 482 public: 483 MigrateJobAction(Action *Input, types::ID OutputType); 484 485 static bool classof(const Action *A) { 486 return A->getKind() == MigrateJobClass; 487 } 488 }; 489 490 class CompileJobAction : public JobAction { 491 void anchor() override; 492 493 public: 494 CompileJobAction(Action *Input, types::ID OutputType); 495 496 static bool classof(const Action *A) { 497 return A->getKind() == CompileJobClass; 498 } 499 }; 500 501 class BackendJobAction : public JobAction { 502 void anchor() override; 503 504 public: 505 BackendJobAction(Action *Input, types::ID OutputType); 506 507 static bool classof(const Action *A) { 508 return A->getKind() == BackendJobClass; 509 } 510 }; 511 512 class AssembleJobAction : public JobAction { 513 void anchor() override; 514 515 public: 516 AssembleJobAction(Action *Input, types::ID OutputType); 517 518 static bool classof(const Action *A) { 519 return A->getKind() == AssembleJobClass; 520 } 521 }; 522 523 class IfsMergeJobAction : public JobAction { 524 void anchor() override; 525 526 public: 527 IfsMergeJobAction(ActionList &Inputs, types::ID Type); 528 529 static bool classof(const Action *A) { 530 return A->getKind() == IfsMergeJobClass; 531 } 532 }; 533 534 class LinkJobAction : public JobAction { 535 void anchor() override; 536 537 public: 538 LinkJobAction(ActionList &Inputs, types::ID Type); 539 540 static bool classof(const Action *A) { 541 return A->getKind() == LinkJobClass; 542 } 543 }; 544 545 class LipoJobAction : public JobAction { 546 void anchor() override; 547 548 public: 549 LipoJobAction(ActionList &Inputs, types::ID Type); 550 551 static bool classof(const Action *A) { 552 return A->getKind() == LipoJobClass; 553 } 554 }; 555 556 class DsymutilJobAction : public JobAction { 557 void anchor() override; 558 559 public: 560 DsymutilJobAction(ActionList &Inputs, types::ID Type); 561 562 static bool classof(const Action *A) { 563 return A->getKind() == DsymutilJobClass; 564 } 565 }; 566 567 class VerifyJobAction : public JobAction { 568 void anchor() override; 569 570 public: 571 VerifyJobAction(ActionClass Kind, Action *Input, types::ID Type); 572 573 static bool classof(const Action *A) { 574 return A->getKind() == VerifyDebugInfoJobClass || 575 A->getKind() == VerifyPCHJobClass; 576 } 577 }; 578 579 class VerifyDebugInfoJobAction : public VerifyJobAction { 580 void anchor() override; 581 582 public: 583 VerifyDebugInfoJobAction(Action *Input, types::ID Type); 584 585 static bool classof(const Action *A) { 586 return A->getKind() == VerifyDebugInfoJobClass; 587 } 588 }; 589 590 class VerifyPCHJobAction : public VerifyJobAction { 591 void anchor() override; 592 593 public: 594 VerifyPCHJobAction(Action *Input, types::ID Type); 595 596 static bool classof(const Action *A) { 597 return A->getKind() == VerifyPCHJobClass; 598 } 599 }; 600 601 class OffloadBundlingJobAction : public JobAction { 602 void anchor() override; 603 604 public: 605 // Offloading bundling doesn't change the type of output. 606 OffloadBundlingJobAction(ActionList &Inputs); 607 608 static bool classof(const Action *A) { 609 return A->getKind() == OffloadBundlingJobClass; 610 } 611 }; 612 613 class OffloadUnbundlingJobAction final : public JobAction { 614 void anchor() override; 615 616 public: 617 /// Type that provides information about the actions that depend on this 618 /// unbundling action. 619 struct DependentActionInfo final { 620 /// The tool chain of the dependent action. 621 const ToolChain *DependentToolChain = nullptr; 622 623 /// The bound architecture of the dependent action. 624 StringRef DependentBoundArch; 625 626 /// The offload kind of the dependent action. 627 const OffloadKind DependentOffloadKind = OFK_None; 628 629 DependentActionInfo(const ToolChain *DependentToolChain, 630 StringRef DependentBoundArch, 631 const OffloadKind DependentOffloadKind) 632 : DependentToolChain(DependentToolChain), 633 DependentBoundArch(DependentBoundArch), 634 DependentOffloadKind(DependentOffloadKind) {} 635 }; 636 637 private: 638 /// Container that keeps information about each dependence of this unbundling 639 /// action. 640 SmallVector<DependentActionInfo, 6> DependentActionInfoArray; 641 642 public: 643 // Offloading unbundling doesn't change the type of output. 644 OffloadUnbundlingJobAction(Action *Input); 645 646 /// Register information about a dependent action. 647 void registerDependentActionInfo(const ToolChain *TC, StringRef BoundArch, 648 OffloadKind Kind) { 649 DependentActionInfoArray.push_back({TC, BoundArch, Kind}); 650 } 651 652 /// Return the information about all depending actions. 653 ArrayRef<DependentActionInfo> getDependentActionsInfo() const { 654 return DependentActionInfoArray; 655 } 656 657 static bool classof(const Action *A) { 658 return A->getKind() == OffloadUnbundlingJobClass; 659 } 660 }; 661 662 class OffloadWrapperJobAction : public JobAction { 663 void anchor() override; 664 665 public: 666 OffloadWrapperJobAction(ActionList &Inputs, types::ID Type); 667 668 static bool classof(const Action *A) { 669 return A->getKind() == OffloadWrapperJobClass; 670 } 671 }; 672 673 class OffloadPackagerJobAction : public JobAction { 674 void anchor() override; 675 676 public: 677 OffloadPackagerJobAction(ActionList &Inputs, types::ID Type); 678 679 static bool classof(const Action *A) { 680 return A->getKind() == OffloadPackagerJobClass; 681 } 682 }; 683 684 class LinkerWrapperJobAction : public JobAction { 685 void anchor() override; 686 687 public: 688 LinkerWrapperJobAction(ActionList &Inputs, types::ID Type); 689 690 static bool classof(const Action *A) { 691 return A->getKind() == LinkerWrapperJobClass; 692 } 693 }; 694 695 class StaticLibJobAction : public JobAction { 696 void anchor() override; 697 698 public: 699 StaticLibJobAction(ActionList &Inputs, types::ID Type); 700 701 static bool classof(const Action *A) { 702 return A->getKind() == StaticLibJobClass; 703 } 704 }; 705 706 } // namespace driver 707 } // namespace clang 708 709 #endif // LLVM_CLANG_DRIVER_ACTION_H 710