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