1 //===- Action.cpp - Abstract compilation steps ----------------------------===// 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 #include "clang/Driver/Action.h" 10 #include "llvm/Support/ErrorHandling.h" 11 #include <cassert> 12 #include <string> 13 14 using namespace clang; 15 using namespace driver; 16 using namespace llvm::opt; 17 18 Action::~Action() = default; 19 20 const char *Action::getClassName(ActionClass AC) { 21 switch (AC) { 22 case InputClass: return "input"; 23 case BindArchClass: return "bind-arch"; 24 case OffloadClass: 25 return "offload"; 26 case PreprocessJobClass: return "preprocessor"; 27 case PrecompileJobClass: return "precompiler"; 28 case ExtractAPIJobClass: 29 return "api-extractor"; 30 case AnalyzeJobClass: return "analyzer"; 31 case MigrateJobClass: return "migrator"; 32 case CompileJobClass: return "compiler"; 33 case BackendJobClass: return "backend"; 34 case AssembleJobClass: return "assembler"; 35 case InstallAPIJobClass: 36 return "installapi"; 37 case IfsMergeJobClass: return "interface-stub-merger"; 38 case LinkJobClass: return "linker"; 39 case LipoJobClass: return "lipo"; 40 case DsymutilJobClass: return "dsymutil"; 41 case VerifyDebugInfoJobClass: return "verify-debug-info"; 42 case VerifyPCHJobClass: return "verify-pch"; 43 case OffloadBundlingJobClass: 44 return "clang-offload-bundler"; 45 case OffloadUnbundlingJobClass: 46 return "clang-offload-unbundler"; 47 case OffloadPackagerJobClass: 48 return "clang-offload-packager"; 49 case LinkerWrapperJobClass: 50 return "clang-linker-wrapper"; 51 case StaticLibJobClass: 52 return "static-lib-linker"; 53 case BinaryAnalyzeJobClass: 54 return "binary-analyzer"; 55 } 56 57 llvm_unreachable("invalid class"); 58 } 59 60 void Action::propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch, 61 const ToolChain *OToolChain) { 62 // Offload action set its own kinds on their dependences. 63 if (Kind == OffloadClass) 64 return; 65 // Unbundling actions use the host kinds. 66 if (Kind == OffloadUnbundlingJobClass) 67 return; 68 69 assert((OffloadingDeviceKind == OKind || OffloadingDeviceKind == OFK_None) && 70 "Setting device kind to a different device??"); 71 assert(!ActiveOffloadKindMask && "Setting a device kind in a host action??"); 72 OffloadingDeviceKind = OKind; 73 OffloadingArch = OArch; 74 OffloadingToolChain = OToolChain; 75 76 for (auto *A : Inputs) 77 A->propagateDeviceOffloadInfo(OffloadingDeviceKind, OArch, OToolChain); 78 } 79 80 void Action::propagateHostOffloadInfo(unsigned OKinds, const char *OArch) { 81 // Offload action set its own kinds on their dependences. 82 if (Kind == OffloadClass) 83 return; 84 85 assert(OffloadingDeviceKind == OFK_None && 86 "Setting a host kind in a device action."); 87 ActiveOffloadKindMask |= OKinds; 88 OffloadingArch = OArch; 89 90 for (auto *A : Inputs) 91 A->propagateHostOffloadInfo(ActiveOffloadKindMask, OArch); 92 } 93 94 void Action::propagateOffloadInfo(const Action *A) { 95 if (unsigned HK = A->getOffloadingHostActiveKinds()) 96 propagateHostOffloadInfo(HK, A->getOffloadingArch()); 97 else 98 propagateDeviceOffloadInfo(A->getOffloadingDeviceKind(), 99 A->getOffloadingArch(), 100 A->getOffloadingToolChain()); 101 } 102 103 std::string Action::getOffloadingKindPrefix() const { 104 switch (OffloadingDeviceKind) { 105 case OFK_None: 106 break; 107 case OFK_Host: 108 llvm_unreachable("Host kind is not an offloading device kind."); 109 break; 110 case OFK_Cuda: 111 return "device-cuda"; 112 case OFK_OpenMP: 113 return "device-openmp"; 114 case OFK_HIP: 115 return "device-hip"; 116 117 // TODO: Add other programming models here. 118 } 119 120 if (!ActiveOffloadKindMask) 121 return {}; 122 123 std::string Res("host"); 124 assert(!((ActiveOffloadKindMask & OFK_Cuda) && 125 (ActiveOffloadKindMask & OFK_HIP)) && 126 "Cannot offload CUDA and HIP at the same time"); 127 if (ActiveOffloadKindMask & OFK_Cuda) 128 Res += "-cuda"; 129 if (ActiveOffloadKindMask & OFK_HIP) 130 Res += "-hip"; 131 if (ActiveOffloadKindMask & OFK_OpenMP) 132 Res += "-openmp"; 133 134 // TODO: Add other programming models here. 135 136 return Res; 137 } 138 139 /// Return a string that can be used as prefix in order to generate unique files 140 /// for each offloading kind. 141 std::string 142 Action::GetOffloadingFileNamePrefix(OffloadKind Kind, 143 StringRef NormalizedTriple, 144 bool CreatePrefixForHost) { 145 // Don't generate prefix for host actions unless required. 146 if (!CreatePrefixForHost && (Kind == OFK_None || Kind == OFK_Host)) 147 return {}; 148 149 std::string Res("-"); 150 Res += GetOffloadKindName(Kind); 151 Res += "-"; 152 Res += NormalizedTriple; 153 return Res; 154 } 155 156 /// Return a string with the offload kind name. If that is not defined, we 157 /// assume 'host'. 158 StringRef Action::GetOffloadKindName(OffloadKind Kind) { 159 switch (Kind) { 160 case OFK_None: 161 case OFK_Host: 162 return "host"; 163 case OFK_Cuda: 164 return "cuda"; 165 case OFK_OpenMP: 166 return "openmp"; 167 case OFK_HIP: 168 return "hip"; 169 170 // TODO: Add other programming models here. 171 } 172 173 llvm_unreachable("invalid offload kind"); 174 } 175 176 void InputAction::anchor() {} 177 178 InputAction::InputAction(const Arg &_Input, types::ID _Type, StringRef _Id) 179 : Action(InputClass, _Type), Input(_Input), Id(_Id.str()) {} 180 181 void BindArchAction::anchor() {} 182 183 BindArchAction::BindArchAction(Action *Input, StringRef ArchName) 184 : Action(BindArchClass, Input), ArchName(ArchName) {} 185 186 void OffloadAction::anchor() {} 187 188 OffloadAction::OffloadAction(const HostDependence &HDep) 189 : Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()) { 190 OffloadingArch = HDep.getBoundArch(); 191 ActiveOffloadKindMask = HDep.getOffloadKinds(); 192 HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(), 193 HDep.getBoundArch()); 194 } 195 196 OffloadAction::OffloadAction(const DeviceDependences &DDeps, types::ID Ty) 197 : Action(OffloadClass, DDeps.getActions(), Ty), 198 DevToolChains(DDeps.getToolChains()) { 199 auto &OKinds = DDeps.getOffloadKinds(); 200 auto &BArchs = DDeps.getBoundArchs(); 201 auto &OTCs = DDeps.getToolChains(); 202 203 // If all inputs agree on the same kind, use it also for this action. 204 if (llvm::all_equal(OKinds)) 205 OffloadingDeviceKind = OKinds.front(); 206 207 // If we have a single dependency, inherit the architecture from it. 208 if (OKinds.size() == 1) 209 OffloadingArch = BArchs.front(); 210 211 // Propagate info to the dependencies. 212 for (unsigned i = 0, e = getInputs().size(); i != e; ++i) 213 getInputs()[i]->propagateDeviceOffloadInfo(OKinds[i], BArchs[i], OTCs[i]); 214 } 215 216 OffloadAction::OffloadAction(const HostDependence &HDep, 217 const DeviceDependences &DDeps) 218 : Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()), 219 DevToolChains(DDeps.getToolChains()) { 220 // We use the kinds of the host dependence for this action. 221 OffloadingArch = HDep.getBoundArch(); 222 ActiveOffloadKindMask = HDep.getOffloadKinds(); 223 HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(), 224 HDep.getBoundArch()); 225 226 // Add device inputs and propagate info to the device actions. Do work only if 227 // we have dependencies. 228 for (unsigned i = 0, e = DDeps.getActions().size(); i != e; ++i) { 229 if (auto *A = DDeps.getActions()[i]) { 230 getInputs().push_back(A); 231 A->propagateDeviceOffloadInfo(DDeps.getOffloadKinds()[i], 232 DDeps.getBoundArchs()[i], 233 DDeps.getToolChains()[i]); 234 // If this action is used to forward single dependency, set the toolchain. 235 if (DDeps.getActions().size() == 1) 236 OffloadingToolChain = DDeps.getToolChains()[i]; 237 } 238 } 239 } 240 241 void OffloadAction::doOnHostDependence(const OffloadActionWorkTy &Work) const { 242 if (!HostTC) 243 return; 244 assert(!getInputs().empty() && "No dependencies for offload action??"); 245 auto *A = getInputs().front(); 246 Work(A, HostTC, A->getOffloadingArch()); 247 } 248 249 void OffloadAction::doOnEachDeviceDependence( 250 const OffloadActionWorkTy &Work) const { 251 auto I = getInputs().begin(); 252 auto E = getInputs().end(); 253 if (I == E) 254 return; 255 256 // We expect to have the same number of input dependences and device tool 257 // chains, except if we also have a host dependence. In that case we have one 258 // more dependence than we have device tool chains. 259 assert(getInputs().size() == DevToolChains.size() + (HostTC ? 1 : 0) && 260 "Sizes of action dependences and toolchains are not consistent!"); 261 262 // Skip host action 263 if (HostTC) 264 ++I; 265 266 auto TI = DevToolChains.begin(); 267 for (; I != E; ++I, ++TI) 268 Work(*I, *TI, (*I)->getOffloadingArch()); 269 } 270 271 void OffloadAction::doOnEachDependence(const OffloadActionWorkTy &Work) const { 272 doOnHostDependence(Work); 273 doOnEachDeviceDependence(Work); 274 } 275 276 void OffloadAction::doOnEachDependence(bool IsHostDependence, 277 const OffloadActionWorkTy &Work) const { 278 if (IsHostDependence) 279 doOnHostDependence(Work); 280 else 281 doOnEachDeviceDependence(Work); 282 } 283 284 bool OffloadAction::hasHostDependence() const { return HostTC != nullptr; } 285 286 Action *OffloadAction::getHostDependence() const { 287 assert(hasHostDependence() && "Host dependence does not exist!"); 288 assert(!getInputs().empty() && "No dependencies for offload action??"); 289 return HostTC ? getInputs().front() : nullptr; 290 } 291 292 bool OffloadAction::hasSingleDeviceDependence( 293 bool DoNotConsiderHostActions) const { 294 if (DoNotConsiderHostActions) 295 return getInputs().size() == (HostTC ? 2 : 1); 296 return !HostTC && getInputs().size() == 1; 297 } 298 299 Action * 300 OffloadAction::getSingleDeviceDependence(bool DoNotConsiderHostActions) const { 301 assert(hasSingleDeviceDependence(DoNotConsiderHostActions) && 302 "Single device dependence does not exist!"); 303 // The previous assert ensures the number of entries in getInputs() is 304 // consistent with what we are doing here. 305 return HostTC ? getInputs()[1] : getInputs().front(); 306 } 307 308 void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC, 309 const char *BoundArch, 310 OffloadKind OKind) { 311 DeviceActions.push_back(&A); 312 DeviceToolChains.push_back(&TC); 313 DeviceBoundArchs.push_back(BoundArch); 314 DeviceOffloadKinds.push_back(OKind); 315 } 316 317 void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC, 318 const char *BoundArch, 319 unsigned OffloadKindMask) { 320 DeviceActions.push_back(&A); 321 DeviceToolChains.push_back(&TC); 322 DeviceBoundArchs.push_back(BoundArch); 323 324 // Add each active offloading kind from a mask. 325 for (OffloadKind OKind : {OFK_OpenMP, OFK_Cuda, OFK_HIP}) 326 if (OKind & OffloadKindMask) 327 DeviceOffloadKinds.push_back(OKind); 328 } 329 330 OffloadAction::HostDependence::HostDependence(Action &A, const ToolChain &TC, 331 const char *BoundArch, 332 const DeviceDependences &DDeps) 333 : HostAction(A), HostToolChain(TC), HostBoundArch(BoundArch) { 334 for (auto K : DDeps.getOffloadKinds()) 335 HostOffloadKinds |= K; 336 } 337 338 void JobAction::anchor() {} 339 340 JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type) 341 : Action(Kind, Input, Type) {} 342 343 JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type) 344 : Action(Kind, Inputs, Type) {} 345 346 void PreprocessJobAction::anchor() {} 347 348 PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType) 349 : JobAction(PreprocessJobClass, Input, OutputType) {} 350 351 void PrecompileJobAction::anchor() {} 352 353 PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType) 354 : JobAction(PrecompileJobClass, Input, OutputType) {} 355 356 PrecompileJobAction::PrecompileJobAction(ActionClass Kind, Action *Input, 357 types::ID OutputType) 358 : JobAction(Kind, Input, OutputType) { 359 assert(isa<PrecompileJobAction>((Action*)this) && "invalid action kind"); 360 } 361 362 void ExtractAPIJobAction::anchor() {} 363 364 ExtractAPIJobAction::ExtractAPIJobAction(Action *Inputs, types::ID OutputType) 365 : JobAction(ExtractAPIJobClass, Inputs, OutputType) {} 366 367 void InstallAPIJobAction::anchor() {} 368 369 InstallAPIJobAction::InstallAPIJobAction(Action *Inputs, types::ID OutputType) 370 : JobAction(InstallAPIJobClass, Inputs, OutputType) {} 371 372 void AnalyzeJobAction::anchor() {} 373 374 AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType) 375 : JobAction(AnalyzeJobClass, Input, OutputType) {} 376 377 void MigrateJobAction::anchor() {} 378 379 MigrateJobAction::MigrateJobAction(Action *Input, types::ID OutputType) 380 : JobAction(MigrateJobClass, Input, OutputType) {} 381 382 void CompileJobAction::anchor() {} 383 384 CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType) 385 : JobAction(CompileJobClass, Input, OutputType) {} 386 387 void BackendJobAction::anchor() {} 388 389 BackendJobAction::BackendJobAction(Action *Input, types::ID OutputType) 390 : JobAction(BackendJobClass, Input, OutputType) {} 391 392 void AssembleJobAction::anchor() {} 393 394 AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType) 395 : JobAction(AssembleJobClass, Input, OutputType) {} 396 397 void IfsMergeJobAction::anchor() {} 398 399 IfsMergeJobAction::IfsMergeJobAction(ActionList &Inputs, types::ID Type) 400 : JobAction(IfsMergeJobClass, Inputs, Type) {} 401 402 void LinkJobAction::anchor() {} 403 404 LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type) 405 : JobAction(LinkJobClass, Inputs, Type) {} 406 407 void LipoJobAction::anchor() {} 408 409 LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type) 410 : JobAction(LipoJobClass, Inputs, Type) {} 411 412 void DsymutilJobAction::anchor() {} 413 414 DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type) 415 : JobAction(DsymutilJobClass, Inputs, Type) {} 416 417 void VerifyJobAction::anchor() {} 418 419 VerifyJobAction::VerifyJobAction(ActionClass Kind, Action *Input, 420 types::ID Type) 421 : JobAction(Kind, Input, Type) { 422 assert((Kind == VerifyDebugInfoJobClass || Kind == VerifyPCHJobClass) && 423 "ActionClass is not a valid VerifyJobAction"); 424 } 425 426 void VerifyDebugInfoJobAction::anchor() {} 427 428 VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(Action *Input, 429 types::ID Type) 430 : VerifyJobAction(VerifyDebugInfoJobClass, Input, Type) {} 431 432 void VerifyPCHJobAction::anchor() {} 433 434 VerifyPCHJobAction::VerifyPCHJobAction(Action *Input, types::ID Type) 435 : VerifyJobAction(VerifyPCHJobClass, Input, Type) {} 436 437 void OffloadBundlingJobAction::anchor() {} 438 439 OffloadBundlingJobAction::OffloadBundlingJobAction(ActionList &Inputs) 440 : JobAction(OffloadBundlingJobClass, Inputs, Inputs.back()->getType()) {} 441 442 void OffloadUnbundlingJobAction::anchor() {} 443 444 OffloadUnbundlingJobAction::OffloadUnbundlingJobAction(Action *Input) 445 : JobAction(OffloadUnbundlingJobClass, Input, Input->getType()) {} 446 447 void OffloadPackagerJobAction::anchor() {} 448 449 OffloadPackagerJobAction::OffloadPackagerJobAction(ActionList &Inputs, 450 types::ID Type) 451 : JobAction(OffloadPackagerJobClass, Inputs, Type) {} 452 453 void LinkerWrapperJobAction::anchor() {} 454 455 LinkerWrapperJobAction::LinkerWrapperJobAction(ActionList &Inputs, 456 types::ID Type) 457 : JobAction(LinkerWrapperJobClass, Inputs, Type) {} 458 459 void StaticLibJobAction::anchor() {} 460 461 StaticLibJobAction::StaticLibJobAction(ActionList &Inputs, types::ID Type) 462 : JobAction(StaticLibJobClass, Inputs, Type) {} 463 464 void BinaryAnalyzeJobAction::anchor() {} 465 466 BinaryAnalyzeJobAction::BinaryAnalyzeJobAction(Action *Input, types::ID Type) 467 : JobAction(BinaryAnalyzeJobClass, Input, Type) {} 468