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