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