18 #include "llvm/Option/ArgList.h"
19 #include "llvm/Support/Path.h"
20 #include <system_error>
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;
31 if (!V.startswith(
"CUDA Version "))
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))
41 if (Major == 7 && Minor == 0) {
46 if (Major == 7 && Minor == 5)
48 if (Major == 8 && Minor == 0)
54 const Driver &D,
const llvm::Triple &HostTriple,
55 const llvm::opt::ArgList &Args)
60 std::initializer_list<const char *> Versions = {
"8.0",
"7.5",
"7.0"};
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" +
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);
76 for (
const auto &CudaPath : CudaPathCandidates) {
80 InstallPath = CudaPath;
81 BinPath = CudaPath +
"/bin";
82 IncludePath = InstallPath +
"/include";
83 LibDevicePath = InstallPath +
"/nvvm/libdevice";
86 if (!(FS.exists(IncludePath) && FS.exists(BinPath) &&
87 FS.exists(LibDevicePath)))
96 if (HostTriple.isArch64Bit() && FS.exists(InstallPath +
"/lib64"))
97 LibPath = InstallPath +
"/lib64";
98 else if (FS.exists(InstallPath +
"/lib"))
99 LibPath = InstallPath +
"/lib";
103 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile =
104 FS.getBufferForFile(InstallPath +
"/version.txt");
114 for (llvm::sys::fs::directory_iterator LI(LibDevicePath, EC), LE;
115 !EC && LI != LE; LI = LI.increment(EC)) {
117 StringRef
FileName = llvm::sys::path::filename(FilePath);
119 const StringRef LibDeviceName =
"libdevice.";
120 if (!(FileName.startswith(LibDeviceName) && FileName.endswith(
".bc")))
122 StringRef GpuArch = FileName.slice(
123 LibDeviceName.size(), FileName.find(
'.', LibDeviceName.size()));
124 LibDeviceMap[GpuArch] = FilePath.str();
128 if (GpuArch ==
"compute_20") {
132 }
else if (GpuArch ==
"compute_30") {
142 }
else if (GpuArch ==
"compute_35") {
145 }
else if (GpuArch ==
"compute_50") {
160 const ArgList &DriverArgs, ArgStringList &CC1Args)
const {
161 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
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));
171 if (DriverArgs.hasArg(options::OPT_nocudainc))
175 D.
Diag(diag::err_drv_no_cuda_installation);
179 CC1Args.push_back(
"-internal-isystem");
181 CC1Args.push_back(
"-include");
182 CC1Args.push_back(
"__clang_cuda_runtime_wrapper.h");
188 ArchsWithVersionTooLowErrors.count(Arch) > 0)
192 if (Version < RequiredVersion) {
193 ArchsWithVersionTooLowErrors.insert(Arch);
194 D.
Diag(diag::err_drv_cuda_version_too_low)
202 OS <<
"Found CUDA installation: " << InstallPath <<
", version "
210 const char *LinkingOutput)
const {
213 assert(TC.getTriple().isNVPTX() &&
"Wrong platform");
218 "Device action expected to have an architecture.");
221 if (!Args.hasArg(options::OPT_no_cuda_version_check)) {
222 TC.CudaInstallation.CheckCudaVersionSupportsArch(gpu_arch);
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)) {
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)) {
242 StringRef OOpt =
"3";
243 if (A->getOption().matches(options::OPT_O4) ||
244 A->getOption().matches(options::OPT_Ofast))
246 else if (A->getOption().matches(options::OPT_O0))
248 else if (A->getOption().matches(options::OPT_O)) {
250 OOpt = llvm::StringSwitch<const char *>(A->getValue())
258 CmdArgs.push_back(Args.MakeArgString(llvm::Twine(
"-O") + OOpt));
262 CmdArgs.push_back(
"-O0");
265 CmdArgs.push_back(
"--gpu-name");
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()));
272 for (
const auto& A : Args.getAllArgValues(options::OPT_Xcuda_ptxas))
273 CmdArgs.push_back(Args.MakeArgString(A));
276 if (Arg *A = Args.getLastArg(options::OPT_ptxas_path_EQ))
277 Exec = A->getValue();
279 Exec = Args.MakeArgString(TC.GetProgramPath(
"ptxas"));
280 C.
addCommand(llvm::make_unique<Command>(JA, *
this, Exec, CmdArgs, Inputs));
290 const char *LinkingOutput)
const {
293 assert(TC.getTriple().isNVPTX() &&
"Wrong platform");
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()));
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!");
313 (II.getType() == types::TY_PP_Asm)
316 CmdArgs.push_back(Args.MakeArgString(llvm::Twine(
"--image=profile=") +
317 Arch +
",file=" + II.getFilename()));
320 for (
const auto& A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary))
321 CmdArgs.push_back(Args.MakeArgString(A));
323 const char *Exec = Args.MakeArgString(TC.GetProgramPath(
"fatbinary"));
324 C.
addCommand(llvm::make_unique<Command>(JA, *
this, Exec, CmdArgs, Inputs));
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) {
340 const llvm::opt::ArgList &DriverArgs,
341 llvm::opt::ArgStringList &CC1Args,
345 StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ);
346 assert(!GpuArch.empty() &&
"Must have an explicit GPU arch.");
349 "Only OpenMP or CUDA offloading kinds are supported for NVIDIA GPUs.");
352 CC1Args.push_back(
"-fcuda-is-device");
354 if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero,
355 options::OPT_fno_cuda_flush_denormals_to_zero,
false))
356 CC1Args.push_back(
"-fcuda-flush-denormals-to-zero");
358 if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals,
359 options::OPT_fno_cuda_approx_transcendentals,
false))
360 CC1Args.push_back(
"-fcuda-approx-transcendentals");
362 if (DriverArgs.hasArg(options::OPT_nocudalib))
368 if (LibDeviceFile.empty()) {
369 getDriver().
Diag(diag::err_drv_no_cuda_libdevice) << GpuArch;
373 CC1Args.push_back(
"-mlink-cuda-bitcode");
374 CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile));
379 CC1Args.push_back(
"-target-feature");
380 CC1Args.push_back(
"+ptx42");
384 ArgStringList &CC1Args)
const {
386 if (!DriverArgs.hasArg(options::OPT_nocudainc) &&
387 !DriverArgs.hasArg(options::OPT_no_cuda_version_check)) {
388 StringRef Arch = DriverArgs.getLastArgValue(options::OPT_march_EQ);
389 assert(!Arch.empty() &&
"Must have an explicit GPU arch.");
395 llvm::opt::DerivedArgList *
399 DerivedArgList *DAL =
402 DAL =
new DerivedArgList(Args.getBaseArgs());
411 bool IsDuplicate =
false;
412 for (Arg *DALArg : *DAL){
424 for (Arg *A : Args) {
425 if (A->getOption().matches(options::OPT_Xarch__)) {
427 if (BoundArch.empty() || A->getValue(0) != BoundArch)
430 unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1));
431 unsigned Prev = Index;
432 std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index));
442 if (!XarchArg || Index > Prev + 1) {
443 getDriver().
Diag(diag::err_drv_invalid_Xarch_argument_with_args)
444 << A->getAsString(Args);
447 getDriver().
Diag(diag::err_drv_invalid_Xarch_argument_isdriver)
448 << A->getAsString(Args);
451 XarchArg->setBaseArg(A);
452 A = XarchArg.release();
453 DAL->AddSynthesizedArg(A);
458 if (!BoundArch.empty()) {
459 DAL->eraseArg(options::OPT_march_EQ);
460 DAL->AddJoinedArg(
nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch);
483 ArgStringList &CC1Args)
const {
488 ArgStringList &CC1Args)
const {
493 ArgStringList &CC1Args)
const {
511 const ArgList &Args)
const {
Represents a version number in the form major[.minor[.subminor[.build]]].
const char * CudaArchToString(CudaArch A)
const llvm::opt::OptTable & getOpts() const
DiagnosticBuilder Diag(unsigned DiagID) const
CudaArch StringToCudaArch(llvm::StringRef S)
CudaInstallationDetector(const Driver &D, const llvm::Triple &HostTriple, const llvm::opt::ArgList &Args)
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
const char * CudaVersionToString(CudaVersion V)
void addCommand(std::unique_ptr< Command > C)
const char * getOffloadingArch() const
const char * CudaVirtualArchToString(CudaVirtualArch A)
StringRef getIncludePath() const
Get the detected Cuda Include path.
vfs::FileSystem & getVFS() const
void print(raw_ostream &OS) const
Print information about the detected CUDA installation.
CudaVersion MinVersionForCudaArch(CudaArch A)
Get the earliest CudaVersion that supports the given CudaArch.
StringRef getBinPath() const
Get the detected path to Cuda's bin directory.
std::string SysRoot
sysroot, if present
Defines the virtual file system interface vfs::FileSystem.
CudaVirtualArch VirtualArchForCudaArch(CudaArch A)
Get the compute_xx corresponding to an sm_yy.
bool exists(const Twine &Path)
Check whether a file exists. Provided for convenience.
Compilation - A set of tasks to perform for a single driver invocation.
std::string getLibDeviceFile(StringRef Gpu) const
Get libdevice file for given architecture.
void CheckCudaVersionSupportsArch(CudaArch Arch) const
Emit an error if Version does not support the given Arch.
bool isValid() const
Check whether we detected a valid Cuda install.
void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const
std::string ResourceDir
The path to the compiler resource directory.