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