forked from OSchip/llvm-project
[CUDA] Check that our CUDA install supports the requested architectures.
Summary: Raise an error if you're using a CUDA installation that's too old for the requested architectures. In practice, this means that you need a CUDA 8 install to compile for sm_6*. Reviewers: tra Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D21869 llvm-svn: 274781
This commit is contained in:
parent
495f1a22af
commit
c43ad9ee5a
|
@ -26,6 +26,10 @@ def err_drv_cuda_bad_gpu_arch : Error<"Unsupported CUDA gpu architecture: %0">;
|
|||
def err_drv_no_cuda_installation : Error<
|
||||
"cannot find CUDA installation. Provide its path via --cuda-path, or pass "
|
||||
"-nocudainc to build without CUDA includes.">;
|
||||
def err_drv_cuda_version_too_low : Error<
|
||||
"GPU arch %1 requires CUDA version at least %3, but installation at %0 is %2. "
|
||||
"Use --cuda-path to specify a different CUDA install, or pass "
|
||||
"--no-cuda-version-check.">;
|
||||
def err_drv_invalid_thread_model_for_target : Error<
|
||||
"invalid thread model '%0' in '%1' for this target">;
|
||||
def err_drv_invalid_linker_name : Error<
|
||||
|
|
|
@ -410,6 +410,9 @@ def cuda_gpu_arch_EQ : Joined<["--"], "cuda-gpu-arch=">, Flags<[DriverOption]>,
|
|||
HelpText<"CUDA GPU architecture (e.g. sm_35). May be specified more than once.">;
|
||||
def cuda_noopt_device_debug : Flag<["--"], "cuda-noopt-device-debug">,
|
||||
HelpText<"Enable device-side debug info generation. Disables ptxas optimizations.">;
|
||||
def no_cuda_version_check : Flag<["--"], "no-cuda-version-check">,
|
||||
HelpText<"Don't error out if the detected version of the CUDA install is "
|
||||
"too low for the requested CUDA gpu architecture.">;
|
||||
def no_cuda_noopt_device_debug : Flag<["--"], "no-cuda-noopt-device-debug">;
|
||||
def cuda_path_EQ : Joined<["--"], "cuda-path=">, Group<i_Group>,
|
||||
HelpText<"CUDA installation path">;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ToolChains.h"
|
||||
#include "clang/Basic/Cuda.h"
|
||||
#include "clang/Basic/ObjCRuntime.h"
|
||||
#include "clang/Basic/Version.h"
|
||||
#include "clang/Basic/VirtualFileSystem.h"
|
||||
|
@ -1703,9 +1704,33 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
|
|||
BiarchTripleAliases.push_back(BiarchTriple.str());
|
||||
}
|
||||
|
||||
// Parses the contents of version.txt in an CUDA installation. It should
|
||||
// contain one line of the from e.g. "CUDA Version 7.5.2".
|
||||
static CudaVersion ParseCudaVersionFile(llvm::StringRef V) {
|
||||
if (!V.startswith("CUDA Version "))
|
||||
return CudaVersion::UNKNOWN;
|
||||
V = V.substr(strlen("CUDA Version "));
|
||||
int Major = -1, Minor = -1;
|
||||
auto First = V.split('.');
|
||||
auto Second = First.second.split('.');
|
||||
if (!First.first.getAsInteger(10, Major) ||
|
||||
!Second.first.getAsInteger(10, Minor))
|
||||
return CudaVersion::UNKNOWN;
|
||||
|
||||
if (Major == 7 && Minor == 0) {
|
||||
// This doesn't appear to ever happen -- version.txt doesn't exist in the
|
||||
// CUDA 7 installs I've seen. But no harm in checking.
|
||||
return CudaVersion::CUDA_70;
|
||||
}
|
||||
if (Major == 7 && Minor == 5)
|
||||
return CudaVersion::CUDA_75;
|
||||
if (Major == 8 && Minor == 0)
|
||||
return CudaVersion::CUDA_80;
|
||||
return CudaVersion::UNKNOWN;
|
||||
}
|
||||
|
||||
// \brief -- try common CUDA installation paths looking for files we need for
|
||||
// CUDA compilation.
|
||||
|
||||
void Generic_GCC::CudaInstallationDetector::init(
|
||||
const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args) {
|
||||
SmallVector<std::string, 4> CudaPathCandidates;
|
||||
|
@ -1768,14 +1793,40 @@ void Generic_GCC::CudaInstallationDetector::init(
|
|||
}
|
||||
}
|
||||
|
||||
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile =
|
||||
FS.getBufferForFile(InstallPath + "/version.txt");
|
||||
if (!VersionFile) {
|
||||
// CUDA 7.0 doesn't have a version.txt, so guess that's our version if
|
||||
// version.txt isn't present.
|
||||
Version = CudaVersion::CUDA_70;
|
||||
} else {
|
||||
Version = ParseCudaVersionFile((*VersionFile)->getBuffer());
|
||||
}
|
||||
|
||||
IsValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Generic_GCC::CudaInstallationDetector::CheckCudaVersionSupportsArch(
|
||||
CudaArch Arch) const {
|
||||
if (Arch == CudaArch::UNKNOWN || Version == CudaVersion::UNKNOWN ||
|
||||
ArchsWithVersionTooLowErrors.count(Arch) > 0)
|
||||
return;
|
||||
|
||||
auto RequiredVersion = MinVersionForCudaArch(Arch);
|
||||
if (Version < RequiredVersion) {
|
||||
ArchsWithVersionTooLowErrors.insert(Arch);
|
||||
D.Diag(diag::err_drv_cuda_version_too_low)
|
||||
<< InstallPath << CudaArchToString(Arch) << CudaVersionToString(Version)
|
||||
<< CudaVersionToString(RequiredVersion);
|
||||
}
|
||||
}
|
||||
|
||||
void Generic_GCC::CudaInstallationDetector::print(raw_ostream &OS) const {
|
||||
if (isValid())
|
||||
OS << "Found CUDA installation: " << InstallPath << "\n";
|
||||
OS << "Found CUDA installation: " << InstallPath << ", version "
|
||||
<< CudaVersionToString(Version) << "\n";
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -4670,6 +4721,18 @@ CudaToolChain::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
|
|||
}
|
||||
}
|
||||
|
||||
void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
|
||||
ArgStringList &CC1Args) const {
|
||||
// Check our CUDA version if we're going to include the CUDA headers.
|
||||
if (!DriverArgs.hasArg(options::OPT_nocudainc) &&
|
||||
!DriverArgs.hasArg(options::OPT_nocuda_version_check)) {
|
||||
StringRef Arch = DriverArgs.getLastArgValue(options::OPT_march_EQ);
|
||||
assert(!Arch.empty() && "Must have an explicit GPU arch.");
|
||||
CudaInstallation.CheckCudaVersionSupportsArch(StringToCudaArch(Arch));
|
||||
}
|
||||
Linux::AddCudaIncludeArgs(DriverArgs, CC1Args);
|
||||
}
|
||||
|
||||
llvm::opt::DerivedArgList *
|
||||
CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
|
||||
const char *BoundArch) const {
|
||||
|
|
|
@ -11,12 +11,14 @@
|
|||
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_H
|
||||
|
||||
#include "Tools.h"
|
||||
#include "clang/Basic/Cuda.h"
|
||||
#include "clang/Basic/VersionTuple.h"
|
||||
#include "clang/Driver/Action.h"
|
||||
#include "clang/Driver/Multilib.h"
|
||||
#include "clang/Driver/ToolChain.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
@ -162,6 +164,7 @@ protected:
|
|||
private:
|
||||
const Driver &D;
|
||||
bool IsValid = false;
|
||||
CudaVersion Version = CudaVersion::UNKNOWN;
|
||||
std::string InstallPath;
|
||||
std::string BinPath;
|
||||
std::string LibPath;
|
||||
|
@ -169,15 +172,27 @@ protected:
|
|||
std::string IncludePath;
|
||||
llvm::StringMap<std::string> LibDeviceMap;
|
||||
|
||||
// CUDA architectures for which we have raised an error in
|
||||
// CheckCudaVersionSupportsArch.
|
||||
mutable llvm::SmallSet<CudaArch, 4> ArchsWithVersionTooLowErrors;
|
||||
|
||||
public:
|
||||
CudaInstallationDetector(const Driver &D) : D(D) {}
|
||||
void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args);
|
||||
|
||||
/// \brief Emit an error if Version does not support the given Arch.
|
||||
///
|
||||
/// If either Version or Arch is unknown, does not emit an error. Emits at
|
||||
/// most one error per Arch.
|
||||
void CheckCudaVersionSupportsArch(CudaArch Arch) const;
|
||||
|
||||
/// \brief Check whether we detected a valid Cuda install.
|
||||
bool isValid() const { return IsValid; }
|
||||
/// \brief Print information about the detected CUDA installation.
|
||||
void print(raw_ostream &OS) const;
|
||||
|
||||
/// \brief Get the deteced Cuda install's version.
|
||||
CudaVersion version() const { return Version; }
|
||||
/// \brief Get the detected Cuda installation path.
|
||||
StringRef getInstallPath() const { return InstallPath; }
|
||||
/// \brief Get the detected path to Cuda's bin directory.
|
||||
|
@ -852,6 +867,16 @@ public:
|
|||
// ptxas.
|
||||
bool useIntegratedAs() const override { return false; }
|
||||
|
||||
void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args) const override;
|
||||
|
||||
const Generic_GCC::CudaInstallationDetector &cudaInstallation() const {
|
||||
return CudaInstallation;
|
||||
}
|
||||
Generic_GCC::CudaInstallationDetector &cudaInstallation() {
|
||||
return CudaInstallation;
|
||||
}
|
||||
|
||||
protected:
|
||||
Tool *buildAssembler() const override; // ptxas
|
||||
Tool *buildLinker() const override; // fatbinary (ok, not really a linker)
|
||||
|
|
|
@ -11146,6 +11146,12 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
|
|||
assert(gpu_archs.size() == 1 && "Exactly one GPU Arch required for ptxas.");
|
||||
const std::string& gpu_arch = gpu_archs[0];
|
||||
|
||||
// Check that our installation's ptxas supports gpu_arch.
|
||||
if (!Args.hasArg(options::OPT_nocuda_version_check)) {
|
||||
TC.cudaInstallation().CheckCudaVersionSupportsArch(
|
||||
StringToCudaArch(gpu_arch));
|
||||
}
|
||||
|
||||
ArgStringList CmdArgs;
|
||||
CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-m64" : "-m32");
|
||||
if (Args.hasFlag(options::OPT_cuda_noopt_device_debug,
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
CUDA Version 8.0.42
|
|
@ -0,0 +1,51 @@
|
|||
// REQUIRES: clang-driver
|
||||
// REQUIRES: x86-registered-target
|
||||
// REQUIRES: nvptx-registered-target
|
||||
|
||||
// RUN: %clang -v -### --cuda-gpu-arch=sm_20 --sysroot=%S/Inputs/CUDA 2>&1 %s | \
|
||||
// RUN: FileCheck %s --check-prefix=OK
|
||||
// RUN: %clang -v -### --cuda-gpu-arch=sm_20 --sysroot=%S/Inputs/CUDA_80 2>&1 %s | \
|
||||
// RUN: FileCheck %s --check-prefix=OK
|
||||
// RUN: %clang -v -### --cuda-gpu-arch=sm_60 --sysroot=%S/Inputs/CUDA_80 2>&1 %s | \
|
||||
// RUN: FileCheck %s --check-prefix=OK
|
||||
|
||||
// The installation at Inputs/CUDA is CUDA 7.0, which doesn't support sm_60.
|
||||
// RUN: %clang -v -### --cuda-gpu-arch=sm_60 --sysroot=%S/Inputs/CUDA 2>&1 %s | \
|
||||
// RUN: FileCheck %s --check-prefix=ERR_SM60
|
||||
|
||||
// This should only complain about sm_60, not sm_35.
|
||||
// RUN: %clang -v -### --cuda-gpu-arch=sm_60 --cuda-gpu-arch=sm_35 \
|
||||
// RUN: --sysroot=%S/Inputs/CUDA 2>&1 %s | \
|
||||
// RUN: FileCheck %s --check-prefix=ERR_SM60 --check-prefix=OK_SM35
|
||||
|
||||
// We should get two errors here, one for sm_60 and one for sm_61.
|
||||
// RUN: %clang -v -### --cuda-gpu-arch=sm_60 --cuda-gpu-arch=sm_61 \
|
||||
// RUN: --sysroot=%S/Inputs/CUDA 2>&1 %s | \
|
||||
// RUN: FileCheck %s --check-prefix=ERR_SM60 --check-prefix=ERR_SM61
|
||||
|
||||
// We should still get an error if we pass -nocudainc, because this compilation
|
||||
// would invoke ptxas, and we do a version check on that, too.
|
||||
// RUN: %clang -v -### --cuda-gpu-arch=sm_60 -nocudainc --sysroot=%S/Inputs/CUDA 2>&1 %s | \
|
||||
// RUN: FileCheck %s --check-prefix=ERR_SM60
|
||||
|
||||
// If with -nocudainc and -E, we don't touch the CUDA install, so we
|
||||
// shouldn't get an error.
|
||||
// RUN: %clang -v -### -E --cuda-device-only --cuda-gpu-arch=sm_60 -nocudainc \
|
||||
// RUN: --sysroot=%S/Inputs/CUDA 2>&1 %s | \
|
||||
// RUN: FileCheck %s --check-prefix=OK
|
||||
|
||||
// -nocuda-version-check should suppress all of these errors.
|
||||
// RUN: %clang -v -### --cuda-gpu-arch=sm_60 --sysroot=%S/Inputs/CUDA 2>&1 \
|
||||
// RUN: -nocuda-version-check %s | \
|
||||
// RUN: FileCheck %s --check-prefix=OK
|
||||
|
||||
// OK-NOT: error: GPU arch
|
||||
|
||||
// OK_SM35-NOT: error: GPU arch sm_35
|
||||
|
||||
// We should only get one error per architecture.
|
||||
// ERR_SM60: error: GPU arch sm_60 {{.*}}
|
||||
// ERR_SM60-NOT: error: GPU arch sm_60
|
||||
|
||||
// ERR_SM61: error: GPU arch sm_61 {{.*}}
|
||||
// ERR_SM61-NOT: error: GPU arch sm_61
|
Loading…
Reference in New Issue