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