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