1 //===--- Cuda.cpp - Cuda Tool and ToolChain Implementations -----*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "Cuda.h" 11 #include "InputInfo.h" 12 #include "clang/Basic/Cuda.h" 13 #include "clang/Basic/VirtualFileSystem.h" 14 #include "clang/Driver/Compilation.h" 15 #include "clang/Driver/Driver.h" 16 #include "clang/Driver/DriverDiagnostic.h" 17 #include "clang/Driver/Options.h" 18 #include "llvm/Option/ArgList.h" 19 #include "llvm/Support/Path.h" 20 #include <system_error> 21 22 using namespace clang::driver; 23 using namespace clang::driver::toolchains; 24 using namespace clang::driver::tools; 25 using namespace clang; 26 using namespace llvm::opt; 27 28 // Parses the contents of version.txt in an CUDA installation. It should 29 // contain one line of the from e.g. "CUDA Version 7.5.2". 30 static CudaVersion ParseCudaVersionFile(llvm::StringRef V) { 31 if (!V.startswith("CUDA Version ")) 32 return CudaVersion::UNKNOWN; 33 V = V.substr(strlen("CUDA Version ")); 34 int Major = -1, Minor = -1; 35 auto First = V.split('.'); 36 auto Second = First.second.split('.'); 37 if (First.first.getAsInteger(10, Major) || 38 Second.first.getAsInteger(10, Minor)) 39 return CudaVersion::UNKNOWN; 40 41 if (Major == 7 && Minor == 0) { 42 // This doesn't appear to ever happen -- version.txt doesn't exist in the 43 // CUDA 7 installs I've seen. But no harm in checking. 44 return CudaVersion::CUDA_70; 45 } 46 if (Major == 7 && Minor == 5) 47 return CudaVersion::CUDA_75; 48 if (Major == 8 && Minor == 0) 49 return CudaVersion::CUDA_80; 50 return CudaVersion::UNKNOWN; 51 } 52 53 CudaInstallationDetector::CudaInstallationDetector( 54 const Driver &D, const llvm::Triple &HostTriple, 55 const llvm::opt::ArgList &Args) 56 : D(D) { 57 SmallVector<std::string, 4> CudaPathCandidates; 58 59 // In decreasing order so we prefer newer versions to older versions. 60 std::initializer_list<const char *> Versions = {"8.0", "7.5", "7.0"}; 61 62 if (Args.hasArg(clang::driver::options::OPT_cuda_path_EQ)) { 63 CudaPathCandidates.push_back( 64 Args.getLastArgValue(clang::driver::options::OPT_cuda_path_EQ)); 65 } else if (HostTriple.isOSWindows()) { 66 for (const char *Ver : Versions) 67 CudaPathCandidates.push_back( 68 D.SysRoot + "/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v" + 69 Ver); 70 } else { 71 CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda"); 72 for (const char *Ver : Versions) 73 CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-" + Ver); 74 } 75 76 for (const auto &CudaPath : CudaPathCandidates) { 77 if (CudaPath.empty() || !D.getVFS().exists(CudaPath)) 78 continue; 79 80 InstallPath = CudaPath; 81 BinPath = CudaPath + "/bin"; 82 IncludePath = InstallPath + "/include"; 83 LibDevicePath = InstallPath + "/nvvm/libdevice"; 84 85 auto &FS = D.getVFS(); 86 if (!(FS.exists(IncludePath) && FS.exists(BinPath) && 87 FS.exists(LibDevicePath))) 88 continue; 89 90 // On Linux, we have both lib and lib64 directories, and we need to choose 91 // based on our triple. On MacOS, we have only a lib directory. 92 // 93 // It's sufficient for our purposes to be flexible: If both lib and lib64 94 // exist, we choose whichever one matches our triple. Otherwise, if only 95 // lib exists, we use it. 96 if (HostTriple.isArch64Bit() && FS.exists(InstallPath + "/lib64")) 97 LibPath = InstallPath + "/lib64"; 98 else if (FS.exists(InstallPath + "/lib")) 99 LibPath = InstallPath + "/lib"; 100 else 101 continue; 102 103 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile = 104 FS.getBufferForFile(InstallPath + "/version.txt"); 105 if (!VersionFile) { 106 // CUDA 7.0 doesn't have a version.txt, so guess that's our version if 107 // version.txt isn't present. 108 Version = CudaVersion::CUDA_70; 109 } else { 110 Version = ParseCudaVersionFile((*VersionFile)->getBuffer()); 111 } 112 113 std::error_code EC; 114 for (llvm::sys::fs::directory_iterator LI(LibDevicePath, EC), LE; 115 !EC && LI != LE; LI = LI.increment(EC)) { 116 StringRef FilePath = LI->path(); 117 StringRef FileName = llvm::sys::path::filename(FilePath); 118 // Process all bitcode filenames that look like libdevice.compute_XX.YY.bc 119 const StringRef LibDeviceName = "libdevice."; 120 if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc"))) 121 continue; 122 StringRef GpuArch = FileName.slice( 123 LibDeviceName.size(), FileName.find('.', LibDeviceName.size())); 124 LibDeviceMap[GpuArch] = FilePath.str(); 125 // Insert map entries for specifc devices with this compute 126 // capability. NVCC's choice of the libdevice library version is 127 // rather peculiar and depends on the CUDA version. 128 if (GpuArch == "compute_20") { 129 LibDeviceMap["sm_20"] = FilePath; 130 LibDeviceMap["sm_21"] = FilePath; 131 LibDeviceMap["sm_32"] = FilePath; 132 } else if (GpuArch == "compute_30") { 133 LibDeviceMap["sm_30"] = FilePath; 134 if (Version < CudaVersion::CUDA_80) { 135 LibDeviceMap["sm_50"] = FilePath; 136 LibDeviceMap["sm_52"] = FilePath; 137 LibDeviceMap["sm_53"] = FilePath; 138 } 139 LibDeviceMap["sm_60"] = FilePath; 140 LibDeviceMap["sm_61"] = FilePath; 141 LibDeviceMap["sm_62"] = FilePath; 142 } else if (GpuArch == "compute_35") { 143 LibDeviceMap["sm_35"] = FilePath; 144 LibDeviceMap["sm_37"] = FilePath; 145 } else if (GpuArch == "compute_50") { 146 if (Version >= CudaVersion::CUDA_80) { 147 LibDeviceMap["sm_50"] = FilePath; 148 LibDeviceMap["sm_52"] = FilePath; 149 LibDeviceMap["sm_53"] = FilePath; 150 } 151 } 152 } 153 154 IsValid = true; 155 break; 156 } 157 } 158 159 void CudaInstallationDetector::AddCudaIncludeArgs( 160 const ArgList &DriverArgs, ArgStringList &CC1Args) const { 161 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { 162 // Add cuda_wrappers/* to our system include path. This lets us wrap 163 // standard library headers. 164 SmallString<128> P(D.ResourceDir); 165 llvm::sys::path::append(P, "include"); 166 llvm::sys::path::append(P, "cuda_wrappers"); 167 CC1Args.push_back("-internal-isystem"); 168 CC1Args.push_back(DriverArgs.MakeArgString(P)); 169 } 170 171 if (DriverArgs.hasArg(options::OPT_nocudainc)) 172 return; 173 174 if (!isValid()) { 175 D.Diag(diag::err_drv_no_cuda_installation); 176 return; 177 } 178 179 CC1Args.push_back("-internal-isystem"); 180 CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath())); 181 CC1Args.push_back("-include"); 182 CC1Args.push_back("__clang_cuda_runtime_wrapper.h"); 183 } 184 185 void CudaInstallationDetector::CheckCudaVersionSupportsArch( 186 CudaArch Arch) const { 187 if (Arch == CudaArch::UNKNOWN || Version == CudaVersion::UNKNOWN || 188 ArchsWithVersionTooLowErrors.count(Arch) > 0) 189 return; 190 191 auto RequiredVersion = MinVersionForCudaArch(Arch); 192 if (Version < RequiredVersion) { 193 ArchsWithVersionTooLowErrors.insert(Arch); 194 D.Diag(diag::err_drv_cuda_version_too_low) 195 << InstallPath << CudaArchToString(Arch) << CudaVersionToString(Version) 196 << CudaVersionToString(RequiredVersion); 197 } 198 } 199 200 void CudaInstallationDetector::print(raw_ostream &OS) const { 201 if (isValid()) 202 OS << "Found CUDA installation: " << InstallPath << ", version " 203 << CudaVersionToString(Version) << "\n"; 204 } 205 206 void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA, 207 const InputInfo &Output, 208 const InputInfoList &Inputs, 209 const ArgList &Args, 210 const char *LinkingOutput) const { 211 const auto &TC = 212 static_cast<const toolchains::CudaToolChain &>(getToolChain()); 213 assert(TC.getTriple().isNVPTX() && "Wrong platform"); 214 215 // Obtain architecture from the action. 216 CudaArch gpu_arch = StringToCudaArch(JA.getOffloadingArch()); 217 assert(gpu_arch != CudaArch::UNKNOWN && 218 "Device action expected to have an architecture."); 219 220 // Check that our installation's ptxas supports gpu_arch. 221 if (!Args.hasArg(options::OPT_no_cuda_version_check)) { 222 TC.CudaInstallation.CheckCudaVersionSupportsArch(gpu_arch); 223 } 224 225 ArgStringList CmdArgs; 226 CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-m64" : "-m32"); 227 if (Args.hasFlag(options::OPT_cuda_noopt_device_debug, 228 options::OPT_no_cuda_noopt_device_debug, false)) { 229 // ptxas does not accept -g option if optimization is enabled, so 230 // we ignore the compiler's -O* options if we want debug info. 231 CmdArgs.push_back("-g"); 232 CmdArgs.push_back("--dont-merge-basicblocks"); 233 CmdArgs.push_back("--return-at-end"); 234 } else if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { 235 // Map the -O we received to -O{0,1,2,3}. 236 // 237 // TODO: Perhaps we should map host -O2 to ptxas -O3. -O3 is ptxas's 238 // default, so it may correspond more closely to the spirit of clang -O2. 239 240 // -O3 seems like the least-bad option when -Osomething is specified to 241 // clang but it isn't handled below. 242 StringRef OOpt = "3"; 243 if (A->getOption().matches(options::OPT_O4) || 244 A->getOption().matches(options::OPT_Ofast)) 245 OOpt = "3"; 246 else if (A->getOption().matches(options::OPT_O0)) 247 OOpt = "0"; 248 else if (A->getOption().matches(options::OPT_O)) { 249 // -Os, -Oz, and -O(anything else) map to -O2, for lack of better options. 250 OOpt = llvm::StringSwitch<const char *>(A->getValue()) 251 .Case("1", "1") 252 .Case("2", "2") 253 .Case("3", "3") 254 .Case("s", "2") 255 .Case("z", "2") 256 .Default("2"); 257 } 258 CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); 259 } else { 260 // If no -O was passed, pass -O0 to ptxas -- no opt flag should correspond 261 // to no optimizations, but ptxas's default is -O3. 262 CmdArgs.push_back("-O0"); 263 } 264 265 CmdArgs.push_back("--gpu-name"); 266 CmdArgs.push_back(Args.MakeArgString(CudaArchToString(gpu_arch))); 267 CmdArgs.push_back("--output-file"); 268 CmdArgs.push_back(Args.MakeArgString(Output.getFilename())); 269 for (const auto& II : Inputs) 270 CmdArgs.push_back(Args.MakeArgString(II.getFilename())); 271 272 for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_ptxas)) 273 CmdArgs.push_back(Args.MakeArgString(A)); 274 275 const char *Exec; 276 if (Arg *A = Args.getLastArg(options::OPT_ptxas_path_EQ)) 277 Exec = A->getValue(); 278 else 279 Exec = Args.MakeArgString(TC.GetProgramPath("ptxas")); 280 C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); 281 } 282 283 // All inputs to this linker must be from CudaDeviceActions, as we need to look 284 // at the Inputs' Actions in order to figure out which GPU architecture they 285 // correspond to. 286 void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, 287 const InputInfo &Output, 288 const InputInfoList &Inputs, 289 const ArgList &Args, 290 const char *LinkingOutput) const { 291 const auto &TC = 292 static_cast<const toolchains::CudaToolChain &>(getToolChain()); 293 assert(TC.getTriple().isNVPTX() && "Wrong platform"); 294 295 ArgStringList CmdArgs; 296 CmdArgs.push_back("--cuda"); 297 CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-64" : "-32"); 298 CmdArgs.push_back(Args.MakeArgString("--create")); 299 CmdArgs.push_back(Args.MakeArgString(Output.getFilename())); 300 301 for (const auto& II : Inputs) { 302 auto *A = II.getAction(); 303 assert(A->getInputs().size() == 1 && 304 "Device offload action is expected to have a single input"); 305 const char *gpu_arch_str = A->getOffloadingArch(); 306 assert(gpu_arch_str && 307 "Device action expected to have associated a GPU architecture!"); 308 CudaArch gpu_arch = StringToCudaArch(gpu_arch_str); 309 310 // We need to pass an Arch of the form "sm_XX" for cubin files and 311 // "compute_XX" for ptx. 312 const char *Arch = 313 (II.getType() == types::TY_PP_Asm) 314 ? CudaVirtualArchToString(VirtualArchForCudaArch(gpu_arch)) 315 : gpu_arch_str; 316 CmdArgs.push_back(Args.MakeArgString(llvm::Twine("--image=profile=") + 317 Arch + ",file=" + II.getFilename())); 318 } 319 320 for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary)) 321 CmdArgs.push_back(Args.MakeArgString(A)); 322 323 const char *Exec = Args.MakeArgString(TC.GetProgramPath("fatbinary")); 324 C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); 325 } 326 327 /// CUDA toolchain. Our assembler is ptxas, and our "linker" is fatbinary, 328 /// which isn't properly a linker but nonetheless performs the step of stitching 329 /// together object files from the assembler into a single blob. 330 331 CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, 332 const ToolChain &HostTC, const ArgList &Args) 333 : ToolChain(D, Triple, Args), HostTC(HostTC), 334 CudaInstallation(D, HostTC.getTriple(), Args) { 335 if (CudaInstallation.isValid()) 336 getProgramPaths().push_back(CudaInstallation.getBinPath()); 337 } 338 339 void CudaToolChain::addClangTargetOptions( 340 const llvm::opt::ArgList &DriverArgs, 341 llvm::opt::ArgStringList &CC1Args) const { 342 HostTC.addClangTargetOptions(DriverArgs, CC1Args); 343 344 CC1Args.push_back("-fcuda-is-device"); 345 346 if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, 347 options::OPT_fno_cuda_flush_denormals_to_zero, false)) 348 CC1Args.push_back("-fcuda-flush-denormals-to-zero"); 349 350 if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, 351 options::OPT_fno_cuda_approx_transcendentals, false)) 352 CC1Args.push_back("-fcuda-approx-transcendentals"); 353 354 if (DriverArgs.hasArg(options::OPT_nocudalib)) 355 return; 356 357 StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ); 358 assert(!GpuArch.empty() && "Must have an explicit GPU arch."); 359 std::string LibDeviceFile = CudaInstallation.getLibDeviceFile(GpuArch); 360 361 if (LibDeviceFile.empty()) { 362 getDriver().Diag(diag::err_drv_no_cuda_libdevice) << GpuArch; 363 return; 364 } 365 366 CC1Args.push_back("-mlink-cuda-bitcode"); 367 CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile)); 368 369 // Libdevice in CUDA-7.0 requires PTX version that's more recent 370 // than LLVM defaults to. Use PTX4.2 which is the PTX version that 371 // came with CUDA-7.0. 372 CC1Args.push_back("-target-feature"); 373 CC1Args.push_back("+ptx42"); 374 } 375 376 void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, 377 ArgStringList &CC1Args) const { 378 // Check our CUDA version if we're going to include the CUDA headers. 379 if (!DriverArgs.hasArg(options::OPT_nocudainc) && 380 !DriverArgs.hasArg(options::OPT_no_cuda_version_check)) { 381 StringRef Arch = DriverArgs.getLastArgValue(options::OPT_march_EQ); 382 assert(!Arch.empty() && "Must have an explicit GPU arch."); 383 CudaInstallation.CheckCudaVersionSupportsArch(StringToCudaArch(Arch)); 384 } 385 CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); 386 } 387 388 llvm::opt::DerivedArgList * 389 CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, 390 StringRef BoundArch, 391 Action::OffloadKind DeviceOffloadKind) const { 392 DerivedArgList *DAL = 393 HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind); 394 if (!DAL) 395 DAL = new DerivedArgList(Args.getBaseArgs()); 396 397 const OptTable &Opts = getDriver().getOpts(); 398 399 for (Arg *A : Args) { 400 if (A->getOption().matches(options::OPT_Xarch__)) { 401 // Skip this argument unless the architecture matches BoundArch 402 if (BoundArch.empty() || A->getValue(0) != BoundArch) 403 continue; 404 405 unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); 406 unsigned Prev = Index; 407 std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index)); 408 409 // If the argument parsing failed or more than one argument was 410 // consumed, the -Xarch_ argument's parameter tried to consume 411 // extra arguments. Emit an error and ignore. 412 // 413 // We also want to disallow any options which would alter the 414 // driver behavior; that isn't going to work in our model. We 415 // use isDriverOption() as an approximation, although things 416 // like -O4 are going to slip through. 417 if (!XarchArg || Index > Prev + 1) { 418 getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) 419 << A->getAsString(Args); 420 continue; 421 } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { 422 getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) 423 << A->getAsString(Args); 424 continue; 425 } 426 XarchArg->setBaseArg(A); 427 A = XarchArg.release(); 428 DAL->AddSynthesizedArg(A); 429 } 430 DAL->append(A); 431 } 432 433 if (!BoundArch.empty()) { 434 DAL->eraseArg(options::OPT_march_EQ); 435 DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch); 436 } 437 return DAL; 438 } 439 440 Tool *CudaToolChain::buildAssembler() const { 441 return new tools::NVPTX::Assembler(*this); 442 } 443 444 Tool *CudaToolChain::buildLinker() const { 445 return new tools::NVPTX::Linker(*this); 446 } 447 448 void CudaToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { 449 HostTC.addClangWarningOptions(CC1Args); 450 } 451 452 ToolChain::CXXStdlibType 453 CudaToolChain::GetCXXStdlibType(const ArgList &Args) const { 454 return HostTC.GetCXXStdlibType(Args); 455 } 456 457 void CudaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 458 ArgStringList &CC1Args) const { 459 HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); 460 } 461 462 void CudaToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args, 463 ArgStringList &CC1Args) const { 464 HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args); 465 } 466 467 void CudaToolChain::AddIAMCUIncludeArgs(const ArgList &Args, 468 ArgStringList &CC1Args) const { 469 HostTC.AddIAMCUIncludeArgs(Args, CC1Args); 470 } 471 472 SanitizerMask CudaToolChain::getSupportedSanitizers() const { 473 // The CudaToolChain only supports sanitizers in the sense that it allows 474 // sanitizer arguments on the command line if they are supported by the host 475 // toolchain. The CudaToolChain will actually ignore any command line 476 // arguments for any of these "supported" sanitizers. That means that no 477 // sanitization of device code is actually supported at this time. 478 // 479 // This behavior is necessary because the host and device toolchains 480 // invocations often share the command line, so the device toolchain must 481 // tolerate flags meant only for the host toolchain. 482 return HostTC.getSupportedSanitizers(); 483 } 484 485 VersionTuple CudaToolChain::computeMSVCVersion(const Driver *D, 486 const ArgList &Args) const { 487 return HostTC.computeMSVCVersion(D, Args); 488 } 489