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