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