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