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