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