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