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