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