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